Commit 6595d358 authored by David S. Miller's avatar David S. Miller

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: default avatarLeon Romanovsky <leon@kernel.org>
   - This change has resulted in update of 0001-xxx.patch and
     all other patches in the patchset.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fbf8ba56 5cb96c29
...@@ -13,6 +13,12 @@ ...@@ -13,6 +13,12 @@
#include "octep_main.h" #include "octep_main.h"
#include "octep_regs_cn9k_pf.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 */ /* Names of Hardware non-queue generic interrupts */
static char *cn93_non_ioq_msix_names[] = { static char *cn93_non_ioq_msix_names[] = {
"epf_ire_rint", "epf_ire_rint",
...@@ -198,7 +204,9 @@ static void octep_init_config_cn93_pf(struct octep_device *oct) ...@@ -198,7 +204,9 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
{ {
struct octep_config *conf = oct->conf; struct octep_config *conf = oct->conf;
struct pci_dev *pdev = oct->pdev; struct pci_dev *pdev = oct->pdev;
u8 link = 0;
u64 val; u64 val;
int pos;
/* Read ring configuration: /* Read ring configuration:
* PF ring count, number of VFs and rings per VF supported * 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) ...@@ -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.ioq_msix = conf->pf_ring_cfg.active_io_rings;
conf->msix_cfg.non_ioq_msix_names = cn93_non_ioq_msix_names; 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 */ /* 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) ...@@ -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); mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
} }
/* Mailbox Interrupt handler */ /* Process non-ioq interrupts required to keep pf interface running.
static void cn93_handle_pf_mbox_intr(struct octep_device *oct) * 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); /* Check for OEI INTR */
for (qno = 0; qno < OCTEP_MAX_VF; qno++) { reg0 = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
val = readq(oct->mbox[qno]->mbox_read_reg); if (reg0) {
dev_dbg(&oct->pdev->dev, dev_info(&oct->pdev->dev,
"PF MBOX READ: val:%llx from VF:%llx\n", val, qno); "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. */ /* Interrupts handler for all non-queue generic interrupts. */
...@@ -434,24 +466,9 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev) ...@@ -434,24 +466,9 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
goto irq_handled; goto irq_handled;
} }
/* Check for MBOX INTR */ /* Check for MBOX INTR and OEI INTR */
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0)); if (octep_poll_non_ioq_interrupts_cn93_pf(oct))
if (reg_val) {
dev_info(&pdev->dev,
"Received MBOX_RINT intr: 0x%llx\n", reg_val);
cn93_handle_pf_mbox_intr(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; goto irq_handled;
}
/* Check for DMA INTR */ /* Check for DMA INTR */
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_RINT); 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) ...@@ -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.enable_interrupts = octep_enable_interrupts_cn93_pf;
oct->hw_ops.disable_interrupts = octep_disable_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; oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cn93_pf;
......
...@@ -200,5 +200,11 @@ struct octep_config { ...@@ -200,5 +200,11 @@ struct octep_config {
/* ctrl mbox config */ /* ctrl mbox config */
struct octep_ctrl_mbox_config ctrl_mbox_cfg; 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_ */ #endif /* _OCTEP_CONFIG_H_ */
...@@ -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.
*/ */
......
...@@ -150,9 +150,12 @@ octep_get_ethtool_stats(struct net_device *netdev, ...@@ -150,9 +150,12 @@ 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);
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;
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++) { for (q = 0; q < oct->num_oqs; q++) {
struct octep_iq *iq = oct->iq[q]; struct octep_iq *iq = oct->iq[q];
...@@ -283,11 +286,11 @@ static int octep_get_link_ksettings(struct net_device *netdev, ...@@ -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, supported);
ethtool_link_ksettings_zero_link_mode(cmd, advertising); 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; advertised_modes = oct->link_info.advertised_modes;
supported_modes = oct->link_info.supported_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(supported_modes, cmd, supported);
OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising); OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);
...@@ -439,7 +442,8 @@ static int octep_set_link_ksettings(struct net_device *netdev, ...@@ -439,7 +442,8 @@ 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, OCTEP_CTRL_NET_INVALID_VFID,
&link_info_new, true);
if (err) if (err)
return err; return err;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "octep_main.h" #include "octep_main.h"
#include "octep_ctrl_net.h" #include "octep_ctrl_net.h"
#define OCTEP_INTR_POLL_TIME_MSECS 100
struct workqueue_struct *octep_wq; struct workqueue_struct *octep_wq;
/* Supported Devices */ /* Supported Devices */
...@@ -506,11 +507,11 @@ static int octep_open(struct net_device *netdev) ...@@ -506,11 +507,11 @@ 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, OCTEP_CTRL_NET_INVALID_VFID, true,
false);
ret = octep_get_link_status(oct); octep_ctrl_net_set_link_status(oct, OCTEP_CTRL_NET_INVALID_VFID, true,
if (!ret) false);
octep_set_link_status(oct, true); 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 */
oct->hw_ops.enable_io_queues(oct); oct->hw_ops.enable_io_queues(oct);
...@@ -520,7 +521,7 @@ static int octep_open(struct net_device *netdev) ...@@ -520,7 +521,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, OCTEP_CTRL_NET_INVALID_VFID);
if (ret > 0) if (ret > 0)
octep_link_up(netdev); octep_link_up(netdev);
...@@ -550,14 +551,16 @@ static int octep_stop(struct net_device *netdev) ...@@ -550,14 +551,16 @@ 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, 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 */ /* 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;
...@@ -572,6 +575,11 @@ static int octep_stop(struct net_device *netdev) ...@@ -572,6 +575,11 @@ static int octep_stop(struct net_device *netdev)
oct->hw_ops.reset_io_queues(oct); oct->hw_ops.reset_io_queues(oct);
octep_free_oqs(oct); octep_free_oqs(oct);
octep_free_iqs(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"); netdev_info(netdev, "Device stopped !!\n");
return 0; return 0;
} }
...@@ -754,7 +762,12 @@ static void octep_get_stats64(struct net_device *netdev, ...@@ -754,7 +762,12 @@ 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,
OCTEP_CTRL_NET_INVALID_VFID,
&oct->iface_rx_stats,
&oct->iface_tx_stats);
tx_packets = 0; tx_packets = 0;
tx_bytes = 0; tx_bytes = 0;
rx_packets = 0; rx_packets = 0;
...@@ -825,7 +838,8 @@ static int octep_set_mac(struct net_device *netdev, void *p) ...@@ -825,7 +838,8 @@ 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, OCTEP_CTRL_NET_INVALID_VFID,
addr->sa_data, true);
if (err) if (err)
return err; return err;
...@@ -845,7 +859,8 @@ static int octep_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -845,7 +859,8 @@ 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, OCTEP_CTRL_NET_INVALID_VFID, 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;
...@@ -864,6 +879,59 @@ static const struct net_device_ops octep_netdev_ops = { ...@@ -864,6 +879,59 @@ static const struct net_device_ops octep_netdev_ops = {
.ndo_change_mtu = octep_change_mtu, .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. * 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) ...@@ -875,34 +943,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 = {}; octep_ctrl_net_recv_fw_messages(oct);
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;
}
}
} }
static const char *octep_devid_to_str(struct octep_device *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) ...@@ -926,7 +968,6 @@ 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, ret;
...@@ -963,19 +1004,14 @@ int octep_device_setup(struct octep_device *oct) ...@@ -963,19 +1004,14 @@ 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 */ ret = octep_ctrl_net_init(oct);
ctrl_mbox = &oct->ctrl_mbox; if (ret)
ctrl_mbox->barmem = CFG_GET_CTRL_MBOX_MEM_ADDR(oct->conf); return ret;
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);
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; return 0;
unsupported_dev: unsupported_dev:
...@@ -1004,7 +1040,8 @@ static void octep_device_cleanup(struct octep_device *oct) ...@@ -1004,7 +1040,8 @@ 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);
cancel_delayed_work_sync(&oct->hb_task);
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++) {
...@@ -1016,6 +1053,26 @@ static void octep_device_cleanup(struct octep_device *oct) ...@@ -1016,6 +1053,26 @@ static void octep_device_cleanup(struct octep_device *oct)
oct->conf = NULL; 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. * 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) ...@@ -1051,6 +1108,12 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev); 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), netdev = alloc_etherdev_mq(sizeof(struct octep_device),
OCTEP_MAX_QUEUES); OCTEP_MAX_QUEUES);
if (!netdev) { if (!netdev) {
...@@ -1073,6 +1136,10 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -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->tx_timeout_task, octep_tx_timeout_task);
INIT_WORK(&octep_dev->ctrl_mbox_task, octep_ctrl_mbox_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; netdev->netdev_ops = &octep_netdev_ops;
octep_set_ethtool_ops(netdev); octep_set_ethtool_ops(netdev);
...@@ -1084,7 +1151,8 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -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->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_CTRL_NET_INVALID_VFID,
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;
...@@ -1133,6 +1201,8 @@ static void octep_remove(struct pci_dev *pdev) ...@@ -1133,6 +1201,8 @@ static void octep_remove(struct pci_dev *pdev)
if (netdev->reg_state == NETREG_REGISTERED) if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev); unregister_netdev(netdev);
oct->poll_non_ioq_intr = false;
cancel_delayed_work_sync(&oct->intr_poll_task);
octep_device_cleanup(oct); octep_device_cleanup(oct);
pci_release_mem_regions(pdev); pci_release_mem_regions(pdev);
free_netdev(netdev); free_netdev(netdev);
......
...@@ -73,6 +73,7 @@ struct octep_hw_ops { ...@@ -73,6 +73,7 @@ struct octep_hw_ops {
void (*enable_interrupts)(struct octep_device *oct); void (*enable_interrupts)(struct octep_device *oct);
void (*disable_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 (*enable_io_queues)(struct octep_device *oct);
void (*disable_io_queues)(struct octep_device *oct); void (*disable_io_queues)(struct octep_device *oct);
...@@ -270,7 +271,22 @@ struct octep_device { ...@@ -270,7 +271,22 @@ struct octep_device {
/* Work entry to handle ctrl mbox interrupt */ /* Work entry to handle ctrl mbox interrupt */
struct work_struct ctrl_mbox_task; 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) static inline u16 OCTEP_MAJOR_REV(struct octep_device *oct)
......
...@@ -364,4 +364,10 @@ ...@@ -364,4 +364,10 @@
/* Number of non-queue interrupts in CN93xx */ /* Number of non-queue interrupts in CN93xx */
#define CN93_NUM_NON_IOQ_INTR 16 #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_ */ #endif /* _OCTEP_REGS_CN9K_PF_H_ */
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