Commit 1e8c86a6 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'xgene-jumbo-and-pause-frame'



Iyappan Subramanian says:

====================
drivers: net: xgene: Add Jumbo and Pause frame support

This patch set adds,

1. Jumbo frame support
2. Pause frame based flow control

and fixes RSS for non-TCP/UDP packets.
====================

Signed-off-by: default avatarIyappan Subramanian <isubramanian@apm.com>
parents 397c5ad1 0296fe4d
Loading
Loading
Loading
Loading
+104 −6
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ static void xgene_cle_dbptr_to_hw(struct xgene_enet_pdata *pdata,
{
	buf[0] = SET_VAL(CLE_DROP, dbptr->drop);
	buf[4] = SET_VAL(CLE_FPSEL, dbptr->fpsel) |
		 SET_VAL(CLE_NFPSEL, dbptr->nxtfpsel) |
		 SET_VAL(CLE_DSTQIDL, dbptr->dstqid);

	buf[5] = SET_VAL(CLE_DSTQIDH, (u32)dbptr->dstqid >> CLE_DSTQIDL_LEN) |
@@ -346,11 +347,15 @@ static int xgene_cle_set_rss_idt(struct xgene_enet_pdata *pdata)
	for (i = 0; i < XGENE_CLE_IDT_ENTRIES; i++) {
		idx = i % pdata->rxq_cnt;
		pool_id = pdata->rx_ring[idx]->buf_pool->id;
		fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
		fpsel = xgene_enet_get_fpsel(pool_id);
		dstqid = xgene_enet_dst_ring_num(pdata->rx_ring[idx]);
		nfpsel = 0;
		idt_reg = 0;
		if (pdata->rx_ring[idx]->page_pool) {
			pool_id = pdata->rx_ring[idx]->page_pool->id;
			nfpsel = xgene_enet_get_fpsel(pool_id);
		}

		idt_reg = 0;
		xgene_cle_idt_to_hw(pdata, dstqid, fpsel, nfpsel, &idt_reg);
		ret = xgene_cle_dram_wr(&pdata->cle, &idt_reg, 1, i,
					RSS_IDT, CLE_CMD_WR);
@@ -400,9 +405,9 @@ static int xgene_cle_setup_rss(struct xgene_enet_pdata *pdata)
static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
{
	struct xgene_enet_cle *enet_cle = &pdata->cle;
	u32 def_qid, def_fpsel, def_nxtfpsel, pool_id;
	struct xgene_cle_dbptr dbptr[DB_MAX_PTRS];
	struct xgene_cle_ptree_branch *br;
	u32 def_qid, def_fpsel, pool_id;
	struct xgene_cle_ptree *ptree;
	struct xgene_cle_ptree_kn kn;
	int ret;
@@ -480,11 +485,11 @@ static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
				},
				{
					.valid = 0,
					.next_packet_pointer = 260,
					.next_packet_pointer = 26,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = LAST_NODE,
					.next_node = RSS_IPV4_OTHERS_NODE,
					.next_branch = 0,
					.data = 0x0,
					.mask = 0xffff
@@ -661,6 +666,92 @@ static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
				}
			}
		},
		{
			/* RSS_IPV4_OTHERS_NODE */
			.node_type = EWDN,
			.last_node = 0,
			.hdr_len_store = 1,
			.hdr_extn = NO_BYTE,
			.byte_store = NO_BYTE,
			.search_byte_store = BOTH_BYTES,
			.result_pointer = DB_RES_DROP,
			.num_branches = 6,
			.branch = {
				{
					/* SRC IPV4 B01 */
					.valid = 0,
					.next_packet_pointer = 28,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = RSS_IPV4_OTHERS_NODE,
					.next_branch = 1,
					.data = 0x0,
					.mask = 0xffff
				},
				{
					/* SRC IPV4 B23 */
					.valid = 0,
					.next_packet_pointer = 30,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = RSS_IPV4_OTHERS_NODE,
					.next_branch = 2,
					.data = 0x0,
					.mask = 0xffff
				},
				{
					/* DST IPV4 B01 */
					.valid = 0,
					.next_packet_pointer = 32,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = RSS_IPV4_OTHERS_NODE,
					.next_branch = 3,
					.data = 0x0,
					.mask = 0xffff
				},
				{
					/* DST IPV4 B23 */
					.valid = 0,
					.next_packet_pointer = 34,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = RSS_IPV4_OTHERS_NODE,
					.next_branch = 4,
					.data = 0x0,
					.mask = 0xffff
				},
				{
					/* TCP SRC Port */
					.valid = 0,
					.next_packet_pointer = 36,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = RSS_IPV4_OTHERS_NODE,
					.next_branch = 5,
					.data = 0x0,
					.mask = 0xffff
				},
				{
					/* TCP DST Port */
					.valid = 0,
					.next_packet_pointer = 260,
					.jump_bw = JMP_FW,
					.jump_rel = JMP_ABS,
					.operation = EQT,
					.next_node = LAST_NODE,
					.next_branch = 0,
					.data = 0x0,
					.mask = 0xffff
				}
			}
		},

		{
			/* LAST NODE */
			.node_type = EWDN,
@@ -706,14 +797,21 @@ static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)

	def_qid = xgene_enet_dst_ring_num(pdata->rx_ring[0]);
	pool_id = pdata->rx_ring[0]->buf_pool->id;
	def_fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
	def_fpsel = xgene_enet_get_fpsel(pool_id);
	def_nxtfpsel = 0;
	if (pdata->rx_ring[0]->page_pool) {
		pool_id = pdata->rx_ring[0]->page_pool->id;
		def_nxtfpsel = xgene_enet_get_fpsel(pool_id);
	}

	memset(dbptr, 0, sizeof(struct xgene_cle_dbptr) * DB_MAX_PTRS);
	dbptr[DB_RES_ACCEPT].fpsel =  def_fpsel;
	dbptr[DB_RES_ACCEPT].nxtfpsel = def_nxtfpsel;
	dbptr[DB_RES_ACCEPT].dstqid = def_qid;
	dbptr[DB_RES_ACCEPT].cle_priority = 1;

	dbptr[DB_RES_DEF].fpsel = def_fpsel;
	dbptr[DB_RES_DEF].nxtfpsel = def_nxtfpsel;
	dbptr[DB_RES_DEF].dstqid = def_qid;
	dbptr[DB_RES_DEF].cle_priority = 7;
	xgene_cle_setup_def_dbptr(pdata, enet_cle, &dbptr[DB_RES_DEF],
+3 −0
Original line number Diff line number Diff line
@@ -91,6 +91,8 @@
#define CLE_DSTQIDH_LEN		5
#define CLE_FPSEL_POS		21
#define CLE_FPSEL_LEN		4
#define CLE_NFPSEL_POS		17
#define CLE_NFPSEL_LEN		4
#define CLE_PRIORITY_POS	5
#define CLE_PRIORITY_LEN	3

@@ -104,6 +106,7 @@ enum xgene_cle_ptree_nodes {
	PKT_PROT_NODE,
	RSS_IPV4_TCP_NODE,
	RSS_IPV4_UDP_NODE,
	RSS_IPV4_OTHERS_NODE,
	LAST_NODE,
	MAX_NODES
};
+70 −0
Original line number Diff line number Diff line
@@ -163,6 +163,74 @@ static void xgene_get_ethtool_stats(struct net_device *ndev,
		*data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
}

static void xgene_get_pauseparam(struct net_device *ndev,
				 struct ethtool_pauseparam *pp)
{
	struct xgene_enet_pdata *pdata = netdev_priv(ndev);

	pp->autoneg = pdata->pause_autoneg;
	pp->tx_pause = pdata->tx_pause;
	pp->rx_pause = pdata->rx_pause;
}

static int xgene_set_pauseparam(struct net_device *ndev,
				struct ethtool_pauseparam *pp)
{
	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
	struct phy_device *phydev = ndev->phydev;
	u32 oldadv, newadv;

	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
	    pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
		if (!phydev)
			return -EINVAL;

		if (!(phydev->supported & SUPPORTED_Pause) ||
		    (!(phydev->supported & SUPPORTED_Asym_Pause) &&
		     pp->rx_pause != pp->tx_pause))
			return -EINVAL;

		pdata->pause_autoneg = pp->autoneg;
		pdata->tx_pause = pp->tx_pause;
		pdata->rx_pause = pp->rx_pause;

		oldadv = phydev->advertising;
		newadv = oldadv & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);

		if (pp->rx_pause)
			newadv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;

		if (pp->tx_pause)
			newadv ^= ADVERTISED_Asym_Pause;

		if (oldadv ^ newadv) {
			phydev->advertising = newadv;

			if (phydev->autoneg)
				return phy_start_aneg(phydev);

			if (!pp->autoneg) {
				pdata->mac_ops->flowctl_tx(pdata,
							   pdata->tx_pause);
				pdata->mac_ops->flowctl_rx(pdata,
							   pdata->rx_pause);
			}
		}

	} else {
		if (pp->autoneg)
			return -EINVAL;

		pdata->tx_pause = pp->tx_pause;
		pdata->rx_pause = pp->rx_pause;

		pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
		pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
	}

	return 0;
}

static const struct ethtool_ops xgene_ethtool_ops = {
	.get_drvinfo = xgene_get_drvinfo,
	.get_link = ethtool_op_get_link,
@@ -171,6 +239,8 @@ static const struct ethtool_ops xgene_ethtool_ops = {
	.get_ethtool_stats = xgene_get_ethtool_stats,
	.get_link_ksettings = xgene_get_link_ksettings,
	.set_link_ksettings = xgene_set_link_ksettings,
	.get_pauseparam = xgene_get_pauseparam,
	.set_pauseparam = xgene_set_pauseparam
};

void xgene_enet_set_ethtool_ops(struct net_device *ndev)
+126 −14
Original line number Diff line number Diff line
@@ -504,6 +504,56 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata)
	xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2);
}

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);
}

static void xgene_gmac_enable_tx_pause(struct xgene_enet_pdata *pdata,
				       bool enable)
{
	u32 data;

	xgene_enet_rd_mcx_csr(pdata, CSR_ECM_CFG_0_ADDR, &data);

	if (enable)
		data |= MULTI_DPF_AUTOCTRL | PAUSE_XON_EN;
	else
		data &= ~(MULTI_DPF_AUTOCTRL | PAUSE_XON_EN);

	xgene_enet_wr_mcx_csr(pdata, CSR_ECM_CFG_0_ADDR, data);
}

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);

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

	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data);

	pdata->mac_ops->enable_tx_pause(pdata, enable);
}

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);

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

	xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data);
}

static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
{
	u32 value;
@@ -527,6 +577,17 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
	/* Rtype should be copied from FP */
	xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0);

	/* Configure HW pause frame generation */
	xgene_enet_rd_mcx_csr(pdata, CSR_MULTI_DPF0_ADDR, &value);
	value = (DEF_QUANTA << 16) | (value & 0xFFFF);
	xgene_enet_wr_mcx_csr(pdata, CSR_MULTI_DPF0_ADDR, value);

	xgene_enet_wr_csr(pdata, RXBUF_PAUSE_THRESH, DEF_PAUSE_THRES);
	xgene_enet_wr_csr(pdata, RXBUF_PAUSE_OFF_THRESH, DEF_PAUSE_OFF_THRES);

	xgene_gmac_flowctl_tx(pdata, pdata->tx_pause);
	xgene_gmac_flowctl_rx(pdata, pdata->rx_pause);

	/* Rx-Tx traffic resume */
	xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0);

@@ -550,12 +611,14 @@ static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
}

static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
				  u32 dst_ring_num, u16 bufpool_id)
				  u32 dst_ring_num, u16 bufpool_id,
				  u16 nxtbufpool_id)
{
	u32 cb;
	u32 fpsel;
	u32 fpsel, nxtfpsel;

	fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20;
	fpsel = xgene_enet_get_fpsel(bufpool_id);
	nxtfpsel = xgene_enet_get_fpsel(nxtbufpool_id);

	xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb);
	cb |= CFG_CLE_BYPASS_EN0;
@@ -565,6 +628,7 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
	xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb);
	CFG_CLE_DSTQID0_SET(&cb, dst_ring_num);
	CFG_CLE_FPSEL0_SET(&cb, fpsel);
	CFG_CLE_NXTFPSEL0_SET(&cb, nxtfpsel);
	xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb);
}

@@ -652,16 +716,14 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
			     struct xgene_enet_desc_ring *ring)
{
	u32 addr, val, data;

	val = xgene_enet_ring_bufnum(ring->id);
	u32 addr, data;

	if (xgene_enet_is_bufpool(ring->id)) {
		addr = ENET_CFGSSQMIFPRESET_ADDR;
		data = BIT(val - 0x20);
		data = BIT(xgene_enet_get_fpsel(ring->id));
	} else {
		addr = ENET_CFGSSQMIWQRESET_ADDR;
		data = BIT(val);
		data = BIT(xgene_enet_ring_bufnum(ring->id));
	}

	xgene_enet_wr_ring_if(pdata, addr, data);
@@ -671,24 +733,24 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
{
	struct device *dev = &pdata->pdev->dev;
	struct xgene_enet_desc_ring *ring;
	u32 pb, val;
	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));

		val = xgene_enet_ring_bufnum(ring->id);
		pb |= BIT(val - 0x20);
	}
	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];

		val = xgene_enet_ring_bufnum(ring->id);
		pb |= BIT(val);
		pb |= BIT(xgene_enet_ring_bufnum(ring->id));
	}
	xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);

@@ -698,6 +760,48 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
	}
}

static u32 xgene_enet_flowctrl_cfg(struct net_device *ndev)
{
	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
	struct phy_device *phydev = ndev->phydev;
	u16 lcladv, rmtadv = 0;
	u32 rx_pause, tx_pause;
	u8 flowctl = 0;

	if (!phydev->duplex || !pdata->pause_autoneg)
		return 0;

	if (pdata->tx_pause)
		flowctl |= FLOW_CTRL_TX;

	if (pdata->rx_pause)
		flowctl |= FLOW_CTRL_RX;

	lcladv = mii_advertise_flowctrl(flowctl);

	if (phydev->pause)
		rmtadv = LPA_PAUSE_CAP;

	if (phydev->asym_pause)
		rmtadv |= LPA_PAUSE_ASYM;

	flowctl = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
	tx_pause = !!(flowctl & FLOW_CTRL_TX);
	rx_pause = !!(flowctl & FLOW_CTRL_RX);

	if (tx_pause != pdata->tx_pause) {
		pdata->tx_pause = tx_pause;
		pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
	}

	if (rx_pause != pdata->rx_pause) {
		pdata->rx_pause = rx_pause;
		pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
	}

	return 0;
}

static void xgene_enet_adjust_link(struct net_device *ndev)
{
	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
@@ -712,6 +816,8 @@ static void xgene_enet_adjust_link(struct net_device *ndev)
			mac_ops->tx_enable(pdata);
			phy_print_status(phydev);
		}

		xgene_enet_flowctrl_cfg(ndev);
	} else {
		mac_ops->rx_disable(pdata);
		mac_ops->tx_disable(pdata);
@@ -785,6 +891,8 @@ int xgene_enet_phy_connect(struct net_device *ndev)
	phy_dev->supported &= ~SUPPORTED_10baseT_Half &
			      ~SUPPORTED_100baseT_Half &
			      ~SUPPORTED_1000baseT_Half;
	phy_dev->supported |= SUPPORTED_Pause |
			      SUPPORTED_Asym_Pause;
	phy_dev->advertising = phy_dev->supported;

	return 0;
@@ -902,6 +1010,10 @@ const struct xgene_mac_ops xgene_gmac_ops = {
	.tx_disable = xgene_gmac_tx_disable,
	.set_speed = xgene_gmac_set_speed,
	.set_mac_addr = xgene_gmac_set_mac_addr,
	.set_framesize = xgene_enet_set_frame_size,
	.enable_tx_pause = xgene_gmac_enable_tx_pause,
	.flowctl_tx     = xgene_gmac_flowctl_tx,
	.flowctl_rx     = xgene_gmac_flowctl_rx,
};

const struct xgene_port_ops xgene_gport_ops = {
+25 −2
Original line number Diff line number Diff line
@@ -165,10 +165,23 @@ enum xgene_enet_rm {
#define CFG_CLE_IP_PROTOCOL0_SET(dst, val)	xgene_set_bits(dst, val, 16, 2)
#define CFG_CLE_DSTQID0_SET(dst, val)		xgene_set_bits(dst, val, 0, 12)
#define CFG_CLE_FPSEL0_SET(dst, val)		xgene_set_bits(dst, val, 16, 4)
#define CFG_CLE_NXTFPSEL0_SET(dst, val)		xgene_set_bits(dst, val, 20, 4)
#define CFG_MACMODE_SET(dst, val)		xgene_set_bits(dst, val, 18, 2)
#define CFG_WAITASYNCRD_SET(dst, val)		xgene_set_bits(dst, val, 0, 16)
#define CFG_CLE_DSTQID0(val)		(val & GENMASK(11, 0))
#define CFG_CLE_FPSEL0(val)		((val << 16) & GENMASK(19, 16))
#define CFG_CLE_DSTQID0(val)		((val) & GENMASK(11, 0))
#define CFG_CLE_FPSEL0(val)		(((val) << 16) & GENMASK(19, 16))
#define CSR_ECM_CFG_0_ADDR		0x0220
#define CSR_ECM_CFG_1_ADDR		0x0224
#define CSR_MULTI_DPF0_ADDR		0x0230
#define RXBUF_PAUSE_THRESH		0x0534
#define RXBUF_PAUSE_OFF_THRESH		0x0540
#define DEF_PAUSE_THRES			0x7d
#define DEF_PAUSE_OFF_THRES		0x6d
#define DEF_QUANTA			0x8000
#define NORM_PAUSE_OPCODE		0x0001
#define PAUSE_XON_EN			BIT(30)
#define MULTI_DPF_AUTOCTRL		BIT(28)
#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 RX_DV_GATE_REG_0_ADDR		0x05fc
@@ -196,6 +209,8 @@ enum xgene_enet_rm {
#define SOFT_RESET1			BIT(31)
#define TX_EN				BIT(0)
#define RX_EN				BIT(2)
#define TX_FLOW_EN			BIT(4)
#define RX_FLOW_EN			BIT(5)
#define ENET_LHD_MODE			BIT(25)
#define ENET_GHD_MODE			BIT(26)
#define FULL_DUPLEX2			BIT(0)
@@ -346,6 +361,14 @@ static inline bool xgene_enet_is_bufpool(u16 id)
	return ((id & RING_BUFNUM_MASK) >= 0x20) ? true : false;
}

static inline u8 xgene_enet_get_fpsel(u16 id)
{
	if (xgene_enet_is_bufpool(id))
		return xgene_enet_ring_bufnum(id) - RING_BUFNUM_BUFPOOL;

	return 0;
}

static inline u16 xgene_enet_get_numslots(u16 id, u32 size)
{
	bool is_bufpool = xgene_enet_is_bufpool(id);
Loading