[Intel-wired-lan] [net-next v3 04/15] idpf: add core init and interrupt request

Shannon Nelson shannon.nelson at amd.com
Fri Apr 28 19:50:02 UTC 2023


On 4/26/23 7:09 PM, Emil Tantilov wrote:
> From: Pavan Kumar Linga <pavan.kumar.linga at intel.com>
> 
> As the mailbox is setup, add the necessary send and receive
> mailbox message framework to support the virtchnl communication
> between the driver and device Control Plane (CP).
> 
> Add the core initialization. To start with, driver confirms the
> virtchnl version with the CP. Once that is done, it requests
> and gets the required capabilities and resources needed such as
> max vectors, queues etc.
> 
> Based on the vector information received in 'VIRTCHNL2_OP_GET_CAPS',
> request the stack to allocate the required vectors. Finally add
> the interrupt handling mechanism for the mailbox queue and enable
> the interrupt.
> 
> Note: Checkpatch issues a warning about IDPF_FOREACH_VPORT_VC_STATE and
> IDPF_GEN_STRING being complex macros and should be enclosed in parentheses
> but it's not the case. They are never used as a statement and instead only
> used to define the enum and array.
> 
> Co-developed-by: Alan Brady <alan.brady at intel.com>
> Signed-off-by: Alan Brady <alan.brady at intel.com>
> Co-developed-by: Emil Tantilov <emil.s.tantilov at intel.com>
> Signed-off-by: Emil Tantilov <emil.s.tantilov at intel.com>
> Co-developed-by: Joshua Hay <joshua.a.hay at intel.com>
> Signed-off-by: Joshua Hay <joshua.a.hay at intel.com>
> Co-developed-by: Madhu Chittim <madhu.chittim at intel.com>
> Signed-off-by: Madhu Chittim <madhu.chittim at intel.com>
> Co-developed-by: Phani Burra <phani.r.burra at intel.com>
> Signed-off-by: Phani Burra <phani.r.burra at intel.com>
> Co-developed-by: Shailendra Bhatnagar <shailendra.bhatnagar at intel.com>
> Signed-off-by: Shailendra Bhatnagar <shailendra.bhatnagar at intel.com>
> Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga at intel.com>
> Reviewed-by: Sridhar Samudrala <sridhar.samudrala at intel.com>
> Reviewed-by: Willem de Bruijn <willemb at google.com>
> ---
>   drivers/net/ethernet/intel/idpf/idpf.h        | 137 ++-
>   drivers/net/ethernet/intel/idpf/idpf_dev.c    |  17 +
>   .../ethernet/intel/idpf/idpf_lan_pf_regs.h    |  43 +
>   .../ethernet/intel/idpf/idpf_lan_vf_regs.h    |  38 +
>   drivers/net/ethernet/intel/idpf/idpf_lib.c    | 343 ++++++++
>   drivers/net/ethernet/intel/idpf/idpf_main.c   |  16 +
>   drivers/net/ethernet/intel/idpf/idpf_txrx.h   |  26 +
>   drivers/net/ethernet/intel/idpf/idpf_vf_dev.c |  22 +-
>   .../net/ethernet/intel/idpf/idpf_virtchnl.c   | 801 ++++++++++++++++++
>   9 files changed, 1441 insertions(+), 2 deletions(-)
>   create mode 100644 drivers/net/ethernet/intel/idpf/idpf_txrx.h
> 
> diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
> index 0b3b5259bd43..1bcfa0f0940f 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf.h
> @@ -11,6 +11,8 @@ struct idpf_adapter;
>   #include <linux/etherdevice.h>
>   #include <linux/pci.h>
> 
> +#include "virtchnl2.h"
> +#include "idpf_txrx.h"
>   #include "idpf_controlq.h"
> 
>   /* Default Mailbox settings */
> @@ -18,12 +20,24 @@ struct idpf_adapter;
>   #define IDPF_NUM_DFLT_MBX_Q            2       /* includes both TX and RX */
>   #define IDPF_DFLT_MBX_Q_LEN            64
>   #define IDPF_DFLT_MBX_ID               -1
> +/* maximum number of times to try before resetting mailbox */
> +#define IDPF_MB_MAX_ERR                        20
> +#define IDPF_WAIT_FOR_EVENT_TIMEO_MIN  2000
> +#define IDPF_WAIT_FOR_EVENT_TIMEO      60000
> +
> +#define IDPF_MAX_WAIT                  500
> 
>   /* available message levels */
>   #define IDPF_AVAIL_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
> 
> +#define IDPF_VIRTCHNL_VERSION_MAJOR VIRTCHNL2_VERSION_MAJOR_2
> +#define IDPF_VIRTCHNL_VERSION_MINOR VIRTCHNL2_VERSION_MINOR_0
> +
>   enum idpf_state {
>          __IDPF_STARTUP,
> +       __IDPF_VER_CHECK,
> +       __IDPF_GET_CAPS,
> +       __IDPF_INIT_SW,
>          __IDPF_STATE_LAST /* this member MUST be last */
>   };
> 
> @@ -37,6 +51,16 @@ enum idpf_flags {
>          __IDPF_HR_DRV_LOAD,
>          /* Reset in progress */
>          __IDPF_HR_RESET_IN_PROG,
> +       /* Resources release in progress*/
> +       __IDPF_REL_RES_IN_PROG,
> +       /* Generic bits to share a message */
> +       /* Mailbox interrupt event */
> +       __IDPF_MB_INTR_MODE,
> +       __IDPF_MB_INTR_TRIGGER,
> +       /* Virtchnl message buffer received needs to be processed */
> +       __IDPF_VC_MSG_PENDING,
> +       /* Do not schedule service task if bit is set */
> +       __IDPF_CANCEL_SERVICE_TASK,
>          /* Driver remove in progress */
>          __IDPF_REMOVE_IN_PROG,
>          /* must be last */
> @@ -53,6 +77,7 @@ struct idpf_reset_reg {
>   /* product specific register API */
>   struct idpf_reg_ops {
>          void (*ctlq_reg_init)(struct idpf_ctlq_create_info *cq);
> +       void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
>          void (*reset_reg_init)(struct idpf_adapter *adapter);
>          void (*trigger_reset)(struct idpf_adapter *adapter,
>                                enum idpf_flags trig_cause);
> @@ -62,22 +87,104 @@ struct idpf_dev_ops {
>          struct idpf_reg_ops reg_ops;
>   };
> 
> +/* These macros allow us to generate an enum and a matching char * array of
> + * stringified enums that are always in sync. Checkpatch issues a bogus warning
> + * about this being a complex macro; but it's wrong, these are never used as a
> + * statement and instead only used to define the enum and array.
> + */
> +#define IDPF_FOREACH_VPORT_VC_STATE(STATE)     \
> +       STATE(IDPF_VC_ALLOC_VECTORS)            \
> +       STATE(IDPF_VC_ALLOC_VECTORS_ERR)        \
> +       STATE(IDPF_VC_DEALLOC_VECTORS)          \
> +       STATE(IDPF_VC_DEALLOC_VECTORS_ERR)      \
> +       STATE(IDPF_VC_NBITS)
> +
> +#define IDPF_GEN_ENUM(ENUM) ENUM,
> +#define IDPF_GEN_STRING(STRING) #STRING,
> +
> +enum idpf_vport_vc_state {
> +       IDPF_FOREACH_VPORT_VC_STATE(IDPF_GEN_ENUM)
> +};
> +
> +extern const char * const idpf_vport_vc_state_str[];
> +
> +struct idpf_vport {
> +       u32 vport_id;
> +};
> +
> +/* Stack to maintain vector indexes used for 'vector distribution' algorithm */
> +struct idpf_vector_lifo {
> +       /* Vector stack maintains all the relative vector indexes at the
> +        * *adapter* level. This stack is divided into 2 parts, first one is
> +        * called as 'default pool' and other one is called 'free pool'.
> +        * Vector distribution algorithm gives priority to default vports in
> +        * a way that at least IDPF_MIN_Q_VEC vectors are allocated per
> +        * default vport and the relative vector indexes for those are
> +        * maintained in default pool. Free pool contains all the unallocated
> +        * vector indexes which can be allocated on-demand basis.
> +        * Mailbox vector index is maintained in the default pool of the stack.
> +        */
> +       u16 top;        /* Points to stack top i.e. next available vector index */
> +       u16 base;       /* Always points to start of the 'free pool' */
> +       u16 size;       /* Total size of the vector stack */
> +       u16 *vec_idx;   /* Array to store all the vector indexes */
> +};
> +
>   struct idpf_adapter {
>          struct pci_dev *pdev;
> +       u32 virt_ver_maj;
> +       u32 virt_ver_min;
> +
>          u32 msg_enable;
> +       u32 mb_wait_count;
>          enum idpf_state state;
>          DECLARE_BITMAP(flags, __IDPF_FLAGS_NBITS);
>          struct idpf_reset_reg reset_reg;
>          struct idpf_hw hw;
> -
> +       u16 num_req_msix;
> +       u16 num_avail_msix;
> +       u16 num_msix_entries;
> +       struct msix_entry *msix_entries;
> +       struct virtchnl2_alloc_vectors *req_vec_chunks;
> +       struct idpf_q_vector mb_vector;
> +       /* Stack to store the msix vector indexes */
> +       struct idpf_vector_lifo vector_stack;
> +       /* handler for hard interrupt for mailbox*/
> +       irqreturn_t (*irq_mb_handler)(int irq, void *data);
> +
> +       struct delayed_work serv_task; /* delayed service task */
> +       struct workqueue_struct *serv_wq;
>          struct delayed_work vc_event_task; /* delayed virtchannel event task */
>          struct workqueue_struct *vc_event_wq;
> +       struct virtchnl2_get_capabilities caps;
> 
> +       wait_queue_head_t vchnl_wq;
> +       DECLARE_BITMAP(vc_state, IDPF_VC_NBITS);
> +       char vc_msg[IDPF_DFLT_MBX_BUF_SIZE];
>          struct idpf_dev_ops dev_ops;
> 
>          struct mutex reset_lock;        /* lock to protect reset flows */
> +       struct mutex vector_lock;       /* lock to protect vector distribution */
>   };
> 
> +/**
> + * idpf_get_reserved_vecs - Get reserved vectors
> + * @adapter: private data struct
> + */
> +static inline u16 idpf_get_reserved_vecs(struct idpf_adapter *adapter)
> +{
> +       return le16_to_cpu(adapter->caps.num_allocated_vectors);
> +}
> +
> +/**
> + * idpf_get_default_vports - Get default number of vports
> + * @adapter: private data struct
> + */
> +static inline u16 idpf_get_default_vports(struct idpf_adapter *adapter)
> +{
> +       return le16_to_cpu(adapter->caps.default_num_vports);
> +}
> +
>   /**
>    * idpf_get_reg_addr - Get BAR0 register address
>    * @adapter: private data struct
> @@ -106,10 +213,38 @@ static inline bool idpf_is_reset_detected(struct idpf_adapter *adapter)
>                   adapter->hw.arq->reg.len_ena_mask);
>   }
> 
> +/**
> + * idpf_is_reset_in_prog - check if reset is in progress
> + * @adapter: driver specific private structure
> + *
> + * Returns true if hard reset is in progress, false otherwise
> + */
> +static inline bool idpf_is_reset_in_prog(struct idpf_adapter *adapter)
> +{
> +       return (test_bit(__IDPF_HR_RESET_IN_PROG, adapter->flags) ||
> +               test_bit(__IDPF_HR_FUNC_RESET, adapter->flags) ||
> +               test_bit(__IDPF_HR_CORE_RESET, adapter->flags) ||
> +               test_bit(__IDPF_HR_DRV_LOAD, adapter->flags));
> +}
> +
> +void idpf_service_task(struct work_struct *work);
>   void idpf_vc_event_task(struct work_struct *work);
>   void idpf_dev_ops_init(struct idpf_adapter *adapter);
>   void idpf_vf_dev_ops_init(struct idpf_adapter *adapter);
>   int idpf_init_dflt_mbx(struct idpf_adapter *adapter);
>   void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);
> +int idpf_vc_core_init(struct idpf_adapter *adapter);
> +void idpf_vc_core_deinit(struct idpf_adapter *adapter);
> +int idpf_intr_req(struct idpf_adapter *adapter);
> +void idpf_intr_rel(struct idpf_adapter *adapter);
> +int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter);
> +int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors);
> +int idpf_get_vec_ids(struct idpf_adapter *adapter,
> +                    u16 *vecids, int num_vecids,
> +                    struct virtchnl2_vector_chunks *chunks);
> +int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op,
> +                    void *msg, int msg_size);
> +int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
> +                    u16 msg_size, u8 *msg);
> 
>   #endif /* !_IDPF_H_ */
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
> index 7c0c8a14aba9..11cc33eb0b44 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
> @@ -44,6 +44,22 @@ static void idpf_ctlq_reg_init(struct idpf_ctlq_create_info *cq)
>          }
>   }
> 
> +/**
> + * idpf_mb_intr_reg_init - Initialize mailbox interrupt register
> + * @adapter: adapter structure
> + */
> +static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
> +{
> +       struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
> +       u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
> +
> +       intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
> +       intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
> +       intr->dyn_ctl_itridx_m = PF_GLINT_DYN_CTL_ITR_INDX_M;
> +       intr->icr_ena = idpf_get_reg_addr(adapter, PF_INT_DIR_OICR_ENA);
> +       intr->icr_ena_ctlq_m = PF_INT_DIR_OICR_ENA_M;
> +}
> +
>   /**
>    * idpf_reset_reg_init - Initialize reset registers
>    * @adapter: Driver specific private structure
> @@ -75,6 +91,7 @@ static void idpf_trigger_reset(struct idpf_adapter *adapter,
>   static void idpf_reg_ops_init(struct idpf_adapter *adapter)
>   {
>          adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_ctlq_reg_init;
> +       adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_mb_intr_reg_init;
>          adapter->dev_ops.reg_ops.reset_reg_init = idpf_reset_reg_init;
>          adapter->dev_ops.reg_ops.trigger_reset = idpf_trigger_reset;
>   }
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h b/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h
> index 9cc9610990b4..a832319f535c 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h
> @@ -53,6 +53,49 @@
>   #define PF_FW_ATQH_ATQH_M              GENMASK(9, 0)
>   #define PF_FW_ATQT                     (PF_FW_BASE + 0x24)
> 
> +/* Interrupts */
> +#define PF_GLINT_BASE                  0x08900000
> +#define PF_GLINT_DYN_CTL(_INT)         (PF_GLINT_BASE + ((_INT) * 0x1000))
> +#define PF_GLINT_DYN_CTL_INTENA_S      0
> +#define PF_GLINT_DYN_CTL_INTENA_M      BIT(PF_GLINT_DYN_CTL_INTENA_S)
> +#define PF_GLINT_DYN_CTL_CLEARPBA_S    1
> +#define PF_GLINT_DYN_CTL_CLEARPBA_M    BIT(PF_GLINT_DYN_CTL_CLEARPBA_S)
> +#define PF_GLINT_DYN_CTL_SWINT_TRIG_S  2
> +#define PF_GLINT_DYN_CTL_SWINT_TRIG_M  BIT(PF_GLINT_DYN_CTL_SWINT_TRIG_S)
> +#define PF_GLINT_DYN_CTL_ITR_INDX_S    3
> +#define PF_GLINT_DYN_CTL_ITR_INDX_M    GENMASK(4, 3)
> +#define PF_GLINT_DYN_CTL_INTERVAL_S    5
> +#define PF_GLINT_DYN_CTL_INTERVAL_M    BIT(PF_GLINT_DYN_CTL_INTERVAL_S)
> +#define PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_S     24
> +#define PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M BIT(PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_S)
> +#define PF_GLINT_DYN_CTL_SW_ITR_INDX_S 25
> +#define PF_GLINT_DYN_CTL_SW_ITR_INDX_M BIT(PF_GLINT_DYN_CTL_SW_ITR_INDX_S)
> +#define PF_GLINT_DYN_CTL_WB_ON_ITR_S   30
> +#define PF_GLINT_DYN_CTL_WB_ON_ITR_M   BIT(PF_GLINT_DYN_CTL_WB_ON_ITR_S)
> +#define PF_GLINT_DYN_CTL_INTENA_MSK_S  31
> +#define PF_GLINT_DYN_CTL_INTENA_MSK_M  BIT(PF_GLINT_DYN_CTL_INTENA_MSK_S)
> +
> +/* Generic registers */
> +#define PF_INT_DIR_OICR_ENA            0x08406000
> +#define PF_INT_DIR_OICR_ENA_S          0
> +#define PF_INT_DIR_OICR_ENA_M          GENMASK(31, 0)
> +#define PF_INT_DIR_OICR                        0x08406004
> +#define PF_INT_DIR_OICR_TSYN_EVNT      0
> +#define PF_INT_DIR_OICR_PHY_TS_0       BIT(1)
> +#define PF_INT_DIR_OICR_PHY_TS_1       BIT(2)
> +#define PF_INT_DIR_OICR_CAUSE          0x08406008
> +#define PF_INT_DIR_OICR_CAUSE_CAUSE_S  0
> +#define PF_INT_DIR_OICR_CAUSE_CAUSE_M  GENMASK(31, 0)
> +#define PF_INT_PBA_CLEAR               0x0840600C
> +
> +#define PF_FUNC_RID                    0x08406010
> +#define PF_FUNC_RID_FUNCTION_NUMBER_S  0
> +#define PF_FUNC_RID_FUNCTION_NUMBER_M  GENMASK(2, 0)
> +#define PF_FUNC_RID_DEVICE_NUMBER_S    3
> +#define PF_FUNC_RID_DEVICE_NUMBER_M    GENMASK(7, 3)
> +#define PF_FUNC_RID_BUS_NUMBER_S       8
> +#define PF_FUNC_RID_BUS_NUMBER_M       GENMASK(15, 8)
> +
>   /* Reset registers */
>   #define PFGEN_RTRIG                    0x08407000
>   #define PFGEN_RTRIG_CORER_S            0
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_lan_vf_regs.h b/drivers/net/ethernet/intel/idpf/idpf_lan_vf_regs.h
> index 8040bedea2fd..d1bff18e2a7d 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_lan_vf_regs.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf_lan_vf_regs.h
> @@ -62,4 +62,42 @@
>   #define VF_QRXB_TAIL_BASE              0x00060000
>   #define VF_QRXB_TAIL(_QRX)             (VF_QRXB_TAIL_BASE + ((_QRX) * 4))
> 
> +/* Interrupts */
> +#define VF_INT_DYN_CTL0                        0x00005C00
> +#define VF_INT_DYN_CTL0_INTENA_S       0
> +#define VF_INT_DYN_CTL0_INTENA_M       BIT(VF_INT_DYN_CTL0_INTENA_S)
> +#define VF_INT_DYN_CTL0_ITR_INDX_S     3
> +#define VF_INT_DYN_CTL0_ITR_INDX_M     GENMASK(4, 3)
> +#define VF_INT_DYN_CTLN(_INT)          (0x00003800 + ((_INT) * 4))
> +#define VF_INT_DYN_CTLN_EXT(_INT)      (0x00070000 + ((_INT) * 4))
> +#define VF_INT_DYN_CTLN_INTENA_S       0
> +#define VF_INT_DYN_CTLN_INTENA_M       BIT(VF_INT_DYN_CTLN_INTENA_S)
> +#define VF_INT_DYN_CTLN_CLEARPBA_S     1
> +#define VF_INT_DYN_CTLN_CLEARPBA_M     BIT(VF_INT_DYN_CTLN_CLEARPBA_S)
> +#define VF_INT_DYN_CTLN_SWINT_TRIG_S   2
> +#define VF_INT_DYN_CTLN_SWINT_TRIG_M   BIT(VF_INT_DYN_CTLN_SWINT_TRIG_S)
> +#define VF_INT_DYN_CTLN_ITR_INDX_S     3
> +#define VF_INT_DYN_CTLN_ITR_INDX_M     GENMASK(4, 3)
> +#define VF_INT_DYN_CTLN_INTERVAL_S     5
> +#define VF_INT_DYN_CTLN_INTERVAL_M     BIT(VF_INT_DYN_CTLN_INTERVAL_S)
> +#define VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_S 24
> +#define VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M BIT(VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_S)
> +#define VF_INT_DYN_CTLN_SW_ITR_INDX_S  25
> +#define VF_INT_DYN_CTLN_SW_ITR_INDX_M  BIT(VF_INT_DYN_CTLN_SW_ITR_INDX_S)
> +#define VF_INT_DYN_CTLN_WB_ON_ITR_S    30
> +#define VF_INT_DYN_CTLN_WB_ON_ITR_M    BIT(VF_INT_DYN_CTLN_WB_ON_ITR_S)
> +#define VF_INT_DYN_CTLN_INTENA_MSK_S   31
> +#define VF_INT_DYN_CTLN_INTENA_MSK_M   BIT(VF_INT_DYN_CTLN_INTENA_MSK_S)
> +
> +#define VF_INT_ICR0_ENA1               0x00005000
> +#define VF_INT_ICR0_ENA1_ADMINQ_S      30
> +#define VF_INT_ICR0_ENA1_ADMINQ_M      BIT(VF_INT_ICR0_ENA1_ADMINQ_S)
> +#define VF_INT_ICR0_ENA1_RSVD_S                31
> +#define VF_INT_ICR01                   0x00004800
> +#define VF_QF_HENA(_i)                 (0x0000C400 + ((_i) * 4))
> +#define VF_QF_HENA_MAX_INDX            1
> +#define VF_QF_HKEY(_i)                 (0x0000CC00 + ((_i) * 4))
> +#define VF_QF_HKEY_MAX_INDX            12
> +#define VF_QF_HLUT(_i)                 (0x0000D000 + ((_i) * 4))
> +#define VF_QF_HLUT_MAX_INDX            15
>   #endif
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> index d4f346312915..1399fcd8ae98 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
> @@ -3,6 +3,333 @@
> 
>   #include "idpf.h"
> 
> +const char * const idpf_vport_vc_state_str[] = {
> +       IDPF_FOREACH_VPORT_VC_STATE(IDPF_GEN_STRING)
> +};
> +
> +/**
> + * idpf_init_vector_stack - Fill the MSIX vector stack with vector index
> + * @adapter: private data struct
> + *
> + * Return 0 on success, error on failure
> + */
> +static int idpf_init_vector_stack(struct idpf_adapter *adapter)
> +{
> +       struct idpf_vector_lifo *stack;
> +       u16 min_vec;
> +       u32 i;
> +
> +       mutex_lock(&adapter->vector_lock);
> +       min_vec = adapter->num_msix_entries - adapter->num_avail_msix;
> +       stack = &adapter->vector_stack;
> +       stack->size = adapter->num_msix_entries;
> +       /* set the base and top to point at start of the 'free pool' to
> +        * distribute the unused vectors on-demand basis
> +        */
> +       stack->base = min_vec;
> +       stack->top = min_vec;
> +
> +       stack->vec_idx = kcalloc(stack->size, sizeof(u16), GFP_KERNEL);
> +       if (!stack->vec_idx) {
> +               mutex_unlock(&adapter->vector_lock);
> +
> +               return -ENOMEM;
> +       }
> +
> +       for (i = 0; i < stack->size; i++)
> +               stack->vec_idx[i] = i;
> +
> +       mutex_unlock(&adapter->vector_lock);
> +
> +       return 0;
> +}
> +
> +/**
> + * idpf_deinit_vector_stack - zero out the MSIX vector stack
> + * @adapter: private data struct
> + */
> +static void idpf_deinit_vector_stack(struct idpf_adapter *adapter)
> +{
> +       struct idpf_vector_lifo *stack;
> +
> +       mutex_lock(&adapter->vector_lock);
> +       stack = &adapter->vector_stack;
> +       kfree(stack->vec_idx);
> +       stack->vec_idx = NULL;
> +       mutex_unlock(&adapter->vector_lock);
> +}
> +
> +/**
> + * idpf_mb_intr_rel_irq - Free the IRQ association with the OS
> + * @adapter: adapter structure
> + */
> +static void idpf_mb_intr_rel_irq(struct idpf_adapter *adapter)
> +{
> +       free_irq(adapter->msix_entries[0].vector, adapter);
> +}
> +
> +/**
> + * idpf_intr_rel - Release interrupt capabilities and free memory
> + * @adapter: adapter to disable interrupts on
> + */
> +void idpf_intr_rel(struct idpf_adapter *adapter)
> +{
> +       int err;
> +
> +       if (!adapter->msix_entries)
> +               return;
> +
> +       clear_bit(__IDPF_MB_INTR_MODE, adapter->flags);
> +       clear_bit(__IDPF_MB_INTR_TRIGGER, adapter->flags);
> +
> +       idpf_mb_intr_rel_irq(adapter);
> +       pci_free_irq_vectors(adapter->pdev);
> +
> +       err = idpf_send_dealloc_vectors_msg(adapter);
> +       if (err)
> +               dev_err(&adapter->pdev->dev,
> +                       "Failed to deallocate vectors: %d\n", err);
> +
> +       idpf_deinit_vector_stack(adapter);
> +       kfree(adapter->msix_entries);
> +       adapter->msix_entries = NULL;
> +}
> +
> +/**
> + * idpf_mb_intr_clean - Interrupt handler for the mailbox
> + * @irq: interrupt number
> + * @data: pointer to the adapter structure
> + */
> +static irqreturn_t idpf_mb_intr_clean(int __always_unused irq, void *data)
> +{
> +       struct idpf_adapter *adapter = (struct idpf_adapter *)data;
> +
> +       set_bit(__IDPF_MB_INTR_TRIGGER, adapter->flags);
> +       mod_delayed_work(adapter->serv_wq, &adapter->serv_task,
> +                        msecs_to_jiffies(0));
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/**
> + * idpf_mb_irq_enable - Enable MSIX interrupt for the mailbox
> + * @adapter: adapter to get the hardware address for register write
> + */
> +static void idpf_mb_irq_enable(struct idpf_adapter *adapter)
> +{
> +       struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
> +       u32 val;
> +
> +       val = intr->dyn_ctl_intena_m | intr->dyn_ctl_itridx_m;
> +       writel(val, intr->dyn_ctl);
> +       writel(intr->icr_ena_ctlq_m, intr->icr_ena);
> +}
> +
> +/**
> + * idpf_mb_intr_req_irq - Request irq for the mailbox interrupt
> + * @adapter: adapter structure to pass to the mailbox irq handler
> + */
> +static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
> +{
> +       struct idpf_q_vector *mb_vector = &adapter->mb_vector;
> +       int irq_num, mb_vidx = 0, err;
> +
> +       irq_num = adapter->msix_entries[mb_vidx].vector;
> +       snprintf(mb_vector->name, sizeof(mb_vector->name) - 1,
> +                "%s-%s-%d", dev_driver_string(&adapter->pdev->dev),
> +                "Mailbox", mb_vidx);
> +       err = request_irq(irq_num, adapter->irq_mb_handler, 0,
> +                         mb_vector->name, adapter);
> +       if (err) {
> +               dev_err(&adapter->pdev->dev,
> +                       "IRQ request for mailbox failed, error: %d\n", err);
> +
> +               return err;
> +       }
> +
> +       set_bit(__IDPF_MB_INTR_MODE, adapter->flags);
> +
> +       return 0;
> +}
> +
> +/**
> + * idpf_set_mb_vec_id - Set vector index for mailbox
> + * @adapter: adapter structure to access the vector chunks
> + *
> + * The first vector id in the requested vector chunks from the CP is for
> + * the mailbox
> + */
> +static void idpf_set_mb_vec_id(struct idpf_adapter *adapter)
> +{
> +       if (adapter->req_vec_chunks)
> +               adapter->mb_vector.v_idx =
> +                       le16_to_cpu(adapter->caps.mailbox_vector_id);
> +       else
> +               adapter->mb_vector.v_idx = 0;
> +}
> +
> +/**
> + * idpf_mb_intr_init - Initialize the mailbox interrupt
> + * @adapter: adapter structure to store the mailbox vector
> + */
> +static int idpf_mb_intr_init(struct idpf_adapter *adapter)
> +{
> +       adapter->dev_ops.reg_ops.mb_intr_reg_init(adapter);
> +       adapter->irq_mb_handler = idpf_mb_intr_clean;
> +
> +       return idpf_mb_intr_req_irq(adapter);
> +}
> +
> +/**
> + * idpf_intr_req - Request interrupt capabilities
> + * @adapter: adapter to enable interrupts on
> + *
> + * Returns 0 on success, negative on failure
> + */
> +int idpf_intr_req(struct idpf_adapter *adapter)
> +{
> +       u16 default_vports = idpf_get_default_vports(adapter);
> +       int num_q_vecs, total_vecs, num_vec_ids;
> +       int min_vectors, v_actual, err = 0;
> +       unsigned int vector;
> +       u16 *vecids;
> +
> +       total_vecs = idpf_get_reserved_vecs(adapter);
> +       num_q_vecs = total_vecs - IDPF_MBX_Q_VEC;
> +
> +       err = idpf_send_alloc_vectors_msg(adapter, num_q_vecs);
> +       if (err) {
> +               dev_err(&adapter->pdev->dev,
> +                       "Failed to allocate vectors: %d\n", err);

To aid in debugging, it would be good to include the number of vectors 
in these error messages.

> +
> +               return -EAGAIN;
> +       }
> +
> +       min_vectors = IDPF_MBX_Q_VEC + IDPF_MIN_Q_VEC * default_vports;
> +       v_actual = pci_alloc_irq_vectors(adapter->pdev, min_vectors,
> +                                        total_vecs, PCI_IRQ_MSIX);
> +       if (v_actual < min_vectors) {
> +               dev_err(&adapter->pdev->dev, "Failed to allocate MSIX vectors: %d\n",
> +                       v_actual);
> +               err = -EAGAIN;
> +               goto send_dealloc_vecs;
> +       }
> +
> +       adapter->msix_entries = kcalloc(v_actual, sizeof(struct msix_entry),
> +                                       GFP_KERNEL);
> +
> +       if (!adapter->msix_entries) {
> +               err = -ENOMEM;
> +               goto free_irq;
> +       }
> +
> +       idpf_set_mb_vec_id(adapter);
> +
> +       vecids = kcalloc(total_vecs, sizeof(u16), GFP_KERNEL);
> +       if (!vecids) {
> +               err = -ENOMEM;
> +               goto free_msix;
> +       }
> +
> +       if (adapter->req_vec_chunks) {
> +               struct virtchnl2_vector_chunks *vchunks;
> +               struct virtchnl2_alloc_vectors *ac;
> +
> +               ac = adapter->req_vec_chunks;
> +               vchunks = &ac->vchunks;
> +
> +               num_vec_ids = idpf_get_vec_ids(adapter, vecids, total_vecs,
> +                                              vchunks);
> +               if (num_vec_ids < v_actual) {
> +                       err = -EINVAL;
> +                       goto free_vecids;
> +               }
> +       } else {
> +               int i = 0;

zero init unnecessary
for that matter, I've recently seen someone using
	for (int i = 0; ...
in simple local for-loops
I'm not sure that's an accepted practice yet, but would make sense here

> +
> +               for (i = 0; i < v_actual; i++)
> +                       vecids[i] = i;
> +       }
> +
> +       for (vector = 0; vector < v_actual; vector++) {
> +               adapter->msix_entries[vector].entry = vecids[vector];
> +               adapter->msix_entries[vector].vector =
> +                       pci_irq_vector(adapter->pdev, vector);
> +       }
> +
> +       adapter->num_req_msix = total_vecs;
> +       adapter->num_msix_entries = v_actual;
> +       /* 'num_avail_msix' is used to distribute excess vectors to the vports
> +        * after considering the minimum vectors required per each default
> +        * vport
> +        */
> +       adapter->num_avail_msix = v_actual - min_vectors;
> +
> +       /* Fill MSIX vector lifo stack with vector indexes */
> +       err = idpf_init_vector_stack(adapter);
> +       if (err)
> +               goto free_vecids;
> +
> +       err = idpf_mb_intr_init(adapter);
> +       if (err)
> +               goto deinit_vec_stack;
> +       idpf_mb_irq_enable(adapter);
> +       kfree(vecids);
> +
> +       return err;
> +
> +deinit_vec_stack:
> +       idpf_deinit_vector_stack(adapter);
> +free_vecids:
> +       kfree(vecids);
> +free_msix:
> +       kfree(adapter->msix_entries);
> +       adapter->msix_entries = NULL;
> +free_irq:
> +       pci_free_irq_vectors(adapter->pdev);
> +send_dealloc_vecs:
> +       idpf_send_dealloc_vectors_msg(adapter);
> +
> +       return err;
> +}
> +
> +/**
> + * idpf_service_task - Delayed task for handling mailbox responses
> + * @work: work_struct handle to our data
> + *
> + */
> +void idpf_service_task(struct work_struct *work)
> +{
> +       struct idpf_adapter *adapter;
> +
> +       adapter = container_of(work, struct idpf_adapter, serv_task.work);
> +
> +       if (test_bit(__IDPF_MB_INTR_MODE, adapter->flags)) {
> +               if (test_and_clear_bit(__IDPF_MB_INTR_TRIGGER,
> +                                      adapter->flags)) {
> +                       idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_UNKNOWN,
> +                                        NULL, 0);
> +                       idpf_mb_irq_enable(adapter);
> +               }
> +       } else {
> +               idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_UNKNOWN, NULL, 0);
> +       }
> +
> +       if (idpf_is_reset_detected(adapter) &&
> +           !idpf_is_reset_in_prog(adapter) &&
> +           !test_bit(__IDPF_REMOVE_IN_PROG, adapter->flags)) {
> +               dev_info(&adapter->pdev->dev, "HW reset detected\n");
> +               set_bit(__IDPF_HR_FUNC_RESET, adapter->flags);

Is there any chance of some other thread starting a reset in the time 
between your is_reset_in_progress check and setting this FUNC_RESET bit?

> +               queue_delayed_work(adapter->vc_event_wq,
> +                                  &adapter->vc_event_task,
> +                                  msecs_to_jiffies(10));
> +       }
> +
> +       if (!test_bit(__IDPF_CANCEL_SERVICE_TASK, adapter->flags))
> +               queue_delayed_work(adapter->serv_wq, &adapter->serv_task,
> +                                  msecs_to_jiffies(300));
> +}
> +
>   /**
>    * idpf_check_reset_complete - check that reset is complete
>    * @hw: pointer to hw struct
> @@ -61,9 +388,12 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
>          } else if (test_and_clear_bit(__IDPF_HR_FUNC_RESET, adapter->flags)) {
>                  bool is_reset = idpf_is_reset_detected(adapter);
> 
> +               idpf_vc_core_deinit(adapter);
>                  if (!is_reset)
>                          reg_ops->trigger_reset(adapter, __IDPF_HR_FUNC_RESET);
>                  idpf_deinit_dflt_mbx(adapter);
> +       } else if (test_and_clear_bit(__IDPF_HR_CORE_RESET, adapter->flags)) {
> +               idpf_vc_core_deinit(adapter);
>          } else {
>                  dev_err(dev, "Unhandled hard reset cause\n");
>                  err = -EBADRQC;
> @@ -83,6 +413,19 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
>          if (err)
>                  dev_err(dev, "Failed to initialize default mailbox: %d\n", err);
> 
> +       /* Initialize the state machine, also allocate memory and request
> +        * resources
> +        */
> +       err = idpf_vc_core_init(adapter);
> +       if (err)
> +               goto init_err;
> +
> +       mutex_unlock(&adapter->reset_lock);
> +
> +       return 0;
> +
> +init_err:
> +       idpf_deinit_dflt_mbx(adapter);
>   handle_err:
>          mutex_unlock(&adapter->reset_lock);
> 
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
> index 4bb0727f7abd..895451cdfa79 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_main.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
> @@ -25,12 +25,14 @@ static void idpf_remove(struct pci_dev *pdev)
>           * end up in bad state.
>           */
>          cancel_delayed_work_sync(&adapter->vc_event_task);
> +       idpf_vc_core_deinit(adapter);
>          /* Be a good citizen and leave the device clean on exit */
>          adapter->dev_ops.reg_ops.trigger_reset(adapter, __IDPF_HR_FUNC_RESET);
>          idpf_deinit_dflt_mbx(adapter);
> 
>          destroy_workqueue(adapter->vc_event_wq);
>          mutex_destroy(&adapter->reset_lock);
> +       mutex_destroy(&adapter->vector_lock);
> 
>          pci_disable_pcie_error_reporting(pdev);
>          pci_set_drvdata(pdev, NULL);
> @@ -127,6 +129,15 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>          pci_set_master(pdev);
>          pci_set_drvdata(pdev, adapter);
> 
> +       adapter->serv_wq = alloc_workqueue("%s-%s-service", 0, 0,
> +                                          dev_driver_string(dev),
> +                                          dev_name(dev));
> +       if (!adapter->serv_wq) {
> +               dev_err(dev, "Failed to allocate service workqueue\n");
> +               err = -ENOMEM;
> +               goto err_mbx_wq_alloc;
> +       }
> +
>          adapter->vc_event_wq = alloc_workqueue("%s-%s-vc_event", 0, 0,
>                                                 dev_driver_string(dev),
>                                                 dev_name(dev));
> @@ -147,7 +158,10 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>          }
> 
>          mutex_init(&adapter->reset_lock);
> +       mutex_init(&adapter->vector_lock);
> +       init_waitqueue_head(&adapter->vchnl_wq);
> 
> +       INIT_DELAYED_WORK(&adapter->serv_task, idpf_service_task);
>          INIT_DELAYED_WORK(&adapter->vc_event_task, idpf_vc_event_task);
> 
>          adapter->dev_ops.reg_ops.reset_reg_init(adapter);
> @@ -160,6 +174,8 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>   err_cfg_hw:
>          destroy_workqueue(adapter->vc_event_wq);
>   err_vc_event_wq_alloc:
> +       destroy_workqueue(adapter->serv_wq);
> +err_mbx_wq_alloc:
>          pci_disable_pcie_error_reporting(pdev);
>   err_free:
>          kfree(adapter);
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> new file mode 100644
> index 000000000000..32f312dbf22b
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2023 Intel Corporation */
> +
> +#ifndef _IDPF_TXRX_H_
> +#define _IDPF_TXRX_H_
> +
> +/* Default vector sharing */
> +#define IDPF_MBX_Q_VEC         1
> +#define IDPF_MIN_Q_VEC         1
> +
> +#define IDPF_INT_NAME_STR_LEN   (IFNAMSIZ + 16)
> +
> +struct idpf_intr_reg {
> +       void __iomem *dyn_ctl;
> +       u32 dyn_ctl_intena_m;
> +       u32 dyn_ctl_itridx_m;
> +       void __iomem *icr_ena;
> +       u32 icr_ena_ctlq_m;
> +};
> +
> +struct idpf_q_vector {
> +       u16 v_idx;              /* index in the vport->q_vector array */
> +       struct idpf_intr_reg intr_reg;
> +       char name[IDPF_INT_NAME_STR_LEN];
> +};
> +#endif /* !_IDPF_TXRX_H_ */
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> index facf525e8e44..40ece76cbc16 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> @@ -44,6 +44,22 @@ static void idpf_vf_ctlq_reg_init(struct idpf_ctlq_create_info *cq)
>          }
>   }
> 
> +/**
> + * idpf_vf_mb_intr_reg_init - Initialize the mailbox register
> + * @adapter: adapter structure
> + */
> +static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter)
> +{
> +       struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
> +       u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
> +
> +       intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
> +       intr->dyn_ctl_intena_m = VF_INT_DYN_CTL0_INTENA_M;
> +       intr->dyn_ctl_itridx_m = VF_INT_DYN_CTL0_ITR_INDX_M;
> +       intr->icr_ena = idpf_get_reg_addr(adapter, VF_INT_ICR0_ENA1);
> +       intr->icr_ena_ctlq_m = VF_INT_ICR0_ENA1_ADMINQ_M;
> +}
> +
>   /**
>    * idpf_vf_reset_reg_init - Initialize reset registers
>    * @adapter: Driver specific private structure
> @@ -62,7 +78,10 @@ static void idpf_vf_reset_reg_init(struct idpf_adapter *adapter)
>   static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,
>                                    enum idpf_flags trig_cause)
>   {
> -       /* stub */
> +       /* Do not send VIRTCHNL2_OP_RESET_VF message on driver unload */
> +       if (trig_cause == __IDPF_HR_FUNC_RESET &&
> +           !test_bit(__IDPF_REMOVE_IN_PROG, adapter->flags))
> +               idpf_send_mb_msg(adapter, VIRTCHNL2_OP_RESET_VF, 0, NULL);
>   }
> 
>   /**
> @@ -72,6 +91,7 @@ static void idpf_vf_trigger_reset(struct idpf_adapter *adapter,
>   static void idpf_vf_reg_ops_init(struct idpf_adapter *adapter)
>   {
>          adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_vf_ctlq_reg_init;
> +       adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_vf_mb_intr_reg_init;
>          adapter->dev_ops.reg_ops.reset_reg_init = idpf_vf_reset_reg_init;
>          adapter->dev_ops.reg_ops.trigger_reset = idpf_vf_trigger_reset;
>   }
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> index 87298c99027d..b26884b5cc60 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> @@ -46,6 +46,635 @@ static int idpf_mb_clean(struct idpf_adapter *adapter)
>          return err;
>   }
> 
> +/**
> + * idpf_send_mb_msg - Send message over mailbox
> + * @adapter: Driver specific private structure
> + * @op: virtchnl opcode
> + * @msg_size: size of the payload
> + * @msg: pointer to buffer holding the payload
> + *
> + * Will prepare the control queue message and initiates the send api
> + *
> + * Returns 0 on success, negative on failure
> + */
> +int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
> +                    u16 msg_size, u8 *msg)
> +{
> +       struct idpf_ctlq_msg *ctlq_msg;
> +       struct idpf_dma_mem *dma_mem;
> +       int err;
> +
> +       /* If we are here and a reset is detected nothing much can be
> +        * done. This thread should silently abort and expected to
> +        * be corrected with a new run either by user or driver
> +        * flows after reset
> +        */
> +       if (idpf_is_reset_detected(adapter))
> +               return 0;
> +
> +       err = idpf_mb_clean(adapter);
> +       if (err)
> +               return err;
> +
> +       ctlq_msg = kzalloc(sizeof(*ctlq_msg), GFP_ATOMIC);
> +       if (!ctlq_msg)
> +               return -ENOMEM;
> +
> +       dma_mem = kzalloc(sizeof(*dma_mem), GFP_ATOMIC);
> +       if (!dma_mem) {
> +               err = -ENOMEM;
> +               goto dma_mem_error;
> +       }
> +
> +       memset(ctlq_msg, 0, sizeof(struct idpf_ctlq_msg));

Unnecessary, kzalloc() did this for you already

> +       ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_pf;
> +       ctlq_msg->func_id = 0;
> +       ctlq_msg->data_len = msg_size;
> +       ctlq_msg->cookie.mbx.chnl_opcode = op;
> +       ctlq_msg->cookie.mbx.chnl_retval = VIRTCHNL2_STATUS_SUCCESS;
> +       dma_mem->size = IDPF_DFLT_MBX_BUF_SIZE;
> +       dma_mem->va = dmam_alloc_coherent(&adapter->pdev->dev, dma_mem->size,
> +                                         &dma_mem->pa, GFP_ATOMIC);

Were you going to replace these dmam as you did the devm?
Or are you intentionally keeping them?

> +       if (!dma_mem->va) {
> +               err = -ENOMEM;
> +               goto dma_alloc_error;
> +       }
> +       memcpy(dma_mem->va, msg, msg_size);
> +       ctlq_msg->ctx.indirect.payload = dma_mem;
> +
> +       err = idpf_ctlq_send(&adapter->hw, adapter->hw.asq, 1, ctlq_msg);
> +       if (err)
> +               goto send_error;
> +
> +       return 0;
> +
> +send_error:
> +       dmam_free_coherent(&adapter->pdev->dev, dma_mem->size, dma_mem->va,
> +                          dma_mem->pa);
> +dma_alloc_error:
> +       kfree(dma_mem);
> +dma_mem_error:
> +       kfree(ctlq_msg);
> +
> +       return err;
> +}
> +
> +/**
> + * idpf_set_msg_pending_bit - Wait for clear and set msg pending
> + * @adapter: driver specific private structure
> + * @vport: virtual port structure
> + *
> + * If clear sets msg pending bit, otherwise waits for it to clear before
> + * setting it again. Returns 0 on success, negative on failure.
> + */
> +static int idpf_set_msg_pending_bit(struct idpf_adapter *adapter,
> +                                   struct idpf_vport *vport)
> +{
> +       unsigned int retries = 100;
> +
> +       /* If msg pending bit already set, there's a message waiting to be
> +        * parsed and we must wait for it to be cleared before copying a new
> +        * message into the vc_msg buffer or else we'll stomp all over the
> +        * previous message.
> +        */
> +       while (retries) {
> +               if (!test_and_set_bit(__IDPF_VC_MSG_PENDING, adapter->flags))
> +                       break;
> +               msleep(20);
> +               retries--;
> +       }
> +
> +       return retries ? 0 : -ETIMEDOUT;
> +}
> +
> +/**
> + * idpf_set_msg_pending - Wait for msg pending bit and copy msg to buf
> + * @adapter: driver specific private structure
> + * @vport: virtual port structure
> + * @ctlq_msg: msg to copy from
> + * @err_enum: err bit to set on error
> + *
> + * Copies payload from ctlq_msg into vc_msg buf in adapter and sets msg pending
> + * bit. Returns 0 on success, negative on failure.
> + */
> +static int idpf_set_msg_pending(struct idpf_adapter *adapter,
> +                               struct idpf_vport *vport,
> +                               struct idpf_ctlq_msg *ctlq_msg,
> +                               enum idpf_vport_vc_state err_enum)
> +{
> +       if (ctlq_msg->cookie.mbx.chnl_retval) {
> +               set_bit(err_enum, adapter->vc_state);
> +
> +               return -EINVAL;
> +       }
> +
> +       if (idpf_set_msg_pending_bit(adapter, vport)) {
> +               set_bit(err_enum, adapter->vc_state);
> +               dev_err(&adapter->pdev->dev, "Timed out setting msg pending\n");
> +
> +               return -ETIMEDOUT;
> +       }
> +
> +       memcpy(adapter->vc_msg, ctlq_msg->ctx.indirect.payload->va,
> +              min_t(int, ctlq_msg->ctx.indirect.payload->size,
> +                    IDPF_DFLT_MBX_BUF_SIZE));
> +
> +       return 0;
> +}
> +
> +/**
> + * idpf_recv_vchnl_op - helper function with common logic when handling the
> + * reception of VIRTCHNL OPs.
> + * @adapter: driver specific private structure
> + * @vport: virtual port structure
> + * @ctlq_msg: msg to copy from
> + * @state: state bit used on timeout check
> + * @err_state: err bit to set on error
> + */
> +static void idpf_recv_vchnl_op(struct idpf_adapter *adapter,
> +                              struct idpf_vport *vport,
> +                              struct idpf_ctlq_msg *ctlq_msg,
> +                              enum idpf_vport_vc_state state,
> +                              enum idpf_vport_vc_state err_state)
> +{
> +       wait_queue_head_t *vchnl_wq = &adapter->vchnl_wq;
> +       int err;
> +
> +       err = idpf_set_msg_pending(adapter, vport, ctlq_msg, err_state);
> +       if (wq_has_sleeper(vchnl_wq)) {
> +               /* sleeper is present and we got the pending bit */
> +               set_bit(state, adapter->vc_state);
> +
> +               wake_up(vchnl_wq);
> +       } else {
> +               if (!err) {
> +                       /* We got the pending bit, but release it if we cannot
> +                        * find a thread waiting for the message.
> +                        */
> +                       dev_warn(&adapter->pdev->dev, "opcode %d received without waiting thread\n",
> +                                ctlq_msg->cookie.mbx.chnl_opcode);
> +                       clear_bit(__IDPF_VC_MSG_PENDING, adapter->flags);
> +               } else {
> +                       /* Clear the errors since there is no sleeper to pass them on */
> +                       clear_bit(err_state, adapter->vc_state);
> +               }
> +       }
> +}
> +
> +/**
> + * idpf_recv_mb_msg - Receive message over mailbox
> + * @adapter: Driver specific private structure
> + * @op: virtchannel operation code
> + * @msg: Received message holding buffer
> + * @msg_size: message size
> + *
> + * Will receive control queue message and posts the receive buffer. Returns 0
> + * on success and negative on failure.
> + */
> +int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op,
> +                    void *msg, int msg_size)
> +{
> +       struct idpf_ctlq_msg ctlq_msg;
> +       struct idpf_dma_mem *dma_mem;
> +       bool work_done = false;
> +       int num_retry = 2000;
> +       u16 num_q_msg;
> +       int err;
> +
> +       while (1) {
> +               int payload_size = 0;
> +
> +               /* Try to get one message */
> +               num_q_msg = 1;
> +               dma_mem = NULL;
> +               err = idpf_ctlq_recv(adapter->hw.arq, &num_q_msg, &ctlq_msg);
> +               /* If no message then decide if we have to retry based on
> +                * opcode
> +                */
> +               if (err || !num_q_msg) {
> +                       /* Increasing num_retry to consider the delayed
> +                        * responses because of large number of VF's mailbox
> +                        * messages. If the mailbox message is received from
> +                        * the other side, we come out of the sleep cycle
> +                        * immediately else we wait for more time.
> +                        */
> +                       if (!op || !num_retry--)
> +                               break;
> +                       if (test_bit(__IDPF_REL_RES_IN_PROG, adapter->flags)) {
> +                               err = -EIO;
> +                               break;
> +                       }
> +                       msleep(20);
> +                       continue;
> +               }
> +
> +               /* If we are here a message is received. Check if we are looking
> +                * for a specific message based on opcode. If it is different
> +                * ignore and post buffers
> +                */
> +               if (op && ctlq_msg.cookie.mbx.chnl_opcode != op)
> +                       goto post_buffs;
> +
> +               if (ctlq_msg.data_len)
> +                       payload_size = ctlq_msg.ctx.indirect.payload->size;
> +
> +               /* All conditions are met. Either a message requested is
> +                * received or we received a message to be processed
> +                */
> +               switch (ctlq_msg.cookie.mbx.chnl_opcode) {
> +               case VIRTCHNL2_OP_VERSION:
> +               case VIRTCHNL2_OP_GET_CAPS:
> +                       if (ctlq_msg.cookie.mbx.chnl_retval) {
> +                               dev_err(&adapter->pdev->dev, "Failure initializing, vc op: %u retval: %u\n",
> +                                       ctlq_msg.cookie.mbx.chnl_opcode,
> +                                       ctlq_msg.cookie.mbx.chnl_retval);
> +                               err = -EBADMSG;
> +                       } else if (msg) {
> +                               memcpy(msg, ctlq_msg.ctx.indirect.payload->va,
> +                                      min_t(int, payload_size, msg_size));
> +                       }
> +                       work_done = true;
> +                       break;
> +               case VIRTCHNL2_OP_ALLOC_VECTORS:
> +                       idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg,
> +                                          IDPF_VC_ALLOC_VECTORS,
> +                                          IDPF_VC_ALLOC_VECTORS_ERR);
> +                       break;
> +               case VIRTCHNL2_OP_DEALLOC_VECTORS:
> +                       idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg,
> +                                          IDPF_VC_DEALLOC_VECTORS,
> +                                          IDPF_VC_DEALLOC_VECTORS_ERR);
> +                       break;
> +               default:
> +                       dev_warn(&adapter->pdev->dev,
> +                                "Unhandled virtchnl response %d\n",
> +                                ctlq_msg.cookie.mbx.chnl_opcode);
> +                       break;
> +               }
> +
> +post_buffs:
> +               if (ctlq_msg.data_len)
> +                       dma_mem = ctlq_msg.ctx.indirect.payload;
> +               else
> +                       num_q_msg = 0;
> +
> +               err = idpf_ctlq_post_rx_buffs(&adapter->hw, adapter->hw.arq,
> +                                             &num_q_msg, &dma_mem);
> +               /* If post failed clear the only buffer we supplied */
> +               if (err && dma_mem)
> +                       dmam_free_coherent(&adapter->pdev->dev, dma_mem->size,
> +                                          dma_mem->va, dma_mem->pa);
> +
> +               /* Applies only if we are looking for a specific opcode */
> +               if (work_done)
> +                       break;
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * __idpf_wait_for_event - wrapper function for wait on virtchannel response
> + * @adapter: Driver private data structure
> + * @vport: virtual port structure
> + * @state: check on state upon timeout
> + * @err_check: check if this specific error bit is set
> + * @timeout: Max time to wait
> + *
> + * Checks if state is set upon expiry of timeout.  Returns 0 on success,
> + * negative on failure.
> + */
> +static int __idpf_wait_for_event(struct idpf_adapter *adapter,
> +                                struct idpf_vport *vport,
> +                                enum idpf_vport_vc_state state,
> +                                enum idpf_vport_vc_state err_check,
> +                                int timeout)
> +{
> +       int time_to_wait, num_waits;
> +       wait_queue_head_t *vchnl_wq;
> +       unsigned long *vc_state;
> +
> +       time_to_wait = ((timeout <= IDPF_MAX_WAIT) ? timeout : IDPF_MAX_WAIT);
> +       num_waits = ((timeout <= IDPF_MAX_WAIT) ? 1 : timeout / IDPF_MAX_WAIT);
> +
> +       vchnl_wq = &adapter->vchnl_wq;
> +       vc_state = adapter->vc_state;
> +
> +       while (num_waits) {
> +               int event;
> +
> +               /* If we are here and a reset is detected do not wait but
> +                * return. Reset timing is out of drivers control. So
> +                * while we are cleaning resources as part of reset if the
> +                * underlying HW mailbox is gone, wait on mailbox messages
> +                * is not meaningful
> +                */
> +               if (idpf_is_reset_detected(adapter))
> +                       return 0;
> +
> +               event = wait_event_timeout(*vchnl_wq,
> +                                          test_and_clear_bit(state, vc_state),
> +                                          msecs_to_jiffies(time_to_wait));
> +               if (event) {
> +                       if (test_and_clear_bit(err_check, vc_state)) {
> +                               dev_err(&adapter->pdev->dev, "VC response error %s\n",
> +                                       idpf_vport_vc_state_str[err_check]);
> +
> +                               return -EINVAL;
> +                       }
> +
> +                       return 0;
> +               }
> +               num_waits--;
> +       }
> +
> +       /* Timeout occurred */
> +       dev_err(&adapter->pdev->dev, "VC timeout, state = %s\n",
> +               idpf_vport_vc_state_str[state]);
> +
> +       return -ETIMEDOUT;
> +}
> +
> +/**
> + * idpf_min_wait_for_event - wait for virtchannel response
> + * @adapter: Driver private data structure
> + * @vport: virtual port structure
> + * @state: check on state upon timeout
> + * @err_check: check if this specific error bit is set
> + *
> + * Returns 0 on success, negative on failure.
> + */
> +static int idpf_min_wait_for_event(struct idpf_adapter *adapter,
> +                                  struct idpf_vport *vport,
> +                                  enum idpf_vport_vc_state state,
> +                                  enum idpf_vport_vc_state err_check)
> +{
> +       return __idpf_wait_for_event(adapter, vport, state, err_check,
> +                                    IDPF_WAIT_FOR_EVENT_TIMEO_MIN);
> +}
> +
> +/**
> + * idpf_wait_for_event - wait for virtchannel response
> + * @adapter: Driver private data structure
> + * @vport: virtual port structure
> + * @state: check on state upon timeout after 500ms
> + * @err_check: check if this specific error bit is set
> + *
> + * Returns 0 on success, negative on failure.
> + */
> +static int idpf_wait_for_event(struct idpf_adapter *adapter,
> +                              struct idpf_vport *vport,
> +                              enum idpf_vport_vc_state state,
> +                              enum idpf_vport_vc_state err_check)
> +{
> +       /* Increasing the timeout in __IDPF_INIT_SW flow to consider large
> +        * number of VF's mailbox message responses. When a message is received
> +        * on mailbox, this thread is wake up by the idpf_recv_mb_msg before the

s/wake up/woken/

> +        * timeout expires. Only in the error case i.e. if no message is
> +        * received on mailbox, we wait for the complete timeout which is
> +        * less likely to happen.
> +        */
> +       return __idpf_wait_for_event(adapter, vport, state, err_check,
> +                                    IDPF_WAIT_FOR_EVENT_TIMEO);
> +}
> +
> +/**
> + * idpf_send_ver_msg - send virtchnl version message
> + * @adapter: Driver specific private structure
> + *
> + * Send virtchnl version message.  Returns 0 on success, negative on failure.
> + */
> +static int idpf_send_ver_msg(struct idpf_adapter *adapter)
> +{
> +       struct virtchnl2_version_info vvi;
> +
> +       if (adapter->virt_ver_maj) {
> +               vvi.major = cpu_to_le32(adapter->virt_ver_maj);
> +               vvi.minor = cpu_to_le32(adapter->virt_ver_min);
> +       } else {
> +               vvi.major = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MAJOR);
> +               vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);
> +       }
> +
> +       return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_VERSION, sizeof(vvi),
> +                               (u8 *)&vvi);
> +}
> +
> +/**
> + * idpf_recv_ver_msg - Receive virtchnl version message
> + * @adapter: Driver specific private structure
> + *
> + * Receive virtchnl version message. Returns 0 on success, -EAGAIN if we need
> + * to send version message again, otherwise negative on failure.
> + */
> +static int idpf_recv_ver_msg(struct idpf_adapter *adapter)
> +{
> +       struct virtchnl2_version_info vvi;
> +       u32 major, minor;
> +       int err;
> +
> +       err = idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_VERSION, &vvi, sizeof(vvi));
> +       if (err)
> +               return err;
> +
> +       major = le32_to_cpu(vvi.major);
> +       minor = le32_to_cpu(vvi.minor);
> +
> +       if (major > IDPF_VIRTCHNL_VERSION_MAJOR) {
> +               dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n");

Printing the bad version value would be helpful here

> +
> +               return -EINVAL;
> +       }
> +
> +       if (major == IDPF_VIRTCHNL_VERSION_MAJOR &&
> +           minor > IDPF_VIRTCHNL_VERSION_MINOR)
> +               dev_warn(&adapter->pdev->dev, "Virtchnl minor version didn't match\n");

ditto

> +
> +       /* If we have a mismatch, resend version to update receiver on what
> +        * version we will use.
> +        */
> +       if (!adapter->virt_ver_maj &&
> +           major != IDPF_VIRTCHNL_VERSION_MAJOR &&
> +           minor != IDPF_VIRTCHNL_VERSION_MINOR)
> +               err = -EAGAIN;
> +
> +       adapter->virt_ver_maj = major;
> +       adapter->virt_ver_min = minor;
> +
> +       return err;
> +}
> +
> +/**
> + * idpf_send_get_caps_msg - Send virtchnl get capabilities message
> + * @adapter: Driver specific private structure
> + *
> + * Send virtchl get capabilities message. Returns 0 on success, negative on
> + * failure.
> + */
> +static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)
> +{
> +       struct virtchnl2_get_capabilities caps = { };
> +
> +       caps.csum_caps =
> +               cpu_to_le32(VIRTCHNL2_CAP_TX_CSUM_L3_IPV4       |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_TCP   |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_UDP   |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_SCTP  |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_TCP   |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_UDP   |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_SCTP  |
> +                           VIRTCHNL2_CAP_RX_CSUM_L3_IPV4       |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_TCP   |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_UDP   |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_SCTP  |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_TCP   |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_UDP   |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_SCTP  |
> +                           VIRTCHNL2_CAP_TX_CSUM_L3_SINGLE_TUNNEL |
> +                           VIRTCHNL2_CAP_RX_CSUM_L3_SINGLE_TUNNEL |
> +                           VIRTCHNL2_CAP_TX_CSUM_L4_SINGLE_TUNNEL |
> +                           VIRTCHNL2_CAP_RX_CSUM_L4_SINGLE_TUNNEL |
> +                           VIRTCHNL2_CAP_RX_CSUM_GENERIC);
> +
> +       caps.seg_caps =
> +               cpu_to_le32(VIRTCHNL2_CAP_SEG_IPV4_TCP          |
> +                           VIRTCHNL2_CAP_SEG_IPV4_UDP          |
> +                           VIRTCHNL2_CAP_SEG_IPV4_SCTP         |
> +                           VIRTCHNL2_CAP_SEG_IPV6_TCP          |
> +                           VIRTCHNL2_CAP_SEG_IPV6_UDP          |
> +                           VIRTCHNL2_CAP_SEG_IPV6_SCTP         |
> +                           VIRTCHNL2_CAP_SEG_TX_SINGLE_TUNNEL);
> +
> +       caps.rss_caps =
> +               cpu_to_le64(VIRTCHNL2_CAP_RSS_IPV4_TCP          |
> +                           VIRTCHNL2_CAP_RSS_IPV4_UDP          |
> +                           VIRTCHNL2_CAP_RSS_IPV4_SCTP         |
> +                           VIRTCHNL2_CAP_RSS_IPV4_OTHER        |
> +                           VIRTCHNL2_CAP_RSS_IPV6_TCP          |
> +                           VIRTCHNL2_CAP_RSS_IPV6_UDP          |
> +                           VIRTCHNL2_CAP_RSS_IPV6_SCTP         |
> +                           VIRTCHNL2_CAP_RSS_IPV6_OTHER);
> +
> +       caps.hsplit_caps =
> +               cpu_to_le32(VIRTCHNL2_CAP_RX_HSPLIT_AT_L4V4     |
> +                           VIRTCHNL2_CAP_RX_HSPLIT_AT_L4V6);
> +
> +       caps.rsc_caps =
> +               cpu_to_le32(VIRTCHNL2_CAP_RSC_IPV4_TCP          |
> +                           VIRTCHNL2_CAP_RSC_IPV6_TCP);
> +
> +       caps.other_caps =
> +               cpu_to_le64(VIRTCHNL2_CAP_SRIOV                 |

I think this routine is getting called for both PF and VF - does this 
SRIOV capability make sense in the VF case?  Or does it simply get 
filtered out by the CP's response and it doesn't matter?

> +                           VIRTCHNL2_CAP_MACFILTER             |
> +                           VIRTCHNL2_CAP_SPLITQ_QSCHED         |
> +                           VIRTCHNL2_CAP_PROMISC               |
> +                           VIRTCHNL2_CAP_LOOPBACK              |
> +                           VIRTCHNL2_CAP_MISS_COMPL_TAG);
> +
> +       return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, sizeof(caps),
> +                               (u8 *)&caps);
> +}
> +
> +/**
> + * idpf_recv_get_caps_msg - Receive virtchnl get capabilities message
> + * @adapter: Driver specific private structure
> + *
> + * Receive virtchnl get capabilities message. Returns 0 on success, negative on
> + * failure.
> + */
> +static int idpf_recv_get_caps_msg(struct idpf_adapter *adapter)
> +{
> +       return idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, &adapter->caps,
> +                               sizeof(struct virtchnl2_get_capabilities));
> +}
> +
> +/**
> + * idpf_send_alloc_vectors_msg - Send virtchnl alloc vectors message
> + * @adapter: Driver specific private structure
> + * @num_vectors: number of vectors to be allocated
> + *
> + * Returns 0 on success, negative on failure.
> + */
> +int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
> +{
> +       struct virtchnl2_alloc_vectors *alloc_vec, *rcvd_vec;
> +       struct virtchnl2_alloc_vectors ac = { };
> +       u16 num_vchunks;
> +       int size, err;
> +
> +       ac.num_vectors = cpu_to_le16(num_vectors);
> +
> +       err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ALLOC_VECTORS,
> +                              sizeof(ac), (u8 *)&ac);
> +       if (err)
> +               return err;
> +
> +       err = idpf_wait_for_event(adapter, NULL, IDPF_VC_ALLOC_VECTORS,
> +                                 IDPF_VC_ALLOC_VECTORS_ERR);
> +       if (err)
> +               return err;
> +
> +       rcvd_vec = (struct virtchnl2_alloc_vectors *)adapter->vc_msg;
> +       num_vchunks = le16_to_cpu(rcvd_vec->vchunks.num_vchunks);
> +
> +       size = struct_size(rcvd_vec, vchunks.vchunks, num_vchunks);
> +       if (size > sizeof(adapter->vc_msg)) {
> +               err = -EINVAL;
> +               goto error;
> +       }
> +
> +       kfree(adapter->req_vec_chunks);
> +       adapter->req_vec_chunks = NULL;
> +       adapter->req_vec_chunks = kmemdup(adapter->vc_msg, size, GFP_KERNEL);
> +       if (!adapter->req_vec_chunks) {
> +               err = -ENOMEM;
> +               goto error;
> +       }
> +
> +       alloc_vec = adapter->req_vec_chunks;
> +       if (le16_to_cpu(alloc_vec->num_vectors) < num_vectors) {
> +               kfree(adapter->req_vec_chunks);
> +               adapter->req_vec_chunks = NULL;
> +               err = -EINVAL;
> +       }
> +
> +error:
> +       clear_bit(__IDPF_VC_MSG_PENDING, adapter->flags);
> +
> +       return err;
> +}
> +
> +/**
> + * idpf_send_dealloc_vectors_msg - Send virtchnl de allocate vectors message
> + * @adapter: Driver specific private structure
> + *
> + * Returns 0 on success, negative on failure.
> + */
> +int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
> +{
> +       struct virtchnl2_alloc_vectors *ac = adapter->req_vec_chunks;
> +       struct virtchnl2_vector_chunks *vcs = &ac->vchunks;
> +       int buf_size, err;
> +
> +       buf_size = struct_size(vcs, vchunks, le16_to_cpu(vcs->num_vchunks));
> +
> +       err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEALLOC_VECTORS, buf_size,
> +                              (u8 *)vcs);
> +       if (err)
> +               return err;
> +
> +       err = idpf_min_wait_for_event(adapter, NULL, IDPF_VC_DEALLOC_VECTORS,
> +                                     IDPF_VC_DEALLOC_VECTORS_ERR);
> +       if (err)
> +               return err;
> +
> +       kfree(adapter->req_vec_chunks);
> +       adapter->req_vec_chunks = NULL;
> +       clear_bit(__IDPF_VC_MSG_PENDING, adapter->flags);
> +
> +       return 0;
> +}
> +
>   /**
>    * idpf_find_ctlq - Given a type and id, find ctlq info
>    * @hw: hardware struct
> @@ -126,3 +755,175 @@ void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter)
>          adapter->hw.arq = NULL;
>          adapter->hw.asq = NULL;
>   }
> +
> +/**
> + * idpf_vc_core_init - Initialize state machine and get driver specific
> + * resources
> + * @adapter: Driver specific private structure
> + *
> + * This function will initialize the state machine and request all necessary
> + * resources required by the device driver. Once the state machine is
> + * initialized, allocate memory to store vport specific information and also
> + * requests required interrupts.
> + *
> + * Returns 0 on success, -EAGAIN function will get called again,
> + * otherwise negative on failure.
> + */
> +int idpf_vc_core_init(struct idpf_adapter *adapter)
> +{
> +       int task_delay = 30;
> +       int err = 0;
> +
> +       while (adapter->state != __IDPF_INIT_SW) {
> +               switch (adapter->state) {
> +               case __IDPF_STARTUP:
> +                       if (idpf_send_ver_msg(adapter))
> +                               goto init_failed;
> +                       adapter->state = __IDPF_VER_CHECK;
> +                       goto restart;
> +               case __IDPF_VER_CHECK:
> +                       err = idpf_recv_ver_msg(adapter);
> +                       if (err == -EIO) {
> +                               return err;
> +                       } else if (err == -EAGAIN) {
> +                               adapter->state = __IDPF_STARTUP;
> +                               goto restart;
> +                       } else if (err) {
> +                               goto init_failed;
> +                       }
> +                       if (idpf_send_get_caps_msg(adapter))
> +                               goto init_failed;
> +                       adapter->state = __IDPF_GET_CAPS;
> +                       goto restart;
> +               case __IDPF_GET_CAPS:
> +                       if (idpf_recv_get_caps_msg(adapter))
> +                               goto init_failed;
> +                       adapter->state = __IDPF_INIT_SW;
> +                       break;
> +               default:
> +                       dev_err(&adapter->pdev->dev, "Device is in bad state: %d\n",
> +                               adapter->state);
> +                       goto init_failed;
> +               }
> +               break;
> +restart:
> +               /* Give enough time before proceeding further with
> +                * state machine
> +                */
> +               msleep(task_delay);
> +       }
> +
> +       /* Start the service task before requesting vectors. This will ensure
> +        * vector information response from mailbox is handled
> +        */
> +       queue_delayed_work(adapter->serv_wq, &adapter->serv_task,
> +                          msecs_to_jiffies(5 * (adapter->pdev->devfn & 0x07)));
> +
> +       err = idpf_intr_req(adapter);
> +       if (err) {
> +               dev_err(&adapter->pdev->dev, "failed to enable interrupt vectors: %d\n",
> +                       err);
> +               goto err_intr_req;
> +       }
> +
> +       goto no_err;
> +
> +err_intr_req:
> +       cancel_delayed_work_sync(&adapter->serv_task);
> +no_err:
> +       return err;
> +
> +init_failed:
> +       if (++adapter->mb_wait_count > IDPF_MB_MAX_ERR) {
> +               dev_err(&adapter->pdev->dev, "Failed to establish mailbox communications with hardware\n");
> +
> +               return -EFAULT;
> +       }
> +       /* If it reached here, it is possible that mailbox queue initialization
> +        * register writes might not have taken effect. Retry to initialize
> +        * the mailbox again
> +        */
> +       adapter->state = __IDPF_STARTUP;
> +       idpf_deinit_dflt_mbx(adapter);
> +       set_bit(__IDPF_HR_DRV_LOAD, adapter->flags);
> +       queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
> +                          msecs_to_jiffies(task_delay));
> +
> +       return -EAGAIN;
> +}
> +
> +/**
> + * idpf_vc_core_deinit - Device deinit routine
> + * @adapter: Driver specific private structure
> + *
> + */
> +void idpf_vc_core_deinit(struct idpf_adapter *adapter)
> +{
> +       int i;
> +
> +       set_bit(__IDPF_REL_RES_IN_PROG, adapter->flags);
> +
> +       idpf_intr_rel(adapter);
> +       /* Set all bits as we dont know on which vc_state the vhnl_wq is
> +        * waiting on and wakeup the virtchnl workqueue even if it is waiting
> +        * for the response as we are going down
> +        */
> +       for (i = 0; i < IDPF_VC_NBITS; i++)
> +               set_bit(i, adapter->vc_state);
> +       wake_up(&adapter->vchnl_wq);
> +
> +       /* Required to indicate periodic task not to schedule again */
> +       set_bit(__IDPF_CANCEL_SERVICE_TASK, adapter->flags);
> +       cancel_delayed_work_sync(&adapter->serv_task);
> +       clear_bit(__IDPF_CANCEL_SERVICE_TASK, adapter->flags);
> +       /* Clear all the bits */
> +       for (i = 0; i < IDPF_VC_NBITS; i++)
> +               clear_bit(i, adapter->vc_state);
> +
> +       clear_bit(__IDPF_REL_RES_IN_PROG, adapter->flags);
> +}
> +
> +/**
> + * idpf_get_vec_ids - Initialize vector id from Mailbox parameters
> + * @adapter: adapter structure to get the mailbox vector id
> + * @vecids: Array of vector ids
> + * @num_vecids: number of vector ids
> + * @chunks: vector ids received over mailbox
> + *
> + * Will initialize the mailbox vector id which is received from the
> + * get capabilities and data queue vector ids with ids received as
> + * mailbox parameters.
> + * Returns number of ids filled
> + */
> +int idpf_get_vec_ids(struct idpf_adapter *adapter,
> +                    u16 *vecids, int num_vecids,
> +                    struct virtchnl2_vector_chunks *chunks)
> +{
> +       u16 num_chunks = le16_to_cpu(chunks->num_vchunks);
> +       int num_vecid_filled = 0;
> +       int i, j;
> +
> +       vecids[num_vecid_filled] = adapter->mb_vector.v_idx;
> +       num_vecid_filled++;
> +
> +       for (j = 0; j < num_chunks; j++) {
> +               struct virtchnl2_vector_chunk *chunk;
> +               u16 start_vecid, num_vec;
> +
> +               chunk = &chunks->vchunks[j];
> +               num_vec = le16_to_cpu(chunk->num_vectors);
> +               start_vecid = le16_to_cpu(chunk->start_vector_id);
> +
> +               for (i = 0; i < num_vec; i++) {
> +                       if ((num_vecid_filled + i) < num_vecids) {
> +                               vecids[num_vecid_filled + i] = start_vecid;
> +                               start_vecid++;
> +                       } else {
> +                               break;
> +                       }
> +               }
> +               num_vecid_filled = num_vecid_filled + i;
> +       }
> +
> +       return num_vecid_filled;
> +}
> --
> 2.17.2
> 


More information about the Intel-wired-lan mailing list