Commit 577f0d1b authored by Veerasenareddy Burru's avatar Veerasenareddy Burru Committed by David S. Miller

octeon_ep: add separate mailbox command and response queues

Enhance control mailbox protocol to support following
 - separate command and response queues
    * command queue to send control commands to firmware.
    * response queue to receive responses and notifications from
      firmware.
 - variable size messages using scatter/gather
Signed-off-by: default avatarAbhijit Ayarekar <aayarekar@marvell.com>
Signed-off-by: default avatarVeerasenareddy Burru <vburru@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7c05d3d0
...@@ -24,41 +24,49 @@ ...@@ -24,41 +24,49 @@
/* Time in msecs to wait for message response */ /* Time in msecs to wait for message response */
#define OCTEP_CTRL_MBOX_MSG_WAIT_MS 10 #define OCTEP_CTRL_MBOX_MSG_WAIT_MS 10
#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(m) (m) /* Size of mbox info in bytes */
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(m) ((m) + 8) #define OCTEP_CTRL_MBOX_INFO_SZ 256
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(m) ((m) + 24) /* Size of mbox host to fw queue info in bytes */
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(m) ((m) + 144) #define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ 16
/* Size of mbox fw to host queue info in bytes */
#define OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ) #define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ 16
#define OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(m) (OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m))
#define OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 4) #define OCTEP_CTRL_MBOX_TOTAL_INFO_SZ (OCTEP_CTRL_MBOX_INFO_SZ + \
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 8) OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 12) OCTEP_CTRL_MBOX_F2HQ_INFO_SZ)
#define OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m) ((m) + \ #define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(m) (m)
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(m) ((m) + 8)
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS(m) ((m) + 24)
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS(m) ((m) + 144)
#define OCTEP_CTRL_MBOX_H2FQ_INFO(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ)
#define OCTEP_CTRL_MBOX_H2FQ_PROD(m) (OCTEP_CTRL_MBOX_H2FQ_INFO(m))
#define OCTEP_CTRL_MBOX_H2FQ_CONS(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 4)
#define OCTEP_CTRL_MBOX_H2FQ_SZ(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 8)
#define OCTEP_CTRL_MBOX_F2HQ_INFO(m) ((m) + \
OCTEP_CTRL_MBOX_INFO_SZ + \ OCTEP_CTRL_MBOX_INFO_SZ + \
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ) OCTEP_CTRL_MBOX_H2FQ_INFO_SZ)
#define OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(m) (OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) #define OCTEP_CTRL_MBOX_F2HQ_PROD(m) (OCTEP_CTRL_MBOX_F2HQ_INFO(m))
#define OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 4) #define OCTEP_CTRL_MBOX_F2HQ_CONS(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 4)
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 8) #define OCTEP_CTRL_MBOX_F2HQ_SZ(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 8)
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 12)
#define OCTEP_CTRL_MBOX_Q_OFFSET(m, i) ((m) + \ static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);
(sizeof(struct octep_ctrl_mbox_msg) * (i)))
static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 mask) static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz)
{ {
return (index + 1) & mask; return (index + inc) % sz;
} }
static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 mask) static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz)
{ {
return mask - ((pi - ci) & mask); return sz - (abs(pi - ci) % sz);
} }
static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 mask) static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)
{ {
return ((pi - ci) & mask); return (abs(pi - ci) % sz);
} }
int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox) int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
...@@ -73,153 +81,170 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox) ...@@ -73,153 +81,170 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
return -EINVAL; return -EINVAL;
} }
magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(mbox->barmem)); magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(mbox->barmem));
if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) { if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) {
pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num); pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num);
return -EINVAL; return -EINVAL;
} }
status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(mbox->barmem)); status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem));
if (status != OCTEP_CTRL_MBOX_STATUS_READY) { if (status != OCTEP_CTRL_MBOX_STATUS_READY) {
pr_info("octep_ctrl_mbox : Firmware is not ready.\n"); pr_info("octep_ctrl_mbox : Firmware is not ready.\n");
return -EINVAL; return -EINVAL;
} }
mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(mbox->barmem)); mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem));
writeq(OCTEP_CTRL_MBOX_STATUS_INIT, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); writeq(OCTEP_CTRL_MBOX_STATUS_INIT,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
mbox->h2fq.elem_cnt = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(mbox->barmem)); mbox->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem));
mbox->h2fq.elem_sz = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(mbox->barmem)); mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem);
mbox->h2fq.mask = (mbox->h2fq.elem_cnt - 1); mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem);
mutex_init(&mbox->h2fq_lock); mbox->h2fq.hw_q = mbox->barmem + OCTEP_CTRL_MBOX_TOTAL_INFO_SZ;
mbox->f2hq.elem_cnt = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(mbox->barmem)); mbox->f2hq.sz = readl(OCTEP_CTRL_MBOX_F2HQ_SZ(mbox->barmem));
mbox->f2hq.elem_sz = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(mbox->barmem)); mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD(mbox->barmem);
mbox->f2hq.mask = (mbox->f2hq.elem_cnt - 1); mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS(mbox->barmem);
mutex_init(&mbox->f2hq_lock); mbox->f2hq.hw_q = mbox->barmem +
OCTEP_CTRL_MBOX_TOTAL_INFO_SZ +
mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(mbox->barmem); mbox->h2fq.sz;
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 */ /* ensure ready state is seen after everything is initialized */
wmb(); wmb();
writeq(OCTEP_CTRL_MBOX_STATUS_READY, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); writeq(OCTEP_CTRL_MBOX_STATUS_READY,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
pr_info("Octep ctrl mbox : Init successful.\n"); pr_info("Octep ctrl mbox : Init successful.\n");
return 0; return 0;
} }
static void
octep_write_mbox_data(struct octep_ctrl_mbox_q *q, u32 *pi, u32 ci, void *buf, u32 w_sz)
{
u8 __iomem *qbuf;
u32 cp_sz;
/* Assumption: Caller has ensured enough write space */
qbuf = (q->hw_q + *pi);
if (*pi < ci) {
/* copy entire w_sz */
memcpy_toio(qbuf, buf, w_sz);
*pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
} else {
/* copy up to end of queue */
cp_sz = min((q->sz - *pi), w_sz);
memcpy_toio(qbuf, buf, cp_sz);
w_sz -= cp_sz;
*pi = octep_ctrl_mbox_circq_inc(*pi, cp_sz, q->sz);
if (w_sz) {
/* roll over and copy remaining w_sz */
buf += cp_sz;
qbuf = (q->hw_q + *pi);
memcpy_toio(qbuf, buf, w_sz);
*pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
}
}
}
int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg) 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); struct octep_ctrl_mbox_msg_buf *sg;
unsigned long period = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_WAIT_MS);
struct octep_ctrl_mbox_q *q; struct octep_ctrl_mbox_q *q;
unsigned long expire; u32 pi, ci, buf_sz, w_sz;
u64 *mbuf, *word0; int s;
u8 __iomem *qidx;
u16 pi, ci;
int i;
if (!mbox || !msg) if (!mbox || !msg)
return -EINVAL; return -EINVAL;
if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
return -EIO;
mutex_lock(&mbox->h2fq_lock);
q = &mbox->h2fq; q = &mbox->h2fq;
pi = readl(q->hw_prod); pi = readl(q->hw_prod);
ci = readl(q->hw_cons); ci = readl(q->hw_cons);
if (!octep_ctrl_mbox_circq_space(pi, ci, q->mask)) if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {
return -ENOMEM; mutex_unlock(&mbox->f2hq_lock);
return -EAGAIN;
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); octep_write_mbox_data(q, &pi, ci, (void *)&msg->hdr, mbox_hdr_sz);
buf_sz = msg->hdr.s.sz;
for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {
sg = &msg->sg_list[s];
w_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;
octep_write_mbox_data(q, &pi, ci, sg->msg, w_sz);
buf_sz -= w_sz;
}
writel(pi, q->hw_prod); writel(pi, q->hw_prod);
mutex_unlock(&mbox->h2fq_lock); mutex_unlock(&mbox->h2fq_lock);
/* don't check for notification response */
if (msg->hdr.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY)
return 0; return 0;
}
expire = jiffies + timeout; static void
while (true) { octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz)
*word0 = readq(qidx); {
if (msg->hdr.flags == OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP) u8 __iomem *qbuf;
break; u32 cp_sz;
schedule_timeout_interruptible(period);
if (signal_pending(current) || time_after(jiffies, expire)) { /* Assumption: Caller has ensured enough read space */
pr_info("octep_ctrl_mbox: Timed out\n"); qbuf = (q->hw_q + *ci);
return -EBUSY; if (*ci < pi) {
/* copy entire r_sz */
memcpy_fromio(buf, qbuf, r_sz);
*ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
} else {
/* copy up to end of queue */
cp_sz = min((q->sz - *ci), r_sz);
memcpy_fromio(buf, qbuf, cp_sz);
r_sz -= cp_sz;
*ci = octep_ctrl_mbox_circq_inc(*ci, cp_sz, q->sz);
if (r_sz) {
/* roll over and copy remaining r_sz */
buf += cp_sz;
qbuf = (q->hw_q + *ci);
memcpy_fromio(buf, qbuf, r_sz);
*ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
} }
} }
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) int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{ {
struct octep_ctrl_mbox_msg_buf *sg;
u32 pi, ci, r_sz, buf_sz, q_depth;
struct octep_ctrl_mbox_q *q; struct octep_ctrl_mbox_q *q;
u32 count, pi, ci; int s;
u8 __iomem *qidx;
u64 *mbuf;
int i;
if (!mbox || !msg) if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
return -EINVAL; return -EIO;
mutex_lock(&mbox->f2hq_lock);
q = &mbox->f2hq; q = &mbox->f2hq;
pi = readl(q->hw_prod); pi = readl(q->hw_prod);
ci = readl(q->hw_cons); 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); q_depth = octep_ctrl_mbox_circq_depth(pi, ci, q->sz);
if (q_depth < mbox_hdr_sz) {
msg->hdr.word0 = readq(qidx); mutex_unlock(&mbox->f2hq_lock);
for (i = 1; i <= msg->hdr.sizew; i++) return -EAGAIN;
*mbuf++ = readq(qidx + (i * 8)); }
ci = octep_ctrl_mbox_circq_inc(ci, q->mask); octep_read_mbox_data(q, pi, &ci, (void *)&msg->hdr, mbox_hdr_sz);
buf_sz = msg->hdr.s.sz;
for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {
sg = &msg->sg_list[s];
r_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;
octep_read_mbox_data(q, pi, &ci, sg->msg, r_sz);
buf_sz -= r_sz;
}
writel(ci, q->hw_cons); writel(ci, q->hw_cons);
mutex_unlock(&mbox->f2hq_lock); 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; return 0;
} }
...@@ -227,18 +252,17 @@ int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox) ...@@ -227,18 +252,17 @@ int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
{ {
if (!mbox) if (!mbox)
return -EINVAL; return -EINVAL;
if (!mbox->barmem)
return -EINVAL;
writeq(OCTEP_CTRL_MBOX_STATUS_UNINIT, writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
/* ensure uninit state is written before uninitialization */ /* ensure uninit state is written before uninitialization */
wmb(); wmb();
mutex_destroy(&mbox->h2fq_lock); mutex_destroy(&mbox->h2fq_lock);
mutex_destroy(&mbox->f2hq_lock); mutex_destroy(&mbox->f2hq_lock);
writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
pr_info("Octep ctrl mbox : Uninit successful.\n"); pr_info("Octep ctrl mbox : Uninit successful.\n");
return 0; return 0;
......
...@@ -27,50 +27,39 @@ ...@@ -27,50 +27,39 @@
* |-------------------------------------------| * |-------------------------------------------|
* |producer index (4 bytes) | * |producer index (4 bytes) |
* |consumer index (4 bytes) | * |consumer index (4 bytes) |
* |element size (4 bytes) | * |max element size (4 bytes) |
* |element count (4 bytes) | * |reserved (4 bytes) |
* |===========================================| * |===========================================|
* |Fw to Host Queue info (16 bytes) | * |Fw to Host Queue info (16 bytes) |
* |-------------------------------------------| * |-------------------------------------------|
* |producer index (4 bytes) | * |producer index (4 bytes) |
* |consumer index (4 bytes) | * |consumer index (4 bytes) |
* |element size (4 bytes) | * |max element size (4 bytes) |
* |element count (4 bytes) | * |reserved (4 bytes) |
* |===========================================| * |===========================================|
* |Host to Fw Queue | * |Host to Fw Queue ((total size-288/2) bytes)|
* |-------------------------------------------| * |-------------------------------------------|
* |((elem_sz + hdr(8 bytes)) * elem_cnt) bytes| * | |
* |===========================================| * |===========================================|
* |===========================================| * |===========================================|
* |Fw to Host Queue | * |Fw to Host Queue ((total size-288/2) bytes)|
* |-------------------------------------------| * |-------------------------------------------|
* |((elem_sz + hdr(8 bytes)) * elem_cnt) bytes| * | |
* |===========================================| * |===========================================|
*/ */
#define OCTEP_CTRL_MBOX_MAGIC_NUMBER 0xdeaddeadbeefbeefull #define OCTEP_CTRL_MBOX_MAGIC_NUMBER 0xdeaddeadbeefbeefull
/* Size of mbox info in bytes */
#define OCTEP_CTRL_MBOX_INFO_SZ 256
/* Size of mbox host to target queue info in bytes */
#define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ 16
/* Size of mbox target to host queue info in bytes */
#define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ 16
/* Size of mbox queue in bytes */
#define OCTEP_CTRL_MBOX_Q_SZ(sz, cnt) (((sz) + 8) * (cnt))
/* Size of mbox in bytes */
#define OCTEP_CTRL_MBOX_SZ(hsz, hcnt, fsz, fcnt) (OCTEP_CTRL_MBOX_INFO_SZ + \
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \
OCTEP_CTRL_MBOX_F2HQ_INFO_SZ + \
OCTEP_CTRL_MBOX_Q_SZ(hsz, hcnt) + \
OCTEP_CTRL_MBOX_Q_SZ(fsz, fcnt))
/* Valid request message */ /* Valid request message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ BIT(0) #define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ BIT(0)
/* Valid response message */ /* Valid response message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP BIT(1) #define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP BIT(1)
/* Valid notification, no response required */ /* Valid notification, no response required */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY BIT(2) #define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY BIT(2)
/* Valid custom message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_CUSTOM BIT(3)
#define OCTEP_CTRL_MBOX_MSG_DESC_MAX 4
enum octep_ctrl_mbox_status { enum octep_ctrl_mbox_status {
OCTEP_CTRL_MBOX_STATUS_INVALID = 0, OCTEP_CTRL_MBOX_STATUS_INVALID = 0,
...@@ -81,31 +70,48 @@ enum octep_ctrl_mbox_status { ...@@ -81,31 +70,48 @@ enum octep_ctrl_mbox_status {
/* mbox message */ /* mbox message */
union octep_ctrl_mbox_msg_hdr { union octep_ctrl_mbox_msg_hdr {
u64 word0; u64 words[2];
struct { struct {
/* must be 0 */
u16 reserved1:15;
/* vf_idx is valid if 1 */
u16 is_vf:1;
/* sender vf index 0-(n-1), 0 if (is_vf==0) */
u16 vf_idx;
/* total size of message excluding header */
u32 sz;
/* OCTEP_CTRL_MBOX_MSG_HDR_FLAG_* */ /* OCTEP_CTRL_MBOX_MSG_HDR_FLAG_* */
u32 flags; u32 flags;
/* size of message in words excluding header */ /* identifier to match responses */
u32 sizew; u16 msg_id;
}; u16 reserved2;
} s;
};
/* mbox message buffer */
struct octep_ctrl_mbox_msg_buf {
u32 reserved1;
u16 reserved2;
/* size of buffer */
u16 sz;
/* pointer to message buffer */
void *msg;
}; };
/* mbox message */ /* mbox message */
struct octep_ctrl_mbox_msg { struct octep_ctrl_mbox_msg {
/* mbox transaction header */ /* mbox transaction header */
union octep_ctrl_mbox_msg_hdr hdr; union octep_ctrl_mbox_msg_hdr hdr;
/* pointer to message buffer */ /* number of sg buffer's */
void *msg; int sg_num;
/* message buffer's */
struct octep_ctrl_mbox_msg_buf sg_list[OCTEP_CTRL_MBOX_MSG_DESC_MAX];
}; };
/* Mbox queue */ /* Mbox queue */
struct octep_ctrl_mbox_q { struct octep_ctrl_mbox_q {
/* q element size, should be aligned to unsigned long */ /* size of queue buffer */
u16 elem_sz; u32 sz;
/* q element count, should be power of 2 */
u16 elem_cnt;
/* q mask */
u16 mask;
/* producer address in bar mem */ /* producer address in bar mem */
u8 __iomem *hw_prod; u8 __iomem *hw_prod;
/* consumer address in bar mem */ /* consumer address in bar mem */
...@@ -115,16 +121,10 @@ struct octep_ctrl_mbox_q { ...@@ -115,16 +121,10 @@ struct octep_ctrl_mbox_q {
}; };
struct octep_ctrl_mbox { struct octep_ctrl_mbox {
/* host driver version */
u64 version;
/* size of bar memory */ /* size of bar memory */
u32 barmem_sz; u32 barmem_sz;
/* pointer to BAR memory */ /* pointer to BAR memory */
u8 __iomem *barmem; u8 __iomem *barmem;
/* user context for callback, can be null */
void *user_ctx;
/* callback handler for processing request, called from octep_ctrl_mbox_recv */
int (*process_req)(void *user_ctx, struct octep_ctrl_mbox_msg *msg);
/* host-to-fw queue */ /* host-to-fw queue */
struct octep_ctrl_mbox_q h2fq; struct octep_ctrl_mbox_q h2fq;
/* fw-to-host queue */ /* fw-to-host queue */
...@@ -146,6 +146,8 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox); ...@@ -146,6 +146,8 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox);
/* Send mbox message. /* Send mbox message.
* *
* @param mbox: non-null pointer to struct octep_ctrl_mbox. * @param mbox: non-null pointer to struct octep_ctrl_mbox.
* @param msg: non-null pointer to struct octep_ctrl_mbox_msg.
* Caller should fill msg.sz and msg.desc.sz for each message.
* *
* return value: 0 on success, -errno on failure. * return value: 0 on success, -errno on failure.
*/ */
...@@ -154,6 +156,8 @@ int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms ...@@ -154,6 +156,8 @@ int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms
/* Retrieve mbox message. /* Retrieve mbox message.
* *
* @param mbox: non-null pointer to struct octep_ctrl_mbox. * @param mbox: non-null pointer to struct octep_ctrl_mbox.
* @param msg: non-null pointer to struct octep_ctrl_mbox_msg.
* Caller should fill msg.sz and msg.desc.sz for each message.
* *
* return value: 0 on success, -errno on failure. * return value: 0 on success, -errno on failure.
*/ */
...@@ -161,7 +165,7 @@ int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms ...@@ -161,7 +165,7 @@ int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms
/* Uninitialize control mbox. /* Uninitialize control mbox.
* *
* @param ep: non-null pointer to struct octep_ctrl_mbox. * @param mbox: non-null pointer to struct octep_ctrl_mbox.
* *
* return value: 0 on success, -errno on failure. * return value: 0 on success, -errno on failure.
*/ */
......
...@@ -8,134 +8,194 @@ ...@@ -8,134 +8,194 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/wait.h>
#include "octep_config.h" #include "octep_config.h"
#include "octep_main.h" #include "octep_main.h"
#include "octep_ctrl_net.h" #include "octep_ctrl_net.h"
int octep_get_link_status(struct octep_device *oct) static const u32 req_hdr_sz = sizeof(union octep_ctrl_net_req_hdr);
static const u32 mtu_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mtu);
static const u32 mac_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mac);
static const u32 state_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_state);
static const u32 link_info_sz = sizeof(struct octep_ctrl_net_link_info);
static const u32 get_stats_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_get_stats);
static atomic_t ctrl_net_msg_id;
static void init_send_req(struct octep_ctrl_mbox_msg *msg, void *buf, u16 sz)
{ {
struct octep_ctrl_net_h2f_req req = {}; msg->hdr.s.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
struct octep_ctrl_net_h2f_resp *resp; msg->hdr.s.msg_id = atomic_inc_return(&ctrl_net_msg_id) &
struct octep_ctrl_mbox_msg msg = {}; GENMASK(sizeof(msg->hdr.s.msg_id) * BITS_PER_BYTE, 0);
int err; msg->hdr.s.sz = req_hdr_sz + sz;
msg->sg_num = 1;
msg->sg_list[0].msg = buf;
msg->sg_list[0].sz = msg->hdr.s.sz;
}
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS; static int octep_send_mbox_req(struct octep_device *oct,
req.link.cmd = OCTEP_CTRL_NET_CMD_GET; struct octep_ctrl_net_wait_data *d,
bool wait_for_response)
{
int err, ret;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ; err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &d->msg);
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_STATE_REQ_SZW; if (err < 0)
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err; return err;
resp = (struct octep_ctrl_net_h2f_resp *)&req; if (!wait_for_response)
return resp->link.state; return 0;
d->done = 0;
INIT_LIST_HEAD(&d->list);
list_add_tail(&d->list, &oct->ctrl_req_wait_list);
ret = wait_event_interruptible_timeout(oct->ctrl_req_wait_q,
(d->done != 0),
jiffies + msecs_to_jiffies(500));
list_del(&d->list);
if (ret == 0 || ret == 1)
return -EAGAIN;
/**
* (ret == 0) cond = false && timeout, return 0
* (ret < 0) interrupted by signal, return 0
* (ret == 1) cond = true && timeout, return 1
* (ret >= 1) cond = true && !timeout, return 1
*/
if (d->data.resp.hdr.s.reply != OCTEP_CTRL_NET_REPLY_OK)
return -EAGAIN;
return 0;
} }
void octep_set_link_status(struct octep_device *oct, bool up) int octep_ctrl_net_init(struct octep_device *oct)
{ {
struct octep_ctrl_net_h2f_req req = {}; struct octep_ctrl_mbox *ctrl_mbox;
struct octep_ctrl_mbox_msg msg = {}; struct pci_dev *pdev = oct->pdev;
int ret;
init_waitqueue_head(&oct->ctrl_req_wait_q);
INIT_LIST_HEAD(&oct->ctrl_req_wait_list);
/* Initialize control mbox */
ctrl_mbox = &oct->ctrl_mbox;
ctrl_mbox->barmem = CFG_GET_CTRL_MBOX_MEM_ADDR(oct->conf);
ret = octep_ctrl_mbox_init(ctrl_mbox);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize control mbox\n");
return ret;
}
oct->ctrl_mbox_ifstats_offset = ctrl_mbox->barmem_sz;
return 0;
}
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS; int octep_ctrl_net_get_link_status(struct octep_device *oct)
req.link.cmd = OCTEP_CTRL_NET_CMD_SET; {
req.link.state = (up) ? OCTEP_CTRL_NET_STATE_UP : OCTEP_CTRL_NET_STATE_DOWN; struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
int err;
init_send_req(&d.msg, (void *)req, state_sz);
req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS;
req->link.cmd = OCTEP_CTRL_NET_CMD_GET;
err = octep_send_mbox_req(oct, &d, true);
if (err < 0)
return err;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ; return d.data.resp.link.state;
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) int octep_ctrl_net_set_link_status(struct octep_device *oct, bool up,
bool wait_for_response)
{ {
struct octep_ctrl_net_h2f_req req = {}; struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_mbox_msg msg = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_RX_STATE; init_send_req(&d.msg, req, state_sz);
req.link.cmd = OCTEP_CTRL_NET_CMD_SET; req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS;
req.link.state = (up) ? OCTEP_CTRL_NET_STATE_UP : OCTEP_CTRL_NET_STATE_DOWN; 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; return octep_send_mbox_req(oct, &d, wait_for_response);
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) int octep_ctrl_net_set_rx_state(struct octep_device *oct, bool up,
bool wait_for_response)
{ {
struct octep_ctrl_net_h2f_req req = {}; struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_net_h2f_resp *resp; struct octep_ctrl_net_h2f_req *req = &d.data.req;
struct octep_ctrl_mbox_msg msg = {};
int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC; init_send_req(&d.msg, req, state_sz);
req.link.cmd = OCTEP_CTRL_NET_CMD_GET; req->hdr.s.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; return octep_send_mbox_req(oct, &d, wait_for_response);
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; int octep_ctrl_net_get_mac_addr(struct octep_device *oct, u8 *addr)
memcpy(addr, resp->mac.addr, ETH_ALEN); {
struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
int err;
init_send_req(&d.msg, req, mac_sz);
req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
req->link.cmd = OCTEP_CTRL_NET_CMD_GET;
err = octep_send_mbox_req(oct, &d, true);
if (err < 0)
return err; return err;
memcpy(addr, d.data.resp.mac.addr, ETH_ALEN);
return 0;
} }
int octep_set_mac_addr(struct octep_device *oct, u8 *addr) int octep_ctrl_net_set_mac_addr(struct octep_device *oct, u8 *addr,
bool wait_for_response)
{ {
struct octep_ctrl_net_h2f_req req = {}; struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_mbox_msg msg = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
req.mac.cmd = OCTEP_CTRL_NET_CMD_SET;
memcpy(&req.mac.addr, addr, ETH_ALEN);
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ; init_send_req(&d.msg, req, mac_sz);
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MAC_REQ_SZW; req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
msg.msg = &req; req->mac.cmd = OCTEP_CTRL_NET_CMD_SET;
memcpy(&req->mac.addr, addr, ETH_ALEN);
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg); return octep_send_mbox_req(oct, &d, wait_for_response);
} }
int octep_set_mtu(struct octep_device *oct, int mtu) int octep_ctrl_net_set_mtu(struct octep_device *oct, int mtu,
bool wait_for_response)
{ {
struct octep_ctrl_net_h2f_req req = {}; struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_mbox_msg msg = {}; struct octep_ctrl_net_h2f_req *req = &d.data.req;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU; init_send_req(&d.msg, req, mtu_sz);
req.mtu.cmd = OCTEP_CTRL_NET_CMD_SET; req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU;
req.mtu.val = mtu; req->mtu.cmd = OCTEP_CTRL_NET_CMD_SET;
req->mtu.val = mtu;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ; return octep_send_mbox_req(oct, &d, wait_for_response);
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MTU_REQ_SZW;
msg.msg = &req;
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
} }
int octep_get_if_stats(struct octep_device *oct) int octep_ctrl_net_get_if_stats(struct octep_device *oct)
{ {
struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
void __iomem *iface_rx_stats; void __iomem *iface_rx_stats;
void __iomem *iface_tx_stats; void __iomem *iface_tx_stats;
struct octep_ctrl_net_h2f_req req = {};
struct octep_ctrl_mbox_msg msg = {};
int err; int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_IF_STATS; init_send_req(&d.msg, req, get_stats_sz);
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET; req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_IF_STATS;
req.get_stats.offset = oct->ctrl_mbox_ifstats_offset; req->get_stats.offset = oct->ctrl_mbox_ifstats_offset;
err = octep_send_mbox_req(oct, &d, true);
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ; if (err < 0)
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_GET_STATS_REQ_SZW;
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err; return err;
iface_rx_stats = oct->ctrl_mbox.barmem + oct->ctrl_mbox_ifstats_offset; iface_rx_stats = oct->ctrl_mbox.barmem + oct->ctrl_mbox_ifstats_offset;
...@@ -144,51 +204,101 @@ int octep_get_if_stats(struct octep_device *oct) ...@@ -144,51 +204,101 @@ int octep_get_if_stats(struct octep_device *oct)
memcpy_fromio(&oct->iface_rx_stats, iface_rx_stats, sizeof(struct octep_iface_rx_stats)); memcpy_fromio(&oct->iface_rx_stats, iface_rx_stats, sizeof(struct octep_iface_rx_stats));
memcpy_fromio(&oct->iface_tx_stats, iface_tx_stats, sizeof(struct octep_iface_tx_stats)); memcpy_fromio(&oct->iface_tx_stats, iface_tx_stats, sizeof(struct octep_iface_tx_stats));
return err; return 0;
} }
int octep_get_link_info(struct octep_device *oct) int octep_ctrl_net_get_link_info(struct octep_device *oct)
{ {
struct octep_ctrl_net_h2f_req req = {}; struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
struct octep_ctrl_net_h2f_resp *resp; struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_mbox_msg msg = {};
int err; int err;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO; init_send_req(&d.msg, req, link_info_sz);
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET; req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
req->link_info.cmd = OCTEP_CTRL_NET_CMD_GET;
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ; err = octep_send_mbox_req(oct, &d, true);
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW; if (err < 0)
msg.msg = &req;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
if (err)
return err; return err;
resp = (struct octep_ctrl_net_h2f_resp *)&req; resp = &d.data.resp;
oct->link_info.supported_modes = resp->link_info.supported_modes; oct->link_info.supported_modes = resp->link_info.supported_modes;
oct->link_info.advertised_modes = resp->link_info.advertised_modes; oct->link_info.advertised_modes = resp->link_info.advertised_modes;
oct->link_info.autoneg = resp->link_info.autoneg; oct->link_info.autoneg = resp->link_info.autoneg;
oct->link_info.pause = resp->link_info.pause; oct->link_info.pause = resp->link_info.pause;
oct->link_info.speed = resp->link_info.speed; oct->link_info.speed = resp->link_info.speed;
return err; return 0;
}
int octep_ctrl_net_set_link_info(struct octep_device *oct,
struct octep_iface_link_info *link_info,
bool wait_for_response)
{
struct octep_ctrl_net_wait_data d = {0};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
init_send_req(&d.msg, req, link_info_sz);
req->hdr.s.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;
return octep_send_mbox_req(oct, &d, wait_for_response);
}
static void process_mbox_resp(struct octep_device *oct,
struct octep_ctrl_mbox_msg *msg)
{
struct octep_ctrl_net_wait_data *pos, *n;
list_for_each_entry_safe(pos, n, &oct->ctrl_req_wait_list, list) {
if (pos->msg.hdr.s.msg_id == msg->hdr.s.msg_id) {
memcpy(&pos->data.resp,
msg->sg_list[0].msg,
msg->hdr.s.sz);
pos->done = 1;
wake_up_interruptible_all(&oct->ctrl_req_wait_q);
break;
}
}
} }
int octep_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info) void octep_ctrl_net_recv_fw_messages(struct octep_device *oct)
{ {
struct octep_ctrl_net_h2f_req req = {}; static u16 msg_sz = sizeof(union octep_ctrl_net_max_data);
struct octep_ctrl_mbox_msg msg = {}; union octep_ctrl_net_max_data data = {0};
struct octep_ctrl_mbox_msg msg = {0};
int ret;
msg.hdr.s.sz = msg_sz;
msg.sg_num = 1;
msg.sg_list[0].sz = msg_sz;
msg.sg_list[0].msg = &data;
while (true) {
/* mbox will overwrite msg.hdr.s.sz so initialize it */
msg.hdr.s.sz = msg_sz;
ret = octep_ctrl_mbox_recv(&oct->ctrl_mbox, (struct octep_ctrl_mbox_msg *)&msg);
if (ret < 0)
break;
if (msg.hdr.s.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP)
process_mbox_resp(oct, &msg);
}
}
int octep_ctrl_net_uninit(struct octep_device *oct)
{
struct octep_ctrl_net_wait_data *pos, *n;
list_for_each_entry_safe(pos, n, &oct->ctrl_req_wait_list, list)
pos->done = 1;
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO; wake_up_interruptible_all(&oct->ctrl_req_wait_q);
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; octep_ctrl_mbox_uninit(&oct->ctrl_mbox);
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW;
msg.msg = &req;
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg); return 0;
} }
...@@ -45,7 +45,9 @@ enum octep_ctrl_net_f2h_cmd { ...@@ -45,7 +45,9 @@ enum octep_ctrl_net_f2h_cmd {
OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS, OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS,
}; };
struct octep_ctrl_net_req_hdr { union octep_ctrl_net_req_hdr {
u64 words[1];
struct {
/* sender id */ /* sender id */
u16 sender; u16 sender;
/* receiver id */ /* receiver id */
...@@ -54,6 +56,7 @@ struct octep_ctrl_net_req_hdr { ...@@ -54,6 +56,7 @@ struct octep_ctrl_net_req_hdr {
u16 cmd; u16 cmd;
/* reserved */ /* reserved */
u16 rsvd0; u16 rsvd0;
} s;
}; };
/* get/set mtu request */ /* get/set mtu request */
...@@ -110,7 +113,7 @@ struct octep_ctrl_net_h2f_req_cmd_link_info { ...@@ -110,7 +113,7 @@ struct octep_ctrl_net_h2f_req_cmd_link_info {
/* Host to fw request data */ /* Host to fw request data */
struct octep_ctrl_net_h2f_req { struct octep_ctrl_net_h2f_req {
struct octep_ctrl_net_req_hdr hdr; union octep_ctrl_net_req_hdr hdr;
union { union {
struct octep_ctrl_net_h2f_req_cmd_mtu mtu; struct octep_ctrl_net_h2f_req_cmd_mtu mtu;
struct octep_ctrl_net_h2f_req_cmd_mac mac; struct octep_ctrl_net_h2f_req_cmd_mac mac;
...@@ -121,7 +124,9 @@ struct octep_ctrl_net_h2f_req { ...@@ -121,7 +124,9 @@ struct octep_ctrl_net_h2f_req {
}; };
} __packed; } __packed;
struct octep_ctrl_net_resp_hdr { union octep_ctrl_net_resp_hdr {
u64 words[1];
struct {
/* sender id */ /* sender id */
u16 sender; u16 sender;
/* receiver id */ /* receiver id */
...@@ -130,6 +135,7 @@ struct octep_ctrl_net_resp_hdr { ...@@ -130,6 +135,7 @@ struct octep_ctrl_net_resp_hdr {
u16 cmd; u16 cmd;
/* octep_ctrl_net_reply */ /* octep_ctrl_net_reply */
u16 reply; u16 reply;
} s;
}; };
/* get mtu response */ /* get mtu response */
...@@ -152,7 +158,7 @@ struct octep_ctrl_net_h2f_resp_cmd_state { ...@@ -152,7 +158,7 @@ struct octep_ctrl_net_h2f_resp_cmd_state {
/* Host to fw response data */ /* Host to fw response data */
struct octep_ctrl_net_h2f_resp { struct octep_ctrl_net_h2f_resp {
struct octep_ctrl_net_resp_hdr hdr; union octep_ctrl_net_resp_hdr hdr;
union { union {
struct octep_ctrl_net_h2f_resp_cmd_mtu mtu; struct octep_ctrl_net_h2f_resp_cmd_mtu mtu;
struct octep_ctrl_net_h2f_resp_cmd_mac mac; struct octep_ctrl_net_h2f_resp_cmd_mac mac;
...@@ -170,7 +176,7 @@ struct octep_ctrl_net_f2h_req_cmd_state { ...@@ -170,7 +176,7 @@ struct octep_ctrl_net_f2h_req_cmd_state {
/* Fw to host request data */ /* Fw to host request data */
struct octep_ctrl_net_f2h_req { struct octep_ctrl_net_f2h_req {
struct octep_ctrl_net_req_hdr hdr; union octep_ctrl_net_req_hdr hdr;
union { union {
struct octep_ctrl_net_f2h_req_cmd_state link; struct octep_ctrl_net_f2h_req_cmd_state link;
}; };
...@@ -178,56 +184,34 @@ struct octep_ctrl_net_f2h_req { ...@@ -178,56 +184,34 @@ struct octep_ctrl_net_f2h_req {
/* Fw to host response data */ /* Fw to host response data */
struct octep_ctrl_net_f2h_resp { struct octep_ctrl_net_f2h_resp {
struct octep_ctrl_net_resp_hdr hdr; union octep_ctrl_net_resp_hdr hdr;
}; };
/* Size of host to fw octep_ctrl_mbox queue element */ /* Max data size to be transferred over mbox */
union octep_ctrl_net_h2f_data_sz { union octep_ctrl_net_max_data {
struct octep_ctrl_net_h2f_req h2f_req; struct octep_ctrl_net_h2f_req h2f_req;
struct octep_ctrl_net_h2f_resp h2f_resp; struct octep_ctrl_net_h2f_resp h2f_resp;
};
/* Size of fw to host octep_ctrl_mbox queue element */
union octep_ctrl_net_f2h_data_sz {
struct octep_ctrl_net_f2h_req f2h_req; struct octep_ctrl_net_f2h_req f2h_req;
struct octep_ctrl_net_f2h_resp f2h_resp; struct octep_ctrl_net_f2h_resp f2h_resp;
}; };
/* size of host to fw data in words */ struct octep_ctrl_net_wait_data {
#define OCTEP_CTRL_NET_H2F_DATA_SZW ((sizeof(union octep_ctrl_net_h2f_data_sz)) / \ struct list_head list;
(sizeof(unsigned long))) int done;
struct octep_ctrl_mbox_msg msg;
/* size of fw to host data in words */ union {
#define OCTEP_CTRL_NET_F2H_DATA_SZW ((sizeof(union octep_ctrl_net_f2h_data_sz)) / \ struct octep_ctrl_net_h2f_req req;
(sizeof(unsigned long))) struct octep_ctrl_net_h2f_resp resp;
} data;
/* size in words of get/set mtu request */ };
#define OCTEP_CTRL_NET_H2F_MTU_REQ_SZW 2
/* size in words of get/set mac request */ /** Initialize data for ctrl net.
#define OCTEP_CTRL_NET_H2F_MAC_REQ_SZW 2 *
/* size in words of get stats request */ * @param oct: non-null pointer to struct octep_device.
#define OCTEP_CTRL_NET_H2F_GET_STATS_REQ_SZW 2 *
/* size in words of get/set state request */ * return value: 0 on success, -errno on error.
#define OCTEP_CTRL_NET_H2F_STATE_REQ_SZW 2 */
/* size in words of get/set link info request */ int octep_ctrl_net_init(struct octep_device *oct);
#define OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW 4
/* size in words of get mtu response */
#define OCTEP_CTRL_NET_H2F_GET_MTU_RESP_SZW 2
/* size in words of set mtu response */
#define OCTEP_CTRL_NET_H2F_SET_MTU_RESP_SZW 1
/* size in words of get mac response */
#define OCTEP_CTRL_NET_H2F_GET_MAC_RESP_SZW 2
/* size in words of set mac response */
#define OCTEP_CTRL_NET_H2F_SET_MAC_RESP_SZW 1
/* size in words of get state request */
#define OCTEP_CTRL_NET_H2F_GET_STATE_RESP_SZW 2
/* size in words of set state request */
#define OCTEP_CTRL_NET_H2F_SET_STATE_RESP_SZW 1
/* size in words of get link info request */
#define OCTEP_CTRL_NET_H2F_GET_LINK_INFO_RESP_SZW 4
/* size in words of set link info request */
#define OCTEP_CTRL_NET_H2F_SET_LINK_INFO_RESP_SZW 1
/** Get link status from firmware. /** Get link status from firmware.
* *
...@@ -235,21 +219,29 @@ union octep_ctrl_net_f2h_data_sz { ...@@ -235,21 +219,29 @@ union octep_ctrl_net_f2h_data_sz {
* *
* return value: link status 0=down, 1=up. * return value: link status 0=down, 1=up.
*/ */
int octep_get_link_status(struct octep_device *oct); int octep_ctrl_net_get_link_status(struct octep_device *oct);
/** Set link status in firmware. /** Set link status in firmware.
* *
* @param oct: non-null pointer to struct octep_device. * @param oct: non-null pointer to struct octep_device.
* @param up: boolean status. * @param up: boolean status.
* @param wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure
*/ */
void octep_set_link_status(struct octep_device *oct, bool up); int octep_ctrl_net_set_link_status(struct octep_device *oct, bool up,
bool wait_for_response);
/** Set rx state in firmware. /** Set rx state in firmware.
* *
* @param oct: non-null pointer to struct octep_device. * @param oct: non-null pointer to struct octep_device.
* @param up: boolean status. * @param up: boolean status.
* @param wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/ */
void octep_set_rx_state(struct octep_device *oct, bool up); int octep_ctrl_net_set_rx_state(struct octep_device *oct, bool up,
bool wait_for_response);
/** Get mac address from firmware. /** Get mac address from firmware.
* *
...@@ -258,21 +250,29 @@ void octep_set_rx_state(struct octep_device *oct, bool up); ...@@ -258,21 +250,29 @@ void octep_set_rx_state(struct octep_device *oct, bool up);
* *
* return value: 0 on success, -errno on failure. * return value: 0 on success, -errno on failure.
*/ */
int octep_get_mac_addr(struct octep_device *oct, u8 *addr); int octep_ctrl_net_get_mac_addr(struct octep_device *oct, u8 *addr);
/** Set mac address in firmware. /** Set mac address in firmware.
* *
* @param oct: non-null pointer to struct octep_device. * @param oct: non-null pointer to struct octep_device.
* @param addr: non-null pointer to mac address. * @param addr: non-null pointer to mac address.
* @param wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/ */
int octep_set_mac_addr(struct octep_device *oct, u8 *addr); int octep_ctrl_net_set_mac_addr(struct octep_device *oct, u8 *addr,
bool wait_for_response);
/** Set mtu in firmware. /** Set mtu in firmware.
* *
* @param oct: non-null pointer to struct octep_device. * @param oct: non-null pointer to struct octep_device.
* @param mtu: mtu. * @param mtu: mtu.
* @param wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/ */
int octep_set_mtu(struct octep_device *oct, int mtu); int octep_ctrl_net_set_mtu(struct octep_device *oct, int mtu,
bool wait_for_response);
/** Get interface statistics from firmware. /** Get interface statistics from firmware.
* *
...@@ -280,7 +280,7 @@ int octep_set_mtu(struct octep_device *oct, int mtu); ...@@ -280,7 +280,7 @@ int octep_set_mtu(struct octep_device *oct, int mtu);
* *
* return value: 0 on success, -errno on failure. * return value: 0 on success, -errno on failure.
*/ */
int octep_get_if_stats(struct octep_device *oct); int octep_ctrl_net_get_if_stats(struct octep_device *oct);
/** Get link info from firmware. /** Get link info from firmware.
* *
...@@ -288,12 +288,32 @@ int octep_get_if_stats(struct octep_device *oct); ...@@ -288,12 +288,32 @@ int octep_get_if_stats(struct octep_device *oct);
* *
* return value: 0 on success, -errno on failure. * return value: 0 on success, -errno on failure.
*/ */
int octep_get_link_info(struct octep_device *oct); int octep_ctrl_net_get_link_info(struct octep_device *oct);
/** Set link info in firmware. /** Set link info in firmware.
* *
* @param oct: non-null pointer to struct octep_device. * @param oct: non-null pointer to struct octep_device.
* @param link_info: non-null pointer to struct octep_iface_link_info.
* @param wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_set_link_info(struct octep_device *oct,
struct octep_iface_link_info *link_info,
bool wait_for_response);
/** Poll for firmware messages and process them.
*
* @param oct: non-null pointer to struct octep_device.
*/
void octep_ctrl_net_recv_fw_messages(struct octep_device *oct);
/** Uninitialize data for ctrl net.
*
* @param oct: non-null pointer to struct octep_device.
*
* return value: 0 on success, -errno on error.
*/ */
int octep_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info); int octep_ctrl_net_uninit(struct octep_device *oct);
#endif /* __OCTEP_CTRL_NET_H__ */ #endif /* __OCTEP_CTRL_NET_H__ */
...@@ -150,7 +150,7 @@ octep_get_ethtool_stats(struct net_device *netdev, ...@@ -150,7 +150,7 @@ octep_get_ethtool_stats(struct net_device *netdev,
rx_packets = 0; rx_packets = 0;
rx_bytes = 0; rx_bytes = 0;
octep_get_if_stats(oct); octep_ctrl_net_get_if_stats(oct);
iface_tx_stats = &oct->iface_tx_stats; iface_tx_stats = &oct->iface_tx_stats;
iface_rx_stats = &oct->iface_rx_stats; iface_rx_stats = &oct->iface_rx_stats;
...@@ -283,7 +283,7 @@ static int octep_get_link_ksettings(struct net_device *netdev, ...@@ -283,7 +283,7 @@ static int octep_get_link_ksettings(struct net_device *netdev,
ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, supported);
ethtool_link_ksettings_zero_link_mode(cmd, advertising); ethtool_link_ksettings_zero_link_mode(cmd, advertising);
octep_get_link_info(oct); octep_ctrl_net_get_link_info(oct);
advertised_modes = oct->link_info.advertised_modes; advertised_modes = oct->link_info.advertised_modes;
supported_modes = oct->link_info.supported_modes; supported_modes = oct->link_info.supported_modes;
...@@ -439,7 +439,7 @@ static int octep_set_link_ksettings(struct net_device *netdev, ...@@ -439,7 +439,7 @@ static int octep_set_link_ksettings(struct net_device *netdev,
link_info_new.speed = cmd->base.speed; link_info_new.speed = cmd->base.speed;
link_info_new.autoneg = autoneg; link_info_new.autoneg = autoneg;
err = octep_set_link_info(oct, &link_info_new); err = octep_ctrl_net_set_link_info(oct, &link_info_new, true);
if (err) if (err)
return err; return err;
......
...@@ -507,11 +507,8 @@ static int octep_open(struct net_device *netdev) ...@@ -507,11 +507,8 @@ static int octep_open(struct net_device *netdev)
octep_napi_enable(oct); octep_napi_enable(oct);
oct->link_info.admin_up = 1; oct->link_info.admin_up = 1;
octep_set_rx_state(oct, true); octep_ctrl_net_set_rx_state(oct, true, false);
octep_ctrl_net_set_link_status(oct, true, false);
ret = octep_get_link_status(oct);
if (!ret)
octep_set_link_status(oct, true);
oct->poll_non_ioq_intr = false; oct->poll_non_ioq_intr = false;
/* Enable the input and output queues for this Octeon device */ /* Enable the input and output queues for this Octeon device */
...@@ -522,7 +519,7 @@ static int octep_open(struct net_device *netdev) ...@@ -522,7 +519,7 @@ static int octep_open(struct net_device *netdev)
octep_oq_dbell_init(oct); octep_oq_dbell_init(oct);
ret = octep_get_link_status(oct); ret = octep_ctrl_net_get_link_status(oct);
if (ret > 0) if (ret > 0)
octep_link_up(netdev); octep_link_up(netdev);
...@@ -552,14 +549,14 @@ static int octep_stop(struct net_device *netdev) ...@@ -552,14 +549,14 @@ static int octep_stop(struct net_device *netdev)
netdev_info(netdev, "Stopping the device ...\n"); netdev_info(netdev, "Stopping the device ...\n");
octep_ctrl_net_set_link_status(oct, false, false);
octep_ctrl_net_set_rx_state(oct, false, false);
/* Stop Tx from stack */ /* Stop Tx from stack */
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev); netif_carrier_off(netdev);
netif_tx_disable(netdev); netif_tx_disable(netdev);
octep_set_link_status(oct, false);
octep_set_rx_state(oct, false);
oct->link_info.admin_up = 0; oct->link_info.admin_up = 0;
oct->link_info.oper_up = 0; oct->link_info.oper_up = 0;
...@@ -761,7 +758,9 @@ static void octep_get_stats64(struct net_device *netdev, ...@@ -761,7 +758,9 @@ static void octep_get_stats64(struct net_device *netdev,
struct octep_device *oct = netdev_priv(netdev); struct octep_device *oct = netdev_priv(netdev);
int q; int q;
octep_get_if_stats(oct); if (netif_running(netdev))
octep_ctrl_net_get_if_stats(oct);
tx_packets = 0; tx_packets = 0;
tx_bytes = 0; tx_bytes = 0;
rx_packets = 0; rx_packets = 0;
...@@ -832,7 +831,7 @@ static int octep_set_mac(struct net_device *netdev, void *p) ...@@ -832,7 +831,7 @@ static int octep_set_mac(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data)) if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
err = octep_set_mac_addr(oct, addr->sa_data); err = octep_ctrl_net_set_mac_addr(oct, addr->sa_data, true);
if (err) if (err)
return err; return err;
...@@ -852,7 +851,7 @@ static int octep_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -852,7 +851,7 @@ static int octep_change_mtu(struct net_device *netdev, int new_mtu)
if (link_info->mtu == new_mtu) if (link_info->mtu == new_mtu)
return 0; return 0;
err = octep_set_mtu(oct, new_mtu); err = octep_ctrl_net_set_mtu(oct, new_mtu, true);
if (!err) { if (!err) {
oct->link_info.mtu = new_mtu; oct->link_info.mtu = new_mtu;
netdev->mtu = new_mtu; netdev->mtu = new_mtu;
...@@ -904,34 +903,8 @@ static void octep_ctrl_mbox_task(struct work_struct *work) ...@@ -904,34 +903,8 @@ static void octep_ctrl_mbox_task(struct work_struct *work)
{ {
struct octep_device *oct = container_of(work, struct octep_device, struct octep_device *oct = container_of(work, struct octep_device,
ctrl_mbox_task); ctrl_mbox_task);
struct net_device *netdev = oct->netdev;
struct octep_ctrl_net_f2h_req req = {};
struct octep_ctrl_mbox_msg msg;
int ret = 0;
msg.msg = &req;
while (true) {
ret = octep_ctrl_mbox_recv(&oct->ctrl_mbox, &msg);
if (ret)
break;
switch (req.hdr.cmd) { octep_ctrl_net_recv_fw_messages(oct);
case OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS:
if (netif_running(netdev)) {
if (req.link.state) {
dev_info(&oct->pdev->dev, "netif_carrier_on\n");
netif_carrier_on(netdev);
} else {
dev_info(&oct->pdev->dev, "netif_carrier_off\n");
netif_carrier_off(netdev);
}
}
break;
default:
pr_info("Unknown mbox req : %u\n", req.hdr.cmd);
break;
}
}
} }
static const char *octep_devid_to_str(struct octep_device *oct) static const char *octep_devid_to_str(struct octep_device *oct)
...@@ -955,9 +928,8 @@ static const char *octep_devid_to_str(struct octep_device *oct) ...@@ -955,9 +928,8 @@ static const char *octep_devid_to_str(struct octep_device *oct)
*/ */
int octep_device_setup(struct octep_device *oct) int octep_device_setup(struct octep_device *oct)
{ {
struct octep_ctrl_mbox *ctrl_mbox;
struct pci_dev *pdev = oct->pdev; struct pci_dev *pdev = oct->pdev;
int i, ret; int i;
/* allocate memory for oct->conf */ /* allocate memory for oct->conf */
oct->conf = kzalloc(sizeof(*oct->conf), GFP_KERNEL); oct->conf = kzalloc(sizeof(*oct->conf), GFP_KERNEL);
...@@ -992,20 +964,7 @@ int octep_device_setup(struct octep_device *oct) ...@@ -992,20 +964,7 @@ int octep_device_setup(struct octep_device *oct)
oct->pkind = CFG_GET_IQ_PKIND(oct->conf); oct->pkind = CFG_GET_IQ_PKIND(oct->conf);
/* Initialize control mbox */ return octep_ctrl_net_init(oct);
ctrl_mbox = &oct->ctrl_mbox;
ctrl_mbox->barmem = CFG_GET_CTRL_MBOX_MEM_ADDR(oct->conf);
ret = octep_ctrl_mbox_init(ctrl_mbox);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize control mbox\n");
goto unsupported_dev;
}
oct->ctrl_mbox_ifstats_offset = OCTEP_CTRL_MBOX_SZ(ctrl_mbox->h2fq.elem_sz,
ctrl_mbox->h2fq.elem_cnt,
ctrl_mbox->f2hq.elem_sz,
ctrl_mbox->f2hq.elem_cnt);
return 0;
unsupported_dev: unsupported_dev:
for (i = 0; i < OCTEP_MMIO_REGIONS; i++) for (i = 0; i < OCTEP_MMIO_REGIONS; i++)
...@@ -1033,7 +992,7 @@ static void octep_device_cleanup(struct octep_device *oct) ...@@ -1033,7 +992,7 @@ static void octep_device_cleanup(struct octep_device *oct)
oct->mbox[i] = NULL; oct->mbox[i] = NULL;
} }
octep_ctrl_mbox_uninit(&oct->ctrl_mbox); octep_ctrl_net_uninit(oct);
oct->hw_ops.soft_reset(oct); oct->hw_ops.soft_reset(oct);
for (i = 0; i < OCTEP_MMIO_REGIONS; i++) { for (i = 0; i < OCTEP_MMIO_REGIONS; i++) {
...@@ -1143,7 +1102,8 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1143,7 +1102,8 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->max_mtu = OCTEP_MAX_MTU; netdev->max_mtu = OCTEP_MAX_MTU;
netdev->mtu = OCTEP_DEFAULT_MTU; netdev->mtu = OCTEP_DEFAULT_MTU;
err = octep_get_mac_addr(octep_dev, octep_dev->mac_addr); err = octep_ctrl_net_get_mac_addr(octep_dev,
octep_dev->mac_addr);
if (err) { if (err) {
dev_err(&pdev->dev, "Failed to get mac address\n"); dev_err(&pdev->dev, "Failed to get mac address\n");
goto register_dev_err; goto register_dev_err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment