From: Jiawen Wu Date: Thu, 25 Feb 2021 08:08:46 +0000 (+0800) Subject: net/txgbe: add VF base code X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=de4576944c7e3676e31618b03d421f5467eefab7;p=dpdk.git net/txgbe: add VF base code Implement VF device init and uninit function with hardware operations, and negotiate with PF in mailbox. Signed-off-by: Jiawen Wu --- diff --git a/drivers/net/txgbe/base/meson.build b/drivers/net/txgbe/base/meson.build index 3c63bf5f4c..33d0adf0d6 100644 --- a/drivers/net/txgbe/base/meson.build +++ b/drivers/net/txgbe/base/meson.build @@ -9,6 +9,7 @@ sources = [ 'txgbe_mbx.c', 'txgbe_mng.c', 'txgbe_phy.c', + 'txgbe_vf.c', ] error_cflags = [] diff --git a/drivers/net/txgbe/base/txgbe.h b/drivers/net/txgbe/base/txgbe.h index b054bb8d0f..d7199512b8 100644 --- a/drivers/net/txgbe/base/txgbe.h +++ b/drivers/net/txgbe/base/txgbe.h @@ -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_ */ diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index dc419d7d42..c357c8658c 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -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; diff --git a/drivers/net/txgbe/base/txgbe_mbx.c b/drivers/net/txgbe/base/txgbe_mbx.c index bfe53478ea..b308839e78 100644 --- a/drivers/net/txgbe/base/txgbe_mbx.c +++ b/drivers/net/txgbe/base/txgbe_mbx.c @@ -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)); diff --git a/drivers/net/txgbe/base/txgbe_mbx.h b/drivers/net/txgbe/base/txgbe_mbx.h index 4a058b0bbc..ccf5d12f21 100644 --- a/drivers/net/txgbe/base/txgbe_mbx.h +++ b/drivers/net/txgbe/base/txgbe_mbx.h @@ -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_ */ diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index 22efcef784..ef8358ae37 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -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 index 0000000000..5d4e101586 --- /dev/null +++ b/drivers/net/txgbe/base/txgbe_vf.c @@ -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 index 0000000000..70f90c2629 --- /dev/null +++ b/drivers/net/txgbe/base/txgbe_vf.h @@ -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__ */ diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c index 1c3765e4e4..4fbb4f1540 100644 --- a/drivers/net/txgbe/txgbe_ethdev_vf.c +++ b/drivers/net/txgbe/txgbe_ethdev_vf.c @@ -10,11 +10,14 @@ #include #include +#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; }