net: stmmac: Support devicetree configs for mcast and ucast filter entries
authorVince Bridgers <vbridgers2013@gmail.com>
Thu, 31 Jul 2014 20:49:17 +0000 (15:49 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 31 Jul 2014 21:13:29 +0000 (14:13 -0700)
This patch adds and modifies code to support multiple Multicast and Unicast
Synopsys MAC filter configurations. The default configuration is defined to
support legacy driver behavior, which is 64 Multicast bins. The Unicast
filter code previously assumed all controllers support 32 or 16 Unicast
addresses based on controller version number, but this has been corrected
to support a default of 1 Unicast address. The filter configuration may
be specified through the devicetree using a Synopsys specific device tree
entry. This information was verified with Synopsys through
Synopsys Support Case #8000684337 and shared with the maintainer.

Signed-off-by: Vince Bridgers <vbridgers2013@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
include/linux/stmmac.h

index 49f72e1ffbef5e67c16647704092f308e9fa1cf0..de507c32036c75331e393ad5b013890ffffb9d1b 100644 (file)
@@ -381,7 +381,7 @@ struct stmmac_ops {
        int (*host_irq_status)(struct mac_device_info *hw,
                               struct stmmac_extra_stats *x);
        /* Multicast filter setting */
-       void (*set_filter)(struct net_device *dev);
+       void (*set_filter)(struct mac_device_info *hw, struct net_device *dev);
        /* Flow control setting */
        void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
                          unsigned int fc, unsigned int pause_time);
@@ -442,9 +442,13 @@ struct mac_device_info {
        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],
index 285e3056f362d39b997ddee141ae22800307a787..71b5419256c138e335c77aab87cf37784ff79037 100644 (file)
@@ -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__ */
index cdcbad1f1ac0e0c1d1a0c23f46cc84f7b83779dd..d8ef18786a1cadae60f5d550269a0036a3f24661 100644 (file)
@@ -97,12 +97,41 @@ static void dwmac1000_get_umac_addr(struct mac_device_info *hw,
                            GMAC_ADDR_LOW(reg_n));
 }
 
-static void dwmac1000_set_filter(struct net_device *dev)
+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));
@@ -120,10 +149,14 @@ static void dwmac1000_set_filter(struct net_device *dev)
                value = GMAC_FRAME_FILTER_HMC;
 
                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.
@@ -132,15 +165,12 @@ static void dwmac1000_set_filter(struct net_device *dev)
                }
        }
 
-       writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
-       writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
-
-       perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES;
+       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 {
@@ -160,10 +190,6 @@ static void dwmac1000_set_filter(struct net_device *dev)
        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));
 }
 
 
@@ -382,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);
@@ -392,6 +419,13 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
                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;
 
index 3a2d63388f8d507613286ce2d67752150f3e93ff..f8dd773f246caa1ecbcdfb451ef2c3fe8ff72395 100644 (file)
@@ -95,7 +95,8 @@ static void dwmac100_get_umac_addr(struct mac_device_info *hw,
        stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void dwmac100_set_filter(struct net_device *dev)
+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);
index cff2b69e62ee22f5e3767247333bb6787796095f..08addd65372818f48075b585eeb1d36ab682025b 100644 (file)
@@ -2225,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->hw->mac->set_filter(priv->hw, dev);
        spin_unlock(&priv->lock);
 }
 
@@ -2598,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);
        }
index ea7a65be1f9af4208748d808128a344bfdb74377..bb524a932be48b6a0fa2e096eab0a2bb7732314d 100644 (file)
@@ -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;
        }
index 6f27d4f957bd3846e12871b9a7da4a99739d49a4..cd63851b57f2804c4321cba8ec5c1b2b5637d935 100644 (file)
@@ -112,6 +112,8 @@ struct plat_stmmacenet_data {
        int riwt_off;
        int max_speed;
        int maxmtu;
+       int multicast_filter_bins;
+       int unicast_filter_entries;
        void (*fix_mac_speed)(void *priv, unsigned int speed);
        void (*bus_setup)(void __iomem *ioaddr);
        void *(*setup)(struct platform_device *pdev);