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

Commit 9efa27bf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'xgene-Add-ethtool-stats-and-bug-fixes'



Iyappan Subramanian says:

====================
drivers: net: xgene: Add ethtool stats and bug fixes

This patch set,

- adds ethtool extended statistics support
- addresses errata workarounds
- fixes bugs related to statistics

v2: Address review comments from v1
	- Adds lock to protect mdio-xgene indirect MAC access
	- Refactors xgene-enet indirect MAC read/write functions
	- Uses mdio-xgene MAC access routines, if xgene-enet port
	  use the same HW.
v1:
	- Initial version

Signed-off-by: default avatarIyappan Subramanian <isubramanian@apm.com>
Signed-off-by: default avatarQuan Nguyen <qnguyen@apm.com>
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a95cfad9 8aba8474
Loading
Loading
Loading
Loading
+128 −4
Original line number Diff line number Diff line
@@ -23,9 +23,17 @@
struct xgene_gstrings_stats {
	char name[ETH_GSTRING_LEN];
	int offset;
	u32 addr;
	u32 mask;
};

#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) }
#define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
#define XGENE_EXTD_STAT(s, a, m)		\
		{			\
		.name = #s,		\
		.addr = a ## _ADDR,	\
		.mask = m		\
		}

static const struct xgene_gstrings_stats gstrings_stats[] = {
	XGENE_STAT(rx_packets),
@@ -40,7 +48,65 @@ static const struct xgene_gstrings_stats gstrings_stats[] = {
	XGENE_STAT(rx_fifo_errors)
};

static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
	XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),
	XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),
	XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),
	XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),
	XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),
	XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),
	XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),
	XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),
	XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),
	XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),
	XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),
	XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),
	XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),
	XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),
	XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),
	XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0),
	XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),
	XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),
	XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),
	XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),
	XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),
	XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),
	XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),
	XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),
	XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),
	XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
	XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),
	XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),
	XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),
	XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),
	XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),
	XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),
	XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),
	XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),
	XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),
	XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),
	XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),
	XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),
	XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),
	XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),
	XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),
	XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),
	XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12),
	XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0)
};

#define XGENE_STATS_LEN		ARRAY_SIZE(gstrings_stats)
#define XGENE_EXTD_STATS_LEN	ARRAY_SIZE(gstrings_extd_stats)
#define RFCS_IDX		7
#define RALN_IDX		13
#define RFLR_IDX		14
#define FALSE_RFLR_IDX		15
#define RUND_IDX		18
#define FALSE_RJBR_IDX		22
#define RX_OVERRUN_IDX		24
#define TFCS_IDX		38
#define TFRG_IDX		42
#define TX_UNDERRUN_IDX		43

static void xgene_get_drvinfo(struct net_device *ndev,
			      struct ethtool_drvinfo *info)
@@ -142,6 +208,11 @@ static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
		memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
		p += ETH_GSTRING_LEN;
	}

	for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
		memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);
		p += ETH_GSTRING_LEN;
	}
}

static int xgene_get_sset_count(struct net_device *ndev, int sset)
@@ -149,18 +220,71 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset)
	if (sset != ETH_SS_STATS)
		return -EINVAL;

	return XGENE_STATS_LEN;
	return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;
}

static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
{
	u32 rx_drop, tx_drop;
	u32 mask, tmp;
	int i;

	for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
		tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
		if (gstrings_extd_stats[i].mask) {
			mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);
			pdata->extd_stats[i] += (tmp & mask);
		}
	}

	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
		/* Errata 10GE_10 - SW should intepret RALN as 0 */
		pdata->extd_stats[RALN_IDX] = 0;
	} else {
		/* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
		pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];
		pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];
		pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];
	}

	pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);
	pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop;
	pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop;

	/* Errata 10GE_8 -  Update Frame recovered from Errata 10GE_8/ENET_11 */
	pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;
	/* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
	pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;
}

int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
{
	pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,
			XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);
	if (!pdata->extd_stats)
		return -ENOMEM;

	xgene_get_extd_stats(pdata);
	memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));

	return 0;
}

static void xgene_get_ethtool_stats(struct net_device *ndev,
				    struct ethtool_stats *dummy,
				    u64 *data)
{
	void *pdata = netdev_priv(ndev);
	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
	struct rtnl_link_stats64 stats;
	int i;

	dev_get_stats(ndev, &stats);
	for (i = 0; i < XGENE_STATS_LEN; i++)
		*data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
		data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);

	xgene_get_extd_stats(pdata);
	for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)
		data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];
}

static void xgene_get_pauseparam(struct net_device *ndev,
+99 −89
Original line number Diff line number Diff line
@@ -205,30 +205,24 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
}

void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
			    struct xgene_enet_pdata *pdata,
			    enum xgene_enet_err_code status)
{
	switch (status) {
	case INGRESS_CRC:
		ring->rx_crc_errors++;
		ring->rx_dropped++;
		break;
	case INGRESS_CHECKSUM:
	case INGRESS_CHECKSUM_COMPUTE:
		ring->rx_errors++;
		ring->rx_dropped++;
		break;
	case INGRESS_TRUNC_FRAME:
		ring->rx_frame_errors++;
		ring->rx_dropped++;
		break;
	case INGRESS_PKT_LEN:
		ring->rx_length_errors++;
		ring->rx_dropped++;
		break;
	case INGRESS_PKT_UNDER:
		ring->rx_frame_errors++;
		ring->rx_dropped++;
		break;
	case INGRESS_FIFO_OVERRUN:
		ring->rx_fifo_errors++;
@@ -270,42 +264,39 @@ static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata,
	iowrite32(val, addr);
}

static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr,
				   void __iomem *cmd, void __iomem *cmd_done,
				   u32 wr_addr, u32 wr_data)
void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data)
{
	u32 done;
	void __iomem *addr, *wr, *cmd, *cmd_done;
	struct net_device *ndev = pdata->ndev;
	u8 wait = 10;
	u32 done;

	if (pdata->mdio_driver && ndev->phydev &&
	    pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
		struct mii_bus *bus = ndev->phydev->mdio.bus;

		return xgene_mdio_wr_mac(bus->priv, wr_addr, wr_data);
	}

	addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
	wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET;
	cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
	cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;

	spin_lock(&pdata->mac_lock);
	iowrite32(wr_addr, addr);
	iowrite32(wr_data, wr);
	iowrite32(XGENE_ENET_WR_CMD, cmd);

	/* wait for write command to complete */
	while (!(done = ioread32(cmd_done)) && wait--)
		udelay(1);

	if (!done)
		return false;
		netdev_err(ndev, "mac write failed, addr: %04x data: %08x\n",
			   wr_addr, wr_data);

	iowrite32(0, cmd);

	return true;
}

static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata,
				  u32 wr_addr, u32 wr_data)
{
	void __iomem *addr, *wr, *cmd, *cmd_done;

	addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
	wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET;
	cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
	cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;

	if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data))
		netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n",
			   wr_addr);
	spin_unlock(&pdata->mac_lock);
}

static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
@@ -332,42 +323,69 @@ static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata,
	*val = ioread32(addr);
}

static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
				   void __iomem *cmd, void __iomem *cmd_done,
				   u32 rd_addr, u32 *rd_data)
u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr)
{
	u32 done;
	void __iomem *addr, *rd, *cmd, *cmd_done;
	u32 done, rd_data;
	u8 wait = 10;

	if (pdata->mdio_driver && pdata->ndev->phydev &&
	    pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
		struct mii_bus *bus = pdata->ndev->phydev->mdio.bus;

		return xgene_mdio_rd_mac(bus->priv, rd_addr);
	}

	addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
	rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET;
	cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
	cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;

	spin_lock(&pdata->mac_lock);
	iowrite32(rd_addr, addr);
	iowrite32(XGENE_ENET_RD_CMD, cmd);

	/* wait for read command to complete */
	while (!(done = ioread32(cmd_done)) && wait--)
		udelay(1);

	if (!done)
		return false;
		netdev_err(pdata->ndev, "mac read failed, addr: %04x\n",
			   rd_addr);

	*rd_data = ioread32(rd);
	rd_data = ioread32(rd);
	iowrite32(0, cmd);
	spin_unlock(&pdata->mac_lock);

	return true;
	return rd_data;
}

static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata,
				  u32 rd_addr, u32 *rd_data)
u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr)
{
	void __iomem *addr, *rd, *cmd, *cmd_done;
	u32 done, rd_data;
	u8 wait = 10;

	addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
	rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET;
	cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
	cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
	addr = pdata->mcx_stats_addr + STAT_ADDR_REG_OFFSET;
	rd = pdata->mcx_stats_addr + STAT_READ_REG_OFFSET;
	cmd = pdata->mcx_stats_addr + STAT_COMMAND_REG_OFFSET;
	cmd_done = pdata->mcx_stats_addr + STAT_COMMAND_DONE_REG_OFFSET;

	spin_lock(&pdata->stats_lock);
	iowrite32(rd_addr, addr);
	iowrite32(XGENE_ENET_RD_CMD, cmd);

	if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data))
		netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n",
	while (!(done = ioread32(cmd_done)) && wait--)
		udelay(1);

	if (!done)
		netdev_err(pdata->ndev, "mac stats read failed, addr: %04x\n",
			   rd_addr);

	rd_data = ioread32(rd);
	iowrite32(0, cmd);
	spin_unlock(&pdata->stats_lock);

	return rd_data;
}

static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
@@ -379,8 +397,8 @@ static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
		(dev_addr[1] << 8) | dev_addr[0];
	addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16);

	xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0);
	xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1);
	xgene_enet_wr_mac(pdata, STATION_ADDR0_ADDR, addr0);
	xgene_enet_wr_mac(pdata, STATION_ADDR1_ADDR, addr1);
}

static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
@@ -405,8 +423,8 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)

static void xgene_gmac_reset(struct xgene_enet_pdata *pdata)
{
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1);
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0);
}

static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata)
@@ -456,8 +474,8 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata)

	xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0);
	xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2);
	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2);
	xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl);
	mc2 = xgene_enet_rd_mac(pdata, MAC_CONFIG_2_ADDR);
	intf_ctl = xgene_enet_rd_mac(pdata, INTERFACE_CONTROL_ADDR);
	xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii);

	switch (pdata->phy_speed) {
@@ -495,8 +513,8 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata)
	}

	mc2 |= FULL_DUPLEX2 | PAD_CRC | LENGTH_CHK;
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
	xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
	xgene_enet_wr_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
	xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
	xgene_enet_configure_clock(pdata);

@@ -506,7 +524,7 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata)

static void xgene_enet_set_frame_size(struct xgene_enet_pdata *pdata, int size)
{
	xgene_enet_wr_mcx_mac(pdata, MAX_FRAME_LEN_ADDR, size);
	xgene_enet_wr_mac(pdata, MAX_FRAME_LEN_ADDR, size);
}

static void xgene_gmac_enable_tx_pause(struct xgene_enet_pdata *pdata,
@@ -528,14 +546,14 @@ static void xgene_gmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable)
{
	u32 data;

	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
	data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR);

	if (enable)
		data |= TX_FLOW_EN;
	else
		data &= ~TX_FLOW_EN;

	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data);

	pdata->mac_ops->enable_tx_pause(pdata, enable);
}
@@ -544,14 +562,14 @@ static void xgene_gmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable)
{
	u32 data;

	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
	data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR);

	if (enable)
		data |= RX_FLOW_EN;
	else
		data &= ~RX_FLOW_EN;

	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data);
}

static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
@@ -565,9 +583,9 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
	xgene_gmac_set_mac_addr(pdata);

	/* Adjust MDC clock frequency */
	xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value);
	value = xgene_enet_rd_mac(pdata, MII_MGMT_CONFIG_ADDR);
	MGMT_CLOCK_SEL_SET(&value, 7);
	xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value);
	xgene_enet_wr_mac(pdata, MII_MGMT_CONFIG_ADDR, value);

	/* Enable drop if bufpool not available */
	xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value);
@@ -600,6 +618,18 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
	xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX);
}

static void xgene_gmac_get_drop_cnt(struct xgene_enet_pdata *pdata,
				    u32 *rx, u32 *tx)
{
	u32 count;

	xgene_enet_rd_mcx_csr(pdata, ICM_ECM_DROP_COUNT_REG0_ADDR, &count);
	*rx = ICM_DROP_COUNT(count);
	*tx = ECM_DROP_COUNT(count);
	/* Errata: 10GE_4 - Fix ICM_ECM_DROP_COUNT not clear-on-read */
	xgene_enet_rd_mcx_csr(pdata, ECM_CONFIG0_REG_0_ADDR, &count);
}

static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
{
	u32 val = 0xffffffff;
@@ -637,32 +667,32 @@ static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata)
{
	u32 data;

	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN);
	data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN);
}

static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata)
{
	u32 data;

	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN);
	data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN);
}

static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata)
{
	u32 data;

	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN);
	data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN);
}

static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata)
{
	u32 data;

	xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN);
	data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR);
	xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN);
}

bool xgene_ring_mgr_init(struct xgene_enet_pdata *p)
@@ -733,27 +763,6 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
{
	struct device *dev = &pdata->pdev->dev;
	struct xgene_enet_desc_ring *ring;
	u32 pb;
	int i;

	pb = 0;
	for (i = 0; i < pdata->rxq_cnt; i++) {
		ring = pdata->rx_ring[i]->buf_pool;
		pb |= BIT(xgene_enet_get_fpsel(ring->id));
		ring = pdata->rx_ring[i]->page_pool;
		if (ring)
			pb |= BIT(xgene_enet_get_fpsel(ring->id));

	}
	xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb);

	pb = 0;
	for (i = 0; i < pdata->txq_cnt; i++) {
		ring = pdata->tx_ring[i];
		pb |= BIT(xgene_enet_ring_bufnum(ring->id));
	}
	xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);

	if (dev->of_node) {
		if (!IS_ERR(pdata->clk))
@@ -1009,6 +1018,7 @@ const struct xgene_mac_ops xgene_gmac_ops = {
	.tx_enable = xgene_gmac_tx_enable,
	.rx_disable = xgene_gmac_rx_disable,
	.tx_disable = xgene_gmac_tx_disable,
	.get_drop_cnt = xgene_gmac_get_drop_cnt,
	.set_speed = xgene_gmac_set_speed,
	.set_mac_addr = xgene_gmac_set_mac_addr,
	.set_framesize = xgene_enet_set_frame_size,
+62 −8
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ enum xgene_enet_rm {
#define BLOCK_ETH_CLKRST_CSR_OFFSET	0xc000
#define BLOCK_ETH_DIAG_CSR_OFFSET	0xD000
#define BLOCK_ETH_MAC_OFFSET		0x0000
#define BLOCK_ETH_STATS_OFFSET		0x0000
#define BLOCK_ETH_MAC_CSR_OFFSET	0x2800

#define CLKEN_ADDR			0xc208
@@ -126,6 +127,12 @@ enum xgene_enet_rm {
#define MAC_READ_REG_OFFSET		0x0c
#define MAC_COMMAND_DONE_REG_OFFSET	0x10

#define STAT_ADDR_REG_OFFSET            0x14
#define STAT_COMMAND_REG_OFFSET         0x18
#define STAT_WRITE_REG_OFFSET           0x1c
#define STAT_READ_REG_OFFSET            0x20
#define STAT_COMMAND_DONE_REG_OFFSET    0x24

#define PCS_ADDR_REG_OFFSET		0x00
#define PCS_COMMAND_REG_OFFSET		0x04
#define PCS_WRITE_REG_OFFSET		0x08
@@ -185,6 +192,10 @@ enum xgene_enet_rm {
#define CFG_CLE_NXTFPSEL0(val)		(((val) << 20) & GENMASK(23, 20))
#define ICM_CONFIG0_REG_0_ADDR		0x0400
#define ICM_CONFIG2_REG_0_ADDR		0x0410
#define ECM_CONFIG0_REG_0_ADDR		0x0500
#define ECM_CONFIG0_REG_1_ADDR		0x0504
#define ICM_ECM_DROP_COUNT_REG0_ADDR	0x0508
#define ICM_ECM_DROP_COUNT_REG1_ADDR	0x050c
#define RX_DV_GATE_REG_0_ADDR		0x05fc
#define TX_DV_GATE_EN0			BIT(2)
#define RX_DV_GATE_EN0			BIT(1)
@@ -217,12 +228,53 @@ enum xgene_enet_rm {
#define FULL_DUPLEX2			BIT(0)
#define PAD_CRC				BIT(2)
#define LENGTH_CHK			BIT(4)
#define SCAN_AUTO_INCR			BIT(5)
#define TBYT_ADDR			0x38
#define TPKT_ADDR			0x39

#define TR64_ADDR	0x20
#define TR127_ADDR	0x21
#define TR255_ADDR	0x22
#define TR511_ADDR	0x23
#define TR1K_ADDR	0x24
#define TRMAX_ADDR	0x25
#define TRMGV_ADDR	0x26

#define RFCS_ADDR	0x29
#define RMCA_ADDR	0x2a
#define RBCA_ADDR	0x2b
#define RXCF_ADDR	0x2c
#define RXPF_ADDR	0x2d
#define RXUO_ADDR	0x2e
#define RALN_ADDR	0x2f
#define RFLR_ADDR	0x30
#define RCDE_ADDR	0x31
#define RCSE_ADDR	0x32
#define RUND_ADDR	0x33
#define ROVR_ADDR	0x34
#define RFRG_ADDR	0x35
#define RJBR_ADDR	0x36
#define RDRP_ADDR	0x37

#define TMCA_ADDR	0x3a
#define TBCA_ADDR	0x3b
#define TXPF_ADDR	0x3c
#define TDFR_ADDR	0x3d
#define TEDF_ADDR	0x3e
#define TSCL_ADDR	0x3f
#define TMCL_ADDR	0x40
#define TLCL_ADDR	0x41
#define TXCL_ADDR	0x42
#define TNCL_ADDR	0x43
#define TPFH_ADDR	0x44
#define TDRP_ADDR	0x45
#define TJBR_ADDR	0x46
#define TFCS_ADDR	0x47
#define TXCF_ADDR	0x48
#define TOVR_ADDR	0x49
#define TUND_ADDR	0x4a
#define TFRG_ADDR	0x4b
#define DUMP_ADDR	0x27

#define ECM_DROP_COUNT(src)	xgene_get_bits(src, 0, 15)
#define ICM_DROP_COUNT(src)	xgene_get_bits(src, 16, 31)

#define TSO_IPPROTO_TCP			1

@@ -380,14 +432,16 @@ static inline u16 xgene_enet_get_numslots(u16 id, u32 size)
}

void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
			    struct xgene_enet_pdata *pdata,
			    enum xgene_enet_err_code status);

int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
bool xgene_ring_mgr_init(struct xgene_enet_pdata *p);
int xgene_enet_phy_connect(struct net_device *ndev);
void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata);
u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr);
void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr,
		       u32 wr_data);
u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr);

extern const struct xgene_mac_ops xgene_gmac_ops;
extern const struct xgene_port_ops xgene_gport_ops;
+44 −15
Original line number Diff line number Diff line
@@ -246,9 +246,9 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
	skb_frag_t *frag;
	dma_addr_t *frag_dma_addr;
	u16 skb_index;
	u8 status;
	int i, ret = 0;
	u8 mss_index;
	u8 status;
	int i;

	skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
	skb = cp_ring->cp_skb[skb_index];
@@ -275,19 +275,17 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
	/* Checking for error */
	status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
	if (unlikely(status > 2)) {
		xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev),
				       status);
		ret = -EIO;
		cp_ring->tx_dropped++;
		cp_ring->tx_errors++;
	}

	if (likely(skb)) {
		dev_kfree_skb_any(skb);
	} else {
		netdev_err(cp_ring->ndev, "completion skb is NULL\n");
		ret = -EIO;
	}

	return ret;
	return 0;
}

static int xgene_enet_setup_mss(struct net_device *ndev, u32 mss)
@@ -658,6 +656,18 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
	buf_pool->head = head;
}

/* Errata 10GE_10 and ENET_15 - Fix duplicated HW statistic counters */
static bool xgene_enet_errata_10GE_10(struct sk_buff *skb, u32 len, u8 status)
{
	if (status == INGRESS_CRC &&
	    len >= (ETHER_STD_PACKET + 1) &&
	    len <= (ETHER_STD_PACKET + 4) &&
	    skb->protocol == htons(ETH_P_8021Q))
		return true;

	return false;
}

/* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */
static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status)
{
@@ -708,10 +718,15 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
	status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) |
		  GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
	if (unlikely(status)) {
		if (!xgene_enet_errata_10GE_8(skb, datalen, status)) {
		if (xgene_enet_errata_10GE_8(skb, datalen, status)) {
			pdata->false_rflr++;
		} else if (xgene_enet_errata_10GE_10(skb, datalen, status)) {
			pdata->vlan_rjbr++;
		} else {
			dev_kfree_skb_any(skb);
			xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
			xgene_enet_parse_error(rx_ring, pdata, status);
			xgene_enet_parse_error(rx_ring, status);
			rx_ring->rx_dropped++;
			goto out;
		}
	}
@@ -1466,10 +1481,9 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)

static void xgene_enet_get_stats64(
			struct net_device *ndev,
			struct rtnl_link_stats64 *storage)
			struct rtnl_link_stats64 *stats)
{
	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
	struct rtnl_link_stats64 *stats = &pdata->stats;
	struct xgene_enet_desc_ring *ring;
	int i;

@@ -1478,6 +1492,8 @@ static void xgene_enet_get_stats64(
		if (ring) {
			stats->tx_packets += ring->tx_packets;
			stats->tx_bytes += ring->tx_bytes;
			stats->tx_dropped += ring->tx_dropped;
			stats->tx_errors += ring->tx_errors;
		}
	}

@@ -1486,14 +1502,18 @@ static void xgene_enet_get_stats64(
		if (ring) {
			stats->rx_packets += ring->rx_packets;
			stats->rx_bytes += ring->rx_bytes;
			stats->rx_errors += ring->rx_length_errors +
			stats->rx_dropped += ring->rx_dropped;
			stats->rx_errors += ring->rx_errors +
				ring->rx_length_errors +
				ring->rx_crc_errors +
				ring->rx_frame_errors +
				ring->rx_fifo_errors;
			stats->rx_dropped += ring->rx_dropped;
			stats->rx_length_errors += ring->rx_length_errors;
			stats->rx_crc_errors += ring->rx_crc_errors;
			stats->rx_frame_errors += ring->rx_frame_errors;
			stats->rx_fifo_errors += ring->rx_fifo_errors;
		}
	}
	memcpy(storage, stats, sizeof(struct rtnl_link_stats64));
}

static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr)
@@ -1788,12 +1808,15 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
	    pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
		pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET;
		pdata->mcx_stats_addr =
			pdata->base_addr + BLOCK_ETH_STATS_OFFSET;
		offset = (pdata->enet_id == XGENE_ENET1) ?
			  BLOCK_ETH_MAC_CSR_OFFSET :
			  X2_BLOCK_ETH_MAC_CSR_OFFSET;
		pdata->mcx_mac_csr_addr = base_addr + offset;
	} else {
		pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET;
		pdata->mcx_stats_addr = base_addr + BLOCK_AXG_STATS_OFFSET;
		pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET;
		pdata->pcs_addr = base_addr + BLOCK_PCS_OFFSET;
	}
@@ -2055,6 +2078,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
		goto err;

	xgene_enet_setup_ops(pdata);
	spin_lock_init(&pdata->mac_lock);

	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
		ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM;
@@ -2085,6 +2109,11 @@ static int xgene_enet_probe(struct platform_device *pdev)
			goto err1;
	}

	spin_lock_init(&pdata->stats_lock);
	ret = xgene_extd_stats_init(pdata);
	if (ret)
		goto err2;

	xgene_enet_napi_add(pdata);
	ret = register_netdev(ndev);
	if (ret) {
@@ -2130,8 +2159,8 @@ static int xgene_enet_remove(struct platform_device *pdev)
		xgene_enet_mdio_remove(pdata);

	unregister_netdev(ndev);
	pdata->port_ops->shutdown(pdata);
	xgene_enet_delete_desc_rings(pdata);
	pdata->port_ops->shutdown(pdata);
	free_netdev(ndev);

	return 0;
+11 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading