Commit b8fea84a authored by Geetha sowjanya's avatar Geetha sowjanya Committed by David S. Miller
Browse files

octeontx2-pf: Add support to sync link state between representor and VFs



Implements the below requirement mentioned
in the representors documentation.

"
The representee's link state is controlled through the
representor. Setting the representor administratively UP
or DOWN should cause carrier ON or OFF at the representee.
"

This patch enables
- Reflecting the link state of representor based on the VF state and
 link state of VF based on representor.
- On VF interface up/down a notification is sent via mbox to representor
  to update the link state.
  eg: ip link set eth0 up/down  will disable carrier on/off
       of the corresponding representor(r0p1) interface.
- On representor interface up/down will cause the link state update of VF.
  eg: ip link set r0p1 up/down  will disable carrier on/off
       of the corresponding representee(eth0) interface.

Signed-off-by: default avatarHarman Kalra <hkalra@marvell.com>
Signed-off-by: default avatarGeetha sowjanya <gakula@marvell.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 940754a2
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \
M(PTP_GET_CAP,		0x00c, ptp_get_cap, msg_req, ptp_get_cap_rsp)	\
M(GET_REP_CNT,		0x00d, get_rep_cnt, msg_req, get_rep_cnt_rsp)	\
M(ESW_CFG,		0x00e, esw_cfg, esw_cfg_req, msg_rsp)	\
M(REP_EVENT_NOTIFY,     0x00f, rep_event_notify, rep_event, msg_rsp) \
/* CGX mbox IDs (range 0x200 - 0x3FF) */				\
M(CGX_START_RXTX,	0x200, cgx_start_rxtx, msg_req, msg_rsp)	\
M(CGX_STOP_RXTX,	0x201, cgx_stop_rxtx, msg_req, msg_rsp)		\
@@ -383,12 +384,16 @@ M(CPT_INST_LMTST, 0xD00, cpt_inst_lmtst, cpt_inst_lmtst_req, msg_rsp)
#define MBOX_UP_MCS_MESSAGES						\
M(MCS_INTR_NOTIFY,	0xE00, mcs_intr_notify, mcs_intr_info, msg_rsp)

#define MBOX_UP_REP_MESSAGES						\
M(REP_EVENT_UP_NOTIFY,	0xEF0, rep_event_up_notify, rep_event, msg_rsp) \

enum {
#define M(_name, _id, _1, _2, _3) MBOX_MSG_ ## _name = _id,
MBOX_MESSAGES
MBOX_UP_CGX_MESSAGES
MBOX_UP_CPT_MESSAGES
MBOX_UP_MCS_MESSAGES
MBOX_UP_REP_MESSAGES
#undef M
};

@@ -1572,6 +1577,26 @@ struct esw_cfg_req {
	u64 rsvd;
};

struct rep_evt_data {
	u8 port_state;
	u8 vf_state;
	u16 rx_mode;
	u16 rx_flags;
	u16 mtu;
	u64 rsvd[5];
};

struct rep_event {
	struct mbox_msghdr hdr;
	u16 pcifunc;
#define RVU_EVENT_PORT_STATE		BIT_ULL(0)
#define RVU_EVENT_PFVF_STATE		BIT_ULL(1)
#define RVU_EVENT_MTU_CHANGE		BIT_ULL(2)
#define RVU_EVENT_RX_MODE_CHANGE	BIT_ULL(3)
	u16 event;
	struct rep_evt_data evt_data;
};

struct flow_msg {
	unsigned char dmac[6];
	unsigned char smac[6];
+11 −0
Original line number Diff line number Diff line
@@ -513,6 +513,11 @@ struct rvu_switch {
	u16 start_entry;
};

struct rep_evtq_ent {
	struct list_head node;
	struct rep_event event;
};

struct rvu {
	void __iomem		*afreg_base;
	void __iomem		*pfreg_base;
@@ -599,6 +604,11 @@ struct rvu {
	int			rep_cnt;
	u16			*rep2pfvf_map;
	u8			rep_mode;
	struct			work_struct rep_evt_work;
	struct			workqueue_struct *rep_evt_wq;
	struct list_head	rep_evtq_head;
	/* Representor event lock */
	spinlock_t		rep_evtq_lock;
};

static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val)
@@ -1081,4 +1091,5 @@ void rvu_mcs_exit(struct rvu *rvu);
int rvu_rep_pf_init(struct rvu *rvu);
int rvu_rep_install_mcam_rules(struct rvu *rvu);
void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena);
int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable);
#endif /* RVU_H */
+12 −3
Original line number Diff line number Diff line
@@ -363,7 +363,6 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf,

		cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
		rvu_npc_set_pkind(rvu, pkind, pfvf);

		break;
	case NIX_INTF_TYPE_LBK:
		vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1;
@@ -5180,7 +5179,7 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
{
	u16 pcifunc = req->hdr.pcifunc;
	struct rvu_pfvf *pfvf;
	int nixlf, err;
	int nixlf, err, pf;

	err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
	if (err)
@@ -5198,6 +5197,10 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,

	rvu_switch_update_rules(rvu, pcifunc, true);

	pf = rvu_get_pf(pcifunc);
	if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode)
		rvu_rep_notify_pfvf_state(rvu, pcifunc, true);

	return rvu_cgx_start_stop_io(rvu, pcifunc, true);
}

@@ -5206,7 +5209,7 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
{
	u16 pcifunc = req->hdr.pcifunc;
	struct rvu_pfvf *pfvf;
	int nixlf, err;
	int nixlf, err, pf;

	err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
	if (err)
@@ -5227,6 +5230,9 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
	rvu_switch_update_rules(rvu, pcifunc, false);
	rvu_cgx_tx_enable(rvu, pcifunc, true);

	pf = rvu_get_pf(pcifunc);
	if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode)
		rvu_rep_notify_pfvf_state(rvu, pcifunc, false);
	return 0;
}

@@ -5254,6 +5260,9 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf)

	clear_bit(NIXLF_INITIALIZED, &pfvf->flags);

	if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode)
		rvu_rep_notify_pfvf_state(rvu, pcifunc, false);

	rvu_cgx_start_stop_io(rvu, pcifunc, false);

	if (pfvf->sq_ctx) {
+128 −0
Original line number Diff line number Diff line
@@ -14,6 +14,124 @@
#include "rvu.h"
#include "rvu_reg.h"

#define M(_name, _id, _fn_name, _req_type, _rsp_type)			\
static struct _req_type __maybe_unused					\
*otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid)		\
{									\
	struct _req_type *req;						\
									\
	req = (struct _req_type *)otx2_mbox_alloc_msg_rsp(		\
		&rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \
		sizeof(struct _rsp_type));				\
	if (!req)							\
		return NULL;						\
	req->hdr.sig = OTX2_MBOX_REQ_SIG;				\
	req->hdr.id = _id;						\
	return req;							\
}

MBOX_UP_REP_MESSAGES
#undef M

static int rvu_rep_up_notify(struct rvu *rvu, struct rep_event *event)
{
	struct rep_event *msg;
	int pf;

	pf = rvu_get_pf(event->pcifunc);

	mutex_lock(&rvu->mbox_lock);
	msg = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf);
	if (!msg) {
		mutex_unlock(&rvu->mbox_lock);
		return -ENOMEM;
	}

	msg->hdr.pcifunc = event->pcifunc;
	msg->event = event->event;

	memcpy(&msg->evt_data, &event->evt_data, sizeof(struct rep_evt_data));

	otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);

	otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);

	mutex_unlock(&rvu->mbox_lock);
	return 0;
}

static void rvu_rep_wq_handler(struct work_struct *work)
{
	struct rvu *rvu = container_of(work, struct rvu, rep_evt_work);
	struct rep_evtq_ent *qentry;
	struct rep_event *event;
	unsigned long flags;

	do {
		spin_lock_irqsave(&rvu->rep_evtq_lock, flags);
		qentry = list_first_entry_or_null(&rvu->rep_evtq_head,
						  struct rep_evtq_ent,
						  node);
		if (qentry)
			list_del(&qentry->node);

		spin_unlock_irqrestore(&rvu->rep_evtq_lock, flags);
		if (!qentry)
			break; /* nothing more to process */

		event = &qentry->event;

		rvu_rep_up_notify(rvu, event);
		kfree(qentry);
	} while (1);
}

int rvu_mbox_handler_rep_event_notify(struct rvu *rvu, struct rep_event *req,
				      struct msg_rsp *rsp)
{
	struct rep_evtq_ent *qentry;

	qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC);
	if (!qentry)
		return -ENOMEM;

	qentry->event = *req;
	spin_lock(&rvu->rep_evtq_lock);
	list_add_tail(&qentry->node, &rvu->rep_evtq_head);
	spin_unlock(&rvu->rep_evtq_lock);
	queue_work(rvu->rep_evt_wq, &rvu->rep_evt_work);
	return 0;
}

int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable)
{
	struct rep_event *req;
	int pf;

	if (!is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc)))
		return 0;

	pf = rvu_get_pf(rvu->rep_pcifunc);

	mutex_lock(&rvu->mbox_lock);
	req = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf);
	if (!req) {
		mutex_unlock(&rvu->mbox_lock);
		return -ENOMEM;
	}

	req->hdr.pcifunc = rvu->rep_pcifunc;
	req->event |= RVU_EVENT_PFVF_STATE;
	req->pcifunc = pcifunc;
	req->evt_data.vf_state = enable;

	otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);
	otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);

	mutex_unlock(&rvu->mbox_lock);
	return 0;
}

#define RVU_LF_RX_STATS(reg) \
		rvu_read64(rvu, blkaddr, NIX_AF_LFX_RX_STATX(nixlf, reg))

@@ -248,6 +366,16 @@ int rvu_rep_install_mcam_rules(struct rvu *rvu)
			}
		}
	}

	/* Initialize the wq for handling REP events */
	spin_lock_init(&rvu->rep_evtq_lock);
	INIT_LIST_HEAD(&rvu->rep_evtq_head);
	INIT_WORK(&rvu->rep_evt_work, rvu_rep_wq_handler);
	rvu->rep_evt_wq = alloc_workqueue("rep_evt_wq", 0, 0);
	if (!rvu->rep_evt_wq) {
		dev_err(rvu->dev, "REP workqueue allocation failed\n");
		return -ENOMEM;
	}
	return 0;
}

+2 −0
Original line number Diff line number Diff line
@@ -441,6 +441,7 @@ struct otx2_nic {
#define OTX2_FLAG_ADPTV_INT_COAL_ENABLED BIT_ULL(16)
#define OTX2_FLAG_TC_MARK_ENABLED		BIT_ULL(17)
#define OTX2_FLAG_REP_MODE_ENABLED		 BIT_ULL(18)
#define OTX2_FLAG_PORT_UP			BIT_ULL(19)
	u64			flags;
	u64			*cq_op_addr;

@@ -1125,4 +1126,5 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid);
void otx2_qos_config_txschq(struct otx2_nic *pfvf);
void otx2_clean_qos_queues(struct otx2_nic *pfvf);
int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info);
#endif /* OTX2_COMMON_H */
Loading