diff options
author | Zhangfei Gao <zhangfei.gao@linaro.org> | 2014-04-04 09:31:41 +0800 |
---|---|---|
committer | Zhangfei Gao <zhangfei.gao@linaro.org> | 2014-04-04 09:40:54 +0800 |
commit | dac7e2b37eee38e7d710b7ecdbcd41c008e4b6b5 (patch) | |
tree | a2c074e535f897fc368daab11024dc3f6a4124f4 | |
parent | 0889ca072c489ac8011366e121a687f87252b372 (diff) |
ether: update hip04_ethtracking-hilt-ether-polish-0404
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
-rw-r--r-- | Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt | 90 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/Kconfig | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hip04_eth.c | 817 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hip04_mdio.c | 48 |
5 files changed, 484 insertions, 479 deletions
diff --git a/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt b/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt index 6bc542a58d37..988fc694b663 100644 --- a/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt +++ b/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt @@ -1,28 +1,88 @@ -* Hisilicon hip04 Ethernet Controller +Hisilicon hip04 Ethernet Controller + +* Ethernet controller node Required properties: - compatible: should be "hisilicon,hip04-mac". - reg: address and length of the register set for the device. - interrupts: interrupt for the device. -- port: port number combined with the controller: range from 0 to 31. -- speed: 100 (100M) or 1000 (1000M). +- port-handle: <phandle port channel> + phandle, specifies a reference to the syscon ppe node + port, port number connected to the controller + channel, recv channel start from channel * number (RX_DESC_NUM) +- phy-mode: see ethernet.txt [1]. + +Optional properties: +- phy-handle: see ethernet.txt [1]. + +[1] Documentation/devicetree/bindings/net/ethernet.txt -Example: - ge0: ethernet@2800000 { - compatible = "hisilicon,hip04-mac"; - reg = <0x2800000 0x10000>; - interrupts = <0 434 4>; - port = <0>; - speed = <1000>; - }; -* Hisilicon hip04 Ethernet ppe: control rx & rx fifos of all ethnet controllers +* Ethernet ppe node: +Control rx & tx fifos of all ethernet controllers. +Have 2048 recv channels shared by all ethernet controllers, only if no overlap. +Each controller's recv channel start from channel * number (RX_DESC_NUM). Required properties: -- compatible: should be "hisilicon,ppebase". +- compatible: "hisilicon,hip04-ppe", "syscon". +- reg: address and length of the register set for the device. + + +* MDIO bus node: + +Required properties: + +- compatible: should be "hisilicon,hip04-mdio". +- Inherits from MDIO bus node binding [2] +[2] Documentation/devicetree/bindings/net/phy.txt Example: - ppebase: ppebase@28c0000 { - compatible = "hisilicon,ppebase"; + mdio { + compatible = "hisilicon,hip04-mdio"; + reg = <0x28f1000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + marvell,reg-init = <18 0x14 0 0x8001>; + }; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + marvell,reg-init = <18 0x14 0 0x8001>; + }; + }; + + ppe: ppe@28c0000 { + compatible = "hisilicon,hip04-ppe", "syscon"; reg = <0x28c0000 0x10000>; }; + + fe: ethernet@28b0000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x28b0000 0x10000>; + interrupts = <0 413 4>; + phy-mode = "mii"; + port-handle = <&ppe 31 0>; + }; + + ge0: ethernet@2800000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x2800000 0x10000>; + interrupts = <0 402 4>; + phy-mode = "sgmii"; + port-handle = <&ppe 0 1>; + phy-handle = <&phy0>; + }; + + ge8: ethernet@2880000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x2880000 0x10000>; + interrupts = <0 410 4>; + phy-mode = "sgmii"; + port-handle = <&ppe 8 2>; + phy-handle = <&phy1>; + }; diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index c1885e57db0e..39b5c7e7923a 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -5,7 +5,7 @@ config NET_VENDOR_HISILICON bool "Hisilicon devices" default y - depends on (ARM && ARCH_HIP04) + depends on ARM ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -13,17 +13,17 @@ config NET_VENDOR_HISILICON Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all - the questions about MOXA ART devices. If you say Y, you will be asked + the questions about Hisilicon devices. If you say Y, you will be asked for your specific card in the following questions. if NET_VENDOR_HISILICON config HIP04_ETH tristate "HISILICON P04 Ethernet support" - depends on ARM && ARCH_HIP04 select NET_CORE select PHYLIB select MARVELL_PHY + select MFD_SYSCON ---help--- If you wish to compile a kernel for a hardware with hisilicon p04 SoC and want to use the internal ethernet then you should answer Y to this. diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index e6fe7af439d9..17dec0340722 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -2,4 +2,4 @@ # Makefile for the HISILICON network device drivers. # -obj-$(CONFIG_HIP04_ETH) += hip04_eth.o hip04_mdio.o +obj-$(CONFIG_HIP04_ETH) += hip04_mdio.o hip04_eth.o diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 9621e1b77a40..db00337115dd 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -13,150 +13,155 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/of_address.h> -#include <linux/dmapool.h> #include <linux/phy.h> #include <linux/of_mdio.h> - -#define PPE_CFG_RX_CFF_ADDR 0x100 -#define PPE_CFG_POOL_GRP 0x300 -#define PPE_CFG_RX_BUF_SIZE 0x400 -#define PPE_CFG_RX_FIFO_SIZE 0x500 -#define PPE_CURR_BUF_CNT_REG 0xa200 - -#define GE_DUPLEX_TYPE 0x8 -#define GE_PORT_MODE 0x40 -#define GE_PORT_EN 0x44 -#define GE_MODE_CHANGE_EN 0x1b4 -#define GE_STATION_MAC_ADDRESS 0x210 -#define PPE_CFG_TX_PKT_BD_ADDR 0x420 -#define PPE_CFG_RX_CTRL_REG 0x428 -#define PPE_CFG_QOS_VMID_GEN 0x500 -#define PPE_CFG_RX_PKT_INT 0x538 -#define PPE_INTEN 0x600 -#define PPE_INTSTS 0x608 -#define PPE_RINT 0x604 -#define PPE_CFG_STS_MODE 0x700 -#define PPE_HIS_RX_PKT_CNT 0x804 - -#define GE_MAX_FRM_SIZE_REG 0x3c -#define GE_SHORT_RUNTS_THR_REG 0x50 -#define GE_TX_LOCAL_PAGE_REG 0x5c -#define GE_TRANSMIT_CONTROL_REG 0x60 -#define GE_CF_CRC_STRIP_REG 0x1b0 -#define GE_RECV_CONTROL_REG 0x1e0 +#include <linux/of_net.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + +#define PPE_CFG_RX_ADDR 0x100 +#define PPE_CFG_POOL_GRP 0x300 +#define PPE_CFG_RX_BUF_SIZE 0x400 +#define PPE_CFG_RX_FIFO_SIZE 0x500 +#define PPE_CURR_BUF_CNT 0xa200 + +#define GE_DUPLEX_TYPE 0x8 +#define GE_MAX_FRM_SIZE_REG 0x3c +#define GE_PORT_MODE 0x40 +#define GE_PORT_EN 0x44 +#define GE_SHORT_RUNTS_THR_REG 0x50 +#define GE_TX_LOCAL_PAGE_REG 0x5c +#define GE_TRANSMIT_CONTROL_REG 0x60 +#define GE_CF_CRC_STRIP_REG 0x1b0 +#define GE_MODE_CHANGE_EN 0x1b4 +#define GE_RECV_CONTROL_REG 0x1e0 +#define GE_STATION_MAC_ADDRESS 0x210 +#define PPE_CFG_TX_PKT_BD_ADDR 0x420 #define PPE_CFG_MAX_FRAME_LEN_REG 0x408 -#define PPE_CFG_BUS_CTRL_REG 0x424 -#define PPE_CFG_RX_PKT_MODE_REG 0x438 -#define GMAC_PPE_RX_PKT_MAX_LEN (379) -#define GMAC_MAX_PKT_LEN 1516 - -/* REG_INTERRUPT_MASK */ -#define RCV_INT BIT(10) -#define RCV_NOBUF BIT(8) -#define DEF_INT_MASK 0x41fdf - -#define RX_DESC_NUM 64 -#define TX_DESC_NUM 64 -#define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM-1)) -#define RX_NEXT(N) (((N) + 1) & (RX_DESC_NUM-1)) - -#define DESC_DEF_CFG 0x14 -#define RX_BUF_SIZE 1600 -#define TX_TIMEOUT (6 * HZ) -#define DRV_NAME "hip04-ether" - -#define OBSOLETE_BUFFER +#define PPE_CFG_BUS_CTRL_REG 0x424 +#define PPE_CFG_RX_CTRL_REG 0x428 +#define PPE_CFG_RX_PKT_MODE_REG 0x438 +#define PPE_CFG_QOS_VMID_GEN 0x500 +#define PPE_CFG_RX_PKT_INT 0x538 +#define PPE_INTEN 0x600 +#define PPE_INTSTS 0x608 +#define PPE_RINT 0x604 +#define PPE_CFG_STS_MODE 0x700 +#define PPE_HIS_RX_PKT_CNT 0x804 + +/* REG_INTERRUPT */ +#define RCV_INT BIT(10) +#define RCV_NOBUF BIT(8) +#define DEF_INT_MASK (RCV_INT | RCV_NOBUF) + +#define RX_DESC_NUM 64 +#define TX_DESC_NUM 64 +#define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM-1)) +#define RX_NEXT(N) (((N) + 1) & (RX_DESC_NUM-1)) + +#define GMAC_PPE_RX_PKT_MAX_LEN 379 +#define GMAC_MAX_PKT_LEN 1516 +#define DESC_DEF_CFG 0x14 +#define RX_BUF_SIZE 1600 +#define RX_PKT_ERR 0x3 +#define TX_TIMEOUT (6 * HZ) +#define RECLAIM_PERIOD HZ + +#define DRV_NAME "hip04-ether" struct tx_desc { u32 send_addr; + u16 reserved_16; u16 send_size; - u16 reserved[3]; + u32 reserved_32; u32 cfg; u32 wb_addr; -}; +} ____cacheline_aligned; struct rx_desc { - u16 pkt_len; u16 reserved_16; - u32 reserve[8]; /* simplified */ + u16 pkt_len; + u32 reserve1[3]; + u32 pkt_err; + u32 reserve2[4]; }; struct hip04_priv { void __iomem *base; + int phy_mode; + int chan; unsigned int port; unsigned int speed; unsigned int duplex; - unsigned int id; unsigned int reg_inten; struct napi_struct napi; struct net_device *ndev; - struct dma_pool *desc_pool; + struct tx_desc *tx_desc; + dma_addr_t tx_desc_dma; struct sk_buff *tx_skb[TX_DESC_NUM]; - struct tx_desc *td_ring[TX_DESC_NUM]; - dma_addr_t td_phys[TX_DESC_NUM]; - spinlock_t txlock; + dma_addr_t tx_phys[TX_DESC_NUM]; + spinlock_t lock; unsigned int tx_head; unsigned int tx_tail; unsigned int tx_count; - struct sk_buff *rx_skb[RX_DESC_NUM]; unsigned char *rx_buf[RX_DESC_NUM]; + dma_addr_t rx_phys[RX_DESC_NUM]; unsigned int rx_head; unsigned int rx_buf_size; struct device_node *phy_node; struct phy_device *phy; + struct regmap *map; + struct timer_list txtimer; }; -static void __iomem *ppebase; - -static void hip04_config_port(struct hip04_priv *priv, u32 speed, u32 duplex) +static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex) { - u32 val, reg; + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; priv->speed = speed; priv->duplex = duplex; - switch (speed) { - case SPEED_1000: - reg = 8; + switch (priv->phy_mode) { + case PHY_INTERFACE_MODE_SGMII: + if (speed == SPEED_1000) + val = 8; + else if (speed == SPEED_100) + val = 7; + else + val = 6; /* SPEED_10 */ break; - case SPEED_100: - if (!priv->id) - reg = 1; + case PHY_INTERFACE_MODE_MII: + if (speed == SPEED_100) + val = 1; else - reg = 7; + val = 0; /* SPEED_10 */ break; default: - reg = 0; + netdev_warn(ndev, "not supported mode\n"); + val = 0; break; } - val = readl_relaxed(priv->base + GE_PORT_MODE); - val &= ~(0xf); - val |= reg; writel_relaxed(val, priv->base + GE_PORT_MODE); - reg = (duplex) ? BIT(0) : 0; - val = readl_relaxed(priv->base + GE_DUPLEX_TYPE); - val &= ~(0x1); - val |= reg; + val = (duplex) ? BIT(0) : 0; writel_relaxed(val, priv->base + GE_DUPLEX_TYPE); - val = readl_relaxed(priv->base + GE_MODE_CHANGE_EN); - val |= BIT(0); + val = BIT(0); writel_relaxed(val, priv->base + GE_MODE_CHANGE_EN); } static void hip04_reset_ppe(struct hip04_priv *priv) { - u32 val; + u32 val, tmp; do { - val = - readl_relaxed(ppebase + priv->port * 4 + PPE_CURR_BUF_CNT_REG); - readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_CFF_ADDR); + regmap_read(priv->map, priv->port * 4 + PPE_CURR_BUF_CNT, &val); + regmap_read(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, &tmp); } while (val & 0xfff); } @@ -165,145 +170,126 @@ static void hip04_config_fifo(struct hip04_priv *priv) u32 val; val = readl_relaxed(priv->base + PPE_CFG_STS_MODE); - val |= BIT(12); /* PPE_HIS_RX_PKT_CNT read clear */ + val |= BIT(12); /* PPE_HIS_RX_PKT_CNT read clear */ writel_relaxed(val, priv->base + PPE_CFG_STS_MODE); - val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_POOL_GRP); - val |= BIT(priv->port); - writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_POOL_GRP); + val = BIT(priv->port); + regmap_write(priv->map, priv->port * 4 + PPE_CFG_POOL_GRP, val); - val = readl_relaxed(priv->base + PPE_CFG_QOS_VMID_GEN); - val &= ~(0x7f00); /* [14:8]*/ + val = priv->port << 8; val |= BIT(14); - val |= priv->port << 8; writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN); - val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_BUF_SIZE); - val &= ~(0xffff); /* [15:0]*/ - val |= RX_BUF_SIZE; - writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_RX_BUF_SIZE); + val = RX_BUF_SIZE; + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_BUF_SIZE, val); - val = readl_relaxed(ppebase + priv->port * 4 + PPE_CFG_RX_FIFO_SIZE); - val &= ~(0xfff0fff); /* [27:16] [11:0]*/ - val |= RX_DESC_NUM << 16; /* depth */ - val |= BIT(11); /* seq: first set first ues */ - val |= RX_DESC_NUM * priv->id; /* start_addr */ - writel_relaxed(val, ppebase + priv->port * 4 + PPE_CFG_RX_FIFO_SIZE); + val = RX_DESC_NUM << 16; /* depth */ + val |= BIT(11); /* seq: first set first ues */ + val |= RX_DESC_NUM * priv->chan; /* start_addr */ + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_FIFO_SIZE, val); /* pkt store format */ - val = readl_relaxed(priv->base + PPE_CFG_RX_CTRL_REG); - val &= ~(0x1f80f); /* [16:11] [3:0]*/ - val |= 2 << 11; /* align */ + val = NET_IP_ALIGN << 11; /* align */ writel_relaxed(val, priv->base + PPE_CFG_RX_CTRL_REG); /* following cfg required for 1000M */ /* pkt mode */ - val = readl_relaxed(priv->base + PPE_CFG_RX_PKT_MODE_REG); - val &= ~(0xc0000); /* [19:18] */ - val |= 1 << 18; /* align */ + val = BIT(18); /* align */ writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_MODE_REG); /* set bus ctrl */ - val = 1 << 14; /* buffer locally release */ - val |= 1; /* big endian */ + val = BIT(14); /* buffer locally release */ + val |= BIT(0); /* big endian */ writel_relaxed(val, priv->base + PPE_CFG_BUS_CTRL_REG); /* set max pkt len, curtail if exceed */ - val = readl_relaxed(priv->base + PPE_CFG_MAX_FRAME_LEN_REG); - val &= ~(0x3fff); /* [13:0]*/ - val |= GMAC_PPE_RX_PKT_MAX_LEN; /* max buffer len */ + val = GMAC_PPE_RX_PKT_MAX_LEN; /* max buffer len */ writel_relaxed(val, priv->base + PPE_CFG_MAX_FRAME_LEN_REG); /* set max len of each pkt */ - val = readl_relaxed(priv->base + GE_MAX_FRM_SIZE_REG); - val &= ~(0xffff); /* [15:0]*/ - val |= GMAC_MAX_PKT_LEN; /* max buffer len */ + val = GMAC_MAX_PKT_LEN; /* max buffer len */ writel_relaxed(val, priv->base + GE_MAX_FRM_SIZE_REG); /* set min len of each pkt */ - val = readl_relaxed(priv->base + GE_SHORT_RUNTS_THR_REG); - val |= 31; /* min buffer len */ + val = 31; /* min buffer len */ writel_relaxed(val, priv->base + GE_SHORT_RUNTS_THR_REG); /* tx */ val = readl_relaxed(priv->base + GE_TRANSMIT_CONTROL_REG); - val |= 1 << 5; /* tx auto neg */ - val |= 1 << 6; /* tx add crc */ - val |= 1 << 7; /* tx short pad through */ + val |= BIT(5); /* tx auto neg */ + val |= BIT(6); /* tx add crc */ + val |= BIT(7); /* tx short pad through */ writel_relaxed(val, priv->base + GE_TRANSMIT_CONTROL_REG); /* rx crc */ - val = readl_relaxed(priv->base + GE_CF_CRC_STRIP_REG); - val |= 1; /* rx strip crc */ + val = BIT(0); /* rx strip crc */ writel_relaxed(val, priv->base + GE_CF_CRC_STRIP_REG); /* rx */ val = readl_relaxed(priv->base + GE_RECV_CONTROL_REG); - val |= 1 << 3; /* rx strip pad */ - val |= 1 << 4; /* run pkt en */ + val |= BIT(3); /* rx strip pad */ + val |= BIT(4); /* run pkt en */ writel_relaxed(val, priv->base + GE_RECV_CONTROL_REG); /* auto neg control */ - val = readl_relaxed(priv->base + GE_TX_LOCAL_PAGE_REG); - val |= 1; - val &= ~(0x1e0); /* [8:5] = 0*/ - val &= ~(0x3c0); /* [13:10] = 0*/ - val &= ~(0x8000); /* [15] = 0*/ + val = BIT(0); writel_relaxed(val, priv->base + GE_TX_LOCAL_PAGE_REG); } -static void hip04_mac_enable(struct net_device *ndev, bool enable) +static void hip04_mac_enable(struct net_device *ndev) { struct hip04_priv *priv = netdev_priv(ndev); u32 val; - if (enable) { - /* enable tx & rx */ - val = readl_relaxed(priv->base + GE_PORT_EN); - val |= 0x1 << 1; /* rx*/ - val |= 0x1 << 2; /* tx*/ - writel_relaxed(val, priv->base + GE_PORT_EN); + /* enable tx & rx */ + val = readl_relaxed(priv->base + GE_PORT_EN); + val |= BIT(1); /* rx */ + val |= BIT(2); /* tx */ + writel_relaxed(val, priv->base + GE_PORT_EN); - /* enable interrupt */ - priv->reg_inten = DEF_INT_MASK; - writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + /* clear rx int */ + val = RCV_INT; + writel_relaxed(val, priv->base + PPE_RINT); - /* clear rx int */ - val = RCV_INT; - writel_relaxed(val, priv->base + PPE_RINT); - - /* config recv int*/ - val = readl_relaxed(priv->base + PPE_CFG_RX_PKT_INT); - val &= ~(0x0fff); /* [11:0] */ - val |= 0x1 << 6; /* int threshold 1 package */ - val |= 0x4; /* recv timeout */ - writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_INT); - } else { - /* disable int */ - priv->reg_inten &= ~(RCV_INT | RCV_NOBUF); - writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + /* config recv int */ + val = BIT(6); /* int threshold 1 package */ + val |= 0x4; /* recv timeout */ + writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_INT); - /* disable tx & rx */ - val = readl_relaxed(priv->base + GE_PORT_EN); - val &= ~(0x1 << 1); /* rx*/ - val &= ~(0x1 << 2); /* tx*/ - writel_relaxed(val, priv->base + GE_PORT_EN); - } + /* enable interrupt */ + priv->reg_inten = DEF_INT_MASK; + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); +} + +static void hip04_mac_disable(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + /* disable int */ + priv->reg_inten &= ~(RCV_INT | RCV_NOBUF); + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + + /* disable tx & rx */ + val = readl_relaxed(priv->base + GE_PORT_EN); + val &= ~(BIT(1)); /* rx */ + val &= ~(BIT(2)); /* tx */ + writel_relaxed(val, priv->base + GE_PORT_EN); } static void hip04_set_xmit_desc(struct hip04_priv *priv, dma_addr_t phys) { - writel_relaxed(phys, priv->base + PPE_CFG_TX_PKT_BD_ADDR); + writel(phys, priv->base + PPE_CFG_TX_PKT_BD_ADDR); } static void hip04_set_recv_desc(struct hip04_priv *priv, dma_addr_t phys) { - writel_relaxed(phys, ppebase + priv->port * 4 + PPE_CFG_RX_CFF_ADDR); + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, phys); } static u32 hip04_recv_cnt(struct hip04_priv *priv) { - return readl_relaxed(priv->base + PPE_HIS_RX_PKT_CNT); + return readl(priv->base + PPE_HIS_RX_PKT_CNT); } static void hip04_update_mac_address(struct net_device *ndev) @@ -319,95 +305,161 @@ static void hip04_update_mac_address(struct net_device *ndev) static int hip04_set_mac_address(struct net_device *ndev, void *addr) { - struct sockaddr *address = addr; + eth_mac_addr(ndev, addr); + hip04_update_mac_address(ndev); + return 0; +} - if (!is_valid_ether_addr(address->sa_data)) - return -EADDRNOTAVAIL; +static void hip04_tx_reclaim(struct net_device *ndev, bool force) +{ + struct hip04_priv *priv = netdev_priv(ndev); + unsigned tx_head = priv->tx_head; + unsigned tx_tail = priv->tx_tail; + struct tx_desc *desc; - memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len); - hip04_update_mac_address(ndev); + spin_lock_bh(&priv->lock); + while ((tx_tail != tx_head) || (priv->tx_count == TX_DESC_NUM)) { + desc = &priv->tx_desc[priv->tx_tail]; + if (desc->send_addr != 0) { + if (force) + desc->send_addr = 0; + else + break; + } + if (priv->tx_phys[tx_tail]) { + dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail], + priv->tx_skb[tx_tail]->len, DMA_TO_DEVICE); + priv->tx_phys[tx_tail] = 0; + } + dev_kfree_skb(priv->tx_skb[tx_tail]); + priv->tx_skb[tx_tail] = NULL; + tx_tail = TX_NEXT(tx_tail); + priv->tx_count--; + } + priv->tx_tail = tx_tail; + spin_unlock_bh(&priv->lock); - return 0; + if (priv->tx_count) + mod_timer(&priv->txtimer, jiffies + RECLAIM_PERIOD); + + if (unlikely(netif_queue_stopped(ndev)) && + (priv->tx_count < TX_DESC_NUM)) + netif_wake_queue(ndev); } -static void endian_change(void *p, int size) +static void hip04_xmit_timer(unsigned long data) { - unsigned int *to_cover = (unsigned int *)p; - int i; + struct net_device *ndev = (void *) data; - size = size >> 2; - for (i = 0; i < size; i++) - *(to_cover+i) = htonl(*(to_cover+i)); + hip04_tx_reclaim(ndev, false); } -#ifdef OBSOLETE_BUFFER -static int -hip04_rx_refill_one_buffer(struct net_device *ndev, unsigned int index) +static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct hip04_priv *priv = netdev_priv(ndev); - struct sk_buff *skb; + struct net_device_stats *stats = &ndev->stats; + unsigned int tx_head = priv->tx_head; + struct tx_desc *desc = &priv->tx_desc[tx_head]; + dma_addr_t phys; - skb = dev_alloc_skb(RX_BUF_SIZE + NET_SKB_PAD); - if (NULL == skb) - return -ENOMEM; + hip04_tx_reclaim(ndev, false); + mod_timer(&priv->txtimer, jiffies + RECLAIM_PERIOD); - memset(skb->data, 0x0, RX_BUF_SIZE); - priv->rx_skb[index] = skb; - dma_map_single(&(ndev->dev), skb->data, RX_BUF_SIZE, DMA_TO_DEVICE); - hip04_set_recv_desc(priv, virt_to_phys(skb->data)); + if (priv->tx_count >= TX_DESC_NUM) { + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } - return 0; + phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + priv->tx_skb[tx_head] = skb; + priv->tx_phys[tx_head] = phys; + desc->send_addr = cpu_to_be32(phys); + desc->send_size = cpu_to_be16(skb->len); + desc->cfg = cpu_to_be32(DESC_DEF_CFG); + phys = priv->tx_desc_dma + tx_head * sizeof(struct tx_desc); + desc->wb_addr = cpu_to_be32(phys); + skb_tx_timestamp(skb); + + /* Don't wait up for transmitted skbs to be freed. */ + skb_orphan(skb); + + hip04_set_xmit_desc(priv, phys); + priv->tx_head = TX_NEXT(tx_head); + + stats->tx_bytes += skb->len; + stats->tx_packets++; + priv->tx_count++; + + return NETDEV_TX_OK; } -#endif static int hip04_rx_poll(struct napi_struct *napi, int budget) { - struct hip04_priv *priv = container_of(napi, - struct hip04_priv, napi); + struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi); struct net_device *ndev = priv->ndev; - struct sk_buff *skb; + struct net_device_stats *stats = &ndev->stats; + unsigned int cnt = hip04_recv_cnt(priv); struct rx_desc *desc; + struct sk_buff *skb; unsigned char *buf; + bool last = false; + dma_addr_t phys; int rx = 0; - unsigned int cnt = hip04_recv_cnt(priv); - unsigned int len, tmp[16]; + u16 len; + u32 err; - while (cnt) { -#ifdef OBSOLETE_BUFFER - skb = priv->rx_skb[priv->rx_head]; -#else + while (cnt && !last) { buf = priv->rx_buf[priv->rx_head]; skb = build_skb(buf, priv->rx_buf_size); if (unlikely(!skb)) net_dbg_ratelimited("build_skb failed\n"); -#endif - dma_map_single(&ndev->dev, skb->data, - RX_BUF_SIZE, DMA_FROM_DEVICE); - memcpy(tmp, skb->data, 64); - endian_change((void *)tmp, 64); - desc = (struct rx_desc *)tmp; - len = desc->pkt_len; + + dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head], + RX_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_phys[priv->rx_head] = 0; + + desc = (struct rx_desc *)skb->data; + len = be16_to_cpu(desc->pkt_len); + err = be32_to_cpu(desc->pkt_err); if (len > RX_BUF_SIZE) len = RX_BUF_SIZE; - if (0 == len) - break; - skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, ndev); - napi_gro_receive(&priv->napi, skb); - -#ifdef OBSOLETE_BUFFER - hip04_rx_refill_one_buffer(ndev, priv->rx_head); -#else - dma_map_single(&ndev->dev, buf, RX_BUF_SIZE, DMA_TO_DEVICE); - /* reuse the buffer after data exhausted */ - hip04_set_recv_desc(priv, virt_to_phys(buf)); -#endif - priv->rx_head = RX_NEXT(priv->rx_head); + if (0 == len) { + dev_kfree_skb_any(skb); + last = true; + } else if (err & RX_PKT_ERR) { + dev_kfree_skb_any(skb); + stats->rx_dropped++; + stats->rx_errors++; + } else { + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, ndev); + napi_gro_receive(&priv->napi, skb); + stats->rx_packets++; + stats->rx_bytes += len; + rx++; + } - if (rx++ >= budget) + buf = netdev_alloc_frag(priv->rx_buf_size); + if (!buf) + return -ENOMEM; + phys = dma_map_single(&ndev->dev, buf, + RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) + return -EIO; + priv->rx_buf[priv->rx_head] = buf; + priv->rx_phys[priv->rx_head] = phys; + hip04_set_recv_desc(priv, phys); + + priv->rx_head = RX_NEXT(priv->rx_head); + if (rx >= budget) break; if (--cnt == 0) @@ -415,13 +467,12 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) } if (rx < budget) { - napi_gro_flush(napi, false); - __napi_complete(napi); - } + napi_complete(napi); - /* enable rx interrupt */ - priv->reg_inten |= RCV_INT | RCV_NOBUF; - writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + /* enable rx interrupt */ + priv->reg_inten |= RCV_INT | RCV_NOBUF; + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + } return rx; } @@ -430,91 +481,29 @@ static irqreturn_t hip04_mac_interrupt(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *) dev_id; struct hip04_priv *priv = netdev_priv(ndev); - unsigned int ists = readl(priv->base + PPE_INTSTS); - u32 val; + u32 ists = readl_relaxed(priv->base + PPE_INTSTS); - val = DEF_INT_MASK; - writel_relaxed(val, priv->base + PPE_RINT); + writel_relaxed(DEF_INT_MASK, priv->base + PPE_RINT); - if ((ists & RCV_INT) || (ists & RCV_NOBUF)) { - if (napi_schedule_prep(&priv->napi)) { - /* disable rx interrupt */ - priv->reg_inten &= ~(RCV_INT | RCV_NOBUF); - writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); - __napi_schedule(&priv->napi); - } + if (ists & (RCV_INT | RCV_NOBUF)) { + /* disable rx interrupt */ + priv->reg_inten &= ~(RCV_INT | RCV_NOBUF); + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + napi_schedule(&priv->napi); } return IRQ_HANDLED; } -static void hip04_tx_reclaim(struct net_device *ndev, bool force) -{ - struct hip04_priv *priv = netdev_priv(ndev); - unsigned tx_head = priv->tx_head; - unsigned tx_tail = priv->tx_tail; - struct tx_desc *desc = priv->td_ring[priv->tx_tail]; - - spin_lock_irq(&priv->txlock); - while (tx_tail != tx_head) { - if (desc->send_addr != 0) { - if (force) - desc->send_addr = 0; - else - break; - } - dev_kfree_skb_irq(priv->tx_skb[tx_tail]); - priv->tx_skb[tx_tail] = NULL; - tx_tail = TX_NEXT(tx_tail); - priv->tx_count--; - } - priv->tx_tail = tx_tail; - spin_unlock_irq(&priv->txlock); -} - -static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - struct hip04_priv *priv = netdev_priv(ndev); - struct tx_desc *desc = priv->td_ring[priv->tx_head]; - unsigned int tx_head = priv->tx_head; - int ret; - - hip04_tx_reclaim(ndev, false); - - spin_lock_irq(&priv->txlock); - if (priv->tx_count++ >= TX_DESC_NUM) { - net_dbg_ratelimited("no TX space for packet\n"); - netif_stop_queue(ndev); - ret = NETDEV_TX_BUSY; - goto out_unlock; - } - - priv->tx_skb[tx_head] = skb; - dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); - memset((void *)desc, 0, sizeof(*desc)); - desc->send_addr = (unsigned int)virt_to_phys(skb->data); - desc->send_size = skb->len; - desc->cfg = DESC_DEF_CFG; - desc->wb_addr = priv->td_phys[tx_head]; - endian_change(desc, 64); - skb_tx_timestamp(skb); - hip04_set_xmit_desc(priv, priv->td_phys[tx_head]); - - priv->tx_head = TX_NEXT(tx_head); - ret = NETDEV_TX_OK; -out_unlock: - spin_unlock_irq(&priv->txlock); - - return ret; -} - static void hip04_adjust_link(struct net_device *ndev) { struct hip04_priv *priv = netdev_priv(ndev); struct phy_device *phy = priv->phy; - if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) - hip04_config_port(priv, phy->speed, phy->duplex); + if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) { + hip04_config_port(ndev, phy->speed, phy->duplex); + phy_print_status(phy); + } } static int hip04_mac_open(struct net_device *ndev) @@ -522,50 +511,63 @@ static int hip04_mac_open(struct net_device *ndev) struct hip04_priv *priv = netdev_priv(ndev); int i; -#ifndef OBSOLETE_BUFFER - hip04_reset_ppe(priv); - for (i = 0; i < RX_DESC_NUM; i++) { - dma_map_single(&ndev->dev, priv->rx_buf[i], - RX_BUF_SIZE, DMA_TO_DEVICE); - hip04_set_recv_desc(priv, virt_to_phys(priv->rx_buf[i])); - } priv->rx_head = 0; -#endif priv->tx_head = 0; priv->tx_tail = 0; priv->tx_count = 0; - if (priv->phy_node) { - priv->phy = of_phy_connect(ndev, priv->phy_node, - &hip04_adjust_link, 0, PHY_INTERFACE_MODE_GMII); - if (!priv->phy) - return -ENODEV; - phy_start(priv->phy); + hip04_reset_ppe(priv); + for (i = 0; i < RX_DESC_NUM; i++) { + dma_addr_t phys; + + phys = dma_map_single(&ndev->dev, priv->rx_buf[i], + RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) + return -EIO; + + priv->rx_phys[i] = phys; + hip04_set_recv_desc(priv, phys); } + if (priv->phy) + phy_start(priv->phy); + netif_start_queue(ndev); - hip04_mac_enable(ndev, true); + hip04_mac_enable(ndev); napi_enable(&priv->napi); + return 0; } static int hip04_mac_stop(struct net_device *ndev) { struct hip04_priv *priv = netdev_priv(ndev); + int i; napi_disable(&priv->napi); netif_stop_queue(ndev); - hip04_mac_enable(ndev, false); + hip04_mac_disable(ndev); hip04_tx_reclaim(ndev, true); -#ifndef OBSOLETE_BUFFER hip04_reset_ppe(priv); -#endif + + if (priv->phy) + phy_stop(priv->phy); + + for (i = 0; i < RX_DESC_NUM; i++) { + if (priv->rx_phys[i]) { + dma_unmap_single(&ndev->dev, priv->rx_phys[i], + RX_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_phys[i] = 0; + } + } + return 0; } static void hip04_timeout(struct net_device *ndev) { - netif_wake_queue(ndev); + hip04_mac_stop(ndev); + hip04_mac_open(ndev); return; } @@ -579,87 +581,54 @@ static struct net_device_ops hip04_netdev_ops = { .ndo_change_mtu = eth_change_mtu, }; -#ifdef OBSOLETE_BUFFER -static int hip04_rx_ring_init(struct net_device *dev) -{ - struct hip04_priv *priv = netdev_priv(dev); - struct sk_buff *skb = NULL; - unsigned int i; - - for (i = 0; i < RX_DESC_NUM; i++) { - skb = dev_alloc_skb(RX_BUF_SIZE); - if (NULL == skb) - return -ENOMEM; - memset(skb->data, 0x0, RX_BUF_SIZE); - dma_map_single(&dev->dev, (skb->data), - RX_BUF_SIZE, DMA_TO_DEVICE); - hip04_set_recv_desc(priv, virt_to_phys(skb->data)); - priv->rx_skb[i] = skb; - } - priv->rx_head = 0; - return 0; -} -#endif - static int hip04_alloc_ring(struct net_device *ndev, struct device *d) { struct hip04_priv *priv = netdev_priv(ndev); - void *base; int i; - priv->desc_pool = dma_pool_create(DRV_NAME, d, sizeof(struct tx_desc), - SKB_DATA_ALIGN(sizeof(struct tx_desc)), 0); - if (!priv->desc_pool) + priv->tx_desc = dma_alloc_coherent(d, + TX_DESC_NUM * sizeof(struct tx_desc), + &priv->tx_desc_dma, GFP_KERNEL); + if (!priv->tx_desc) return -ENOMEM; - for (i = 0; i < TX_DESC_NUM; i++) { - priv->td_ring[i] = dma_pool_alloc(priv->desc_pool, - GFP_ATOMIC, &priv->td_phys[i]); - if (!priv->td_ring[i]) + priv->rx_buf_size = RX_BUF_SIZE + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + for (i = 0; i < RX_DESC_NUM; i++) { + priv->rx_buf[i] = netdev_alloc_frag(priv->rx_buf_size); + if (!priv->rx_buf[i]) return -ENOMEM; } -#ifndef OBSOLETE_BUFFER - priv->rx_head = 0; - priv->rx_buf_size = RX_BUF_SIZE + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - /* mallco one more buffer for SKB_DATA_ALIGN */ - base = devm_kzalloc(d, priv->rx_buf_size * (RX_DESC_NUM + 1), - GFP_ATOMIC); - if (!base) - return -ENOMEM; - base = (void *)SKB_DATA_ALIGN((unsigned int)base); - for (i = 0; i < RX_DESC_NUM; i++) - priv->rx_buf[i] = base + i * priv->rx_buf_size; -#endif return 0; } -static void hip04_free_ring(struct net_device *dev) +static void hip04_free_ring(struct net_device *ndev, struct device *d) { - struct hip04_priv *priv = netdev_priv(dev); + struct hip04_priv *priv = netdev_priv(ndev); int i; - for (i = 0; i < TX_DESC_NUM; i++) { + for (i = 0; i < RX_DESC_NUM; i++) + if (priv->rx_buf[i]) + put_page(virt_to_head_page(priv->rx_buf[i])); + + for (i = 0; i < TX_DESC_NUM; i++) if (priv->tx_skb[i]) dev_kfree_skb_any(priv->tx_skb[i]); - if ((priv->desc_pool) && (priv->td_ring[i])) - dma_pool_free(priv->desc_pool, priv->td_ring[i], - priv->td_phys[i]); - } - if (priv->desc_pool) - dma_pool_destroy(priv->desc_pool); + dma_free_coherent(d, TX_DESC_NUM * sizeof(struct tx_desc), + priv->tx_desc, priv->tx_desc_dma); } static int hip04_mac_probe(struct platform_device *pdev) { struct device *d = &pdev->dev; struct device_node *node = d->of_node; + struct of_phandle_args arg; struct net_device *ndev; struct hip04_priv *priv; struct resource *res; - unsigned int irq, val; + unsigned int irq; int ret; ndev = alloc_etherdev(sizeof(struct hip04_priv)); @@ -669,62 +638,60 @@ static int hip04_mac_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->ndev = ndev; platform_set_drvdata(pdev, ndev); - spin_lock_init(&priv->txlock); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -EINVAL; + priv->base = devm_ioremap_resource(d, res); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); goto init_fail; } - ndev->base_addr = res->start; - priv->base = devm_ioremap_resource(d, res); - ret = IS_ERR(priv->base); - if (ret) { - dev_err(d, "devm_ioremap_resource failed\n"); + + ret = of_parse_phandle_with_fixed_args(node, "port-handle", 2, 0, &arg); + if (ret < 0) { + dev_warn(d, "no port-handle\n"); goto init_fail; } - if (!ppebase) { - struct device_node *n; + priv->port = arg.args[0]; + priv->chan = arg.args[1]; - n = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-ppebase"); - if (!n) { - ret = -EINVAL; - netdev_err(ndev, "not find hisilicon,ppebase\n"); - goto init_fail; - } - ppebase = of_iomap(n, 0); + priv->map = syscon_node_to_regmap(arg.np); + if (IS_ERR(priv->map)) { + dev_warn(d, "no syscon hisilicon,hip04-ppe\n"); + ret = PTR_ERR(priv->map); + goto init_fail; } - ret = of_property_read_u32(node, "port", &val); - if (ret) { - dev_warn(d, "not find port info\n"); + priv->phy_mode = of_get_phy_mode(node); + if (priv->phy_mode < 0) { + dev_warn(d, "not find phy-mode\n"); + ret = -EINVAL; goto init_fail; } - priv->port = val & 0x1f; - ret = of_property_read_u32(node, "speed", &val); - if (ret) { - dev_warn(d, "not find speed info\n"); - priv->speed = SPEED_1000; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + ret = -EINVAL; + goto init_fail; } - if (SPEED_100 == val) - priv->speed = SPEED_100; - else - priv->speed = SPEED_1000; - priv->duplex = DUPLEX_FULL; - - /* fixme any id can be used directly? */ - ret = of_property_read_u32(node, "id", &priv->id); + ret = devm_request_irq(d, irq, hip04_mac_interrupt, + 0, pdev->name, ndev); if (ret) { - dev_warn(d, "not find id info\n"); + netdev_err(ndev, "devm_request_irq failed\n"); goto init_fail; } - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - ret = -EINVAL; - goto init_fail; + + priv->phy_node = of_parse_phandle(node, "phy-handle", 0); + if (priv->phy_node) { + priv->phy = of_phy_connect(ndev, priv->phy_node, + &hip04_adjust_link, 0, priv->phy_mode); + if (!priv->phy) { + ret = -EPROBE_DEFER; + goto init_fail; + } } + ether_setup(ndev); ndev->netdev_ops = &hip04_netdev_ops; ndev->watchdog_timeo = TX_TIMEOUT; @@ -734,37 +701,30 @@ static int hip04_mac_probe(struct platform_device *pdev) SET_NETDEV_DEV(ndev, &pdev->dev); hip04_reset_ppe(priv); - hip04_config_port(priv, priv->speed, priv->duplex); + if (priv->phy_mode == PHY_INTERFACE_MODE_MII) + hip04_config_port(ndev, SPEED_100, DUPLEX_FULL); + hip04_config_fifo(priv); random_ether_addr(ndev->dev_addr); hip04_update_mac_address(ndev); -#ifdef OBSOLETE_BUFFER - hip04_rx_ring_init(ndev); -#endif + ret = hip04_alloc_ring(ndev, d); if (ret) { netdev_err(ndev, "alloc ring fail\n"); goto alloc_fail; } - ret = devm_request_irq(d, irq, hip04_mac_interrupt, - 0, pdev->name, ndev); - if (ret) { - netdev_err(ndev, "devm_request_irq failed\n"); - goto init_fail; - } - - priv->phy_node = of_parse_phandle(node, "phy-handle", 0); - + setup_timer(&priv->txtimer, hip04_xmit_timer, (unsigned long) ndev); ret = register_netdev(ndev); if (ret) { free_netdev(ndev); - goto init_fail; + goto alloc_fail; } return 0; + alloc_fail: - hip04_free_ring(ndev); + hip04_free_ring(ndev, d); init_fail: of_node_put(priv->phy_node); free_netdev(ndev); @@ -775,12 +735,17 @@ static int hip04_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct hip04_priv *priv = netdev_priv(ndev); + struct device *d = &pdev->dev; + + if (priv->phy) + phy_disconnect(priv->phy); + del_timer_sync(&priv->txtimer); + hip04_free_ring(ndev, d); unregister_netdev(ndev); free_irq(ndev->irq, ndev); - free_netdev(ndev); - free_netdev(ndev); of_node_put(priv->phy_node); + free_netdev(ndev); return 0; } diff --git a/drivers/net/ethernet/hisilicon/hip04_mdio.c b/drivers/net/ethernet/hisilicon/hip04_mdio.c index d9764e306d79..e4f67caf4b5a 100644 --- a/drivers/net/ethernet/hisilicon/hip04_mdio.c +++ b/drivers/net/ethernet/hisilicon/hip04_mdio.c @@ -8,19 +8,11 @@ * (at your option) any later version. */ -#include <linux/init.h> -#include <linux/kernel.h> #include <linux/module.h> -#include <linux/mutex.h> -#include <linux/phy.h> -#include <linux/interrupt.h> #include <linux/platform_device.h> -#include <linux/delay.h> #include <linux/io.h> -#include <linux/clk.h> #include <linux/of_mdio.h> -#include <linux/sched.h> -#include <linux/wait.h> +#include <linux/delay.h> #define MDIO_CMD_REG 0x0 #define MDIO_ADDR_REG 0x4 @@ -34,11 +26,10 @@ #define MDIO_WRITE (BIT(12) | BIT(10) | MDIO_START) struct hip04_mdio_priv { - struct mutex lock; void __iomem *base; }; -#define WAIT_TIMEOUT 10 +#define WAIT_TIMEOUT 10 static int hip04_mdio_wait_ready(struct mii_bus *bus) { struct hip04_mdio_priv *priv = bus->priv; @@ -58,28 +49,28 @@ static int hip04_mdio_read(struct mii_bus *bus, int mii_id, int regnum) struct hip04_mdio_priv *priv = bus->priv; u32 val; int ret; - mutex_lock(&priv->lock); ret = hip04_mdio_wait_ready(bus); if (ret < 0) goto out; - val = (regnum & 0x1f) | ((mii_id & 0x1f) << 5) | MDIO_READ; + val = regnum | (mii_id << 5) | MDIO_READ; writel_relaxed(val, priv->base + MDIO_CMD_REG); ret = hip04_mdio_wait_ready(bus); if (ret < 0) goto out; + val = readl_relaxed(priv->base + MDIO_STA_REG); if (val & MDIO_R_VALID) { dev_err(bus->parent, "SMI bus read not valid\n"); ret = -ENODEV; goto out; } + val = readl_relaxed(priv->base + MDIO_RDATA_REG); ret = val & 0xFFFF; out: - mutex_unlock(&priv->lock); return ret; } @@ -90,17 +81,14 @@ static int hip04_mdio_write(struct mii_bus *bus, int mii_id, u32 val; int ret; - mutex_lock(&priv->lock); - ret = hip04_mdio_wait_ready(bus); if (ret < 0) goto out; writel_relaxed(value, priv->base + MDIO_WDATA_REG); - val = (regnum & 0x1f) | ((mii_id & 0x1f) << 5) | MDIO_WRITE; + val = regnum | (mii_id << 5) | MDIO_WRITE; writel_relaxed(val, priv->base + MDIO_CMD_REG); out: - mutex_unlock(&priv->lock); return ret; } @@ -109,7 +97,7 @@ static int hip04_mdio_reset(struct mii_bus *bus) { int temp, err, i; - for (i = 0; i < 2; i++) { + for (i = 0; i < PHY_MAX_ADDR; i++) { hip04_mdio_write(bus, i, 22, 0); temp = hip04_mdio_read(bus, i, MII_BMCR); temp |= BMCR_RESET; @@ -127,13 +115,7 @@ static int hip04_mdio_probe(struct platform_device *pdev) struct resource *r; struct mii_bus *bus; struct hip04_mdio_priv *priv; - int i, ret; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - dev_err(&pdev->dev, "No SMI register address given\n"); - return -ENODEV; - } + int ret; bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv)); if (!bus) { @@ -145,19 +127,17 @@ static int hip04_mdio_probe(struct platform_device *pdev) bus->read = hip04_mdio_read; bus->write = hip04_mdio_write; bus->reset = hip04_mdio_reset; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", - dev_name(&pdev->dev)); + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); bus->parent = &pdev->dev; priv = bus->priv; - priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (!priv->base) { - dev_err(&pdev->dev, "Unable to remap SMI register\n"); - ret = -ENODEV; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); goto out_mdio; } - mutex_init(&priv->lock); - ret = of_mdiobus_register(bus, pdev->dev.of_node); if (ret < 0) { dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); |