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

Merge branch 'octeontx2-af-priority-flow-control'



Hariprasad Kelam says:

====================
Priority flow control support for RVU netdev

In network congestion, instead of pausing all traffic on link
PFC allows user to selectively pause traffic according to its
class. This series of patches add support of PFC for RVU netdev
drivers.

Patch1 adds support to disable pause frames by default as
with PFC user can enable either PFC or 802.3 pause frames.
Patch2&3 adds resource management support for flow control
and configures necessary registers for PFC.
Patch4 adds dcb ops registration for netdev drivers.

V2 changes:
Fix compilation error by exporting required symbols 'otx2_config_pause_frm'
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b4f029f4 8e675581
Loading
Loading
Loading
Loading
+188 −59
Original line number Diff line number Diff line
@@ -578,16 +578,51 @@ void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable)
	}
}

static int cgx_lmac_get_pause_frm_status(void *cgxd, int lmac_id,
					 u8 *tx_pause, u8 *rx_pause)
{
	struct cgx *cgx = cgxd;
	u64 cfg;

	if (is_dev_rpm(cgx))
		return 0;

	if (!is_lmac_valid(cgx, lmac_id))
		return -ENODEV;

	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
	*rx_pause = !!(cfg & CGX_SMUX_RX_FRM_CTL_CTL_BCK);

	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
	*tx_pause = !!(cfg & CGX_SMUX_TX_CTL_L2P_BP_CONV);
	return 0;
}

/* Enable or disable forwarding received pause frames to Tx block */
void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable)
{
	struct cgx *cgx = cgxd;
	u8 rx_pause, tx_pause;
	bool is_pfc_enabled;
	struct lmac *lmac;
	u64 cfg;

	if (!cgx)
		return;

	lmac = lmac_pdata(lmac_id, cgx);
	if (!lmac)
		return;

	/* Pause frames are not enabled just return */
	if (!bitmap_weight(lmac->rx_fc_pfvf_bmap.bmap, lmac->rx_fc_pfvf_bmap.max))
		return;

	cgx_lmac_get_pause_frm_status(cgx, lmac_id, &rx_pause, &tx_pause);
	is_pfc_enabled = rx_pause ? false : true;

	if (enable) {
		if (!is_pfc_enabled) {
			cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL);
			cfg |= CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK;
			cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg);
@@ -596,6 +631,13 @@ void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable)
			cfg |= CGX_SMUX_RX_FRM_CTL_CTL_BCK;
			cgx_write(cgx, lmac_id,	CGXX_SMUX_RX_FRM_CTL, cfg);
		} else {
			cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_CBFC_CTL);
			cfg |= CGXX_SMUX_CBFC_CTL_BCK_EN;
			cgx_write(cgx, lmac_id, CGXX_SMUX_CBFC_CTL, cfg);
		}
	} else {

		if (!is_pfc_enabled) {
			cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL);
			cfg &= ~CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK;
			cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg);
@@ -603,6 +645,11 @@ void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable)
			cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
			cfg &= ~CGX_SMUX_RX_FRM_CTL_CTL_BCK;
			cgx_write(cgx, lmac_id,	CGXX_SMUX_RX_FRM_CTL, cfg);
		} else {
			cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_CBFC_CTL);
			cfg &= ~CGXX_SMUX_CBFC_CTL_BCK_EN;
			cgx_write(cgx, lmac_id, CGXX_SMUX_CBFC_CTL, cfg);
		}
	}
}

@@ -722,26 +769,6 @@ int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable)
	return !!(last & DATA_PKT_TX_EN);
}

static int cgx_lmac_get_pause_frm_status(void *cgxd, int lmac_id,
					 u8 *tx_pause, u8 *rx_pause)
{
	struct cgx *cgx = cgxd;
	u64 cfg;

	if (is_dev_rpm(cgx))
		return 0;

	if (!is_lmac_valid(cgx, lmac_id))
		return -ENODEV;

	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
	*rx_pause = !!(cfg & CGX_SMUX_RX_FRM_CTL_CTL_BCK);

	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
	*tx_pause = !!(cfg & CGX_SMUX_TX_CTL_L2P_BP_CONV);
	return 0;
}

static int cgx_lmac_enadis_pause_frm(void *cgxd, int lmac_id,
				     u8 tx_pause, u8 rx_pause)
{
@@ -782,21 +809,8 @@ static void cgx_lmac_pause_frm_config(void *cgxd, int lmac_id, bool enable)

	if (!is_lmac_valid(cgx, lmac_id))
		return;
	if (enable) {
		/* Enable receive pause frames */
		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
		cfg |= CGX_SMUX_RX_FRM_CTL_CTL_BCK;
		cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg);

		cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL);
		cfg |= CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK;
		cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg);

		/* Enable pause frames transmission */
		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
		cfg |= CGX_SMUX_TX_CTL_L2P_BP_CONV;
		cgx_write(cgx, lmac_id, CGXX_SMUX_TX_CTL, cfg);

	if (enable) {
		/* Set pause time and interval */
		cgx_write(cgx, lmac_id, CGXX_SMUX_TX_PAUSE_PKT_TIME,
			  DEFAULT_PAUSE_TIME);
@@ -813,7 +827,8 @@ static void cgx_lmac_pause_frm_config(void *cgxd, int lmac_id, bool enable)
		cfg &= ~0xFFFFULL;
		cgx_write(cgx, lmac_id, CGXX_GMP_GMI_TX_PAUSE_PKT_INTERVAL,
			  cfg | (DEFAULT_PAUSE_TIME / 2));
	} else {
	}

	/* ALL pause frames received are completely ignored */
	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
	cfg &= ~CGX_SMUX_RX_FRM_CTL_CTL_BCK;
@@ -827,7 +842,105 @@ static void cgx_lmac_pause_frm_config(void *cgxd, int lmac_id, bool enable)
	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
	cfg &= ~CGX_SMUX_TX_CTL_L2P_BP_CONV;
	cgx_write(cgx, lmac_id, CGXX_SMUX_TX_CTL, cfg);

	cfg = cgx_read(cgx, 0, CGXX_CMR_RX_OVR_BP);
	cfg |= CGX_CMR_RX_OVR_BP_EN(lmac_id);
	cfg &= ~CGX_CMR_RX_OVR_BP_BP(lmac_id);
	cgx_write(cgx, 0, CGXX_CMR_RX_OVR_BP, cfg);
}

int verify_lmac_fc_cfg(void *cgxd, int lmac_id, u8 tx_pause, u8 rx_pause,
		       int pfvf_idx)
{
	struct cgx *cgx = cgxd;
	struct lmac *lmac;

	lmac = lmac_pdata(lmac_id, cgx);
	if (!lmac)
		return -ENODEV;

	if (!rx_pause)
		clear_bit(pfvf_idx, lmac->rx_fc_pfvf_bmap.bmap);
	else
		set_bit(pfvf_idx, lmac->rx_fc_pfvf_bmap.bmap);

	if (!tx_pause)
		clear_bit(pfvf_idx, lmac->tx_fc_pfvf_bmap.bmap);
	else
		set_bit(pfvf_idx, lmac->tx_fc_pfvf_bmap.bmap);

	/* check if other pfvfs are using flow control */
	if (!rx_pause && bitmap_weight(lmac->rx_fc_pfvf_bmap.bmap, lmac->rx_fc_pfvf_bmap.max)) {
		dev_warn(&cgx->pdev->dev,
			 "Receive Flow control disable not permitted as its used by other PFVFs\n");
		return -EPERM;
	}

	if (!tx_pause && bitmap_weight(lmac->tx_fc_pfvf_bmap.bmap, lmac->tx_fc_pfvf_bmap.max)) {
		dev_warn(&cgx->pdev->dev,
			 "Transmit Flow control disable not permitted as its used by other PFVFs\n");
		return -EPERM;
	}

	return 0;
}

int cgx_lmac_pfc_config(void *cgxd, int lmac_id, u8 tx_pause,
			u8 rx_pause, u16 pfc_en)
{
	struct cgx *cgx = cgxd;
	u64 cfg;

	if (!is_lmac_valid(cgx, lmac_id))
		return -ENODEV;

	/* Return as no traffic classes are requested */
	if (tx_pause && !pfc_en)
		return 0;

	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_CBFC_CTL);

	if (rx_pause) {
		cfg |= (CGXX_SMUX_CBFC_CTL_RX_EN |
			CGXX_SMUX_CBFC_CTL_BCK_EN |
			CGXX_SMUX_CBFC_CTL_DRP_EN);
	} else {
		cfg &= ~(CGXX_SMUX_CBFC_CTL_RX_EN |
			CGXX_SMUX_CBFC_CTL_BCK_EN |
			CGXX_SMUX_CBFC_CTL_DRP_EN);
	}

	if (tx_pause)
		cfg |= CGXX_SMUX_CBFC_CTL_TX_EN;
	else
		cfg &= ~CGXX_SMUX_CBFC_CTL_TX_EN;

	cfg = FIELD_SET(CGX_PFC_CLASS_MASK, pfc_en, cfg);

	cgx_write(cgx, lmac_id, CGXX_SMUX_CBFC_CTL, cfg);

	/* Write source MAC address which will be filled into PFC packet */
	cfg = cgx_lmac_addr_get(cgx->cgx_id, lmac_id);
	cgx_write(cgx, lmac_id, CGXX_SMUX_SMAC, cfg);

	return 0;
}

int cgx_lmac_get_pfc_frm_cfg(void *cgxd, int lmac_id, u8 *tx_pause,
			     u8 *rx_pause)
{
	struct cgx *cgx = cgxd;
	u64 cfg;

	if (!is_lmac_valid(cgx, lmac_id))
		return -ENODEV;

	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_CBFC_CTL);

	*rx_pause = !!(cfg & CGXX_SMUX_CBFC_CTL_RX_EN);
	*tx_pause = !!(cfg & CGXX_SMUX_CBFC_CTL_TX_EN);

	return 0;
}

void cgx_lmac_ptp_config(void *cgxd, int lmac_id, bool enable)
@@ -1489,6 +1602,16 @@ static int cgx_lmac_init(struct cgx *cgx)
		/* Reserve first entry for default MAC address */
		set_bit(0, lmac->mac_to_index_bmap.bmap);

		lmac->rx_fc_pfvf_bmap.max = 128;
		err = rvu_alloc_bitmap(&lmac->rx_fc_pfvf_bmap);
		if (err)
			goto err_dmac_bmap_free;

		lmac->tx_fc_pfvf_bmap.max = 128;
		err = rvu_alloc_bitmap(&lmac->tx_fc_pfvf_bmap);
		if (err)
			goto err_rx_fc_bmap_free;

		init_waitqueue_head(&lmac->wq_cmd_cmplt);
		mutex_init(&lmac->cmd_lock);
		spin_lock_init(&lmac->event_cb_lock);
@@ -1505,6 +1628,10 @@ static int cgx_lmac_init(struct cgx *cgx)
	return cgx_lmac_verify_fwi_version(cgx);

err_bitmap_free:
	rvu_free_bitmap(&lmac->tx_fc_pfvf_bmap);
err_rx_fc_bmap_free:
	rvu_free_bitmap(&lmac->rx_fc_pfvf_bmap);
err_dmac_bmap_free:
	rvu_free_bitmap(&lmac->mac_to_index_bmap);
err_name_free:
	kfree(lmac->name);
@@ -1572,6 +1699,8 @@ static struct mac_ops cgx_mac_ops = {
	.mac_enadis_ptp_config =	cgx_lmac_ptp_config,
	.mac_rx_tx_enable =		cgx_lmac_rx_tx_enable,
	.mac_tx_enable =		cgx_lmac_tx_enable,
	.pfc_config =                   cgx_lmac_pfc_config,
	.mac_get_pfc_frm_cfg   =        cgx_lmac_get_pfc_frm_cfg,
};

static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+13 −0
Original line number Diff line number Diff line
@@ -76,6 +76,13 @@
#define CGXX_SMUX_TX_CTL		0x20178
#define CGXX_SMUX_TX_PAUSE_PKT_TIME	0x20110
#define CGXX_SMUX_TX_PAUSE_PKT_INTERVAL	0x20120
#define CGXX_SMUX_SMAC                        0x20108
#define CGXX_SMUX_CBFC_CTL                    0x20218
#define CGXX_SMUX_CBFC_CTL_RX_EN             BIT_ULL(0)
#define CGXX_SMUX_CBFC_CTL_TX_EN             BIT_ULL(1)
#define CGXX_SMUX_CBFC_CTL_DRP_EN            BIT_ULL(2)
#define CGXX_SMUX_CBFC_CTL_BCK_EN            BIT_ULL(3)
#define CGX_PFC_CLASS_MASK		     GENMASK_ULL(47, 32)
#define CGXX_GMP_GMI_TX_PAUSE_PKT_TIME	0x38230
#define CGXX_GMP_GMI_TX_PAUSE_PKT_INTERVAL	0x38248
#define CGX_SMUX_TX_CTL_L2P_BP_CONV	BIT_ULL(7)
@@ -172,4 +179,10 @@ u64 cgx_lmac_read(int cgx_id, int lmac_id, u64 offset);
int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index);
u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id);
u64 cgx_read_dmac_entry(void *cgxd, int index);
int cgx_lmac_pfc_config(void *cgxd, int lmac_id, u8 tx_pause, u8 rx_pause,
			u16 pfc_en);
int cgx_lmac_get_pfc_frm_cfg(void *cgxd, int lmac_id, u8 *tx_pause,
			     u8 *rx_pause);
int verify_lmac_fc_cfg(void *cgxd, int lmac_id, u8 tx_pause, u8 rx_pause,
		       int pfvf_idx);
#endif /* CGX_H */
+10 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
 * @resp:		command response
 * @link_info:		link related information
 * @mac_to_index_bmap:	Mac address to CGX table index mapping
 * @rx_fc_pfvf_bmap:    Receive flow control enabled netdev mapping
 * @tx_fc_pfvf_bmap:    Transmit flow control enabled netdev mapping
 * @event_cb:		callback for linkchange events
 * @event_cb_lock:	lock for serializing callback with unregister
 * @cgx:		parent cgx port
@@ -33,6 +35,8 @@ struct lmac {
	u64 resp;
	struct cgx_link_user_info link_info;
	struct rsrc_bmap mac_to_index_bmap;
	struct rsrc_bmap rx_fc_pfvf_bmap;
	struct rsrc_bmap tx_fc_pfvf_bmap;
	struct cgx_event_cb event_cb;
	/* lock for serializing callback with unregister */
	spinlock_t event_cb_lock;
@@ -110,6 +114,12 @@ struct mac_ops {

	int			(*mac_rx_tx_enable)(void *cgxd, int lmac_id, bool enable);
	int			(*mac_tx_enable)(void *cgxd, int lmac_id, bool enable);
	int                     (*pfc_config)(void *cgxd, int lmac_id,
					      u8 tx_pause, u8 rx_pause, u16 pfc_en);

	int                     (*mac_get_pfc_frm_cfg)(void *cgxd, int lmac_id,
						       u8 *tx_pause, u8 *rx_pause);

};

struct cgx {
+19 −0
Original line number Diff line number Diff line
@@ -172,6 +172,8 @@ M(RPM_STATS, 0x21C, rpm_stats, msg_req, rpm_stats_rsp) \
M(CGX_MAC_ADDR_RESET,	0x21D, cgx_mac_addr_reset, msg_req, msg_rsp)	\
M(CGX_MAC_ADDR_UPDATE,	0x21E, cgx_mac_addr_update, cgx_mac_addr_update_req, \
			       msg_rsp)					\
M(CGX_PRIO_FLOW_CTRL_CFG, 0x21F, cgx_prio_flow_ctrl_cfg, cgx_pfc_cfg,  \
				 cgx_pfc_rsp)                               \
/* NPA mbox IDs (range 0x400 - 0x5FF) */				\
M(NPA_LF_ALLOC,		0x400, npa_lf_alloc,				\
				npa_lf_alloc_req, npa_lf_alloc_rsp)	\
@@ -609,6 +611,21 @@ struct rpm_stats_rsp {
	u64 tx_stats[RPM_TX_STATS_COUNT];
};

struct cgx_pfc_cfg {
	struct mbox_msghdr hdr;
	u8 rx_pause;
	u8 tx_pause;
	u16 pfc_en; /*  bitmap indicating pfc enabled traffic classes */
};

struct cgx_pfc_rsp {
	struct mbox_msghdr hdr;
	u8 rx_pause;
	u8 tx_pause;
};

 /* NPA mbox message formats */

struct npc_set_pkind {
	struct mbox_msghdr hdr;
#define OTX2_PRIV_FLAGS_DEFAULT  BIT_ULL(0)
@@ -1603,6 +1620,8 @@ enum cgx_af_status {
	LMAC_AF_ERR_INVALID_PARAM	= -1101,
	LMAC_AF_ERR_PF_NOT_MAPPED	= -1102,
	LMAC_AF_ERR_PERM_DENIED		= -1103,
	LMAC_AF_ERR_PFC_ENADIS_PERM_DENIED       = -1104,
	LMAC_AF_ERR_8023PAUSE_ENADIS_PERM_DENIED = -1105,
};

#endif /* MBOX_H */
+172 −51
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ static struct mac_ops rpm_mac_ops = {
	.mac_enadis_ptp_config =	rpm_lmac_ptp_config,
	.mac_rx_tx_enable =		rpm_lmac_rx_tx_enable,
	.mac_tx_enable =		rpm_lmac_tx_enable,
	.pfc_config =                   rpm_lmac_pfc_config,
	.mac_get_pfc_frm_cfg   =        rpm_lmac_get_pfc_frm_cfg,
};

struct mac_ops *rpm_get_mac_ops(void)
@@ -96,11 +98,20 @@ int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable)
void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable)
{
	rpm_t *rpm = rpmd;
	struct lmac *lmac;
	u64 cfg;

	if (!rpm)
		return;

	lmac = lmac_pdata(lmac_id, rpm);
	if (!lmac)
		return;

	/* Pause frames are not enabled just return */
	if (!bitmap_weight(lmac->rx_fc_pfvf_bmap.bmap, lmac->rx_fc_pfvf_bmap.max))
		return;

	if (enable) {
		cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
@@ -122,13 +133,93 @@ int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id,
		return -ENODEV;

	cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
	if (!(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE)) {
		*rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE);

	cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
		*tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE);
	}

	return 0;
}

static void rpm_cfg_pfc_quanta_thresh(rpm_t *rpm, int lmac_id, u16 pfc_en,
				      bool enable)
{
	u64 quanta_offset = 0, quanta_thresh = 0, cfg;
	int i, shift;

	/* Set pause time and interval */
	for_each_set_bit(i, (unsigned long *)&pfc_en, 16) {
		switch (i) {
		case 0:
		case 1:
			quanta_offset = RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL01_QUANTA_THRESH;
			break;
		case 2:
		case 3:
			quanta_offset = RPMX_MTI_MAC100X_CL23_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL23_QUANTA_THRESH;
			break;
		case 4:
		case 5:
			quanta_offset = RPMX_MTI_MAC100X_CL45_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL45_QUANTA_THRESH;
			break;
		case 6:
		case 7:
			quanta_offset = RPMX_MTI_MAC100X_CL67_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL67_QUANTA_THRESH;
			break;
		case 8:
		case 9:
			quanta_offset = RPMX_MTI_MAC100X_CL89_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL89_QUANTA_THRESH;
			break;
		case 10:
		case 11:
			quanta_offset = RPMX_MTI_MAC100X_CL1011_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL1011_QUANTA_THRESH;
			break;
		case 12:
		case 13:
			quanta_offset = RPMX_MTI_MAC100X_CL1213_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL1213_QUANTA_THRESH;
			break;
		case 14:
		case 15:
			quanta_offset = RPMX_MTI_MAC100X_CL1415_PAUSE_QUANTA;
			quanta_thresh = RPMX_MTI_MAC100X_CL1415_QUANTA_THRESH;
			break;
		}

		if (!quanta_offset || !quanta_thresh)
			continue;

		shift = (i % 2) ? 1 : 0;
		cfg = rpm_read(rpm, lmac_id, quanta_offset);
		if (enable) {
			cfg |= ((u64)RPM_DEFAULT_PAUSE_TIME <<  shift * 16);
		} else {
			if (!shift)
				cfg &= ~GENMASK_ULL(15, 0);
			else
				cfg &= ~GENMASK_ULL(31, 16);
		}
		rpm_write(rpm, lmac_id, quanta_offset, cfg);

		cfg = rpm_read(rpm, lmac_id, quanta_thresh);
		if (enable) {
			cfg |= ((u64)(RPM_DEFAULT_PAUSE_TIME / 2) <<  shift * 16);
		} else {
			if (!shift)
				cfg &= ~GENMASK_ULL(15, 0);
			else
				cfg &= ~GENMASK_ULL(31, 16);
		}
		rpm_write(rpm, lmac_id, quanta_thresh, cfg);
	}
}

int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
			      u8 rx_pause)
{
@@ -152,8 +243,12 @@ int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,

	cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP);
	if (tx_pause) {
		/* Configure CL0 Pause Quanta & threshold for 802.3X frames */
		rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 1, true);
		cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id);
	} else {
		/* Disable all Pause Quanta & threshold values */
		rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xffff, false);
		cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id);
		cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id);
	}
@@ -166,41 +261,6 @@ void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
	rpm_t *rpm = rpmd;
	u64 cfg;

	if (enable) {
		/* Enable 802.3 pause frame mode */
		cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;
		rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);

		/* Enable receive pause frames */
		cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
		rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);

		/* Enable forward pause to TX block */
		cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
		rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);

		/* Enable pause frames transmission */
		cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
		rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);

		/* Set pause time and interval */
		cfg = rpm_read(rpm, lmac_id,
			       RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA);
		cfg &= ~0xFFFFULL;
		rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA,
			  cfg | RPM_DEFAULT_PAUSE_TIME);
		/* Set pause interval as the hardware default is too short */
		cfg = rpm_read(rpm, lmac_id,
			       RPMX_MTI_MAC100X_CL01_QUANTA_THRESH);
		cfg &= ~0xFFFFULL;
		rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_QUANTA_THRESH,
			  cfg | (RPM_DEFAULT_PAUSE_TIME / 2));

	} else {
	/* ALL pause frames received are completely ignored */
	cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
	cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
@@ -216,7 +276,6 @@ void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
	cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
	rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
}
}

int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat)
{
@@ -323,3 +382,65 @@ void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable)
		cfg &= ~RPMX_RX_TS_PREPEND;
	rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg);
}

int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 pfc_en)
{
	rpm_t *rpm = rpmd;
	u64 cfg;

	if (!is_lmac_valid(rpm, lmac_id))
		return -ENODEV;

	/* reset PFC class quanta and threshold */
	rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xffff, false);

	cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);

	if (rx_pause) {
		cfg &= ~(RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE |
				RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE |
				RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_FWD);
	} else {
		cfg |= (RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE |
				RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE |
				RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_FWD);
	}

	if (tx_pause) {
		rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, pfc_en, true);
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
	} else {
		rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xfff, false);
		cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
	}

	if (!rx_pause && !tx_pause)
		cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;
	else
		cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;

	rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);

	cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL);
	cfg = FIELD_SET(RPM_PFC_CLASS_MASK, pfc_en, cfg);
	rpm_write(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL, cfg);

	return 0;
}

int  rpm_lmac_get_pfc_frm_cfg(void *rpmd, int lmac_id, u8 *tx_pause, u8 *rx_pause)
{
	rpm_t *rpm = rpmd;
	u64 cfg;

	if (!is_lmac_valid(rpm, lmac_id))
		return -ENODEV;

	cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
	if (cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE) {
		*rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE);
		*tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE);
	}

	return 0;
}
Loading