diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 69 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 131 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c | 27 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 42 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 67 |
8 files changed, 299 insertions, 93 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 74610f3..de507c3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -368,34 +368,36 @@ struct stmmac_dma_ops { void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt); }; +struct mac_device_info; + struct stmmac_ops { /* MAC core initialization */ - void (*core_init) (void __iomem *ioaddr, int mtu); + void (*core_init)(struct mac_device_info *hw, int mtu); /* Enable and verify that the IPC module is supported */ - int (*rx_ipc) (void __iomem *ioaddr); + int (*rx_ipc)(struct mac_device_info *hw); /* Dump MAC registers */ - void (*dump_regs) (void __iomem *ioaddr); + void (*dump_regs)(struct mac_device_info *hw); /* Handle extra events on specific interrupts hw dependent */ - int (*host_irq_status) (void __iomem *ioaddr, - struct stmmac_extra_stats *x); + int (*host_irq_status)(struct mac_device_info *hw, + struct stmmac_extra_stats *x); /* Multicast filter setting */ - void (*set_filter) (struct net_device *dev, int id); + void (*set_filter)(struct mac_device_info *hw, struct net_device *dev); /* Flow control setting */ - void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex, - unsigned int fc, unsigned int pause_time); + void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex, + unsigned int fc, unsigned int pause_time); /* Set power management mode (e.g. magic frame) */ - void (*pmt) (void __iomem *ioaddr, unsigned long mode); + void (*pmt)(struct mac_device_info *hw, unsigned long mode); /* Set/Get Unicast MAC addresses */ - void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr, - unsigned int reg_n); - void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr, - unsigned int reg_n); - void (*set_eee_mode) (void __iomem *ioaddr); - void (*reset_eee_mode) (void __iomem *ioaddr); - void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw); - void (*set_eee_pls) (void __iomem *ioaddr, int link); - void (*ctrl_ane) (void __iomem *ioaddr, bool restart); - void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv); + void (*set_umac_addr)(struct mac_device_info *hw, unsigned char *addr, + unsigned int reg_n); + void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr, + unsigned int reg_n); + void (*set_eee_mode)(struct mac_device_info *hw); + void (*reset_eee_mode)(struct mac_device_info *hw); + void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw); + void (*set_eee_pls)(struct mac_device_info *hw, int link); + void (*ctrl_ane)(struct mac_device_info *hw, bool restart); + void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv); }; struct stmmac_hwtimestamp { @@ -439,9 +441,14 @@ struct mac_device_info { struct mii_regs mii; /* MII register Addresses */ struct mac_link link; unsigned int synopsys_uid; + void __iomem *pcsr; /* vpointer to device CSRs */ + int multicast_filter_bins; + int unicast_filter_entries; + int mcast_bits_log2; }; -struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr); +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, + int perfect_uc_entries); struct mac_device_info *dwmac100_setup(void __iomem *ioaddr); void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index fd8a217..ec632e6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -20,7 +20,9 @@ #include <linux/of_net.h> #include <linux/phy.h> #include <linux/regmap.h> +#include <linux/reset.h> #include <linux/stmmac.h> +#include "stmmac.h" #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 @@ -34,6 +36,7 @@ struct socfpga_dwmac { u32 reg_shift; struct device *dev; struct regmap *sys_mgr_base_addr; + struct reset_control *stmmac_rst; }; static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) @@ -43,6 +46,13 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * u32 reg_offset, reg_shift; int ret; + dwmac->stmmac_rst = devm_reset_control_get(dev, + STMMAC_RESOURCE_NAME); + if (IS_ERR(dwmac->stmmac_rst)) { + dev_info(dev, "Could not get reset control!\n"); + return -EINVAL; + } + dwmac->interface = of_get_phy_mode(np); sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); @@ -125,6 +135,65 @@ static void *socfpga_dwmac_probe(struct platform_device *pdev) return dwmac; } +static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv) +{ + struct socfpga_dwmac *dwmac = priv; + + /* On socfpga platform exit, assert and hold reset to the + * enet controller - the default state after a hard reset. + */ + if (dwmac->stmmac_rst) + reset_control_assert(dwmac->stmmac_rst); +} + +static int socfpga_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct socfpga_dwmac *dwmac = priv; + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *stpriv = NULL; + int ret = 0; + + if (ndev) + stpriv = netdev_priv(ndev); + + /* Assert reset to the enet controller before changing the phy mode */ + if (dwmac->stmmac_rst) + reset_control_assert(dwmac->stmmac_rst); + + /* Setup the phy mode in the system manager registers according to + * devicetree configuration + */ + ret = socfpga_dwmac_setup(dwmac); + + /* Deassert reset for the phy configuration to be sampled by + * the enet controller, and operation to start in requested mode + */ + if (dwmac->stmmac_rst) + reset_control_deassert(dwmac->stmmac_rst); + + /* Before the enet controller is suspended, the phy is suspended. + * This causes the phy clock to be gated. The enet controller is + * resumed before the phy, so the clock is still gated "off" when + * the enet controller is resumed. This code makes sure the phy + * is "resumed" before reinitializing the enet controller since + * the enet controller depends on an active phy clock to complete + * a DMA reset. A DMA reset will "time out" if executed + * with no phy clock input on the Synopsys enet controller. + * Verified through Synopsys Case #8000711656. + * + * Note that the phy clock is also gated when the phy is isolated. + * Phy "suspend" and "isolate" controls are located in phy basic + * control register 0, and can be modified by the phy driver + * framework. + */ + if (stpriv && stpriv->phydev) + phy_resume(stpriv->phydev); + + return ret; +} + const struct stmmac_of_data socfpga_gmac_data = { .setup = socfpga_dwmac_probe, + .init = socfpga_dwmac_init, + .exit = socfpga_dwmac_exit, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index f37d90f..71b5419 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -87,7 +87,7 @@ enum power_event { (reg * 8)) #define GMAC_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \ (reg * 8)) -#define GMAC_MAX_PERFECT_ADDRESSES 32 +#define GMAC_MAX_PERFECT_ADDRESSES 1 /* PCS registers (AN/TBI/SGMII/RGMII) offset */ #define GMAC_AN_CTRL 0x000000c0 /* AN control */ @@ -261,6 +261,7 @@ enum rtc_control { #define GMAC_MMC_RX_INTR 0x104 #define GMAC_MMC_TX_INTR 0x108 #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 +#define GMAC_EXTHASH_BASE 0x500 extern const struct stmmac_dma_ops dwmac1000_dma_ops; #endif /* __DWMAC1000_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 9d37483..d8ef187 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -32,8 +32,9 @@ #include <asm/io.h> #include "dwmac1000.h" -static void dwmac1000_core_init(void __iomem *ioaddr, int mtu) +static void dwmac1000_core_init(struct mac_device_info *hw, int mtu) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_CONTROL); value |= GMAC_CORE_INIT; if (mtu > 1500) @@ -52,8 +53,9 @@ static void dwmac1000_core_init(void __iomem *ioaddr, int mtu) #endif } -static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr) +static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_CONTROL); value |= GMAC_CONTROL_IPC; @@ -64,8 +66,9 @@ static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr) return !!(value & GMAC_CONTROL_IPC); } -static void dwmac1000_dump_regs(void __iomem *ioaddr) +static void dwmac1000_dump_regs(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; int i; pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr); @@ -76,69 +79,98 @@ static void dwmac1000_dump_regs(void __iomem *ioaddr) } } -static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac1000_set_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), GMAC_ADDR_LOW(reg_n)); } -static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac1000_get_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), GMAC_ADDR_LOW(reg_n)); } -static void dwmac1000_set_filter(struct net_device *dev, int id) +static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits, + int mcbitslog2) +{ + int numhashregs, regs; + + switch (mcbitslog2) { + case 6: + writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW); + writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH); + return; + break; + case 7: + numhashregs = 4; + break; + case 8: + numhashregs = 8; + break; + default: + pr_debug("STMMAC: err in setting mulitcast filter\n"); + return; + break; + } + for (regs = 0; regs < numhashregs; regs++) + writel(mcfilterbits[regs], + ioaddr + GMAC_EXTHASH_BASE + regs * 4); +} + +static void dwmac1000_set_filter(struct mac_device_info *hw, + struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; unsigned int value = 0; - unsigned int perfect_addr_number; + unsigned int perfect_addr_number = hw->unicast_filter_entries; + u32 mc_filter[2]; + int mcbitslog2 = hw->mcast_bits_log2; pr_debug("%s: # mcasts %d, # unicast %d\n", __func__, netdev_mc_count(dev), netdev_uc_count(dev)); - if (dev->flags & IFF_PROMISC) + memset(mc_filter, 0, sizeof(mc_filter)); + + if (dev->flags & IFF_PROMISC) { value = GMAC_FRAME_FILTER_PR; - else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) - || (dev->flags & IFF_ALLMULTI)) { + } else if (dev->flags & IFF_ALLMULTI) { value = GMAC_FRAME_FILTER_PM; /* pass all multi */ - writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); - writel(0xffffffff, ioaddr + GMAC_HASH_LOW); } else if (!netdev_mc_empty(dev)) { - u32 mc_filter[2]; struct netdev_hw_addr *ha; /* Hash filter for multicast */ value = GMAC_FRAME_FILTER_HMC; - memset(mc_filter, 0, sizeof(mc_filter)); netdev_for_each_mc_addr(ha, dev) { - /* The upper 6 bits of the calculated CRC are used to - * index the contens of the hash table + /* The upper n bits of the calculated CRC are used to + * index the contents of the hash table. The number of + * bits used depends on the hardware configuration + * selected at core configuration time. */ - int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26; + int bit_nr = bitrev32(~crc32_le(~0, ha->addr, + ETH_ALEN)) >> + (32 - mcbitslog2); /* The most significant bit determines the register to * use (H/L) while the other 5 bits determine the bit * within the register. */ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); } - writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); - writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); } - /* Extra 16 regs are available in cores newer than the 3.40. */ - if (id > DWMAC_CORE_3_40) - perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES; - else - perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2; + dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2); /* Handle multiple unicast addresses (perfect filtering) */ if (netdev_uc_count(dev) > perfect_addr_number) - /* Switch to promiscuous mode if more than 16 addrs - * are required + /* Switch to promiscuous mode if more than unicast + * addresses are requested than supported by hardware. */ value |= GMAC_FRAME_FILTER_PR; else { @@ -146,7 +178,9 @@ static void dwmac1000_set_filter(struct net_device *dev, int id) struct netdev_hw_addr *ha; netdev_for_each_uc_addr(ha, dev) { - dwmac1000_set_umac_addr(ioaddr, ha->addr, reg); + stmmac_get_mac_addr(ioaddr, ha->addr, + GMAC_ADDR_HIGH(reg), + GMAC_ADDR_LOW(reg)); reg++; } } @@ -156,15 +190,13 @@ static void dwmac1000_set_filter(struct net_device *dev, int id) value |= GMAC_FRAME_FILTER_RA; #endif writel(value, ioaddr + GMAC_FRAME_FILTER); - - pr_debug("\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n", - readl(ioaddr + GMAC_FRAME_FILTER), - readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); } -static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + +static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, unsigned int fc, unsigned int pause_time) { + void __iomem *ioaddr = hw->pcsr; unsigned int flow = 0; pr_debug("GMAC Flow-Control:\n"); @@ -185,8 +217,9 @@ static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, writel(flow, ioaddr + GMAC_FLOW_CTRL); } -static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) +static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode) { + void __iomem *ioaddr = hw->pcsr; unsigned int pmt = 0; if (mode & WAKE_MAGIC) { @@ -201,9 +234,10 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) writel(pmt, ioaddr + GMAC_PMT); } -static int dwmac1000_irq_status(void __iomem *ioaddr, +static int dwmac1000_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { + void __iomem *ioaddr = hw->pcsr; u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); int ret = 0; @@ -268,8 +302,9 @@ static int dwmac1000_irq_status(void __iomem *ioaddr, return ret; } -static void dwmac1000_set_eee_mode(void __iomem *ioaddr) +static void dwmac1000_set_eee_mode(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; u32 value; /* Enable the link status receive on RGMII, SGMII ore SMII @@ -281,8 +316,9 @@ static void dwmac1000_set_eee_mode(void __iomem *ioaddr) writel(value, ioaddr + LPI_CTRL_STATUS); } -static void dwmac1000_reset_eee_mode(void __iomem *ioaddr) +static void dwmac1000_reset_eee_mode(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; u32 value; value = readl(ioaddr + LPI_CTRL_STATUS); @@ -290,8 +326,9 @@ static void dwmac1000_reset_eee_mode(void __iomem *ioaddr) writel(value, ioaddr + LPI_CTRL_STATUS); } -static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link) +static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link) { + void __iomem *ioaddr = hw->pcsr; u32 value; value = readl(ioaddr + LPI_CTRL_STATUS); @@ -304,8 +341,9 @@ static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link) writel(value, ioaddr + LPI_CTRL_STATUS); } -static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw) +static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw) { + void __iomem *ioaddr = hw->pcsr; int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16); /* Program the timers in the LPI timer control register: @@ -318,8 +356,9 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw) writel(value, ioaddr + LPI_TIMER_CTRL); } -static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart) +static void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart) { + void __iomem *ioaddr = hw->pcsr; /* auto negotiation enable and External Loopback enable */ u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE; @@ -329,8 +368,9 @@ static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart) writel(value, ioaddr + GMAC_AN_CTRL); } -static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv) +static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_ANE_ADV); if (value & GMAC_ANE_FD) @@ -368,7 +408,8 @@ static const struct stmmac_ops dwmac1000_ops = { .get_adv = dwmac1000_get_adv, }; -struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, + int perfect_uc_entries) { struct mac_device_info *mac; u32 hwid = readl(ioaddr + GMAC_VERSION); @@ -377,6 +418,14 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) if (!mac) return NULL; + mac->pcsr = ioaddr; + mac->multicast_filter_bins = mcbins; + mac->unicast_filter_entries = perfect_uc_entries; + mac->mcast_bits_log2 = 0; + + if (mac->multicast_filter_bins) + mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); + mac->mac = &dwmac1000_ops; mac->dma = &dwmac1000_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 2ff767b..f8dd773 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -32,8 +32,9 @@ #include <asm/io.h> #include "dwmac100.h" -static void dwmac100_core_init(void __iomem *ioaddr, int mtu) +static void dwmac100_core_init(struct mac_device_info *hw, int mtu) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + MAC_CONTROL); writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL); @@ -43,8 +44,9 @@ static void dwmac100_core_init(void __iomem *ioaddr, int mtu) #endif } -static void dwmac100_dump_mac_regs(void __iomem *ioaddr) +static void dwmac100_dump_mac_regs(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; pr_info("\t----------------------------------------------\n" "\t DWMAC 100 CSR (base addr = 0x%p)\n" "\t----------------------------------------------\n", ioaddr); @@ -66,30 +68,35 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr) readl(ioaddr + MAC_VLAN2)); } -static int dwmac100_rx_ipc_enable(void __iomem *ioaddr) +static int dwmac100_rx_ipc_enable(struct mac_device_info *hw) { return 0; } -static int dwmac100_irq_status(void __iomem *ioaddr, +static int dwmac100_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { return 0; } -static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac100_set_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac100_get_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void dwmac100_set_filter(struct net_device *dev, int id) +static void dwmac100_set_filter(struct mac_device_info *hw, + struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; u32 value = readl(ioaddr + MAC_CONTROL); @@ -137,9 +144,10 @@ static void dwmac100_set_filter(struct net_device *dev, int id) writel(value, ioaddr + MAC_CONTROL); } -static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, +static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, unsigned int fc, unsigned int pause_time) { + void __iomem *ioaddr = hw->pcsr; unsigned int flow = MAC_FLOW_CTRL_ENABLE; if (duplex) @@ -148,7 +156,7 @@ static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, } /* No PMT module supported on ST boards with this Eth chip. */ -static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode) +static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode) { return; } @@ -175,6 +183,7 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr) pr_info("\tDWMAC100\n"); + mac->pcsr = ioaddr; mac->mac = &dwmac100_ops; mac->dma = &dwmac100_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index c62e67f..9af50ba 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -262,7 +262,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev, /* Get and convert ADV/LP_ADV from the HW AN registers */ if (priv->hw->mac->get_adv) - priv->hw->mac->get_adv(priv->ioaddr, &adv); + priv->hw->mac->get_adv(priv->hw, &adv); else return -EOPNOTSUPP; /* should never happen indeed */ @@ -350,7 +350,7 @@ static int stmmac_ethtool_setsettings(struct net_device *dev, spin_lock(&priv->lock); if (priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->ioaddr, 1); + priv->hw->mac->ctrl_ane(priv->hw, 1); spin_unlock(&priv->lock); } @@ -464,7 +464,7 @@ stmmac_set_pauseparam(struct net_device *netdev, if (netif_running(netdev)) ret = phy_start_aneg(phy); } else - priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, + priv->hw->mac->flow_ctrl(priv->hw, phy->duplex, priv->flow_ctrl, priv->pause); return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 057a120..08addd6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -233,7 +233,7 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv) /* Check and enter in LPI mode */ if ((priv->dirty_tx == priv->cur_tx) && (priv->tx_path_in_lpi_mode == false)) - priv->hw->mac->set_eee_mode(priv->ioaddr); + priv->hw->mac->set_eee_mode(priv->hw); } /** @@ -244,7 +244,7 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv) */ void stmmac_disable_eee_mode(struct stmmac_priv *priv) { - priv->hw->mac->reset_eee_mode(priv->ioaddr); + priv->hw->mac->reset_eee_mode(priv->hw); del_timer_sync(&priv->eee_ctrl_timer); priv->tx_path_in_lpi_mode = false; } @@ -298,7 +298,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv) if (priv->eee_active) { pr_debug("stmmac: disable EEE\n"); del_timer_sync(&priv->eee_ctrl_timer); - priv->hw->mac->set_eee_timer(priv->ioaddr, 0, + priv->hw->mac->set_eee_timer(priv->hw, 0, tx_lpi_timer); } priv->eee_active = 0; @@ -313,12 +313,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv) priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer); add_timer(&priv->eee_ctrl_timer); - priv->hw->mac->set_eee_timer(priv->ioaddr, + priv->hw->mac->set_eee_timer(priv->hw, STMMAC_DEFAULT_LIT_LS, tx_lpi_timer); } else /* Set HW EEE according to the speed */ - priv->hw->mac->set_eee_pls(priv->ioaddr, + priv->hw->mac->set_eee_pls(priv->hw, priv->phydev->link); pr_debug("stmmac: Energy-Efficient Ethernet initialized\n"); @@ -693,7 +693,7 @@ static void stmmac_adjust_link(struct net_device *dev) } /* Flow Control operation */ if (phydev->pause) - priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex, + priv->hw->mac->flow_ctrl(priv->hw, phydev->duplex, fc, pause_time); if (phydev->speed != priv->speed) { @@ -1531,8 +1531,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) static void stmmac_check_ether_addr(struct stmmac_priv *priv) { if (!is_valid_ether_addr(priv->dev->dev_addr)) { - priv->hw->mac->get_umac_addr((void __iomem *) - priv->dev->base_addr, + priv->hw->mac->get_umac_addr(priv->hw, priv->dev->dev_addr, 0); if (!is_valid_ether_addr(priv->dev->dev_addr)) eth_hw_addr_random(priv->dev); @@ -1629,14 +1628,14 @@ static int stmmac_hw_setup(struct net_device *dev) } /* Copy the MAC addr into the HW */ - priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); + priv->hw->mac->set_umac_addr(priv->hw, dev->dev_addr, 0); /* If required, perform hw setup of the bus. */ if (priv->plat->bus_setup) priv->plat->bus_setup(priv->ioaddr); /* Initialize the MAC Core */ - priv->hw->mac->core_init(priv->ioaddr, dev->mtu); + priv->hw->mac->core_init(priv->hw, dev->mtu); /* Enable the MAC Rx/Tx */ stmmac_set_mac(priv->ioaddr, true); @@ -1662,7 +1661,7 @@ static int stmmac_hw_setup(struct net_device *dev) /* Dump DMA/MAC registers */ if (netif_msg_hw(priv)) { - priv->hw->mac->dump_regs(priv->ioaddr); + priv->hw->mac->dump_regs(priv->hw); priv->hw->dma->dump_regs(priv->ioaddr); } priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; @@ -1677,7 +1676,7 @@ static int stmmac_hw_setup(struct net_device *dev) } if (priv->pcs && priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->ioaddr, 0); + priv->hw->mac->ctrl_ane(priv->hw, 0); return 0; } @@ -2226,7 +2225,7 @@ static void stmmac_set_rx_mode(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); - priv->hw->mac->set_filter(dev, priv->synopsys_id); + priv->hw->mac->set_filter(priv->hw, dev); spin_unlock(&priv->lock); } @@ -2316,8 +2315,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) /* To handle GMAC own interrupts */ if (priv->plat->has_gmac) { - int status = priv->hw->mac->host_irq_status((void __iomem *) - dev->base_addr, + int status = priv->hw->mac->host_irq_status(priv->hw, &priv->xstats); if (unlikely(status)) { /* For LPI we need to save the tx status */ @@ -2600,7 +2598,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv) /* Identify the MAC HW device */ if (priv->plat->has_gmac) { priv->dev->priv_flags |= IFF_UNICAST_FLT; - mac = dwmac1000_setup(priv->ioaddr); + mac = dwmac1000_setup(priv->ioaddr, + priv->plat->multicast_filter_bins, + priv->plat->unicast_filter_entries); } else { mac = dwmac100_setup(priv->ioaddr); } @@ -2649,7 +2649,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv) /* To use alternate (extended) or normal descriptor structures */ stmmac_selec_desc_mode(priv); - ret = priv->hw->mac->rx_ipc(priv->ioaddr); + ret = priv->hw->mac->rx_ipc(priv->hw); if (!ret) { pr_warn(" RX IPC Checksum Offload not configured.\n"); priv->plat->rx_coe = STMMAC_RX_COE_NONE; @@ -2869,7 +2869,7 @@ int stmmac_suspend(struct net_device *ndev) /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) { - priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); + priv->hw->mac->pmt(priv->hw, priv->wolopts); priv->irq_wake = 1; } else { stmmac_set_mac(priv->ioaddr, false); @@ -2878,6 +2878,10 @@ int stmmac_suspend(struct net_device *ndev) clk_disable_unprepare(priv->stmmac_clk); } spin_unlock_irqrestore(&priv->lock, flags); + + priv->oldlink = 0; + priv->speed = 0; + priv->oldduplex = -1; return 0; } @@ -2898,7 +2902,7 @@ int stmmac_resume(struct net_device *ndev) * from another devices (e.g. serial console). */ if (device_may_wakeup(priv->device)) { - priv->hw->mac->pmt(priv->ioaddr, 0); + priv->hw->mac->pmt(priv->hw, 0); priv->irq_wake = 0; } else { pinctrl_pm_select_default_state(priv->device); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index ea7a65b..bb524a9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -52,6 +52,59 @@ static const struct of_device_id stmmac_dt_ids[] = { MODULE_DEVICE_TABLE(of, stmmac_dt_ids); #ifdef CONFIG_OF + +/* This function validates the number of Multicast filtering bins specified + * by the configuration through the device tree. The Synopsys GMAC supports + * 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC + * number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds + * to 7 bits, and 256 refers to 8 bits of the CRC. Any other setting is + * invalid and will cause the filtering algorithm to use Multicast + * promiscuous mode. + */ +static int dwmac1000_validate_mcast_bins(int mcast_bins) +{ + int x = mcast_bins; + + switch (x) { + case HASH_TABLE_SIZE: + case 128: + case 256: + break; + default: + x = 0; + pr_info("Hash table entries set to unexpected value %d", + mcast_bins); + break; + } + return x; +} + +/* This function validates the number of Unicast address entries supported + * by a particular Synopsys 10/100/1000 controller. The Synopsys controller + * supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter + * logic. This function validates a valid, supported configuration is + * selected, and defaults to 1 Unicast address if an unsupported + * configuration is selected. + */ +static int dwmac1000_validate_ucast_entries(int ucast_entries) +{ + int x = ucast_entries; + + switch (x) { + case 1: + case 32: + case 64: + case 128: + break; + default: + x = 1; + pr_info("Unicast table entries set to unexpected value %d\n", + ucast_entries); + break; + } + return x; +} + static int stmmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat, const char **mac) @@ -115,6 +168,12 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, */ plat->maxmtu = JUMBO_LEN; + /* Set default value for multicast hash bins */ + plat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat->unicast_filter_entries = 1; + /* * Currently only the properties needed on SPEAr600 * are provided. All other properties should be added @@ -131,6 +190,14 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, * are clearly MTUs */ of_property_read_u32(np, "max-frame-size", &plat->maxmtu); + of_property_read_u32(np, "snps,multicast-filter-bins", + &plat->multicast_filter_bins); + of_property_read_u32(np, "snps,perfect-filter-entries", + &plat->unicast_filter_entries); + plat->unicast_filter_entries = dwmac1000_validate_ucast_entries( + plat->unicast_filter_entries); + plat->multicast_filter_bins = dwmac1000_validate_mcast_bins( + plat->multicast_filter_bins); plat->has_gmac = 1; plat->pmt = 1; } |