octeon_ep: Add mailbox for control commands

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>
This commit is contained in:
Veerasenareddy Burru 2022-04-12 20:34:59 -07:00 коммит произвёл David S. Miller
Родитель 1f2c2d0cee
Коммит 4ca2fbdd0b
3 изменённых файлов: 294 добавлений и 10 удалений

Просмотреть файл

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

Просмотреть файл

@ -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 {

Просмотреть файл

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