786 lines
20 KiB
C
786 lines
20 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
|
|
|
|
#include "vf.h"
|
|
#include "rnpvf.h"
|
|
|
|
static int rnpvf_reset_pf(struct rnpvf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNP_VF_RESET_PF;
|
|
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 2, false);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 2, false);
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static int rnpvf_get_mtu(struct rnpvf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNP_VF_GET_MTU;
|
|
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 2, false);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 2, false);
|
|
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
|
|
/* if nacked the address was rejected, use "perm_addr" */
|
|
if (!ret_val &&
|
|
(msgbuf[0] == (RNP_VF_SET_MTU | RNP_VT_MSGTYPE_NACK)))
|
|
return -1;
|
|
hw->mtu = msgbuf[1];
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static int rnpvf_set_mtu(struct rnpvf_hw *hw, int mtu)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNP_VF_SET_MTU;
|
|
msgbuf[1] = mtu;
|
|
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 2, false);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 2, false);
|
|
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
|
|
/* if nacked the address was rejected, use "perm_addr" */
|
|
if (!ret_val &&
|
|
(msgbuf[0] == (RNP_VF_SET_MTU | RNP_VT_MSGTYPE_NACK))) {
|
|
// set mtu failed
|
|
return -1;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static int rnpvf_read_eth_reg(struct rnpvf_hw *hw, int reg, u32 *value)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
int err;
|
|
|
|
msgbuf[0] = RNP_VF_REG_RD;
|
|
msgbuf[1] = reg;
|
|
|
|
err = mbx->ops.write_posted(hw, msgbuf, 2, false);
|
|
if (err)
|
|
goto mbx_err;
|
|
|
|
err = mbx->ops.read_posted(hw, msgbuf, 2, false);
|
|
if (err)
|
|
goto mbx_err;
|
|
|
|
/* remove extra bits from the message */
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
msgbuf[0] &= ~(0xFF << RNP_VT_MSGINFO_SHIFT);
|
|
|
|
if (msgbuf[0] != (RNP_VF_REG_RD | RNP_VT_MSGTYPE_ACK))
|
|
err = RNP_ERR_INVALID_ARGUMENT;
|
|
|
|
*value = msgbuf[1];
|
|
|
|
mbx_err:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_start_hw_vf - Prepare hardware for Tx/Rx
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Starts the hardware by filling the bus info structure and media type, clears
|
|
* all on chip counters, initializes receive address registers, multicast
|
|
* table, VLAN filter table, calls routine to set up link and flow control
|
|
* settings, and leaves transmit and receive units disabled and uninitialized
|
|
**/
|
|
static s32 rnpvf_start_hw_vf(struct rnpvf_hw *hw)
|
|
{
|
|
/* Clear adapter stopped flag */
|
|
hw->adapter_stopped = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_init_hw_vf - virtual function hardware initialization
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Initialize the hardware by resetting the hardware and then starting
|
|
* the hardware
|
|
**/
|
|
static s32 rnpvf_init_hw_vf(struct rnpvf_hw *hw)
|
|
{
|
|
s32 status;
|
|
|
|
status = hw->mac.ops.start_hw(hw);
|
|
|
|
hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_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.
|
|
**/
|
|
static s32 rnpvf_reset_hw_vf(struct rnpvf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
struct rnpvf_adapter *adapter = hw->back;
|
|
// u32 timeout = RNP_VF_INIT_TIMEOUT;
|
|
s32 ret_val = RNP_ERR_INVALID_MAC_ADDR;
|
|
u32 msgbuf[RNP_VF_PERMADDR_MSG_LEN];
|
|
u8 *addr = (u8 *)(&msgbuf[1]);
|
|
u32 vlan;
|
|
int try_cnt = 10;
|
|
|
|
/* Call adapter stop to disable tx/rx and clear interrupts */
|
|
hw->mac.ops.stop_adapter(hw);
|
|
|
|
/* reset the api version */
|
|
hw->api_version = 0;
|
|
|
|
/* mailbox timeout can now become active */
|
|
mbx->timeout = RNP_VF_MBX_INIT_TIMEOUT;
|
|
|
|
while (try_cnt--) {
|
|
msgbuf[0] = RNP_VF_RESET;
|
|
mbx->ops.write_posted(hw, msgbuf, 1, false);
|
|
/* ack write back maybe too fast */
|
|
mdelay(20);
|
|
|
|
/* 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->ops.read_posted(hw, msgbuf,
|
|
RNP_VF_PERMADDR_MSG_LEN,
|
|
false);
|
|
if (ret_val == 0)
|
|
break;
|
|
}
|
|
if (ret_val)
|
|
return ret_val;
|
|
|
|
/* New versions of the PF may NACK the reset return message
|
|
* to indicate that no MAC address has yet been assigned for
|
|
* the VF.
|
|
*/
|
|
if (msgbuf[0] != (RNP_VF_RESET | RNP_VT_MSGTYPE_ACK) &&
|
|
msgbuf[0] != (RNP_VF_RESET | RNP_VT_MSGTYPE_NACK))
|
|
return RNP_ERR_INVALID_MAC_ADDR;
|
|
/* we get mac address from mailbox */
|
|
|
|
memcpy(hw->mac.perm_addr, addr, ETH_ALEN);
|
|
hw->mac.mc_filter_type = msgbuf[RNP_VF_MC_TYPE_WORD] & 0xff;
|
|
|
|
/* ft padding */
|
|
if ((msgbuf[RNP_VF_MC_TYPE_WORD] >> 8) & 0xff)
|
|
adapter->priv_flags |= RNPVF_PRIV_FLAG_FT_PADDING;
|
|
else
|
|
adapter->priv_flags = 0;
|
|
/* fc mode */
|
|
hw->fc.current_mode = (msgbuf[RNP_VF_MC_TYPE_WORD] >> 16) & 0xff;
|
|
|
|
/* phy status */
|
|
hw->phy_type = (msgbuf[RNP_VF_PHY_TYPE_WORD] & 0xffff);
|
|
|
|
hw->mac.dma_version = msgbuf[RNP_VF_DMA_VERSION_WORD];
|
|
hw->dma_version = hw->mac.dma_version;
|
|
|
|
/* vlan status */
|
|
vlan = msgbuf[RNP_VF_VLAN_WORD];
|
|
if (vlan & 0xffff) {
|
|
adapter->vf_vlan = vlan & 0xffff;
|
|
adapter->flags |= RNPVF_FLAG_PF_SET_VLAN;
|
|
}
|
|
hw->ops.set_veb_vlan(hw, vlan, VFNUM(mbx, hw->vfnum));
|
|
hw->fw_version = msgbuf[RNP_VF_FW_VERSION_WORD];
|
|
|
|
if (msgbuf[RNP_VF_LINK_STATUS_WORD] & RNP_PF_LINK_UP) {
|
|
hw->link = true;
|
|
hw->speed = msgbuf[RNP_VF_LINK_STATUS_WORD] & 0xffff;
|
|
|
|
} else {
|
|
hw->link = false;
|
|
hw->speed = 0;
|
|
}
|
|
|
|
hw->usecstocount = msgbuf[RNP_VF_AXI_MHZ];
|
|
|
|
DPRINTK(PROBE, INFO, "dma_versioin:%x vlan %d\n",
|
|
hw->mac.dma_version, adapter->vf_vlan);
|
|
DPRINTK(PROBE, INFO, "axi:%x\n", hw->usecstocount);
|
|
DPRINTK(PROBE, INFO, "firmware :%x\n", hw->fw_version);
|
|
DPRINTK(PROBE, INFO, "link speed :%x\n", hw->speed);
|
|
DPRINTK(PROBE, INFO, "link status :%s\n",
|
|
hw->link ? "up" : "down");
|
|
hw->pf_feature = msgbuf[RNP_VF_FEATURE];
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_stop_hw_vf - Generic stop Tx/Rx units
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Sets the adapter_stopped flag within rnpvf_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.
|
|
**/
|
|
static s32 rnpvf_stop_hw_vf(struct rnpvf_hw *hw)
|
|
{
|
|
u16 i;
|
|
struct rnpvf_adapter *adapter = hw->back;
|
|
struct rnpvf_ring *ring;
|
|
|
|
/* Set the adapter_stopped flag so other driver functions stop touching
|
|
* the hardware
|
|
*/
|
|
hw->adapter_stopped = true;
|
|
|
|
/* Disable the receive unit by stopped each queue */
|
|
for (i = 0; i < adapter->num_rx_queues; i++) {
|
|
ring = adapter->rx_ring[i];
|
|
ring_wr32(ring, RNP_DMA_RX_START, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_mta_vector - Determines bit-vector in multicast table to set
|
|
* @hw: pointer to hardware structure
|
|
* @mc_addr: the multicast address
|
|
*
|
|
* Extracts the 12 bits, from a multicast address, to determine which
|
|
* bit-vector to set in the multicast table. The hardware uses 12 bits, from
|
|
* incoming rx multicast addresses, to determine the bit-vector to check in
|
|
* the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
|
|
* by the MO field of the MCSTCTRL. The MO field is set during initialization
|
|
* to mc_filter_type.
|
|
**/
|
|
static s32 rnpvf_mta_vector(struct rnpvf_hw *hw, u8 *mc_addr)
|
|
{
|
|
u32 vector = 0;
|
|
|
|
switch (hw->mac.mc_filter_type) {
|
|
case 0: /* use bits [47:36] of the address */
|
|
vector = ((mc_addr[4] << 8) | (((u16)mc_addr[5])));
|
|
break;
|
|
case 1: /* use bits [46:35] of the address */
|
|
vector = ((mc_addr[4] << 7) | (((u16)mc_addr[5]) >> 1));
|
|
break;
|
|
case 2: /* use bits [45:34] of the address */
|
|
vector = ((mc_addr[4] << 6) | (((u16)mc_addr[5]) >> 2));
|
|
break;
|
|
case 3: /* use bits [43:32] of the address */
|
|
vector = ((mc_addr[4]) << 4 | (((u16)mc_addr[5]) >> 4));
|
|
break;
|
|
case 4: /* use bits [32:43] of the address */
|
|
vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1])));
|
|
vector = (vector >> 4);
|
|
break;
|
|
case 5: /* use bits [32:43] of the address */
|
|
vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1])));
|
|
vector = (vector >> 3);
|
|
break;
|
|
case 6: /* use bits [32:43] of the address */
|
|
vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1])));
|
|
vector = (vector >> 2);
|
|
break;
|
|
case 7: /* use bits [32:43] of the address */
|
|
vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1])));
|
|
break;
|
|
default: /* Invalid mc_filter_type */
|
|
break;
|
|
}
|
|
|
|
/* vector can only be 12-bits or boundary will be exceeded */
|
|
vector &= 0xFFF;
|
|
return vector;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_get_mac_addr_vf - Read device MAC address
|
|
* @hw: pointer to the HW structure
|
|
* @mac_addr: pointer to storage for retrieved MAC address
|
|
**/
|
|
static s32 rnpvf_get_mac_addr_vf(struct rnpvf_hw *hw, u8 *mac_addr)
|
|
{
|
|
// memcpy(mac_addr, hw->mac.perm_addr, ETH_ALEN);
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[3];
|
|
u8 *msg_addr = (u8 *)(&msgbuf[1]);
|
|
s32 ret_val = 0;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
/* If index is one then this is the start of a new list and needs
|
|
* indication to the PF so it can do it's own list management.
|
|
* If it is zero then that tells the PF to just clear all of
|
|
* this VF's macvlans and there is no new list.
|
|
*/
|
|
msgbuf[0] |= RNP_VF_SET_MACVLAN;
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 1, false);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 3, false);
|
|
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
|
|
if (!ret_val)
|
|
if (msgbuf[0] ==
|
|
(RNP_VF_GET_MACVLAN | RNP_VT_MSGTYPE_NACK))
|
|
ret_val = -ENOMEM;
|
|
|
|
memcpy(mac_addr, msg_addr, 6);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_get_queues_vf - Read device MAC address
|
|
* @hw: pointer to the HW structure
|
|
*
|
|
**/
|
|
static s32 rnpvf_get_queues_vf(struct rnpvf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
s32 ret_val = 0;
|
|
u32 msgbuf[7];
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] |= RNP_VF_GET_QUEUE;
|
|
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 1, false);
|
|
|
|
mdelay(10);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 7, false);
|
|
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
|
|
if (!ret_val)
|
|
if (msgbuf[0] == (RNP_VF_GET_QUEUE | RNP_VT_MSGTYPE_NACK))
|
|
ret_val = -ENOMEM;
|
|
#define MSG_TX_NUM_WORD 1
|
|
#define MSG_RX_NUM_WORD 2
|
|
#define MSG_RING_BASE_WORD 5
|
|
#define MSG_RING_DEPTH 6
|
|
|
|
hw->queue_ring_base = msgbuf[MSG_RING_BASE_WORD];
|
|
hw->mac.max_tx_queues = msgbuf[MSG_TX_NUM_WORD];
|
|
hw->mac.max_rx_queues = msgbuf[MSG_RX_NUM_WORD];
|
|
hw->tx_items_count = 0xffff & (msgbuf[MSG_RING_DEPTH] >> 16);
|
|
hw->rx_items_count = 0xffff & (msgbuf[MSG_RING_DEPTH] >> 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 rnpvf_set_uc_addr_vf(struct rnpvf_hw *hw, u32 index, u8 *addr)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[3];
|
|
u8 *msg_addr = (u8 *)(&msgbuf[1]);
|
|
s32 ret_val = 0;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
/* If index is one then this is the start of a new list and needs
|
|
* indication to the PF so it can do it's own list management.
|
|
* If it is zero then that tells the PF to just clear all of
|
|
* this VF's macvlans and there is no new list.
|
|
*/
|
|
msgbuf[0] |= index << RNP_VT_MSGINFO_SHIFT;
|
|
msgbuf[0] |= RNP_VF_SET_MACVLAN;
|
|
if (addr)
|
|
memcpy(msg_addr, addr, 6);
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 3, false);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 3, false);
|
|
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
|
|
if (!ret_val)
|
|
if (msgbuf[0] ==
|
|
(RNP_VF_SET_MACVLAN | RNP_VT_MSGTYPE_NACK))
|
|
ret_val = -ENOMEM;
|
|
return ret_val;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_set_rar_vf - set device MAC address
|
|
* @hw: pointer to hardware structure
|
|
* @index: Receive address register to write
|
|
* @addr: Address to put into receive address register
|
|
* @vmdq: Unused in this implementation
|
|
**/
|
|
static s32 rnpvf_set_rar_vf(struct rnpvf_hw *hw, u32 index, u8 *addr,
|
|
u32 vmdq)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[3];
|
|
u8 *msg_addr = (u8 *)(&msgbuf[1]);
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNP_VF_SET_MAC_ADDR;
|
|
memcpy(msg_addr, addr, 6);
|
|
ret_val = mbx->ops.write_posted(hw, msgbuf, 3, false);
|
|
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read_posted(hw, msgbuf, 3, false);
|
|
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
|
|
/* if nacked the address was rejected, use "perm_addr" */
|
|
if (!ret_val &&
|
|
(msgbuf[0] == (RNP_VF_SET_MAC_ADDR | RNP_VT_MSGTYPE_NACK))) {
|
|
rnpvf_get_mac_addr_vf(hw, hw->mac.addr);
|
|
return -1;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static void rnpvf_write_msg_read_ack(struct rnpvf_hw *hw, u32 *msg,
|
|
u16 size)
|
|
{
|
|
u32 retmsg[RNP_VFMAILBOX_SIZE];
|
|
s32 retval;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
|
|
retval = mbx->ops.write_posted(hw, msg, size, false);
|
|
if (!retval)
|
|
mbx->ops.read_posted(hw, retmsg, size, false);
|
|
}
|
|
|
|
static u8 *rnpvf_addr_list_itr(struct rnpvf_hw __maybe_unused *hw,
|
|
u8 **mc_addr_ptr)
|
|
{
|
|
struct netdev_hw_addr *mc_ptr;
|
|
u8 *addr = *mc_addr_ptr;
|
|
|
|
mc_ptr = container_of(addr, struct netdev_hw_addr, addr[0]);
|
|
if (mc_ptr->list.next) {
|
|
struct netdev_hw_addr *ha;
|
|
|
|
ha = list_entry(mc_ptr->list.next, struct netdev_hw_addr,
|
|
list);
|
|
*mc_addr_ptr = ha->addr;
|
|
} else {
|
|
*mc_addr_ptr = NULL;
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_update_mc_addr_list_vf - Update Multicast addresses
|
|
* @hw: pointer to the HW structure
|
|
* @netdev: pointer to net device structure
|
|
*
|
|
* Updates the Multicast Table Array.
|
|
**/
|
|
static s32 rnpvf_update_mc_addr_list_vf(struct rnpvf_hw *hw,
|
|
struct net_device *netdev)
|
|
{
|
|
struct netdev_hw_addr *ha;
|
|
u32 msgbuf[RNP_VFMAILBOX_SIZE];
|
|
u16 *vector_list = (u16 *)&msgbuf[1];
|
|
u32 cnt, i;
|
|
int addr_count = 0;
|
|
u8 *addr_list = NULL;
|
|
|
|
/* Each entry in the list uses 1 16 bit word. We have 30
|
|
* 16 bit words available in our HW msg buffer (minus 1 for the
|
|
* msg type). That's 30 hash values if we pack 'em right. If
|
|
* there are more than 30 MC addresses to add then punt the
|
|
* extras for now and then add code to handle more than 30 later.
|
|
* It would be unusual for a server to request that many multi-cast
|
|
* addresses except for in large enterprise network environments.
|
|
*/
|
|
|
|
cnt = netdev_mc_count(netdev);
|
|
if (cnt > 30)
|
|
cnt = 30;
|
|
msgbuf[0] = RNP_VF_SET_MULTICAST;
|
|
msgbuf[0] |= cnt << RNP_VT_MSGINFO_SHIFT;
|
|
|
|
addr_count = netdev_mc_count(netdev);
|
|
|
|
ha = list_first_entry(&netdev->mc.list, struct netdev_hw_addr,
|
|
list);
|
|
addr_list = ha->addr;
|
|
for (i = 0; i < addr_count; i++) {
|
|
vector_list[i] = rnpvf_mta_vector(hw,
|
|
rnpvf_addr_list_itr(hw, &addr_list));
|
|
}
|
|
|
|
rnpvf_write_msg_read_ack(hw, msgbuf, RNP_VFMAILBOX_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_set_vfta_vf - Set/Unset vlan filter table address
|
|
* @hw: pointer to the HW structure
|
|
* @vlan: 12 bit VLAN ID
|
|
* @vind: unused by VF drivers
|
|
* @vlan_on: if true then set bit, else clear bit
|
|
**/
|
|
static s32 rnpvf_set_vfta_vf(struct rnpvf_hw *hw, u32 vlan, u32 vind,
|
|
bool vlan_on)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 err;
|
|
|
|
msgbuf[0] = RNP_VF_SET_VLAN;
|
|
msgbuf[1] = vlan;
|
|
/* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
|
|
msgbuf[0] |= vlan_on << RNP_VT_MSGINFO_SHIFT;
|
|
|
|
err = mbx->ops.write_posted(hw, msgbuf, 2, false);
|
|
if (err)
|
|
goto mbx_err;
|
|
|
|
err = mbx->ops.read_posted(hw, msgbuf, 2, false);
|
|
if (err)
|
|
goto mbx_err;
|
|
|
|
/* remove extra bits from the message */
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
msgbuf[0] &= ~(0xFF << RNP_VT_MSGINFO_SHIFT);
|
|
|
|
if (msgbuf[0] != (RNP_VF_SET_VLAN | RNP_VT_MSGTYPE_ACK))
|
|
err = RNP_ERR_INVALID_ARGUMENT;
|
|
|
|
mbx_err:
|
|
return err;
|
|
}
|
|
|
|
static s32 rnpvf_set_vlan_strip(struct rnpvf_hw *hw, bool vlan_on)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
struct rnpvf_adapter *adapter = (struct rnpvf_adapter *)hw->back;
|
|
u32 msgbuf[4];
|
|
s32 err;
|
|
int i;
|
|
|
|
if (adapter->num_rx_queues > 2) {
|
|
err = -EINVAL;
|
|
goto mbx_err;
|
|
}
|
|
|
|
msgbuf[0] = RNP_VF_SET_VLAN_STRIP;
|
|
msgbuf[1] = (vlan_on << 31) | adapter->num_rx_queues;
|
|
|
|
for (i = 0; i < adapter->num_rx_queues; i++)
|
|
msgbuf[2 + i] = adapter->rx_ring[i]->rnpvf_queue_idx;
|
|
|
|
err = mbx->ops.write_posted(hw, msgbuf, 2 + adapter->num_rx_queues,
|
|
false);
|
|
if (err)
|
|
goto mbx_err;
|
|
|
|
err = mbx->ops.read_posted(hw, msgbuf, 1, false);
|
|
if (err)
|
|
goto mbx_err;
|
|
|
|
/* remove extra bits from the message */
|
|
msgbuf[0] &= ~RNP_VT_MSGTYPE_CTS;
|
|
msgbuf[0] &= ~(0xFF << RNP_VT_MSGINFO_SHIFT);
|
|
|
|
if (msgbuf[0] != (RNP_VF_SET_VLAN_STRIP | RNP_VT_MSGTYPE_ACK))
|
|
err = RNP_ERR_INVALID_ARGUMENT;
|
|
|
|
mbx_err:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_setup_mac_link_vf - Setup MAC link settings
|
|
* @hw: pointer to hardware structure
|
|
* @speed: Unused in this implementation
|
|
* @autoneg: Unused in this implementation
|
|
* @autoneg_wait_to_complete: Unused in this implementation
|
|
*
|
|
* Do nothing and return success. VF drivers are not allowed to change
|
|
* global settings. Maintained for driver compatibility.
|
|
**/
|
|
static s32 rnpvf_setup_mac_link_vf(struct rnpvf_hw *hw,
|
|
rnp_link_speed speed, bool autoneg,
|
|
bool autoneg_wait_to_complete)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_check_mac_link_vf - Get link/speed status
|
|
* @hw: pointer to hardware structure
|
|
* @speed: pointer to link speed
|
|
* @link_up: true is link is up, false otherwise
|
|
* @autoneg_wait_to_complete: true when waiting for completion is needed
|
|
*
|
|
* Reads the links register to determine if link is up and the current speed
|
|
**/
|
|
static s32 rnpvf_check_mac_link_vf(struct rnpvf_hw *hw,
|
|
rnp_link_speed *speed, bool *link_up,
|
|
bool autoneg_wait_to_complete)
|
|
{
|
|
*speed = hw->speed;
|
|
*link_up = hw->link;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpvf_rlpml_set_vf - Set the maximum receive packet length
|
|
* @hw: pointer to the HW structure
|
|
* @max_size: value to assign to max frame size
|
|
**/
|
|
void rnpvf_rlpml_set_vf(struct rnpvf_hw *hw, u16 max_size)
|
|
{
|
|
u32 msgbuf[2];
|
|
|
|
msgbuf[0] = RNP_VF_SET_LPE;
|
|
msgbuf[1] = max_size;
|
|
rnpvf_write_msg_read_ack(hw, msgbuf, 2);
|
|
}
|
|
|
|
static void rnpvf_set_veb_mac_n10(struct rnpvf_hw *hw,
|
|
u8 *mac,
|
|
u32 vfnum,
|
|
u32 ring)
|
|
{
|
|
int port;
|
|
u32 maclow, machi;
|
|
|
|
maclow = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
|
|
machi = (mac[0] << 8) | mac[1];
|
|
for (port = 0; port < 4; port++) {
|
|
maclow = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
|
|
mac[5];
|
|
machi = (mac[0] << 8) | mac[1];
|
|
|
|
wr32(hw, RNP_DMA_PORT_VBE_MAC_LO_TBL_N10(port, vfnum),
|
|
maclow);
|
|
wr32(hw, RNP_DMA_PORT_VBE_MAC_HI_TBL_N10(port, vfnum),
|
|
machi);
|
|
wr32(hw, RNP_DMA_PORT_VEB_VF_RING_TBL_N10(port, vfnum),
|
|
ring);
|
|
}
|
|
}
|
|
|
|
static void rnpvf_set_vlan_n10(struct rnpvf_hw *hw, u16 vid, u32 vf_num)
|
|
{
|
|
int port;
|
|
|
|
for (port = 0; port < 4; port++)
|
|
wr32(hw, RNP_DMA_PORT_VEB_VID_TBL_N10(port, vf_num), vid);
|
|
}
|
|
|
|
static const struct rnpvf_hw_operations rnpvf_hw_ops_n10 = {
|
|
.set_veb_mac = rnpvf_set_veb_mac_n10,
|
|
.set_veb_vlan = rnpvf_set_vlan_n10,
|
|
};
|
|
|
|
static s32 rnpvf_get_invariants_n10(struct rnpvf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
#ifdef FIX_MAC_PADDIN
|
|
struct rnpvf_adapter *adapter = (struct rnpvf_adapter *)hw->back;
|
|
#endif
|
|
|
|
hw->feature_flags |=
|
|
RNPVF_NET_FEATURE_SG | RNPVF_NET_FEATURE_TX_CHECKSUM |
|
|
RNPVF_NET_FEATURE_RX_CHECKSUM | RNPVF_NET_FEATURE_TSO |
|
|
RNPVF_NET_FEATURE_TX_UDP_TUNNEL |
|
|
RNPVF_NET_FEATURE_VLAN_OFFLOAD | RNPVF_NET_FEATURE_RX_HASH;
|
|
|
|
mbx->pf2vf_mbox_vec_base = 0xa5000;
|
|
mbx->vf2pf_mbox_vec_base = 0xa5100;
|
|
mbx->cpu2vf_mbox_vec_base = 0xa5200;
|
|
mbx->cpu2pf_mbox_vec = 0xa5300;
|
|
mbx->pf_vf_shm_base = 0xa6000;
|
|
mbx->cpu_vf_shm_base = 0xa8000;
|
|
mbx->vf2cpu_mbox_ctrl_base = 0xa9000;
|
|
mbx->cpu_vf_mbox_mask_lo_base = 0xa9200;
|
|
mbx->cpu_vf_mbox_mask_hi_base = 0xa9300;
|
|
mbx->mbx_mem_size = 64;
|
|
|
|
mbx->vf2pf_mbox_ctrl_base = 0xa7000;
|
|
mbx->pf2vf_mbox_ctrl_base = 0xa7100;
|
|
mbx->pf_vf_mbox_mask_lo = 0xa7200;
|
|
mbx->pf_vf_mbox_mask_hi = 0xa7300;
|
|
|
|
mbx->cpu_pf_shm_base = 0xaa000;
|
|
mbx->pf2cpu_mbox_ctrl = 0xaa100;
|
|
mbx->pf2cpu_mbox_mask = 0xaa300;
|
|
|
|
mbx->vf_num_mask = 0x3f;
|
|
|
|
hw->min_length = RNPVF_MIN_MTU;
|
|
hw->max_length = RNPVF_N10_MAX_JUMBO_FRAME_SIZE;
|
|
|
|
#ifdef FIX_MAC_PADDIN
|
|
adapter->priv_flags |= RNPVF_PRIV_FLAG_TX_PADDING;
|
|
#endif
|
|
|
|
memcpy(&hw->ops, &rnpvf_hw_ops_n10, sizeof(hw->ops));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct rnp_mac_operations rnpvf_mac_ops = {
|
|
.init_hw = rnpvf_init_hw_vf,
|
|
.reset_hw = rnpvf_reset_hw_vf,
|
|
.start_hw = rnpvf_start_hw_vf,
|
|
.get_mac_addr = rnpvf_get_mac_addr_vf,
|
|
.get_queues = rnpvf_get_queues_vf,
|
|
.stop_adapter = rnpvf_stop_hw_vf,
|
|
.setup_link = rnpvf_setup_mac_link_vf,
|
|
.check_link = rnpvf_check_mac_link_vf,
|
|
.set_rar = rnpvf_set_rar_vf,
|
|
.update_mc_addr_list = rnpvf_update_mc_addr_list_vf,
|
|
.set_uc_addr = rnpvf_set_uc_addr_vf,
|
|
.set_vfta = rnpvf_set_vfta_vf,
|
|
.set_vlan_strip = rnpvf_set_vlan_strip,
|
|
.read_eth_reg = rnpvf_read_eth_reg,
|
|
.get_mtu = rnpvf_get_mtu,
|
|
.set_mtu = rnpvf_set_mtu,
|
|
.req_reset_pf = rnpvf_reset_pf,
|
|
};
|
|
|
|
const struct rnpvf_info rnp_n10_vf_info = {
|
|
.mac = rnp_mac_2port_40G,
|
|
.mac_ops = &rnpvf_mac_ops,
|
|
.board_type = rnp_board_n10,
|
|
.get_invariants = &rnpvf_get_invariants_n10,
|
|
};
|