net/txgbe: add VF base code
authorJiawen Wu <jiawenwu@trustnetic.com>
Thu, 25 Feb 2021 08:08:46 +0000 (16:08 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 26 Feb 2021 13:13:03 +0000 (14:13 +0100)
Implement VF device init and uninit function with hardware operations,
and negotiate with PF in mailbox.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
drivers/net/txgbe/base/meson.build
drivers/net/txgbe/base/txgbe.h
drivers/net/txgbe/base/txgbe_hw.c
drivers/net/txgbe/base/txgbe_mbx.c
drivers/net/txgbe/base/txgbe_mbx.h
drivers/net/txgbe/base/txgbe_type.h
drivers/net/txgbe/base/txgbe_vf.c [new file with mode: 0644]
drivers/net/txgbe/base/txgbe_vf.h [new file with mode: 0644]
drivers/net/txgbe/txgbe_ethdev_vf.c

index 3c63bf5..33d0adf 100644 (file)
@@ -9,6 +9,7 @@ sources = [
        'txgbe_mbx.c',
        'txgbe_mng.c',
        'txgbe_phy.c',
+       'txgbe_vf.c',
 ]
 
 error_cflags = []
index b054bb8..d719951 100644 (file)
@@ -11,6 +11,7 @@
 #include "txgbe_eeprom.h"
 #include "txgbe_phy.h"
 #include "txgbe_hw.h"
+#include "txgbe_vf.h"
 #include "txgbe_dcb.h"
 
 #endif /* _TXGBE_H_ */
index dc419d7..c357c86 100644 (file)
@@ -6,6 +6,7 @@
 #include "txgbe_mbx.h"
 #include "txgbe_phy.h"
 #include "txgbe_dcb.h"
+#include "txgbe_vf.h"
 #include "txgbe_eeprom.h"
 #include "txgbe_mng.h"
 #include "txgbe_hw.h"
@@ -2491,6 +2492,9 @@ s32 txgbe_init_shared_code(struct txgbe_hw *hw)
        case txgbe_mac_raptor:
                status = txgbe_init_ops_pf(hw);
                break;
+       case txgbe_mac_raptor_vf:
+               status = txgbe_init_ops_vf(hw);
+               break;
        default:
                status = TXGBE_ERR_DEVICE_NOT_SUPPORTED;
                break;
index bfe5347..b308839 100644 (file)
@@ -118,6 +118,360 @@ s32 txgbe_check_for_rst(struct txgbe_hw *hw, u16 mbx_id)
        return ret_val;
 }
 
+/**
+ *  txgbe_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification
+ **/
+STATIC s32 txgbe_poll_for_msg(struct txgbe_hw *hw, u16 mbx_id)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       DEBUGFUNC("txgbe_poll_for_msg");
+
+       if (!countdown || !mbx->check_for_msg)
+               goto out;
+
+       while (countdown && mbx->check_for_msg(hw, mbx_id)) {
+               countdown--;
+               if (!countdown)
+                       break;
+               usec_delay(mbx->usec_delay);
+       }
+
+       if (countdown == 0)
+               DEBUGOUT("Polling for VF%d mailbox message timedout", mbx_id);
+
+out:
+       return countdown ? 0 : TXGBE_ERR_MBX;
+}
+
+/**
+ *  txgbe_poll_for_ack - Wait for message acknowledgment
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message acknowledgment
+ **/
+STATIC s32 txgbe_poll_for_ack(struct txgbe_hw *hw, u16 mbx_id)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       DEBUGFUNC("txgbe_poll_for_ack");
+
+       if (!countdown || !mbx->check_for_ack)
+               goto out;
+
+       while (countdown && mbx->check_for_ack(hw, mbx_id)) {
+               countdown--;
+               if (!countdown)
+                       break;
+               usec_delay(mbx->usec_delay);
+       }
+
+       if (countdown == 0)
+               DEBUGOUT("Polling for VF%d mailbox ack timedout", mbx_id);
+
+out:
+       return countdown ? 0 : TXGBE_ERR_MBX;
+}
+
+/**
+ *  txgbe_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+s32 txgbe_read_posted_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       DEBUGFUNC("txgbe_read_posted_mbx");
+
+       if (!mbx->read)
+               goto out;
+
+       ret_val = txgbe_poll_for_msg(hw, mbx_id);
+
+       /* if ack received read message, otherwise we timed out */
+       if (!ret_val)
+               ret_val = mbx->read(hw, msg, size, mbx_id);
+out:
+       return ret_val;
+}
+
+/**
+ *  txgbe_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+s32 txgbe_write_posted_mbx(struct txgbe_hw *hw, u32 *msg, u16 size,
+                          u16 mbx_id)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       DEBUGFUNC("txgbe_write_posted_mbx");
+
+       /* exit if either we can't write or there isn't a defined timeout */
+       if (!mbx->write || !mbx->timeout)
+               goto out;
+
+       /* send msg */
+       ret_val = mbx->write(hw, msg, size, mbx_id);
+
+       /* if msg sent wait until we receive an ack */
+       if (!ret_val)
+               ret_val = txgbe_poll_for_ack(hw, mbx_id);
+out:
+       return ret_val;
+}
+
+/**
+ *  txgbe_read_v2p_mailbox - read v2p mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  This function is used to read the v2p mailbox without losing the read to
+ *  clear status bits.
+ **/
+STATIC u32 txgbe_read_v2p_mailbox(struct txgbe_hw *hw)
+{
+       u32 v2p_mailbox = rd32(hw, TXGBE_VFMBCTL);
+
+       v2p_mailbox |= hw->mbx.v2p_mailbox;
+       hw->mbx.v2p_mailbox |= v2p_mailbox & TXGBE_VFMBCTL_R2C_BITS;
+
+       return v2p_mailbox;
+}
+
+/**
+ *  txgbe_check_for_bit_vf - Determine if a status bit was set
+ *  @hw: pointer to the HW structure
+ *  @mask: bitmask for bits to be tested and cleared
+ *
+ *  This function is used to check for the read to clear bits within
+ *  the V2P mailbox.
+ **/
+STATIC s32 txgbe_check_for_bit_vf(struct txgbe_hw *hw, u32 mask)
+{
+       u32 v2p_mailbox = txgbe_read_v2p_mailbox(hw);
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       if (v2p_mailbox & mask)
+               ret_val = 0;
+
+       hw->mbx.v2p_mailbox &= ~mask;
+
+       return ret_val;
+}
+
+/**
+ *  txgbe_check_for_msg_vf - checks to see if the PF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the PF has set the Status bit or else ERR_MBX
+ **/
+s32 txgbe_check_for_msg_vf(struct txgbe_hw *hw, u16 mbx_id)
+{
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       UNREFERENCED_PARAMETER(mbx_id);
+       DEBUGFUNC("txgbe_check_for_msg_vf");
+
+       if (!txgbe_check_for_bit_vf(hw, TXGBE_VFMBCTL_PFSTS)) {
+               ret_val = 0;
+               hw->mbx.stats.reqs++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  txgbe_check_for_ack_vf - checks to see if the PF has ACK'd
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
+ **/
+s32 txgbe_check_for_ack_vf(struct txgbe_hw *hw, u16 mbx_id)
+{
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       UNREFERENCED_PARAMETER(mbx_id);
+       DEBUGFUNC("txgbe_check_for_ack_vf");
+
+       if (!txgbe_check_for_bit_vf(hw, TXGBE_VFMBCTL_PFACK)) {
+               ret_val = 0;
+               hw->mbx.stats.acks++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  txgbe_check_for_rst_vf - checks to see if the PF has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns true if the PF has set the reset done bit or else false
+ **/
+s32 txgbe_check_for_rst_vf(struct txgbe_hw *hw, u16 mbx_id)
+{
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       UNREFERENCED_PARAMETER(mbx_id);
+       DEBUGFUNC("txgbe_check_for_rst_vf");
+
+       if (!txgbe_check_for_bit_vf(hw, (TXGBE_VFMBCTL_RSTD |
+           TXGBE_VFMBCTL_RSTI))) {
+               ret_val = 0;
+               hw->mbx.stats.rsts++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  txgbe_obtain_mbx_lock_vf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *
+ *  return SUCCESS if we obtained the mailbox lock
+ **/
+STATIC s32 txgbe_obtain_mbx_lock_vf(struct txgbe_hw *hw)
+{
+       s32 ret_val = TXGBE_ERR_MBX;
+
+       DEBUGFUNC("txgbe_obtain_mbx_lock_vf");
+
+       /* Take ownership of the buffer */
+       wr32(hw, TXGBE_VFMBCTL, TXGBE_VFMBCTL_VFU);
+
+       /* reserve mailbox for vf use */
+       if (txgbe_read_v2p_mailbox(hw) & TXGBE_VFMBCTL_VFU)
+               ret_val = 0;
+
+       return ret_val;
+}
+
+/**
+ *  txgbe_write_mbx_vf - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+s32 txgbe_write_mbx_vf(struct txgbe_hw *hw, u32 *msg, u16 size,
+                             u16 mbx_id)
+{
+       s32 ret_val;
+       u16 i;
+
+       UNREFERENCED_PARAMETER(mbx_id);
+
+       DEBUGFUNC("txgbe_write_mbx_vf");
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = txgbe_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               goto out_no_write;
+
+       /* flush msg and acks as we are overwriting the message buffer */
+       txgbe_check_for_msg_vf(hw, 0);
+       txgbe_check_for_ack_vf(hw, 0);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               wr32a(hw, TXGBE_VFMBX, i, msg[i]);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+       /* Drop VFU and interrupt the PF to tell it a message has been sent */
+       wr32(hw, TXGBE_VFMBCTL, TXGBE_VFMBCTL_REQ);
+
+out_no_write:
+       return ret_val;
+}
+
+/**
+ *  txgbe_read_mbx_vf - Reads a message from the inbox intended for vf
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns SUCCESS if it successfully read message from buffer
+ **/
+s32 txgbe_read_mbx_vf(struct txgbe_hw *hw, u32 *msg, u16 size,
+                            u16 mbx_id)
+{
+       s32 ret_val = 0;
+       u16 i;
+
+       DEBUGFUNC("txgbe_read_mbx_vf");
+       UNREFERENCED_PARAMETER(mbx_id);
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = txgbe_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               goto out_no_read;
+
+       /* copy the message from the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = rd32a(hw, TXGBE_VFMBX, i);
+
+       /* Acknowledge receipt and release mailbox, then we're done */
+       wr32(hw, TXGBE_VFMBCTL, TXGBE_VFMBCTL_ACK);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+       return ret_val;
+}
+
+/**
+ *  txgbe_init_mbx_params_vf - set initial values for vf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+void txgbe_init_mbx_params_vf(struct txgbe_hw *hw)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+
+       /* start mailbox as timed out and let the reset_hw call set the timeout
+        * value to begin communications
+        */
+       mbx->timeout = 0;
+       mbx->usec_delay = TXGBE_VF_MBX_INIT_DELAY;
+
+       mbx->size = TXGBE_P2VMBX_SIZE;
+
+       mbx->stats.msgs_tx = 0;
+       mbx->stats.msgs_rx = 0;
+       mbx->stats.reqs = 0;
+       mbx->stats.acks = 0;
+       mbx->stats.rsts = 0;
+}
+
 STATIC s32 txgbe_check_for_bit_pf(struct txgbe_hw *hw, u32 mask, s32 index)
 {
        u32 mbvficr = rd32(hw, TXGBE_MBVFICR(index));
index 4a058b0..ccf5d12 100644 (file)
@@ -60,6 +60,8 @@ enum txgbe_pfvf_api_rev {
 #define TXGBE_VF_GET_RSS_KEY   0x0b    /* get RSS key */
 #define TXGBE_VF_UPDATE_XCAST_MODE     0x0c
 
+#define TXGBE_VF_BACKUP                0x8001 /* VF requests backup */
+
 /* mode choices for TXGBE_VF_UPDATE_XCAST_MODE */
 enum txgbevf_xcast_modes {
        TXGBEVF_XCAST_MODE_NONE = 0,
@@ -76,12 +78,20 @@ enum txgbevf_xcast_modes {
 
 /* length of permanent address message returned from PF */
 #define TXGBE_VF_PERMADDR_MSG_LEN      4
+/* word in permanent address message with the current multicast type */
+#define TXGBE_VF_MC_TYPE_WORD          3
+
+#define TXGBE_VF_MBX_INIT_TIMEOUT      2000 /* number of retries on mailbox */
+#define TXGBE_VF_MBX_INIT_DELAY                500  /* microseconds between retries */
 
 s32 txgbe_read_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
 s32 txgbe_write_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+s32 txgbe_read_posted_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+s32 txgbe_write_posted_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
 s32 txgbe_check_for_msg(struct txgbe_hw *hw, u16 mbx_id);
 s32 txgbe_check_for_ack(struct txgbe_hw *hw, u16 mbx_id);
 s32 txgbe_check_for_rst(struct txgbe_hw *hw, u16 mbx_id);
+void txgbe_init_mbx_params_vf(struct txgbe_hw *hw);
 void txgbe_init_mbx_params_pf(struct txgbe_hw *hw);
 
 s32 txgbe_read_mbx_pf(struct txgbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
@@ -90,4 +100,10 @@ s32 txgbe_check_for_msg_pf(struct txgbe_hw *hw, u16 vf_number);
 s32 txgbe_check_for_ack_pf(struct txgbe_hw *hw, u16 vf_number);
 s32 txgbe_check_for_rst_pf(struct txgbe_hw *hw, u16 vf_number);
 
+s32 txgbe_read_mbx_vf(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+s32 txgbe_write_mbx_vf(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+s32 txgbe_check_for_msg_vf(struct txgbe_hw *hw, u16 mbx_id);
+s32 txgbe_check_for_ack_vf(struct txgbe_hw *hw, u16 mbx_id);
+s32 txgbe_check_for_rst_vf(struct txgbe_hw *hw, u16 mbx_id);
+
 #endif /* _TXGBE_MBX_H_ */
index 22efcef..ef8358a 100644 (file)
@@ -11,6 +11,9 @@
 #define TXGBE_LINK_UP_TIME     90 /* 9.0 Seconds */
 #define TXGBE_AUTO_NEG_TIME    45 /* 4.5 Seconds */
 
+#define TXGBE_RX_HDR_SIZE      256
+#define TXGBE_RX_BUF_SIZE      2048
+
 #define TXGBE_FRAME_SIZE_MAX   (9728) /* Maximum frame size, +FCS */
 #define TXGBE_FRAME_SIZE_DFT   (1518) /* Default frame size, +FCS */
 #define TXGBE_NUM_POOL         (64)
@@ -23,6 +26,7 @@
 
 #define TXGBE_FDIR_INIT_DONE_POLL              10
 #define TXGBE_FDIRCMD_CMD_POLL                 10
+#define TXGBE_VF_INIT_TIMEOUT  200 /* Number of retries to clear RSTI */
 
 #define TXGBE_ALIGN            128 /* as intel did */
 
@@ -703,6 +707,7 @@ struct txgbe_mbx_info {
        struct txgbe_mbx_stats stats;
        u32 timeout;
        u32 usec_delay;
+       u32 v2p_mailbox;
        u16 size;
 };
 
@@ -732,6 +737,7 @@ struct txgbe_hw {
        u16 subsystem_vendor_id;
        u8 revision_id;
        bool adapter_stopped;
+       int api_version;
        bool allow_unsupported_sfp;
        bool need_crosstalk_fix;
 
@@ -755,6 +761,7 @@ struct txgbe_hw {
        u32 q_rx_regs[128 * 4];
        u32 q_tx_regs[128 * 4];
        bool offset_loaded;
+       bool rx_loaded;
        struct {
                u64 rx_qp_packets;
                u64 tx_qp_packets;
diff --git a/drivers/net/txgbe/base/txgbe_vf.c b/drivers/net/txgbe/base/txgbe_vf.c
new file mode 100644 (file)
index 0000000..5d4e101
--- /dev/null
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2015-2020
+ */
+
+#include "txgbe_mbx.h"
+#include "txgbe_vf.h"
+
+/**
+ *  txgbe_init_ops_vf - Initialize the pointers for vf
+ *  @hw: pointer to hardware structure
+ *
+ *  This will assign function pointers, adapter-specific functions can
+ *  override the assignment of generic function pointers by assigning
+ *  their own adapter-specific function pointers.
+ *  Does not touch the hardware.
+ **/
+s32 txgbe_init_ops_vf(struct txgbe_hw *hw)
+{
+       struct txgbe_mac_info *mac = &hw->mac;
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+
+       /* MAC */
+       mac->reset_hw = txgbe_reset_hw_vf;
+       mac->stop_hw = txgbe_stop_hw_vf;
+       mac->negotiate_api_version = txgbevf_negotiate_api_version;
+
+       mac->max_tx_queues = 1;
+       mac->max_rx_queues = 1;
+
+       mbx->init_params = txgbe_init_mbx_params_vf;
+       mbx->read = txgbe_read_mbx_vf;
+       mbx->write = txgbe_write_mbx_vf;
+       mbx->read_posted = txgbe_read_posted_mbx;
+       mbx->write_posted = txgbe_write_posted_mbx;
+       mbx->check_for_msg = txgbe_check_for_msg_vf;
+       mbx->check_for_ack = txgbe_check_for_ack_vf;
+       mbx->check_for_rst = txgbe_check_for_rst_vf;
+
+       return 0;
+}
+
+/* txgbe_virt_clr_reg - Set register to default (power on) state.
+ * @hw: pointer to hardware structure
+ */
+static void txgbe_virt_clr_reg(struct txgbe_hw *hw)
+{
+       int i;
+       u32 vfsrrctl;
+
+       /* default values (BUF_SIZE = 2048, HDR_SIZE = 256) */
+       vfsrrctl = TXGBE_RXCFG_HDRLEN(TXGBE_RX_HDR_SIZE);
+       vfsrrctl |= TXGBE_RXCFG_PKTLEN(TXGBE_RX_BUF_SIZE);
+
+       for (i = 0; i < 8; i++) {
+               wr32m(hw, TXGBE_RXCFG(i),
+                       (TXGBE_RXCFG_HDRLEN_MASK | TXGBE_RXCFG_PKTLEN_MASK),
+                       vfsrrctl);
+       }
+
+       txgbe_flush(hw);
+}
+
+/**
+ *  txgbe_reset_hw_vf - Performs hardware reset
+ *  @hw: pointer to hardware structure
+ *
+ *  Resets the hardware by resetting the transmit and receive units, masks and
+ *  clears all interrupts.
+ **/
+s32 txgbe_reset_hw_vf(struct txgbe_hw *hw)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+       u32 timeout = TXGBE_VF_INIT_TIMEOUT;
+       s32 ret_val = TXGBE_ERR_INVALID_MAC_ADDR;
+       u32 msgbuf[TXGBE_VF_PERMADDR_MSG_LEN];
+       u8 *addr = (u8 *)(&msgbuf[1]);
+
+       DEBUGFUNC("txgbevf_reset_hw_vf");
+
+       /* Call adapter stop to disable tx/rx and clear interrupts */
+       hw->mac.stop_hw(hw);
+
+       /* reset the api version */
+       hw->api_version = txgbe_mbox_api_10;
+
+       /* backup msix vectors */
+       mbx->timeout = TXGBE_VF_MBX_INIT_TIMEOUT;
+       msgbuf[0] = TXGBE_VF_BACKUP;
+       mbx->write_posted(hw, msgbuf, 1, 0);
+       msec_delay(10);
+
+       DEBUGOUT("Issuing a function level reset to MAC\n");
+       wr32(hw, TXGBE_VFRST, TXGBE_VFRST_SET);
+       txgbe_flush(hw);
+       msec_delay(50);
+
+       hw->offset_loaded = 1;
+
+       /* we cannot reset while the RSTI / RSTD bits are asserted */
+       while (!mbx->check_for_rst(hw, 0) && timeout) {
+               timeout--;
+               /* if it doesn't work, try in 1 ms */
+               usec_delay(5);
+       }
+
+       if (!timeout)
+               return TXGBE_ERR_RESET_FAILED;
+
+       /* Reset VF registers to initial values */
+       txgbe_virt_clr_reg(hw);
+
+       /* mailbox timeout can now become active */
+       mbx->timeout = TXGBE_VF_MBX_INIT_TIMEOUT;
+
+       msgbuf[0] = TXGBE_VF_RESET;
+       mbx->write_posted(hw, msgbuf, 1, 0);
+
+       msec_delay(10);
+
+       /*
+        * set our "perm_addr" based on info provided by PF
+        * also set up the mc_filter_type which is piggy backed
+        * on the mac address in word 3
+        */
+       ret_val = mbx->read_posted(hw, msgbuf,
+                       TXGBE_VF_PERMADDR_MSG_LEN, 0);
+       if (ret_val)
+               return ret_val;
+
+       if (msgbuf[0] != (TXGBE_VF_RESET | TXGBE_VT_MSGTYPE_ACK) &&
+           msgbuf[0] != (TXGBE_VF_RESET | TXGBE_VT_MSGTYPE_NACK))
+               return TXGBE_ERR_INVALID_MAC_ADDR;
+
+       if (msgbuf[0] == (TXGBE_VF_RESET | TXGBE_VT_MSGTYPE_ACK))
+               memcpy(hw->mac.perm_addr, addr, ETH_ADDR_LEN);
+
+       hw->mac.mc_filter_type = msgbuf[TXGBE_VF_MC_TYPE_WORD];
+
+       return ret_val;
+}
+
+/**
+ *  txgbe_stop_hw_vf - Generic stop Tx/Rx units
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the adapter_stopped flag within txgbe_hw struct. Clears interrupts,
+ *  disables transmit and receive units. The adapter_stopped flag is used by
+ *  the shared code and drivers to determine if the adapter is in a stopped
+ *  state and should not touch the hardware.
+ **/
+s32 txgbe_stop_hw_vf(struct txgbe_hw *hw)
+{
+       u16 i;
+
+       /*
+        * Set the adapter_stopped flag so other driver functions stop touching
+        * the hardware
+        */
+       hw->adapter_stopped = true;
+
+       /* Clear interrupt mask to stop from interrupts being generated */
+       wr32(hw, TXGBE_VFIMC, TXGBE_VFIMC_MASK);
+
+       /* Clear any pending interrupts, flush previous writes */
+       wr32(hw, TXGBE_VFICR, TXGBE_VFICR_MASK);
+
+       /* Disable the transmit unit.  Each queue must be disabled. */
+       for (i = 0; i < hw->mac.max_tx_queues; i++)
+               wr32(hw, TXGBE_TXCFG(i), TXGBE_TXCFG_FLUSH);
+
+       /* Disable the receive unit by stopping each queue */
+       for (i = 0; i < hw->mac.max_rx_queues; i++)
+               wr32m(hw, TXGBE_RXCFG(i), TXGBE_RXCFG_ENA, 0);
+
+       /* Clear packet split and pool config */
+       wr32(hw, TXGBE_VFPLCFG, 0);
+       hw->rx_loaded = 1;
+
+       /* flush all queues disables */
+       txgbe_flush(hw);
+       msec_delay(2);
+
+       return 0;
+}
+
+STATIC s32 txgbevf_write_msg_read_ack(struct txgbe_hw *hw, u32 *msg,
+                                     u32 *retmsg, u16 size)
+{
+       struct txgbe_mbx_info *mbx = &hw->mbx;
+       s32 retval = mbx->write_posted(hw, msg, size, 0);
+
+       if (retval)
+               return retval;
+
+       return mbx->read_posted(hw, retmsg, size, 0);
+}
+
+/**
+ *  txgbevf_negotiate_api_version - Negotiate supported API version
+ *  @hw: pointer to the HW structure
+ *  @api: integer containing requested API version
+ **/
+int txgbevf_negotiate_api_version(struct txgbe_hw *hw, int api)
+{
+       int err;
+       u32 msg[3];
+
+       /* Negotiate the mailbox API version */
+       msg[0] = TXGBE_VF_API_NEGOTIATE;
+       msg[1] = api;
+       msg[2] = 0;
+
+       err = txgbevf_write_msg_read_ack(hw, msg, msg, 3);
+       if (!err) {
+               msg[0] &= ~TXGBE_VT_MSGTYPE_CTS;
+
+               /* Store value and return 0 on success */
+               if (msg[0] == (TXGBE_VF_API_NEGOTIATE | TXGBE_VT_MSGTYPE_ACK)) {
+                       hw->api_version = api;
+                       return 0;
+               }
+
+               err = TXGBE_ERR_INVALID_ARGUMENT;
+       }
+
+       return err;
+}
+
+int txgbevf_get_queues(struct txgbe_hw *hw, unsigned int *num_tcs,
+                      unsigned int *default_tc)
+{
+       int err, i;
+       u32 msg[5];
+
+       /* do nothing if API doesn't support txgbevf_get_queues */
+       switch (hw->api_version) {
+       case txgbe_mbox_api_11:
+       case txgbe_mbox_api_12:
+       case txgbe_mbox_api_13:
+               break;
+       default:
+               return 0;
+       }
+
+       /* Fetch queue configuration from the PF */
+       msg[0] = TXGBE_VF_GET_QUEUES;
+       for (i = 1; i < 5; i++)
+               msg[i] = 0;
+
+       err = txgbevf_write_msg_read_ack(hw, msg, msg, 5);
+       if (!err) {
+               msg[0] &= ~TXGBE_VT_MSGTYPE_CTS;
+
+               /*
+                * if we didn't get an ACK there must have been
+                * some sort of mailbox error so we should treat it
+                * as such
+                */
+               if (msg[0] != (TXGBE_VF_GET_QUEUES | TXGBE_VT_MSGTYPE_ACK))
+                       return TXGBE_ERR_MBX;
+
+               /* record and validate values from message */
+               hw->mac.max_tx_queues = msg[TXGBE_VF_TX_QUEUES];
+               if (hw->mac.max_tx_queues == 0 ||
+                   hw->mac.max_tx_queues > TXGBE_VF_MAX_TX_QUEUES)
+                       hw->mac.max_tx_queues = TXGBE_VF_MAX_TX_QUEUES;
+
+               hw->mac.max_rx_queues = msg[TXGBE_VF_RX_QUEUES];
+               if (hw->mac.max_rx_queues == 0 ||
+                   hw->mac.max_rx_queues > TXGBE_VF_MAX_RX_QUEUES)
+                       hw->mac.max_rx_queues = TXGBE_VF_MAX_RX_QUEUES;
+
+               *num_tcs = msg[TXGBE_VF_TRANS_VLAN];
+               /* in case of unknown state assume we cannot tag frames */
+               if (*num_tcs > hw->mac.max_rx_queues)
+                       *num_tcs = 1;
+
+               *default_tc = msg[TXGBE_VF_DEF_QUEUE];
+               /* default to queue 0 on out-of-bounds queue number */
+               if (*default_tc >= hw->mac.max_tx_queues)
+                       *default_tc = 0;
+       }
+
+       return err;
+}
diff --git a/drivers/net/txgbe/base/txgbe_vf.h b/drivers/net/txgbe/base/txgbe_vf.h
new file mode 100644 (file)
index 0000000..70f90c2
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2015-2020
+ */
+
+#ifndef _TXGBE_VF_H_
+#define _TXGBE_VF_H_
+
+#include "txgbe_type.h"
+
+#define TXGBE_VF_MAX_TX_QUEUES 8
+#define TXGBE_VF_MAX_RX_QUEUES 8
+
+s32 txgbe_init_ops_vf(struct txgbe_hw *hw);
+s32 txgbe_reset_hw_vf(struct txgbe_hw *hw);
+s32 txgbe_stop_hw_vf(struct txgbe_hw *hw);
+int txgbevf_negotiate_api_version(struct txgbe_hw *hw, int api);
+int txgbevf_get_queues(struct txgbe_hw *hw, unsigned int *num_tcs,
+                      unsigned int *default_tc);
+
+#endif /* __TXGBE_VF_H__ */
index 1c3765e..4fbb4f1 100644 (file)
 #include <rte_log.h>
 #include <ethdev_pci.h>
 
+#include "txgbe_logs.h"
 #include "base/txgbe.h"
 #include "txgbe_ethdev.h"
 #include "txgbe_rxtx.h"
 
 static int txgbevf_dev_close(struct rte_eth_dev *dev);
+static void txgbevf_intr_disable(struct rte_eth_dev *dev);
+static void txgbevf_intr_enable(struct rte_eth_dev *dev);
 
 /*
  * The set of PCI devices this driver supports (for VF)
@@ -27,14 +30,43 @@ static const struct rte_pci_id pci_id_txgbevf_map[] = {
 
 static const struct eth_dev_ops txgbevf_eth_dev_ops;
 
+/*
+ * Negotiate mailbox API version with the PF.
+ * After reset API version is always set to the basic one (txgbe_mbox_api_10).
+ * Then we try to negotiate starting with the most recent one.
+ * If all negotiation attempts fail, then we will proceed with
+ * the default one (txgbe_mbox_api_10).
+ */
+static void
+txgbevf_negotiate_api(struct txgbe_hw *hw)
+{
+       int32_t i;
+
+       /* start with highest supported, proceed down */
+       static const int sup_ver[] = {
+               txgbe_mbox_api_13,
+               txgbe_mbox_api_12,
+               txgbe_mbox_api_11,
+               txgbe_mbox_api_10,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(sup_ver); i++) {
+               if (txgbevf_negotiate_api_version(hw, sup_ver[i]) == 0)
+                       break;
+       }
+}
+
 /*
  * Virtual Function device init
  */
 static int
 eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
 {
+       int err;
+       uint32_t tc, tcs;
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        struct txgbe_hw *hw = TXGBE_DEV_HW(eth_dev);
+
        PMD_INIT_FUNC_TRACE();
 
        eth_dev->dev_ops = &txgbevf_eth_dev_ops;
@@ -71,6 +103,46 @@ eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
        hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
        hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
 
+       /* Initialize the shared code (base driver) */
+       err = txgbe_init_shared_code(hw);
+       if (err != 0) {
+               PMD_INIT_LOG(ERR,
+                       "Shared code init failed for txgbevf: %d", err);
+               return -EIO;
+       }
+
+       /* init_mailbox_params */
+       hw->mbx.init_params(hw);
+
+       /* Disable the interrupts for VF */
+       txgbevf_intr_disable(eth_dev);
+
+       hw->mac.num_rar_entries = 128; /* The MAX of the underlying PF */
+       err = hw->mac.reset_hw(hw);
+
+       /*
+        * The VF reset operation returns the TXGBE_ERR_INVALID_MAC_ADDR when
+        * the underlying PF driver has not assigned a MAC address to the VF.
+        * In this case, assign a random MAC address.
+        */
+       if (err != 0 && err != TXGBE_ERR_INVALID_MAC_ADDR) {
+               PMD_INIT_LOG(ERR, "VF Initialization Failure: %d", err);
+               /*
+                * This error code will be propagated to the app by
+                * rte_eth_dev_reset, so use a public error code rather than
+                * the internal-only TXGBE_ERR_RESET_FAILED
+                */
+               return -EAGAIN;
+       }
+
+       /* negotiate mailbox API version to use with the PF. */
+       txgbevf_negotiate_api(hw);
+
+       /* Get Rx/Tx queue count via mailbox, which is ready after reset_hw */
+       txgbevf_get_queues(hw, &tcs, &tc);
+
+       txgbevf_intr_enable(eth_dev);
+
        return 0;
 }
 
@@ -110,13 +182,57 @@ static struct rte_pci_driver rte_txgbevf_pmd = {
        .remove = eth_txgbevf_pci_remove,
 };
 
+/*
+ * Virtual Function operations
+ */
+static void
+txgbevf_intr_disable(struct rte_eth_dev *dev)
+{
+       struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev);
+       struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+
+       PMD_INIT_FUNC_TRACE();
+
+       /* Clear interrupt mask to stop from interrupts being generated */
+       wr32(hw, TXGBE_VFIMS, TXGBE_VFIMS_MASK);
+
+       txgbe_flush(hw);
+
+       /* Clear mask value. */
+       intr->mask_misc = TXGBE_VFIMS_MASK;
+}
+
+static void
+txgbevf_intr_enable(struct rte_eth_dev *dev)
+{
+       struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev);
+       struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+
+       PMD_INIT_FUNC_TRACE();
+
+       /* VF enable interrupt autoclean */
+       wr32(hw, TXGBE_VFIMC, TXGBE_VFIMC_MASK);
+
+       txgbe_flush(hw);
+
+       intr->mask_misc = 0;
+}
+
 static int
 txgbevf_dev_close(struct rte_eth_dev *dev)
 {
+       struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
        PMD_INIT_FUNC_TRACE();
        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
                return 0;
 
+       hw->mac.reset_hw(hw);
+
+       txgbe_dev_free_queues(dev);
+
+       /* Disable the interrupts for VF */
+       txgbevf_intr_disable(dev);
+
        return 0;
 }