Commit 3b57de95 authored by Vince Bridgers's avatar Vince Bridgers Committed by David S. Miller
Browse files

net: stmmac: Support devicetree configs for mcast and ucast filter entries



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: default avatarVince Bridgers <vbridgers2013@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ea6856e3
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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],
+1 −0
Original line number Diff line number Diff line
@@ -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__ */
+50 −16
Original line number Diff line number Diff line
@@ -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;

+2 −1
Original line number Diff line number Diff line
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -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);
	}
Loading