aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-07-25 21:51:44 -0700
committerDavid S. Miller <davem@davemloft.net>2016-07-25 21:51:44 -0700
commitee591f46a5a0ca0caaeb72b79ec5e012c6e3c9ef (patch)
treeed3f955b3ce6ab5c4170b7c16a56915ef775c5c9 /drivers/net/ethernet/apm/xgene/xgene_enet_main.c
parentMerge branch 'refactor-tc_action-structs' (diff)
parentMAINTAINERS: xgene: Add driver and documentation path (diff)
downloadlinux-dev-ee591f46a5a0ca0caaeb72b79ec5e012c6e3c9ef.tar.xz
linux-dev-ee591f46a5a0ca0caaeb72b79ec5e012c6e3c9ef.zip
Merge branch 'xgene-fix-mod-crash-and-1g-hotplug'
Iyappan Subramanian says: ==================== drivers: net: xgene: Fix module crash and 1G hot-plug This patchset addresses the following issues, 1. Fixes the kernel crash when the driver loaded as an kernel module - by fixing hardware cleanups and rearrange kernel API calls 2. Hot-plug issue on the SGMII 1G interface - by adding a driver for MDIO management Signed-off-by: Iyappan Subramanian <isubramanian@apm.com> Tested-by: Fushen Chen <fchen@apm.com> Tested-by: Toan Le <toanle@apm.com> --- v7: Address review comments from v6 - fixed kbuild warnings - unmapped DMA memory on xgene_enet_delete_bufpool() - delete descriptor rings and buffer pools on cle_init() failure - fixed error deconstruction path on probe v6: Address review comments from v5 - changed to use devm_ioremap_resource - changed to return PTR_ERR(clk) on failure - cleaned up and removed indirections - exported mdio read/write and phy_register functions - changed mii_bus is to indicate interface instance - changed to call the exported mdio read/write and phy_register functions v5: Address review comments from v4 - Fixed clock reset sequence by adding delay - Fixed clock count by adding clk_unprepare_disable() in port shutdown v4: Address review comments from v3 - Reorganized into smaller patches - Added wrapper functions for sgmii_control_reset and sgmii_tbi_control_reset - Removed clk_get warning info - mdio: Changed the order of 'if' statements and removed the 'else' statement - mdio: Removed the mdio_read(write) indirection wrapper functions - ethtool: Fixed SGMII 1G get_settings and set_settings - Documentation: dtb: Added MDIO node information - MAINTAINERS: Added MDIO driver and documentation path v3: Address review comments from v2 - Add comment about hardware clock reset sequence on xgene_mdio_reset v2: Address review comments from v1 - Fixed patch 1 compilation error - Fixed mdio@1f610000 xge0clk reference - Squashed dtb patches - Added PORT_OFFSET macro v1: - Initial version ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/apm/xgene/xgene_enet_main.c')
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c215
1 files changed, 128 insertions, 87 deletions
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index d208b172f4d7..d1d6b5eeb613 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -102,25 +102,13 @@ static u8 xgene_enet_hdr_len(const void *data)
static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
{
- struct xgene_enet_pdata *pdata = netdev_priv(buf_pool->ndev);
- struct xgene_enet_raw_desc16 *raw_desc;
- u32 slots = buf_pool->slots - 1;
- u32 tail = buf_pool->tail;
- u32 userinfo;
- int i, len;
-
- len = pdata->ring_ops->len(buf_pool);
- for (i = 0; i < len; i++) {
- tail = (tail - 1) & slots;
- raw_desc = &buf_pool->raw_desc16[tail];
+ int i;
- /* Hardware stores descriptor in little endian format */
- userinfo = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
- dev_kfree_skb_any(buf_pool->rx_skb[userinfo]);
+ /* Free up the buffers held by hardware */
+ for (i = 0; i < buf_pool->slots; i++) {
+ if (buf_pool->rx_skb[i])
+ dev_kfree_skb_any(buf_pool->rx_skb[i]);
}
-
- pdata->ring_ops->wr_cmd(buf_pool, -len);
- buf_pool->tail = tail;
}
static irqreturn_t xgene_enet_rx_irq(const int irq, void *data)
@@ -481,6 +469,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE);
skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
skb = buf_pool->rx_skb[skb_index];
+ buf_pool->rx_skb[skb_index] = NULL;
/* checking for error */
status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) ||
@@ -619,6 +608,30 @@ static void xgene_enet_timeout(struct net_device *ndev)
}
}
+static void xgene_enet_set_irq_name(struct net_device *ndev)
+{
+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+ struct xgene_enet_desc_ring *ring;
+ int i;
+
+ for (i = 0; i < pdata->rxq_cnt; i++) {
+ ring = pdata->rx_ring[i];
+ if (!pdata->cq_cnt) {
+ snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc",
+ ndev->name);
+ } else {
+ snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-rx-%d",
+ ndev->name, i);
+ }
+ }
+
+ for (i = 0; i < pdata->cq_cnt; i++) {
+ ring = pdata->tx_ring[i]->cp_ring;
+ snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-txc-%d",
+ ndev->name, i);
+ }
+}
+
static int xgene_enet_register_irq(struct net_device *ndev)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
@@ -626,6 +639,7 @@ static int xgene_enet_register_irq(struct net_device *ndev)
struct xgene_enet_desc_ring *ring;
int ret = 0, i;
+ xgene_enet_set_irq_name(ndev);
for (i = 0; i < pdata->rxq_cnt; i++) {
ring = pdata->rx_ring[i];
irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
@@ -720,20 +734,21 @@ static int xgene_enet_open(struct net_device *ndev)
if (ret)
return ret;
- mac_ops->tx_enable(pdata);
- mac_ops->rx_enable(pdata);
-
xgene_enet_napi_enable(pdata);
ret = xgene_enet_register_irq(ndev);
if (ret)
return ret;
- if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ if (pdata->phy_dev) {
phy_start(pdata->phy_dev);
- else
+ } else {
schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF);
+ netif_carrier_off(ndev);
+ }
- netif_start_queue(ndev);
+ mac_ops->tx_enable(pdata);
+ mac_ops->rx_enable(pdata);
+ netif_tx_start_all_queues(ndev);
return ret;
}
@@ -744,16 +759,15 @@ static int xgene_enet_close(struct net_device *ndev)
const struct xgene_mac_ops *mac_ops = pdata->mac_ops;
int i;
- netif_stop_queue(ndev);
+ netif_tx_stop_all_queues(ndev);
+ mac_ops->tx_disable(pdata);
+ mac_ops->rx_disable(pdata);
- if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ if (pdata->phy_dev)
phy_stop(pdata->phy_dev);
else
cancel_delayed_work_sync(&pdata->link_work);
- mac_ops->tx_disable(pdata);
- mac_ops->rx_disable(pdata);
-
xgene_enet_free_irq(ndev);
xgene_enet_napi_disable(pdata);
for (i = 0; i < pdata->rxq_cnt; i++)
@@ -761,7 +775,6 @@ static int xgene_enet_close(struct net_device *ndev)
return 0;
}
-
static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
{
struct xgene_enet_pdata *pdata;
@@ -771,7 +784,7 @@ static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
dev = ndev_to_dev(ring->ndev);
pdata->ring_ops->clear(ring);
- dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
+ dmam_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
}
static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
@@ -784,6 +797,9 @@ static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
ring = pdata->tx_ring[i];
if (ring) {
xgene_enet_delete_ring(ring);
+ pdata->port_ops->clear(pdata, ring);
+ if (pdata->cq_cnt)
+ xgene_enet_delete_ring(ring->cp_ring);
pdata->tx_ring[i] = NULL;
}
}
@@ -794,6 +810,7 @@ static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
buf_pool = ring->buf_pool;
xgene_enet_delete_bufpool(buf_pool);
xgene_enet_delete_ring(buf_pool);
+ pdata->port_ops->clear(pdata, buf_pool);
xgene_enet_delete_ring(ring);
pdata->rx_ring[i] = NULL;
}
@@ -842,7 +859,7 @@ static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring)
if (ring->desc_addr) {
pdata->ring_ops->clear(ring);
- dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
+ dmam_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
}
devm_kfree(dev, ring);
}
@@ -900,9 +917,10 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
struct net_device *ndev, u32 ring_num,
enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id)
{
- struct xgene_enet_desc_ring *ring;
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct device *dev = ndev_to_dev(ndev);
+ struct xgene_enet_desc_ring *ring;
+ void *irq_mbox_addr;
int size;
size = xgene_enet_get_ring_size(dev, cfgsize);
@@ -919,8 +937,8 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
ring->cfgsize = cfgsize;
ring->id = ring_id;
- ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma,
- GFP_KERNEL);
+ ring->desc_addr = dmam_alloc_coherent(dev, size, &ring->dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!ring->desc_addr) {
devm_kfree(dev, ring);
return NULL;
@@ -928,14 +946,16 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
ring->size = size;
if (is_irq_mbox_required(pdata, ring)) {
- ring->irq_mbox_addr = dma_zalloc_coherent(dev, INTR_MBOX_SIZE,
- &ring->irq_mbox_dma, GFP_KERNEL);
- if (!ring->irq_mbox_addr) {
- dma_free_coherent(dev, size, ring->desc_addr,
- ring->dma);
+ irq_mbox_addr = dmam_alloc_coherent(dev, INTR_MBOX_SIZE,
+ &ring->irq_mbox_dma,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!irq_mbox_addr) {
+ dmam_free_coherent(dev, size, ring->desc_addr,
+ ring->dma);
devm_kfree(dev, ring);
return NULL;
}
+ ring->irq_mbox_addr = irq_mbox_addr;
}
ring->cmd_base = xgene_enet_ring_cmd_base(pdata, ring);
@@ -996,6 +1016,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
u8 eth_bufnum = pdata->eth_bufnum;
u8 bp_bufnum = pdata->bp_bufnum;
u16 ring_num = pdata->ring_num;
+ __le64 *exp_bufs;
u16 ring_id;
int i, ret, size;
@@ -1027,13 +1048,6 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
rx_ring->nbufpool = NUM_BUFPOOL;
rx_ring->buf_pool = buf_pool;
rx_ring->irq = pdata->irqs[i];
- if (!pdata->cq_cnt) {
- snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc",
- ndev->name);
- } else {
- snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx%d",
- ndev->name, i);
- }
buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots,
sizeof(struct sk_buff *),
GFP_KERNEL);
@@ -1060,13 +1074,13 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
}
size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS;
- tx_ring->exp_bufs = dma_zalloc_coherent(dev, size,
- &dma_exp_bufs,
- GFP_KERNEL);
- if (!tx_ring->exp_bufs) {
+ exp_bufs = dmam_alloc_coherent(dev, size, &dma_exp_bufs,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!exp_bufs) {
ret = -ENOMEM;
goto err;
}
+ tx_ring->exp_bufs = exp_bufs;
pdata->tx_ring[i] = tx_ring;
@@ -1086,8 +1100,6 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
cp_ring->irq = pdata->irqs[pdata->rxq_cnt + i];
cp_ring->index = i;
- snprintf(cp_ring->irq_name, IRQ_ID_SIZE, "%s-txc%d",
- ndev->name, i);
}
cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots,
@@ -1283,6 +1295,23 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata)
return 0;
}
+static int xgene_enet_check_phy_handle(struct xgene_enet_pdata *pdata)
+{
+ int ret;
+
+ if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII)
+ return 0;
+
+ if (!IS_ENABLED(CONFIG_MDIO_XGENE))
+ return 0;
+
+ ret = xgene_enet_phy_connect(pdata->ndev);
+ if (!ret)
+ pdata->mdio_driver = true;
+
+ return 0;
+}
+
static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
{
struct platform_device *pdev;
@@ -1368,6 +1397,10 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
if (ret)
return ret;
+ ret = xgene_enet_check_phy_handle(pdata);
+ if (ret)
+ return ret;
+
pdata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pdata->clk)) {
/* Firmware may have set up the clock already. */
@@ -1447,6 +1480,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
}
+ pdata->phy_speed = SPEED_UNKNOWN;
pdata->mac_ops->init(pdata);
return ret;
@@ -1556,28 +1590,12 @@ static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata)
}
}
-static void xgene_enet_napi_del(struct xgene_enet_pdata *pdata)
-{
- struct napi_struct *napi;
- int i;
-
- for (i = 0; i < pdata->rxq_cnt; i++) {
- napi = &pdata->rx_ring[i]->napi;
- netif_napi_del(napi);
- }
-
- for (i = 0; i < pdata->cq_cnt; i++) {
- napi = &pdata->tx_ring[i]->cp_ring->napi;
- netif_napi_del(napi);
- }
-}
-
static int xgene_enet_probe(struct platform_device *pdev)
{
struct net_device *ndev;
struct xgene_enet_pdata *pdata;
struct device *dev = &pdev->dev;
- const struct xgene_mac_ops *mac_ops;
+ void (*link_state)(struct work_struct *);
const struct of_device_id *of_id;
int ret;
@@ -1635,27 +1653,31 @@ static int xgene_enet_probe(struct platform_device *pdev)
goto err;
}
- ret = register_netdev(ndev);
- if (ret) {
- netdev_err(ndev, "Failed to register netdev\n");
- goto err;
- }
-
ret = xgene_enet_init_hw(pdata);
if (ret)
goto err_netdev;
- mac_ops = pdata->mac_ops;
- if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
- ret = xgene_enet_mdio_config(pdata);
- if (ret)
- goto err_netdev;
- } else {
- INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state);
+ link_state = pdata->mac_ops->link_state;
+ if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+ INIT_DELAYED_WORK(&pdata->link_work, link_state);
+ } else if (!pdata->mdio_driver) {
+ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ ret = xgene_enet_mdio_config(pdata);
+ else
+ INIT_DELAYED_WORK(&pdata->link_work, link_state);
}
+ if (ret)
+ goto err;
xgene_enet_napi_add(pdata);
+ ret = register_netdev(ndev);
+ if (ret) {
+ netdev_err(ndev, "Failed to register netdev\n");
+ goto err;
+ }
+
return 0;
+
err_netdev:
unregister_netdev(ndev);
err:
@@ -1673,20 +1695,38 @@ static int xgene_enet_remove(struct platform_device *pdev)
mac_ops = pdata->mac_ops;
ndev = pdata->ndev;
- mac_ops->rx_disable(pdata);
- mac_ops->tx_disable(pdata);
+ rtnl_lock();
+ if (netif_running(ndev))
+ dev_close(ndev);
+ rtnl_unlock();
- xgene_enet_napi_del(pdata);
- if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ if (pdata->mdio_driver)
+ xgene_enet_phy_disconnect(pdata);
+ else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
xgene_enet_mdio_remove(pdata);
+
unregister_netdev(ndev);
- xgene_enet_delete_desc_rings(pdata);
pdata->port_ops->shutdown(pdata);
+ xgene_enet_delete_desc_rings(pdata);
free_netdev(ndev);
return 0;
}
+static void xgene_enet_shutdown(struct platform_device *pdev)
+{
+ struct xgene_enet_pdata *pdata;
+
+ pdata = platform_get_drvdata(pdev);
+ if (!pdata)
+ return;
+
+ if (!pdata->ndev)
+ return;
+
+ xgene_enet_remove(pdev);
+}
+
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_enet_acpi_match[] = {
{ "APMC0D05", XGENE_ENET1},
@@ -1721,6 +1761,7 @@ static struct platform_driver xgene_enet_driver = {
},
.probe = xgene_enet_probe,
.remove = xgene_enet_remove,
+ .shutdown = xgene_enet_shutdown,
};
module_platform_driver(xgene_enet_driver);