Skip to content

Commit

Permalink
octeon_ep: Add mailbox for control commands
Browse files Browse the repository at this point in the history
Add mailbox between host and NIC to send control commands from host to
NIC and receive responses and notifications from NIC to host driver,
like link status update.

Signed-off-by: Veerasenareddy Burru <vburru@marvell.com>
Signed-off-by: Abhijit Ayarekar <aayarekar@marvell.com>
Signed-off-by: Satananda Burla <sburla@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Veerasenareddy Burru authored and David S. Miller committed Apr 13, 2022
1 parent 1f2c2d0 commit 4ca2fbd
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 10 deletions.
198 changes: 195 additions & 3 deletions drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,209 @@
#define OCTEP_CTRL_MBOX_Q_OFFSET(m, i) ((m) + \
(sizeof(struct octep_ctrl_mbox_msg) * (i)))

static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 mask)
{
return (index + 1) & mask;
}

static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 mask)
{
return mask - ((pi - ci) & mask);
}

static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 mask)
{
return ((pi - ci) & mask);
}

int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
{
return -EINVAL;
u64 version, magic_num, status;

if (!mbox)
return -EINVAL;

if (!mbox->barmem) {
pr_info("octep_ctrl_mbox : Invalid barmem %p\n", mbox->barmem);
return -EINVAL;
}

magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(mbox->barmem));
if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) {
pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num);
return -EINVAL;
}

version = readq(OCTEP_CTRL_MBOX_INFO_FW_VERSION_OFFSET(mbox->barmem));
if (version != OCTEP_DRV_VERSION) {
pr_info("octep_ctrl_mbox : Firmware version mismatch %llx != %x\n",
version, OCTEP_DRV_VERSION);
return -EINVAL;
}

status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(mbox->barmem));
if (status != OCTEP_CTRL_MBOX_STATUS_READY) {
pr_info("octep_ctrl_mbox : Firmware is not ready.\n");
return -EINVAL;
}

mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(mbox->barmem));

writeq(mbox->version, OCTEP_CTRL_MBOX_INFO_HOST_VERSION_OFFSET(mbox->barmem));
writeq(OCTEP_CTRL_MBOX_STATUS_INIT, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));

mbox->h2fq.elem_cnt = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(mbox->barmem));
mbox->h2fq.elem_sz = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(mbox->barmem));
mbox->h2fq.mask = (mbox->h2fq.elem_cnt - 1);
mutex_init(&mbox->h2fq_lock);

mbox->f2hq.elem_cnt = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(mbox->barmem));
mbox->f2hq.elem_sz = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(mbox->barmem));
mbox->f2hq.mask = (mbox->f2hq.elem_cnt - 1);
mutex_init(&mbox->f2hq_lock);

mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(mbox->barmem);
mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(mbox->barmem);
mbox->h2fq.hw_q = mbox->barmem +
OCTEP_CTRL_MBOX_INFO_SZ +
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ +
OCTEP_CTRL_MBOX_F2HQ_INFO_SZ;

mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(mbox->barmem);
mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(mbox->barmem);
mbox->f2hq.hw_q = mbox->h2fq.hw_q +
((mbox->h2fq.elem_sz + sizeof(union octep_ctrl_mbox_msg_hdr)) *
mbox->h2fq.elem_cnt);

/* ensure ready state is seen after everything is initialized */
wmb();
writeq(OCTEP_CTRL_MBOX_STATUS_READY, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));

pr_info("Octep ctrl mbox : Init successful.\n");

return 0;
}

int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{
unsigned long timeout = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS);
unsigned long period = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_WAIT_MS);
struct octep_ctrl_mbox_q *q;
unsigned long expire;
u64 *mbuf, *word0;
u8 __iomem *qidx;
u16 pi, ci;
int i;

if (!mbox || !msg)
return -EINVAL;

q = &mbox->h2fq;
pi = readl(q->hw_prod);
ci = readl(q->hw_cons);

if (!octep_ctrl_mbox_circq_space(pi, ci, q->mask))
return -ENOMEM;

qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, pi);
mbuf = (u64 *)msg->msg;
word0 = &msg->hdr.word0;

mutex_lock(&mbox->h2fq_lock);
for (i = 1; i <= msg->hdr.sizew; i++)
writeq(*mbuf++, (qidx + (i * 8)));

writeq(*word0, qidx);

pi = octep_ctrl_mbox_circq_inc(pi, q->mask);
writel(pi, q->hw_prod);
mutex_unlock(&mbox->h2fq_lock);

/* don't check for notification response */
if (msg->hdr.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY)
return 0;

expire = jiffies + timeout;
while (true) {
*word0 = readq(qidx);
if (msg->hdr.flags == OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP)
break;
schedule_timeout_interruptible(period);
if (signal_pending(current) || time_after(jiffies, expire)) {
pr_info("octep_ctrl_mbox: Timed out\n");
return -EBUSY;
}
}
mbuf = (u64 *)msg->msg;
for (i = 1; i <= msg->hdr.sizew; i++)
*mbuf++ = readq(qidx + (i * 8));

return 0;
}

int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{
return -EINVAL;
struct octep_ctrl_mbox_q *q;
u32 count, pi, ci;
u8 __iomem *qidx;
u64 *mbuf;
int i;

if (!mbox || !msg)
return -EINVAL;

q = &mbox->f2hq;
pi = readl(q->hw_prod);
ci = readl(q->hw_cons);
count = octep_ctrl_mbox_circq_depth(pi, ci, q->mask);
if (!count)
return -EAGAIN;

qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, ci);
mbuf = (u64 *)msg->msg;

mutex_lock(&mbox->f2hq_lock);

msg->hdr.word0 = readq(qidx);
for (i = 1; i <= msg->hdr.sizew; i++)
*mbuf++ = readq(qidx + (i * 8));

ci = octep_ctrl_mbox_circq_inc(ci, q->mask);
writel(ci, q->hw_cons);

mutex_unlock(&mbox->f2hq_lock);

if (msg->hdr.flags != OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ || !mbox->process_req)
return 0;

mbox->process_req(mbox->user_ctx, msg);
mbuf = (u64 *)msg->msg;
for (i = 1; i <= msg->hdr.sizew; i++)
writeq(*mbuf++, (qidx + (i * 8)));

writeq(msg->hdr.word0, qidx);

return 0;
}

int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
{
return -EINVAL;
if (!mbox)
return -EINVAL;

writeq(OCTEP_CTRL_MBOX_STATUS_UNINIT,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
/* ensure uninit state is written before uninitialization */
wmb();

mutex_destroy(&mbox->h2fq_lock);
mutex_destroy(&mbox->f2hq_lock);

writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
writeq(0, OCTEP_CTRL_MBOX_INFO_HOST_VERSION_OFFSET(mbox->barmem));

pr_info("Octep ctrl mbox : Uninit successful.\n");

return 0;
}
6 changes: 3 additions & 3 deletions drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ struct octep_ctrl_mbox_q {
/* q mask */
u16 mask;
/* producer address in bar mem */
void __iomem *hw_prod;
u8 __iomem *hw_prod;
/* consumer address in bar mem */
void __iomem *hw_cons;
u8 __iomem *hw_cons;
/* q base address in bar mem */
void __iomem *hw_q;
u8 __iomem *hw_q;
};

struct octep_ctrl_mbox {
Expand Down
100 changes: 96 additions & 4 deletions drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,120 @@

int octep_get_link_status(struct octep_device *oct)
{
return 0;
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err;

req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS;
req.link.cmd = OCTEP_CTRL_NET_CMD_GET;

msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;

resp = (struct octep_ctrl_net_h2f_resp *)&req;
return resp->link.state;
}

void octep_set_link_status(struct octep_device *oct, bool up)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};

req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS;
req.link.cmd = OCTEP_CTRL_NET_CMD_SET;
req.link.state = (up) ? OCTEP_CTRL_NET_STATE_UP : OCTEP_CTRL_NET_STATE_DOWN;

msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW;
msg.msg = &req;
octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}

void octep_set_rx_state(struct octep_device *oct, bool up)
{
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};

req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_RX_STATE;
req.link.cmd = OCTEP_CTRL_NET_CMD_SET;
req.link.state = (up) ? OCTEP_CTRL_NET_STATE_UP : OCTEP_CTRL_NET_STATE_DOWN;

msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW;
msg.msg = &req;
octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}

int octep_get_mac_addr(struct octep_device *oct, u8 *addr)
{
return -1;
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err;

req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
req.link.cmd = OCTEP_CTRL_NET_CMD_GET;

msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MAC_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;

resp = (struct octep_ctrl_net_h2f_resp *)&req;
memcpy(addr, resp->mac.addr, ETH_ALEN);

return err;
}

int octep_get_link_info(struct octep_device *oct)
{
return -1;
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err;

req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET;

msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err;

resp = (struct octep_ctrl_net_h2f_resp *)&req;
oct->link_info.supported_modes = resp->link_info.supported_modes;
oct->link_info.advertised_modes = resp->link_info.advertised_modes;
oct->link_info.autoneg = resp->link_info.autoneg;
oct->link_info.pause = resp->link_info.pause;
oct->link_info.speed = resp->link_info.speed;

return err;
}

int octep_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info)
{
return -1;
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};

req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
req.link_info.cmd = OCTEP_CTRL_NET_CMD_SET;
req.link_info.info.advertised_modes = link_info->advertised_modes;
req.link_info.info.autoneg = link_info->autoneg;
req.link_info.info.pause = link_info->pause;
req.link_info.info.speed = link_info->speed;

msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW;
msg.msg = &req;

return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
}

0 comments on commit 4ca2fbd

Please sign in to comment.