From 9a8c5ddedd9805cf52744ef6bdf591326684f88c Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:36 -0700 Subject: drivers: net: xgene: Separate set_speed from mac_init Since mac_init is too heavy to be called when the link changes, moved the speed_set configuration to a new function and added mac_ops->set_speed function pointer. This function will be called from adjust_link callback. Added cases for 10/100 support for SGMII based 1G interface. Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 30 +++-- drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 2 + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 6 +- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 135 +++++++++++++++++++--- drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h | 7 ++ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 3 + 7 files changed, 151 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2f5638f7f864..725109b964c3 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -512,14 +512,11 @@ static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) #endif } -static void xgene_gmac_init(struct xgene_enet_pdata *pdata) +static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; - u32 value, mc2; - u32 intf_ctl, rgmii; - u32 icm0, icm2; - - xgene_gmac_reset(pdata); + u32 icm0, icm2, mc2; + u32 intf_ctl, rgmii, value; xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); @@ -564,7 +561,19 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) mc2 |= FULL_DUPLEX2 | PAD_CRC; xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); + xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); + xgene_enet_configure_clock(pdata); + + xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); + xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); +} +static void xgene_gmac_init(struct xgene_enet_pdata *pdata) +{ + u32 value; + + xgene_gmac_reset(pdata); + xgene_gmac_set_speed(pdata); xgene_gmac_set_mac_addr(pdata); /* Adjust MDC clock frequency */ @@ -579,15 +588,10 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) /* Rtype should be copied from FP */ xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); - xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); - xgene_enet_configure_clock(pdata); /* Rx-Tx traffic resume */ xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); - xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); - xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); - xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); value &= ~TX_DV_GATE_EN0; value &= ~RX_DV_GATE_EN0; @@ -724,12 +728,13 @@ static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, static void xgene_enet_adjust_link(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); + const struct xgene_mac_ops *mac_ops = pdata->mac_ops; struct phy_device *phydev = pdata->phy_dev; if (phydev->link) { if (pdata->phy_speed != phydev->speed) { pdata->phy_speed = phydev->speed; - xgene_gmac_init(pdata); + mac_ops->set_speed(pdata); xgene_gmac_rx_enable(pdata); xgene_gmac_tx_enable(pdata); phy_print_status(phydev); @@ -890,6 +895,7 @@ const struct xgene_mac_ops xgene_gmac_ops = { .tx_enable = xgene_gmac_tx_enable, .rx_disable = xgene_gmac_rx_disable, .tx_disable = xgene_gmac_tx_disable, + .set_speed = xgene_gmac_set_speed, .set_mac_addr = xgene_gmac_set_mac_addr, }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 45220be3122f..e840f9633734 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -104,6 +104,8 @@ enum xgene_enet_rm { #define RECOMBBUF BIT(27) #define MAC_OFFSET 0x30 +#define OFFSET_4 0x04 +#define OFFSET_8 0x08 #define BLOCK_ETH_CSR_OFFSET 0x2000 #define BLOCK_ETH_CLE_CSR_OFFSET 0x6000 diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index d208b172f4d7..8da3860691ee 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -730,8 +730,10 @@ static int xgene_enet_open(struct net_device *ndev) if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) 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); @@ -761,7 +763,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; @@ -1447,6 +1448,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; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 092fbeccaa20..aed9f430e0bc 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -140,6 +140,7 @@ struct xgene_mac_ops { void (*rx_enable)(struct xgene_enet_pdata *pdata); void (*tx_disable)(struct xgene_enet_pdata *pdata); void (*rx_disable)(struct xgene_enet_pdata *pdata); + void (*set_speed)(struct xgene_enet_pdata *pdata); void (*set_mac_addr)(struct xgene_enet_pdata *pdata); void (*set_mss)(struct xgene_enet_pdata *pdata); void (*link_state)(struct work_struct *work); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index 78475512b683..a3063fd7681f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -93,6 +93,11 @@ static u32 xgene_enet_rd_diag_csr(struct xgene_enet_pdata *p, u32 offset) return ioread32(p->eth_diag_csr_addr + offset); } +static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset) +{ + return ioread32(p->mcx_mac_csr_addr + offset); +} + static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) { u32 rd_data; @@ -230,21 +235,105 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *p) data = xgene_mii_phy_read(p, INT_PHY_ADDR, SGMII_BASE_PAGE_ABILITY_ADDR >> 2); + if (LINK_SPEED(data) == PHY_SPEED_1000) + p->phy_speed = SPEED_1000; + else if (LINK_SPEED(data) == PHY_SPEED_100) + p->phy_speed = SPEED_100; + else + p->phy_speed = SPEED_10; + return data & LINK_UP; } -static void xgene_sgmac_init(struct xgene_enet_pdata *p) +static void xgene_sgmii_configure(struct xgene_enet_pdata *p) { - u32 data, loop = 10; - u32 offset = p->port_id * 4; - u32 enet_spare_cfg_reg, rsif_config_reg; - u32 cfg_bypass_reg, rx_dv_gate_reg; - - xgene_sgmac_reset(p); + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, + 0x8000); + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x9000); + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); +} - /* Enable auto-negotiation */ - xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000); +static void xgene_sgmii_tbi_control_reset(struct xgene_enet_pdata *p) +{ + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, + 0x8000); xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); +} + +static void xgene_sgmii_reset(struct xgene_enet_pdata *p) +{ + u32 value; + + if (p->phy_speed == SPEED_UNKNOWN) + return; + + value = xgene_mii_phy_read(p, INT_PHY_ADDR, + SGMII_BASE_PAGE_ABILITY_ADDR >> 2); + if (!(value & LINK_UP)) + xgene_sgmii_tbi_control_reset(p); +} + +static void xgene_sgmac_set_speed(struct xgene_enet_pdata *p) +{ + u32 icm0_addr, icm2_addr, debug_addr; + u32 icm0, icm2, intf_ctl; + u32 mc2, value; + + xgene_sgmii_reset(p); + + if (p->enet_id == XGENE_ENET1) { + icm0_addr = ICM_CONFIG0_REG_0_ADDR + p->port_id * OFFSET_8; + icm2_addr = ICM_CONFIG2_REG_0_ADDR + p->port_id * OFFSET_4; + debug_addr = DEBUG_REG_ADDR; + } else { + icm0_addr = XG_MCX_ICM_CONFIG0_REG_0_ADDR; + icm2_addr = XG_MCX_ICM_CONFIG2_REG_0_ADDR; + debug_addr = XG_DEBUG_REG_ADDR; + } + + icm0 = xgene_enet_rd_mcx_csr(p, icm0_addr); + icm2 = xgene_enet_rd_mcx_csr(p, icm2_addr); + mc2 = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); + intf_ctl = xgene_enet_rd_mac(p, INTERFACE_CONTROL_ADDR); + + switch (p->phy_speed) { + case SPEED_10: + ENET_INTERFACE_MODE2_SET(&mc2, 1); + intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE); + CFG_MACMODE_SET(&icm0, 0); + CFG_WAITASYNCRD_SET(&icm2, 500); + break; + case SPEED_100: + ENET_INTERFACE_MODE2_SET(&mc2, 1); + intf_ctl &= ~ENET_GHD_MODE; + intf_ctl |= ENET_LHD_MODE; + CFG_MACMODE_SET(&icm0, 1); + CFG_WAITASYNCRD_SET(&icm2, 80); + break; + default: + ENET_INTERFACE_MODE2_SET(&mc2, 2); + intf_ctl &= ~ENET_LHD_MODE; + intf_ctl |= ENET_GHD_MODE; + CFG_MACMODE_SET(&icm0, 2); + CFG_WAITASYNCRD_SET(&icm2, 16); + value = xgene_enet_rd_csr(p, debug_addr); + value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; + xgene_enet_wr_csr(p, debug_addr, value); + break; + } + + mc2 |= FULL_DUPLEX2 | PAD_CRC; + xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, mc2); + xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, intf_ctl); + xgene_enet_wr_mcx_csr(p, icm0_addr, icm0); + xgene_enet_wr_mcx_csr(p, icm2_addr, icm2); +} + +static void xgene_sgmii_enable_autoneg(struct xgene_enet_pdata *p) +{ + u32 data, loop = 10; + + xgene_sgmii_configure(p); while (loop--) { data = xgene_mii_phy_read(p, INT_PHY_ADDR, @@ -255,17 +344,25 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) } if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS)) netdev_err(p->ndev, "Auto-negotiation failed\n"); +} - data = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); - ENET_INTERFACE_MODE2_SET(&data, 2); - xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2); - xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE); +static void xgene_sgmac_init(struct xgene_enet_pdata *p) +{ + u32 enet_spare_cfg_reg, rsif_config_reg; + u32 cfg_bypass_reg, rx_dv_gate_reg; + u32 data, offset; + + xgene_sgmac_reset(p); + xgene_sgmii_enable_autoneg(p); + xgene_sgmac_set_speed(p); + xgene_sgmac_set_mac_addr(p); if (p->enet_id == XGENE_ENET1) { enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR; rsif_config_reg = RSIF_CONFIG_REG_ADDR; cfg_bypass_reg = CFG_BYPASS_ADDR; - rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR; + offset = p->port_id * OFFSET_4; + rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR + offset; } else { enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR; rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR; @@ -277,8 +374,6 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) data |= MPA_IDLE_WITH_QMI_EMPTY; xgene_enet_wr_csr(p, enet_spare_cfg_reg, data); - xgene_sgmac_set_mac_addr(p); - /* Adjust MDC clock frequency */ data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR); MGMT_CLOCK_SEL_SET(&data, 7); @@ -292,7 +387,7 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) /* Bypass traffic gating */ xgene_enet_wr_csr(p, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x84); xgene_enet_wr_csr(p, cfg_bypass_reg, RESUME_TX); - xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg + offset, RESUME_RX0); + xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg, RESUME_RX0); } static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set) @@ -386,10 +481,11 @@ static void xgene_enet_link_state(struct work_struct *work) if (link) { if (!netif_carrier_ok(ndev)) { netif_carrier_on(ndev); - xgene_sgmac_init(p); + xgene_sgmac_set_speed(p); xgene_sgmac_rx_enable(p); xgene_sgmac_tx_enable(p); - netdev_info(ndev, "Link is Up - 1Gbps\n"); + netdev_info(ndev, "Link is Up - %dMbps\n", + p->phy_speed); } poll_interval = PHY_POLL_LINK_ON; } else { @@ -412,6 +508,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = { .tx_enable = xgene_sgmac_tx_enable, .rx_disable = xgene_sgmac_rx_disable, .tx_disable = xgene_sgmac_tx_disable, + .set_speed = xgene_sgmac_set_speed, .set_mac_addr = xgene_sgmac_set_mac_addr, .link_state = xgene_enet_link_state }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h index 002df5a6756e..32f140ab49d8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h @@ -24,6 +24,7 @@ #define PHY_ADDR(src) (((src)<<8) & GENMASK(12, 8)) #define REG_ADDR(src) ((src) & GENMASK(4, 0)) #define PHY_CONTROL(src) ((src) & GENMASK(15, 0)) +#define LINK_SPEED(src) (((src) & GENMASK(11, 10)) >> 10) #define INT_PHY_ADDR 0x1e #define SGMII_TBI_CONTROL_ADDR 0x44 #define SGMII_CONTROL_ADDR 0x00 @@ -35,6 +36,12 @@ #define MPA_IDLE_WITH_QMI_EMPTY BIT(12) #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc +enum xgene_phy_speed { + PHY_SPEED_10, + PHY_SPEED_100, + PHY_SPEED_1000 +}; + extern const struct xgene_mac_ops xgene_sgmac_ops; extern const struct xgene_port_ops xgene_sgport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index 0a2dca8a1725..f1ea485f916b 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -65,9 +65,12 @@ #define XG_CFG_LINK_AGGR_RESUME_0_ADDR 0x0214 #define XG_LINK_STATUS_ADDR 0x0228 #define XG_TSIF_MSS_REG0_ADDR 0x02a4 +#define XG_DEBUG_REG_ADDR 0x0400 #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 +#define XG_MCX_ICM_CONFIG0_REG_0_ADDR 0x00e0 +#define XG_MCX_ICM_CONFIG2_REG_0_ADDR 0x00e8 extern const struct xgene_mac_ops xgene_xgmac_ops; extern const struct xgene_port_ops xgene_xgport_ops; -- cgit v1.2.3-59-g8ed1b From cb11c062f9052c6bde6a5fa18cab1f41d81131b3 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:37 -0700 Subject: drivers: net: xgene: Fix module unload crash - hw resource cleanup When the driver is configured as kernel module and when it gets unloaded and reloaded, kernel crash was observed. This patch address the hardware resource cleanups by doing the following, - Added mac_ops->clear() to do prefetch buffer clean up - Fixed delete freepool buffers logic - Reordered mac_enable and mac_disable - Added Tx completion ring free - Moved down delete_desc_rings after ring cleanup Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 41 ++++++++++++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 2 + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 39 +++++++---------- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 2 + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 52 +++++++++++++++++++++-- drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 42 +++++++++++++++++- 6 files changed, 149 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 725109b964c3..009fb8e401d1 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -697,8 +697,48 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata) return 0; } +static void xgene_enet_clear(struct xgene_enet_pdata *pdata, + struct xgene_enet_desc_ring *ring) +{ + u32 addr, val, data; + + val = xgene_enet_ring_bufnum(ring->id); + + if (xgene_enet_is_bufpool(ring->id)) { + addr = ENET_CFGSSQMIFPRESET_ADDR; + data = BIT(val - 0x20); + } else { + addr = ENET_CFGSSQMIWQRESET_ADDR; + data = BIT(val); + } + + xgene_enet_wr_ring_if(pdata, addr, data); +} + static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) { + struct xgene_enet_desc_ring *ring; + u32 pb, val; + int i; + + pb = 0; + for (i = 0; i < pdata->rxq_cnt; i++) { + ring = pdata->rx_ring[i]->buf_pool; + + val = xgene_enet_ring_bufnum(ring->id); + pb |= BIT(val - 0x20); + } + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); + + pb = 0; + for (i = 0; i < pdata->txq_cnt; i++) { + ring = pdata->tx_ring[i]; + + val = xgene_enet_ring_bufnum(ring->id); + pb |= BIT(val); + } + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); + if (!IS_ERR(pdata->clk)) clk_disable_unprepare(pdata->clk); } @@ -901,6 +941,7 @@ const struct xgene_mac_ops xgene_gmac_ops = { const struct xgene_port_ops xgene_gport_ops = { .reset = xgene_enet_reset, + .clear = xgene_enet_clear, .cle_bypass = xgene_enet_cle_bypass, .shutdown = xgene_gport_shutdown, }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index e840f9633734..eec55c1d41db 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -167,6 +167,8 @@ enum xgene_enet_rm { #define TX_DV_GATE_EN0 BIT(2) #define RX_DV_GATE_EN0 BIT(1) #define RESUME_RX0 BIT(0) +#define ENET_CFGSSQMIFPRESET_ADDR 0x14 +#define ENET_CFGSSQMIWQRESET_ADDR 0x1c #define ENET_CFGSSQMIWQASSOC_ADDR 0xe0 #define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc #define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0 diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 8da3860691ee..f79950ab9277 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) || @@ -720,9 +709,6 @@ 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) @@ -735,6 +721,8 @@ static int xgene_enet_open(struct net_device *ndev) netif_carrier_off(ndev); } + mac_ops->tx_enable(pdata); + mac_ops->rx_enable(pdata); netif_start_queue(ndev); return ret; @@ -747,15 +735,14 @@ static int xgene_enet_close(struct net_device *ndev) int i; netif_stop_queue(ndev); + mac_ops->tx_disable(pdata); + mac_ops->rx_disable(pdata); if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) 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++) @@ -785,6 +772,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; } } @@ -795,6 +785,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; } @@ -1682,8 +1673,8 @@ static int xgene_enet_remove(struct platform_device *pdev) 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; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index aed9f430e0bc..681a47321fd8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -148,6 +148,8 @@ struct xgene_mac_ops { struct xgene_port_ops { int (*reset)(struct xgene_enet_pdata *pdata); + void (*clear)(struct xgene_enet_pdata *pdata, + struct xgene_enet_desc_ring *ring); void (*cle_bypass)(struct xgene_enet_pdata *pdata, u32 dst_ring_num, u16 bufpool_id); void (*shutdown)(struct xgene_enet_pdata *pdata); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index a3063fd7681f..f1477d244660 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -137,9 +137,17 @@ static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr) static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) { struct net_device *ndev = p->ndev; - u32 data; + u32 data, shutdown; int i = 0; + shutdown = xgene_enet_rd_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR); + data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR); + + if (!shutdown && data == ~0U) { + netdev_dbg(ndev, "+ ecc_init done, skipping\n"); + return 0; + } + xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); do { usleep_range(100, 110); @@ -464,10 +472,47 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p, xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data); } +static void xgene_enet_clear(struct xgene_enet_pdata *pdata, + struct xgene_enet_desc_ring *ring) +{ + u32 addr, val, data; + + val = xgene_enet_ring_bufnum(ring->id); + + if (xgene_enet_is_bufpool(ring->id)) { + addr = ENET_CFGSSQMIFPRESET_ADDR; + data = BIT(val - 0x20); + } else { + addr = ENET_CFGSSQMIWQRESET_ADDR; + data = BIT(val); + } + + xgene_enet_wr_ring_if(pdata, addr, data); +} + static void xgene_enet_shutdown(struct xgene_enet_pdata *p) { - if (!IS_ERR(p->clk)) - clk_disable_unprepare(p->clk); + struct xgene_enet_desc_ring *ring; + u32 pb, val; + int i; + + pb = 0; + for (i = 0; i < p->rxq_cnt; i++) { + ring = p->rx_ring[i]->buf_pool; + + val = xgene_enet_ring_bufnum(ring->id); + pb |= BIT(val - 0x20); + } + xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPRESET_ADDR, pb); + + pb = 0; + for (i = 0; i < p->txq_cnt; i++) { + ring = p->tx_ring[i]; + + val = xgene_enet_ring_bufnum(ring->id); + pb |= BIT(val); + } + xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb); } static void xgene_enet_link_state(struct work_struct *work) @@ -515,6 +560,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = { const struct xgene_port_ops xgene_sgport_ops = { .reset = xgene_enet_reset, + .clear = xgene_enet_clear, .cle_bypass = xgene_enet_cle_bypass, .shutdown = xgene_enet_shutdown }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index ba030dc1940b..d0b441934091 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -292,8 +292,45 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) { - if (!IS_ERR(pdata->clk)) - clk_disable_unprepare(pdata->clk); + struct xgene_enet_desc_ring *ring; + u32 pb, val; + int i; + + pb = 0; + for (i = 0; i < pdata->rxq_cnt; i++) { + ring = pdata->rx_ring[i]->buf_pool; + + val = xgene_enet_ring_bufnum(ring->id); + pb |= BIT(val - 0x20); + } + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); + + pb = 0; + for (i = 0; i < pdata->txq_cnt; i++) { + ring = pdata->tx_ring[i]; + + val = xgene_enet_ring_bufnum(ring->id); + pb |= BIT(val); + } + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); +} + +static void xgene_enet_clear(struct xgene_enet_pdata *pdata, + struct xgene_enet_desc_ring *ring) +{ + u32 addr, val, data; + + val = xgene_enet_ring_bufnum(ring->id); + + if (xgene_enet_is_bufpool(ring->id)) { + addr = ENET_CFGSSQMIFPRESET_ADDR; + data = BIT(val - 0x20); + } else { + addr = ENET_CFGSSQMIWQRESET_ADDR; + data = BIT(val); + } + + xgene_enet_wr_ring_if(pdata, addr, data); } static void xgene_enet_link_state(struct work_struct *work) @@ -340,6 +377,7 @@ const struct xgene_mac_ops xgene_xgmac_ops = { const struct xgene_port_ops xgene_xgport_ops = { .reset = xgene_enet_reset, + .clear = xgene_enet_clear, .cle_bypass = xgene_enet_xgcle_bypass, .shutdown = xgene_enet_shutdown, }; -- cgit v1.2.3-59-g8ed1b From cb0366b7c16427a25923350b69f53a5b1345a34b Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:38 -0700 Subject: drivers: net: xgene: Fix module unload crash - change sw sequence When the driver is configured as kernel module and when it gets unloaded and reloaded, kernel crash was observed. This patch addresses the software cleanup by doing the following, - Moved register_netdev call after hardware is ready - Since ndev is not ready, added set_irq_name to set irq name - Since ndev is not ready, changed mdio_bus->parent to pdev->dev - Replaced netif_start(stop)_queue by netif_tx_start(stop)_queues - Removed napi_del call since it's called by free_netdev - Added dev_close call, within remove - Added shutdown callback - Changed to use dmam_ APIs Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 2 +- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 120 ++++++++++++++--------- 2 files changed, 73 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 009fb8e401d1..4f98749d3a24 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -901,7 +901,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) ndev->name); mdio_bus->priv = pdata; - mdio_bus->parent = &ndev->dev; + mdio_bus->parent = &pdata->pdev->dev; ret = xgene_mdiobus_register(pdata, mdio_bus); if (ret) { diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index f79950ab9277..87e592955470 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -608,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); @@ -615,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); @@ -723,7 +748,7 @@ static int xgene_enet_open(struct net_device *ndev) mac_ops->tx_enable(pdata); mac_ops->rx_enable(pdata); - netif_start_queue(ndev); + netif_tx_start_all_queues(ndev); return ret; } @@ -734,7 +759,7 @@ 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); @@ -759,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) @@ -834,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); } @@ -892,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); @@ -911,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; @@ -920,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); @@ -988,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; @@ -1019,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); @@ -1052,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; @@ -1078,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, @@ -1549,22 +1569,6 @@ 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; @@ -1628,12 +1632,6 @@ 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; @@ -1648,7 +1646,14 @@ static int xgene_enet_probe(struct platform_device *pdev) } 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: @@ -1666,10 +1671,14 @@ static int xgene_enet_remove(struct platform_device *pdev) mac_ops = pdata->mac_ops; ndev = pdata->ndev; + rtnl_lock(); + if (netif_running(ndev)) + dev_close(ndev); + rtnl_unlock(); + mac_ops->rx_disable(pdata); mac_ops->tx_disable(pdata); - xgene_enet_napi_del(pdata); if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) xgene_enet_mdio_remove(pdata); unregister_netdev(ndev); @@ -1680,6 +1689,20 @@ static int xgene_enet_remove(struct platform_device *pdev) 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}, @@ -1714,6 +1737,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); -- cgit v1.2.3-59-g8ed1b From bc61167ac816621c94f722177d2ae718c103005f Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:39 -0700 Subject: drivers: net: xgene: Fix module unload crash - clkrst sequence This patch fixes clock reset sequence. - Added clock reset sequence for ACPI - Added delay in clock reset sequence to make sure pulse is generated - Added clk_unprepare_disable() in port shutdown to make sure clock increment/decrement counts are matching - Removed MII_MGMT_CONFIG programming, since it is not required - Fixed programming XGENET_CONFIG_REG to enable SGMII mode Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 34 +++++++++++------ drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 45 ++++++++++++++++++++--- drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 24 +++++++++++- 4 files changed, 86 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 4f98749d3a24..91a67a028548 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -675,24 +675,33 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) static int xgene_enet_reset(struct xgene_enet_pdata *pdata) { - u32 val; + struct device *dev = &pdata->pdev->dev; if (!xgene_ring_mgr_init(pdata)) return -ENODEV; - if (!IS_ERR(pdata->clk)) { + if (dev->of_node) { clk_prepare_enable(pdata->clk); + udelay(5); clk_disable_unprepare(pdata->clk); + udelay(5); clk_prepare_enable(pdata->clk); - xgene_enet_ecc_init(pdata); + udelay(5); + } else { +#ifdef CONFIG_ACPI + if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) { + acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), + "_RST", NULL, NULL); + } else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), + "_INI")) { + acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), + "_INI", NULL, NULL); + } +#endif } - xgene_enet_config_ring_if_assoc(pdata); - /* Enable auto-incr for scanning */ - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); - val |= SCAN_AUTO_INCR; - MGMT_CLOCK_SEL_SET(&val, 1); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); + xgene_enet_ecc_init(pdata); + xgene_enet_config_ring_if_assoc(pdata); return 0; } @@ -717,6 +726,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) { + struct device *dev = &pdata->pdev->dev; struct xgene_enet_desc_ring *ring; u32 pb, val; int i; @@ -739,8 +749,10 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) } xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); - if (!IS_ERR(pdata->clk)) - clk_disable_unprepare(pdata->clk); + if (dev->of_node) { + if (!IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + } } static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index f1477d244660..03a70c58bb9d 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -28,6 +28,12 @@ static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val) iowrite32(val, p->eth_csr_addr + offset); } +static void xgene_enet_wr_clkrst_csr(struct xgene_enet_pdata *p, u32 offset, + u32 val) +{ + iowrite32(val, p->base_addr + offset); +} + static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p, u32 offset, u32 val) { @@ -434,17 +440,38 @@ static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p) static int xgene_enet_reset(struct xgene_enet_pdata *p) { + struct device *dev = &p->pdev->dev; + if (!xgene_ring_mgr_init(p)) return -ENODEV; - if (!IS_ERR(p->clk)) { - clk_prepare_enable(p->clk); - clk_disable_unprepare(p->clk); - clk_prepare_enable(p->clk); + if (p->enet_id == XGENE_ENET2) + xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN); + + if (dev->of_node) { + if (!IS_ERR(p->clk)) { + clk_prepare_enable(p->clk); + udelay(5); + clk_disable_unprepare(p->clk); + udelay(5); + clk_prepare_enable(p->clk); + udelay(5); + } + } else { +#ifdef CONFIG_ACPI + if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_RST")) + acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev), + "_RST", NULL, NULL); + else if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_INI")) + acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev), + "_INI", NULL, NULL); +#endif } - xgene_enet_ecc_init(p); - xgene_enet_config_ring_if_assoc(p); + if (!p->port_id) { + xgene_enet_ecc_init(p); + xgene_enet_config_ring_if_assoc(p); + } return 0; } @@ -492,6 +519,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *p) { + struct device *dev = &p->pdev->dev; struct xgene_enet_desc_ring *ring; u32 pb, val; int i; @@ -513,6 +541,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *p) pb |= BIT(val); } xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb); + + if (dev->of_node) { + if (!IS_ERR(p->clk)) + clk_disable_unprepare(p->clk); + } } static void xgene_enet_link_state(struct work_struct *work) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h index 32f140ab49d8..3d0ba374491b 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h @@ -35,6 +35,7 @@ #define LINK_UP BIT(15) #define MPA_IDLE_WITH_QMI_EMPTY BIT(12) #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc +#define SGMII_EN 0x1 enum xgene_phy_speed { PHY_SPEED_10, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index d0b441934091..9c6ad0dce00f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -258,13 +258,29 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) static int xgene_enet_reset(struct xgene_enet_pdata *pdata) { + struct device *dev = &pdata->pdev->dev; + if (!xgene_ring_mgr_init(pdata)) return -ENODEV; - if (!IS_ERR(pdata->clk)) { + if (dev->of_node) { clk_prepare_enable(pdata->clk); + udelay(5); clk_disable_unprepare(pdata->clk); + udelay(5); clk_prepare_enable(pdata->clk); + udelay(5); + } else { +#ifdef CONFIG_ACPI + if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) { + acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), + "_RST", NULL, NULL); + } else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), + "_INI")) { + acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), + "_INI", NULL, NULL); + } +#endif } xgene_enet_ecc_init(pdata); @@ -292,6 +308,7 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) { + struct device *dev = &pdata->pdev->dev; struct xgene_enet_desc_ring *ring; u32 pb, val; int i; @@ -313,6 +330,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) pb |= BIT(val); } xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); + + if (dev->of_node) { + if (!IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + } } static void xgene_enet_clear(struct xgene_enet_pdata *pdata, -- cgit v1.2.3-59-g8ed1b From 43b3cf6634a4ae2eac3b6f08019db8f19a114811 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:40 -0700 Subject: drivers: net: phy: xgene: Add MDIO driver Currently, SGMII based 1G rely on the hardware registers for link state and sometimes it's not reliable. To get most accurate link state, this interface has to use the MDIO bus to poll the PHY. In X-Gene SoC, MDIO bus is shared across RGMII and SGMII based 1G interfaces, so adding this driver to manage MDIO bus. This driver registers the mdio bus and registers the PHYs connected to it. Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/mdio-xgene.c | 477 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mdio-xgene.h | 143 +++++++++++++ 4 files changed, 627 insertions(+) create mode 100644 drivers/net/phy/mdio-xgene.c create mode 100644 drivers/net/phy/mdio-xgene.h (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 1d7b208b1629..47a64342cc16 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -301,6 +301,12 @@ config MDIO_HISI_FEMAC This module provides a driver for the MDIO busses found in the Hisilicon SoC that have an Fast Ethernet MAC. +config MDIO_XGENE + tristate "APM X-Gene SoC MDIO bus controller" + help + This module provides a driver for the MDIO busses found in the + APM X-Gene SoC's. + endif # PHYLIB config MICREL_KS8995MA diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 19e38a97963a..534dfa74d5a2 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_MICROCHIP_PHY) += microchip.o obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o +obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c new file mode 100644 index 000000000000..d94a978024d9 --- /dev/null +++ b/drivers/net/phy/mdio-xgene.c @@ -0,0 +1,477 @@ +/* Applied Micro X-Gene SoC MDIO Driver + * + * Copyright (c) 2016, Applied Micro Circuits Corporation + * Author: Iyappan Subramanian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdio-xgene.h" + +static bool xgene_mdio_status; + +static u32 xgene_enet_rd_mac(void __iomem *base_addr, u32 rd_addr) +{ + void __iomem *addr, *rd, *cmd, *cmd_done; + u32 done, rd_data = BUSY_MASK; + u8 wait = 10; + + addr = base_addr + MAC_ADDR_REG_OFFSET; + rd = base_addr + MAC_READ_REG_OFFSET; + cmd = base_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; + + iowrite32(rd_addr, addr); + iowrite32(XGENE_ENET_RD_CMD, cmd); + + while (wait--) { + done = ioread32(cmd_done); + if (done) + break; + udelay(1); + } + + if (!done) + return rd_data; + + rd_data = ioread32(rd); + iowrite32(0, cmd); + + return rd_data; +} + +static void xgene_enet_wr_mac(void __iomem *base_addr, u32 wr_addr, u32 wr_data) +{ + void __iomem *addr, *wr, *cmd, *cmd_done; + u8 wait = 10; + u32 done; + + addr = base_addr + MAC_ADDR_REG_OFFSET; + wr = base_addr + MAC_WRITE_REG_OFFSET; + cmd = base_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; + + iowrite32(wr_addr, addr); + iowrite32(wr_data, wr); + iowrite32(XGENE_ENET_WR_CMD, cmd); + + while (wait--) { + done = ioread32(cmd_done); + if (done) + break; + udelay(1); + } + + if (!done) + pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr); + + iowrite32(0, cmd); +} + +int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) +{ + void __iomem *addr = (void __iomem *)bus->priv; + u32 data, done; + u8 wait = 10; + + data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); + xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, data); + xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); + do { + usleep_range(5, 10); + done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); + } while ((done & BUSY_MASK) && wait--); + + if (done & BUSY_MASK) { + dev_err(&bus->dev, "MII_MGMT read failed\n"); + return -EBUSY; + } + + data = xgene_enet_rd_mac(addr, MII_MGMT_STATUS_ADDR); + xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, 0); + + return data; +} +EXPORT_SYMBOL(xgene_mdio_rgmii_read); + +int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data) +{ + void __iomem *addr = (void __iomem *)bus->priv; + u32 val, done; + u8 wait = 10; + + val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); + xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, val); + + xgene_enet_wr_mac(addr, MII_MGMT_CONTROL_ADDR, data); + do { + usleep_range(5, 10); + done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); + } while ((done & BUSY_MASK) && wait--); + + if (done & BUSY_MASK) { + dev_err(&bus->dev, "MII_MGMT write failed\n"); + return -EBUSY; + } + + return 0; +} +EXPORT_SYMBOL(xgene_mdio_rgmii_write); + +static u32 xgene_menet_rd_diag_csr(struct xgene_mdio_pdata *pdata, u32 offset) +{ + return ioread32(pdata->diag_csr_addr + offset); +} + +static void xgene_menet_wr_diag_csr(struct xgene_mdio_pdata *pdata, + u32 offset, u32 val) +{ + iowrite32(val, pdata->diag_csr_addr + offset); +} + +static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata) +{ + u32 data; + u8 wait = 10; + + xgene_menet_wr_diag_csr(pdata, MENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); + do { + usleep_range(100, 110); + data = xgene_menet_rd_diag_csr(pdata, MENET_BLOCK_MEM_RDY_ADDR); + } while ((data != 0xffffffff) && wait--); + + if (data != 0xffffffff) { + dev_err(pdata->dev, "Failed to release memory from shutdown\n"); + return -ENODEV; + } + + return 0; +} + +static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata) +{ + xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, SOFT_RESET); + xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, 0); +} + +static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) +{ + int ret; + + if (pdata->dev->of_node) { + clk_prepare_enable(pdata->clk); + udelay(5); + clk_disable_unprepare(pdata->clk); + udelay(5); + clk_prepare_enable(pdata->clk); + udelay(5); + } else { +#ifdef CONFIG_ACPI + acpi_evaluate_object(ACPI_HANDLE(pdata->dev), + "_RST", NULL, NULL); +#endif + } + + ret = xgene_enet_ecc_init(pdata); + if (ret) + return ret; + xgene_gmac_reset(pdata); + + return 0; +} + +static void xgene_enet_rd_mdio_csr(void __iomem *base_addr, + u32 offset, u32 *val) +{ + void __iomem *addr = base_addr + offset; + + *val = ioread32(addr); +} + +static void xgene_enet_wr_mdio_csr(void __iomem *base_addr, + u32 offset, u32 val) +{ + void __iomem *addr = base_addr + offset; + + iowrite32(val, addr); +} + +static int xgene_xfi_mdio_write(struct mii_bus *bus, int phy_id, + int reg, u16 data) +{ + void __iomem *addr = (void __iomem *)bus->priv; + int timeout = 100; + u32 status, val; + + val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg) | + SET_VAL(HSTMIIMWRDAT, data); + xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, data); + + val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_WRITE); + xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); + + do { + usleep_range(5, 10); + xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); + } while ((status & BUSY_MASK) && timeout--); + + xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); + + return 0; +} + +static int xgene_xfi_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + void __iomem *addr = (void __iomem *)bus->priv; + u32 data, status, val; + int timeout = 100; + + val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg); + xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); + + val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_READ); + xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); + + do { + usleep_range(5, 10); + xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); + } while ((status & BUSY_MASK) && timeout--); + + if (status & BUSY_MASK) { + pr_err("XGENET_MII_MGMT write failed\n"); + return -EBUSY; + } + + xgene_enet_rd_mdio_csr(addr, MIIMRD_FIELD_ADDR, &data); + xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); + + return data; +} + +struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr) +{ + struct phy_device *phy_dev; + + phy_dev = get_phy_device(bus, phy_addr, false); + if (!phy_dev || IS_ERR(phy_dev)) + return NULL; + + if (phy_device_register(phy_dev)) + phy_device_free(phy_dev); + + return phy_dev; +} +EXPORT_SYMBOL(xgene_enet_phy_register); + +#ifdef CONFIG_ACPI +static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl, + void *context, void **ret) +{ + struct mii_bus *mdio = context; + struct acpi_device *adev; + struct phy_device *phy_dev; + const union acpi_object *obj; + u32 phy_addr; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (acpi_dev_get_property(adev, "phy-channel", ACPI_TYPE_INTEGER, &obj)) + return AE_OK; + phy_addr = obj->integer.value; + + phy_dev = xgene_enet_phy_register(mdio, phy_addr); + adev->driver_data = phy_dev; + + return AE_OK; +} +#endif + +static int xgene_mdio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mii_bus *mdio_bus; + const struct of_device_id *of_id; + struct resource *res; + struct xgene_mdio_pdata *pdata; + void __iomem *csr_base; + int mdio_id = 0, ret = 0; + + of_id = of_match_device(xgene_mdio_of_match, &pdev->dev); + if (of_id) { + mdio_id = (enum xgene_mdio_id)of_id->data; + } else { +#ifdef CONFIG_ACPI + const struct acpi_device_id *acpi_id; + + acpi_id = acpi_match_device(xgene_mdio_acpi_match, &pdev->dev); + if (acpi_id) + mdio_id = (enum xgene_mdio_id)acpi_id->driver_data; +#endif + } + + if (!mdio_id) + return -ENODEV; + + pdata = devm_kzalloc(dev, sizeof(struct xgene_mdio_pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->mdio_id = mdio_id; + pdata->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csr_base = devm_ioremap_resource(dev, res); + if (IS_ERR(csr_base)) { + dev_err(dev, "Unable to retrieve mac CSR region\n"); + return PTR_ERR(csr_base); + } + pdata->mac_csr_addr = csr_base; + pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET; + pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET; + + if (dev->of_node) { + pdata->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pdata->clk)) { + dev_err(dev, "Unable to retrieve clk\n"); + return PTR_ERR(pdata->clk); + } + } + + ret = xgene_mdio_reset(pdata); + if (ret) + return ret; + + mdio_bus = mdiobus_alloc(); + if (!mdio_bus) + return -ENOMEM; + + mdio_bus->name = "APM X-Gene MDIO bus"; + + if (mdio_id == XGENE_MDIO_RGMII) { + mdio_bus->read = xgene_mdio_rgmii_read; + mdio_bus->write = xgene_mdio_rgmii_write; + mdio_bus->priv = (void __force *)pdata->mac_csr_addr; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", + "xgene-mii-rgmii"); + } else { + mdio_bus->read = xgene_xfi_mdio_read; + mdio_bus->write = xgene_xfi_mdio_write; + mdio_bus->priv = (void __force *)pdata->mdio_csr_addr; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", + "xgene-mii-xfi"); + } + + mdio_bus->parent = dev; + platform_set_drvdata(pdev, pdata); + + if (dev->of_node) { + ret = of_mdiobus_register(mdio_bus, dev->of_node); + } else { +#ifdef CONFIG_ACPI + /* Mask out all PHYs from auto probing. */ + mdio_bus->phy_mask = ~0; + ret = mdiobus_register(mdio_bus); + if (ret) + goto out; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1, + acpi_register_phy, NULL, mdio_bus, NULL); +#endif + } + + if (ret) + goto out; + + pdata->mdio_bus = mdio_bus; + xgene_mdio_status = true; + + return 0; + +out: + mdiobus_free(mdio_bus); + + return ret; +} + +static int xgene_mdio_remove(struct platform_device *pdev) +{ + struct xgene_mdio_pdata *pdata = platform_get_drvdata(pdev); + struct mii_bus *mdio_bus = pdata->mdio_bus; + struct device *dev = &pdev->dev; + + mdiobus_unregister(mdio_bus); + mdiobus_free(mdio_bus); + + if (dev->of_node) { + if (IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id xgene_mdio_of_match[] = { + { + .compatible = "apm,xgene-mdio-rgmii", + .data = (void *)XGENE_MDIO_RGMII + }, + { + .compatible = "apm,xgene-mdio-xfi", + .data = (void *)XGENE_MDIO_XFI + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, xgene_mdio_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_mdio_acpi_match[] = { + { "APMC0D65", XGENE_MDIO_RGMII }, + { "APMC0D66", XGENE_MDIO_XFI }, + { } +}; + +MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match); +#endif + +static struct platform_driver xgene_mdio_driver = { + .driver = { + .name = "xgene-mdio", + .of_match_table = of_match_ptr(xgene_mdio_of_match), + .acpi_match_table = ACPI_PTR(xgene_mdio_acpi_match), + }, + .probe = xgene_mdio_probe, + .remove = xgene_mdio_remove, +}; + +module_platform_driver(xgene_mdio_driver); + +MODULE_DESCRIPTION("APM X-Gene SoC MDIO driver"); +MODULE_AUTHOR("Iyappan Subramanian "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h new file mode 100644 index 000000000000..354241b53c1d --- /dev/null +++ b/drivers/net/phy/mdio-xgene.h @@ -0,0 +1,143 @@ +/* Applied Micro X-Gene SoC MDIO Driver + * + * Copyright (c) 2016, Applied Micro Circuits Corporation + * Author: Iyappan Subramanian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __MDIO_XGENE_H__ +#define __MDIO_XGENE_H__ + +#define BLOCK_XG_MDIO_CSR_OFFSET 0x5000 +#define BLOCK_DIAG_CSR_OFFSET 0xd000 +#define XGENET_CONFIG_REG_ADDR 0x20 + +#define MAC_ADDR_REG_OFFSET 0x00 +#define MAC_COMMAND_REG_OFFSET 0x04 +#define MAC_WRITE_REG_OFFSET 0x08 +#define MAC_READ_REG_OFFSET 0x0c +#define MAC_COMMAND_DONE_REG_OFFSET 0x10 + +#define CLKEN_OFFSET 0x08 +#define SRST_OFFSET 0x00 + +#define MENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 +#define MENET_BLOCK_MEM_RDY_ADDR 0x74 + +#define MAC_CONFIG_1_ADDR 0x00 +#define MII_MGMT_COMMAND_ADDR 0x24 +#define MII_MGMT_ADDRESS_ADDR 0x28 +#define MII_MGMT_CONTROL_ADDR 0x2c +#define MII_MGMT_STATUS_ADDR 0x30 +#define MII_MGMT_INDICATORS_ADDR 0x34 +#define SOFT_RESET BIT(31) + +#define MII_MGMT_CONFIG_ADDR 0x20 +#define MII_MGMT_COMMAND_ADDR 0x24 +#define MII_MGMT_ADDRESS_ADDR 0x28 +#define MII_MGMT_CONTROL_ADDR 0x2c +#define MII_MGMT_STATUS_ADDR 0x30 +#define MII_MGMT_INDICATORS_ADDR 0x34 + +#define MIIM_COMMAND_ADDR 0x20 +#define MIIM_FIELD_ADDR 0x24 +#define MIIM_CONFIGURATION_ADDR 0x28 +#define MIIM_LINKFAILVECTOR_ADDR 0x2c +#define MIIM_INDICATOR_ADDR 0x30 +#define MIIMRD_FIELD_ADDR 0x34 + +#define MDIO_CSR_OFFSET 0x5000 + +#define REG_ADDR_POS 0 +#define REG_ADDR_LEN 5 +#define PHY_ADDR_POS 8 +#define PHY_ADDR_LEN 5 + +#define HSTMIIMWRDAT_POS 0 +#define HSTMIIMWRDAT_LEN 16 +#define HSTPHYADX_POS 23 +#define HSTPHYADX_LEN 5 +#define HSTREGADX_POS 18 +#define HSTREGADX_LEN 5 +#define HSTLDCMD BIT(3) +#define HSTMIIMCMD_POS 0 +#define HSTMIIMCMD_LEN 3 + +#define BUSY_MASK BIT(0) +#define READ_CYCLE_MASK BIT(0) + +enum xgene_enet_cmd { + XGENE_ENET_WR_CMD = BIT(31), + XGENE_ENET_RD_CMD = BIT(30) +}; + +enum { + MIIM_CMD_IDLE, + MIIM_CMD_LEGACY_WRITE, + MIIM_CMD_LEGACY_READ, +}; + +enum xgene_mdio_id { + XGENE_MDIO_RGMII = 1, + XGENE_MDIO_XFI +}; + +struct xgene_mdio_pdata { + struct clk *clk; + struct device *dev; + void __iomem *mac_csr_addr; + void __iomem *diag_csr_addr; + void __iomem *mdio_csr_addr; + struct mii_bus *mdio_bus; + int mdio_id; +}; + +/* Set the specified value into a bit-field defined by its starting position + * and length within a single u64. + */ +static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) +{ + return (val & ((1ULL << len) - 1)) << pos; +} + +#define SET_VAL(field, val) \ + xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) + +#define SET_BIT(field) \ + xgene_enet_set_field_value(field ## _POS, 1, 1) + +/* Get the value from a bit-field defined by its starting position + * and length within the specified u64. + */ +static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) +{ + return (src >> pos) & ((1ULL << len) - 1); +} + +#define GET_VAL(field, src) \ + xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) + +#define GET_BIT(field, src) \ + xgene_enet_get_field_value(field ## _POS, 1, src) + +static const struct of_device_id xgene_mdio_of_match[]; +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_mdio_acpi_match[]; +#endif +int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); +int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); +struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); + +#endif /* __MDIO_XGENE_H__ */ -- cgit v1.2.3-59-g8ed1b From 8089a96f601bdfe3e1b41d14bb703aafaf1b8f34 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:41 -0700 Subject: drivers: net: xgene: Add backward compatibility This patch adds xgene_enet_check_phy_hanlde() function that checks whether MDIO driver is probed successfully and sets pdata->mdio_driver to true. If MDIO driver is not probed, ethernet driver falls back to backward compatibility mode. Since enum xgene_enet_cmd is used by MDIO driver, removing this from ethernet driver. Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 57 ++++++++++++++++++++--- drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 7 +-- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 50 ++++++++++++++------ drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 30 +----------- drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 9 +++- 5 files changed, 100 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 91a67a028548..b8b643f27361 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -572,7 +572,9 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) { u32 value; - xgene_gmac_reset(pdata); + if (!pdata->mdio_driver) + xgene_gmac_reset(pdata); + xgene_gmac_set_speed(pdata); xgene_gmac_set_mac_addr(pdata); @@ -680,6 +682,11 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata) if (!xgene_ring_mgr_init(pdata)) return -ENODEV; + if (pdata->mdio_driver) { + xgene_enet_config_ring_if_assoc(pdata); + return 0; + } + if (dev->of_node) { clk_prepare_enable(pdata->clk); udelay(5); @@ -799,21 +806,47 @@ static void xgene_enet_adjust_link(struct net_device *ndev) } } -static int xgene_enet_phy_connect(struct net_device *ndev) +#ifdef CONFIG_ACPI +static struct acpi_device *acpi_phy_find_device(struct device *dev) +{ + struct acpi_reference_args args; + struct fwnode_handle *fw_node; + int status; + + fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev)); + status = acpi_node_get_property_reference(fw_node, "phy-handle", 0, + &args); + if (ACPI_FAILURE(status)) { + dev_dbg(dev, "No matching phy in ACPI table\n"); + return NULL; + } + + return args.adev; +} +#endif + +int xgene_enet_phy_connect(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); - struct device_node *phy_np; + struct device_node *np; struct phy_device *phy_dev; struct device *dev = &pdata->pdev->dev; + struct acpi_device *adev; + int i; if (dev->of_node) { - phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); - if (!phy_np) { + for (i = 0 ; i < 2; i++) { + np = of_parse_phandle(dev->of_node, "phy-handle", i); + if (np) + break; + } + + if (!np) { netdev_dbg(ndev, "No phy-handle found in DT\n"); return -ENODEV; } - phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, + phy_dev = of_phy_connect(ndev, np, &xgene_enet_adjust_link, 0, pdata->phy_mode); if (!phy_dev) { netdev_err(ndev, "Could not connect to PHY\n"); @@ -822,6 +855,11 @@ static int xgene_enet_phy_connect(struct net_device *ndev) pdata->phy_dev = phy_dev; } else { +#ifdef CONFIG_ACPI + adev = acpi_phy_find_device(dev); + if (adev) + pdata->phy_dev = adev->driver_data; + phy_dev = pdata->phy_dev; if (!phy_dev || @@ -830,6 +868,7 @@ static int xgene_enet_phy_connect(struct net_device *ndev) netdev_err(ndev, "Could not connect to PHY\n"); return -ENODEV; } +#endif } pdata->phy_speed = SPEED_UNKNOWN; @@ -930,6 +969,12 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) return ret; } +void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata) +{ + if (pdata->phy_dev) + phy_disconnect(pdata->phy_dev); +} + void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) { if (pdata->phy_dev) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index eec55c1d41db..179a44dceb29 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -301,11 +301,6 @@ enum xgene_enet_ring_bufnum { RING_BUFNUM_INVALID }; -enum xgene_enet_cmd { - XGENE_ENET_WR_CMD = BIT(31), - XGENE_ENET_RD_CMD = BIT(30) -}; - enum xgene_enet_err_code { HBF_READ_DATA = 3, HBF_LL_READ = 4, @@ -351,6 +346,8 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); +int xgene_enet_phy_connect(struct net_device *ndev); +void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); extern const struct xgene_mac_ops xgene_gmac_ops; extern const struct xgene_port_ops xgene_gport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 87e592955470..639833729d0a 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -763,7 +763,7 @@ static int xgene_enet_close(struct net_device *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); @@ -1295,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; @@ -1380,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. */ @@ -1574,7 +1595,7 @@ 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; @@ -1636,14 +1657,17 @@ static int xgene_enet_probe(struct platform_device *pdev) 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); @@ -1676,11 +1700,11 @@ static int xgene_enet_remove(struct platform_device *pdev) dev_close(ndev); rtnl_unlock(); - mac_ops->rx_disable(pdata); - mac_ops->tx_disable(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); pdata->port_ops->shutdown(pdata); xgene_enet_delete_desc_rings(pdata); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 681a47321fd8..217546e5714a 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -38,6 +38,7 @@ #include "xgene_enet_hw.h" #include "xgene_enet_cle.h" #include "xgene_enet_ring2.h" +#include "../../../phy/mdio-xgene.h" #define XGENE_DRV_VERSION "v1.0" #define XGENE_ENET_MAX_MTU 1536 @@ -214,6 +215,7 @@ struct xgene_enet_pdata { u32 mss; u8 tx_delay; u8 rx_delay; + bool mdio_driver; }; struct xgene_indirect_ctl { @@ -223,34 +225,6 @@ struct xgene_indirect_ctl { void __iomem *cmd_done; }; -/* Set the specified value into a bit-field defined by its starting position - * and length within a single u64. - */ -static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) -{ - return (val & ((1ULL << len) - 1)) << pos; -} - -#define SET_VAL(field, val) \ - xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) - -#define SET_BIT(field) \ - xgene_enet_set_field_value(field ## _POS, 1, 1) - -/* Get the value from a bit-field defined by its starting position - * and length within the specified u64. - */ -static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) -{ - return (src >> pos) & ((1ULL << len) - 1); -} - -#define GET_VAL(field, src) \ - xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) - -#define GET_BIT(field, src) \ - xgene_enet_get_field_value(field ## _POS, 1, src) - static inline struct device *ndev_to_dev(struct net_device *ndev) { return ndev->dev.parent; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index 03a70c58bb9d..d12e9cbae820 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -366,7 +366,9 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) u32 cfg_bypass_reg, rx_dv_gate_reg; u32 data, offset; - xgene_sgmac_reset(p); + if (!(p->enet_id == XGENE_ENET2 && p->mdio_driver)) + xgene_sgmac_reset(p); + xgene_sgmii_enable_autoneg(p); xgene_sgmac_set_speed(p); xgene_sgmac_set_mac_addr(p); @@ -445,6 +447,11 @@ static int xgene_enet_reset(struct xgene_enet_pdata *p) if (!xgene_ring_mgr_init(p)) return -ENODEV; + if (p->mdio_driver && p->enet_id == XGENE_ENET2) { + xgene_enet_config_ring_if_assoc(p); + return 0; + } + if (p->enet_id == XGENE_ENET2) xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN); -- cgit v1.2.3-59-g8ed1b From 47c62b6d5f9466fbb81ee45273d4a9929200a273 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:42 -0700 Subject: drivers: net: xgene: Enable MDIO driver This patch enables MDIO driver by, - Selecting MDIO_XGENE - Changed open and close to use phy_start and phy_stop - Changed to use mac_ops->tx(rx)_enable and tx(rx)_disable Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/Kconfig | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 8 ++++---- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig index 19e38afbc5ee..300e3b5c54e0 100644 --- a/drivers/net/ethernet/apm/xgene/Kconfig +++ b/drivers/net/ethernet/apm/xgene/Kconfig @@ -3,6 +3,7 @@ config NET_XGENE depends on HAS_DMA depends on ARCH_XGENE || COMPILE_TEST select PHYLIB + select MDIO_XGENE help This is the Ethernet driver for the on-chip ethernet interface on the APM X-Gene SoC. diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index b8b643f27361..27a7a1c960e0 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -794,13 +794,13 @@ static void xgene_enet_adjust_link(struct net_device *ndev) if (pdata->phy_speed != phydev->speed) { pdata->phy_speed = phydev->speed; mac_ops->set_speed(pdata); - xgene_gmac_rx_enable(pdata); - xgene_gmac_tx_enable(pdata); + mac_ops->rx_enable(pdata); + mac_ops->tx_enable(pdata); phy_print_status(phydev); } } else { - xgene_gmac_rx_disable(pdata); - xgene_gmac_tx_disable(pdata); + mac_ops->rx_disable(pdata); + mac_ops->tx_disable(pdata); pdata->phy_speed = SPEED_UNKNOWN; phy_print_status(phydev); } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 639833729d0a..d1d6b5eeb613 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -739,9 +739,9 @@ static int xgene_enet_open(struct net_device *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); } -- cgit v1.2.3-59-g8ed1b From 8c1519632fa6cb34a5ff4dddffd4a182c4fae1b6 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:43 -0700 Subject: drivers: net: xgene: Use exported functions This patch reuses the mdio read/write and phy_register functions and removed the local definitions. Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 97 +++----------------------- 1 file changed, 9 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 27a7a1c960e0..8a2a221a9838 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -381,59 +381,6 @@ static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata, rd_addr); } -static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id, - u32 reg, u16 data) -{ - u32 addr = 0, wr_data = 0; - u32 done; - u8 wait = 10; - - PHY_ADDR_SET(&addr, phy_id); - REG_ADDR_SET(&addr, reg); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); - - PHY_CONTROL_SET(&wr_data, data); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data); - do { - usleep_range(5, 10); - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); - } while ((done & BUSY_MASK) && wait--); - - if (done & BUSY_MASK) { - netdev_err(pdata->ndev, "MII_MGMT write failed\n"); - return -EBUSY; - } - - return 0; -} - -static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata, - u8 phy_id, u32 reg) -{ - u32 addr = 0; - u32 data, done; - u8 wait = 10; - - PHY_ADDR_SET(&addr, phy_id); - REG_ADDR_SET(&addr, reg); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); - do { - usleep_range(5, 10); - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); - } while ((done & BUSY_MASK) && wait--); - - if (done & BUSY_MASK) { - netdev_err(pdata->ndev, "MII_MGMT read failed\n"); - return -EBUSY; - } - - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); - - return data; -} - static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) { u32 addr0, addr1; @@ -762,28 +709,6 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) } } -static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct xgene_enet_pdata *pdata = bus->priv; - u32 val; - - val = xgene_mii_phy_read(pdata, mii_id, regnum); - netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n", - mii_id, regnum, val); - - return val; -} - -static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, - u16 val) -{ - struct xgene_enet_pdata *pdata = bus->priv; - - netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n", - mii_id, regnum, val); - return xgene_mii_phy_write(pdata, mii_id, regnum, val); -} - static void xgene_enet_adjust_link(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); @@ -888,8 +813,8 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, struct phy_device *phy; struct device_node *child_np; struct device_node *mdio_np = NULL; + u32 phy_addr; int ret; - u32 phy_id; if (dev->of_node) { for_each_child_of_node(dev->of_node, child_np) { @@ -916,21 +841,17 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, if (ret) return ret; - ret = device_property_read_u32(dev, "phy-channel", &phy_id); + ret = device_property_read_u32(dev, "phy-channel", &phy_addr); if (ret) - ret = device_property_read_u32(dev, "phy-addr", &phy_id); + ret = device_property_read_u32(dev, "phy-addr", &phy_addr); if (ret) return -EINVAL; - phy = get_phy_device(mdio, phy_id, false); - if (IS_ERR(phy)) + phy = xgene_enet_phy_register(mdio, phy_addr); + if (!phy) return -EIO; - ret = phy_device_register(phy); - if (ret) - phy_device_free(phy); - else - pdata->phy_dev = phy; + pdata->phy_dev = phy; return ret; } @@ -946,12 +867,12 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) return -ENOMEM; mdio_bus->name = "APM X-Gene MDIO bus"; - mdio_bus->read = xgene_enet_mdio_read; - mdio_bus->write = xgene_enet_mdio_write; + mdio_bus->read = xgene_mdio_rgmii_read; + mdio_bus->write = xgene_mdio_rgmii_write; snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii", ndev->name); - mdio_bus->priv = pdata; + mdio_bus->priv = (void __force *)pdata->mcx_mac_addr; mdio_bus->parent = &pdata->pdev->dev; ret = xgene_mdiobus_register(pdata, mdio_bus); -- cgit v1.2.3-59-g8ed1b From 52d1fd9983182e9e92507a18a997b3614864e0ee Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 25 Jul 2016 17:12:44 -0700 Subject: drivers: net: xgene: ethtool: Use phy_ethtool_gset and sset Changed SGMII 1G get_settings to use phy_ethtool_gset. Changed SGMII 1G set_settings to use phy_ethtool_sset. Signed-off-by: Iyappan Subramanian Tested-by: Fushen Chen Tested-by: Toan Le Signed-off-by: David S. Miller --- .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 416d6ebfc2ce..22a7b26ca1d6 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -65,8 +65,15 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) return phy_ethtool_gset(phydev, cmd); } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { - cmd->supported = SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_MII; + if (pdata->mdio_driver) { + if (!phydev) + return -ENODEV; + + return phy_ethtool_gset(phydev, cmd); + } + + cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_MII; cmd->advertising = cmd->supported; ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; @@ -92,12 +99,21 @@ static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) struct phy_device *phydev = pdata->phy_dev; if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { - if (phydev == NULL) + if (!phydev) return -ENODEV; return phy_ethtool_sset(phydev, cmd); } + if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { + if (pdata->mdio_driver) { + if (!phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); + } + } + return -EINVAL; } -- cgit v1.2.3-59-g8ed1b