815 lines
22 KiB
C
815 lines
22 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
|
|
|
|
#include "vf.h"
|
|
#include "rnpgbevf.h"
|
|
|
|
static int rnpgbevf_reset_pf(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNPGBE_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 rnpgbevf_get_mtu(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
|
|
/* if nacked the address was rejected, use "perm_addr" */
|
|
if (!ret_val &&
|
|
(msgbuf[0] == (RNPGBE_VF_GET_MTU | RNPGBE_VT_MSGTYPE_NACK))) {
|
|
return -1;
|
|
}
|
|
hw->mtu = msgbuf[1];
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static int rnpgbevf_set_mtu(struct rnpgbevf_hw *hw, int mtu)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 ret_val;
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
|
|
/* if nacked the address was rejected, use "perm_addr" */
|
|
if (!ret_val &&
|
|
(msgbuf[0] == (RNPGBE_VF_SET_MTU | RNPGBE_VT_MSGTYPE_NACK))) {
|
|
return -1;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static int rnpgbevf_read_eth_reg(struct rnpgbevf_hw *hw, int reg, u32 *value)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
int err;
|
|
|
|
msgbuf[0] = RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
msgbuf[0] &= ~(0xFF << RNPGBE_VT_MSGINFO_SHIFT);
|
|
|
|
if (msgbuf[0] != (RNPGBE_VF_REG_RD | RNPGBE_VT_MSGTYPE_ACK))
|
|
err = RNPGBE_ERR_INVALID_ARGUMENT;
|
|
|
|
*value = msgbuf[1];
|
|
|
|
mbx_err:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_start_hw_vf(struct rnpgbevf_hw *hw)
|
|
{
|
|
/* Clear adapter stopped flag */
|
|
hw->adapter_stopped = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_init_hw_vf(struct rnpgbevf_hw *hw)
|
|
{
|
|
s32 status;
|
|
|
|
status = hw->mac.ops.start_hw(hw);
|
|
|
|
hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_reset_hw_vf(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
struct rnpgbevf_adapter *adapter = hw->back;
|
|
s32 ret_val = RNPGBE_ERR_INVALID_MAC_ADDR;
|
|
u32 msgbuf[RNPGBE_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 = RNPGBE_VF_MBX_INIT_TIMEOUT;
|
|
|
|
while (try_cnt--) {
|
|
msgbuf[0] = RNPGBE_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,
|
|
RNPGBE_VF_PERMADDR_MSG_LEN,
|
|
false);
|
|
if (ret_val == 0)
|
|
break;
|
|
}
|
|
if (ret_val) {
|
|
dev_info(&hw->pdev->dev, "echo vf reset timeout\n");
|
|
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] != (RNPGBE_VF_RESET | RNPGBE_VT_MSGTYPE_ACK) &&
|
|
msgbuf[0] != (RNPGBE_VF_RESET | RNPGBE_VT_MSGTYPE_NACK))
|
|
return RNPGBE_ERR_INVALID_MAC_ADDR;
|
|
/* we get mac address from mailbox */
|
|
|
|
memcpy(hw->mac.perm_addr, addr, ETH_ALEN);
|
|
hw->mac.mc_filter_type = msgbuf[RNPGBE_VF_MC_TYPE_WORD] & 0xff;
|
|
|
|
/* ft padding */
|
|
if ((msgbuf[RNPGBE_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[RNPGBE_VF_MC_TYPE_WORD] >> 16) & 0xff;
|
|
|
|
/* phy status */
|
|
hw->phy_type = (msgbuf[RNPGBE_VF_PHY_TYPE_WORD] & 0xffff);
|
|
|
|
hw->mac.dma_version = msgbuf[RNPGBE_VF_DMA_VERSION_WORD];
|
|
|
|
hw->dma_version = hw->mac.dma_version;
|
|
/* vlan status */
|
|
vlan = msgbuf[RNPGBE_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[RNPGBE_VF_FW_VERSION_WORD];
|
|
|
|
if (msgbuf[RNPGBE_VF_LINK_STATUS_WORD] & RNPGBE_PF_LINK_UP) {
|
|
hw->link = true;
|
|
hw->speed = msgbuf[RNPGBE_VF_LINK_STATUS_WORD] & 0xffff;
|
|
|
|
} else {
|
|
hw->link = false;
|
|
hw->speed = 0;
|
|
}
|
|
|
|
hw->usecstocount = msgbuf[RNPGBE_VF_AXI_MHZ];
|
|
|
|
DPRINTK(PROBE, INFO, "dma_version:%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[RNPGBE_VF_FEATURE];
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_stop_hw_vf - Generic stop Tx/Rx units
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Sets the adapter_stopped flag within rnpgbevf_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 rnpgbevf_stop_hw_vf(struct rnpgbevf_hw *hw)
|
|
{
|
|
u16 i;
|
|
struct rnpgbevf_adapter *adapter = hw->back;
|
|
struct rnpgbevf_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, RNPGBE_DMA_RX_START, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_mta_vector(struct rnpgbevf_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;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_get_mac_addr_vf(struct rnpgbevf_hw *hw, u8 *mac_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] |= RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
|
|
if (!ret_val) {
|
|
if (msgbuf[0] ==
|
|
(RNPGBE_VF_GET_MACVLAN | RNPGBE_VT_MSGTYPE_NACK))
|
|
ret_val = -ENOMEM;
|
|
}
|
|
|
|
memcpy(mac_addr, msg_addr, 6);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_get_queues_vf - Read device MAC address
|
|
* @hw: pointer to the HW structure
|
|
**/
|
|
static s32 rnpgbevf_get_queues_vf(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
s32 ret_val = 0;
|
|
u32 msgbuf[7];
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] |= RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
|
|
if (!ret_val)
|
|
if (msgbuf[0] == (RNPGBE_VF_GET_QUEUE | RNPGBE_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 rnpgbevf_set_uc_addr_vf(struct rnpgbevf_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 << RNPGBE_VT_MSGINFO_SHIFT;
|
|
msgbuf[0] |= RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
|
|
if (!ret_val)
|
|
if (msgbuf[0] ==
|
|
(RNPGBE_VF_SET_MACVLAN | RNPGBE_VT_MSGTYPE_NACK))
|
|
ret_val = -ENOMEM;
|
|
return ret_val;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_set_rar_vf(struct rnpgbevf_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] = RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
|
|
/* if nacked the address was rejected, use "perm_addr" */
|
|
if (!ret_val &&
|
|
(msgbuf[0] == (RNPGBE_VF_SET_MAC_ADDR | RNPGBE_VT_MSGTYPE_NACK))) {
|
|
rnpgbevf_get_mac_addr_vf(hw, hw->mac.addr);
|
|
return -1;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static void rnpgbevf_write_msg_read_ack(struct rnpgbevf_hw *hw, u32 *msg,
|
|
u16 size)
|
|
{
|
|
u32 retmsg[RNPGBE_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 *rnpgbevf_addr_list_itr(struct rnpgbevf_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;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_update_mc_addr_list_vf(struct rnpgbevf_hw *hw,
|
|
struct net_device *netdev)
|
|
{
|
|
struct netdev_hw_addr *ha;
|
|
u32 msgbuf[RNPGBE_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] = RNPGBE_VF_SET_MULTICAST;
|
|
msgbuf[0] |= cnt << RNPGBE_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] = rnpgbevf_mta_vector(hw,
|
|
rnpgbevf_addr_list_itr(hw, &addr_list));
|
|
}
|
|
|
|
rnpgbevf_write_msg_read_ack(hw, msgbuf, RNPGBE_VFMAILBOX_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_set_vfta_vf(struct rnpgbevf_hw *hw, u32 vlan, u32 vind,
|
|
bool vlan_on)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 msgbuf[2];
|
|
s32 err;
|
|
|
|
msgbuf[0] = RNPGBE_VF_SET_VLAN;
|
|
msgbuf[1] = vlan;
|
|
/* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
|
|
msgbuf[0] |= vlan_on << RNPGBE_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
msgbuf[0] &= ~(0xFF << RNPGBE_VT_MSGINFO_SHIFT);
|
|
|
|
if (msgbuf[0] != (RNPGBE_VF_SET_VLAN | RNPGBE_VT_MSGTYPE_ACK))
|
|
err = RNPGBE_ERR_INVALID_ARGUMENT;
|
|
|
|
mbx_err:
|
|
return err;
|
|
}
|
|
|
|
static s32 rnpgbevf_set_vlan_strip(struct rnpgbevf_hw *hw, bool vlan_on)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
struct rnpgbevf_adapter *adapter = (struct rnpgbevf_adapter *)hw->back;
|
|
u32 msgbuf[4];
|
|
s32 err;
|
|
int i;
|
|
|
|
if (adapter->num_rx_queues > 2) {
|
|
err = -EINVAL;
|
|
goto mbx_err;
|
|
}
|
|
|
|
msgbuf[0] = RNPGBE_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]->rnpgbevf_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] &= ~RNPGBE_VT_MSGTYPE_CTS;
|
|
msgbuf[0] &= ~(0xFF << RNPGBE_VT_MSGINFO_SHIFT);
|
|
|
|
if (msgbuf[0] != (RNPGBE_VF_SET_VLAN_STRIP | RNPGBE_VT_MSGTYPE_ACK))
|
|
err = RNPGBE_ERR_INVALID_ARGUMENT;
|
|
|
|
mbx_err:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_setup_mac_link_vf(struct rnpgbevf_hw *hw,
|
|
rnp_link_speed speed, bool autoneg,
|
|
bool autoneg_wait_to_complete)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_check_mac_link_vf(struct rnpgbevf_hw *hw,
|
|
rnp_link_speed *speed, bool *link_up,
|
|
bool autoneg_wait_to_complete)
|
|
{
|
|
*speed = hw->speed;
|
|
*link_up = hw->link;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_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 rnpgbevf_rlpml_set_vf(struct rnpgbevf_hw *hw, u16 max_size)
|
|
{
|
|
u32 msgbuf[2];
|
|
|
|
msgbuf[0] = RNPGBE_VF_SET_LPE;
|
|
msgbuf[1] = max_size;
|
|
rnpgbevf_write_msg_read_ack(hw, msgbuf, 2);
|
|
}
|
|
|
|
static void rnpgbevf_set_veb_mac_n500(struct rnpgbevf_hw *hw,
|
|
u8 *mac, u32 vf_num,
|
|
u32 ring)
|
|
{
|
|
u32 maclow, machi;
|
|
|
|
maclow = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
|
|
machi = (mac[0] << 8) | mac[1];
|
|
|
|
wr32(hw, RNPGBE_DMA_PORT_VBE_MAC_LO_TBL_N500, maclow);
|
|
wr32(hw, RNPGBE_DMA_PORT_VBE_MAC_HI_TBL_N500, machi);
|
|
wr32(hw, RNPGBE_DMA_PORT_VEB_VF_RING_TBL_N500, ring);
|
|
}
|
|
|
|
static void rnpgbevf_set_vlan_n500(struct rnpgbevf_hw *hw,
|
|
u16 vid, u32 vf_num)
|
|
{
|
|
wr32(hw, RNPGBE_DMA_PORT_VEB_VID_TBL_N500, vid);
|
|
}
|
|
|
|
static const struct rnpgbevf_hw_operations rnpgbevf_hw_ops_n500 = {
|
|
.set_veb_mac = rnpgbevf_set_veb_mac_n500,
|
|
.set_veb_vlan = rnpgbevf_set_vlan_n500,
|
|
};
|
|
|
|
static s32 rnpgbevf_get_invariants_n500(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
|
|
hw->feature_flags |=
|
|
RNPVF_NET_FEATURE_SG | RNPVF_NET_FEATURE_TX_CHECKSUM |
|
|
RNPVF_NET_FEATURE_RX_CHECKSUM | RNPVF_NET_FEATURE_TSO |
|
|
RNPVF_NET_FEATURE_VLAN_OFFLOAD |
|
|
RNPVF_NET_FEATURE_STAG_OFFLOAD | RNPVF_NET_FEATURE_USO |
|
|
RNPVF_NET_FEATURE_RX_HASH;
|
|
|
|
mbx->pf2vf_mbox_vec_base = 0x28800;
|
|
mbx->vf2pf_mbox_vec_base = 0x28900;
|
|
mbx->cpu2vf_mbox_vec_base = 0x28a00;
|
|
mbx->cpu2pf_mbox_vec = 0x28b00;
|
|
mbx->pf_vf_shm_base = 0x29000;
|
|
mbx->cpu_vf_shm_base = 0x2b000;
|
|
mbx->vf2cpu_mbox_ctrl_base = 0x2c000;
|
|
mbx->cpu_vf_mbox_mask_lo_base = 0x2c200;
|
|
mbx->cpu_vf_mbox_mask_hi_base = 0;
|
|
mbx->mbx_mem_size = 64;
|
|
|
|
mbx->vf2pf_mbox_ctrl_base = 0x2a000;
|
|
mbx->pf2vf_mbox_ctrl_base = 0x2a100;
|
|
mbx->pf_vf_mbox_mask_lo = 0x2a200;
|
|
mbx->pf_vf_mbox_mask_hi = 0;
|
|
|
|
mbx->cpu_pf_shm_base = 0x2d040;
|
|
mbx->pf2cpu_mbox_ctrl = 0x2e000;
|
|
mbx->pf2cpu_mbox_mask = 0x2e200;
|
|
|
|
mbx->vf_num_mask = 0x1f;
|
|
|
|
hw->min_length = RNPVF_MIN_MTU;
|
|
hw->max_length = RNPVF_N500_MAX_JUMBO_FRAME_SIZE;
|
|
|
|
memcpy(&hw->ops, &rnpgbevf_hw_ops_n500, sizeof(hw->ops));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 rnpgbevf_get_invariants_n210(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
|
|
hw->feature_flags |=
|
|
RNPVF_NET_FEATURE_SG | RNPVF_NET_FEATURE_TX_CHECKSUM |
|
|
RNPVF_NET_FEATURE_RX_CHECKSUM | RNPVF_NET_FEATURE_TSO |
|
|
RNPVF_NET_FEATURE_VLAN_OFFLOAD |
|
|
RNPVF_NET_FEATURE_STAG_OFFLOAD | RNPVF_NET_FEATURE_USO |
|
|
RNPVF_NET_FEATURE_RX_HASH;
|
|
|
|
mbx->pf2vf_mbox_vec_base = 0x29100;
|
|
mbx->vf2pf_mbox_vec_base = 0x29200;
|
|
mbx->cpu2vf_mbox_vec_base = 0x29300;
|
|
mbx->cpu2pf_mbox_vec = 0x29400;
|
|
mbx->pf_vf_shm_base = 0x29900;
|
|
mbx->cpu_vf_shm_base = 0x2b900;
|
|
mbx->vf2cpu_mbox_ctrl_base = 0x2c900;
|
|
mbx->cpu_vf_mbox_mask_lo_base = 0x2cb00;
|
|
mbx->cpu_vf_mbox_mask_hi_base = 0;
|
|
mbx->mbx_mem_size = 64;
|
|
|
|
mbx->vf2pf_mbox_ctrl_base = 0x2a900;
|
|
mbx->pf2vf_mbox_ctrl_base = 0x2aa00;
|
|
mbx->pf_vf_mbox_mask_lo = 0x2a200;
|
|
mbx->pf_vf_mbox_mask_hi = 0;
|
|
|
|
mbx->cpu_pf_shm_base = 0x2d940;
|
|
mbx->pf2cpu_mbox_ctrl = 0x2e900;
|
|
mbx->pf2cpu_mbox_mask = 0x2eb00;
|
|
|
|
mbx->vf_num_mask = 0x1f;
|
|
|
|
hw->min_length = RNPVF_MIN_MTU;
|
|
hw->max_length = RNPVF_N500_MAX_JUMBO_FRAME_SIZE;
|
|
|
|
memcpy(&hw->ops, &rnpgbevf_hw_ops_n500, sizeof(hw->ops));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct rnp_mac_operations rnpgbevf_mac_ops = {
|
|
.init_hw = rnpgbevf_init_hw_vf,
|
|
.reset_hw = rnpgbevf_reset_hw_vf,
|
|
.start_hw = rnpgbevf_start_hw_vf,
|
|
.get_mac_addr = rnpgbevf_get_mac_addr_vf,
|
|
.get_queues = rnpgbevf_get_queues_vf,
|
|
.stop_adapter = rnpgbevf_stop_hw_vf,
|
|
.setup_link = rnpgbevf_setup_mac_link_vf,
|
|
.check_link = rnpgbevf_check_mac_link_vf,
|
|
.set_rar = rnpgbevf_set_rar_vf,
|
|
.update_mc_addr_list = rnpgbevf_update_mc_addr_list_vf,
|
|
.set_uc_addr = rnpgbevf_set_uc_addr_vf,
|
|
.set_vfta = rnpgbevf_set_vfta_vf,
|
|
.set_vlan_strip = rnpgbevf_set_vlan_strip,
|
|
.read_eth_reg = rnpgbevf_read_eth_reg,
|
|
.get_mtu = rnpgbevf_get_mtu,
|
|
.set_mtu = rnpgbevf_set_mtu,
|
|
.req_reset_pf = rnpgbevf_reset_pf,
|
|
};
|
|
|
|
const struct rnpgbevf_info rnp_n500_vf_info = {
|
|
.mac = rnp_mac_2port_40G,
|
|
.mac_ops = &rnpgbevf_mac_ops,
|
|
.board_type = rnp_board_n500,
|
|
.get_invariants = &rnpgbevf_get_invariants_n500,
|
|
};
|
|
|
|
const struct rnpgbevf_info rnp_n210_vf_info = {
|
|
.mac = rnp_mac_2port_40G,
|
|
.mac_ops = &rnpgbevf_mac_ops,
|
|
.board_type = rnp_board_n210,
|
|
.get_invariants = &rnpgbevf_get_invariants_n210,
|
|
};
|