diff --git a/debian/changelog b/debian/changelog index 0056ed9c3..cc170c566 100644 --- a/debian/changelog +++ b/debian/changelog @@ -12,6 +12,8 @@ linux (3.16.7-3) UNRELEASED; urgency=medium * [armhf] Increase Ethernet phy startup delay on Banana-Pi. Patch from Karsten Merker (Closes: #767042) * [armhf] Enable FB_SIMPLE, used on some Exynos platforms and elsewhere. + * [arm64] Backport various upstream fixes and improvements to the APM X-gene + Ethernet driver. -- Ben Hutchings Sun, 09 Nov 2014 10:13:09 +0000 diff --git a/debian/patches/features/arm64/drivers-net-xgene-Add-10GbE-ethtool-support.patch b/debian/patches/features/arm64/drivers-net-xgene-Add-10GbE-ethtool-support.patch new file mode 100644 index 000000000..c260426f7 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Add-10GbE-ethtool-support.patch @@ -0,0 +1,64 @@ +From 23a92cd33a89eaf4c76c0a848ec878035c08cc85 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Thu, 9 Oct 2014 18:32:07 -0700 +Subject: [PATCH 03/11] drivers: net: xgene: Add 10GbE ethtool support +Origin: https://git.kernel.org/linus/41aace6e088d198f2441f3d0e579657d6815234c + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 28 +++++++++++++++++----- + 1 file changed, 22 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +index 63f2aa5..c1c997b 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +@@ -59,10 +59,22 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) + struct xgene_enet_pdata *pdata = netdev_priv(ndev); + struct phy_device *phydev = pdata->phy_dev; + +- if (phydev == NULL) +- return -ENODEV; ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ++ if (phydev == NULL) ++ return -ENODEV; + +- return phy_ethtool_gset(phydev, cmd); ++ return phy_ethtool_gset(phydev, cmd); ++ } ++ ++ cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; ++ cmd->advertising = cmd->supported; ++ ethtool_cmd_speed_set(cmd, SPEED_10000); ++ cmd->duplex = DUPLEX_FULL; ++ cmd->port = PORT_FIBRE; ++ cmd->transceiver = XCVR_EXTERNAL; ++ cmd->autoneg = AUTONEG_DISABLE; ++ ++ return 0; + } + + static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +@@ -70,10 +82,14 @@ static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) + struct xgene_enet_pdata *pdata = netdev_priv(ndev); + struct phy_device *phydev = pdata->phy_dev; + +- if (phydev == NULL) +- return -ENODEV; ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ++ if (phydev == NULL) ++ return -ENODEV; ++ ++ return phy_ethtool_sset(phydev, cmd); ++ } + +- return phy_ethtool_sset(phydev, cmd); ++ return -EINVAL; + } + + static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Add-10GbE-support.patch b/debian/patches/features/arm64/drivers-net-xgene-Add-10GbE-support.patch new file mode 100644 index 000000000..89a830420 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Add-10GbE-support.patch @@ -0,0 +1,662 @@ +From 226068a83722c5cf3da300cce9bab7201088a061 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Thu, 9 Oct 2014 18:32:06 -0700 +Subject: [PATCH 02/11] drivers: net: xgene: Add 10GbE support +Origin: https://git.kernel.org/linus/0148d38d36b76b190ddddff68f02d2617ada3bcb + +- Added 10GbE support +- Removed unused macros/variables +- Moved mac_init call to the end of hardware init + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/Makefile | 3 +- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 14 +- + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 58 ++-- + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 5 +- + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 331 ++++++++++++++++++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 57 ++++ + 6 files changed, 438 insertions(+), 30 deletions(-) + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h + +diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile +index c643e8a..589b352 100644 +--- a/drivers/net/ethernet/apm/xgene/Makefile ++++ b/drivers/net/ethernet/apm/xgene/Makefile +@@ -2,5 +2,6 @@ + # Makefile for APM X-Gene Ethernet Driver. + # + +-xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o ++xgene-enet-objs := xgene_enet_hw.o xgene_enet_xgmac.o \ ++ xgene_enet_main.o xgene_enet_ethtool.o + obj-$(CONFIG_NET_XGENE) += xgene-enet.o +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +index 084ac68..15ec426 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +@@ -42,6 +42,11 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) + return (val & GENMASK(end, start)) >> start; + } + ++enum xgene_enet_rm { ++ RM0, ++ RM3 = 3 ++}; ++ + #define CSR_RING_ID 0x0008 + #define OVERWRITE BIT(31) + #define IS_BUFFER_POOL BIT(20) +@@ -52,7 +57,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) + #define CSR_RING_WR_BASE 0x0070 + #define NUM_RING_CONFIG 5 + #define BUFPOOL_MODE 3 +-#define RM3 3 + #define INC_DEC_CMD_ADDR 0x002c + #define UDP_HDR_SIZE 2 + #define BUF_LEN_CODE_2K 0x5000 +@@ -94,11 +98,9 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) + + #define BLOCK_ETH_CSR_OFFSET 0x2000 + #define BLOCK_ETH_RING_IF_OFFSET 0x9000 +-#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000 + #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 + + #define BLOCK_ETH_MAC_OFFSET 0x0000 +-#define BLOCK_ETH_STATS_OFFSET 0x0014 + #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 + + #define MAC_ADDR_REG_OFFSET 0x00 +@@ -107,12 +109,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) + #define MAC_READ_REG_OFFSET 0x0c + #define MAC_COMMAND_DONE_REG_OFFSET 0x10 + +-#define STAT_ADDR_REG_OFFSET 0x00 +-#define STAT_COMMAND_REG_OFFSET 0x04 +-#define STAT_WRITE_REG_OFFSET 0x08 +-#define STAT_READ_REG_OFFSET 0x0c +-#define STAT_COMMAND_DONE_REG_OFFSET 0x10 +- + #define MII_MGMT_CONFIG_ADDR 0x20 + #define MII_MGMT_COMMAND_ADDR 0x24 + #define MII_MGMT_ADDRESS_ADDR 0x28 +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index c432644..9b85239 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -21,6 +21,7 @@ + + #include "xgene_enet_main.h" + #include "xgene_enet_hw.h" ++#include "xgene_enet_xgmac.h" + + static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) + { +@@ -390,7 +391,7 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, + } + } + +- return budget; ++ return count; + } + + static int xgene_enet_napi(struct napi_struct *napi, const int budget) +@@ -456,8 +457,10 @@ static int xgene_enet_open(struct net_device *ndev) + return ret; + napi_enable(&pdata->rx_ring->napi); + +- if (pdata->phy_dev) ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + phy_start(pdata->phy_dev); ++ else ++ schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); + + netif_start_queue(ndev); + +@@ -471,8 +474,10 @@ static int xgene_enet_close(struct net_device *ndev) + + netif_stop_queue(ndev); + +- if (pdata->phy_dev) ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + phy_stop(pdata->phy_dev); ++ else ++ cancel_delayed_work_sync(&pdata->link_work); + + napi_disable(&pdata->rx_ring->napi); + xgene_enet_free_irq(ndev); +@@ -615,7 +620,6 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( + + ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6); + ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR; +- pdata->rm = RM3; + ring = xgene_enet_setup_ring(ring); + netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n", + ring->num, ring->size, ring->id, ring->slots); +@@ -805,8 +809,13 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + + pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); + if (pdata->phy_mode < 0) { +- dev_err(dev, "Incorrect phy-connection-type in DTS\n"); +- return -EINVAL; ++ dev_err(dev, "Unable to get phy-connection-type\n"); ++ return pdata->phy_mode; ++ } ++ if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && ++ pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { ++ dev_err(dev, "Incorrect phy-connection-type specified\n"); ++ return -ENODEV; + } + + pdata->clk = devm_clk_get(&pdev->dev, NULL); +@@ -821,12 +830,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; + pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; + pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; +- pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; +- pdata->mcx_stats_addr = base_addr + BLOCK_ETH_STATS_OFFSET; +- pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ++ pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; ++ pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; ++ pdata->rm = RM3; ++ } else { ++ pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; ++ pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; ++ pdata->rm = RM0; ++ } + pdata->rx_buff_cnt = NUM_PKT_BUF; + +- return ret; ++ return 0; + } + + static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) +@@ -836,8 +851,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) + u16 dst_ring_num; + int ret; + +- pdata->mac_ops->tx_disable(pdata); +- pdata->mac_ops->rx_disable(pdata); ++ pdata->port_ops->reset(pdata); + + ret = xgene_enet_create_desc_rings(ndev); + if (ret) { +@@ -856,14 +870,23 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) + + dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); + pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); ++ pdata->mac_ops->init(pdata); + + return ret; + } + + static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) + { +- pdata->mac_ops = &xgene_gmac_ops; +- pdata->port_ops = &xgene_gport_ops; ++ switch (pdata->phy_mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ pdata->mac_ops = &xgene_gmac_ops; ++ pdata->port_ops = &xgene_gport_ops; ++ break; ++ default: ++ pdata->mac_ops = &xgene_xgmac_ops; ++ pdata->port_ops = &xgene_xgport_ops; ++ break; ++ } + } + + static int xgene_enet_probe(struct platform_device *pdev) +@@ -895,8 +918,6 @@ static int xgene_enet_probe(struct platform_device *pdev) + goto err; + + xgene_enet_setup_ops(pdata); +- pdata->port_ops->reset(pdata); +- pdata->mac_ops->init(pdata); + + ret = register_netdev(ndev); + if (ret) { +@@ -916,7 +937,10 @@ static int xgene_enet_probe(struct platform_device *pdev) + + napi = &pdata->rx_ring->napi; + netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); +- ret = xgene_enet_mdio_config(pdata); ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) ++ ret = xgene_enet_mdio_config(pdata); ++ else ++ INIT_DELAYED_WORK(&pdata->link_work, xgene_enet_link_state); + + return ret; + err: +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index ac180f9..86cf68b 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -105,18 +105,17 @@ struct xgene_enet_pdata { + void __iomem *eth_ring_if_addr; + void __iomem *eth_diag_csr_addr; + void __iomem *mcx_mac_addr; +- void __iomem *mcx_stats_addr; + void __iomem *mcx_mac_csr_addr; + void __iomem *base_addr; + void __iomem *ring_csr_addr; + void __iomem *ring_cmd_addr; + u32 phy_addr; + int phy_mode; +- u32 speed; +- u16 rm; ++ enum xgene_enet_rm rm; + struct rtnl_link_stats64 stats; + struct xgene_mac_ops *mac_ops; + struct xgene_port_ops *port_ops; ++ struct delayed_work link_work; + }; + + /* Set the specified value into a bit-field defined by its starting position +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +new file mode 100644 +index 0000000..cd64b9f +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +@@ -0,0 +1,331 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian ++ * Keyur Chudgar ++ * ++ * 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 "xgene_enet_main.h" ++#include "xgene_enet_hw.h" ++#include "xgene_enet_xgmac.h" ++ ++static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_ring_if_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_diag_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, ++ void __iomem *cmd, void __iomem *cmd_done, ++ u32 wr_addr, u32 wr_data) ++{ ++ u32 done; ++ u8 wait = 10; ++ ++ iowrite32(wr_addr, addr); ++ iowrite32(wr_data, wr); ++ iowrite32(XGENE_ENET_WR_CMD, cmd); ++ ++ /* wait for write command to complete */ ++ while (!(done = ioread32(cmd_done)) && wait--) ++ udelay(1); ++ ++ if (!done) ++ return false; ++ ++ iowrite32(0, cmd); ++ ++ return true; ++} ++ ++static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, ++ u32 wr_addr, u32 wr_data) ++{ ++ void __iomem *addr, *wr, *cmd, *cmd_done; ++ ++ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; ++ wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; ++ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; ++ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; ++ ++ if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) ++ netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", ++ wr_addr); ++} ++ ++static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->eth_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->eth_diag_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, ++ void __iomem *cmd, void __iomem *cmd_done, ++ u32 rd_addr, u32 *rd_data) ++{ ++ u32 done; ++ u8 wait = 10; ++ ++ iowrite32(rd_addr, addr); ++ iowrite32(XGENE_ENET_RD_CMD, cmd); ++ ++ /* wait for read command to complete */ ++ while (!(done = ioread32(cmd_done)) && wait--) ++ udelay(1); ++ ++ if (!done) ++ return false; ++ ++ *rd_data = ioread32(rd); ++ iowrite32(0, cmd); ++ ++ return true; ++} ++ ++static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, ++ u32 rd_addr, u32 *rd_data) ++{ ++ void __iomem *addr, *rd, *cmd, *cmd_done; ++ ++ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; ++ rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; ++ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; ++ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; ++ ++ if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) ++ netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", ++ rd_addr); ++} ++ ++static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) ++{ ++ struct net_device *ndev = pdata->ndev; ++ u32 data; ++ u8 wait = 10; ++ ++ xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); ++ do { ++ usleep_range(100, 110); ++ xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data); ++ } while ((data != 0xffffffff) && wait--); ++ ++ if (data != 0xffffffff) { ++ netdev_err(ndev, "Failed to release memory from shutdown\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) ++{ ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, 0); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, 0); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, 0); ++} ++ ++static void xgene_xgmac_reset(struct xgene_enet_pdata *pdata) ++{ ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, HSTMACRST); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, 0); ++} ++ ++static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata) ++{ ++ u32 addr0, addr1; ++ u8 *dev_addr = pdata->ndev->dev_addr; ++ ++ addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | ++ (dev_addr[1] << 8) | dev_addr[0]; ++ addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); ++ ++ xgene_enet_wr_mac(pdata, HSTMACADR_LSW_ADDR, addr0); ++ xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1); ++} ++ ++static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_csr(pdata, XG_LINK_STATUS_ADDR, &data); ++ ++ return data; ++} ++ ++static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_xgmac_reset(pdata); ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ data |= HSTPPEN; ++ data &= ~HSTLENCHK; ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); ++ ++ xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR, 0x06000600); ++ xgene_xgmac_set_mac_addr(pdata); ++ ++ xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data); ++ data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; ++ xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data); ++ ++ xgene_enet_wr_csr(pdata, XG_CFG_BYPASS_ADDR, RESUME_TX); ++ xgene_enet_wr_csr(pdata, XGENET_RX_DV_GATE_REG_0_ADDR, 0); ++ xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data); ++ data |= BIT(12); ++ xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data); ++ xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x82); ++} ++ ++static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN); ++} ++ ++static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN); ++} ++ ++static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN); ++} ++ ++static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); ++} ++ ++static void xgene_enet_reset(struct xgene_enet_pdata *pdata) ++{ ++ clk_prepare_enable(pdata->clk); ++ clk_disable_unprepare(pdata->clk); ++ clk_prepare_enable(pdata->clk); ++ ++ xgene_enet_ecc_init(pdata); ++ xgene_enet_config_ring_if_assoc(pdata); ++} ++ ++static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, ++ u32 dst_ring_num, u16 bufpool_id) ++{ ++ u32 cb, fpsel; ++ ++ xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG0_ADDR, &cb); ++ cb |= CFG_CLE_BYPASS_EN0; ++ CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); ++ xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG0_ADDR, cb); ++ ++ fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; ++ xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG1_ADDR, &cb); ++ CFG_CLE_DSTQID0_SET(&cb, dst_ring_num); ++ CFG_CLE_FPSEL0_SET(&cb, fpsel); ++ xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG1_ADDR, cb); ++} ++ ++static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) ++{ ++ clk_disable_unprepare(pdata->clk); ++} ++ ++void xgene_enet_link_state(struct work_struct *work) ++{ ++ struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work), ++ struct xgene_enet_pdata, link_work); ++ struct net_device *ndev = pdata->ndev; ++ u32 link_status, poll_interval; ++ ++ link_status = xgene_enet_link_status(pdata); ++ if (link_status) { ++ if (!netif_carrier_ok(ndev)) { ++ netif_carrier_on(ndev); ++ xgene_xgmac_init(pdata); ++ xgene_xgmac_rx_enable(pdata); ++ xgene_xgmac_tx_enable(pdata); ++ netdev_info(ndev, "Link is Up - 10Gbps\n"); ++ } ++ poll_interval = PHY_POLL_LINK_ON; ++ } else { ++ if (netif_carrier_ok(ndev)) { ++ xgene_xgmac_rx_disable(pdata); ++ xgene_xgmac_tx_disable(pdata); ++ netif_carrier_off(ndev); ++ netdev_info(ndev, "Link is Down\n"); ++ } ++ poll_interval = PHY_POLL_LINK_OFF; ++ } ++ ++ schedule_delayed_work(&pdata->link_work, poll_interval); ++} ++ ++struct xgene_mac_ops xgene_xgmac_ops = { ++ .init = xgene_xgmac_init, ++ .reset = xgene_xgmac_reset, ++ .rx_enable = xgene_xgmac_rx_enable, ++ .tx_enable = xgene_xgmac_tx_enable, ++ .rx_disable = xgene_xgmac_rx_disable, ++ .tx_disable = xgene_xgmac_tx_disable, ++ .set_mac_addr = xgene_xgmac_set_mac_addr, ++}; ++ ++struct xgene_port_ops xgene_xgport_ops = { ++ .reset = xgene_enet_reset, ++ .cle_bypass = xgene_enet_xgcle_bypass, ++ .shutdown = xgene_enet_shutdown, ++}; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +new file mode 100644 +index 0000000..d2d59e7 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +@@ -0,0 +1,57 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian ++ * Keyur Chudgar ++ * ++ * 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 __XGENE_ENET_XGMAC_H__ ++#define __XGENE_ENET_XGMAC_H__ ++ ++#define BLOCK_AXG_MAC_OFFSET 0x0800 ++#define BLOCK_AXG_MAC_CSR_OFFSET 0x2000 ++ ++#define AXGMAC_CONFIG_0 0x0000 ++#define AXGMAC_CONFIG_1 0x0004 ++#define HSTMACRST BIT(31) ++#define HSTTCTLEN BIT(31) ++#define HSTTFEN BIT(30) ++#define HSTRCTLEN BIT(29) ++#define HSTRFEN BIT(28) ++#define HSTPPEN BIT(7) ++#define HSTDRPLT64 BIT(5) ++#define HSTLENCHK BIT(3) ++#define HSTMACADR_LSW_ADDR 0x0010 ++#define HSTMACADR_MSW_ADDR 0x0014 ++#define HSTMAXFRAME_LENGTH_ADDR 0x0020 ++ ++#define XG_RSIF_CONFIG_REG_ADDR 0x00a0 ++#define XCLE_BYPASS_REG0_ADDR 0x0160 ++#define XCLE_BYPASS_REG1_ADDR 0x0164 ++#define XG_CFG_BYPASS_ADDR 0x0204 ++#define XG_LINK_STATUS_ADDR 0x0228 ++#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 PHY_POLL_LINK_ON (10 * HZ) ++#define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) ++ ++void xgene_enet_link_state(struct work_struct *work); ++extern struct xgene_mac_ops xgene_xgmac_ops; ++extern struct xgene_port_ops xgene_xgport_ops; ++ ++#endif /* __XGENE_ENET_XGMAC_H__ */ +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-ethtool-suppo.patch b/debian/patches/features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-ethtool-suppo.patch new file mode 100644 index 000000000..a8fb3d087 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-ethtool-suppo.patch @@ -0,0 +1,55 @@ +From c566829d7ea3c25a85a372901b0fce080017034b Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 13 Oct 2014 17:05:35 -0700 +Subject: [PATCH 06/11] drivers: net: xgene: Add SGMII based 1GbE ethtool + support +Origin: https://git.kernel.org/linus/5e6a024bebea5bad6b787cf2c0ee28116b4147f0 + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 25 +++++++++++++++------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +index c1c997b..416d6eb 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +@@ -64,16 +64,25 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) + return -ENODEV; + + return phy_ethtool_gset(phydev, cmd); ++ } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { ++ cmd->supported = SUPPORTED_1000baseT_Full | ++ SUPPORTED_Autoneg | SUPPORTED_MII; ++ cmd->advertising = cmd->supported; ++ ethtool_cmd_speed_set(cmd, SPEED_1000); ++ cmd->duplex = DUPLEX_FULL; ++ cmd->port = PORT_MII; ++ cmd->transceiver = XCVR_INTERNAL; ++ cmd->autoneg = AUTONEG_ENABLE; ++ } else { ++ cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; ++ cmd->advertising = cmd->supported; ++ ethtool_cmd_speed_set(cmd, SPEED_10000); ++ cmd->duplex = DUPLEX_FULL; ++ cmd->port = PORT_FIBRE; ++ cmd->transceiver = XCVR_INTERNAL; ++ cmd->autoneg = AUTONEG_DISABLE; + } + +- cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; +- cmd->advertising = cmd->supported; +- ethtool_cmd_speed_set(cmd, SPEED_10000); +- cmd->duplex = DUPLEX_FULL; +- cmd->port = PORT_FIBRE; +- cmd->transceiver = XCVR_EXTERNAL; +- cmd->autoneg = AUTONEG_DISABLE; +- + return 0; + } + +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-support.patch b/debian/patches/features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-support.patch new file mode 100644 index 000000000..8001eab79 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-support.patch @@ -0,0 +1,583 @@ +From 30bf224d12eb84225e3c0dcdd520cf9a23276f11 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 13 Oct 2014 17:05:34 -0700 +Subject: [PATCH 05/11] drivers: net: xgene: Add SGMII based 1GbE support +Origin: https://git.kernel.org/linus/32f784b50e14c653ad0f010fbd5921a5f8caf846 + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/Makefile | 2 +- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 3 + + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 10 +- + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 10 + + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 389 ++++++++++++++++++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h | 41 +++ + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 3 - + 7 files changed, 453 insertions(+), 5 deletions(-) + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h + +diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile +index 589b352..68be5655 100644 +--- a/drivers/net/ethernet/apm/xgene/Makefile ++++ b/drivers/net/ethernet/apm/xgene/Makefile +@@ -2,6 +2,6 @@ + # Makefile for APM X-Gene Ethernet Driver. + # + +-xgene-enet-objs := xgene_enet_hw.o xgene_enet_xgmac.o \ ++xgene-enet-objs := xgene_enet_hw.o xgene_enet_sgmac.o xgene_enet_xgmac.o \ + xgene_enet_main.o xgene_enet_ethtool.o + obj-$(CONFIG_NET_XGENE) += xgene-enet.o +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +index 2efc4d9..3855858 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +@@ -44,6 +44,7 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) + + enum xgene_enet_rm { + RM0, ++ RM1, + RM3 = 3 + }; + +@@ -143,6 +144,8 @@ enum xgene_enet_rm { + #define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4) + #define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2) + #define CFG_WAITASYNCRD_SET(dst, val) xgene_set_bits(dst, val, 0, 16) ++#define CFG_CLE_DSTQID0(val) (val & GENMASK(11, 0)) ++#define CFG_CLE_FPSEL0(val) ((val << 16) & GENMASK(19, 16)) + #define ICM_CONFIG0_REG_0_ADDR 0x0400 + #define ICM_CONFIG2_REG_0_ADDR 0x0410 + #define RX_DV_GATE_REG_0_ADDR 0x05fc +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index 9e251ec..3c208cc 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -21,6 +21,7 @@ + + #include "xgene_enet_main.h" + #include "xgene_enet_hw.h" ++#include "xgene_enet_sgmac.h" + #include "xgene_enet_xgmac.h" + + static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) +@@ -813,6 +814,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + return pdata->phy_mode; + } + if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && ++ pdata->phy_mode != PHY_INTERFACE_MODE_SGMII && + pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { + dev_err(dev, "Incorrect phy-connection-type specified\n"); + return -ENODEV; +@@ -830,7 +832,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; + pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; + pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; +- if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || ++ pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { + pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; + pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; + } else { +@@ -881,6 +884,11 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) + pdata->port_ops = &xgene_gport_ops; + pdata->rm = RM3; + break; ++ case PHY_INTERFACE_MODE_SGMII: ++ pdata->mac_ops = &xgene_sgmac_ops; ++ pdata->port_ops = &xgene_sgport_ops; ++ pdata->rm = RM1; ++ break; + default: + pdata->mac_ops = &xgene_xgmac_ops; + pdata->port_ops = &xgene_xgport_ops; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index 10b03a1..874e5a0 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -39,6 +39,9 @@ + #define NUM_PKT_BUF 64 + #define NUM_BUFPOOL 32 + ++#define PHY_POLL_LINK_ON (10 * HZ) ++#define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) ++ + /* software context of a descriptor ring */ + struct xgene_enet_desc_ring { + struct net_device *ndev; +@@ -118,6 +121,13 @@ struct xgene_enet_pdata { + struct delayed_work link_work; + }; + ++struct xgene_indirect_ctl { ++ void __iomem *addr; ++ void __iomem *ctl; ++ void __iomem *cmd; ++ void __iomem *cmd_done; ++}; ++ + /* Set the specified value into a bit-field defined by its starting position + * and length within a single u64. + */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +new file mode 100644 +index 0000000..e6d24c2 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +@@ -0,0 +1,389 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian ++ * Keyur Chudgar ++ * ++ * 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 "xgene_enet_main.h" ++#include "xgene_enet_hw.h" ++#include "xgene_enet_sgmac.h" ++ ++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_ring_if(struct xgene_enet_pdata *p, ++ u32 offset, u32 val) ++{ ++ iowrite32(val, p->eth_ring_if_addr + offset); ++} ++ ++static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *p, ++ u32 offset, u32 val) ++{ ++ iowrite32(val, p->eth_diag_csr_addr + offset); ++} ++ ++static bool xgene_enet_wr_indirect(struct xgene_indirect_ctl *ctl, ++ u32 wr_addr, u32 wr_data) ++{ ++ int i; ++ ++ iowrite32(wr_addr, ctl->addr); ++ iowrite32(wr_data, ctl->ctl); ++ iowrite32(XGENE_ENET_WR_CMD, ctl->cmd); ++ ++ /* wait for write command to complete */ ++ for (i = 0; i < 10; i++) { ++ if (ioread32(ctl->cmd_done)) { ++ iowrite32(0, ctl->cmd); ++ return true; ++ } ++ udelay(1); ++ } ++ ++ return false; ++} ++ ++static void xgene_enet_wr_mac(struct xgene_enet_pdata *p, ++ u32 wr_addr, u32 wr_data) ++{ ++ struct xgene_indirect_ctl ctl = { ++ .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, ++ .ctl = p->mcx_mac_addr + MAC_WRITE_REG_OFFSET, ++ .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, ++ .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET ++ }; ++ ++ if (!xgene_enet_wr_indirect(&ctl, wr_addr, wr_data)) ++ netdev_err(p->ndev, "mac write failed, addr: %04x\n", wr_addr); ++} ++ ++static u32 xgene_enet_rd_csr(struct xgene_enet_pdata *p, u32 offset) ++{ ++ return ioread32(p->eth_csr_addr + offset); ++} ++ ++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_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) ++{ ++ u32 rd_data; ++ int i; ++ ++ iowrite32(rd_addr, ctl->addr); ++ iowrite32(XGENE_ENET_RD_CMD, ctl->cmd); ++ ++ /* wait for read command to complete */ ++ for (i = 0; i < 10; i++) { ++ if (ioread32(ctl->cmd_done)) { ++ rd_data = ioread32(ctl->ctl); ++ iowrite32(0, ctl->cmd); ++ ++ return rd_data; ++ } ++ udelay(1); ++ } ++ ++ pr_err("%s: mac read failed, addr: %04x\n", __func__, rd_addr); ++ ++ return 0; ++} ++ ++static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr) ++{ ++ struct xgene_indirect_ctl ctl = { ++ .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, ++ .ctl = p->mcx_mac_addr + MAC_READ_REG_OFFSET, ++ .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, ++ .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET ++ }; ++ ++ return xgene_enet_rd_indirect(&ctl, rd_addr); ++} ++ ++static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) ++{ ++ struct net_device *ndev = p->ndev; ++ u32 data; ++ int i; ++ ++ xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); ++ for (i = 0; i < 10 && data != ~0U ; i++) { ++ usleep_range(100, 110); ++ data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR); ++ } ++ ++ if (data != ~0U) { ++ netdev_err(ndev, "Failed to release memory from shutdown\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p) ++{ ++ u32 val = 0xffffffff; ++ ++ xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQASSOC_ADDR, val); ++ xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPQASSOC_ADDR, val); ++} ++ ++static void xgene_mii_phy_write(struct xgene_enet_pdata *p, u8 phy_id, ++ u32 reg, u16 data) ++{ ++ u32 addr, wr_data, done; ++ int i; ++ ++ addr = PHY_ADDR(phy_id) | REG_ADDR(reg); ++ xgene_enet_wr_mac(p, MII_MGMT_ADDRESS_ADDR, addr); ++ ++ wr_data = PHY_CONTROL(data); ++ xgene_enet_wr_mac(p, MII_MGMT_CONTROL_ADDR, wr_data); ++ ++ for (i = 0; i < 10; i++) { ++ done = xgene_enet_rd_mac(p, MII_MGMT_INDICATORS_ADDR); ++ if (!(done & BUSY_MASK)) ++ return; ++ usleep_range(10, 20); ++ } ++ ++ netdev_err(p->ndev, "MII_MGMT write failed\n"); ++} ++ ++static u32 xgene_mii_phy_read(struct xgene_enet_pdata *p, u8 phy_id, u32 reg) ++{ ++ u32 addr, data, done; ++ int i; ++ ++ addr = PHY_ADDR(phy_id) | REG_ADDR(reg); ++ xgene_enet_wr_mac(p, MII_MGMT_ADDRESS_ADDR, addr); ++ xgene_enet_wr_mac(p, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); ++ ++ for (i = 0; i < 10; i++) { ++ done = xgene_enet_rd_mac(p, MII_MGMT_INDICATORS_ADDR); ++ if (!(done & BUSY_MASK)) { ++ data = xgene_enet_rd_mac(p, MII_MGMT_STATUS_ADDR); ++ xgene_enet_wr_mac(p, MII_MGMT_COMMAND_ADDR, 0); ++ ++ return data; ++ } ++ usleep_range(10, 20); ++ } ++ ++ netdev_err(p->ndev, "MII_MGMT read failed\n"); ++ ++ return 0; ++} ++ ++static void xgene_sgmac_reset(struct xgene_enet_pdata *p) ++{ ++ xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, SOFT_RESET1); ++ xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, 0); ++} ++ ++static void xgene_sgmac_set_mac_addr(struct xgene_enet_pdata *p) ++{ ++ u32 addr0, addr1; ++ u8 *dev_addr = p->ndev->dev_addr; ++ ++ addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | ++ (dev_addr[1] << 8) | dev_addr[0]; ++ xgene_enet_wr_mac(p, STATION_ADDR0_ADDR, addr0); ++ ++ addr1 = xgene_enet_rd_mac(p, STATION_ADDR1_ADDR); ++ addr1 |= (dev_addr[5] << 24) | (dev_addr[4] << 16); ++ xgene_enet_wr_mac(p, STATION_ADDR1_ADDR, addr1); ++} ++ ++static u32 xgene_enet_link_status(struct xgene_enet_pdata *p) ++{ ++ u32 data; ++ ++ data = xgene_mii_phy_read(p, INT_PHY_ADDR, ++ SGMII_BASE_PAGE_ABILITY_ADDR >> 2); ++ ++ return data & LINK_UP; ++} ++ ++static void xgene_sgmac_init(struct xgene_enet_pdata *p) ++{ ++ u32 data, loop = 10; ++ ++ xgene_sgmac_reset(p); ++ ++ /* Enable auto-negotiation */ ++ xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000); ++ xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); ++ ++ while (loop--) { ++ data = xgene_mii_phy_read(p, INT_PHY_ADDR, ++ SGMII_STATUS_ADDR >> 2); ++ if ((data & AUTO_NEG_COMPLETE) && (data & LINK_STATUS)) ++ break; ++ usleep_range(10, 20); ++ } ++ 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); ++ ++ data = xgene_enet_rd_csr(p, ENET_SPARE_CFG_REG_ADDR); ++ data |= MPA_IDLE_WITH_QMI_EMPTY; ++ xgene_enet_wr_csr(p, ENET_SPARE_CFG_REG_ADDR, data); ++ ++ xgene_sgmac_set_mac_addr(p); ++ ++ data = xgene_enet_rd_csr(p, DEBUG_REG_ADDR); ++ data |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; ++ xgene_enet_wr_csr(p, DEBUG_REG_ADDR, data); ++ ++ /* Adjust MDC clock frequency */ ++ data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR); ++ MGMT_CLOCK_SEL_SET(&data, 7); ++ xgene_enet_wr_mac(p, MII_MGMT_CONFIG_ADDR, data); ++ ++ /* Enable drop if bufpool not available */ ++ data = xgene_enet_rd_csr(p, RSIF_CONFIG_REG_ADDR); ++ data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; ++ xgene_enet_wr_csr(p, RSIF_CONFIG_REG_ADDR, data); ++ ++ /* Rtype should be copied from FP */ ++ xgene_enet_wr_csr(p, RSIF_RAM_DBG_REG0_ADDR, 0); ++ ++ /* Bypass traffic gating */ ++ xgene_enet_wr_csr(p, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); ++ xgene_enet_wr_csr(p, CFG_BYPASS_ADDR, RESUME_TX); ++ xgene_enet_wr_csr(p, SG_RX_DV_GATE_REG_0_ADDR, RESUME_RX0); ++} ++ ++static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set) ++{ ++ u32 data; ++ ++ data = xgene_enet_rd_mac(p, MAC_CONFIG_1_ADDR); ++ ++ if (set) ++ data |= bits; ++ else ++ data &= ~bits; ++ ++ xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, data); ++} ++ ++static void xgene_sgmac_rx_enable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, RX_EN, true); ++} ++ ++static void xgene_sgmac_tx_enable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, TX_EN, true); ++} ++ ++static void xgene_sgmac_rx_disable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, RX_EN, false); ++} ++ ++static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, TX_EN, false); ++} ++ ++static void xgene_enet_reset(struct xgene_enet_pdata *p) ++{ ++ clk_prepare_enable(p->clk); ++ clk_disable_unprepare(p->clk); ++ clk_prepare_enable(p->clk); ++ ++ xgene_enet_ecc_init(p); ++ xgene_enet_config_ring_if_assoc(p); ++} ++ ++static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p, ++ u32 dst_ring_num, u16 bufpool_id) ++{ ++ u32 data, fpsel; ++ ++ data = CFG_CLE_BYPASS_EN0; ++ xgene_enet_wr_csr(p, CLE_BYPASS_REG0_0_ADDR, data); ++ ++ fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; ++ data = CFG_CLE_DSTQID0(dst_ring_num) | CFG_CLE_FPSEL0(fpsel); ++ xgene_enet_wr_csr(p, CLE_BYPASS_REG1_0_ADDR, data); ++} ++ ++static void xgene_enet_shutdown(struct xgene_enet_pdata *p) ++{ ++ clk_disable_unprepare(p->clk); ++} ++ ++static void xgene_enet_link_state(struct work_struct *work) ++{ ++ struct xgene_enet_pdata *p = container_of(to_delayed_work(work), ++ struct xgene_enet_pdata, link_work); ++ struct net_device *ndev = p->ndev; ++ u32 link, poll_interval; ++ ++ link = xgene_enet_link_status(p); ++ if (link) { ++ if (!netif_carrier_ok(ndev)) { ++ netif_carrier_on(ndev); ++ xgene_sgmac_init(p); ++ xgene_sgmac_rx_enable(p); ++ xgene_sgmac_tx_enable(p); ++ netdev_info(ndev, "Link is Up - 1Gbps\n"); ++ } ++ poll_interval = PHY_POLL_LINK_ON; ++ } else { ++ if (netif_carrier_ok(ndev)) { ++ xgene_sgmac_rx_disable(p); ++ xgene_sgmac_tx_disable(p); ++ netif_carrier_off(ndev); ++ netdev_info(ndev, "Link is Down\n"); ++ } ++ poll_interval = PHY_POLL_LINK_OFF; ++ } ++ ++ schedule_delayed_work(&p->link_work, poll_interval); ++} ++ ++struct xgene_mac_ops xgene_sgmac_ops = { ++ .init = xgene_sgmac_init, ++ .reset = xgene_sgmac_reset, ++ .rx_enable = xgene_sgmac_rx_enable, ++ .tx_enable = xgene_sgmac_tx_enable, ++ .rx_disable = xgene_sgmac_rx_disable, ++ .tx_disable = xgene_sgmac_tx_disable, ++ .set_mac_addr = xgene_sgmac_set_mac_addr, ++ .link_state = xgene_enet_link_state ++}; ++ ++struct xgene_port_ops xgene_sgport_ops = { ++ .reset = xgene_enet_reset, ++ .cle_bypass = xgene_enet_cle_bypass, ++ .shutdown = xgene_enet_shutdown ++}; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +new file mode 100644 +index 0000000..de43246 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +@@ -0,0 +1,41 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian ++ * Keyur Chudgar ++ * ++ * 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 __XGENE_ENET_SGMAC_H__ ++#define __XGENE_ENET_SGMAC_H__ ++ ++#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 INT_PHY_ADDR 0x1e ++#define SGMII_TBI_CONTROL_ADDR 0x44 ++#define SGMII_CONTROL_ADDR 0x00 ++#define SGMII_STATUS_ADDR 0x04 ++#define SGMII_BASE_PAGE_ABILITY_ADDR 0x14 ++#define AUTO_NEG_COMPLETE BIT(5) ++#define LINK_STATUS BIT(2) ++#define LINK_UP BIT(15) ++#define MPA_IDLE_WITH_QMI_EMPTY BIT(12) ++#define SG_RX_DV_GATE_REG_0_ADDR 0x0dfc ++ ++extern struct xgene_mac_ops xgene_sgmac_ops; ++extern struct xgene_port_ops xgene_sgport_ops; ++ ++#endif /* __XGENE_ENET_SGMAC_H__ */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +index dcb2087..5a5296a 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +@@ -47,9 +47,6 @@ + #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 + #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 + +-#define PHY_POLL_LINK_ON (10 * HZ) +-#define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) +- + extern struct xgene_mac_ops xgene_xgmac_ops; + extern struct xgene_port_ops xgene_xgport_ops; + +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Backward-compatibility-with-older-.patch b/debian/patches/features/arm64/drivers-net-xgene-Backward-compatibility-with-older-.patch new file mode 100644 index 000000000..de166c118 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Backward-compatibility-with-older-.patch @@ -0,0 +1,175 @@ +From 092e35e5b10fdea2d814aa96ab2c2f2aad477640 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 3 Nov 2014 11:59:55 -0800 +Subject: [PATCH 08/11] drivers: net: xgene: Backward compatibility with older + firmware +Origin: https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=c3f4465d272fa94d5a077c502e83d3e712ec8d62 + +This patch adds support when used with older firmware (<= 1.13.28). + +- Added xgene_ring_mgr_init() to check whether ring manager is initialized +- Calling xgene_ring_mgr_init() from xgene_port_ops.reset() +- To handle errors, changed the return type of xgene_port_ops.reset() + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 18 +++++++++++++++++- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 4 ++++ + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 5 ++++- + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 2 +- + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 7 ++++++- + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 7 ++++++- + 6 files changed, 38 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +index 63ea194..7ba83ff 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +@@ -575,10 +575,24 @@ static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); + } + +-static void xgene_enet_reset(struct xgene_enet_pdata *pdata) ++bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) ++{ ++ if (!ioread32(p->ring_csr_addr + CLKEN_ADDR)) ++ return false; ++ ++ if (ioread32(p->ring_csr_addr + SRST_ADDR)) ++ return false; ++ ++ return true; ++} ++ ++static int xgene_enet_reset(struct xgene_enet_pdata *pdata) + { + u32 val; + ++ if (!xgene_ring_mgr_init(pdata)) ++ return -ENODEV; ++ + clk_prepare_enable(pdata->clk); + clk_disable_unprepare(pdata->clk); + clk_prepare_enable(pdata->clk); +@@ -590,6 +604,8 @@ static void xgene_enet_reset(struct xgene_enet_pdata *pdata) + val |= SCAN_AUTO_INCR; + MGMT_CLOCK_SEL_SET(&val, 1); + xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); ++ ++ return 0; + } + + static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +index 3855858..ec45f32 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +@@ -104,6 +104,9 @@ enum xgene_enet_rm { + #define BLOCK_ETH_MAC_OFFSET 0x0000 + #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 + ++#define CLKEN_ADDR 0xc208 ++#define SRST_ADDR 0xc200 ++ + #define MAC_ADDR_REG_OFFSET 0x00 + #define MAC_COMMAND_REG_OFFSET 0x04 + #define MAC_WRITE_REG_OFFSET 0x08 +@@ -318,6 +321,7 @@ 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); + + extern struct xgene_mac_ops xgene_gmac_ops; + extern 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 3c208cc..cc3f955 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -852,7 +852,9 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) + u16 dst_ring_num; + int ret; + +- pdata->port_ops->reset(pdata); ++ ret = pdata->port_ops->reset(pdata); ++ if (ret) ++ return ret; + + ret = xgene_enet_create_desc_rings(ndev); + if (ret) { +@@ -954,6 +956,7 @@ static int xgene_enet_probe(struct platform_device *pdev) + + return ret; + err: ++ unregister_netdev(ndev); + free_netdev(ndev); + 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 874e5a0..dba647d 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -83,7 +83,7 @@ struct xgene_mac_ops { + }; + + struct xgene_port_ops { +- void (*reset)(struct xgene_enet_pdata *pdata); ++ int (*reset)(struct xgene_enet_pdata *pdata); + 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 c22f326..f5d4f68 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +@@ -311,14 +311,19 @@ static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p) + xgene_sgmac_rxtx(p, TX_EN, false); + } + +-static void xgene_enet_reset(struct xgene_enet_pdata *p) ++static int xgene_enet_reset(struct xgene_enet_pdata *p) + { ++ if (!xgene_ring_mgr_init(p)) ++ return -ENODEV; ++ + clk_prepare_enable(p->clk); + clk_disable_unprepare(p->clk); + clk_prepare_enable(p->clk); + + xgene_enet_ecc_init(p); + xgene_enet_config_ring_if_assoc(p); ++ ++ return 0; + } + + static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p, +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +index 67d0720..a18a9d1 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +@@ -252,14 +252,19 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); + } + +-static void xgene_enet_reset(struct xgene_enet_pdata *pdata) ++static int xgene_enet_reset(struct xgene_enet_pdata *pdata) + { ++ if (!xgene_ring_mgr_init(pdata)) ++ return -ENODEV; ++ + clk_prepare_enable(pdata->clk); + clk_disable_unprepare(pdata->clk); + clk_prepare_enable(pdata->clk); + + xgene_enet_ecc_init(pdata); + xgene_enet_config_ring_if_assoc(pdata); ++ ++ return 0; + } + + static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Preparing-for-adding-10GbE-support.patch b/debian/patches/features/arm64/drivers-net-xgene-Preparing-for-adding-10GbE-support.patch new file mode 100644 index 000000000..d48a634c8 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Preparing-for-adding-10GbE-support.patch @@ -0,0 +1,353 @@ +From 33f8dba6cb5493b2fff26c43a6cc0321e0814732 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Thu, 9 Oct 2014 18:32:05 -0700 +Subject: [PATCH 01/11] drivers: net: xgene: Preparing for adding 10GbE support +Origin: https://git.kernel.org/linus/d0eb74582fa7b5c15710d293a3c4d8d3409ae165 + +- Rearranged code to pave the way for adding 10GbE support +- Added mac_ops structure containing function pointers for mac specific functions +- Added port_ops structure containing function pointers for port specific functions + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 44 ++++++++++++++++-------- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 16 ++------- + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 40 +++++++++++++-------- + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 19 ++++++++++ + 4 files changed, 78 insertions(+), 41 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +index 812d8d6..c8f3824 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +@@ -402,7 +402,7 @@ static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata, + return data; + } + +-void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) ++static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) + { + u32 addr0, addr1; + u8 *dev_addr = pdata->ndev->dev_addr; +@@ -436,13 +436,13 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) + return 0; + } + +-void xgene_gmac_reset(struct xgene_enet_pdata *pdata) ++static void xgene_gmac_reset(struct xgene_enet_pdata *pdata) + { + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); + } + +-void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed) ++static void xgene_gmac_init(struct xgene_enet_pdata *pdata) + { + u32 value, mc2; + u32 intf_ctl, rgmii; +@@ -456,7 +456,7 @@ void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed) + xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl); + xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii); + +- switch (speed) { ++ switch (pdata->phy_speed) { + case SPEED_10: + ENET_INTERFACE_MODE2_SET(&mc2, 1); + CFG_MACMODE_SET(&icm0, 0); +@@ -525,8 +525,8 @@ static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val); + } + +-void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, +- u32 dst_ring_num, u16 bufpool_id) ++static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, ++ u32 dst_ring_num, u16 bufpool_id) + { + u32 cb; + u32 fpsel; +@@ -544,7 +544,7 @@ void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, + xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb); + } + +-void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) ++static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) + { + u32 data; + +@@ -552,7 +552,7 @@ void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); + } + +-void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) ++static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) + { + u32 data; + +@@ -560,7 +560,7 @@ void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); + } + +-void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) ++static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) + { + u32 data; + +@@ -568,7 +568,7 @@ void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); + } + +-void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) ++static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) + { + u32 data; + +@@ -576,7 +576,7 @@ void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); + } + +-void xgene_enet_reset(struct xgene_enet_pdata *pdata) ++static void xgene_enet_reset(struct xgene_enet_pdata *pdata) + { + u32 val; + +@@ -593,7 +593,7 @@ void xgene_enet_reset(struct xgene_enet_pdata *pdata) + xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); + } + +-void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) ++static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) + { + clk_disable_unprepare(pdata->clk); + } +@@ -627,10 +627,10 @@ static void xgene_enet_adjust_link(struct net_device *ndev) + + if (phydev->link) { + if (pdata->phy_speed != phydev->speed) { +- xgene_gmac_init(pdata, phydev->speed); ++ pdata->phy_speed = phydev->speed; ++ xgene_gmac_init(pdata); + xgene_gmac_rx_enable(pdata); + xgene_gmac_tx_enable(pdata); +- pdata->phy_speed = phydev->speed; + phy_print_status(phydev); + } + } else { +@@ -726,3 +726,19 @@ void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) + mdiobus_free(pdata->mdio_bus); + pdata->mdio_bus = NULL; + } ++ ++struct xgene_mac_ops xgene_gmac_ops = { ++ .init = xgene_gmac_init, ++ .reset = xgene_gmac_reset, ++ .rx_enable = xgene_gmac_rx_enable, ++ .tx_enable = xgene_gmac_tx_enable, ++ .rx_disable = xgene_gmac_rx_disable, ++ .tx_disable = xgene_gmac_tx_disable, ++ .set_mac_addr = xgene_gmac_set_mac_addr, ++}; ++ ++struct xgene_port_ops xgene_gport_ops = { ++ .reset = xgene_enet_reset, ++ .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 371e7a5..084ac68 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +@@ -318,20 +318,10 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, + struct xgene_enet_pdata *pdata, + enum xgene_enet_err_code status); + +-void xgene_enet_reset(struct xgene_enet_pdata *priv); +-void xgene_gmac_reset(struct xgene_enet_pdata *priv); +-void xgene_gmac_init(struct xgene_enet_pdata *priv, int speed); +-void xgene_gmac_tx_enable(struct xgene_enet_pdata *priv); +-void xgene_gmac_rx_enable(struct xgene_enet_pdata *priv); +-void xgene_gmac_tx_disable(struct xgene_enet_pdata *priv); +-void xgene_gmac_rx_disable(struct xgene_enet_pdata *priv); +-void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata); +-void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, +- u32 dst_ring_num, u16 bufpool_id); +-void xgene_gport_shutdown(struct xgene_enet_pdata *priv); +-void xgene_gmac_get_tx_stats(struct xgene_enet_pdata *pdata); +- + int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); + void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); + ++extern struct xgene_mac_ops xgene_gmac_ops; ++extern struct xgene_port_ops xgene_gport_ops; ++ + #endif /* __XGENE_ENET_HW_H__ */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index e4222af..c432644 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -413,7 +413,7 @@ static void xgene_enet_timeout(struct net_device *ndev) + { + struct xgene_enet_pdata *pdata = netdev_priv(ndev); + +- xgene_gmac_reset(pdata); ++ pdata->mac_ops->reset(pdata); + } + + static int xgene_enet_register_irq(struct net_device *ndev) +@@ -445,10 +445,11 @@ static void xgene_enet_free_irq(struct net_device *ndev) + static int xgene_enet_open(struct net_device *ndev) + { + struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct xgene_mac_ops *mac_ops = pdata->mac_ops; + int ret; + +- xgene_gmac_tx_enable(pdata); +- xgene_gmac_rx_enable(pdata); ++ mac_ops->tx_enable(pdata); ++ mac_ops->rx_enable(pdata); + + ret = xgene_enet_register_irq(ndev); + if (ret) +@@ -466,6 +467,7 @@ static int xgene_enet_open(struct net_device *ndev) + static int xgene_enet_close(struct net_device *ndev) + { + struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct xgene_mac_ops *mac_ops = pdata->mac_ops; + + netif_stop_queue(ndev); + +@@ -476,8 +478,8 @@ static int xgene_enet_close(struct net_device *ndev) + xgene_enet_free_irq(ndev); + xgene_enet_process_ring(pdata->rx_ring, -1); + +- xgene_gmac_tx_disable(pdata); +- xgene_gmac_rx_disable(pdata); ++ mac_ops->tx_disable(pdata); ++ mac_ops->rx_disable(pdata); + + return 0; + } +@@ -724,7 +726,7 @@ static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) + ret = eth_mac_addr(ndev, addr); + if (ret) + return ret; +- xgene_gmac_set_mac_addr(pdata); ++ pdata->mac_ops->set_mac_addr(pdata); + + return ret; + } +@@ -834,8 +836,8 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) + u16 dst_ring_num; + int ret; + +- xgene_gmac_tx_disable(pdata); +- xgene_gmac_rx_disable(pdata); ++ pdata->mac_ops->tx_disable(pdata); ++ pdata->mac_ops->rx_disable(pdata); + + ret = xgene_enet_create_desc_rings(ndev); + if (ret) { +@@ -853,11 +855,17 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) + } + + dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); +- xgene_enet_cle_bypass(pdata, dst_ring_num, buf_pool->id); ++ pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); + + return ret; + } + ++static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) ++{ ++ pdata->mac_ops = &xgene_gmac_ops; ++ pdata->port_ops = &xgene_gport_ops; ++} ++ + static int xgene_enet_probe(struct platform_device *pdev) + { + struct net_device *ndev; +@@ -886,8 +894,9 @@ static int xgene_enet_probe(struct platform_device *pdev) + if (ret) + goto err; + +- xgene_enet_reset(pdata); +- xgene_gmac_init(pdata, SPEED_1000); ++ xgene_enet_setup_ops(pdata); ++ pdata->port_ops->reset(pdata); ++ pdata->mac_ops->init(pdata); + + ret = register_netdev(ndev); + if (ret) { +@@ -918,19 +927,21 @@ err: + static int xgene_enet_remove(struct platform_device *pdev) + { + struct xgene_enet_pdata *pdata; ++ struct xgene_mac_ops *mac_ops; + struct net_device *ndev; + + pdata = platform_get_drvdata(pdev); ++ mac_ops = pdata->mac_ops; + ndev = pdata->ndev; + +- xgene_gmac_rx_disable(pdata); +- xgene_gmac_tx_disable(pdata); ++ mac_ops->rx_disable(pdata); ++ mac_ops->tx_disable(pdata); + + netif_napi_del(&pdata->rx_ring->napi); + xgene_enet_mdio_remove(pdata); + xgene_enet_delete_desc_rings(pdata); + unregister_netdev(ndev); +- xgene_gport_shutdown(pdata); ++ pdata->port_ops->shutdown(pdata); + free_netdev(ndev); + + return 0; +@@ -956,5 +967,6 @@ module_platform_driver(xgene_enet_driver); + + MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver"); + MODULE_VERSION(XGENE_DRV_VERSION); ++MODULE_AUTHOR("Iyappan Subramanian "); + MODULE_AUTHOR("Keyur Chudgar "); + MODULE_LICENSE("GPL"); +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index 0815866..ac180f9 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -68,6 +68,23 @@ struct xgene_enet_desc_ring { + }; + }; + ++struct xgene_mac_ops { ++ void (*init)(struct xgene_enet_pdata *pdata); ++ void (*reset)(struct xgene_enet_pdata *pdata); ++ void (*tx_enable)(struct xgene_enet_pdata *pdata); ++ 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_mac_addr)(struct xgene_enet_pdata *pdata); ++}; ++ ++struct xgene_port_ops { ++ void (*reset)(struct xgene_enet_pdata *pdata); ++ void (*cle_bypass)(struct xgene_enet_pdata *pdata, ++ u32 dst_ring_num, u16 bufpool_id); ++ void (*shutdown)(struct xgene_enet_pdata *pdata); ++}; ++ + /* ethernet private data */ + struct xgene_enet_pdata { + struct net_device *ndev; +@@ -98,6 +115,8 @@ struct xgene_enet_pdata { + u32 speed; + u16 rm; + struct rtnl_link_stats64 stats; ++ struct xgene_mac_ops *mac_ops; ++ struct xgene_port_ops *port_ops; + }; + + /* Set the specified value into a bit-field defined by its starting position +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Preparing-for-adding-SGMII-based-1.patch b/debian/patches/features/arm64/drivers-net-xgene-Preparing-for-adding-SGMII-based-1.patch new file mode 100644 index 000000000..3f3573051 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Preparing-for-adding-SGMII-based-1.patch @@ -0,0 +1,153 @@ +From 0d0393191a19911ef523a4cba10bedb10bbf07dd Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 13 Oct 2014 17:05:33 -0700 +Subject: [PATCH 04/11] drivers: net: xgene: Preparing for adding SGMII based + 1GbE +Origin: https://git.kernel.org/linus/dc8385f0c0f46ca18c1c8ab59c9f565dc7cfa6bf + +- Added link_state function pointer to the xgene__mac_ops structure +- Moved ring manager (pdata->rm) assignment to xgene_enet_setup_ops +- Removed unused variable (pdata->phy_addr) and macro (FULL_DUPLEX) + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 1 - + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 1 - + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 8 +++++--- + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 2 +- + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 3 ++- + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 1 - + 6 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +index c8f3824..63ea194 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +@@ -410,7 +410,6 @@ static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) + addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | + (dev_addr[1] << 8) | dev_addr[0]; + addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); +- addr1 |= pdata->phy_addr & 0xFFFF; + + xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0); + xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1); +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +index 15ec426..2efc4d9 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +@@ -179,7 +179,6 @@ enum xgene_enet_rm { + #define TUND_ADDR 0x4a + + #define TSO_IPPROTO_TCP 1 +-#define FULL_DUPLEX 2 + + #define USERINFO_POS 0 + #define USERINFO_LEN 32 +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index 9b85239..9e251ec 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -833,11 +833,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; + pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; +- pdata->rm = RM3; + } else { + pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; + pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; +- pdata->rm = RM0; + } + pdata->rx_buff_cnt = NUM_PKT_BUF; + +@@ -881,10 +879,12 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) + case PHY_INTERFACE_MODE_RGMII: + pdata->mac_ops = &xgene_gmac_ops; + pdata->port_ops = &xgene_gport_ops; ++ pdata->rm = RM3; + break; + default: + pdata->mac_ops = &xgene_xgmac_ops; + pdata->port_ops = &xgene_xgport_ops; ++ pdata->rm = RM0; + break; + } + } +@@ -895,6 +895,7 @@ static int xgene_enet_probe(struct platform_device *pdev) + struct xgene_enet_pdata *pdata; + struct device *dev = &pdev->dev; + struct napi_struct *napi; ++ struct xgene_mac_ops *mac_ops; + int ret; + + ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata)); +@@ -937,10 +938,11 @@ static int xgene_enet_probe(struct platform_device *pdev) + + napi = &pdata->rx_ring->napi; + netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); ++ mac_ops = pdata->mac_ops; + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + ret = xgene_enet_mdio_config(pdata); + else +- INIT_DELAYED_WORK(&pdata->link_work, xgene_enet_link_state); ++ INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); + + return ret; + err: +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index 86cf68b..10b03a1 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -76,6 +76,7 @@ struct xgene_mac_ops { + void (*tx_disable)(struct xgene_enet_pdata *pdata); + void (*rx_disable)(struct xgene_enet_pdata *pdata); + void (*set_mac_addr)(struct xgene_enet_pdata *pdata); ++ void (*link_state)(struct work_struct *work); + }; + + struct xgene_port_ops { +@@ -109,7 +110,6 @@ struct xgene_enet_pdata { + void __iomem *base_addr; + void __iomem *ring_csr_addr; + void __iomem *ring_cmd_addr; +- u32 phy_addr; + int phy_mode; + enum xgene_enet_rm rm; + struct rtnl_link_stats64 stats; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +index cd64b9f..67d0720 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +@@ -284,7 +284,7 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) + clk_disable_unprepare(pdata->clk); + } + +-void xgene_enet_link_state(struct work_struct *work) ++static void xgene_enet_link_state(struct work_struct *work) + { + struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work), + struct xgene_enet_pdata, link_work); +@@ -322,6 +322,7 @@ struct xgene_mac_ops xgene_xgmac_ops = { + .rx_disable = xgene_xgmac_rx_disable, + .tx_disable = xgene_xgmac_tx_disable, + .set_mac_addr = xgene_xgmac_set_mac_addr, ++ .link_state = xgene_enet_link_state + }; + + struct xgene_port_ops xgene_xgport_ops = { +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +index d2d59e7..dcb2087 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +@@ -50,7 +50,6 @@ + #define PHY_POLL_LINK_ON (10 * HZ) + #define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) + +-void xgene_enet_link_state(struct work_struct *work); + extern struct xgene_mac_ops xgene_xgmac_ops; + extern struct xgene_port_ops xgene_xgport_ops; + +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-Rewrite-buggy-loop-in-xgene_enet_e.patch b/debian/patches/features/arm64/drivers-net-xgene-Rewrite-buggy-loop-in-xgene_enet_e.patch new file mode 100644 index 000000000..3676425c0 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-Rewrite-buggy-loop-in-xgene_enet_e.patch @@ -0,0 +1,54 @@ +From 9f2bc2c30d24987cff5edc43a3d8f89bef6ce12a Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Thu, 23 Oct 2014 10:25:53 +0200 +Subject: [PATCH 07/11] drivers: net: xgene: Rewrite buggy loop in + xgene_enet_ecc_init() +Origin: https://git.kernel.org/linus/b71e821de50f0ff92f10f33064ee1713e9014158 + +drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c: In function ‘xgene_enet_ecc_init’: +drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c:126: warning: ‘data’ may be used uninitialized in this function + +Depending on the arbitrary value on the stack, the loop may terminate +too early, and cause a bogus -ENODEV failure. + +Signed-off-by: Geert Uytterhoeven +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +index e6d24c2..c22f326 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +@@ -124,20 +124,18 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) + { + struct net_device *ndev = p->ndev; + u32 data; +- int i; ++ int i = 0; + + xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); +- for (i = 0; i < 10 && data != ~0U ; i++) { ++ do { + usleep_range(100, 110); + data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR); +- } ++ if (data == ~0U) ++ return 0; ++ } while (++i < 10); + +- if (data != ~0U) { +- netdev_err(ndev, "Failed to release memory from shutdown\n"); +- return -ENODEV; +- } +- +- return 0; ++ netdev_err(ndev, "Failed to release memory from shutdown\n"); ++ return -ENODEV; + } + + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p) +-- +2.1.0 + diff --git a/debian/patches/features/arm64/drivers-net-xgene-fix-Use-separate-resources.patch b/debian/patches/features/arm64/drivers-net-xgene-fix-Use-separate-resources.patch new file mode 100644 index 000000000..67fd5aab2 --- /dev/null +++ b/debian/patches/features/arm64/drivers-net-xgene-fix-Use-separate-resources.patch @@ -0,0 +1,78 @@ +From 33b54088743086cd6fdce269486e0bf27ed24155 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 3 Nov 2014 11:59:56 -0800 +Subject: [PATCH 09/11] drivers: net: xgene: fix: Use separate resources +Origin: https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=bdd330f0506b2c4d02d5453fa32e785f0c348388 + +This patch fixes the following kernel crash during SGMII based 1GbE probe. + + BUG: Bad page state in process swapper/0 pfn:40fe6ad + page:ffffffbee37a75d8 count:-1 mapcount:0 mapping: (null) index:0x0 + flags: 0x0() + page dumped because: nonzero _count + Modules linked in: + CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.17.0+ #7 + Call trace: + [] dump_backtrace+0x0/0x12c + [] show_stack+0x10/0x1c + [] dump_stack+0x74/0xc4 + [] bad_page+0xd8/0x128 + [] get_page_from_freelist+0x4b8/0x640 + [] __alloc_pages_nodemask+0xd8/0x834 + [] __netdev_alloc_frag+0x124/0x1b8 + [] __netdev_alloc_skb+0x90/0x10c + [] xgene_enet_refill_bufpool+0x11c/0x280 + [] xgene_enet_process_ring+0x168/0x340 + [] xgene_enet_napi+0x1c/0x50 + [] net_rx_action+0xc8/0x18c + [] __do_softirq+0x114/0x24c + [] irq_exit+0x94/0xc8 + [] __handle_domain_irq+0x8c/0xf4 + [] gic_handle_irq+0x30/0x7c + +This was due to hardware resource sharing conflict with the firmware. This +patch fixes this crash by using resources (descriptor ring, prefetch buffer) +that are not shared. + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 6 +++--- + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 3 +++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index cc3f955..1236696 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -639,9 +639,9 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) + struct device *dev = ndev_to_dev(ndev); + struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring; + struct xgene_enet_desc_ring *buf_pool = NULL; +- u8 cpu_bufnum = 0, eth_bufnum = 0; +- u8 bp_bufnum = 0x20; +- u16 ring_id, ring_num = 0; ++ u8 cpu_bufnum = 0, eth_bufnum = START_ETH_BUFNUM; ++ u8 bp_bufnum = START_BP_BUFNUM; ++ u16 ring_id, ring_num = START_RING_NUM; + int ret; + + /* allocate rx descriptor ring */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index dba647d..f9958fa 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -38,6 +38,9 @@ + #define SKB_BUFFER_SIZE (XGENE_ENET_MAX_MTU - NET_IP_ALIGN) + #define NUM_PKT_BUF 64 + #define NUM_BUFPOOL 32 ++#define START_ETH_BUFNUM 2 ++#define START_BP_BUFNUM 0x22 ++#define START_RING_NUM 8 + + #define PHY_POLL_LINK_ON (10 * HZ) + #define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) +-- +2.1.0 + diff --git a/debian/patches/features/arm64/dtb-Add-10GbE-node-to-APM-X-Gene-SoC-device-tree.patch b/debian/patches/features/arm64/dtb-Add-10GbE-node-to-APM-X-Gene-SoC-device-tree.patch new file mode 100644 index 000000000..913c14f95 --- /dev/null +++ b/debian/patches/features/arm64/dtb-Add-10GbE-node-to-APM-X-Gene-SoC-device-tree.patch @@ -0,0 +1,84 @@ +From fe64571ba6b03ee505c4b384da1b335729b36db3 Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Thu, 9 Oct 2014 18:32:04 -0700 +Subject: [PATCH 10/11] dtb: Add 10GbE node to APM X-Gene SoC device tree +Origin: https://git.kernel.org/linus/5fb32417b7e52d2e6d5f5c64d277a03e5c998a02 + +Added 10GbE interface and clock nodes. + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + arch/arm64/boot/dts/apm-mustang.dts | 4 ++++ + arch/arm64/boot/dts/apm-storm.dtsi | 29 ++++++++++++++++++++++++++++- + 2 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts +index b2f5622..2ae782b 100644 +--- a/arch/arm64/boot/dts/apm-mustang.dts ++++ b/arch/arm64/boot/dts/apm-mustang.dts +@@ -32,3 +32,7 @@ + &menet { + status = "ok"; + }; ++ ++&xgenet { ++ status = "ok"; ++}; +diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi +index c0aceef..4d762a3 100644 +--- a/arch/arm64/boot/dts/apm-storm.dtsi ++++ b/arch/arm64/boot/dts/apm-storm.dtsi +@@ -176,6 +176,16 @@ + clock-output-names = "menetclk"; + }; + ++ xge0clk: xge0clk@1f61c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f61c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ csr-mask = <0x3>; ++ clock-output-names = "xge0clk"; ++ }; ++ + sataphy1clk: sataphy1clk@1f21c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; +@@ -407,7 +417,8 @@ + interrupts = <0x0 0x3c 0x4>; + dma-coherent; + clocks = <&menetclk 0>; +- local-mac-address = [00 01 73 00 00 01]; ++ /* mac address will be overwritten by the bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; + phy-connection-type = "rgmii"; + phy-handle = <&menetphy>; + mdio { +@@ -421,5 +432,21 @@ + + }; + }; ++ ++ xgenet: ethernet@1f610000 { ++ compatible = "apm,xgene-enet"; ++ status = "disabled"; ++ reg = <0x0 0x1f610000 0x0 0xd100>, ++ <0x0 0x1f600000 0x0 0X400>, ++ <0x0 0x18000000 0x0 0X200>; ++ reg-names = "enet_csr", "ring_csr", "ring_cmd"; ++ interrupts = <0x0 0x60 0x4>; ++ dma-coherent; ++ clocks = <&xge0clk 0>; ++ /* mac address will be overwritten by the bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ phy-connection-type = "xgmii"; ++ }; ++ + }; + }; +-- +2.1.0 + diff --git a/debian/patches/features/arm64/dtb-Add-SGMII-based-1GbE-node-to-APM-X-Gene-SoC-devi.patch b/debian/patches/features/arm64/dtb-Add-SGMII-based-1GbE-node-to-APM-X-Gene-SoC-devi.patch new file mode 100644 index 000000000..c0257595f --- /dev/null +++ b/debian/patches/features/arm64/dtb-Add-SGMII-based-1GbE-node-to-APM-X-Gene-SoC-devi.patch @@ -0,0 +1,75 @@ +From 8e17e86dde4b417cdbe8ee9073b8ffc10a1f5afb Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 13 Oct 2014 17:05:32 -0700 +Subject: [PATCH 11/11] dtb: Add SGMII based 1GbE node to APM X-Gene SoC device + tree +Origin: https://git.kernel.org/linus/4c2e7f0954dcd9fbb47d065c654d44608dad38e0 + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Signed-off-by: David S. Miller +--- + arch/arm64/boot/dts/apm-mustang.dts | 4 ++++ + arch/arm64/boot/dts/apm-storm.dtsi | 24 ++++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts +index 2ae782b..71a1489 100644 +--- a/arch/arm64/boot/dts/apm-mustang.dts ++++ b/arch/arm64/boot/dts/apm-mustang.dts +@@ -33,6 +33,10 @@ + status = "ok"; + }; + ++&sgenet0 { ++ status = "ok"; ++}; ++ + &xgenet { + status = "ok"; + }; +diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi +index d16cc03..f45bbfe 100644 +--- a/arch/arm64/boot/dts/apm-storm.dtsi ++++ b/arch/arm64/boot/dts/apm-storm.dtsi +@@ -176,6 +176,16 @@ + clock-output-names = "menetclk"; + }; + ++ sge0clk: sge0clk@1f21c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f21c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ csr-mask = <0x3>; ++ clock-output-names = "sge0clk"; ++ }; ++ + xge0clk: xge0clk@1f61c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; +@@ -446,6 +456,20 @@ + }; + }; + ++ sgenet0: ethernet@1f210000 { ++ compatible = "apm,xgene-enet"; ++ status = "disabled"; ++ reg = <0x0 0x1f210000 0x0 0x10000>, ++ <0x0 0x1f200000 0x0 0X10000>, ++ <0x0 0x1B000000 0x0 0X20000>; ++ reg-names = "enet_csr", "ring_csr", "ring_cmd"; ++ interrupts = <0x0 0xA0 0x4>; ++ dma-coherent; ++ clocks = <&sge0clk 0>; ++ local-mac-address = [00 00 00 00 00 00]; ++ phy-connection-type = "sgmii"; ++ }; ++ + xgenet: ethernet@1f610000 { + compatible = "apm,xgene-enet"; + status = "disabled"; +-- +2.1.0 + diff --git a/debian/patches/features/arm64/dtb-xgene-fix-Backward-compatibility-with-older-firm.patch b/debian/patches/features/arm64/dtb-xgene-fix-Backward-compatibility-with-older-firm.patch new file mode 100644 index 000000000..6f5e6f735 --- /dev/null +++ b/debian/patches/features/arm64/dtb-xgene-fix-Backward-compatibility-with-older-firm.patch @@ -0,0 +1,85 @@ +From 09c9e0593d7215c809a4a47659b0e760112d656e Mon Sep 17 00:00:00 2001 +From: Iyappan Subramanian +Date: Mon, 3 Nov 2014 11:59:54 -0800 +Subject: [PATCH] dtb: xgene: fix: Backward compatibility with older firmware + +The following kernel crash was reported when using older firmware (<= 1.13.28). + +[ 0.980000] libphy: APM X-Gene MDIO bus: probed +[ 1.130000] Unhandled fault: synchronous external abort (0x96000010) at 0xffffff800009a17c +[ 1.140000] Internal error: : 96000010 [#1] SMP +[ 1.140000] Modules linked in: +[ 1.140000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.17.0+ #21 +[ 1.140000] task: ffffffc3f0110000 ti: ffffffc3f0064000 task.ti: ffffffc3f0064000 +[ 1.140000] PC is at ioread32+0x58/0x68 +[ 1.140000] LR is at xgene_enet_setup_ring+0x18c/0x1cc +[ 1.140000] pc : [] lr : [] pstate: a0000045 +[ 1.140000] sp : ffffffc3f0067b20 +[ 1.140000] x29: ffffffc3f0067b20 x28: ffffffc000aa8ea0 +[ 1.140000] x27: ffffffc000bb2000 x26: ffffffc000a64270 +[ 1.140000] x25: ffffffc000b05ad8 x24: ffffffc0ff99ba58 +[ 1.140000] x23: 0000000000004000 x22: 0000000000004000 +[ 1.140000] x21: 0000000000000200 x20: 0000000000200000 +[ 1.140000] x19: ffffffc0ff99ba18 x18: ffffffc0007a6000 +[ 1.140000] x17: 0000000000000007 x16: 000000000000000e +[ 1.140000] x15: 0000000000000001 x14: 0000000000000000 +[ 1.140000] x13: ffffffbeedb71320 x12: 00000000ffffff80 +[ 1.140000] x11: 0000000000000002 x10: 0000000000000000 +[ 1.140000] x9 : 0000000000000000 x8 : ffffffc3eb2a4000 +[ 1.140000] x7 : 0000000000000000 x6 : 0000000000000000 +[ 1.140000] x5 : 0000000001080000 x4 : 000000007d654010 +[ 1.140000] x3 : ffffffffffffffff x2 : 000000000003ffff +[ 1.140000] x1 : ffffff800009a17c x0 : ffffff800009a17c + +The issue was that the older firmware does not support 10GbE and +SGMII based 1GBE interfaces. + +This patch changes the address length of the reg property of sgmii0 and xgmii +nodes and serves as preparatory patch for the fix. + +Signed-off-by: Iyappan Subramanian +Signed-off-by: Keyur Chudgar +Reported-by: Dann Frazier +Signed-off-by: David S. Miller +--- + arch/arm64/boot/dts/apm-storm.dtsi | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi +index 295c72d..f1ad9c2 100644 +--- a/arch/arm64/boot/dts/apm-storm.dtsi ++++ b/arch/arm64/boot/dts/apm-storm.dtsi +@@ -599,7 +599,7 @@ + compatible = "apm,xgene-enet"; + status = "disabled"; + reg = <0x0 0x17020000 0x0 0xd100>, +- <0x0 0X17030000 0x0 0X400>, ++ <0x0 0X17030000 0x0 0Xc300>, + <0x0 0X10000000 0x0 0X200>; + reg-names = "enet_csr", "ring_csr", "ring_cmd"; + interrupts = <0x0 0x3c 0x4>; +@@ -624,9 +624,9 @@ + sgenet0: ethernet@1f210000 { + compatible = "apm,xgene-enet"; + status = "disabled"; +- reg = <0x0 0x1f210000 0x0 0x10000>, +- <0x0 0x1f200000 0x0 0X10000>, +- <0x0 0x1B000000 0x0 0X20000>; ++ reg = <0x0 0x1f210000 0x0 0xd100>, ++ <0x0 0x1f200000 0x0 0Xc300>, ++ <0x0 0x1B000000 0x0 0X200>; + reg-names = "enet_csr", "ring_csr", "ring_cmd"; + interrupts = <0x0 0xA0 0x4>; + dma-coherent; +@@ -639,7 +639,7 @@ + compatible = "apm,xgene-enet"; + status = "disabled"; + reg = <0x0 0x1f610000 0x0 0xd100>, +- <0x0 0x1f600000 0x0 0X400>, ++ <0x0 0x1f600000 0x0 0Xc300>, + <0x0 0x18000000 0x0 0X200>; + reg-names = "enet_csr", "ring_csr", "ring_cmd"; + interrupts = <0x0 0x60 0x4>; +-- +2.1.0 + diff --git a/debian/patches/series b/debian/patches/series index bb35c4d43..1a6f31b9f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -120,6 +120,18 @@ features/arm64/drivers-net-NET_XGENE-should-depend-on-HAS_DMA.patch features/arm64/net-xgene-Check-negative-return-value-of-xgene_enet_.patch features/arm64/net-xgene-fix-possible-NULL-dereference-in-xgene_ene.patch features/arm64/dts-Add-bindings-for-APM-X-Gene-SoC-ethernet-driver.patch +features/arm64/drivers-net-xgene-Preparing-for-adding-10GbE-support.patch +features/arm64/drivers-net-xgene-Add-10GbE-support.patch +features/arm64/drivers-net-xgene-Add-10GbE-ethtool-support.patch +features/arm64/drivers-net-xgene-Preparing-for-adding-SGMII-based-1.patch +features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-support.patch +features/arm64/drivers-net-xgene-Add-SGMII-based-1GbE-ethtool-suppo.patch +features/arm64/drivers-net-xgene-Rewrite-buggy-loop-in-xgene_enet_e.patch +features/arm64/drivers-net-xgene-Backward-compatibility-with-older-.patch +features/arm64/drivers-net-xgene-fix-Use-separate-resources.patch +features/arm64/dtb-Add-10GbE-node-to-APM-X-Gene-SoC-device-tree.patch +features/arm64/dtb-Add-SGMII-based-1GbE-node-to-APM-X-Gene-SoC-devi.patch +features/arm64/dtb-xgene-fix-Backward-compatibility-with-older-firm.patch # Miscellaneous bug fixes bugfix/all/misc-bmp085-Enable-building-as-a-module.patch