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 <jiawenwu@trustnetic.com>
This commit is contained in:
Jiawen Wu 2021-02-25 16:08:46 +08:00 committed by Ferruh Yigit
parent 803e4bb14d
commit de4576944c
9 changed files with 804 additions and 0 deletions

View File

@ -9,6 +9,7 @@ sources = [
'txgbe_mbx.c',
'txgbe_mng.c',
'txgbe_phy.c',
'txgbe_vf.c',
]
error_cflags = []

View 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_ */

View 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;

View 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));

View 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_ */

View 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;

View File

@ -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;
}

View File

@ -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__ */

View File

@ -10,11 +10,14 @@
#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;
}