diff options
author | David S. Miller <davem@davemloft.net> | 2016-07-25 21:51:44 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-07-25 21:51:44 -0700 |
commit | ee591f46a5a0ca0caaeb72b79ec5e012c6e3c9ef (patch) | |
tree | ed3f955b3ce6ab5c4170b7c16a56915ef775c5c9 | |
parent | c43212bb7bebe24a93a7a7d86e767e1ce295d72a (diff) | |
parent | 2efccc601c1c139cb88e3e5d0a6f4402fd040c46 (diff) | |
download | linux-ee591f46a5a0ca0caaeb72b79ec5e012c6e3c9ef.tar.gz linux-ee591f46a5a0ca0caaeb72b79ec5e012c6e3c9ef.tar.bz2 linux-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>
20 files changed, 1291 insertions, 283 deletions
diff --git a/Documentation/devicetree/bindings/net/apm-xgene-mdio.txt b/Documentation/devicetree/bindings/net/apm-xgene-mdio.txt new file mode 100644 index 000000000000..78722d74cea8 --- /dev/null +++ b/Documentation/devicetree/bindings/net/apm-xgene-mdio.txt @@ -0,0 +1,37 @@ +APM X-Gene SoC MDIO node + +MDIO node is defined to describe on-chip MDIO controller. + +Required properties: + - compatible: Must be "apm,xgene-mdio-rgmii" or "apm,xgene-mdio-xfi" + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + - reg: Address and length of the register set + - clocks: Reference to the clock entry + +For the phys on the mdio bus, there must be a node with the following fields: + - compatible: PHY identifier. Please refer ./phy.txt for the format. + - reg: The ID number for the phy. + +Example: + + mdio: mdio@17020000 { + compatible = "apm,xgene-mdio-rgmii"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x17020000 0x0 0xd100>; + clocks = <&menetclk 0>; + }; + + /* Board-specific peripheral configurations */ + &mdio { + menetphy: phy@3 { + reg = <0x3>; + }; + sgenet0phy: phy@4 { + reg = <0x4>; + }; + sgenet1phy: phy@5 { + reg = <0x5>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index dc3481d7c80d..a9bdba0484d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -839,7 +839,9 @@ M: Iyappan Subramanian <isubramanian@apm.com> M: Keyur Chudgar <kchudgar@apm.com> S: Supported F: drivers/net/ethernet/apm/xgene/ +F: drivers/net/phy/mdio-xgene.c F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt +F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt APTINA CAMERA SENSOR PLL M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> diff --git a/arch/arm64/boot/dts/apm/apm-merlin.dts b/arch/arm64/boot/dts/apm/apm-merlin.dts index 387c6a8d0da9..b0f64414c1b0 100644 --- a/arch/arm64/boot/dts/apm/apm-merlin.dts +++ b/arch/arm64/boot/dts/apm/apm-merlin.dts @@ -83,3 +83,9 @@ status = "ok"; }; }; + +&mdio { + sgenet0phy: phy@0 { + reg = <0x0>; + }; +}; diff --git a/arch/arm64/boot/dts/apm/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts index 44db32ec5e9c..b7fb5d9295c2 100644 --- a/arch/arm64/boot/dts/apm/apm-mustang.dts +++ b/arch/arm64/boot/dts/apm/apm-mustang.dts @@ -79,3 +79,15 @@ &mmc0 { status = "ok"; }; + +&mdio { + menet0phy: phy@3 { + reg = <0x3>; + }; + sgenet0phy: phy@4 { + reg = <0x4>; + }; + sgenet1phy: phy@5 { + reg = <0x5>; + }; +}; diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi index c569f761d090..2e1e5daa1dc7 100644 --- a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi +++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi @@ -625,10 +625,18 @@ apm,irq-start = <8>; }; + mdio: mdio@1f610000 { + compatible = "apm,xgene-mdio-xfi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x1f610000 0x0 0xd100>; + clocks = <&xge0clk 0>; + }; + sgenet0: ethernet@1f610000 { compatible = "apm,xgene2-sgenet"; status = "disabled"; - reg = <0x0 0x1f610000 0x0 0x10000>, + reg = <0x0 0x1f610000 0x0 0xd100>, <0x0 0x1f600000 0x0 0Xd100>, <0x0 0x20000000 0x0 0X20000>; interrupts = <0 96 4>, @@ -637,6 +645,7 @@ clocks = <&xge0clk 0>; local-mac-address = [00 01 73 00 00 01]; phy-connection-type = "sgmii"; + phy-handle = <&sgenet0phy>; }; xgenet1: ethernet@1f620000 { diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi index 5147d7698924..6bf7cbe2e72d 100644 --- a/arch/arm64/boot/dts/apm/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi @@ -237,20 +237,11 @@ clocks = <&socplldiv2 0>; reg = <0x0 0x1f21c000 0x0 0x1000>; reg-names = "csr-reg"; - csr-mask = <0x3>; + csr-mask = <0xa>; + enable-mask = <0xf>; clock-output-names = "sge0clk"; }; - sge1clk: sge1clk@1f21c000 { - compatible = "apm,xgene-device-clock"; - #clock-cells = <1>; - clocks = <&socplldiv2 0>; - reg = <0x0 0x1f21c000 0x0 0x1000>; - reg-names = "csr-reg"; - csr-mask = <0xc>; - clock-output-names = "sge1clk"; - }; - xge0clk: xge0clk@1f61c000 { compatible = "apm,xgene-device-clock"; #clock-cells = <1>; @@ -921,6 +912,14 @@ clocks = <&rtcclk 0>; }; + mdio: mdio@17020000 { + compatible = "apm,xgene-mdio-rgmii"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x17020000 0x0 0xd100>; + clocks = <&menetclk 0>; + }; + menet: ethernet@17020000 { compatible = "apm,xgene-enet"; status = "disabled"; @@ -934,7 +933,7 @@ /* mac address will be overwritten by the bootloader */ local-mac-address = [00 00 00 00 00 00]; phy-connection-type = "rgmii"; - phy-handle = <&menetphy>; + phy-handle = <&menet0phy>,<&menetphy>; mdio { compatible = "apm,xgene-mdio"; #address-cells = <1>; @@ -960,6 +959,7 @@ clocks = <&sge0clk 0>; local-mac-address = [00 00 00 00 00 00]; phy-connection-type = "sgmii"; + phy-handle = <&sgenet0phy>; }; sgenet1: ethernet@1f210030 { @@ -973,9 +973,9 @@ <0x0 0xAD 0x4>; port-id = <1>; dma-coherent; - clocks = <&sge1clk 0>; local-mac-address = [00 00 00 00 00 00]; phy-connection-type = "sgmii"; + phy-handle = <&sgenet1phy>; }; xgenet: ethernet@1f610000 { 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_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; } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2f5638f7f864..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; @@ -512,14 +459,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 +508,21 @@ 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; + if (!pdata->mdio_driver) + xgene_gmac_reset(pdata); + + xgene_gmac_set_speed(pdata); xgene_gmac_set_mac_addr(pdata); /* Adjust MDC clock frequency */ @@ -579,15 +537,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; @@ -671,92 +624,154 @@ 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 (pdata->mdio_driver) { + xgene_enet_config_ring_if_assoc(pdata); + return 0; + } + + 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; } -static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) +static void xgene_enet_clear(struct xgene_enet_pdata *pdata, + struct xgene_enet_desc_ring *ring) { - if (!IS_ERR(pdata->clk)) - clk_disable_unprepare(pdata->clk); -} + u32 addr, val, data; -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_enet_ring_bufnum(ring->id); - 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); + if (xgene_enet_is_bufpool(ring->id)) { + addr = ENET_CFGSSQMIFPRESET_ADDR; + data = BIT(val - 0x20); + } else { + addr = ENET_CFGSSQMIWQRESET_ADDR; + data = BIT(val); + } - return val; + xgene_enet_wr_ring_if(pdata, addr, data); } -static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, - u16 val) +static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) { - struct xgene_enet_pdata *pdata = bus->priv; + struct device *dev = &pdata->pdev->dev; + 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); - 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); + if (dev->of_node) { + if (!IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + } } 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); - xgene_gmac_rx_enable(pdata); - xgene_gmac_tx_enable(pdata); + mac_ops->set_speed(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); } } -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"); @@ -765,6 +780,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 || @@ -773,6 +793,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; @@ -792,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) { @@ -820,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; } @@ -850,13 +867,13 @@ 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->parent = &ndev->dev; + mdio_bus->priv = (void __force *)pdata->mcx_mac_addr; + mdio_bus->parent = &pdata->pdev->dev; ret = xgene_mdiobus_register(pdata, mdio_bus); if (ret) { @@ -873,6 +890,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) @@ -890,11 +913,13 @@ 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, }; 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 45220be3122f..179a44dceb29 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 @@ -165,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 @@ -297,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, @@ -347,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 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 |