Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0efedbf1 authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller
Browse files

net: stmmac: xgmac: Fix XGMAC selftests



Fixup the XGMAC selftests by correctly finishing the implementation of
set_filter callback.

Result:
$ ethtool -t enp4s0
The test result is PASS
The test extra info:
 1. MAC Loopback         	 0
 2. PHY Loopback         	 -95
 3. MMC Counters         	 -95
 4. EEE                  	 -95
 5. Hash Filter MC       	 0
 6. Perfect Filter UC    	 0
 7. MC Filter            	 0
 8. UC Filter            	 0
 9. Flow Control         	 0

Signed-off-by: default avatarJose Abreu <joabreu@synopsys.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0574f2ed
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -44,11 +44,13 @@
#define XGMAC_CORE_INIT_RX		0
#define XGMAC_PACKET_FILTER		0x00000008
#define XGMAC_FILTER_RA			BIT(31)
#define XGMAC_FILTER_HPF		BIT(10)
#define XGMAC_FILTER_PCF		BIT(7)
#define XGMAC_FILTER_PM			BIT(4)
#define XGMAC_FILTER_HMC		BIT(2)
#define XGMAC_FILTER_PR			BIT(0)
#define XGMAC_HASH_TABLE(x)		(0x00000010 + (x) * 4)
#define XGMAC_MAX_HASH_TABLE		8
#define XGMAC_RXQ_CTRL0			0x000000a0
#define XGMAC_RXQEN(x)			GENMASK((x) * 2 + 1, (x) * 2)
#define XGMAC_RXQEN_SHIFT(x)		((x) * 2)
@@ -99,11 +101,12 @@
#define XGMAC_MDIO_ADDR			0x00000200
#define XGMAC_MDIO_DATA			0x00000204
#define XGMAC_MDIO_C22P			0x00000220
#define XGMAC_ADDR0_HIGH		0x00000300
#define XGMAC_ADDRx_HIGH(x)		(0x00000300 + (x) * 0x8)
#define XGMAC_ADDR_MAX			32
#define XGMAC_AE			BIT(31)
#define XGMAC_DCS			GENMASK(19, 16)
#define XGMAC_DCS_SHIFT			16
#define XGMAC_ADDR0_LOW			0x00000304
#define XGMAC_ADDRx_LOW(x)		(0x00000304 + (x) * 0x8)
#define XGMAC_ARP_ADDR			0x00000c10
#define XGMAC_TIMESTAMP_STATUS		0x00000d20
#define XGMAC_TXTSC			BIT(15)
+74 −9
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@
 * stmmac XGMAC support.
 */

#include <linux/bitrev.h>
#include <linux/crc32.h>
#include "stmmac.h"
#include "dwxgmac2.h"

@@ -278,10 +280,10 @@ static void dwxgmac2_set_umac_addr(struct mac_device_info *hw,
	u32 value;

	value = (addr[5] << 8) | addr[4];
	writel(value | XGMAC_AE, ioaddr + XGMAC_ADDR0_HIGH);
	writel(value | XGMAC_AE, ioaddr + XGMAC_ADDRx_HIGH(reg_n));

	value = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
	writel(value, ioaddr + XGMAC_ADDR0_LOW);
	writel(value, ioaddr + XGMAC_ADDRx_LOW(reg_n));
}

static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
@@ -291,8 +293,8 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
	u32 hi_addr, lo_addr;

	/* Read the MAC address from the hardware */
	hi_addr = readl(ioaddr + XGMAC_ADDR0_HIGH);
	lo_addr = readl(ioaddr + XGMAC_ADDR0_LOW);
	hi_addr = readl(ioaddr + XGMAC_ADDRx_HIGH(reg_n));
	lo_addr = readl(ioaddr + XGMAC_ADDRx_LOW(reg_n));

	/* Extract the MAC address from the high and low words */
	addr[0] = lo_addr & 0xff;
@@ -303,19 +305,82 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
	addr[5] = (hi_addr >> 8) & 0xff;
}

static void dwxgmac2_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
				int mcbitslog2)
{
	int numhashregs, regs;

	switch (mcbitslog2) {
	case 6:
		numhashregs = 2;
		break;
	case 7:
		numhashregs = 4;
		break;
	case 8:
		numhashregs = 8;
		break;
	default:
		return;
	}

	for (regs = 0; regs < numhashregs; regs++)
		writel(mcfilterbits[regs], ioaddr + XGMAC_HASH_TABLE(regs));
}

static void dwxgmac2_set_filter(struct mac_device_info *hw,
				struct net_device *dev)
{
	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
	u32 value = XGMAC_FILTER_RA;
	u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
	int mcbitslog2 = hw->mcast_bits_log2;
	u32 mc_filter[8];
	int i;

	value &= ~(XGMAC_FILTER_PR | XGMAC_FILTER_HMC | XGMAC_FILTER_PM);
	value |= XGMAC_FILTER_HPF;

	memset(mc_filter, 0, sizeof(mc_filter));

	if (dev->flags & IFF_PROMISC) {
		value |= XGMAC_FILTER_PR | XGMAC_FILTER_PCF;
		value |= XGMAC_FILTER_PR;
		value |= XGMAC_FILTER_PCF;
	} else if ((dev->flags & IFF_ALLMULTI) ||
		   (netdev_mc_count(dev) > HASH_TABLE_SIZE)) {
		   (netdev_mc_count(dev) > hw->multicast_filter_bins)) {
		value |= XGMAC_FILTER_PM;
		writel(~0x0, ioaddr + XGMAC_HASH_TABLE(0));
		writel(~0x0, ioaddr + XGMAC_HASH_TABLE(1));

		for (i = 0; i < XGMAC_MAX_HASH_TABLE; i++)
			writel(~0x0, ioaddr + XGMAC_HASH_TABLE(i));
	} else if (!netdev_mc_empty(dev)) {
		struct netdev_hw_addr *ha;

		value |= XGMAC_FILTER_HMC;

		netdev_for_each_mc_addr(ha, dev) {
			int nr = (bitrev32(~crc32_le(~0, ha->addr, 6)) >>
					(32 - mcbitslog2));
			mc_filter[nr >> 5] |= (1 << (nr & 0x1F));
		}
	}

	dwxgmac2_set_mchash(ioaddr, mc_filter, mcbitslog2);

	/* Handle multiple unicast addresses */
	if (netdev_uc_count(dev) > XGMAC_ADDR_MAX) {
		value |= XGMAC_FILTER_PR;
	} else {
		struct netdev_hw_addr *ha;
		int reg = 1;

		netdev_for_each_uc_addr(ha, dev) {
			dwxgmac2_set_umac_addr(hw, ha->addr, reg);
			reg++;
		}

		for ( ; reg < XGMAC_ADDR_MAX; reg++) {
			writel(0, ioaddr + XGMAC_ADDRx_HIGH(reg));
			writel(0, ioaddr + XGMAC_ADDRx_LOW(reg));
		}
	}

	writel(value, ioaddr + XGMAC_PACKET_FILTER);