|
@@ -43,6 +43,7 @@
|
|
|
#include <linux/dma-mapping.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/prefetch.h>
|
|
|
+#include <linux/pinctrl/consumer.h>
|
|
|
#ifdef CONFIG_STMMAC_DEBUG_FS
|
|
|
#include <linux/debugfs.h>
|
|
|
#include <linux/seq_file.h>
|
|
@@ -776,6 +777,7 @@ static int stmmac_init_phy(struct net_device *dev)
|
|
|
char phy_id_fmt[MII_BUS_ID_SIZE + 3];
|
|
|
char bus_id[MII_BUS_ID_SIZE];
|
|
|
int interface = priv->plat->interface;
|
|
|
+ int max_speed = priv->plat->max_speed;
|
|
|
priv->oldlink = 0;
|
|
|
priv->speed = 0;
|
|
|
priv->oldduplex = -1;
|
|
@@ -800,7 +802,8 @@ static int stmmac_init_phy(struct net_device *dev)
|
|
|
|
|
|
/* Stop Advertising 1000BASE Capability if interface is not GMII */
|
|
|
if ((interface == PHY_INTERFACE_MODE_MII) ||
|
|
|
- (interface == PHY_INTERFACE_MODE_RMII))
|
|
|
+ (interface == PHY_INTERFACE_MODE_RMII) ||
|
|
|
+ (max_speed < 1000 && max_speed > 0))
|
|
|
phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
|
|
|
SUPPORTED_1000baseT_Full);
|
|
|
|
|
@@ -994,66 +997,6 @@ static int init_dma_desc_rings(struct net_device *dev)
|
|
|
pr_debug("%s: txsize %d, rxsize %d, bfsize %d\n", __func__,
|
|
|
txsize, rxsize, bfsize);
|
|
|
|
|
|
- if (priv->extend_desc) {
|
|
|
- priv->dma_erx = dma_alloc_coherent(priv->device, rxsize *
|
|
|
- sizeof(struct
|
|
|
- dma_extended_desc),
|
|
|
- &priv->dma_rx_phy,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->dma_erx)
|
|
|
- goto err_dma;
|
|
|
-
|
|
|
- priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
|
|
|
- sizeof(struct
|
|
|
- dma_extended_desc),
|
|
|
- &priv->dma_tx_phy,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->dma_etx) {
|
|
|
- dma_free_coherent(priv->device, priv->dma_rx_size *
|
|
|
- sizeof(struct dma_extended_desc),
|
|
|
- priv->dma_erx, priv->dma_rx_phy);
|
|
|
- goto err_dma;
|
|
|
- }
|
|
|
- } else {
|
|
|
- priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
|
|
|
- sizeof(struct dma_desc),
|
|
|
- &priv->dma_rx_phy,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->dma_rx)
|
|
|
- goto err_dma;
|
|
|
-
|
|
|
- priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
|
|
|
- sizeof(struct dma_desc),
|
|
|
- &priv->dma_tx_phy,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->dma_tx) {
|
|
|
- dma_free_coherent(priv->device, priv->dma_rx_size *
|
|
|
- sizeof(struct dma_desc),
|
|
|
- priv->dma_rx, priv->dma_rx_phy);
|
|
|
- goto err_dma;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->rx_skbuff_dma)
|
|
|
- goto err_rx_skbuff_dma;
|
|
|
-
|
|
|
- priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->rx_skbuff)
|
|
|
- goto err_rx_skbuff;
|
|
|
-
|
|
|
- priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->tx_skbuff_dma)
|
|
|
- goto err_tx_skbuff_dma;
|
|
|
-
|
|
|
- priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!priv->tx_skbuff)
|
|
|
- goto err_tx_skbuff;
|
|
|
-
|
|
|
if (netif_msg_probe(priv)) {
|
|
|
pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,
|
|
|
(u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);
|
|
@@ -1121,30 +1064,6 @@ static int init_dma_desc_rings(struct net_device *dev)
|
|
|
err_init_rx_buffers:
|
|
|
while (--i >= 0)
|
|
|
stmmac_free_rx_buffers(priv, i);
|
|
|
- kfree(priv->tx_skbuff);
|
|
|
-err_tx_skbuff:
|
|
|
- kfree(priv->tx_skbuff_dma);
|
|
|
-err_tx_skbuff_dma:
|
|
|
- kfree(priv->rx_skbuff);
|
|
|
-err_rx_skbuff:
|
|
|
- kfree(priv->rx_skbuff_dma);
|
|
|
-err_rx_skbuff_dma:
|
|
|
- if (priv->extend_desc) {
|
|
|
- dma_free_coherent(priv->device, priv->dma_tx_size *
|
|
|
- sizeof(struct dma_extended_desc),
|
|
|
- priv->dma_etx, priv->dma_tx_phy);
|
|
|
- dma_free_coherent(priv->device, priv->dma_rx_size *
|
|
|
- sizeof(struct dma_extended_desc),
|
|
|
- priv->dma_erx, priv->dma_rx_phy);
|
|
|
- } else {
|
|
|
- dma_free_coherent(priv->device,
|
|
|
- priv->dma_tx_size * sizeof(struct dma_desc),
|
|
|
- priv->dma_tx, priv->dma_tx_phy);
|
|
|
- dma_free_coherent(priv->device,
|
|
|
- priv->dma_rx_size * sizeof(struct dma_desc),
|
|
|
- priv->dma_rx, priv->dma_rx_phy);
|
|
|
- }
|
|
|
-err_dma:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1180,6 +1099,85 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int alloc_dma_desc_resources(struct stmmac_priv *priv)
|
|
|
+{
|
|
|
+ unsigned int txsize = priv->dma_tx_size;
|
|
|
+ unsigned int rxsize = priv->dma_rx_size;
|
|
|
+ int ret = -ENOMEM;
|
|
|
+
|
|
|
+ priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->rx_skbuff_dma)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->rx_skbuff)
|
|
|
+ goto err_rx_skbuff;
|
|
|
+
|
|
|
+ priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->tx_skbuff_dma)
|
|
|
+ goto err_tx_skbuff_dma;
|
|
|
+
|
|
|
+ priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->tx_skbuff)
|
|
|
+ goto err_tx_skbuff;
|
|
|
+
|
|
|
+ if (priv->extend_desc) {
|
|
|
+ priv->dma_erx = dma_alloc_coherent(priv->device, rxsize *
|
|
|
+ sizeof(struct
|
|
|
+ dma_extended_desc),
|
|
|
+ &priv->dma_rx_phy,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->dma_erx)
|
|
|
+ goto err_dma;
|
|
|
+
|
|
|
+ priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
|
|
|
+ sizeof(struct
|
|
|
+ dma_extended_desc),
|
|
|
+ &priv->dma_tx_phy,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->dma_etx) {
|
|
|
+ dma_free_coherent(priv->device, priv->dma_rx_size *
|
|
|
+ sizeof(struct dma_extended_desc),
|
|
|
+ priv->dma_erx, priv->dma_rx_phy);
|
|
|
+ goto err_dma;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
|
|
|
+ sizeof(struct dma_desc),
|
|
|
+ &priv->dma_rx_phy,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->dma_rx)
|
|
|
+ goto err_dma;
|
|
|
+
|
|
|
+ priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
|
|
|
+ sizeof(struct dma_desc),
|
|
|
+ &priv->dma_tx_phy,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!priv->dma_tx) {
|
|
|
+ dma_free_coherent(priv->device, priv->dma_rx_size *
|
|
|
+ sizeof(struct dma_desc),
|
|
|
+ priv->dma_rx, priv->dma_rx_phy);
|
|
|
+ goto err_dma;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_dma:
|
|
|
+ kfree(priv->tx_skbuff);
|
|
|
+err_tx_skbuff:
|
|
|
+ kfree(priv->tx_skbuff_dma);
|
|
|
+err_tx_skbuff_dma:
|
|
|
+ kfree(priv->rx_skbuff);
|
|
|
+err_rx_skbuff:
|
|
|
+ kfree(priv->rx_skbuff_dma);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static void free_dma_desc_resources(struct stmmac_priv *priv)
|
|
|
{
|
|
|
/* Release the DMA TX/RX socket buffers */
|
|
@@ -1588,6 +1586,86 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)
|
|
|
add_timer(&priv->txtimer);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * stmmac_hw_setup: setup mac in a usable state.
|
|
|
+ * @dev : pointer to the device structure.
|
|
|
+ * Description:
|
|
|
+ * This function sets up the ip in a usable state.
|
|
|
+ * Return value:
|
|
|
+ * 0 on success and an appropriate (-)ve integer as defined in errno.h
|
|
|
+ * file on failure.
|
|
|
+ */
|
|
|
+static int stmmac_hw_setup(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct stmmac_priv *priv = netdev_priv(dev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = init_dma_desc_rings(dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_err("%s: DMA descriptors initialization failed\n", __func__);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ /* DMA initialization and SW reset */
|
|
|
+ ret = stmmac_init_dma_engine(priv);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_err("%s: DMA engine initialization failed\n", __func__);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Copy the MAC addr into the HW */
|
|
|
+ priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
|
|
|
+
|
|
|
+ /* If required, perform hw setup of the bus. */
|
|
|
+ if (priv->plat->bus_setup)
|
|
|
+ priv->plat->bus_setup(priv->ioaddr);
|
|
|
+
|
|
|
+ /* Initialize the MAC Core */
|
|
|
+ priv->hw->mac->core_init(priv->ioaddr);
|
|
|
+
|
|
|
+ /* Enable the MAC Rx/Tx */
|
|
|
+ stmmac_set_mac(priv->ioaddr, true);
|
|
|
+
|
|
|
+ /* Set the HW DMA mode and the COE */
|
|
|
+ stmmac_dma_operation_mode(priv);
|
|
|
+
|
|
|
+ stmmac_mmc_setup(priv);
|
|
|
+
|
|
|
+ ret = stmmac_init_ptp(priv);
|
|
|
+ if (ret)
|
|
|
+ pr_warn("%s: failed PTP initialisation\n", __func__);
|
|
|
+
|
|
|
+#ifdef CONFIG_STMMAC_DEBUG_FS
|
|
|
+ ret = stmmac_init_fs(dev);
|
|
|
+ if (ret < 0)
|
|
|
+ pr_warn("%s: failed debugFS registration\n", __func__);
|
|
|
+#endif
|
|
|
+ /* Start the ball rolling... */
|
|
|
+ pr_debug("%s: DMA RX/TX processes started...\n", dev->name);
|
|
|
+ priv->hw->dma->start_tx(priv->ioaddr);
|
|
|
+ priv->hw->dma->start_rx(priv->ioaddr);
|
|
|
+
|
|
|
+ /* Dump DMA/MAC registers */
|
|
|
+ if (netif_msg_hw(priv)) {
|
|
|
+ priv->hw->mac->dump_regs(priv->ioaddr);
|
|
|
+ priv->hw->dma->dump_regs(priv->ioaddr);
|
|
|
+ }
|
|
|
+ priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
|
|
|
+
|
|
|
+ priv->eee_enabled = stmmac_eee_init(priv);
|
|
|
+
|
|
|
+ stmmac_init_tx_coalesce(priv);
|
|
|
+
|
|
|
+ if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
|
|
|
+ priv->rx_riwt = MAX_DMA_RIWT;
|
|
|
+ priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (priv->pcs && priv->hw->mac->ctrl_ane)
|
|
|
+ priv->hw->mac->ctrl_ane(priv->ioaddr, 0);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* stmmac_open - open entry point of the driver
|
|
|
* @dev : pointer to the device structure.
|
|
@@ -1616,33 +1694,29 @@ static int stmmac_open(struct net_device *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /* Extra statistics */
|
|
|
+ memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
|
|
|
+ priv->xstats.threshold = tc;
|
|
|
+
|
|
|
/* Create and initialize the TX/RX descriptors chains. */
|
|
|
priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
|
|
|
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
|
|
|
priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
|
|
|
|
|
|
- ret = init_dma_desc_rings(dev);
|
|
|
+ alloc_dma_desc_resources(priv);
|
|
|
if (ret < 0) {
|
|
|
- pr_err("%s: DMA descriptors initialization failed\n", __func__);
|
|
|
+ pr_err("%s: DMA descriptors allocation failed\n", __func__);
|
|
|
goto dma_desc_error;
|
|
|
}
|
|
|
|
|
|
- /* DMA initialization and SW reset */
|
|
|
- ret = stmmac_init_dma_engine(priv);
|
|
|
+ ret = stmmac_hw_setup(dev);
|
|
|
if (ret < 0) {
|
|
|
- pr_err("%s: DMA engine initialization failed\n", __func__);
|
|
|
+ pr_err("%s: Hw setup failed\n", __func__);
|
|
|
goto init_error;
|
|
|
}
|
|
|
|
|
|
- /* Copy the MAC addr into the HW */
|
|
|
- priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
|
|
|
-
|
|
|
- /* If required, perform hw setup of the bus. */
|
|
|
- if (priv->plat->bus_setup)
|
|
|
- priv->plat->bus_setup(priv->ioaddr);
|
|
|
-
|
|
|
- /* Initialize the MAC Core */
|
|
|
- priv->hw->mac->core_init(priv->ioaddr);
|
|
|
+ if (priv->phydev)
|
|
|
+ phy_start(priv->phydev);
|
|
|
|
|
|
/* Request the IRQ lines */
|
|
|
ret = request_irq(dev->irq, stmmac_interrupt,
|
|
@@ -1675,55 +1749,6 @@ static int stmmac_open(struct net_device *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* Enable the MAC Rx/Tx */
|
|
|
- stmmac_set_mac(priv->ioaddr, true);
|
|
|
-
|
|
|
- /* Set the HW DMA mode and the COE */
|
|
|
- stmmac_dma_operation_mode(priv);
|
|
|
-
|
|
|
- /* Extra statistics */
|
|
|
- memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
|
|
|
- priv->xstats.threshold = tc;
|
|
|
-
|
|
|
- stmmac_mmc_setup(priv);
|
|
|
-
|
|
|
- ret = stmmac_init_ptp(priv);
|
|
|
- if (ret)
|
|
|
- pr_warn("%s: failed PTP initialisation\n", __func__);
|
|
|
-
|
|
|
-#ifdef CONFIG_STMMAC_DEBUG_FS
|
|
|
- ret = stmmac_init_fs(dev);
|
|
|
- if (ret < 0)
|
|
|
- pr_warn("%s: failed debugFS registration\n", __func__);
|
|
|
-#endif
|
|
|
- /* Start the ball rolling... */
|
|
|
- pr_debug("%s: DMA RX/TX processes started...\n", dev->name);
|
|
|
- priv->hw->dma->start_tx(priv->ioaddr);
|
|
|
- priv->hw->dma->start_rx(priv->ioaddr);
|
|
|
-
|
|
|
- /* Dump DMA/MAC registers */
|
|
|
- if (netif_msg_hw(priv)) {
|
|
|
- priv->hw->mac->dump_regs(priv->ioaddr);
|
|
|
- priv->hw->dma->dump_regs(priv->ioaddr);
|
|
|
- }
|
|
|
-
|
|
|
- if (priv->phydev)
|
|
|
- phy_start(priv->phydev);
|
|
|
-
|
|
|
- priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
|
|
|
-
|
|
|
- priv->eee_enabled = stmmac_eee_init(priv);
|
|
|
-
|
|
|
- stmmac_init_tx_coalesce(priv);
|
|
|
-
|
|
|
- if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
|
|
|
- priv->rx_riwt = MAX_DMA_RIWT;
|
|
|
- priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
|
|
|
- }
|
|
|
-
|
|
|
- if (priv->pcs && priv->hw->mac->ctrl_ane)
|
|
|
- priv->hw->mac->ctrl_ane(priv->ioaddr, 0);
|
|
|
-
|
|
|
napi_enable(&priv->napi);
|
|
|
netif_start_queue(dev);
|
|
|
|
|
@@ -2295,6 +2320,9 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
|
|
|
struct net_device *dev = (struct net_device *)dev_id;
|
|
|
struct stmmac_priv *priv = netdev_priv(dev);
|
|
|
|
|
|
+ if (priv->irq_wake)
|
|
|
+ pm_wakeup_event(priv->device, 0);
|
|
|
+
|
|
|
if (unlikely(!dev)) {
|
|
|
pr_err("%s: invalid dev pointer\n", __func__);
|
|
|
return IRQ_NONE;
|
|
@@ -2836,10 +2864,12 @@ int stmmac_suspend(struct net_device *ndev)
|
|
|
stmmac_clear_descriptors(priv);
|
|
|
|
|
|
/* Enable Power down mode by programming the PMT regs */
|
|
|
- if (device_may_wakeup(priv->device))
|
|
|
+ if (device_may_wakeup(priv->device)) {
|
|
|
priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
|
|
|
- else {
|
|
|
+ priv->irq_wake = 1;
|
|
|
+ } else {
|
|
|
stmmac_set_mac(priv->ioaddr, false);
|
|
|
+ pinctrl_pm_select_sleep_state(priv->device);
|
|
|
/* Disable clock in case of PWM is off */
|
|
|
clk_disable_unprepare(priv->stmmac_clk);
|
|
|
}
|
|
@@ -2863,18 +2893,21 @@ int stmmac_resume(struct net_device *ndev)
|
|
|
* this bit because it can generate problems while resuming
|
|
|
* from another devices (e.g. serial console).
|
|
|
*/
|
|
|
- if (device_may_wakeup(priv->device))
|
|
|
+ if (device_may_wakeup(priv->device)) {
|
|
|
priv->hw->mac->pmt(priv->ioaddr, 0);
|
|
|
- else
|
|
|
+ priv->irq_wake = 0;
|
|
|
+ } else {
|
|
|
+ pinctrl_pm_select_default_state(priv->device);
|
|
|
/* enable the clk prevously disabled */
|
|
|
clk_prepare_enable(priv->stmmac_clk);
|
|
|
+ /* reset the phy so that it's ready */
|
|
|
+ if (priv->mii)
|
|
|
+ stmmac_mdio_reset(priv->mii);
|
|
|
+ }
|
|
|
|
|
|
netif_device_attach(ndev);
|
|
|
|
|
|
- /* Enable the MAC and DMA */
|
|
|
- stmmac_set_mac(priv->ioaddr, true);
|
|
|
- priv->hw->dma->start_tx(priv->ioaddr);
|
|
|
- priv->hw->dma->start_rx(priv->ioaddr);
|
|
|
+ stmmac_hw_setup(ndev);
|
|
|
|
|
|
napi_enable(&priv->napi);
|
|
|
|
|
@@ -2887,22 +2920,6 @@ int stmmac_resume(struct net_device *ndev)
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
-
|
|
|
-int stmmac_freeze(struct net_device *ndev)
|
|
|
-{
|
|
|
- if (!ndev || !netif_running(ndev))
|
|
|
- return 0;
|
|
|
-
|
|
|
- return stmmac_release(ndev);
|
|
|
-}
|
|
|
-
|
|
|
-int stmmac_restore(struct net_device *ndev)
|
|
|
-{
|
|
|
- if (!ndev || !netif_running(ndev))
|
|
|
- return 0;
|
|
|
-
|
|
|
- return stmmac_open(ndev);
|
|
|
-}
|
|
|
#endif /* CONFIG_PM */
|
|
|
|
|
|
/* Driver can be configured w/ and w/ both PCI and Platf drivers
|