Skip to content

Commit

Permalink
octeontx2-af: Forward CGX link notifications to PFs
Browse files Browse the repository at this point in the history
Upon receiving notification from firmware the CGX event handler
in the AF driver gets the current link info such as status, speed,
duplex etc from CGX driver and sends it across to PFs who have
registered to receive such notifications.

To support above
 - Mbox messaging support for sending msgs from AF to PF has been added.
 - Added mbox msgs so that PFs can register/unregister for link events.
 - Link notifications are sent to PF under two scenarioss.
  1. When a asynchronous link change notification is received from
     firmware with notification flag turned on for that PF.
  2. Upon notification turn on request, the current link status is
     send to the PF.

Also added a new mailbox msg using which RVU PF/VF can retrieve
their mapped CGX LMAC's current link info. Link info includes
status, speed, duplex and lmac type.

Signed-off-by: Linu Cherian <lcherian@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Linu Cherian authored and davem330 committed Oct 18, 2018
1 parent 96be2e0 commit 61071a8
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 12 deletions.
99 changes: 89 additions & 10 deletions drivers/net/ethernet/marvell/octeontx2/af/cgx.c
Expand Up @@ -29,6 +29,7 @@
* @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion
* @cmd_lock: Lock to serialize the command interface
* @resp: command response
* @link_info: link related information
* @event_cb: callback for linkchange events
* @cmd_pend: flag set before new command is started
* flag cleared after command response is received
Expand All @@ -40,6 +41,7 @@ struct lmac {
wait_queue_head_t wq_cmd_cmplt;
struct mutex cmd_lock;
u64 resp;
struct cgx_link_user_info link_info;
struct cgx_event_cb event_cb;
bool cmd_pend;
struct cgx *cgx;
Expand All @@ -58,6 +60,12 @@ struct cgx {

static LIST_HEAD(cgx_list);

/* Convert firmware speed encoding to user format(Mbps) */
static u32 cgx_speed_mbps[CGX_LINK_SPEED_MAX];

/* Convert firmware lmac type encoding to string */
static char *cgx_lmactype_string[LMAC_MODE_MAX];

/* Supported devices */
static const struct pci_device_id cgx_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) },
Expand Down Expand Up @@ -119,6 +127,24 @@ void *cgx_get_pdata(int cgx_id)
}
EXPORT_SYMBOL(cgx_get_pdata);

/* Ensure the required lock for event queue(where asynchronous events are
* posted) is acquired before calling this API. Else an asynchronous event(with
* latest link status) can reach the destination before this function returns
* and could make the link status appear wrong.
*/
int cgx_get_link_info(void *cgxd, int lmac_id,
struct cgx_link_user_info *linfo)
{
struct lmac *lmac = lmac_pdata(lmac_id, cgxd);

if (!lmac)
return -ENODEV;

*linfo = lmac->link_info;
return 0;
}
EXPORT_SYMBOL(cgx_get_link_info);

static u64 mac2u64 (u8 *mac_addr)
{
u64 mac = 0;
Expand Down Expand Up @@ -160,6 +186,14 @@ u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id)
}
EXPORT_SYMBOL(cgx_lmac_addr_get);

static inline u8 cgx_get_lmac_type(struct cgx *cgx, int lmac_id)
{
u64 cfg;

cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG);
return (cfg >> CGX_LMAC_TYPE_SHIFT) & CGX_LMAC_TYPE_MASK;
}

void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable)
{
struct cgx *cgx = cgx_get_pdata(cgx_id);
Expand Down Expand Up @@ -306,36 +340,79 @@ static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp,
return err;
}

static inline void cgx_link_usertable_init(void)
{
cgx_speed_mbps[CGX_LINK_NONE] = 0;
cgx_speed_mbps[CGX_LINK_10M] = 10;
cgx_speed_mbps[CGX_LINK_100M] = 100;
cgx_speed_mbps[CGX_LINK_1G] = 1000;
cgx_speed_mbps[CGX_LINK_2HG] = 2500;
cgx_speed_mbps[CGX_LINK_5G] = 5000;
cgx_speed_mbps[CGX_LINK_10G] = 10000;
cgx_speed_mbps[CGX_LINK_20G] = 20000;
cgx_speed_mbps[CGX_LINK_25G] = 25000;
cgx_speed_mbps[CGX_LINK_40G] = 40000;
cgx_speed_mbps[CGX_LINK_50G] = 50000;
cgx_speed_mbps[CGX_LINK_100G] = 100000;

cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII";
cgx_lmactype_string[LMAC_MODE_XAUI] = "XAUI";
cgx_lmactype_string[LMAC_MODE_RXAUI] = "RXAUI";
cgx_lmactype_string[LMAC_MODE_10G_R] = "10G_R";
cgx_lmactype_string[LMAC_MODE_40G_R] = "40G_R";
cgx_lmactype_string[LMAC_MODE_QSGMII] = "QSGMII";
cgx_lmactype_string[LMAC_MODE_25G_R] = "25G_R";
cgx_lmactype_string[LMAC_MODE_50G_R] = "50G_R";
cgx_lmactype_string[LMAC_MODE_100G_R] = "100G_R";
cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII";
}

static inline void link_status_user_format(u64 lstat,
struct cgx_link_user_info *linfo,
struct cgx *cgx, u8 lmac_id)
{
char *lmac_string;

linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)];
linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id);
lmac_string = cgx_lmactype_string[linfo->lmac_type_id];
strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1);
}

/* Hardware event handlers */
static inline void cgx_link_change_handler(u64 lstat,
struct lmac *lmac)
{
struct cgx_link_user_info *linfo;
struct cgx *cgx = lmac->cgx;
struct cgx_link_event event;
struct device *dev;
int err_type;

dev = &cgx->pdev->dev;

event.lstat.link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
event.lstat.full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
event.lstat.speed = FIELD_GET(RESP_LINKSTAT_SPEED, lstat);
event.lstat.err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat);
link_status_user_format(lstat, &event.link_uinfo, cgx, lmac->lmac_id);
err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat);

event.cgx_id = cgx->cgx_id;
event.lmac_id = lmac->lmac_id;

/* update the local copy of link status */
lmac->link_info = event.link_uinfo;
linfo = &lmac->link_info;

if (!lmac->event_cb.notify_link_chg) {
dev_dbg(dev, "cgx port %d:%d Link change handler null",
cgx->cgx_id, lmac->lmac_id);
if (event.lstat.err_type != CGX_ERR_NONE) {
if (err_type != CGX_ERR_NONE) {
dev_err(dev, "cgx port %d:%d Link error %d\n",
cgx->cgx_id, lmac->lmac_id,
event.lstat.err_type);
cgx->cgx_id, lmac->lmac_id, err_type);
}
dev_info(dev, "cgx port %d:%d Link status %s, speed %x\n",
dev_info(dev, "cgx port %d:%d Link is %s %d Mbps\n",
cgx->cgx_id, lmac->lmac_id,
event.lstat.link_up ? "UP" : "DOWN",
event.lstat.speed);
linfo->link_up ? "UP" : "DOWN", linfo->speed);
return;
}

Expand Down Expand Up @@ -563,6 +640,8 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
list_add(&cgx->cgx_list, &cgx_list);
cgx->cgx_id = cgx_get_cgx_cnt() - 1;

cgx_link_usertable_init();

err = cgx_lmac_init(cgx);
if (err)
goto err_release_lmac;
Expand Down
21 changes: 20 additions & 1 deletion drivers/net/ethernet/marvell/octeontx2/af/cgx.h
Expand Up @@ -11,6 +11,7 @@
#ifndef CGX_H
#define CGX_H

#include "mbox.h"
#include "cgx_fw_if.h"

/* PCI device IDs */
Expand All @@ -28,6 +29,8 @@
#define CMR_EN BIT_ULL(55)
#define DATA_PKT_TX_EN BIT_ULL(53)
#define DATA_PKT_RX_EN BIT_ULL(54)
#define CGX_LMAC_TYPE_SHIFT 40
#define CGX_LMAC_TYPE_MASK 0xF
#define CGXX_CMRX_INT 0x040
#define FW_CGX_INT BIT_ULL(1)
#define CGXX_CMRX_INT_ENA_W1S 0x058
Expand Down Expand Up @@ -55,8 +58,22 @@
#define CGX_NVEC 37
#define CGX_LMAC_FWI 0

enum LMAC_TYPE {
LMAC_MODE_SGMII = 0,
LMAC_MODE_XAUI = 1,
LMAC_MODE_RXAUI = 2,
LMAC_MODE_10G_R = 3,
LMAC_MODE_40G_R = 4,
LMAC_MODE_QSGMII = 6,
LMAC_MODE_25G_R = 7,
LMAC_MODE_50G_R = 8,
LMAC_MODE_100G_R = 9,
LMAC_MODE_USXGMII = 10,
LMAC_MODE_MAX,
};

struct cgx_link_event {
struct cgx_lnk_sts lstat;
struct cgx_link_user_info link_uinfo;
u8 cgx_id;
u8 lmac_id;
};
Expand All @@ -83,4 +100,6 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id);
void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable);
int cgx_get_link_info(void *cgxd, int lmac_id,
struct cgx_link_user_info *linfo);
#endif /* CGX_H */
22 changes: 22 additions & 0 deletions drivers/net/ethernet/marvell/octeontx2/af/mbox.h
Expand Up @@ -133,16 +133,24 @@ M(CGX_MAC_ADDR_GET, 0x204, cgx_mac_addr_set_or_get, \
cgx_mac_addr_set_or_get) \
M(CGX_PROMISC_ENABLE, 0x205, msg_req, msg_rsp) \
M(CGX_PROMISC_DISABLE, 0x206, msg_req, msg_rsp) \
M(CGX_START_LINKEVENTS, 0x207, msg_req, msg_rsp) \
M(CGX_STOP_LINKEVENTS, 0x208, msg_req, msg_rsp) \
M(CGX_GET_LINKINFO, 0x209, msg_req, cgx_link_info_msg) \
/* NPA mbox IDs (range 0x400 - 0x5FF) */ \
/* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \
/* TIM mbox IDs (range 0x800 - 0x9FF) */ \
/* CPT mbox IDs (range 0xA00 - 0xBFF) */ \
/* NPC mbox IDs (range 0x6000 - 0x7FFF) */ \
/* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \

/* Messages initiated by AF (range 0xC00 - 0xDFF) */
#define MBOX_UP_CGX_MESSAGES \
M(CGX_LINK_EVENT, 0xC00, cgx_link_info_msg, msg_rsp)

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

Expand Down Expand Up @@ -234,4 +242,18 @@ struct cgx_mac_addr_set_or_get {
struct mbox_msghdr hdr;
u8 mac_addr[ETH_ALEN];
};

struct cgx_link_user_info {
uint64_t link_up:1;
uint64_t full_duplex:1;
uint64_t lmac_type_id:4;
uint64_t speed:20; /* speed in Mbps */
#define LMACTYPE_STR_LEN 16
char lmac_type[LMACTYPE_STR_LEN];
};

struct cgx_link_info_msg {
struct mbox_msghdr hdr;
struct cgx_link_user_info link_info;
};
#endif /* MBOX_H */
82 changes: 82 additions & 0 deletions drivers/net/ethernet/marvell/octeontx2/af/rvu.c
Expand Up @@ -1316,6 +1316,63 @@ static void rvu_mbox_handler(struct work_struct *work)
otx2_mbox_msg_send(mbox, pf);
}

static void rvu_mbox_up_handler(struct work_struct *work)
{
struct rvu_work *mwork = container_of(work, struct rvu_work, work);
struct rvu *rvu = mwork->rvu;
struct otx2_mbox_dev *mdev;
struct mbox_hdr *rsp_hdr;
struct mbox_msghdr *msg;
struct otx2_mbox *mbox;
int offset, id;
u16 pf;

mbox = &rvu->mbox_up;
pf = mwork - rvu->mbox_wrk_up;
mdev = &mbox->dev[pf];

rsp_hdr = mdev->mbase + mbox->rx_start;
if (rsp_hdr->num_msgs == 0) {
dev_warn(rvu->dev, "mbox up handler: num_msgs = 0\n");
return;
}

offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);

for (id = 0; id < rsp_hdr->num_msgs; id++) {
msg = mdev->mbase + offset;

if (msg->id >= MBOX_MSG_MAX) {
dev_err(rvu->dev,
"Mbox msg with unknown ID 0x%x\n", msg->id);
goto end;
}

if (msg->sig != OTX2_MBOX_RSP_SIG) {
dev_err(rvu->dev,
"Mbox msg with wrong signature %x, ID 0x%x\n",
msg->sig, msg->id);
goto end;
}

switch (msg->id) {
case MBOX_MSG_CGX_LINK_EVENT:
break;
default:
if (msg->rc)
dev_err(rvu->dev,
"Mbox msg response has err %d, ID 0x%x\n",
msg->rc, msg->id);
break;
}
end:
offset = mbox->rx_start + msg->next_msgoff;
mdev->msgs_acked++;
}

otx2_mbox_reset(mbox, 0);
}

static int rvu_mbox_init(struct rvu *rvu)
{
struct rvu_hwinfo *hw = rvu->hw;
Expand All @@ -1337,6 +1394,13 @@ static int rvu_mbox_init(struct rvu *rvu)
goto exit;
}

rvu->mbox_wrk_up = devm_kcalloc(rvu->dev, hw->total_pfs,
sizeof(struct rvu_work), GFP_KERNEL);
if (!rvu->mbox_wrk_up) {
err = -ENOMEM;
goto exit;
}

/* Map mbox region shared with PFs */
bar4_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PF_BAR4_ADDR);
/* Mailbox is a reserved memory (in RAM) region shared between
Expand All @@ -1355,12 +1419,23 @@ static int rvu_mbox_init(struct rvu *rvu)
if (err)
goto exit;

err = otx2_mbox_init(&rvu->mbox_up, hwbase, rvu->pdev, rvu->afreg_base,
MBOX_DIR_AFPF_UP, hw->total_pfs);
if (err)
goto exit;

for (pf = 0; pf < hw->total_pfs; pf++) {
mwork = &rvu->mbox_wrk[pf];
mwork->rvu = rvu;
INIT_WORK(&mwork->work, rvu_mbox_handler);
}

for (pf = 0; pf < hw->total_pfs; pf++) {
mwork = &rvu->mbox_wrk_up[pf];
mwork->rvu = rvu;
INIT_WORK(&mwork->work, rvu_mbox_up_handler);
}

return 0;
exit:
if (hwbase)
Expand All @@ -1381,6 +1456,7 @@ static void rvu_mbox_destroy(struct rvu *rvu)
iounmap((void __iomem *)rvu->mbox.hwbase);

otx2_mbox_destroy(&rvu->mbox);
otx2_mbox_destroy(&rvu->mbox_up);
}

static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq)
Expand All @@ -1407,6 +1483,12 @@ static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq)
if (hdr->num_msgs)
queue_work(rvu->mbox_wq,
&rvu->mbox_wrk[pf].work);
mbox = &rvu->mbox_up;
mdev = &mbox->dev[pf];
hdr = mdev->mbase + mbox->rx_start;
if (hdr->num_msgs)
queue_work(rvu->mbox_wq,
&rvu->mbox_wrk_up[pf].work);
}
}

Expand Down

0 comments on commit 61071a8

Please sign in to comment.