2026-01-29 22:25:33 +08:00

1089 lines
29 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/ipv6.h>
#ifdef NETIF_F_HW_VLAN_CTAG_TX
#include <linux/if_vlan.h>
#endif
#include "rnpm.h"
#include "rnpm_type.h"
#include "rnpm_sriov.h"
#ifdef CONFIG_PCI_IOV
static int __rnpm_enable_sriov(struct rnpm_adapter *adapter)
{
struct rnpm_hw *hw = &adapter->hw;
int num_vf_macvlans, i;
struct vf_macvlans *mv_list;
u32 v;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
adapter->flags |= RNPM_FLAG_SRIOV_ENABLED;
e_info(probe, "SR-IOV enabled with %d VFs\n", adapter->num_vfs);
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
/* Enable VMDq flag so device will be set in VM mode */
adapter->flags |= RNPM_FLAG_VMDQ_ENABLED;
if (!adapter->ring_feature[RING_F_VMDQ].limit)
adapter->ring_feature[RING_F_VMDQ].limit = 1;
adapter->ring_feature[RING_F_VMDQ].offset = adapter->num_vfs;
num_vf_macvlans = hw->mac.num_rar_entries -
(RNPM_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
adapter->mv_list = mv_list = kcalloc(
num_vf_macvlans, sizeof(struct vf_macvlans), GFP_KERNEL);
if (mv_list) {
/* Initialize list of VF macvlans */
INIT_LIST_HEAD(&adapter->vf_mvs.l);
for (i = 0; i < num_vf_macvlans; i++) {
mv_list->vf = -1;
mv_list->free = true;
mv_list->rar_entry = hw->mac.num_rar_entries -
(i + adapter->num_vfs + 1);
list_add(&mv_list->l, &adapter->vf_mvs.l);
mv_list++;
}
}
/* Initialize default switching mode VEB */
wr32(hw, RNPM_DMA_CONFIG,
rd32(hw, RNPM_DMA_CONFIG) & (~DMA_VEB_BYPASS));
adapter->flags2 |= RNPM_FLAG2_BRIDGE_MODE_VEB;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
//ETH_BYPASS
rd32(hw, RNPM_ETH_BYPASS);
wr32(hw, RNPM_HOST_FILTER_EN, 1);
wr32(hw, RNPM_REDIR_EN, 1);
v = rd32(hw, RNPM_MRQC_IOV_EN);
v |= RNPM_IOV_ENABLED;
wr32(hw, RNPM_MRQC_IOV_EN, v);
wr32(hw, RNPM_ETH_DMAC_FCTRL,
rd32(hw, RNPM_ETH_DMAC_FCTRL) | RNPM_FCTRL_BROADCASE_BYPASS);
//wr32(hw, RNPM_ETH_DMAC_MCSTCTRL, v);
/* If call to enable VFs succeeded then allocate memory
* for per VF control structures.
*/
adapter->vfinfo = kcalloc(adapter->num_vfs,
sizeof(struct vf_data_storage), GFP_KERNEL);
if (adapter->vfinfo) {
/* limit trafffic classes based on VFs enabled */
/* TODO analyze VF need support pfc or traffic classes */
/* We do not support RSS w/ SR-IOV */
adapter->ring_feature[RING_F_RSS].limit = 2;
/* Disable RSC when in SR-IOV mode */
adapter->flags2 &=
~(RNPM_FLAG2_RSC_CAPABLE | RNPM_FLAG2_RSC_ENABLED);
/* enable spoof checking for all VFs */
//for (i = 0; i < adapter->num_vfs; i++)
//adapter->vfinfo[i].spoofchk_enabled = true;
return 0;
}
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
return -ENOMEM;
}
/* Note this function is called when the user wants to enable SR-IOV
* VFs using the now deprecated module parameter
*/
void rnpm_enable_sriov(struct rnpm_adapter *adapter)
{
int pre_existing_vfs = 0;
pre_existing_vfs = pci_num_vf(adapter->pdev);
if (!pre_existing_vfs && !adapter->num_vfs)
return;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
if (!pre_existing_vfs)
dev_warn(
&adapter->pdev->dev,
"Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
/* If there are pre-existing VFs then we have to force
* use of that many - over ride any module parameter value.
* This may result from the user unloading the PF driver
* while VFs were assigned to guest VMs or because the VFs
* have been created via the new PCI SR-IOV sysfs interface.
*/
if (pre_existing_vfs) {
adapter->num_vfs = pre_existing_vfs;
dev_warn(
&adapter->pdev->dev,
"Virtual Functions already enabled for this device - Please reload all VF drivers to avoid spoofed packet errors\n");
} else {
int err;
/* The n10 supports up to 64 VFs per physical function
* but this implementation limits allocation to 127 so that
* basic networking resources are still available to the
* physical function. If the user requests greater than
* 64 VFs then it is an error - reset to default of zero.
*/
adapter->num_vfs = min_t(unsigned int, adapter->num_vfs,
RNPM_MAX_VF_CNT - 1);
err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
if (err) {
e_err(probe, "Failed to enable PCI sriov: %d\n", err);
adapter->num_vfs = 0;
return;
}
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
}
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
if (!__rnpm_enable_sriov(adapter))
return;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
/* If we have gotten to this point then there is no memory available
* to manage the VF devices - print message and bail.
*/
e_err(probe, "Unable to allocate memory for VF Data Storage\n");
rnpm_disable_sriov(adapter);
}
static bool rnpm_vfs_are_assigned(struct rnpm_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct pci_dev *vfdev;
int dev_id;
unsigned int vendor_id;
if (adapter->pdev->device == RNPM_DEV_ID_N10_PF0) {
vendor_id = 0x1dab;
dev_id = RNPM_DEV_ID_N10_PF0_VF;
} else if (adapter->pdev->device == RNPM_DEV_ID_N10_PF1) {
vendor_id = 0x1dab;
dev_id = RNPM_DEV_ID_N10_PF1_VF;
} else if (adapter->pdev->device == RNPM_DEV_ID_N10_PF0_N) {
vendor_id = PCI_VENDOR_ID_MUCSE;
dev_id = RNPM_DEV_ID_N10_PF0_VF_N;
} else {
vendor_id = PCI_VENDOR_ID_MUCSE;
dev_id = RNPM_DEV_ID_N10_PF1_VF_N;
}
/* loop through all the VFs to see if we own any that are assigned */
vfdev = pci_get_device(vendor_id, dev_id, NULL);
while (vfdev) {
/* if we don't own it we don't care */
if (vfdev->is_virtfn && vfdev->physfn == pdev) {
/* if it is assigned we cannot release it */
if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
return true;
}
vfdev = pci_get_device(vendor_id, dev_id, vfdev);
}
return false;
}
#endif /* #ifdef CONFIG_PCI_IOV */
int rnpm_disable_sriov(struct rnpm_adapter *adapter)
{
struct rnpm_hw *hw = &adapter->hw;
u32 v;
int rss;
// disable
v = rd32(hw, RNPM_MRQC_IOV_EN);
v &= ~(RNPM_IOV_ENABLED);
wr32(hw, RNPM_MRQC_IOV_EN, v);
/* set num VFs to 0 to prevent access to vfinfo */
adapter->num_vfs = 0;
/* free VF control structures */
kfree(adapter->vfinfo);
adapter->vfinfo = NULL;
/* free macvlan list */
kfree(adapter->mv_list);
adapter->mv_list = NULL;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
/* if SR-IOV is already disabled then there is nothing to do */
if (!(adapter->flags & RNPM_FLAG_SRIOV_ENABLED))
return 0;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
#ifdef CONFIG_PCI_IOV
/* If our VFs are assigned we cannot shut down SR-IOV
* without causing issues, so just leave the hardware
* available but disabled
*/
if (rnpm_vfs_are_assigned(adapter)) {
e_dev_warn(
"Unloading driver while VFs are assigned - VFs will not be deallocated\n");
return -EPERM;
}
/* disable iov and allow time for transactions to clear */
pci_disable_sriov(adapter->pdev);
#endif
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
/* set default pool back to 0 */
/* Disable VMDq flag so device will be set in VM mode */
if (adapter->ring_feature[RING_F_VMDQ].limit == 1)
adapter->flags &= ~RNPM_FLAG_VMDQ_ENABLED;
adapter->ring_feature[RING_F_VMDQ].offset = 0;
rss = min_t(int, adapter->max_ring_pair_counts, num_online_cpus());
adapter->ring_feature[RING_F_RSS].limit = rss;
/* take a breather then clean up driver data */
msleep(100);
adapter->flags &= ~RNPM_FLAG_SRIOV_ENABLED;
dbg("%s:%d flags:0x%x\n", __func__, __LINE__, adapter->flags);
return 0;
}
static int rnpm_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
{
#ifdef CONFIG_PCI_IOV
// todo fix me
struct rnpm_adapter *adapter = pci_get_drvdata(dev);
//struct rnpm_pf_adapter *pf_adapter = pci_get_drvdata(pdev);
int err = 0;
int i;
int pre_existing_vfs = pci_num_vf(dev);
if (adapter->flags & RNPM_FLAG_MUTIPORT_ENABLED) {
err = -EACCES;
goto err_out;
}
if (pre_existing_vfs && pre_existing_vfs != num_vfs)
err = rnpm_disable_sriov(adapter);
else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
goto out;
if (err)
goto err_out;
/* While the SR-IOV capability structure reports total VFs to be
* 64 we limit the actual number that can be allocated to 63 so
* that some transmit/receive resources can be reserved to the
* PF. The PCI bus driver already checks for other values out of
* range.
*/
if (num_vfs > (RNPM_MAX_VF_FUNCTIONS - 1)) {
err = -EPERM;
goto err_out;
}
adapter->num_vfs = num_vfs;
err = __rnpm_enable_sriov(adapter);
if (err)
goto err_out;
for (i = 0; i < adapter->num_vfs; i++)
rnpm_vf_configuration(dev, (i | 0x10000000));
err = pci_enable_sriov(dev, num_vfs);
if (err) {
e_dev_warn("Failed to enable PCI sriov: %d\n", err);
goto err_out;
}
dbg("flags:0x%x\n", adapter->flags);
rnpm_sriov_reinit(adapter);
out:
return num_vfs;
err_out:
return err;
#endif
return 0;
}
static int rnpm_pci_sriov_disable(struct pci_dev *dev)
{
struct rnpm_adapter *adapter = pci_get_drvdata(dev);
int err;
u32 current_flags = adapter->flags;
err = rnpm_disable_sriov(adapter);
/* Only reinit if no error and state changed */
if (!err && current_flags != adapter->flags) {
/* rnpm_disable_sriov() doesn't clear VMDQ flag */
adapter->flags &= ~RNPM_FLAG_VMDQ_ENABLED;
#ifdef CONFIG_PCI_IOV
rnpm_sriov_reinit(adapter);
#endif
}
return err;
}
static int rnpm_set_vf_multicasts(struct rnpm_adapter *adapter, u32 *msgbuf,
u32 vf)
{
int entries =
(msgbuf[0] & RNPM_VT_MSGINFO_MASK) >> RNPM_VT_MSGINFO_SHIFT;
u16 *hash_list = (u16 *)&msgbuf[1];
struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
struct rnpm_hw *hw = &adapter->hw;
int i;
u32 vector_bit;
u32 vector_reg;
u32 mta_reg;
/* only so many hash values supported */
entries = min(entries, RNPM_MAX_VF_MC_ENTRIES);
// enable multicast and unicast filter
mta_reg = rd32(hw, RNPM_ETH_DMAC_MCSTCTRL);
wr32(hw, RNPM_ETH_DMAC_MCSTCTRL,
mta_reg | RNPM_MCSTCTRL_MULTICASE_TBL_EN |
RNPM_MCSTCTRL_UNICASE_TBL_EN);
/* salt away the number of multi cast addresses assigned
* to this VF for later use to restore when the PF multi cast
* list changes
*/
vfinfo->num_vf_mc_hashes = entries;
/* VFs are limited to using the MTA hash table for their multicast
* addresses
*/
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 = (vfinfo->vf_mc_hashes[i] >> 5) & 0x7F;
vector_bit = vfinfo->vf_mc_hashes[i] & 0x1F;
mta_reg = rd32(hw, RNPM_ETH_MUTICAST_HASH_TABLE(vector_reg));
mta_reg |= (1 << vector_bit);
wr32(hw, RNPM_ETH_MUTICAST_HASH_TABLE(vector_reg), mta_reg);
}
return 0;
}
static void rnpm_restore_vf_macvlans(struct rnpm_adapter *adapter)
{
struct rnpm_hw *hw = &adapter->hw;
struct list_head *pos;
struct vf_macvlans *entry;
list_for_each(pos, &adapter->vf_mvs.l) {
entry = list_entry(pos, struct vf_macvlans, l);
if (!entry->free) {
hw_dbg(hw, " vf:%d MACVLAN: RAR[%d] <= %pM\n",
entry->vf, entry->rar_entry, entry->vf_macvlan);
hw->mac.ops.set_rar(hw, entry->rar_entry,
entry->vf_macvlan, entry->vf,
RNPM_RAH_AV);
}
}
}
void rnpm_restore_vf_multicasts(struct rnpm_adapter *adapter)
{
struct rnpm_hw *hw = &adapter->hw;
struct vf_data_storage *vfinfo;
int i, j;
u32 vector_bit;
u32 vector_reg;
u32 mta_reg;
hw_dbg(hw, "%s num_vf:%d\n", __func__, adapter->num_vfs);
for (i = 0; i < adapter->num_vfs; i++) {
vfinfo = &adapter->vfinfo[i];
for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) {
hw->addr_ctrl.mta_in_use++;
vector_reg = (vfinfo->vf_mc_hashes[j] >> 5) & 0x7F;
vector_bit = vfinfo->vf_mc_hashes[j] & 0x1F;
mta_reg = rd32(
hw, RNPM_ETH_MUTICAST_HASH_TABLE(vector_reg));
mta_reg |= (1 << vector_bit);
wr32(hw, RNPM_ETH_MUTICAST_HASH_TABLE(vector_reg),
mta_reg);
hw_dbg(hw, " VF:%2d mc_hash:0x%x, MTA[%2d][%2d]=1\n", i,
vfinfo->vf_mc_hashes[j], vector_reg, vector_bit);
}
}
/* Restore any VF macvlans */
rnpm_restore_vf_macvlans(adapter);
}
static int rnpm_set_vf_vlan(struct rnpm_adapter *adapter, int add, int vid,
u32 vf)
{
/* VLAN 0 is a special case, don't allow it to be removed */
if (!vid && !add)
return 0;
return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
}
static s32 rnpm_set_vf_lpe(struct rnpm_adapter *adapter, u32 *msgbuf, u32 vf)
{
return 0;
}
static void __maybe_unused rnpm_set_vmolr(struct rnpm_hw *hw, u32 vf, bool aupe)
{
}
static void __maybe_unused rnpm_clear_vmvir(struct rnpm_adapter *adapter,
u32 vf)
{
// struct rnpm_hw *hw = &adapter->hw;
//RNPM_WRITE_REG(hw, RNPM_VMVIR(vf), 0);
}
static inline void rnpm_vf_reset_event(struct rnpm_adapter *adapter, u32 vf)
{
struct rnpm_hw *hw = &adapter->hw;
struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
int rar_entry = hw->mac.num_rar_entries - (vf + 1);
u8 num_tcs = netdev_get_num_tc(adapter->netdev);
/* add PF assigned VLAN or VLAN 0 */
// rnpm_set_vf_vlan(adapter, true, vfinfo->pf_vlan, vf);
/* reset offloads to defaults */
// rnpm_set_vmolr(hw, vf, !vfinfo->pf_vlan);
/* set outgoing tags for VFs */
if (!vfinfo->pf_vlan && !vfinfo->pf_qos && !num_tcs) {
// rnpm_clear_vmvir(adapter, vf);
} else {
if (vfinfo->pf_qos || !num_tcs)
rnpm_set_vmvir(adapter, vfinfo->pf_vlan, vfinfo->pf_qos,
vf);
else
rnpm_set_vmvir(adapter, vfinfo->pf_vlan,
adapter->default_up, vf);
//if (vfinfo->spoofchk_enabled)
// hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
}
/* reset multicast table array for vf */
adapter->vfinfo[vf].num_vf_mc_hashes = 0;
/* Flush and reset the mta with the new values */
rnpm_set_rx_mode(adapter->netdev);
/* clear this rar_entry */
hw->mac.ops.clear_rar(hw, rar_entry);
/* reset VF api back to unknown */
adapter->vfinfo[vf].vf_api = 0;
}
static int rnpm_set_vf_mac(struct rnpm_adapter *adapter, int vf,
unsigned char *mac_addr)
{
struct rnpm_hw *hw = &adapter->hw;
/* this rar_entry may be cofict with mac vlan with pf */
int rar_entry = hw->mac.num_rar_entries - (vf + 1);
int vf_ring = vf * 2;
memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf_ring / 2, RNPM_RAH_AV);
return 0;
}
static int rnpm_set_vf_macvlan(struct rnpm_adapter *adapter, int vf, int index,
unsigned char *mac_addr)
{
struct rnpm_hw *hw = &adapter->hw;
struct list_head *pos;
struct vf_macvlans *entry;
if (index <= 1) {
list_for_each(pos, &adapter->vf_mvs.l) {
entry = list_entry(pos, struct vf_macvlans, l);
if (entry->vf == vf) {
entry->vf = -1;
entry->free = true;
entry->is_macvlan = false;
hw->mac.ops.clear_rar(hw, entry->rar_entry);
}
}
}
/* If index was zero then we were asked to clear the uc list
* for the VF. We're done.
*/
if (!index)
return 0;
entry = NULL;
list_for_each(pos, &adapter->vf_mvs.l) {
entry = list_entry(pos, struct vf_macvlans, l);
if (entry->free)
break;
}
/* If we traversed the entire list and didn't find a free entry
* then we're out of space on the RAR table. Also entry may
* be NULL because the original memory allocation for the list
* failed, which is not fatal but does mean we can't support
* VF requests for MACVLAN because we couldn't allocate
* memory for the list management required.
*/
if (!entry || !entry->free)
return -ENOSPC;
entry->free = false;
entry->is_macvlan = true;
entry->vf = vf;
memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, RNPM_RAH_AV);
return 0;
}
int rnpm_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
{
unsigned char vf_mac_addr[6];
struct rnpm_adapter *adapter = pci_get_drvdata(pdev);
unsigned int vfn = (event_mask & 0x3f);
bool enable = ((event_mask & 0x10000000U) != 0);
if (enable) {
eth_zero_addr(vf_mac_addr);
memcpy(vf_mac_addr, adapter->hw.mac.perm_addr, 6);
vf_mac_addr[5] = vf_mac_addr[5] + (0x80 | vfn);
memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6);
}
return 0;
}
static int rnpm_vf_reset_msg(struct rnpm_adapter *adapter, u32 vf)
{
struct rnpm_hw *hw = &adapter->hw;
unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
u32 msgbuf[5];
// u32 reg_offset, vf_shift;
u8 *addr = (u8 *)(&msgbuf[1]);
e_info(probe, "VF Reset msg received from vf %d. cmd:0x%x\n", vf,
msgbuf[0]);
/* reset the filters for the device */
rnpm_vf_reset_event(adapter, vf);
/* set vf mac address */
if (!is_zero_ether_addr(vf_mac))
rnpm_set_vf_mac(adapter, vf, vf_mac);
/* enable VF mailbox for further messages */
adapter->vfinfo[vf].clear_to_send = true;
/* Enable counting of spoofed packets in the SSVPC register */
/* reply to reset with ack and vf mac address */
msgbuf[0] = RNPM_VF_RESET;
if (!is_zero_ether_addr(vf_mac)) {
msgbuf[0] |= RNPM_VT_MSGTYPE_ACK;
memcpy(addr, vf_mac, ETH_ALEN);
} else {
msgbuf[0] |= RNPM_VT_MSGTYPE_NACK;
dev_warn(
&adapter->pdev->dev,
"VF %d has no MAC address assigned, you may have to assign one manually\n",
vf);
}
/* Piggyback the multicast filter type so VF can compute the
* correct vectors
*/
msgbuf[RNPM_VF_MC_TYPE_WORD] = 0;
/* setup link status , pause mode, ft padding mode */
/* link status */
// to-do
/* pause mode */
msgbuf[RNPM_VF_MC_TYPE_WORD] |= (0xff & hw->fc.current_mode) << 16;
if (adapter->priv_flags & RNPM_PRIV_FLAG_PCIE_CACHE_ALIGN_PATCH)
msgbuf[RNPM_VF_MC_TYPE_WORD] |= (0x01 << 8);
else
msgbuf[RNPM_VF_MC_TYPE_WORD] |= (0x00 << 8);
/* mc_type */
msgbuf[RNPM_VF_MC_TYPE_WORD] |= rd32(hw, RNPM_ETH_DMAC_MCSTCTRL) & 0x3;
msgbuf[RNPM_VF_DMA_VERSION_WORD] = rd32(hw, RNPM_DMA_VERSION);
;
/* now vf maybe has no irq handler if it is the first reset*/
rnpm_write_mbx(hw, msgbuf, RNPM_VF_PERMADDR_MSG_LEN, vf);
return 0;
}
static int rnpm_set_vf_mac_addr(struct rnpm_adapter *adapter, u32 *msgbuf,
u32 vf)
{
u8 *new_mac = ((u8 *)(&msgbuf[1]));
if (!is_valid_ether_addr(new_mac)) {
e_warn(drv, "VF %d attempted to set invalid mac\n", vf);
return -1;
}
if (adapter->vfinfo[vf].pf_set_mac &&
memcmp(adapter->vfinfo[vf].vf_mac_addresses, new_mac, ETH_ALEN)) {
e_warn(drv,
"VF %d attempted to override administratively set MAC address\n"
"Reload the VF driver to resume operations\n",
vf);
return -1;
}
return rnpm_set_vf_mac(adapter, vf, new_mac) < 0;
}
static int rnpm_set_vf_vlan_msg(struct rnpm_adapter *adapter, u32 *msgbuf,
u32 vf)
{
// struct rnpm_hw *hw = &adapter->hw;
int add = ((msgbuf[0] & RNPM_VT_MSGINFO_MASK) >> RNPM_VT_MSGINFO_SHIFT);
int vid = (msgbuf[1] & RNPM_VLVF_VLANID_MASK);
int err;
//u8 tcs = netdev_get_num_tc(adapter->netdev);
if (adapter->vfinfo[vf].pf_vlan) {
e_warn(drv,
"VF %d attempted to override administratively set VLAN configuration\n"
"Reload the VF driver to resume operations\n",
vf);
return -1;
}
if (add)
adapter->vfinfo[vf].vlan_count++;
else if (adapter->vfinfo[vf].vlan_count)
adapter->vfinfo[vf].vlan_count--;
err = rnpm_set_vf_vlan(adapter, add, vid, vf);
return err;
}
static int rnpm_set_vf_vlan_strip_msg(struct rnpm_adapter *adapter, u32 *msgbuf,
u32 vf)
{
struct rnpm_hw *hw = &adapter->hw;
int vlan_strip_on = !!(msgbuf[1] >> 31);
int queue_cnt = msgbuf[1] & 0xffff;
int err = 0, i;
vf_dbg("strip_on:%d queeu_cnt:%d, %d %d\n", vlan_strip_on, queue_cnt,
msgbuf[2], msgbuf[3]);
for (i = 0; i < queue_cnt; i++) {
if (vlan_strip_on)
hw_queue_strip_rx_vlan(hw, msgbuf[2 + i], true);
else
hw_queue_strip_rx_vlan(hw, msgbuf[2 + i], false);
}
return err;
}
static int rnpm_set_vf_macvlan_msg(struct rnpm_adapter *adapter, u32 *msgbuf,
u32 vf)
{
u8 *new_mac = ((u8 *)(&msgbuf[1]));
int index = (msgbuf[0] & RNPM_VT_MSGINFO_MASK) >> RNPM_VT_MSGINFO_SHIFT;
int err;
if (adapter->vfinfo[vf].pf_set_mac && index > 0) {
e_warn(drv,
"VF %d requested MACVLAN filter but is administratively denied\n",
vf);
return -1;
}
/* An non-zero index indicates the VF is setting a filter */
if (index) {
if (!is_valid_ether_addr(new_mac)) {
e_warn(drv, "VF %d attempted to set invalid mac\n", vf);
return -1;
}
}
err = rnpm_set_vf_macvlan(adapter, vf, index, new_mac);
if (err == -ENOSPC)
e_warn(drv,
"VF %d has requested a MACVLAN filter but there is no space for it\n",
vf);
return err < 0;
return 0;
}
static int rnpm_negotiate_vf_api(struct rnpm_adapter *adapter, u32 *msgbuf,
u32 vf)
{
adapter->vfinfo[vf].vf_api = 0;
return 0;
}
static int rnpm_get_vf_reg(struct rnpm_adapter *adapter, u32 *msgbuf, u32 vf)
{
// struct net_device *dev = adapter->netdev;
u32 reg = msgbuf[1];
if (reg == 0) { //FIXME check regs
return -1;
}
msgbuf[1] = rd32(&adapter->hw, reg);
return 0;
}
static int rnpm_get_vf_queues(struct rnpm_adapter *adapter, u32 *msgbuf, u32 vf)
{
struct net_device *dev = adapter->netdev;
// struct rnpm_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
unsigned int default_tc = 0;
u8 num_tcs = netdev_get_num_tc(dev);
/* verify the PF is supporting the correct APIs */
/* only allow 1 Tx queue for bandwidth limiting */
msgbuf[RNPM_VF_TX_QUEUES] = 1;
msgbuf[RNPM_VF_RX_QUEUES] = 1;
/* if TCs > 1 determine which TC belongs to default user priority */
if (num_tcs > 1)
default_tc = netdev_get_prio_tc_map(dev, adapter->default_up);
/* notify VF of need for VLAN tag stripping, and correct queue */
if (num_tcs)
msgbuf[RNPM_VF_TRANS_VLAN] = num_tcs;
else if (adapter->vfinfo[vf].pf_vlan || adapter->vfinfo[vf].pf_qos)
msgbuf[RNPM_VF_TRANS_VLAN] = 1;
else
msgbuf[RNPM_VF_TRANS_VLAN] = 0;
/* notify VF of default queue */
msgbuf[RNPM_VF_DEF_QUEUE] = default_tc;
return 0;
}
static int __maybe_unused rnpm_rcv_msg_from_vf(struct rnpm_adapter *adapter,
u32 vf)
{
u32 mbx_size = RNPM_VFMAILBOX_SIZE;
u32 msgbuf[RNPM_VFMAILBOX_SIZE];
struct rnpm_hw *hw = &adapter->hw;
s32 retval;
retval = rnpm_read_mbx(hw, msgbuf, mbx_size, vf);
if (retval) {
pr_err("Error receiving message from VF\n");
return retval;
}
vf_dbg("msg[0]=0x%08x\n", msgbuf[0]);
/* this is a message we already processed, do nothing */
if (msgbuf[0] & (RNPM_VT_MSGTYPE_ACK | RNPM_VT_MSGTYPE_NACK))
return retval;
/* this is a vf reset irq */
if (msgbuf[0] == RNPM_VF_RESET)
return rnpm_vf_reset_msg(adapter, vf);
/* until the vf completes a virtual function reset it should not be
* allowed to start any configuration.
*/
if (!adapter->vfinfo[vf].clear_to_send) {
msgbuf[0] |= RNPM_VT_MSGTYPE_NACK;
rnpm_write_mbx(hw, msgbuf, 1, vf);
return retval;
}
switch ((msgbuf[0] & 0xFFFF)) {
case RNPM_VF_SET_MAC_ADDR:
retval = rnpm_set_vf_mac_addr(adapter, msgbuf, vf);
break;
case RNPM_VF_SET_MULTICAST:
retval = rnpm_set_vf_multicasts(adapter, msgbuf, vf);
break;
case RNPM_VF_SET_VLAN:
retval = rnpm_set_vf_vlan_msg(adapter, msgbuf, vf);
break;
case RNPM_VF_SET_VLAN_STRIP:
retval = rnpm_set_vf_vlan_strip_msg(adapter, msgbuf, vf);
break;
case RNPM_VF_SET_LPE:
retval = rnpm_set_vf_lpe(adapter, msgbuf, vf);
break;
case RNPM_VF_SET_MACVLAN:
retval = rnpm_set_vf_macvlan_msg(adapter, msgbuf, vf);
break;
case RNPM_VF_API_NEGOTIATE:
retval = rnpm_negotiate_vf_api(adapter, msgbuf, vf);
break;
case RNPM_VF_GET_QUEUES:
retval = rnpm_get_vf_queues(adapter, msgbuf, vf);
break;
case RNPM_VF_REG_RD:
retval = rnpm_get_vf_reg(adapter, msgbuf, vf);
break;
case RNPM_PF_REMOVE:
//dbg("vf %d down\n", vf);
adapter->vfinfo[vf].clear_to_send = false;
retval = 1;
break;
default:
e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
retval = RNPM_ERR_MBX;
break;
}
/* notify the VF of the results of what it sent us */
if (retval)
msgbuf[0] |= RNPM_VT_MSGTYPE_NACK;
else
msgbuf[0] |= RNPM_VT_MSGTYPE_ACK;
msgbuf[0] |= RNPM_VT_MSGTYPE_CTS;
rnpm_write_mbx(hw, msgbuf, mbx_size, vf);
return retval;
}
static void __maybe_unused rnpm_rcv_ack_from_vf(struct rnpm_adapter *adapter,
u32 vf)
{
struct rnpm_hw *hw = &adapter->hw;
u32 msg = RNPM_VT_MSGTYPE_NACK;
/* if device isn't clear to send it shouldn't be reading either */
if (!adapter->vfinfo[vf].clear_to_send)
rnpm_write_mbx(hw, &msg, 1, vf);
}
void rnpm_msg_task(struct rnpm_pf_adapter *pf_adapter)
{
rnpm_fw_msg_handler(pf_adapter);
}
/* try to send mailbox to all active vf */
void rnpm_msg_post_status(struct rnpm_adapter *adapter, enum PF_STATUS status)
{
u32 msgbuf[RNPM_VFMAILBOX_SIZE];
struct rnpm_hw *hw = &adapter->hw;
struct rnpm_mbx_info *mbx = &hw->mbx;
u32 vf;
for (vf = 0; vf < adapter->num_vfs; vf++) {
if (adapter->vfinfo[vf].clear_to_send) {
dbg("now send msg to vf %d\n", vf);
switch (status) {
case PF_FCS_STATUS:
msgbuf[0] = RNPM_PF_SET_FCS;
if (adapter->netdev->features & NETIF_F_RXFCS)
msgbuf[1] = 1;
else
msgbuf[1] = 0;
break;
case PF_PAUSE_STATUS:
msgbuf[0] = RNPM_PF_SET_PAUSE;
msgbuf[1] = hw->fc.requested_mode;
break;
case PF_FT_PADDING_STATUS:
msgbuf[0] = RNPM_PF_SET_FT_PADDING;
if (adapter->priv_flags &
RNPM_PRIV_FLAG_PCIE_CACHE_ALIGN_PATCH) {
msgbuf[1] = 1;
} else {
msgbuf[1] = 0;
}
break;
default:
break;
}
//dbg("msg 0 is %x\n", msgbuf[0]);
//dbg("msg 1 is %x\n", msgbuf[1]);
//
mbx->ops.write(hw, msgbuf, 2, vf);
}
}
}
void rnpm_disable_tx_rx(struct rnpm_adapter *adapter)
{
// struct rnpm_hw *hw = &adapter->hw;
/* disable transmit and receive for all vfs */
}
void rnpm_ping_all_vfs(struct rnpm_adapter *adapter)
{
struct rnpm_hw *hw = &adapter->hw;
u32 ping;
int i;
for (i = 0; i < adapter->num_vfs; i++) {
ping = RNPM_PF_CONTROL_PRING_MSG;
/* only send to active vf */
//if (adapter->vfinfo[i].clear_to_send) {
ping |= RNPM_VT_MSGTYPE_CTS;
rnpm_write_mbx(hw, &ping, 1, i);
// }
}
}
int rnpm_get_vf_ringnum(int vf, int num)
{
//fix me if ring alloc reset
return (vf * 2 + num);
}
int rnpm_setup_ring_maxrate(struct rnpm_adapter *adapter, int ring,
u64 max_rate)
{
u64 x, y, result;
#define RNPM_SAMPING_1SEC_INTERNAL (180000000)
/* set hardware samping internal 1S */
rnpm_wr_reg(adapter->hw.hw_addr + RNPM_DMA_REG_TX_FLOW_CTRL_TM(ring),
RNPM_SAMPING_1SEC_INTERNAL / 10);
x = max_rate;
y = do_div(x, 10);
result = x;
result = x * 3;
rnpm_wr_reg(adapter->hw.hw_addr + RNPM_DMA_REG_TX_FLOW_CTRL_TH(ring),
result);
return 0;
}
#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
int rnpm_ndo_set_vf_bw(struct net_device *netdev, int vf,
int __always_unused min_tx_rate, int max_tx_rate)
#else
int rnpm_ndo_set_vf_bw(struct net_device *netdev, int vf, int max_tx_rate)
#endif /* HAVE_NDO_SET_VF_MIN_MAX_TX_RATE */
{
struct rnpm_adapter *adapter = netdev_priv(netdev);
/* limit vf ring rate */
int ring_max_rate;
int vf_ring;
int link_speed;
if (vf >= RNPM_MAX_VF_CNT - 1)
return -EINVAL;
// todo
link_speed = 10000;
//link_speed = rnpm_link_mbps(adapter);
/* rate limit cannot be less than 10Mbs or greater than link speed */
if (max_tx_rate && ((max_tx_rate <= 10) || (max_tx_rate > link_speed)))
return -EINVAL;
ring_max_rate = max_tx_rate / PF_RING_CNT_WHEN_IOV_ENABLED;
vf_ring = rnpm_get_vf_ringnum(vf, 0);
rnpm_setup_ring_maxrate(adapter, vf_ring, ring_max_rate);
vf_ring = rnpm_get_vf_ringnum(vf, 1);
rnpm_setup_ring_maxrate(adapter, vf_ring, ring_max_rate);
return 0;
}
int rnpm_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
{
struct rnpm_adapter *adapter = netdev_priv(netdev);
if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs))
return -EINVAL;
adapter->vfinfo[vf].pf_set_mac = true;
dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf);
if (test_bit(__RNPM_DOWN, &adapter->state)) {
dev_warn(
&adapter->pdev->dev,
"The VF MAC address has been set but the PFis not up.\n");
}
return rnpm_set_vf_mac(adapter, vf, mac);
}
static int __maybe_unused rnpm_link_mbps(struct rnpm_adapter *adapter)
{
switch (adapter->link_speed) {
case RNPM_LINK_SPEED_100_FULL:
return 100;
case RNPM_LINK_SPEED_1GB_FULL:
return 1000;
case RNPM_LINK_SPEED_10GB_FULL:
return 10000;
default:
return 0;
}
}
int rnpm_ndo_get_vf_config(struct net_device *netdev, int vf,
struct ifla_vf_info *ivi)
{
struct rnpm_adapter *adapter = netdev_priv(netdev);
if (vf >= adapter->num_vfs)
return -EINVAL;
ivi->vf = vf;
memcpy(&ivi->mac, adapter->vfinfo[vf].vf_mac_addresses, ETH_ALEN);
//ivi->tx_rate = adapter->vfinfo[vf].tx_rate;
ivi->vlan = adapter->vfinfo[vf].pf_vlan;
ivi->qos = adapter->vfinfo[vf].pf_qos;
#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
ivi->spoofchk = adapter->vfinfo[vf].spoofchk_enabled;
#endif
return 0;
}
int rnpm_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
{
vf_dbg("\n\n !!!! %s:%d num_vfs:%d\n", __func__, __LINE__, num_vfs);
if (num_vfs == 0)
return rnpm_pci_sriov_disable(dev);
else
return rnpm_pci_sriov_enable(dev, num_vfs);
}