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);
        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],
 
 #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__ */
 
                            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));
                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.
                }
        }
 
-       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 {
        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));
 }
 
 
        .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);
                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;
 
 
        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);
 
        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);
 }
 
        /* 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);
        }
 
 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)
         */
        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
                 * 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;
        }
 
        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);