net: libwx: Add msg task func
Implement wx_msg_task which is used to process mailbox messages sent by vf. Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com> Link: https://patch.msgid.link/8257B39B95CDB469+20250408091556.9640-5-mengyuanlou@net-swift.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
c52d4b8989
commit
359e41f631
@@ -1011,7 +1011,7 @@ void wx_flush_sw_mac_table(struct wx *wx)
|
||||
}
|
||||
EXPORT_SYMBOL(wx_flush_sw_mac_table);
|
||||
|
||||
static int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool)
|
||||
int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
@@ -1042,7 +1042,7 @@ static int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool)
|
||||
int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
@@ -1469,7 +1469,7 @@ static void wx_set_ethertype_anti_spoofing(struct wx *wx, bool enable, int vf)
|
||||
wr32(wx, WX_TDM_ETYPE_AS(reg_offset), pfvfspoof);
|
||||
}
|
||||
|
||||
static int wx_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting)
|
||||
int wx_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting)
|
||||
{
|
||||
u32 index = WX_VF_REG_OFFSET(vf), vf_bit = WX_VF_IND_SHIFT(vf);
|
||||
struct wx *wx = netdev_priv(netdev);
|
||||
@@ -2530,7 +2530,7 @@ static int wx_set_vlvf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
|
||||
*
|
||||
* Turn on/off specified VLAN in the VLAN filter table.
|
||||
**/
|
||||
static int wx_set_vfta(struct wx *wx, u32 vlan, u32 vind, bool vlan_on)
|
||||
int wx_set_vfta(struct wx *wx, u32 vlan, u32 vind, bool vlan_on)
|
||||
{
|
||||
u32 bitindex, vfta, targetbit;
|
||||
bool vfta_changed = false;
|
||||
|
||||
@@ -26,9 +26,12 @@ void wx_init_eeprom_params(struct wx *wx);
|
||||
void wx_get_mac_addr(struct wx *wx, u8 *mac_addr);
|
||||
void wx_init_rx_addrs(struct wx *wx);
|
||||
void wx_mac_set_default_filter(struct wx *wx, u8 *addr);
|
||||
int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool);
|
||||
int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool);
|
||||
void wx_flush_sw_mac_table(struct wx *wx);
|
||||
int wx_set_mac(struct net_device *netdev, void *p);
|
||||
void wx_disable_rx(struct wx *wx);
|
||||
int wx_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
|
||||
int wx_disable_sec_rx_path(struct wx *wx);
|
||||
void wx_enable_sec_rx_path(struct wx *wx);
|
||||
void wx_set_rx_mode(struct net_device *netdev);
|
||||
@@ -42,6 +45,7 @@ int wx_stop_adapter(struct wx *wx);
|
||||
void wx_reset_misc(struct wx *wx);
|
||||
int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count);
|
||||
int wx_sw_init(struct wx *wx);
|
||||
int wx_set_vfta(struct wx *wx, u32 vlan, u32 vind, bool vlan_on);
|
||||
int wx_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
|
||||
int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
|
||||
int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause);
|
||||
|
||||
@@ -21,10 +21,51 @@
|
||||
#define WX_MBVFICR_VFREQ_MASK GENMASK(15, 0)
|
||||
#define WX_MBVFICR_VFACK_MASK GENMASK(31, 16)
|
||||
|
||||
#define WX_VT_MSGTYPE_ACK BIT(31)
|
||||
#define WX_VT_MSGTYPE_NACK BIT(30)
|
||||
#define WX_VT_MSGTYPE_CTS BIT(29)
|
||||
#define WX_VT_MSGINFO_SHIFT 16
|
||||
#define WX_VT_MSGINFO_MASK GENMASK(23, 16)
|
||||
|
||||
enum wx_pfvf_api_rev {
|
||||
wx_mbox_api_null,
|
||||
wx_mbox_api_13 = 4, /* API version 1.3 */
|
||||
wx_mbox_api_unknown, /* indicates that API version is not known */
|
||||
};
|
||||
|
||||
/* mailbox API */
|
||||
#define WX_VF_RESET 0x01 /* VF requests reset */
|
||||
#define WX_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */
|
||||
#define WX_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
|
||||
#define WX_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
|
||||
#define WX_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
|
||||
#define WX_VF_SET_MACVLAN 0x06 /* VF requests PF unicast filter */
|
||||
#define WX_VF_API_NEGOTIATE 0x08 /* negotiate API version */
|
||||
#define WX_VF_GET_QUEUES 0x09 /* get queue configuration */
|
||||
#define WX_VF_GET_RETA 0x0a /* VF request for RETA */
|
||||
#define WX_VF_GET_RSS_KEY 0x0b /* get RSS key */
|
||||
#define WX_VF_UPDATE_XCAST_MODE 0x0c
|
||||
#define WX_VF_GET_LINK_STATE 0x10 /* get vf link state */
|
||||
#define WX_VF_GET_FW_VERSION 0x11 /* get fw version */
|
||||
|
||||
#define WX_VF_BACKUP 0x8001 /* VF requests backup */
|
||||
|
||||
#define WX_PF_CONTROL_MSG BIT(8) /* PF control message */
|
||||
#define WX_PF_NOFITY_VF_LINK_STATUS 0x1
|
||||
#define WX_PF_NOFITY_VF_NET_NOT_RUNNING BIT(31)
|
||||
|
||||
#define WX_VF_TX_QUEUES 1 /* number of Tx queues supported */
|
||||
#define WX_VF_RX_QUEUES 2 /* number of Rx queues supported */
|
||||
#define WX_VF_TRANS_VLAN 3 /* Indication of port vlan */
|
||||
#define WX_VF_DEF_QUEUE 4 /* Default queue offset */
|
||||
|
||||
#define WX_VF_PERMADDR_MSG_LEN 4
|
||||
|
||||
enum wxvf_xcast_modes {
|
||||
WXVF_XCAST_MODE_NONE = 0,
|
||||
WXVF_XCAST_MODE_MULTI,
|
||||
WXVF_XCAST_MODE_ALLMULTI,
|
||||
WXVF_XCAST_MODE_PROMISC,
|
||||
};
|
||||
|
||||
int wx_write_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "wx_type.h"
|
||||
#include "wx_hw.h"
|
||||
#include "wx_mbx.h"
|
||||
#include "wx_sriov.h"
|
||||
|
||||
@@ -198,3 +199,638 @@ int wx_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
||||
return num_vfs;
|
||||
}
|
||||
EXPORT_SYMBOL(wx_pci_sriov_configure);
|
||||
|
||||
static int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr)
|
||||
{
|
||||
u8 hw_addr[ETH_ALEN];
|
||||
int ret = 0;
|
||||
|
||||
ether_addr_copy(hw_addr, mac_addr);
|
||||
wx_del_mac_filter(wx, wx->vfinfo[vf].vf_mac_addr, vf);
|
||||
ret = wx_add_mac_filter(wx, hw_addr, vf);
|
||||
if (ret >= 0)
|
||||
ether_addr_copy(wx->vfinfo[vf].vf_mac_addr, mac_addr);
|
||||
else
|
||||
eth_zero_addr(wx->vfinfo[vf].vf_mac_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wx_set_vmolr(struct wx *wx, u16 vf, bool aupe)
|
||||
{
|
||||
u32 vmolr = rd32(wx, WX_PSR_VM_L2CTL(vf));
|
||||
|
||||
vmolr |= WX_PSR_VM_L2CTL_BAM;
|
||||
if (aupe)
|
||||
vmolr |= WX_PSR_VM_L2CTL_AUPE;
|
||||
else
|
||||
vmolr &= ~WX_PSR_VM_L2CTL_AUPE;
|
||||
wr32(wx, WX_PSR_VM_L2CTL(vf), vmolr);
|
||||
}
|
||||
|
||||
static void wx_set_vmvir(struct wx *wx, u16 vid, u16 qos, u16 vf)
|
||||
{
|
||||
u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) |
|
||||
WX_TDM_VLAN_INS_VLANA_DEFAULT;
|
||||
|
||||
wr32(wx, WX_TDM_VLAN_INS(vf), vmvir);
|
||||
}
|
||||
|
||||
static int wx_set_vf_vlan(struct wx *wx, int add, int vid, u16 vf)
|
||||
{
|
||||
if (!vid && !add)
|
||||
return 0;
|
||||
|
||||
return wx_set_vfta(wx, vid, vf, (bool)add);
|
||||
}
|
||||
|
||||
static void wx_set_vlan_anti_spoofing(struct wx *wx, bool enable, int vf)
|
||||
{
|
||||
u32 index = WX_VF_REG_OFFSET(vf), vf_bit = WX_VF_IND_SHIFT(vf);
|
||||
u32 pfvfspoof;
|
||||
|
||||
pfvfspoof = rd32(wx, WX_TDM_VLAN_AS(index));
|
||||
if (enable)
|
||||
pfvfspoof |= BIT(vf_bit);
|
||||
else
|
||||
pfvfspoof &= ~BIT(vf_bit);
|
||||
wr32(wx, WX_TDM_VLAN_AS(index), pfvfspoof);
|
||||
}
|
||||
|
||||
static void wx_write_qde(struct wx *wx, u32 vf, u32 qde)
|
||||
{
|
||||
struct wx_ring_feature *vmdq = &wx->ring_feature[RING_F_VMDQ];
|
||||
u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
|
||||
u32 reg = 0, n = vf * q_per_pool / 32;
|
||||
u32 i = vf * q_per_pool;
|
||||
|
||||
reg = rd32(wx, WX_RDM_PF_QDE(n));
|
||||
for (i = (vf * q_per_pool - n * 32);
|
||||
i < ((vf + 1) * q_per_pool - n * 32);
|
||||
i++) {
|
||||
if (qde == 1)
|
||||
reg |= qde << i;
|
||||
else
|
||||
reg &= qde << i;
|
||||
}
|
||||
|
||||
wr32(wx, WX_RDM_PF_QDE(n), reg);
|
||||
}
|
||||
|
||||
static void wx_clear_vmvir(struct wx *wx, u32 vf)
|
||||
{
|
||||
wr32(wx, WX_TDM_VLAN_INS(vf), 0);
|
||||
}
|
||||
|
||||
static void wx_set_vf_rx_tx(struct wx *wx, int vf)
|
||||
{
|
||||
u32 index = WX_VF_REG_OFFSET(vf), vf_bit = WX_VF_IND_SHIFT(vf);
|
||||
u32 reg_cur_tx, reg_cur_rx, reg_req_tx, reg_req_rx;
|
||||
|
||||
reg_cur_tx = rd32(wx, WX_TDM_VF_TE(index));
|
||||
reg_cur_rx = rd32(wx, WX_RDM_VF_RE(index));
|
||||
|
||||
if (wx->vfinfo[vf].link_enable) {
|
||||
reg_req_tx = reg_cur_tx | BIT(vf_bit);
|
||||
reg_req_rx = reg_cur_rx | BIT(vf_bit);
|
||||
/* Enable particular VF */
|
||||
if (reg_cur_tx != reg_req_tx)
|
||||
wr32(wx, WX_TDM_VF_TE(index), reg_req_tx);
|
||||
if (reg_cur_rx != reg_req_rx)
|
||||
wr32(wx, WX_RDM_VF_RE(index), reg_req_rx);
|
||||
} else {
|
||||
reg_req_tx = BIT(vf_bit);
|
||||
reg_req_rx = BIT(vf_bit);
|
||||
/* Disable particular VF */
|
||||
if (reg_cur_tx & reg_req_tx)
|
||||
wr32(wx, WX_TDM_VFTE_CLR(index), reg_req_tx);
|
||||
if (reg_cur_rx & reg_req_rx)
|
||||
wr32(wx, WX_RDM_VFRE_CLR(index), reg_req_rx);
|
||||
}
|
||||
}
|
||||
|
||||
static int wx_get_vf_queues(struct wx *wx, u32 *msgbuf, u32 vf)
|
||||
{
|
||||
struct wx_ring_feature *vmdq = &wx->ring_feature[RING_F_VMDQ];
|
||||
unsigned int default_tc = 0;
|
||||
|
||||
msgbuf[WX_VF_TX_QUEUES] = __ALIGN_MASK(1, ~vmdq->mask);
|
||||
msgbuf[WX_VF_RX_QUEUES] = __ALIGN_MASK(1, ~vmdq->mask);
|
||||
|
||||
if (wx->vfinfo[vf].pf_vlan || wx->vfinfo[vf].pf_qos)
|
||||
msgbuf[WX_VF_TRANS_VLAN] = 1;
|
||||
else
|
||||
msgbuf[WX_VF_TRANS_VLAN] = 0;
|
||||
|
||||
/* notify VF of default queue */
|
||||
msgbuf[WX_VF_DEF_QUEUE] = default_tc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wx_vf_reset_event(struct wx *wx, u16 vf)
|
||||
{
|
||||
struct vf_data_storage *vfinfo = &wx->vfinfo[vf];
|
||||
u8 num_tcs = netdev_get_num_tc(wx->netdev);
|
||||
|
||||
/* add PF assigned VLAN */
|
||||
wx_set_vf_vlan(wx, true, vfinfo->pf_vlan, vf);
|
||||
|
||||
/* reset offloads to defaults */
|
||||
wx_set_vmolr(wx, vf, !vfinfo->pf_vlan);
|
||||
|
||||
/* set outgoing tags for VFs */
|
||||
if (!vfinfo->pf_vlan && !vfinfo->pf_qos && !num_tcs) {
|
||||
wx_clear_vmvir(wx, vf);
|
||||
} else {
|
||||
if (vfinfo->pf_qos || !num_tcs)
|
||||
wx_set_vmvir(wx, vfinfo->pf_vlan,
|
||||
vfinfo->pf_qos, vf);
|
||||
else
|
||||
wx_set_vmvir(wx, vfinfo->pf_vlan,
|
||||
wx->default_up, vf);
|
||||
}
|
||||
|
||||
/* reset multicast table array for vf */
|
||||
wx->vfinfo[vf].num_vf_mc_hashes = 0;
|
||||
|
||||
/* Flush and reset the mta with the new values */
|
||||
wx_set_rx_mode(wx->netdev);
|
||||
|
||||
wx_del_mac_filter(wx, wx->vfinfo[vf].vf_mac_addr, vf);
|
||||
/* reset VF api back to unknown */
|
||||
wx->vfinfo[vf].vf_api = wx_mbox_api_null;
|
||||
}
|
||||
|
||||
static void wx_vf_reset_msg(struct wx *wx, u16 vf)
|
||||
{
|
||||
const u8 *vf_mac = wx->vfinfo[vf].vf_mac_addr;
|
||||
struct net_device *dev = wx->netdev;
|
||||
u32 msgbuf[5] = {0, 0, 0, 0, 0};
|
||||
u8 *addr = (u8 *)(&msgbuf[1]);
|
||||
u32 reg = 0, index, vf_bit;
|
||||
int pf_max_frame;
|
||||
|
||||
/* reset the filters for the device */
|
||||
wx_vf_reset_event(wx, vf);
|
||||
|
||||
/* set vf mac address */
|
||||
if (!is_zero_ether_addr(vf_mac))
|
||||
wx_set_vf_mac(wx, vf, vf_mac);
|
||||
|
||||
index = WX_VF_REG_OFFSET(vf);
|
||||
vf_bit = WX_VF_IND_SHIFT(vf);
|
||||
|
||||
/* force drop enable for all VF Rx queues */
|
||||
wx_write_qde(wx, vf, 1);
|
||||
|
||||
/* set transmit and receive for vf */
|
||||
wx_set_vf_rx_tx(wx, vf);
|
||||
|
||||
pf_max_frame = dev->mtu + ETH_HLEN;
|
||||
|
||||
if (pf_max_frame > ETH_FRAME_LEN)
|
||||
reg = BIT(vf_bit);
|
||||
wr32(wx, WX_RDM_VFRE_CLR(index), reg);
|
||||
|
||||
/* enable VF mailbox for further messages */
|
||||
wx->vfinfo[vf].clear_to_send = true;
|
||||
|
||||
/* reply to reset with ack and vf mac address */
|
||||
msgbuf[0] = WX_VF_RESET;
|
||||
if (!is_zero_ether_addr(vf_mac)) {
|
||||
msgbuf[0] |= WX_VT_MSGTYPE_ACK;
|
||||
memcpy(addr, vf_mac, ETH_ALEN);
|
||||
} else {
|
||||
msgbuf[0] |= WX_VT_MSGTYPE_NACK;
|
||||
wx_err(wx, "VF %d has no MAC address assigned", vf);
|
||||
}
|
||||
|
||||
msgbuf[3] = wx->mac.mc_filter_type;
|
||||
wx_write_mbx_pf(wx, msgbuf, WX_VF_PERMADDR_MSG_LEN, vf);
|
||||
}
|
||||
|
||||
static int wx_set_vf_mac_addr(struct wx *wx, u32 *msgbuf, u16 vf)
|
||||
{
|
||||
const u8 *new_mac = ((u8 *)(&msgbuf[1]));
|
||||
int ret;
|
||||
|
||||
if (!is_valid_ether_addr(new_mac)) {
|
||||
wx_err(wx, "VF %d attempted to set invalid mac\n", vf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wx->vfinfo[vf].pf_set_mac &&
|
||||
memcmp(wx->vfinfo[vf].vf_mac_addr, new_mac, ETH_ALEN)) {
|
||||
wx_err(wx,
|
||||
"VF %d attempt to set a MAC but it already had a MAC.",
|
||||
vf);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = wx_set_vf_mac(wx, vf, new_mac);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wx_set_vf_multicasts(struct wx *wx, u32 *msgbuf, u32 vf)
|
||||
{
|
||||
struct vf_data_storage *vfinfo = &wx->vfinfo[vf];
|
||||
u16 entries = (msgbuf[0] & WX_VT_MSGINFO_MASK)
|
||||
>> WX_VT_MSGINFO_SHIFT;
|
||||
u32 vmolr = rd32(wx, WX_PSR_VM_L2CTL(vf));
|
||||
u32 vector_bit, vector_reg, mta_reg, i;
|
||||
u16 *hash_list = (u16 *)&msgbuf[1];
|
||||
|
||||
/* only so many hash values supported */
|
||||
entries = min_t(u16, entries, WX_MAX_VF_MC_ENTRIES);
|
||||
vfinfo->num_vf_mc_hashes = entries;
|
||||
|
||||
for (i = 0; i < entries; i++)
|
||||
vfinfo->vf_mc_hashes[i] = hash_list[i];
|
||||
|
||||
for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) {
|
||||
vector_reg = WX_PSR_MC_TBL_REG(vfinfo->vf_mc_hashes[i]);
|
||||
vector_bit = WX_PSR_MC_TBL_BIT(vfinfo->vf_mc_hashes[i]);
|
||||
mta_reg = wx->mac.mta_shadow[vector_reg];
|
||||
mta_reg |= BIT(vector_bit);
|
||||
wx->mac.mta_shadow[vector_reg] = mta_reg;
|
||||
wr32(wx, WX_PSR_MC_TBL(vector_reg), mta_reg);
|
||||
}
|
||||
vmolr |= WX_PSR_VM_L2CTL_ROMPE;
|
||||
wr32(wx, WX_PSR_VM_L2CTL(vf), vmolr);
|
||||
}
|
||||
|
||||
static void wx_set_vf_lpe(struct wx *wx, u32 max_frame, u32 vf)
|
||||
{
|
||||
u32 index, vf_bit, vfre;
|
||||
u32 max_frs, reg_val;
|
||||
|
||||
/* determine VF receive enable location */
|
||||
index = WX_VF_REG_OFFSET(vf);
|
||||
vf_bit = WX_VF_IND_SHIFT(vf);
|
||||
|
||||
vfre = rd32(wx, WX_RDM_VF_RE(index));
|
||||
vfre |= BIT(vf_bit);
|
||||
wr32(wx, WX_RDM_VF_RE(index), vfre);
|
||||
|
||||
/* pull current max frame size from hardware */
|
||||
max_frs = DIV_ROUND_UP(max_frame, 1024);
|
||||
reg_val = rd32(wx, WX_MAC_WDG_TIMEOUT) & WX_MAC_WDG_TIMEOUT_WTO_MASK;
|
||||
if (max_frs > (reg_val + WX_MAC_WDG_TIMEOUT_WTO_DELTA))
|
||||
wr32(wx, WX_MAC_WDG_TIMEOUT,
|
||||
max_frs - WX_MAC_WDG_TIMEOUT_WTO_DELTA);
|
||||
}
|
||||
|
||||
static int wx_find_vlvf_entry(struct wx *wx, u32 vlan)
|
||||
{
|
||||
int regindex;
|
||||
u32 vlvf;
|
||||
|
||||
/* short cut the special case */
|
||||
if (vlan == 0)
|
||||
return 0;
|
||||
|
||||
/* Search for the vlan id in the VLVF entries */
|
||||
for (regindex = 1; regindex < WX_PSR_VLAN_SWC_ENTRIES; regindex++) {
|
||||
wr32(wx, WX_PSR_VLAN_SWC_IDX, regindex);
|
||||
vlvf = rd32(wx, WX_PSR_VLAN_SWC);
|
||||
if ((vlvf & VLAN_VID_MASK) == vlan)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return a negative value if not found */
|
||||
if (regindex >= WX_PSR_VLAN_SWC_ENTRIES)
|
||||
regindex = -EINVAL;
|
||||
|
||||
return regindex;
|
||||
}
|
||||
|
||||
static int wx_set_vf_macvlan(struct wx *wx,
|
||||
u16 vf, int index, unsigned char *mac_addr)
|
||||
{
|
||||
struct vf_macvlans *entry;
|
||||
struct list_head *pos;
|
||||
int retval = 0;
|
||||
|
||||
if (index <= 1) {
|
||||
list_for_each(pos, &wx->vf_mvs.mvlist) {
|
||||
entry = list_entry(pos, struct vf_macvlans, mvlist);
|
||||
if (entry->vf == vf) {
|
||||
entry->vf = -1;
|
||||
entry->free = true;
|
||||
entry->is_macvlan = false;
|
||||
wx_del_mac_filter(wx, entry->vf_macvlan, vf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!index)
|
||||
return 0;
|
||||
|
||||
entry = NULL;
|
||||
list_for_each(pos, &wx->vf_mvs.mvlist) {
|
||||
entry = list_entry(pos, struct vf_macvlans, mvlist);
|
||||
if (entry->free)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!entry || !entry->free)
|
||||
return -ENOSPC;
|
||||
|
||||
retval = wx_add_mac_filter(wx, mac_addr, vf);
|
||||
if (retval >= 0) {
|
||||
entry->free = false;
|
||||
entry->is_macvlan = true;
|
||||
entry->vf = vf;
|
||||
memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int wx_set_vf_vlan_msg(struct wx *wx, u32 *msgbuf, u16 vf)
|
||||
{
|
||||
int add = (msgbuf[0] & WX_VT_MSGINFO_MASK) >> WX_VT_MSGINFO_SHIFT;
|
||||
int vid = (msgbuf[1] & WX_PSR_VLAN_SWC_VLANID_MASK);
|
||||
int ret;
|
||||
|
||||
if (add)
|
||||
wx->vfinfo[vf].vlan_count++;
|
||||
else if (wx->vfinfo[vf].vlan_count)
|
||||
wx->vfinfo[vf].vlan_count--;
|
||||
|
||||
/* in case of promiscuous mode any VLAN filter set for a VF must
|
||||
* also have the PF pool added to it.
|
||||
*/
|
||||
if (add && wx->netdev->flags & IFF_PROMISC)
|
||||
wx_set_vf_vlan(wx, add, vid, VMDQ_P(0));
|
||||
|
||||
ret = wx_set_vf_vlan(wx, add, vid, vf);
|
||||
if (!ret && wx->vfinfo[vf].spoofchk_enabled)
|
||||
wx_set_vlan_anti_spoofing(wx, true, vf);
|
||||
|
||||
/* Go through all the checks to see if the VLAN filter should
|
||||
* be wiped completely.
|
||||
*/
|
||||
if (!add && wx->netdev->flags & IFF_PROMISC) {
|
||||
u32 bits = 0, vlvf;
|
||||
int reg_ndx;
|
||||
|
||||
reg_ndx = wx_find_vlvf_entry(wx, vid);
|
||||
if (reg_ndx < 0)
|
||||
return -ENOSPC;
|
||||
wr32(wx, WX_PSR_VLAN_SWC_IDX, reg_ndx);
|
||||
vlvf = rd32(wx, WX_PSR_VLAN_SWC);
|
||||
/* See if any other pools are set for this VLAN filter
|
||||
* entry other than the PF.
|
||||
*/
|
||||
if (VMDQ_P(0) < 32) {
|
||||
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
|
||||
bits &= ~BIT(VMDQ_P(0));
|
||||
if (wx->mac.type != wx_mac_em)
|
||||
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_H);
|
||||
} else {
|
||||
if (wx->mac.type != wx_mac_em)
|
||||
bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
|
||||
bits &= ~BIT(VMDQ_P(0) % 32);
|
||||
bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_L);
|
||||
}
|
||||
/* If the filter was removed then ensure PF pool bit
|
||||
* is cleared if the PF only added itself to the pool
|
||||
* because the PF is in promiscuous mode.
|
||||
*/
|
||||
if ((vlvf & VLAN_VID_MASK) == vid && !bits)
|
||||
wx_set_vf_vlan(wx, add, vid, VMDQ_P(0));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wx_set_vf_macvlan_msg(struct wx *wx, u32 *msgbuf, u16 vf)
|
||||
{
|
||||
int index = (msgbuf[0] & WX_VT_MSGINFO_MASK) >>
|
||||
WX_VT_MSGINFO_SHIFT;
|
||||
u8 *new_mac = ((u8 *)(&msgbuf[1]));
|
||||
int err;
|
||||
|
||||
if (wx->vfinfo[vf].pf_set_mac && index > 0) {
|
||||
wx_err(wx, "VF %d request MACVLAN filter but is denied\n", vf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* An non-zero index indicates the VF is setting a filter */
|
||||
if (index) {
|
||||
if (!is_valid_ether_addr(new_mac)) {
|
||||
wx_err(wx, "VF %d attempted to set invalid mac\n", vf);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* If the VF is allowed to set MAC filters then turn off
|
||||
* anti-spoofing to avoid false positives.
|
||||
*/
|
||||
if (wx->vfinfo[vf].spoofchk_enabled)
|
||||
wx_set_vf_spoofchk(wx->netdev, vf, false);
|
||||
}
|
||||
|
||||
err = wx_set_vf_macvlan(wx, vf, index, new_mac);
|
||||
if (err == -ENOSPC)
|
||||
wx_err(wx,
|
||||
"VF %d request MACVLAN filter but there is no space\n",
|
||||
vf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wx_negotiate_vf_api(struct wx *wx, u32 *msgbuf, u32 vf)
|
||||
{
|
||||
int api = msgbuf[1];
|
||||
|
||||
switch (api) {
|
||||
case wx_mbox_api_13:
|
||||
wx->vfinfo[vf].vf_api = api;
|
||||
return 0;
|
||||
default:
|
||||
wx_err(wx, "VF %d requested invalid api version %u\n", vf, api);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int wx_get_vf_link_state(struct wx *wx, u32 *msgbuf, u32 vf)
|
||||
{
|
||||
msgbuf[1] = wx->vfinfo[vf].link_enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wx_get_fw_version(struct wx *wx, u32 *msgbuf, u32 vf)
|
||||
{
|
||||
unsigned long fw_version = 0ULL;
|
||||
int ret = 0;
|
||||
|
||||
ret = kstrtoul(wx->eeprom_id, 16, &fw_version);
|
||||
if (ret)
|
||||
return -EOPNOTSUPP;
|
||||
msgbuf[1] = fw_version;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wx_update_vf_xcast_mode(struct wx *wx, u32 *msgbuf, u32 vf)
|
||||
{
|
||||
int xcast_mode = msgbuf[1];
|
||||
u32 vmolr, disable, enable;
|
||||
|
||||
if (wx->vfinfo[vf].xcast_mode == xcast_mode)
|
||||
return 0;
|
||||
|
||||
switch (xcast_mode) {
|
||||
case WXVF_XCAST_MODE_NONE:
|
||||
disable = WX_PSR_VM_L2CTL_BAM | WX_PSR_VM_L2CTL_ROMPE |
|
||||
WX_PSR_VM_L2CTL_MPE | WX_PSR_VM_L2CTL_UPE |
|
||||
WX_PSR_VM_L2CTL_VPE;
|
||||
enable = 0;
|
||||
break;
|
||||
case WXVF_XCAST_MODE_MULTI:
|
||||
disable = WX_PSR_VM_L2CTL_MPE | WX_PSR_VM_L2CTL_UPE |
|
||||
WX_PSR_VM_L2CTL_VPE;
|
||||
enable = WX_PSR_VM_L2CTL_BAM | WX_PSR_VM_L2CTL_ROMPE;
|
||||
break;
|
||||
case WXVF_XCAST_MODE_ALLMULTI:
|
||||
disable = WX_PSR_VM_L2CTL_UPE | WX_PSR_VM_L2CTL_VPE;
|
||||
enable = WX_PSR_VM_L2CTL_BAM | WX_PSR_VM_L2CTL_ROMPE |
|
||||
WX_PSR_VM_L2CTL_MPE;
|
||||
break;
|
||||
case WXVF_XCAST_MODE_PROMISC:
|
||||
disable = 0;
|
||||
enable = WX_PSR_VM_L2CTL_BAM | WX_PSR_VM_L2CTL_ROMPE |
|
||||
WX_PSR_VM_L2CTL_MPE | WX_PSR_VM_L2CTL_UPE |
|
||||
WX_PSR_VM_L2CTL_VPE;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
vmolr = rd32(wx, WX_PSR_VM_L2CTL(vf));
|
||||
vmolr &= ~disable;
|
||||
vmolr |= enable;
|
||||
wr32(wx, WX_PSR_VM_L2CTL(vf), vmolr);
|
||||
|
||||
wx->vfinfo[vf].xcast_mode = xcast_mode;
|
||||
msgbuf[1] = xcast_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wx_rcv_msg_from_vf(struct wx *wx, u16 vf)
|
||||
{
|
||||
u16 mbx_size = WX_VXMAILBOX_SIZE;
|
||||
u32 msgbuf[WX_VXMAILBOX_SIZE];
|
||||
int retval;
|
||||
|
||||
retval = wx_read_mbx_pf(wx, msgbuf, mbx_size, vf);
|
||||
if (retval) {
|
||||
wx_err(wx, "Error receiving message from VF\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* this is a message we already processed, do nothing */
|
||||
if (msgbuf[0] & (WX_VT_MSGTYPE_ACK | WX_VT_MSGTYPE_NACK))
|
||||
return;
|
||||
|
||||
if (msgbuf[0] == WX_VF_RESET) {
|
||||
wx_vf_reset_msg(wx, vf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* until the vf completes a virtual function reset it should not be
|
||||
* allowed to start any configuration.
|
||||
*/
|
||||
if (!wx->vfinfo[vf].clear_to_send) {
|
||||
msgbuf[0] |= WX_VT_MSGTYPE_NACK;
|
||||
wx_write_mbx_pf(wx, msgbuf, 1, vf);
|
||||
return;
|
||||
}
|
||||
|
||||
switch ((msgbuf[0] & U16_MAX)) {
|
||||
case WX_VF_SET_MAC_ADDR:
|
||||
retval = wx_set_vf_mac_addr(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_SET_MULTICAST:
|
||||
wx_set_vf_multicasts(wx, msgbuf, vf);
|
||||
retval = 0;
|
||||
break;
|
||||
case WX_VF_SET_VLAN:
|
||||
retval = wx_set_vf_vlan_msg(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_SET_LPE:
|
||||
wx_set_vf_lpe(wx, msgbuf[1], vf);
|
||||
retval = 0;
|
||||
break;
|
||||
case WX_VF_SET_MACVLAN:
|
||||
retval = wx_set_vf_macvlan_msg(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_API_NEGOTIATE:
|
||||
retval = wx_negotiate_vf_api(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_GET_QUEUES:
|
||||
retval = wx_get_vf_queues(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_GET_LINK_STATE:
|
||||
retval = wx_get_vf_link_state(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_GET_FW_VERSION:
|
||||
retval = wx_get_fw_version(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_UPDATE_XCAST_MODE:
|
||||
retval = wx_update_vf_xcast_mode(wx, msgbuf, vf);
|
||||
break;
|
||||
case WX_VF_BACKUP:
|
||||
break;
|
||||
default:
|
||||
wx_err(wx, "Unhandled Msg %8.8x\n", msgbuf[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
/* notify the VF of the results of what it sent us */
|
||||
if (retval)
|
||||
msgbuf[0] |= WX_VT_MSGTYPE_NACK;
|
||||
else
|
||||
msgbuf[0] |= WX_VT_MSGTYPE_ACK;
|
||||
|
||||
msgbuf[0] |= WX_VT_MSGTYPE_CTS;
|
||||
|
||||
wx_write_mbx_pf(wx, msgbuf, mbx_size, vf);
|
||||
}
|
||||
|
||||
static void wx_rcv_ack_from_vf(struct wx *wx, u16 vf)
|
||||
{
|
||||
u32 msg = WX_VT_MSGTYPE_NACK;
|
||||
|
||||
/* if device isn't clear to send it shouldn't be reading either */
|
||||
if (!wx->vfinfo[vf].clear_to_send)
|
||||
wx_write_mbx_pf(wx, &msg, 1, vf);
|
||||
}
|
||||
|
||||
void wx_msg_task(struct wx *wx)
|
||||
{
|
||||
u16 vf;
|
||||
|
||||
for (vf = 0; vf < wx->num_vfs; vf++) {
|
||||
/* process any reset requests */
|
||||
if (!wx_check_for_rst_pf(wx, vf))
|
||||
wx_vf_reset_event(wx, vf);
|
||||
|
||||
/* process any messages pending */
|
||||
if (!wx_check_for_msg_pf(wx, vf))
|
||||
wx_rcv_msg_from_vf(wx, vf);
|
||||
|
||||
/* process any acks */
|
||||
if (!wx_check_for_ack_pf(wx, vf))
|
||||
wx_rcv_ack_from_vf(wx, vf);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(wx_msg_task);
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
|
||||
void wx_disable_sriov(struct wx *wx);
|
||||
int wx_pci_sriov_configure(struct pci_dev *pdev, int num_vfs);
|
||||
void wx_msg_task(struct wx *wx);
|
||||
|
||||
#endif /* _WX_SRIOV_H_ */
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
|
||||
/*********************** Receive DMA registers **************************/
|
||||
#define WX_RDM_VF_RE(_i) (0x12004 + ((_i) * 4))
|
||||
#define WX_RDM_PF_QDE(_i) (0x12080 + ((_i) * 4))
|
||||
#define WX_RDM_VFRE_CLR(_i) (0x120A0 + ((_i) * 4))
|
||||
#define WX_RDM_DRP_PKT 0x12500
|
||||
#define WX_RDM_PKT_CNT 0x12504
|
||||
#define WX_RDM_BYTE_CNT_LSB 0x12508
|
||||
@@ -125,6 +127,7 @@
|
||||
#define WX_TDM_VF_TE(_i) (0x18004 + ((_i) * 4))
|
||||
#define WX_TDM_MAC_AS(_i) (0x18060 + ((_i) * 4))
|
||||
#define WX_TDM_VLAN_AS(_i) (0x18070 + ((_i) * 4))
|
||||
#define WX_TDM_VFTE_CLR(_i) (0x180A0 + ((_i) * 4))
|
||||
|
||||
/* TDM CTL BIT */
|
||||
#define WX_TDM_CTL_TE BIT(0) /* Transmit Enable */
|
||||
@@ -226,6 +229,7 @@
|
||||
#define WX_PSR_VM_L2CTL(_i) (0x15600 + ((_i) * 4))
|
||||
#define WX_PSR_VM_L2CTL_UPE BIT(4) /* unicast promiscuous */
|
||||
#define WX_PSR_VM_L2CTL_VACC BIT(6) /* accept nomatched vlan */
|
||||
#define WX_PSR_VM_L2CTL_VPE BIT(7) /* vlan promiscuous mode */
|
||||
#define WX_PSR_VM_L2CTL_AUPE BIT(8) /* accept untagged packets */
|
||||
#define WX_PSR_VM_L2CTL_ROMPE BIT(9) /* accept packets in MTA tbl */
|
||||
#define WX_PSR_VM_L2CTL_ROPE BIT(10) /* accept packets in UC tbl */
|
||||
@@ -269,6 +273,7 @@
|
||||
/* VLAN pool filtering masks */
|
||||
#define WX_PSR_VLAN_SWC_VIEN BIT(31) /* filter is valid */
|
||||
#define WX_PSR_VLAN_SWC_ENTRIES 64
|
||||
#define WX_PSR_VLAN_SWC_VLANID_MASK GENMASK(11, 0)
|
||||
|
||||
/********************************* RSEC **************************************/
|
||||
/* general rsec */
|
||||
@@ -282,6 +287,9 @@
|
||||
/*********************** Transmit DMA registers **************************/
|
||||
/* transmit global control */
|
||||
#define WX_TDM_ETYPE_AS(_i) (0x18058 + ((_i) * 4))
|
||||
#define WX_TDM_VLAN_INS(_i) (0x18100 + ((_i) * 4))
|
||||
/* Per VF Port VLAN insertion rules */
|
||||
#define WX_TDM_VLAN_INS_VLANA_DEFAULT BIT(30) /* Always use default VLAN*/
|
||||
|
||||
/****************************** TDB ******************************************/
|
||||
#define WX_TDB_PB_SZ(_i) (0x1CC00 + ((_i) * 4))
|
||||
@@ -352,6 +360,9 @@
|
||||
#define WX_MAC_WDG_TIMEOUT 0x1100C
|
||||
#define WX_MAC_RX_FLOW_CTRL 0x11090
|
||||
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
|
||||
|
||||
#define WX_MAC_WDG_TIMEOUT_WTO_MASK GENMASK(3, 0)
|
||||
#define WX_MAC_WDG_TIMEOUT_WTO_DELTA 2
|
||||
/* MDIO Registers */
|
||||
#define WX_MSCA 0x11200
|
||||
#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
|
||||
@@ -1152,6 +1163,11 @@ struct vf_data_storage {
|
||||
bool link_enable;
|
||||
bool trusted;
|
||||
int xcast_mode;
|
||||
unsigned int vf_api;
|
||||
bool clear_to_send;
|
||||
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
|
||||
u16 pf_qos;
|
||||
bool pf_set_mac;
|
||||
|
||||
u16 vf_mc_hashes[WX_MAX_VF_MC_ENTRIES];
|
||||
u16 num_vf_mc_hashes;
|
||||
@@ -1269,6 +1285,7 @@ struct wx {
|
||||
u32 wol;
|
||||
|
||||
u16 bd_number;
|
||||
bool default_up;
|
||||
|
||||
struct wx_hw_stats stats;
|
||||
u64 tx_busy;
|
||||
|
||||
Reference in New Issue
Block a user