mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-30 10:26:56 -05:00
Merge branch 'octeon_ep-deferred-probe-and-mailbox'
Veerasenareddy Burru says:
====================
octeon_ep: deferred probe and mailbox
Implement Deferred probe, mailbox enhancements and heartbeat monitor.
v4 -> v5:
- addressed review comments
https://lore.kernel.org/all/20230323104703.GD36557@unreal/
replaced atomic_inc() + atomic_read() with atomic_inc_return().
v3 -> v4:
- addressed review comments on v3
https://lore.kernel.org/all/20230214051422.13705-1-vburru@marvell.com/
- 0004-xxx.patch v3 is split into 0004-xxx.patch and 0005-xxx.patch
in v4.
- API changes to accept function ID are moved to 0005-xxx.patch.
- fixed rct violations.
- reverted newly added changes that do not yet have use cases.
v2 -> v3:
- removed SRIOV VF support changes from v2, as new drivers which use
ndo_get_vf_xxx() and ndo_set_vf_xxx() are not accepted.
https://lore.kernel.org/all/20221207200204.6819575a@kernel.org/
Will implement VF representors and submit again.
- 0007-xxx.patch and 0008-xxx.patch from v2 are removed and
0009-xxx.patch in v2 is now 0007-xxx.patch in v3.
- accordingly, changed title for cover letter.
v1 -> v2:
- remove separate workqueue task to wait for firmware ready.
instead defer probe when firmware is not ready.
Reported-by: Leon Romanovsky <leon@kernel.org>
- This change has resulted in update of 0001-xxx.patch and
all other patches in the patchset.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -13,6 +13,12 @@
|
||||
#include "octep_main.h"
|
||||
#include "octep_regs_cn9k_pf.h"
|
||||
|
||||
#define CTRL_MBOX_MAX_PF 128
|
||||
#define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF))
|
||||
|
||||
#define FW_HB_INTERVAL_IN_SECS 1
|
||||
#define FW_HB_MISS_COUNT 10
|
||||
|
||||
/* Names of Hardware non-queue generic interrupts */
|
||||
static char *cn93_non_ioq_msix_names[] = {
|
||||
"epf_ire_rint",
|
||||
@@ -198,7 +204,9 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
|
||||
{
|
||||
struct octep_config *conf = oct->conf;
|
||||
struct pci_dev *pdev = oct->pdev;
|
||||
u8 link = 0;
|
||||
u64 val;
|
||||
int pos;
|
||||
|
||||
/* Read ring configuration:
|
||||
* PF ring count, number of VFs and rings per VF supported
|
||||
@@ -234,7 +242,20 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
|
||||
conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings;
|
||||
conf->msix_cfg.non_ioq_msix_names = cn93_non_ioq_msix_names;
|
||||
|
||||
conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr + (0x400000ull * 7);
|
||||
pos = pci_find_ext_capability(oct->pdev, PCI_EXT_CAP_ID_SRIOV);
|
||||
if (pos) {
|
||||
pci_read_config_byte(oct->pdev,
|
||||
pos + PCI_SRIOV_FUNC_LINK,
|
||||
&link);
|
||||
link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link);
|
||||
}
|
||||
conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr +
|
||||
(0x400000ull * 7) +
|
||||
(link * CTRL_MBOX_SZ);
|
||||
|
||||
conf->hb_interval = FW_HB_INTERVAL_IN_SECS;
|
||||
conf->max_hb_miss_cnt = FW_HB_MISS_COUNT;
|
||||
|
||||
}
|
||||
|
||||
/* Setup registers for a hardware Tx Queue */
|
||||
@@ -352,19 +373,30 @@ static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no)
|
||||
mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
|
||||
}
|
||||
|
||||
/* Mailbox Interrupt handler */
|
||||
static void cn93_handle_pf_mbox_intr(struct octep_device *oct)
|
||||
/* Process non-ioq interrupts required to keep pf interface running.
|
||||
* OEI_RINT is needed for control mailbox
|
||||
*/
|
||||
static bool octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
|
||||
{
|
||||
u64 mbox_int_val = 0ULL, val = 0ULL, qno = 0ULL;
|
||||
bool handled = false;
|
||||
u64 reg0;
|
||||
|
||||
mbox_int_val = readq(oct->mbox[0]->mbox_int_reg);
|
||||
for (qno = 0; qno < OCTEP_MAX_VF; qno++) {
|
||||
val = readq(oct->mbox[qno]->mbox_read_reg);
|
||||
dev_dbg(&oct->pdev->dev,
|
||||
"PF MBOX READ: val:%llx from VF:%llx\n", val, qno);
|
||||
/* Check for OEI INTR */
|
||||
reg0 = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
|
||||
if (reg0) {
|
||||
dev_info(&oct->pdev->dev,
|
||||
"Received OEI_RINT intr: 0x%llx\n",
|
||||
reg0);
|
||||
octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg0);
|
||||
if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX)
|
||||
queue_work(octep_wq, &oct->ctrl_mbox_task);
|
||||
else if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT)
|
||||
atomic_set(&oct->hb_miss_cnt, 0);
|
||||
|
||||
handled = true;
|
||||
}
|
||||
|
||||
writeq(mbox_int_val, oct->mbox[0]->mbox_int_reg);
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* Interrupts handler for all non-queue generic interrupts. */
|
||||
@@ -434,24 +466,9 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
||||
goto irq_handled;
|
||||
}
|
||||
|
||||
/* Check for MBOX INTR */
|
||||
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0));
|
||||
if (reg_val) {
|
||||
dev_info(&pdev->dev,
|
||||
"Received MBOX_RINT intr: 0x%llx\n", reg_val);
|
||||
cn93_handle_pf_mbox_intr(oct);
|
||||
/* Check for MBOX INTR and OEI INTR */
|
||||
if (octep_poll_non_ioq_interrupts_cn93_pf(oct))
|
||||
goto irq_handled;
|
||||
}
|
||||
|
||||
/* Check for OEI INTR */
|
||||
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
|
||||
if (reg_val) {
|
||||
dev_info(&pdev->dev,
|
||||
"Received OEI_EINT intr: 0x%llx\n", reg_val);
|
||||
octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg_val);
|
||||
queue_work(octep_wq, &oct->ctrl_mbox_task);
|
||||
goto irq_handled;
|
||||
}
|
||||
|
||||
/* Check for DMA INTR */
|
||||
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_RINT);
|
||||
@@ -712,6 +729,7 @@ void octep_device_setup_cn93_pf(struct octep_device *oct)
|
||||
|
||||
oct->hw_ops.enable_interrupts = octep_enable_interrupts_cn93_pf;
|
||||
oct->hw_ops.disable_interrupts = octep_disable_interrupts_cn93_pf;
|
||||
oct->hw_ops.poll_non_ioq_interrupts = octep_poll_non_ioq_interrupts_cn93_pf;
|
||||
|
||||
oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cn93_pf;
|
||||
|
||||
|
||||
@@ -200,5 +200,11 @@ struct octep_config {
|
||||
|
||||
/* ctrl mbox config */
|
||||
struct octep_ctrl_mbox_config ctrl_mbox_cfg;
|
||||
|
||||
/* Configured maximum heartbeat miss count */
|
||||
u32 max_hb_miss_cnt;
|
||||
|
||||
/* Configured firmware heartbeat interval in secs */
|
||||
u32 hb_interval;
|
||||
};
|
||||
#endif /* _OCTEP_CONFIG_H_ */
|
||||
|
||||
@@ -24,41 +24,49 @@
|
||||
/* Time in msecs to wait for message response */
|
||||
#define OCTEP_CTRL_MBOX_MSG_WAIT_MS 10
|
||||
|
||||
#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(m) (m)
|
||||
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(m) ((m) + 8)
|
||||
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(m) ((m) + 24)
|
||||
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(m) ((m) + 144)
|
||||
/* Size of mbox info in bytes */
|
||||
#define OCTEP_CTRL_MBOX_INFO_SZ 256
|
||||
/* Size of mbox host to fw queue info in bytes */
|
||||
#define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ 16
|
||||
/* Size of mbox fw to host queue info in bytes */
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ 16
|
||||
|
||||
#define OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ)
|
||||
#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_H2FQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 8)
|
||||
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 12)
|
||||
#define OCTEP_CTRL_MBOX_TOTAL_INFO_SZ (OCTEP_CTRL_MBOX_INFO_SZ + \
|
||||
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \
|
||||
OCTEP_CTRL_MBOX_F2HQ_INFO_SZ)
|
||||
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m) ((m) + \
|
||||
OCTEP_CTRL_MBOX_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_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 4)
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 8)
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 12)
|
||||
#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_Q_OFFSET(m, i) ((m) + \
|
||||
(sizeof(struct octep_ctrl_mbox_msg) * (i)))
|
||||
#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)
|
||||
|
||||
static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 mask)
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_INFO(m) ((m) + \
|
||||
OCTEP_CTRL_MBOX_INFO_SZ + \
|
||||
OCTEP_CTRL_MBOX_H2FQ_INFO_SZ)
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_PROD(m) (OCTEP_CTRL_MBOX_F2HQ_INFO(m))
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_CONS(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 4)
|
||||
#define OCTEP_CTRL_MBOX_F2HQ_SZ(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 8)
|
||||
|
||||
static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);
|
||||
|
||||
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)
|
||||
@@ -73,153 +81,170 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
|
||||
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) {
|
||||
pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num);
|
||||
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) {
|
||||
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));
|
||||
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.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->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem));
|
||||
mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem);
|
||||
mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem);
|
||||
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.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);
|
||||
mbox->f2hq.sz = readl(OCTEP_CTRL_MBOX_F2HQ_SZ(mbox->barmem));
|
||||
mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD(mbox->barmem);
|
||||
mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS(mbox->barmem);
|
||||
mbox->f2hq.hw_q = mbox->barmem +
|
||||
OCTEP_CTRL_MBOX_TOTAL_INFO_SZ +
|
||||
mbox->h2fq.sz;
|
||||
|
||||
/* 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));
|
||||
writeq(OCTEP_CTRL_MBOX_STATUS_READY,
|
||||
OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
|
||||
|
||||
pr_info("Octep ctrl mbox : Init successful.\n");
|
||||
|
||||
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)
|
||||
{
|
||||
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_msg_buf *sg;
|
||||
struct octep_ctrl_mbox_q *q;
|
||||
unsigned long expire;
|
||||
u64 *mbuf, *word0;
|
||||
u8 __iomem *qidx;
|
||||
u16 pi, ci;
|
||||
int i;
|
||||
u32 pi, ci, buf_sz, w_sz;
|
||||
int s;
|
||||
|
||||
if (!mbox || !msg)
|
||||
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;
|
||||
pi = readl(q->hw_prod);
|
||||
ci = readl(q->hw_cons);
|
||||
|
||||
if (!octep_ctrl_mbox_circq_space(pi, ci, q->mask))
|
||||
return -ENOMEM;
|
||||
if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz)
|
||||
{
|
||||
u8 __iomem *qbuf;
|
||||
u32 cp_sz;
|
||||
|
||||
/* Assumption: Caller has ensured enough read space */
|
||||
qbuf = (q->hw_q + *ci);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
u32 count, pi, ci;
|
||||
u8 __iomem *qidx;
|
||||
u64 *mbuf;
|
||||
int i;
|
||||
int s;
|
||||
|
||||
if (!mbox || !msg)
|
||||
return -EINVAL;
|
||||
if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&mbox->f2hq_lock);
|
||||
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)
|
||||
|
||||
q_depth = octep_ctrl_mbox_circq_depth(pi, ci, q->sz);
|
||||
if (q_depth < mbox_hdr_sz) {
|
||||
mutex_unlock(&mbox->f2hq_lock);
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -227,18 +252,17 @@ int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
|
||||
{
|
||||
if (!mbox)
|
||||
return -EINVAL;
|
||||
if (!mbox->barmem)
|
||||
return -EINVAL;
|
||||
|
||||
writeq(OCTEP_CTRL_MBOX_STATUS_UNINIT,
|
||||
OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
|
||||
writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
|
||||
OCTEP_CTRL_MBOX_INFO_HOST_STATUS(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));
|
||||
|
||||
pr_info("Octep ctrl mbox : Uninit successful.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -27,50 +27,39 @@
|
||||
* |-------------------------------------------|
|
||||
* |producer index (4 bytes) |
|
||||
* |consumer index (4 bytes) |
|
||||
* |element size (4 bytes) |
|
||||
* |element count (4 bytes) |
|
||||
* |max element size (4 bytes) |
|
||||
* |reserved (4 bytes) |
|
||||
* |===========================================|
|
||||
* |Fw to Host Queue info (16 bytes) |
|
||||
* |-------------------------------------------|
|
||||
* |producer index (4 bytes) |
|
||||
* |consumer index (4 bytes) |
|
||||
* |element size (4 bytes) |
|
||||
* |element count (4 bytes) |
|
||||
* |max element size (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
|
||||
|
||||
/* 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 */
|
||||
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ BIT(0)
|
||||
/* Valid response message */
|
||||
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP BIT(1)
|
||||
/* Valid notification, no response required */
|
||||
#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 {
|
||||
OCTEP_CTRL_MBOX_STATUS_INVALID = 0,
|
||||
@@ -81,31 +70,48 @@ enum octep_ctrl_mbox_status {
|
||||
|
||||
/* mbox message */
|
||||
union octep_ctrl_mbox_msg_hdr {
|
||||
u64 word0;
|
||||
u64 words[2];
|
||||
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_* */
|
||||
u32 flags;
|
||||
/* size of message in words excluding header */
|
||||
u32 sizew;
|
||||
};
|
||||
/* identifier to match responses */
|
||||
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 */
|
||||
struct octep_ctrl_mbox_msg {
|
||||
/* mbox transaction header */
|
||||
union octep_ctrl_mbox_msg_hdr hdr;
|
||||
/* pointer to message buffer */
|
||||
void *msg;
|
||||
/* number of sg buffer's */
|
||||
int sg_num;
|
||||
/* message buffer's */
|
||||
struct octep_ctrl_mbox_msg_buf sg_list[OCTEP_CTRL_MBOX_MSG_DESC_MAX];
|
||||
};
|
||||
|
||||
/* Mbox queue */
|
||||
struct octep_ctrl_mbox_q {
|
||||
/* q element size, should be aligned to unsigned long */
|
||||
u16 elem_sz;
|
||||
/* q element count, should be power of 2 */
|
||||
u16 elem_cnt;
|
||||
/* q mask */
|
||||
u16 mask;
|
||||
/* size of queue buffer */
|
||||
u32 sz;
|
||||
/* producer address in bar mem */
|
||||
u8 __iomem *hw_prod;
|
||||
/* consumer address in bar mem */
|
||||
@@ -115,16 +121,10 @@ struct octep_ctrl_mbox_q {
|
||||
};
|
||||
|
||||
struct octep_ctrl_mbox {
|
||||
/* host driver version */
|
||||
u64 version;
|
||||
/* size of bar memory */
|
||||
u32 barmem_sz;
|
||||
/* pointer to BAR memory */
|
||||
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 */
|
||||
struct octep_ctrl_mbox_q h2fq;
|
||||
/* fw-to-host queue */
|
||||
@@ -146,6 +146,8 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox);
|
||||
/* Send mbox message.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@@ -154,6 +156,8 @@ int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms
|
||||
/* Retrieve mbox message.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@@ -161,7 +165,7 @@ int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
@@ -8,187 +8,328 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "octep_config.h"
|
||||
#include "octep_main.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 atomic_t ctrl_net_msg_id;
|
||||
|
||||
static void init_send_req(struct octep_ctrl_mbox_msg *msg, void *buf,
|
||||
u16 sz, int vfid)
|
||||
{
|
||||
struct octep_ctrl_net_h2f_req req = {};
|
||||
msg->hdr.s.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
|
||||
msg->hdr.s.msg_id = atomic_inc_return(&ctrl_net_msg_id) &
|
||||
GENMASK(sizeof(msg->hdr.s.msg_id) * BITS_PER_BYTE, 0);
|
||||
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;
|
||||
if (vfid != OCTEP_CTRL_NET_INVALID_VFID) {
|
||||
msg->hdr.s.is_vf = 1;
|
||||
msg->hdr.s.vf_idx = vfid;
|
||||
}
|
||||
}
|
||||
|
||||
static int octep_send_mbox_req(struct octep_device *oct,
|
||||
struct octep_ctrl_net_wait_data *d,
|
||||
bool wait_for_response)
|
||||
{
|
||||
int err, ret;
|
||||
|
||||
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &d->msg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!wait_for_response)
|
||||
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;
|
||||
}
|
||||
|
||||
int octep_ctrl_net_init(struct octep_device *oct)
|
||||
{
|
||||
struct octep_ctrl_mbox *ctrl_mbox;
|
||||
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;
|
||||
}
|
||||
|
||||
int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid)
|
||||
{
|
||||
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, vfid);
|
||||
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;
|
||||
|
||||
return d.data.resp.link.state;
|
||||
}
|
||||
|
||||
int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up,
|
||||
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, state_sz, vfid);
|
||||
req->hdr.s.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;
|
||||
|
||||
return octep_send_mbox_req(oct, &d, wait_for_response);
|
||||
}
|
||||
|
||||
int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up,
|
||||
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, state_sz, vfid);
|
||||
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;
|
||||
|
||||
return octep_send_mbox_req(oct, &d, wait_for_response);
|
||||
}
|
||||
|
||||
int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr)
|
||||
{
|
||||
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, vfid);
|
||||
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;
|
||||
|
||||
memcpy(addr, d.data.resp.mac.addr, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr,
|
||||
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, mac_sz, vfid);
|
||||
req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MAC;
|
||||
req->mac.cmd = OCTEP_CTRL_NET_CMD_SET;
|
||||
memcpy(&req->mac.addr, addr, ETH_ALEN);
|
||||
|
||||
return octep_send_mbox_req(oct, &d, wait_for_response);
|
||||
}
|
||||
|
||||
int octep_ctrl_net_set_mtu(struct octep_device *oct, int vfid, int mtu,
|
||||
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, mtu_sz, vfid);
|
||||
req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU;
|
||||
req->mtu.cmd = OCTEP_CTRL_NET_CMD_SET;
|
||||
req->mtu.val = mtu;
|
||||
|
||||
return octep_send_mbox_req(oct, &d, wait_for_response);
|
||||
}
|
||||
|
||||
int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid,
|
||||
struct octep_iface_rx_stats *rx_stats,
|
||||
struct octep_iface_tx_stats *tx_stats)
|
||||
{
|
||||
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_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)
|
||||
init_send_req(&d.msg, req, 0, vfid);
|
||||
req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_IF_STATS;
|
||||
err = octep_send_mbox_req(oct, &d, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
resp = (struct octep_ctrl_net_h2f_resp *)&req;
|
||||
return resp->link.state;
|
||||
resp = &d.data.resp;
|
||||
memcpy(rx_stats, &resp->if_stats.rx_stats, sizeof(struct octep_iface_rx_stats));
|
||||
memcpy(tx_stats, &resp->if_stats.tx_stats, sizeof(struct octep_iface_tx_stats));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void octep_set_link_status(struct octep_device *oct, bool up)
|
||||
int octep_ctrl_net_get_link_info(struct octep_device *oct, int vfid,
|
||||
struct octep_iface_link_info *link_info)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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_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)
|
||||
init_send_req(&d.msg, req, link_info_sz, vfid);
|
||||
req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
|
||||
req->link_info.cmd = OCTEP_CTRL_NET_CMD_GET;
|
||||
err = octep_send_mbox_req(oct, &d, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
resp = (struct octep_ctrl_net_h2f_resp *)&req;
|
||||
memcpy(addr, resp->mac.addr, ETH_ALEN);
|
||||
resp = &d.data.resp;
|
||||
link_info->supported_modes = resp->link_info.supported_modes;
|
||||
link_info->advertised_modes = resp->link_info.advertised_modes;
|
||||
link_info->autoneg = resp->link_info.autoneg;
|
||||
link_info->pause = resp->link_info.pause;
|
||||
link_info->speed = resp->link_info.speed;
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_set_mac_addr(struct octep_device *oct, u8 *addr)
|
||||
int octep_ctrl_net_set_link_info(struct octep_device *oct, int vfid,
|
||||
struct octep_iface_link_info *link_info,
|
||||
bool wait_for_response)
|
||||
{
|
||||
struct octep_ctrl_net_h2f_req req = {};
|
||||
struct octep_ctrl_mbox_msg msg = {};
|
||||
struct octep_ctrl_net_wait_data d = {0};
|
||||
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);
|
||||
init_send_req(&d.msg, req, link_info_sz, vfid);
|
||||
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;
|
||||
|
||||
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
|
||||
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MAC_REQ_SZW;
|
||||
msg.msg = &req;
|
||||
|
||||
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)
|
||||
static void process_mbox_resp(struct octep_device *oct,
|
||||
struct octep_ctrl_mbox_msg *msg)
|
||||
{
|
||||
struct octep_ctrl_net_h2f_req req = {};
|
||||
struct octep_ctrl_mbox_msg msg = {};
|
||||
struct octep_ctrl_net_wait_data *pos, *n;
|
||||
|
||||
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU;
|
||||
req.mtu.cmd = OCTEP_CTRL_NET_CMD_SET;
|
||||
req.mtu.val = mtu;
|
||||
|
||||
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
|
||||
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_MTU_REQ_SZW;
|
||||
msg.msg = &req;
|
||||
|
||||
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
|
||||
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_get_if_stats(struct octep_device *oct)
|
||||
static int process_mbox_notify(struct octep_device *oct,
|
||||
struct octep_ctrl_mbox_msg *msg)
|
||||
{
|
||||
void __iomem *iface_rx_stats;
|
||||
void __iomem *iface_tx_stats;
|
||||
struct octep_ctrl_net_h2f_req req = {};
|
||||
struct octep_ctrl_mbox_msg msg = {};
|
||||
int err;
|
||||
struct net_device *netdev = oct->netdev;
|
||||
struct octep_ctrl_net_f2h_req *req;
|
||||
|
||||
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_IF_STATS;
|
||||
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET;
|
||||
req.get_stats.offset = oct->ctrl_mbox_ifstats_offset;
|
||||
req = (struct octep_ctrl_net_f2h_req *)msg->sg_list[0].msg;
|
||||
switch (req->hdr.s.cmd) {
|
||||
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.s.cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
|
||||
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;
|
||||
|
||||
iface_rx_stats = oct->ctrl_mbox.barmem + oct->ctrl_mbox_ifstats_offset;
|
||||
iface_tx_stats = oct->ctrl_mbox.barmem + oct->ctrl_mbox_ifstats_offset +
|
||||
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));
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int octep_get_link_info(struct octep_device *oct)
|
||||
void octep_ctrl_net_recv_fw_messages(struct octep_device *oct)
|
||||
{
|
||||
struct octep_ctrl_net_h2f_req req = {};
|
||||
struct octep_ctrl_net_h2f_resp *resp;
|
||||
struct octep_ctrl_mbox_msg msg = {};
|
||||
int err;
|
||||
static u16 msg_sz = sizeof(union octep_ctrl_net_max_data);
|
||||
union octep_ctrl_net_max_data data = {0};
|
||||
struct octep_ctrl_mbox_msg msg = {0};
|
||||
int ret;
|
||||
|
||||
req.hdr.cmd = OCTEP_CTRL_NET_H2F_CMD_LINK_INFO;
|
||||
req.mac.cmd = OCTEP_CTRL_NET_CMD_GET;
|
||||
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;
|
||||
|
||||
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;
|
||||
if (msg.hdr.s.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP)
|
||||
process_mbox_resp(oct, &msg);
|
||||
else if (msg.hdr.s.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY)
|
||||
process_mbox_notify(oct, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct octep_ctrl_net_h2f_req req = {};
|
||||
struct octep_ctrl_mbox_msg msg = {};
|
||||
struct octep_ctrl_net_wait_data *pos, *n;
|
||||
|
||||
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;
|
||||
list_for_each_entry_safe(pos, n, &oct->ctrl_req_wait_list, list)
|
||||
pos->done = 1;
|
||||
|
||||
msg.hdr.flags = OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ;
|
||||
msg.hdr.sizew = OCTEP_CTRL_NET_H2F_LINK_INFO_REQ_SZW;
|
||||
msg.msg = &req;
|
||||
wake_up_interruptible_all(&oct->ctrl_req_wait_q);
|
||||
|
||||
return octep_ctrl_mbox_send(&oct->ctrl_mbox, &msg);
|
||||
octep_ctrl_mbox_uninit(&oct->ctrl_mbox);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef __OCTEP_CTRL_NET_H__
|
||||
#define __OCTEP_CTRL_NET_H__
|
||||
|
||||
#define OCTEP_CTRL_NET_INVALID_VFID (-1)
|
||||
|
||||
/* Supported commands */
|
||||
enum octep_ctrl_net_cmd {
|
||||
OCTEP_CTRL_NET_CMD_GET = 0,
|
||||
@@ -45,15 +47,18 @@ enum octep_ctrl_net_f2h_cmd {
|
||||
OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS,
|
||||
};
|
||||
|
||||
struct octep_ctrl_net_req_hdr {
|
||||
/* sender id */
|
||||
u16 sender;
|
||||
/* receiver id */
|
||||
u16 receiver;
|
||||
/* octep_ctrl_net_h2t_cmd */
|
||||
u16 cmd;
|
||||
/* reserved */
|
||||
u16 rsvd0;
|
||||
union octep_ctrl_net_req_hdr {
|
||||
u64 words[1];
|
||||
struct {
|
||||
/* sender id */
|
||||
u16 sender;
|
||||
/* receiver id */
|
||||
u16 receiver;
|
||||
/* octep_ctrl_net_h2t_cmd */
|
||||
u16 cmd;
|
||||
/* reserved */
|
||||
u16 rsvd0;
|
||||
} s;
|
||||
};
|
||||
|
||||
/* get/set mtu request */
|
||||
@@ -72,12 +77,6 @@ struct octep_ctrl_net_h2f_req_cmd_mac {
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/* get if_stats, xstats, q_stats request */
|
||||
struct octep_ctrl_net_h2f_req_cmd_get_stats {
|
||||
/* offset into barmem where fw should copy over stats */
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
/* get/set link state, rx state */
|
||||
struct octep_ctrl_net_h2f_req_cmd_state {
|
||||
/* enum octep_ctrl_net_cmd */
|
||||
@@ -110,26 +109,28 @@ struct octep_ctrl_net_h2f_req_cmd_link_info {
|
||||
|
||||
/* Host to fw request data */
|
||||
struct octep_ctrl_net_h2f_req {
|
||||
struct octep_ctrl_net_req_hdr hdr;
|
||||
union octep_ctrl_net_req_hdr hdr;
|
||||
union {
|
||||
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_get_stats get_stats;
|
||||
struct octep_ctrl_net_h2f_req_cmd_state link;
|
||||
struct octep_ctrl_net_h2f_req_cmd_state rx;
|
||||
struct octep_ctrl_net_h2f_req_cmd_link_info link_info;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct octep_ctrl_net_resp_hdr {
|
||||
/* sender id */
|
||||
u16 sender;
|
||||
/* receiver id */
|
||||
u16 receiver;
|
||||
/* octep_ctrl_net_h2t_cmd */
|
||||
u16 cmd;
|
||||
/* octep_ctrl_net_reply */
|
||||
u16 reply;
|
||||
union octep_ctrl_net_resp_hdr {
|
||||
u64 words[1];
|
||||
struct {
|
||||
/* sender id */
|
||||
u16 sender;
|
||||
/* receiver id */
|
||||
u16 receiver;
|
||||
/* octep_ctrl_net_h2t_cmd */
|
||||
u16 cmd;
|
||||
/* octep_ctrl_net_reply */
|
||||
u16 reply;
|
||||
} s;
|
||||
};
|
||||
|
||||
/* get mtu response */
|
||||
@@ -144,6 +145,12 @@ struct octep_ctrl_net_h2f_resp_cmd_mac {
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/* get if_stats, xstats, q_stats request */
|
||||
struct octep_ctrl_net_h2f_resp_cmd_get_stats {
|
||||
struct octep_iface_rx_stats rx_stats;
|
||||
struct octep_iface_tx_stats tx_stats;
|
||||
};
|
||||
|
||||
/* get link state, rx state response */
|
||||
struct octep_ctrl_net_h2f_resp_cmd_state {
|
||||
/* enum octep_ctrl_net_state */
|
||||
@@ -152,10 +159,11 @@ struct octep_ctrl_net_h2f_resp_cmd_state {
|
||||
|
||||
/* Host to fw response data */
|
||||
struct octep_ctrl_net_h2f_resp {
|
||||
struct octep_ctrl_net_resp_hdr hdr;
|
||||
union octep_ctrl_net_resp_hdr hdr;
|
||||
union {
|
||||
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_get_stats if_stats;
|
||||
struct octep_ctrl_net_h2f_resp_cmd_state link;
|
||||
struct octep_ctrl_net_h2f_resp_cmd_state rx;
|
||||
struct octep_ctrl_net_link_info link_info;
|
||||
@@ -170,7 +178,7 @@ struct octep_ctrl_net_f2h_req_cmd_state {
|
||||
|
||||
/* Fw to host request data */
|
||||
struct octep_ctrl_net_f2h_req {
|
||||
struct octep_ctrl_net_req_hdr hdr;
|
||||
union octep_ctrl_net_req_hdr hdr;
|
||||
union {
|
||||
struct octep_ctrl_net_f2h_req_cmd_state link;
|
||||
};
|
||||
@@ -178,122 +186,152 @@ struct octep_ctrl_net_f2h_req {
|
||||
|
||||
/* Fw to host response data */
|
||||
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 */
|
||||
union octep_ctrl_net_h2f_data_sz {
|
||||
/* Max data size to be transferred over mbox */
|
||||
union octep_ctrl_net_max_data {
|
||||
struct octep_ctrl_net_h2f_req h2f_req;
|
||||
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_resp f2h_resp;
|
||||
};
|
||||
|
||||
/* size of host to fw data in words */
|
||||
#define OCTEP_CTRL_NET_H2F_DATA_SZW ((sizeof(union octep_ctrl_net_h2f_data_sz)) / \
|
||||
(sizeof(unsigned long)))
|
||||
struct octep_ctrl_net_wait_data {
|
||||
struct list_head list;
|
||||
int done;
|
||||
struct octep_ctrl_mbox_msg msg;
|
||||
union {
|
||||
struct octep_ctrl_net_h2f_req req;
|
||||
struct octep_ctrl_net_h2f_resp resp;
|
||||
} data;
|
||||
};
|
||||
|
||||
/* size of fw to host data in words */
|
||||
#define OCTEP_CTRL_NET_F2H_DATA_SZW ((sizeof(union octep_ctrl_net_f2h_data_sz)) / \
|
||||
(sizeof(unsigned long)))
|
||||
|
||||
/* 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 */
|
||||
#define OCTEP_CTRL_NET_H2F_MAC_REQ_SZW 2
|
||||
/* size in words of get stats request */
|
||||
#define OCTEP_CTRL_NET_H2F_GET_STATS_REQ_SZW 2
|
||||
/* size in words of get/set state request */
|
||||
#define OCTEP_CTRL_NET_H2F_STATE_REQ_SZW 2
|
||||
/* size in words of get/set link info request */
|
||||
#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
|
||||
/** Initialize data for ctrl net.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
*
|
||||
* return value: 0 on success, -errno on error.
|
||||
*/
|
||||
int octep_ctrl_net_init(struct octep_device *oct);
|
||||
|
||||
/** Get link status from firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
*
|
||||
* 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, int vfid);
|
||||
|
||||
/** Set link status in firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @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, int vfid, bool up,
|
||||
bool wait_for_response);
|
||||
|
||||
/** Set rx state in firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @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, int vfid, bool up,
|
||||
bool wait_for_response);
|
||||
|
||||
/** Get mac address from firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @param addr: non-null pointer to mac address.
|
||||
*
|
||||
* 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, int vfid, u8 *addr);
|
||||
|
||||
/** Set mac address in firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @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, int vfid, u8 *addr,
|
||||
bool wait_for_response);
|
||||
|
||||
/** Set mtu in firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @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 vfid, int mtu,
|
||||
bool wait_for_response);
|
||||
|
||||
/** Get interface statistics from firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @param rx_stats: non-null pointer struct octep_iface_rx_stats.
|
||||
* @param tx_stats: non-null pointer struct octep_iface_tx_stats.
|
||||
*
|
||||
* 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, int vfid,
|
||||
struct octep_iface_rx_stats *rx_stats,
|
||||
struct octep_iface_tx_stats *tx_stats);
|
||||
|
||||
/** Get link info from firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @param link_info: non-null pointer to struct octep_iface_link_info.
|
||||
*
|
||||
* 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, int vfid,
|
||||
struct octep_iface_link_info *link_info);
|
||||
|
||||
/** Set link info in firmware.
|
||||
*
|
||||
* @param oct: non-null pointer to struct octep_device.
|
||||
* @param vfid: Index of virtual function.
|
||||
* @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_set_link_info(struct octep_device *oct, struct octep_iface_link_info *link_info);
|
||||
int octep_ctrl_net_set_link_info(struct octep_device *oct,
|
||||
int vfid,
|
||||
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_ctrl_net_uninit(struct octep_device *oct);
|
||||
|
||||
#endif /* __OCTEP_CTRL_NET_H__ */
|
||||
|
||||
@@ -150,9 +150,12 @@ octep_get_ethtool_stats(struct net_device *netdev,
|
||||
rx_packets = 0;
|
||||
rx_bytes = 0;
|
||||
|
||||
octep_get_if_stats(oct);
|
||||
iface_tx_stats = &oct->iface_tx_stats;
|
||||
iface_rx_stats = &oct->iface_rx_stats;
|
||||
octep_ctrl_net_get_if_stats(oct,
|
||||
OCTEP_CTRL_NET_INVALID_VFID,
|
||||
iface_rx_stats,
|
||||
iface_tx_stats);
|
||||
|
||||
for (q = 0; q < oct->num_oqs; q++) {
|
||||
struct octep_iq *iq = oct->iq[q];
|
||||
@@ -283,11 +286,11 @@ 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, advertising);
|
||||
|
||||
octep_get_link_info(oct);
|
||||
link_info = &oct->link_info;
|
||||
octep_ctrl_net_get_link_info(oct, OCTEP_CTRL_NET_INVALID_VFID, link_info);
|
||||
|
||||
advertised_modes = oct->link_info.advertised_modes;
|
||||
supported_modes = oct->link_info.supported_modes;
|
||||
link_info = &oct->link_info;
|
||||
|
||||
OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported);
|
||||
OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);
|
||||
@@ -439,7 +442,8 @@ static int octep_set_link_ksettings(struct net_device *netdev,
|
||||
link_info_new.speed = cmd->base.speed;
|
||||
link_info_new.autoneg = autoneg;
|
||||
|
||||
err = octep_set_link_info(oct, &link_info_new);
|
||||
err = octep_ctrl_net_set_link_info(oct, OCTEP_CTRL_NET_INVALID_VFID,
|
||||
&link_info_new, true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "octep_main.h"
|
||||
#include "octep_ctrl_net.h"
|
||||
|
||||
#define OCTEP_INTR_POLL_TIME_MSECS 100
|
||||
struct workqueue_struct *octep_wq;
|
||||
|
||||
/* Supported Devices */
|
||||
@@ -506,11 +507,11 @@ static int octep_open(struct net_device *netdev)
|
||||
octep_napi_enable(oct);
|
||||
|
||||
oct->link_info.admin_up = 1;
|
||||
octep_set_rx_state(oct, true);
|
||||
|
||||
ret = octep_get_link_status(oct);
|
||||
if (!ret)
|
||||
octep_set_link_status(oct, true);
|
||||
octep_ctrl_net_set_rx_state(oct, OCTEP_CTRL_NET_INVALID_VFID, true,
|
||||
false);
|
||||
octep_ctrl_net_set_link_status(oct, OCTEP_CTRL_NET_INVALID_VFID, true,
|
||||
false);
|
||||
oct->poll_non_ioq_intr = false;
|
||||
|
||||
/* Enable the input and output queues for this Octeon device */
|
||||
oct->hw_ops.enable_io_queues(oct);
|
||||
@@ -520,7 +521,7 @@ static int octep_open(struct net_device *netdev)
|
||||
|
||||
octep_oq_dbell_init(oct);
|
||||
|
||||
ret = octep_get_link_status(oct);
|
||||
ret = octep_ctrl_net_get_link_status(oct, OCTEP_CTRL_NET_INVALID_VFID);
|
||||
if (ret > 0)
|
||||
octep_link_up(netdev);
|
||||
|
||||
@@ -550,14 +551,16 @@ static int octep_stop(struct net_device *netdev)
|
||||
|
||||
netdev_info(netdev, "Stopping the device ...\n");
|
||||
|
||||
octep_ctrl_net_set_link_status(oct, OCTEP_CTRL_NET_INVALID_VFID, false,
|
||||
false);
|
||||
octep_ctrl_net_set_rx_state(oct, OCTEP_CTRL_NET_INVALID_VFID, false,
|
||||
false);
|
||||
|
||||
/* Stop Tx from stack */
|
||||
netif_tx_stop_all_queues(netdev);
|
||||
netif_carrier_off(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.oper_up = 0;
|
||||
|
||||
@@ -572,6 +575,11 @@ static int octep_stop(struct net_device *netdev)
|
||||
oct->hw_ops.reset_io_queues(oct);
|
||||
octep_free_oqs(oct);
|
||||
octep_free_iqs(oct);
|
||||
|
||||
oct->poll_non_ioq_intr = true;
|
||||
queue_delayed_work(octep_wq, &oct->intr_poll_task,
|
||||
msecs_to_jiffies(OCTEP_INTR_POLL_TIME_MSECS));
|
||||
|
||||
netdev_info(netdev, "Device stopped !!\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -754,7 +762,12 @@ static void octep_get_stats64(struct net_device *netdev,
|
||||
struct octep_device *oct = netdev_priv(netdev);
|
||||
int q;
|
||||
|
||||
octep_get_if_stats(oct);
|
||||
if (netif_running(netdev))
|
||||
octep_ctrl_net_get_if_stats(oct,
|
||||
OCTEP_CTRL_NET_INVALID_VFID,
|
||||
&oct->iface_rx_stats,
|
||||
&oct->iface_tx_stats);
|
||||
|
||||
tx_packets = 0;
|
||||
tx_bytes = 0;
|
||||
rx_packets = 0;
|
||||
@@ -825,7 +838,8 @@ static int octep_set_mac(struct net_device *netdev, void *p)
|
||||
if (!is_valid_ether_addr(addr->sa_data))
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
err = octep_set_mac_addr(oct, addr->sa_data);
|
||||
err = octep_ctrl_net_set_mac_addr(oct, OCTEP_CTRL_NET_INVALID_VFID,
|
||||
addr->sa_data, true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -845,7 +859,8 @@ static int octep_change_mtu(struct net_device *netdev, int new_mtu)
|
||||
if (link_info->mtu == new_mtu)
|
||||
return 0;
|
||||
|
||||
err = octep_set_mtu(oct, new_mtu);
|
||||
err = octep_ctrl_net_set_mtu(oct, OCTEP_CTRL_NET_INVALID_VFID, new_mtu,
|
||||
true);
|
||||
if (!err) {
|
||||
oct->link_info.mtu = new_mtu;
|
||||
netdev->mtu = new_mtu;
|
||||
@@ -864,6 +879,59 @@ static const struct net_device_ops octep_netdev_ops = {
|
||||
.ndo_change_mtu = octep_change_mtu,
|
||||
};
|
||||
|
||||
/**
|
||||
* octep_intr_poll_task - work queue task to process non-ioq interrupts.
|
||||
*
|
||||
* @work: pointer to mbox work_struct
|
||||
*
|
||||
* Process non-ioq interrupts to handle control mailbox, pfvf mailbox.
|
||||
**/
|
||||
static void octep_intr_poll_task(struct work_struct *work)
|
||||
{
|
||||
struct octep_device *oct = container_of(work, struct octep_device,
|
||||
intr_poll_task.work);
|
||||
|
||||
if (!oct->poll_non_ioq_intr) {
|
||||
dev_info(&oct->pdev->dev, "Interrupt poll task stopped.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
oct->hw_ops.poll_non_ioq_interrupts(oct);
|
||||
queue_delayed_work(octep_wq, &oct->intr_poll_task,
|
||||
msecs_to_jiffies(OCTEP_INTR_POLL_TIME_MSECS));
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_hb_timeout_task - work queue task to check firmware heartbeat.
|
||||
*
|
||||
* @work: pointer to hb work_struct
|
||||
*
|
||||
* Check for heartbeat miss count. Uninitialize oct device if miss count
|
||||
* exceeds configured max heartbeat miss count.
|
||||
*
|
||||
**/
|
||||
static void octep_hb_timeout_task(struct work_struct *work)
|
||||
{
|
||||
struct octep_device *oct = container_of(work, struct octep_device,
|
||||
hb_task.work);
|
||||
|
||||
int miss_cnt;
|
||||
|
||||
miss_cnt = atomic_inc_return(&oct->hb_miss_cnt);
|
||||
if (miss_cnt < oct->conf->max_hb_miss_cnt) {
|
||||
queue_delayed_work(octep_wq, &oct->hb_task,
|
||||
msecs_to_jiffies(oct->conf->hb_interval * 1000));
|
||||
return;
|
||||
}
|
||||
|
||||
dev_err(&oct->pdev->dev, "Missed %u heartbeats. Uninitializing\n",
|
||||
miss_cnt);
|
||||
rtnl_lock();
|
||||
if (netif_running(oct->netdev))
|
||||
octep_stop(oct->netdev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_ctrl_mbox_task - work queue task to handle ctrl mbox messages.
|
||||
*
|
||||
@@ -875,34 +943,8 @@ static void octep_ctrl_mbox_task(struct work_struct *work)
|
||||
{
|
||||
struct octep_device *oct = container_of(work, struct octep_device,
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
octep_ctrl_net_recv_fw_messages(oct);
|
||||
}
|
||||
|
||||
static const char *octep_devid_to_str(struct octep_device *oct)
|
||||
@@ -926,7 +968,6 @@ static const char *octep_devid_to_str(struct octep_device *oct)
|
||||
*/
|
||||
int octep_device_setup(struct octep_device *oct)
|
||||
{
|
||||
struct octep_ctrl_mbox *ctrl_mbox;
|
||||
struct pci_dev *pdev = oct->pdev;
|
||||
int i, ret;
|
||||
|
||||
@@ -963,19 +1004,14 @@ int octep_device_setup(struct octep_device *oct)
|
||||
|
||||
oct->pkind = CFG_GET_IQ_PKIND(oct->conf);
|
||||
|
||||
/* 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");
|
||||
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);
|
||||
ret = octep_ctrl_net_init(oct);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atomic_set(&oct->hb_miss_cnt, 0);
|
||||
INIT_DELAYED_WORK(&oct->hb_task, octep_hb_timeout_task);
|
||||
queue_delayed_work(octep_wq, &oct->hb_task,
|
||||
msecs_to_jiffies(oct->conf->hb_interval * 1000));
|
||||
return 0;
|
||||
|
||||
unsupported_dev:
|
||||
@@ -1004,7 +1040,8 @@ static void octep_device_cleanup(struct octep_device *oct)
|
||||
oct->mbox[i] = NULL;
|
||||
}
|
||||
|
||||
octep_ctrl_mbox_uninit(&oct->ctrl_mbox);
|
||||
octep_ctrl_net_uninit(oct);
|
||||
cancel_delayed_work_sync(&oct->hb_task);
|
||||
|
||||
oct->hw_ops.soft_reset(oct);
|
||||
for (i = 0; i < OCTEP_MMIO_REGIONS; i++) {
|
||||
@@ -1016,6 +1053,26 @@ static void octep_device_cleanup(struct octep_device *oct)
|
||||
oct->conf = NULL;
|
||||
}
|
||||
|
||||
static bool get_fw_ready_status(struct pci_dev *pdev)
|
||||
{
|
||||
u32 pos = 0;
|
||||
u16 vsec_id;
|
||||
u8 status;
|
||||
|
||||
while ((pos = pci_find_next_ext_capability(pdev, pos,
|
||||
PCI_EXT_CAP_ID_VNDR))) {
|
||||
pci_read_config_word(pdev, pos + 4, &vsec_id);
|
||||
#define FW_STATUS_VSEC_ID 0xA3
|
||||
if (vsec_id != FW_STATUS_VSEC_ID)
|
||||
continue;
|
||||
|
||||
pci_read_config_byte(pdev, (pos + 8), &status);
|
||||
dev_info(&pdev->dev, "Firmware ready status = %u\n", status);
|
||||
return status;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_probe() - Octeon PCI device probe handler.
|
||||
*
|
||||
@@ -1051,6 +1108,12 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (!get_fw_ready_status(pdev)) {
|
||||
dev_notice(&pdev->dev, "Firmware not ready; defer probe.\n");
|
||||
err = -EPROBE_DEFER;
|
||||
goto err_alloc_netdev;
|
||||
}
|
||||
|
||||
netdev = alloc_etherdev_mq(sizeof(struct octep_device),
|
||||
OCTEP_MAX_QUEUES);
|
||||
if (!netdev) {
|
||||
@@ -1073,6 +1136,10 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
}
|
||||
INIT_WORK(&octep_dev->tx_timeout_task, octep_tx_timeout_task);
|
||||
INIT_WORK(&octep_dev->ctrl_mbox_task, octep_ctrl_mbox_task);
|
||||
INIT_DELAYED_WORK(&octep_dev->intr_poll_task, octep_intr_poll_task);
|
||||
octep_dev->poll_non_ioq_intr = true;
|
||||
queue_delayed_work(octep_wq, &octep_dev->intr_poll_task,
|
||||
msecs_to_jiffies(OCTEP_INTR_POLL_TIME_MSECS));
|
||||
|
||||
netdev->netdev_ops = &octep_netdev_ops;
|
||||
octep_set_ethtool_ops(netdev);
|
||||
@@ -1084,7 +1151,8 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
netdev->max_mtu = OCTEP_MAX_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_CTRL_NET_INVALID_VFID,
|
||||
octep_dev->mac_addr);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to get mac address\n");
|
||||
goto register_dev_err;
|
||||
@@ -1133,6 +1201,8 @@ static void octep_remove(struct pci_dev *pdev)
|
||||
if (netdev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdev(netdev);
|
||||
|
||||
oct->poll_non_ioq_intr = false;
|
||||
cancel_delayed_work_sync(&oct->intr_poll_task);
|
||||
octep_device_cleanup(oct);
|
||||
pci_release_mem_regions(pdev);
|
||||
free_netdev(netdev);
|
||||
|
||||
@@ -73,6 +73,7 @@ struct octep_hw_ops {
|
||||
|
||||
void (*enable_interrupts)(struct octep_device *oct);
|
||||
void (*disable_interrupts)(struct octep_device *oct);
|
||||
bool (*poll_non_ioq_interrupts)(struct octep_device *oct);
|
||||
|
||||
void (*enable_io_queues)(struct octep_device *oct);
|
||||
void (*disable_io_queues)(struct octep_device *oct);
|
||||
@@ -270,7 +271,22 @@ struct octep_device {
|
||||
|
||||
/* Work entry to handle ctrl mbox interrupt */
|
||||
struct work_struct ctrl_mbox_task;
|
||||
/* Wait queue for host to firmware requests */
|
||||
wait_queue_head_t ctrl_req_wait_q;
|
||||
/* List of objects waiting for h2f response */
|
||||
struct list_head ctrl_req_wait_list;
|
||||
|
||||
/* Enable non-ioq interrupt polling */
|
||||
bool poll_non_ioq_intr;
|
||||
/* Work entry to poll non-ioq interrupts */
|
||||
struct delayed_work intr_poll_task;
|
||||
|
||||
/* Firmware heartbeat timer */
|
||||
struct timer_list hb_timer;
|
||||
/* Firmware heartbeat miss count tracked by timer */
|
||||
atomic_t hb_miss_cnt;
|
||||
/* Task to reset device on heartbeat miss */
|
||||
struct delayed_work hb_task;
|
||||
};
|
||||
|
||||
static inline u16 OCTEP_MAJOR_REV(struct octep_device *oct)
|
||||
|
||||
@@ -364,4 +364,10 @@
|
||||
|
||||
/* Number of non-queue interrupts in CN93xx */
|
||||
#define CN93_NUM_NON_IOQ_INTR 16
|
||||
|
||||
/* bit 0 for control mbox interrupt */
|
||||
#define CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX BIT_ULL(0)
|
||||
/* bit 1 for firmware heartbeat interrupt */
|
||||
#define CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1)
|
||||
|
||||
#endif /* _OCTEP_REGS_CN9K_PF_H_ */
|
||||
|
||||
Reference in New Issue
Block a user