Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
577389a
Documentation
arch
block
certs
crypto
drivers
accessibility
acpi
amba
android
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dca
devfreq
dio
dma-buf
dma
edac
eisa
extcon
firewire
firmware
fmc
fpga
gpio
gpu
hid
hsi
hv
hwmon
hwspinlock
hwtracing
i2c
ide
idle
iio
infiniband
input
iommu
ipack
irqchip
isdn
leds
lguest
lightnvm
macintosh
mailbox
mcb
md
media
memory
memstick
message
mfd
misc
mmc
mtd
net
appletalk
arcnet
bonding
caif
can
cris
dsa
ethernet
3com
8390
adaptec
adi
aeroflex
agere
allwinner
alteon
altera
amd
apm
apple
arc
atheros
aurora
broadcom
brocade
cadence
calxeda
cavium
chelsio
cirrus
cisco
davicom
dec
dlink
emulex
ezchip
faraday
freescale
fujitsu
hisilicon
hp
i825xx
ibm
intel
e1000
e1000e
fm10k
i40e
i40evf
Makefile
i40e_adminq.c
i40e_adminq.h
i40e_adminq_cmd.h
i40e_alloc.h
i40e_common.c
i40e_devids.h
i40e_hmc.h
i40e_lan_hmc.h
i40e_osdep.h
i40e_prototype.h
i40e_register.h
i40e_status.h
i40e_txrx.c
i40e_txrx.h
i40e_type.h
i40e_virtchnl.h
i40evf.h
i40evf_ethtool.c
i40evf_main.c
i40evf_virtchnl.c
igb
igbvf
ixgb
ixgbe
ixgbevf
Kconfig
Makefile
e100.c
marvell
mediatek
mellanox
micrel
microchip
moxa
myricom
natsemi
neterion
netronome
nuvoton
nvidia
nxp
oki-semi
packetengines
pasemi
qlogic
qualcomm
rdc
realtek
renesas
rocker
samsung
seeq
sfc
sgi
silan
sis
smsc
stmicro
sun
synopsys
tehuti
ti
tile
toshiba
tundra
via
wiznet
xilinx
xircom
xscale
Kconfig
Makefile
dnet.c
dnet.h
ec_bhf.c
ethoc.c
fealnx.c
jme.c
jme.h
korina.c
lantiq_etop.c
netx-eth.c
fddi
fjes
hamradio
hippi
hyperv
ieee802154
ipvlan
irda
phy
plip
ppp
slip
team
usb
vmxnet3
wan
wimax
wireless
xen-netback
Kconfig
LICENSE.SRC
Makefile
Space.c
dummy.c
eql.c
geneve.c
ifb.c
loopback.c
macsec.c
macvlan.c
macvtap.c
mdio.c
mii.c
netconsole.c
nlmon.c
ntb_netdev.c
rionet.c
sb1000.c
sungem_phy.c
tun.c
veth.c
virtio_net.c
vrf.c
vxlan.c
xen-netfront.c
nfc
ntb
nubus
nvdimm
nvme
nvmem
of
oprofile
parisc
parport
pci
pcmcia
perf
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
ras
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sfi
sh
sn
soc
spi
spmi
ssb
staging
target
tc
thermal
thunderbolt
tty
uio
usb
uwb
vfio
vhost
video
virt
virtio
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.get_maintainer.ignore
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
drivers
/
net
/
ethernet
/
intel
/
i40evf
/
i40evf_main.c
Blame
Blame
Latest commit
History
History
2961 lines (2559 loc) · 78.1 KB
Breadcrumbs
linux
/
drivers
/
net
/
ethernet
/
intel
/
i40evf
/
i40evf_main.c
Top
File metadata and controls
Code
Blame
2961 lines (2559 loc) · 78.1 KB
Raw
/******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver * Copyright(c) 2013 - 2016 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * * Contact Information: * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * ******************************************************************************/ #include "i40evf.h" #include "i40e_prototype.h" static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); static int i40evf_close(struct net_device *netdev); char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) 40-10 Gigabit Virtual Function Network Driver"; #define DRV_KERN "-k" #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 5 #define DRV_VERSION_BUILD 5 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) \ DRV_KERN const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2015 Intel Corporation."; /* i40evf_pci_tbl - PCI Device ID Table * * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */ static const struct pci_device_id i40evf_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0}, /* required last entry */ {0, } }; MODULE_DEVICE_TABLE(pci, i40evf_pci_tbl); MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>"); MODULE_DESCRIPTION("Intel(R) XL710 X710 Virtual Function Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); static struct workqueue_struct *i40evf_wq; /** * i40evf_allocate_dma_mem_d - OS specific memory alloc for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to fill out * @size: size of memory requested * @alignment: what to align the allocation to **/ i40e_status i40evf_allocate_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem, u64 size, u32 alignment) { struct i40evf_adapter *adapter = (struct i40evf_adapter *)hw->back; if (!mem) return I40E_ERR_PARAM; mem->size = ALIGN(size, alignment); mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, (dma_addr_t *)&mem->pa, GFP_KERNEL); if (mem->va) return 0; else return I40E_ERR_NO_MEMORY; } /** * i40evf_free_dma_mem_d - OS specific memory free for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ i40e_status i40evf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) { struct i40evf_adapter *adapter = (struct i40evf_adapter *)hw->back; if (!mem || !mem->va) return I40E_ERR_PARAM; dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va, (dma_addr_t)mem->pa); return 0; } /** * i40evf_allocate_virt_mem_d - OS specific memory alloc for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to fill out * @size: size of memory requested **/ i40e_status i40evf_allocate_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem, u32 size) { if (!mem) return I40E_ERR_PARAM; mem->size = size; mem->va = kzalloc(size, GFP_KERNEL); if (mem->va) return 0; else return I40E_ERR_NO_MEMORY; } /** * i40evf_free_virt_mem_d - OS specific memory free for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ i40e_status i40evf_free_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem) { if (!mem) return I40E_ERR_PARAM; /* it's ok to kfree a NULL pointer */ kfree(mem->va); return 0; } /** * i40evf_debug_d - OS dependent version of debug printing * @hw: pointer to the HW structure * @mask: debug level mask * @fmt_str: printf-type format description **/ void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...) { char buf[512]; va_list argptr; if (!(mask & ((struct i40e_hw *)hw)->debug_mask)) return; va_start(argptr, fmt_str); vsnprintf(buf, sizeof(buf), fmt_str, argptr); va_end(argptr); /* the debug string is already formatted with a newline */ pr_info("%s", buf); } /** * i40evf_schedule_reset - Set the flags and schedule a reset event * @adapter: board private structure **/ void i40evf_schedule_reset(struct i40evf_adapter *adapter) { if (!(adapter->flags & (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED))) { adapter->flags |= I40EVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); } } /** * i40evf_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure **/ static void i40evf_tx_timeout(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); adapter->tx_timeout_count++; i40evf_schedule_reset(adapter); } /** * i40evf_misc_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/ static void i40evf_misc_irq_disable(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; wr32(hw, I40E_VFINT_DYN_CTL01, 0); /* read flush */ rd32(hw, I40E_VFGEN_RSTAT); synchronize_irq(adapter->msix_entries[0].vector); } /** * i40evf_misc_irq_enable - Enable default interrupt generation settings * @adapter: board private structure **/ static void i40evf_misc_irq_enable(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK | I40E_VFINT_DYN_CTL01_ITR_INDX_MASK); wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK); /* read flush */ rd32(hw, I40E_VFGEN_RSTAT); } /** * i40evf_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/ static void i40evf_irq_disable(struct i40evf_adapter *adapter) { int i; struct i40e_hw *hw = &adapter->hw; if (!adapter->msix_entries) return; for (i = 1; i < adapter->num_msix_vectors; i++) { wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), 0); synchronize_irq(adapter->msix_entries[i].vector); } /* read flush */ rd32(hw, I40E_VFGEN_RSTAT); } /** * i40evf_irq_enable_queues - Enable interrupt for specified queues * @adapter: board private structure * @mask: bitmap of queues to enable **/ void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask) { struct i40e_hw *hw = &adapter->hw; int i; for (i = 1; i < adapter->num_msix_vectors; i++) { if (mask & BIT(i - 1)) { wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), I40E_VFINT_DYN_CTLN1_INTENA_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK); } } } /** * i40evf_fire_sw_int - Generate SW interrupt for specified vectors * @adapter: board private structure * @mask: bitmap of vectors to trigger **/ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, u32 mask) { struct i40e_hw *hw = &adapter->hw; int i; u32 dyn_ctl; if (mask & 1) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01); dyn_ctl |= I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl); } for (i = 1; i < adapter->num_msix_vectors; i++) { if (mask & BIT(i)) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1)); dyn_ctl |= I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), dyn_ctl); } } } /** * i40evf_irq_enable - Enable default interrupt generation settings * @adapter: board private structure * @flush: boolean value whether to run rd32() **/ void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush) { struct i40e_hw *hw = &adapter->hw; i40evf_misc_irq_enable(adapter); i40evf_irq_enable_queues(adapter, ~0); if (flush) rd32(hw, I40E_VFGEN_RSTAT); } /** * i40evf_msix_aq - Interrupt handler for vector 0 * @irq: interrupt number * @data: pointer to netdev **/ static irqreturn_t i40evf_msix_aq(int irq, void *data) { struct net_device *netdev = data; struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40e_hw *hw = &adapter->hw; u32 val; /* handle non-queue interrupts, these reads clear the registers */ val = rd32(hw, I40E_VFINT_ICR01); val = rd32(hw, I40E_VFINT_ICR0_ENA1); val = rd32(hw, I40E_VFINT_DYN_CTL01) | I40E_VFINT_DYN_CTL01_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, val); /* schedule work on the private workqueue */ schedule_work(&adapter->adminq_task); return IRQ_HANDLED; } /** * i40evf_msix_clean_rings - MSIX mode Interrupt Handler * @irq: interrupt number * @data: pointer to a q_vector **/ static irqreturn_t i40evf_msix_clean_rings(int irq, void *data) { struct i40e_q_vector *q_vector = data; if (!q_vector->tx.ring && !q_vector->rx.ring) return IRQ_HANDLED; napi_schedule_irqoff(&q_vector->napi); return IRQ_HANDLED; } /** * i40evf_map_vector_to_rxq - associate irqs with rx queues * @adapter: board private structure * @v_idx: interrupt number * @r_idx: queue number **/ static void i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx) { struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; struct i40e_ring *rx_ring = &adapter->rx_rings[r_idx]; rx_ring->q_vector = q_vector; rx_ring->next = q_vector->rx.ring; rx_ring->vsi = &adapter->vsi; q_vector->rx.ring = rx_ring; q_vector->rx.count++; q_vector->rx.latency_range = I40E_LOW_LATENCY; q_vector->itr_countdown = ITR_COUNTDOWN_START; } /** * i40evf_map_vector_to_txq - associate irqs with tx queues * @adapter: board private structure * @v_idx: interrupt number * @t_idx: queue number **/ static void i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx) { struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; struct i40e_ring *tx_ring = &adapter->tx_rings[t_idx]; tx_ring->q_vector = q_vector; tx_ring->next = q_vector->tx.ring; tx_ring->vsi = &adapter->vsi; q_vector->tx.ring = tx_ring; q_vector->tx.count++; q_vector->tx.latency_range = I40E_LOW_LATENCY; q_vector->itr_countdown = ITR_COUNTDOWN_START; q_vector->num_ringpairs++; q_vector->ring_mask |= BIT(t_idx); } /** * i40evf_map_rings_to_vectors - Maps descriptor rings to vectors * @adapter: board private structure to initialize * * This function maps descriptor rings to the queue-specific vectors * we were allotted through the MSI-X enabling code. Ideally, we'd have * one vector per ring/queue, but on a constrained vector budget, we * group the rings as "efficiently" as possible. You would add new * mapping configurations in here. **/ static int i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter) { int q_vectors; int v_start = 0; int rxr_idx = 0, txr_idx = 0; int rxr_remaining = adapter->num_active_queues; int txr_remaining = adapter->num_active_queues; int i, j; int rqpv, tqpv; int err = 0; q_vectors = adapter->num_msix_vectors - NONQ_VECS; /* The ideal configuration... * We have enough vectors to map one per queue. */ if (q_vectors >= (rxr_remaining * 2)) { for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++) i40evf_map_vector_to_rxq(adapter, v_start, rxr_idx); for (; txr_idx < txr_remaining; v_start++, txr_idx++) i40evf_map_vector_to_txq(adapter, v_start, txr_idx); goto out; } /* If we don't have enough vectors for a 1-to-1 * mapping, we'll have to group them so there are * multiple queues per vector. * Re-adjusting *qpv takes care of the remainder. */ for (i = v_start; i < q_vectors; i++) { rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i); for (j = 0; j < rqpv; j++) { i40evf_map_vector_to_rxq(adapter, i, rxr_idx); rxr_idx++; rxr_remaining--; } } for (i = v_start; i < q_vectors; i++) { tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i); for (j = 0; j < tqpv; j++) { i40evf_map_vector_to_txq(adapter, i, txr_idx); txr_idx++; txr_remaining--; } } out: adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS; return err; } #ifdef CONFIG_NET_POLL_CONTROLLER /** * i40evf_netpoll - A Polling 'interrupt' handler * @netdev: network interface device structure * * This is used by netconsole to send skbs without having to re-enable * interrupts. It's not called while the normal interrupt routine is executing. **/ static void i40evf_netpoll(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); int q_vectors = adapter->num_msix_vectors - NONQ_VECS; int i; /* if interface is down do nothing */ if (test_bit(__I40E_DOWN, &adapter->vsi.state)) return; for (i = 0; i < q_vectors; i++) i40evf_msix_clean_rings(0, &adapter->q_vectors[i]); } #endif /** * i40evf_request_traffic_irqs - Initialize MSI-X interrupts * @adapter: board private structure * * Allocates MSI-X vectors for tx and rx handling, and requests * interrupts from the kernel. **/ static int i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename) { int vector, err, q_vectors; int rx_int_idx = 0, tx_int_idx = 0; i40evf_irq_disable(adapter); /* Decrement for Other and TCP Timer vectors */ q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (vector = 0; vector < q_vectors; vector++) { struct i40e_q_vector *q_vector = &adapter->q_vectors[vector]; if (q_vector->tx.ring && q_vector->rx.ring) { snprintf(q_vector->name, sizeof(q_vector->name) - 1, "i40evf-%s-%s-%d", basename, "TxRx", rx_int_idx++); tx_int_idx++; } else if (q_vector->rx.ring) { snprintf(q_vector->name, sizeof(q_vector->name) - 1, "i40evf-%s-%s-%d", basename, "rx", rx_int_idx++); } else if (q_vector->tx.ring) { snprintf(q_vector->name, sizeof(q_vector->name) - 1, "i40evf-%s-%s-%d", basename, "tx", tx_int_idx++); } else { /* skip this unused q_vector */ continue; } err = request_irq( adapter->msix_entries[vector + NONQ_VECS].vector, i40evf_msix_clean_rings, 0, q_vector->name, q_vector); if (err) { dev_info(&adapter->pdev->dev, "Request_irq failed, error: %d\n", err); goto free_queue_irqs; } /* assign the mask for this irq */ irq_set_affinity_hint( adapter->msix_entries[vector + NONQ_VECS].vector, q_vector->affinity_mask); } return 0; free_queue_irqs: while (vector) { vector--; irq_set_affinity_hint( adapter->msix_entries[vector + NONQ_VECS].vector, NULL); free_irq(adapter->msix_entries[vector + NONQ_VECS].vector, &adapter->q_vectors[vector]); } return err; } /** * i40evf_request_misc_irq - Initialize MSI-X interrupts * @adapter: board private structure * * Allocates MSI-X vector 0 and requests interrupts from the kernel. This * vector is only for the admin queue, and stays active even when the netdev * is closed. **/ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; snprintf(adapter->misc_vector_name, sizeof(adapter->misc_vector_name) - 1, "i40evf-%s:mbx", dev_name(&adapter->pdev->dev)); err = request_irq(adapter->msix_entries[0].vector, &i40evf_msix_aq, 0, adapter->misc_vector_name, netdev); if (err) { dev_err(&adapter->pdev->dev, "request_irq for %s failed: %d\n", adapter->misc_vector_name, err); free_irq(adapter->msix_entries[0].vector, netdev); } return err; } /** * i40evf_free_traffic_irqs - Free MSI-X interrupts * @adapter: board private structure * * Frees all MSI-X vectors other than 0. **/ static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter) { int i; int q_vectors; q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (i = 0; i < q_vectors; i++) { irq_set_affinity_hint(adapter->msix_entries[i+1].vector, NULL); free_irq(adapter->msix_entries[i+1].vector, &adapter->q_vectors[i]); } } /** * i40evf_free_misc_irq - Free MSI-X miscellaneous vector * @adapter: board private structure * * Frees MSI-X vector 0. **/ static void i40evf_free_misc_irq(struct i40evf_adapter *adapter) { struct net_device *netdev = adapter->netdev; free_irq(adapter->msix_entries[0].vector, netdev); } /** * i40evf_configure_tx - Configure Transmit Unit after Reset * @adapter: board private structure * * Configure the Tx unit of the MAC after a reset. **/ static void i40evf_configure_tx(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; int i; for (i = 0; i < adapter->num_active_queues; i++) adapter->tx_rings[i].tail = hw->hw_addr + I40E_QTX_TAIL1(i); } /** * i40evf_configure_rx - Configure Receive Unit after Reset * @adapter: board private structure * * Configure the Rx unit of the MAC after a reset. **/ static void i40evf_configure_rx(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; int i; int rx_buf_len; /* Set the RX buffer length according to the mode */ if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED || netdev->mtu <= ETH_DATA_LEN) rx_buf_len = I40EVF_RXBUFFER_2048; else rx_buf_len = ALIGN(max_frame, 1024); for (i = 0; i < adapter->num_active_queues; i++) { adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i); adapter->rx_rings[i].rx_buf_len = rx_buf_len; if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) { set_ring_ps_enabled(&adapter->rx_rings[i]); adapter->rx_rings[i].rx_hdr_len = I40E_RX_HDR_SIZE; } else { clear_ring_ps_enabled(&adapter->rx_rings[i]); } } } /** * i40evf_find_vlan - Search filter list for specific vlan filter * @adapter: board private structure * @vlan: vlan tag * * Returns ptr to the filter object or NULL **/ static struct i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan) { struct i40evf_vlan_filter *f; list_for_each_entry(f, &adapter->vlan_filter_list, list) { if (vlan == f->vlan) return f; } return NULL; } /** * i40evf_add_vlan - Add a vlan filter to the list * @adapter: board private structure * @vlan: VLAN tag * * Returns ptr to the filter object or NULL when no memory available. **/ static struct i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan) { struct i40evf_vlan_filter *f = NULL; int count = 50; while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) { udelay(1); if (--count == 0) goto out; } f = i40evf_find_vlan(adapter, vlan); if (!f) { f = kzalloc(sizeof(*f), GFP_ATOMIC); if (!f) goto clearout; f->vlan = vlan; INIT_LIST_HEAD(&f->list); list_add(&f->list, &adapter->vlan_filter_list); f->add = true; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; } clearout: clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); out: return f; } /** * i40evf_del_vlan - Remove a vlan filter from the list * @adapter: board private structure * @vlan: VLAN tag **/ static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan) { struct i40evf_vlan_filter *f; int count = 50; while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) { udelay(1); if (--count == 0) return; } f = i40evf_find_vlan(adapter, vlan); if (f) { f->remove = true; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; } clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** * i40evf_vlan_rx_add_vid - Add a VLAN filter to a device * @netdev: network device struct * @vid: VLAN tag **/ static int i40evf_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, u16 vid) { struct i40evf_adapter *adapter = netdev_priv(netdev); if (!VLAN_ALLOWED(adapter)) return -EIO; if (i40evf_add_vlan(adapter, vid) == NULL) return -ENOMEM; return 0; } /** * i40evf_vlan_rx_kill_vid - Remove a VLAN filter from a device * @netdev: network device struct * @vid: VLAN tag **/ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, u16 vid) { struct i40evf_adapter *adapter = netdev_priv(netdev); if (VLAN_ALLOWED(adapter)) { i40evf_del_vlan(adapter, vid); return 0; } return -EIO; } /** * i40evf_find_filter - Search filter list for specific mac filter * @adapter: board private structure * @macaddr: the MAC address * * Returns ptr to the filter object or NULL **/ static struct i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter, u8 *macaddr) { struct i40evf_mac_filter *f; if (!macaddr) return NULL; list_for_each_entry(f, &adapter->mac_filter_list, list) { if (ether_addr_equal(macaddr, f->macaddr)) return f; } return NULL; } /** * i40e_add_filter - Add a mac filter to the filter list * @adapter: board private structure * @macaddr: the MAC address * * Returns ptr to the filter object or NULL when no memory available. **/ static struct i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter, u8 *macaddr) { struct i40evf_mac_filter *f; int count = 50; if (!macaddr) return NULL; while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) { udelay(1); if (--count == 0) return NULL; } f = i40evf_find_filter(adapter, macaddr); if (!f) { f = kzalloc(sizeof(*f), GFP_ATOMIC); if (!f) { clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); return NULL; } ether_addr_copy(f->macaddr, macaddr); list_add(&f->list, &adapter->mac_filter_list); f->add = true; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; } clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); return f; } /** * i40evf_set_mac - NDO callback to set port mac address * @netdev: network interface device structure * @p: pointer to an address structure * * Returns 0 on success, negative on failure **/ static int i40evf_set_mac(struct net_device *netdev, void *p) { struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40e_hw *hw = &adapter->hw; struct i40evf_mac_filter *f; struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) return 0; if (adapter->flags & I40EVF_FLAG_ADDR_SET_BY_PF) return -EPERM; f = i40evf_find_filter(adapter, hw->mac.addr); if (f) { f->remove = true; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; } f = i40evf_add_filter(adapter, addr->sa_data); if (f) { ether_addr_copy(hw->mac.addr, addr->sa_data); ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); } return (f == NULL) ? -ENOMEM : 0; } /** * i40evf_set_rx_mode - NDO callback to set the netdev filters * @netdev: network interface device structure **/ static void i40evf_set_rx_mode(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_mac_filter *f, *ftmp; struct netdev_hw_addr *uca; struct netdev_hw_addr *mca; struct netdev_hw_addr *ha; int count = 50; /* add addr if not already in the filter list */ netdev_for_each_uc_addr(uca, netdev) { i40evf_add_filter(adapter, uca->addr); } netdev_for_each_mc_addr(mca, netdev) { i40evf_add_filter(adapter, mca->addr); } while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) { udelay(1); if (--count == 0) { dev_err(&adapter->pdev->dev, "Failed to get lock in %s\n", __func__); return; } } /* remove filter if not in netdev list */ list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { netdev_for_each_mc_addr(mca, netdev) if (ether_addr_equal(mca->addr, f->macaddr)) goto bottom_of_search_loop; netdev_for_each_uc_addr(uca, netdev) if (ether_addr_equal(uca->addr, f->macaddr)) goto bottom_of_search_loop; for_each_dev_addr(netdev, ha) if (ether_addr_equal(ha->addr, f->macaddr)) goto bottom_of_search_loop; if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) goto bottom_of_search_loop; /* f->macaddr wasn't found in uc, mc, or ha list so delete it */ f->remove = true; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; bottom_of_search_loop: continue; } clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** * i40evf_napi_enable_all - enable NAPI on all queue vectors * @adapter: board private structure **/ static void i40evf_napi_enable_all(struct i40evf_adapter *adapter) { int q_idx; struct i40e_q_vector *q_vector; int q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (q_idx = 0; q_idx < q_vectors; q_idx++) { struct napi_struct *napi; q_vector = &adapter->q_vectors[q_idx]; napi = &q_vector->napi; napi_enable(napi); } } /** * i40evf_napi_disable_all - disable NAPI on all queue vectors * @adapter: board private structure **/ static void i40evf_napi_disable_all(struct i40evf_adapter *adapter) { int q_idx; struct i40e_q_vector *q_vector; int q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (q_idx = 0; q_idx < q_vectors; q_idx++) { q_vector = &adapter->q_vectors[q_idx]; napi_disable(&q_vector->napi); } } /** * i40evf_configure - set up transmit and receive data structures * @adapter: board private structure **/ static void i40evf_configure(struct i40evf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int i; i40evf_set_rx_mode(netdev); i40evf_configure_tx(adapter); i40evf_configure_rx(adapter); adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES; for (i = 0; i < adapter->num_active_queues; i++) { struct i40e_ring *ring = &adapter->rx_rings[i]; if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) { i40evf_alloc_rx_headers(ring); i40evf_alloc_rx_buffers_ps(ring, ring->count); } else { i40evf_alloc_rx_buffers_1buf(ring, ring->count); } ring->next_to_use = ring->count - 1; writel(ring->next_to_use, ring->tail); } } /** * i40evf_up_complete - Finish the last steps of bringing up a connection * @adapter: board private structure **/ static int i40evf_up_complete(struct i40evf_adapter *adapter) { adapter->state = __I40EVF_RUNNING; clear_bit(__I40E_DOWN, &adapter->vsi.state); i40evf_napi_enable_all(adapter); adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_QUEUES; mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); return 0; } /** * i40e_down - Shutdown the connection processing * @adapter: board private structure **/ void i40evf_down(struct i40evf_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct i40evf_mac_filter *f; if (adapter->state <= __I40EVF_DOWN_PENDING) return; while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) usleep_range(500, 1000); netif_carrier_off(netdev); netif_tx_disable(netdev); i40evf_napi_disable_all(adapter); i40evf_irq_disable(adapter); /* remove all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->remove = true; } /* remove all VLAN filters */ list_for_each_entry(f, &adapter->vlan_filter_list, list) { f->remove = true; } if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && adapter->state != __I40EVF_RESETTING) { /* cancel any current operation */ adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; /* Schedule operations to close down the HW. Don't wait * here for this to complete. The watchdog is still running * and it will take care of this. */ adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; } clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** * i40evf_acquire_msix_vectors - Setup the MSIX capability * @adapter: board private structure * @vectors: number of vectors to request * * Work with the OS to set up the MSIX vectors needed. * * Returns 0 on success, negative on failure **/ static int i40evf_acquire_msix_vectors(struct i40evf_adapter *adapter, int vectors) { int err, vector_threshold; /* We'll want at least 3 (vector_threshold): * 0) Other (Admin Queue and link, mostly) * 1) TxQ[0] Cleanup * 2) RxQ[0] Cleanup */ vector_threshold = MIN_MSIX_COUNT; /* The more we get, the more we will assign to Tx/Rx Cleanup * for the separate queues...where Rx Cleanup >= Tx Cleanup. * Right now, we simply care about how many we'll get; we'll * set them up later while requesting irq's. */ err = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, vector_threshold, vectors); if (err < 0) { dev_err(&adapter->pdev->dev, "Unable to allocate MSI-X interrupts\n"); kfree(adapter->msix_entries); adapter->msix_entries = NULL; return err; } /* Adjust for only the vectors we'll use, which is minimum * of max_msix_q_vectors + NONQ_VECS, or the number of * vectors we were allocated. */ adapter->num_msix_vectors = err; return 0; } /** * i40evf_free_queues - Free memory for all rings * @adapter: board private structure to initialize * * Free all of the memory associated with queue pairs. **/ static void i40evf_free_queues(struct i40evf_adapter *adapter) { if (!adapter->vsi_res) return; kfree(adapter->tx_rings); adapter->tx_rings = NULL; kfree(adapter->rx_rings); adapter->rx_rings = NULL; } /** * i40evf_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize * * We allocate one ring per queue at run-time since we don't know the * number of queues at compile-time. The polling_netdev array is * intended for Multiqueue, but should work fine with a single queue. **/ static int i40evf_alloc_queues(struct i40evf_adapter *adapter) { int i; adapter->tx_rings = kcalloc(adapter->num_active_queues, sizeof(struct i40e_ring), GFP_KERNEL); if (!adapter->tx_rings) goto err_out; adapter->rx_rings = kcalloc(adapter->num_active_queues, sizeof(struct i40e_ring), GFP_KERNEL); if (!adapter->rx_rings) goto err_out; for (i = 0; i < adapter->num_active_queues; i++) { struct i40e_ring *tx_ring; struct i40e_ring *rx_ring; tx_ring = &adapter->tx_rings[i]; tx_ring->queue_index = i; tx_ring->netdev = adapter->netdev; tx_ring->dev = &adapter->pdev->dev; tx_ring->count = adapter->tx_desc_count; if (adapter->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) tx_ring->flags |= I40E_TXR_FLAGS_WB_ON_ITR; rx_ring = &adapter->rx_rings[i]; rx_ring->queue_index = i; rx_ring->netdev = adapter->netdev; rx_ring->dev = &adapter->pdev->dev; rx_ring->count = adapter->rx_desc_count; } return 0; err_out: i40evf_free_queues(adapter); return -ENOMEM; } /** * i40evf_set_interrupt_capability - set MSI-X or FAIL if not supported * @adapter: board private structure to initialize * * Attempt to configure the interrupts using the best available * capabilities of the hardware and the kernel. **/ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter) { int vector, v_budget; int pairs = 0; int err = 0; if (!adapter->vsi_res) { err = -EIO; goto out; } pairs = adapter->num_active_queues; /* It's easy to be greedy for MSI-X vectors, but it really * doesn't do us much good if we have a lot more vectors * than CPU's. So let's be conservative and only ask for * (roughly) twice the number of vectors as there are CPU's. */ v_budget = min_t(int, pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS; v_budget = min_t(int, v_budget, (int)adapter->vf_res->max_vectors); adapter->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); if (!adapter->msix_entries) { err = -ENOMEM; goto out; } for (vector = 0; vector < v_budget; vector++) adapter->msix_entries[vector].entry = vector; err = i40evf_acquire_msix_vectors(adapter, v_budget); out: netif_set_real_num_rx_queues(adapter->netdev, pairs); netif_set_real_num_tx_queues(adapter->netdev, pairs); return err; } /** * i40e_config_rss_aq - Prepare for RSS using AQ commands * @vsi: vsi structure * @seed: RSS hash seed * @lut: Lookup table * @lut_size: Lookup table size * * Return 0 on success, negative on failure **/ static int i40evf_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed, u8 *lut, u16 lut_size) { struct i40evf_adapter *adapter = vsi->back; struct i40e_hw *hw = &adapter->hw; int ret = 0; if (!vsi->id) return -EINVAL; if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot configure RSS, command %d pending\n", adapter->current_op); return -EBUSY; } if (seed) { struct i40e_aqc_get_set_rss_key_data *rss_key = (struct i40e_aqc_get_set_rss_key_data *)seed; ret = i40evf_aq_set_rss_key(hw, vsi->id, rss_key); if (ret) { dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n", i40evf_stat_str(hw, ret), i40evf_aq_str(hw, hw->aq.asq_last_status)); return ret; } } if (lut) { ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, lut, lut_size); if (ret) { dev_err(&adapter->pdev->dev, "Cannot set RSS lut, err %s aq_err %s\n", i40evf_stat_str(hw, ret), i40evf_aq_str(hw, hw->aq.asq_last_status)); return ret; } } return ret; } /** * i40evf_config_rss_reg - Configure RSS keys and lut by writing registers * @vsi: Pointer to vsi structure * @seed: RSS hash seed * @lut: Lookup table * @lut_size: Lookup table size * * Returns 0 on success, negative on failure **/ static int i40evf_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed, const u8 *lut, u16 lut_size) { struct i40evf_adapter *adapter = vsi->back; struct i40e_hw *hw = &adapter->hw; u16 i; if (seed) { u32 *seed_dw = (u32 *)seed; for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]); } if (lut) { u32 *lut_dw = (u32 *)lut; if (lut_size != I40EVF_HLUT_ARRAY_SIZE) return -EINVAL; for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) wr32(hw, I40E_VFQF_HLUT(i), lut_dw[i]); } i40e_flush(hw); return 0; } /** * * i40evf_get_rss_aq - Get RSS keys and lut by using AQ commands * @vsi: Pointer to vsi structure * @seed: RSS hash seed * @lut: Lookup table * @lut_size: Lookup table size * * Return 0 on success, negative on failure **/ static int i40evf_get_rss_aq(struct i40e_vsi *vsi, const u8 *seed, u8 *lut, u16 lut_size) { struct i40evf_adapter *adapter = vsi->back; struct i40e_hw *hw = &adapter->hw; int ret = 0; if (seed) { ret = i40evf_aq_get_rss_key(hw, vsi->id, (struct i40e_aqc_get_set_rss_key_data *)seed); if (ret) { dev_err(&adapter->pdev->dev, "Cannot get RSS key, err %s aq_err %s\n", i40evf_stat_str(hw, ret), i40evf_aq_str(hw, hw->aq.asq_last_status)); return ret; } } if (lut) { ret = i40evf_aq_get_rss_lut(hw, vsi->id, false, lut, lut_size); if (ret) { dev_err(&adapter->pdev->dev, "Cannot get RSS lut, err %s aq_err %s\n", i40evf_stat_str(hw, ret), i40evf_aq_str(hw, hw->aq.asq_last_status)); return ret; } } return ret; } /** * * i40evf_get_rss_reg - Get RSS keys and lut by reading registers * @vsi: Pointer to vsi structure * @seed: RSS hash seed * @lut: Lookup table * @lut_size: Lookup table size * * Returns 0 on success, negative on failure **/ static int i40evf_get_rss_reg(struct i40e_vsi *vsi, const u8 *seed, const u8 *lut, u16 lut_size) { struct i40evf_adapter *adapter = vsi->back; struct i40e_hw *hw = &adapter->hw; u16 i; if (seed) { u32 *seed_dw = (u32 *)seed; for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) seed_dw[i] = rd32(hw, I40E_VFQF_HKEY(i)); } if (lut) { u32 *lut_dw = (u32 *)lut; if (lut_size != I40EVF_HLUT_ARRAY_SIZE) return -EINVAL; for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) lut_dw[i] = rd32(hw, I40E_VFQF_HLUT(i)); } return 0; } /** * i40evf_config_rss - Configure RSS keys and lut * @vsi: Pointer to vsi structure * @seed: RSS hash seed * @lut: Lookup table * @lut_size: Lookup table size * * Returns 0 on success, negative on failure **/ int i40evf_config_rss(struct i40e_vsi *vsi, const u8 *seed, u8 *lut, u16 lut_size) { struct i40evf_adapter *adapter = vsi->back; if (RSS_AQ(adapter)) return i40evf_config_rss_aq(vsi, seed, lut, lut_size); else return i40evf_config_rss_reg(vsi, seed, lut, lut_size); } /** * i40evf_get_rss - Get RSS keys and lut * @vsi: Pointer to vsi structure * @seed: RSS hash seed * @lut: Lookup table * @lut_size: Lookup table size * * Returns 0 on success, negative on failure **/ int i40evf_get_rss(struct i40e_vsi *vsi, const u8 *seed, u8 *lut, u16 lut_size) { struct i40evf_adapter *adapter = vsi->back; if (RSS_AQ(adapter)) return i40evf_get_rss_aq(vsi, seed, lut, lut_size); else return i40evf_get_rss_reg(vsi, seed, lut, lut_size); } /** * i40evf_fill_rss_lut - Fill the lut with default values * @lut: Lookup table to be filled with * @rss_table_size: Lookup table size * @rss_size: Range of queue number for hashing **/ static void i40evf_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size) { u16 i; for (i = 0; i < rss_table_size; i++) lut[i] = i % rss_size; } /** * i40evf_init_rss - Prepare for RSS * @adapter: board private structure * * Return 0 on success, negative on failure **/ static int i40evf_init_rss(struct i40evf_adapter *adapter) { struct i40e_vsi *vsi = &adapter->vsi; struct i40e_hw *hw = &adapter->hw; u8 seed[I40EVF_HKEY_ARRAY_SIZE]; u64 hena; u8 *lut; int ret; /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ if (adapter->vf_res->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) hena = I40E_DEFAULT_RSS_HENA_EXPANDED; else hena = I40E_DEFAULT_RSS_HENA; wr32(hw, I40E_VFQF_HENA(0), (u32)hena); wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); lut = kzalloc(I40EVF_HLUT_ARRAY_SIZE, GFP_KERNEL); if (!lut) return -ENOMEM; /* Use user configured lut if there is one, otherwise use default */ if (vsi->rss_lut_user) memcpy(lut, vsi->rss_lut_user, I40EVF_HLUT_ARRAY_SIZE); else i40evf_fill_rss_lut(lut, I40EVF_HLUT_ARRAY_SIZE, adapter->num_active_queues); /* Use user configured hash key if there is one, otherwise * user default. */ if (vsi->rss_hkey_user) memcpy(seed, vsi->rss_hkey_user, I40EVF_HKEY_ARRAY_SIZE); else netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE); ret = i40evf_config_rss(vsi, seed, lut, I40EVF_HLUT_ARRAY_SIZE); kfree(lut); return ret; } /** * i40evf_alloc_q_vectors - Allocate memory for interrupt vectors * @adapter: board private structure to initialize * * We allocate one q_vector per queue interrupt. If allocation fails we * return -ENOMEM. **/ static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter) { int q_idx = 0, num_q_vectors; struct i40e_q_vector *q_vector; num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; adapter->q_vectors = kcalloc(num_q_vectors, sizeof(*q_vector), GFP_KERNEL); if (!adapter->q_vectors) return -ENOMEM; for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { q_vector = &adapter->q_vectors[q_idx]; q_vector->adapter = adapter; q_vector->vsi = &adapter->vsi; q_vector->v_idx = q_idx; netif_napi_add(adapter->netdev, &q_vector->napi, i40evf_napi_poll, NAPI_POLL_WEIGHT); } return 0; } /** * i40evf_free_q_vectors - Free memory allocated for interrupt vectors * @adapter: board private structure to initialize * * This function frees the memory allocated to the q_vectors. In addition if * NAPI is enabled it will delete any references to the NAPI struct prior * to freeing the q_vector. **/ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter) { int q_idx, num_q_vectors; int napi_vectors; num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; napi_vectors = adapter->num_active_queues; for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { struct i40e_q_vector *q_vector = &adapter->q_vectors[q_idx]; if (q_idx < napi_vectors) netif_napi_del(&q_vector->napi); } kfree(adapter->q_vectors); } /** * i40evf_reset_interrupt_capability - Reset MSIX setup * @adapter: board private structure * **/ void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter) { pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); adapter->msix_entries = NULL; } /** * i40evf_init_interrupt_scheme - Determine if MSIX is supported and init * @adapter: board private structure to initialize * **/ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter) { int err; err = i40evf_set_interrupt_capability(adapter); if (err) { dev_err(&adapter->pdev->dev, "Unable to setup interrupt capabilities\n"); goto err_set_interrupt; } err = i40evf_alloc_q_vectors(adapter); if (err) { dev_err(&adapter->pdev->dev, "Unable to allocate memory for queue vectors\n"); goto err_alloc_q_vectors; } err = i40evf_alloc_queues(adapter); if (err) { dev_err(&adapter->pdev->dev, "Unable to allocate memory for queues\n"); goto err_alloc_queues; } dev_info(&adapter->pdev->dev, "Multiqueue %s: Queue pair count = %u", (adapter->num_active_queues > 1) ? "Enabled" : "Disabled", adapter->num_active_queues); return 0; err_alloc_queues: i40evf_free_q_vectors(adapter); err_alloc_q_vectors: i40evf_reset_interrupt_capability(adapter); err_set_interrupt: return err; } /** * i40evf_clear_rss_config_user - Clear user configurations of RSS * @vsi: Pointer to VSI structure **/ static void i40evf_clear_rss_config_user(struct i40e_vsi *vsi) { if (!vsi) return; kfree(vsi->rss_hkey_user); vsi->rss_hkey_user = NULL; kfree(vsi->rss_lut_user); vsi->rss_lut_user = NULL; } /** * i40evf_watchdog_timer - Periodic call-back timer * @data: pointer to adapter disguised as unsigned long **/ static void i40evf_watchdog_timer(unsigned long data) { struct i40evf_adapter *adapter = (struct i40evf_adapter *)data; schedule_work(&adapter->watchdog_task); /* timer will be rescheduled in watchdog task */ } /** * i40evf_watchdog_task - Periodic call-back task * @work: pointer to work_struct **/ static void i40evf_watchdog_task(struct work_struct *work) { struct i40evf_adapter *adapter = container_of(work, struct i40evf_adapter, watchdog_task); struct i40e_hw *hw = &adapter->hw; u32 reg_val; if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) goto restart_watchdog; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; if ((reg_val == I40E_VFR_VFACTIVE) || (reg_val == I40E_VFR_COMPLETED)) { /* A chance for redemption! */ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); adapter->state = __I40EVF_STARTUP; adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; schedule_delayed_work(&adapter->init_task, 10); clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); /* Don't reschedule the watchdog, since we've restarted * the init task. When init_task contacts the PF and * gets everything set up again, it'll restart the * watchdog for us. Down, boy. Sit. Stay. Woof. */ return; } adapter->aq_required = 0; adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } if ((adapter->state < __I40EVF_DOWN) || (adapter->flags & I40EVF_FLAG_RESET_PENDING)) goto watchdog_done; /* check for reset */ reg_val = rd32(hw, I40E_VF_ARQLEN1) & I40E_VF_ARQLEN1_ARQENABLE_MASK; if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) && !reg_val) { adapter->state = __I40EVF_RESETTING; adapter->flags |= I40EVF_FLAG_RESET_PENDING; dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); schedule_work(&adapter->reset_task); adapter->aq_required = 0; adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } /* Process admin queue tasks. After init, everything gets done * here so we don't race on the admin queue. */ if (adapter->current_op) { if (!i40evf_asq_done(hw)) { dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n"); i40evf_send_api_ver(adapter); } goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_GET_CONFIG) { i40evf_send_vf_config_msg(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) { i40evf_disable_queues(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) { i40evf_map_queues(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_MAC_FILTER) { i40evf_add_ether_addrs(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_VLAN_FILTER) { i40evf_add_vlans(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_MAC_FILTER) { i40evf_del_ether_addrs(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_VLAN_FILTER) { i40evf_del_vlans(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_QUEUES) { i40evf_configure_queues(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_QUEUES) { i40evf_enable_queues(adapter); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_RSS) { /* This message goes straight to the firmware, not the * PF, so we don't have to set current_op as we will * not get a response through the ARQ. */ i40evf_init_rss(adapter); adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_RSS; goto watchdog_done; } if (adapter->state == __I40EVF_RUNNING) i40evf_request_stats(adapter); watchdog_done: if (adapter->state == __I40EVF_RUNNING) { i40evf_irq_enable_queues(adapter, ~0); i40evf_fire_sw_int(adapter, 0xFF); } else { i40evf_fire_sw_int(adapter, 0x1); } clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); restart_watchdog: if (adapter->state == __I40EVF_REMOVE) return; if (adapter->aq_required) mod_timer(&adapter->watchdog_timer, jiffies + msecs_to_jiffies(20)); else mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2)); schedule_work(&adapter->adminq_task); } #define I40EVF_RESET_WAIT_MS 10 #define I40EVF_RESET_WAIT_COUNT 500 /** * i40evf_reset_task - Call-back task to handle hardware reset * @work: pointer to work_struct * * During reset we need to shut down and reinitialize the admin queue * before we can use it to communicate with the PF again. We also clear * and reinit the rings because that context is lost as well. **/ static void i40evf_reset_task(struct work_struct *work) { struct i40evf_adapter *adapter = container_of(work, struct i40evf_adapter, reset_task); struct net_device *netdev = adapter->netdev; struct i40e_hw *hw = &adapter->hw; struct i40evf_vlan_filter *vlf; struct i40evf_mac_filter *f; u32 reg_val; int i = 0, err; while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) usleep_range(500, 1000); i40evf_misc_irq_disable(adapter); if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) { adapter->flags &= ~I40EVF_FLAG_RESET_NEEDED; /* Restart the AQ here. If we have been reset but didn't * detect it, or if the PF had to reinit, our AQ will be hosed. */ i40evf_shutdown_adminq(hw); i40evf_init_adminq(hw); i40evf_request_reset(adapter); } adapter->flags |= I40EVF_FLAG_RESET_PENDING; /* poll until we see the reset actually happen */ for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { reg_val = rd32(hw, I40E_VF_ARQLEN1) & I40E_VF_ARQLEN1_ARQENABLE_MASK; if (!reg_val) break; usleep_range(5000, 10000); } if (i == I40EVF_RESET_WAIT_COUNT) { dev_info(&adapter->pdev->dev, "Never saw reset\n"); goto continue_reset; /* act like the reset happened */ } /* wait until the reset is complete and the PF is responding to us */ for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; if (reg_val == I40E_VFR_VFACTIVE) break; msleep(I40EVF_RESET_WAIT_MS); } pci_set_master(adapter->pdev); /* extra wait to make sure minimum wait is met */ msleep(I40EVF_RESET_WAIT_MS); if (i == I40EVF_RESET_WAIT_COUNT) { struct i40evf_mac_filter *ftmp; struct i40evf_vlan_filter *fv, *fvtmp; /* reset never finished */ dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", reg_val); adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; if (netif_running(adapter->netdev)) { set_bit(__I40E_DOWN, &adapter->vsi.state); netif_carrier_off(netdev); netif_tx_disable(netdev); i40evf_napi_disable_all(adapter); i40evf_irq_disable(adapter); i40evf_free_traffic_irqs(adapter); i40evf_free_all_tx_resources(adapter); i40evf_free_all_rx_resources(adapter); } /* Delete all of the filters, both MAC and VLAN. */ list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { list_del(&f->list); kfree(f); } list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list, list) { list_del(&fv->list); kfree(fv); } i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); i40evf_free_queues(adapter); i40evf_free_q_vectors(adapter); kfree(adapter->vf_res); i40evf_shutdown_adminq(hw); adapter->netdev->flags &= ~IFF_UP; clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; adapter->state = __I40EVF_DOWN; dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n"); return; /* Do not attempt to reinit. It's dead, Jim. */ } continue_reset: if (netif_running(adapter->netdev)) { netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); i40evf_napi_disable_all(adapter); } i40evf_irq_disable(adapter); adapter->state = __I40EVF_RESETTING; adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; /* free the Tx/Rx rings and descriptors, might be better to just * re-use them sometime in the future */ i40evf_free_all_rx_resources(adapter); i40evf_free_all_tx_resources(adapter); /* kill and reinit the admin queue */ if (i40evf_shutdown_adminq(hw)) dev_warn(&adapter->pdev->dev, "Failed to shut down adminq\n"); adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; err = i40evf_init_adminq(hw); if (err) dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", err); adapter->aq_required = I40EVF_FLAG_AQ_GET_CONFIG; adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS; /* re-add all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->add = true; } /* re-add all VLAN filters */ list_for_each_entry(vlf, &adapter->vlan_filter_list, list) { vlf->add = true; } adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); i40evf_misc_irq_enable(adapter); mod_timer(&adapter->watchdog_timer, jiffies + 2); if (netif_running(adapter->netdev)) { /* allocate transmit descriptors */ err = i40evf_setup_all_tx_resources(adapter); if (err) goto reset_err; /* allocate receive descriptors */ err = i40evf_setup_all_rx_resources(adapter); if (err) goto reset_err; i40evf_configure(adapter); err = i40evf_up_complete(adapter); if (err) goto reset_err; i40evf_irq_enable(adapter, true); } else { adapter->state = __I40EVF_DOWN; } return; reset_err: dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); i40evf_close(adapter->netdev); } /** * i40evf_adminq_task - worker thread to clean the admin queue * @work: pointer to work_struct containing our data **/ static void i40evf_adminq_task(struct work_struct *work) { struct i40evf_adapter *adapter = container_of(work, struct i40evf_adapter, adminq_task); struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; struct i40e_virtchnl_msg *v_msg; i40e_status ret; u32 val, oldval; u16 pending; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) goto out; event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) goto out; v_msg = (struct i40e_virtchnl_msg *)&event.desc; do { ret = i40evf_clean_arq_element(hw, &event, &pending); if (ret || !v_msg->v_opcode) break; /* No event to process or error cleaning ARQ */ i40evf_virtchnl_completion(adapter, v_msg->v_opcode, v_msg->v_retval, event.msg_buf, event.msg_len); if (pending != 0) memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE); } while (pending); if ((adapter->flags & (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED)) || adapter->state == __I40EVF_RESETTING) goto freedom; /* check for error indications */ val = rd32(hw, hw->aq.arq.len); if (val == 0xdeadbeef) /* indicates device in reset */ goto freedom; oldval = val; if (val & I40E_VF_ARQLEN1_ARQVFE_MASK) { dev_info(&adapter->pdev->dev, "ARQ VF Error detected\n"); val &= ~I40E_VF_ARQLEN1_ARQVFE_MASK; } if (val & I40E_VF_ARQLEN1_ARQOVFL_MASK) { dev_info(&adapter->pdev->dev, "ARQ Overflow Error detected\n"); val &= ~I40E_VF_ARQLEN1_ARQOVFL_MASK; } if (val & I40E_VF_ARQLEN1_ARQCRIT_MASK) { dev_info(&adapter->pdev->dev, "ARQ Critical Error detected\n"); val &= ~I40E_VF_ARQLEN1_ARQCRIT_MASK; } if (oldval != val) wr32(hw, hw->aq.arq.len, val); val = rd32(hw, hw->aq.asq.len); oldval = val; if (val & I40E_VF_ATQLEN1_ATQVFE_MASK) { dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n"); val &= ~I40E_VF_ATQLEN1_ATQVFE_MASK; } if (val & I40E_VF_ATQLEN1_ATQOVFL_MASK) { dev_info(&adapter->pdev->dev, "ASQ Overflow Error detected\n"); val &= ~I40E_VF_ATQLEN1_ATQOVFL_MASK; } if (val & I40E_VF_ATQLEN1_ATQCRIT_MASK) { dev_info(&adapter->pdev->dev, "ASQ Critical Error detected\n"); val &= ~I40E_VF_ATQLEN1_ATQCRIT_MASK; } if (oldval != val) wr32(hw, hw->aq.asq.len, val); freedom: kfree(event.msg_buf); out: /* re-enable Admin queue interrupt cause */ i40evf_misc_irq_enable(adapter); } /** * i40evf_free_all_tx_resources - Free Tx Resources for All Queues * @adapter: board private structure * * Free all transmit software resources **/ void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter) { int i; if (!adapter->tx_rings) return; for (i = 0; i < adapter->num_active_queues; i++) if (adapter->tx_rings[i].desc) i40evf_free_tx_resources(&adapter->tx_rings[i]); } /** * i40evf_setup_all_tx_resources - allocate all queues Tx resources * @adapter: board private structure * * If this function returns with an error, then it's possible one or * more of the rings is populated (while the rest are not). It is the * callers duty to clean those orphaned rings. * * Return 0 on success, negative on failure **/ static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter) { int i, err = 0; for (i = 0; i < adapter->num_active_queues; i++) { adapter->tx_rings[i].count = adapter->tx_desc_count; err = i40evf_setup_tx_descriptors(&adapter->tx_rings[i]); if (!err) continue; dev_err(&adapter->pdev->dev, "Allocation for Tx Queue %u failed\n", i); break; } return err; } /** * i40evf_setup_all_rx_resources - allocate all queues Rx resources * @adapter: board private structure * * If this function returns with an error, then it's possible one or * more of the rings is populated (while the rest are not). It is the * callers duty to clean those orphaned rings. * * Return 0 on success, negative on failure **/ static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter) { int i, err = 0; for (i = 0; i < adapter->num_active_queues; i++) { adapter->rx_rings[i].count = adapter->rx_desc_count; err = i40evf_setup_rx_descriptors(&adapter->rx_rings[i]); if (!err) continue; dev_err(&adapter->pdev->dev, "Allocation for Rx Queue %u failed\n", i); break; } return err; } /** * i40evf_free_all_rx_resources - Free Rx Resources for All Queues * @adapter: board private structure * * Free all receive software resources **/ void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter) { int i; if (!adapter->rx_rings) return; for (i = 0; i < adapter->num_active_queues; i++) if (adapter->rx_rings[i].desc) i40evf_free_rx_resources(&adapter->rx_rings[i]); } /** * i40evf_open - Called when a network interface is made active * @netdev: network interface device structure * * Returns 0 on success, negative value on failure * * The open entry point is called when a network interface is made * active by the system (IFF_UP). At this point all resources needed * for transmit and receive operations are allocated, the interrupt * handler is registered with the OS, the watchdog timer is started, * and the stack is notified that the interface is ready. **/ static int i40evf_open(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); int err; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n"); return -EIO; } if (adapter->state != __I40EVF_DOWN) return -EBUSY; /* allocate transmit descriptors */ err = i40evf_setup_all_tx_resources(adapter); if (err) goto err_setup_tx; /* allocate receive descriptors */ err = i40evf_setup_all_rx_resources(adapter); if (err) goto err_setup_rx; /* clear any pending interrupts, may auto mask */ err = i40evf_request_traffic_irqs(adapter, netdev->name); if (err) goto err_req_irq; i40evf_add_filter(adapter, adapter->hw.mac.addr); i40evf_configure(adapter); err = i40evf_up_complete(adapter); if (err) goto err_req_irq; i40evf_irq_enable(adapter, true); return 0; err_req_irq: i40evf_down(adapter); i40evf_free_traffic_irqs(adapter); err_setup_rx: i40evf_free_all_rx_resources(adapter); err_setup_tx: i40evf_free_all_tx_resources(adapter); return err; } /** * i40evf_close - Disables a network interface * @netdev: network interface device structure * * Returns 0, this is not allowed to fail * * The close entry point is called when an interface is de-activated * by the OS. The hardware is still under the drivers control, but * needs to be disabled. All IRQs except vector 0 (reserved for admin queue) * are freed, along with all transmit and receive resources. **/ static int i40evf_close(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); if (adapter->state <= __I40EVF_DOWN_PENDING) return 0; set_bit(__I40E_DOWN, &adapter->vsi.state); i40evf_down(adapter); adapter->state = __I40EVF_DOWN_PENDING; i40evf_free_traffic_irqs(adapter); return 0; } /** * i40evf_get_stats - Get System Network Statistics * @netdev: network interface device structure * * Returns the address of the device statistics structure. * The statistics are actually updated from the timer callback. **/ static struct net_device_stats *i40evf_get_stats(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); /* only return the current stats */ return &adapter->net_stats; } /** * i40evf_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size * * Returns 0 on success, negative on failure **/ static int i40evf_change_mtu(struct net_device *netdev, int new_mtu) { struct i40evf_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; if ((new_mtu < 68) || (max_frame > I40E_MAX_RXBUFFER)) return -EINVAL; netdev->mtu = new_mtu; adapter->flags |= I40EVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); return 0; } #define I40EVF_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_TX |\ NETIF_F_HW_VLAN_CTAG_RX |\ NETIF_F_HW_VLAN_CTAG_FILTER) /** * i40evf_fix_features - fix up the netdev feature bits * @netdev: our net device * @features: desired feature bits * * Returns fixed-up features bits **/ static netdev_features_t i40evf_fix_features(struct net_device *netdev, netdev_features_t features) { struct i40evf_adapter *adapter = netdev_priv(netdev); features &= ~I40EVF_VLAN_FEATURES; if (adapter->vf_res->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) features |= I40EVF_VLAN_FEATURES; return features; } static const struct net_device_ops i40evf_netdev_ops = { .ndo_open = i40evf_open, .ndo_stop = i40evf_close, .ndo_start_xmit = i40evf_xmit_frame, .ndo_get_stats = i40evf_get_stats, .ndo_set_rx_mode = i40evf_set_rx_mode, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = i40evf_set_mac, .ndo_change_mtu = i40evf_change_mtu, .ndo_tx_timeout = i40evf_tx_timeout, .ndo_vlan_rx_add_vid = i40evf_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = i40evf_vlan_rx_kill_vid, .ndo_fix_features = i40evf_fix_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = i40evf_netpoll, #endif }; /** * i40evf_check_reset_complete - check that VF reset is complete * @hw: pointer to hw struct * * Returns 0 if device is ready to use, or -EBUSY if it's in reset. **/ static int i40evf_check_reset_complete(struct i40e_hw *hw) { u32 rstat; int i; for (i = 0; i < 100; i++) { rstat = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; if ((rstat == I40E_VFR_VFACTIVE) || (rstat == I40E_VFR_COMPLETED)) return 0; usleep_range(10, 20); } return -EBUSY; } /** * i40evf_process_config - Process the config information we got from the PF * @adapter: board private structure * * Verify that we have a valid config struct, and set up our netdev features * and our VSI struct. **/ int i40evf_process_config(struct i40evf_adapter *adapter) { struct i40e_virtchnl_vf_resource *vfres = adapter->vf_res; struct net_device *netdev = adapter->netdev; int i; /* got VF config message back from PF, now we can parse it */ for (i = 0; i < vfres->num_vsis; i++) { if (vfres->vsi_res[i].vsi_type == I40E_VSI_SRIOV) adapter->vsi_res = &vfres->vsi_res[i]; } if (!adapter->vsi_res) { dev_err(&adapter->pdev->dev, "No LAN VSI found\n"); return -ENODEV; } netdev->hw_enc_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA | NETIF_F_SOFT_FEATURES | NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_IPIP | NETIF_F_GSO_SIT | NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC | NETIF_F_RXHASH | NETIF_F_RXCSUM | 0; if (!(adapter->flags & I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE)) netdev->hw_enc_features ^= NETIF_F_GSO_UDP_TUNNEL_CSUM; /* record features VLANs can make use of */ netdev->vlan_features |= netdev->hw_enc_features; /* Write features and hw_features separately to avoid polluting * with, or dropping, features that are set when we registgered. */ netdev->hw_features |= netdev->hw_enc_features; netdev->features |= netdev->hw_enc_features | I40EVF_VLAN_FEATURES; /* disable VLAN features if not supported */ if (!(vfres->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_VLAN)) netdev->features ^= I40EVF_VLAN_FEATURES; adapter->vsi.id = adapter->vsi_res->vsi_id; adapter->vsi.back = adapter; adapter->vsi.base_vector = 1; adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; adapter->vsi.rx_itr_setting = (I40E_ITR_DYNAMIC | ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); adapter->vsi.tx_itr_setting = (I40E_ITR_DYNAMIC | ITR_REG_TO_USEC(I40E_ITR_TX_DEF)); adapter->vsi.netdev = adapter->netdev; adapter->vsi.qs_handle = adapter->vsi_res->qset_handle; return 0; } /** * i40evf_init_task - worker thread to perform delayed initialization * @work: pointer to work_struct containing our data * * This task completes the work that was begun in probe. Due to the nature * of VF-PF communications, we may need to wait tens of milliseconds to get * responses back from the PF. Rather than busy-wait in probe and bog down the * whole system, we'll do it in a task so we can sleep. * This task only runs during driver init. Once we've established * communications with the PF driver and set up our netdev, the watchdog * takes over. **/ static void i40evf_init_task(struct work_struct *work) { struct i40evf_adapter *adapter = container_of(work, struct i40evf_adapter, init_task.work); struct net_device *netdev = adapter->netdev; struct i40e_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; int err, bufsz; switch (adapter->state) { case __I40EVF_STARTUP: /* driver loaded, probe complete */ adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; err = i40e_set_mac_type(hw); if (err) { dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", err); goto err; } err = i40evf_check_reset_complete(hw); if (err) { dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n", err); goto err; } hw->aq.num_arq_entries = I40EVF_AQ_LEN; hw->aq.num_asq_entries = I40EVF_AQ_LEN; hw->aq.arq_buf_size = I40EVF_MAX_AQ_BUF_SIZE; hw->aq.asq_buf_size = I40EVF_MAX_AQ_BUF_SIZE; err = i40evf_init_adminq(hw); if (err) { dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n", err); goto err; } err = i40evf_send_api_ver(adapter); if (err) { dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err); i40evf_shutdown_adminq(hw); goto err; } adapter->state = __I40EVF_INIT_VERSION_CHECK; goto restart; case __I40EVF_INIT_VERSION_CHECK: if (!i40evf_asq_done(hw)) { dev_err(&pdev->dev, "Admin queue command never completed\n"); i40evf_shutdown_adminq(hw); adapter->state = __I40EVF_STARTUP; goto err; } /* aq msg sent, awaiting reply */ err = i40evf_verify_api_ver(adapter); if (err) { if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) err = i40evf_send_api_ver(adapter); else dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", adapter->pf_version.major, adapter->pf_version.minor, I40E_VIRTCHNL_VERSION_MAJOR, I40E_VIRTCHNL_VERSION_MINOR); goto err; } err = i40evf_send_vf_config_msg(adapter); if (err) { dev_err(&pdev->dev, "Unable to send config request (%d)\n", err); goto err; } adapter->state = __I40EVF_INIT_GET_RESOURCES; goto restart; case __I40EVF_INIT_GET_RESOURCES: /* aq msg sent, awaiting reply */ if (!adapter->vf_res) { bufsz = sizeof(struct i40e_virtchnl_vf_resource) + (I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource)); adapter->vf_res = kzalloc(bufsz, GFP_KERNEL); if (!adapter->vf_res) goto err; } err = i40evf_get_vf_config(adapter); if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { err = i40evf_send_vf_config_msg(adapter); goto err; } else if (err == I40E_ERR_PARAM) { /* We only get ERR_PARAM if the device is in a very bad * state or if we've been disabled for previous bad * behavior. Either way, we're done now. */ i40evf_shutdown_adminq(hw); dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n"); return; } if (err) { dev_err(&pdev->dev, "Unable to get VF config (%d)\n", err); goto err_alloc; } adapter->state = __I40EVF_INIT_SW; break; default: goto err_alloc; } if (hw->mac.type == I40E_MAC_X722_VF) adapter->flags |= I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE; if (i40evf_process_config(adapter)) goto err_alloc; adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE; adapter->flags |= I40EVF_FLAG_RX_PS_CAPABLE; /* Default to single buffer rx, can be changed through ethtool. */ adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED; netdev->netdev_ops = &i40evf_netdev_ops; i40evf_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; if (!is_valid_ether_addr(adapter->hw.mac.addr)) { dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n", adapter->hw.mac.addr); eth_hw_addr_random(netdev); ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); } else { adapter->flags |= I40EVF_FLAG_ADDR_SET_BY_PF; ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); } init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &i40evf_watchdog_timer; adapter->watchdog_timer.data = (unsigned long)adapter; mod_timer(&adapter->watchdog_timer, jiffies + 1); adapter->num_active_queues = min_t(int, adapter->vsi_res->num_queue_pairs, (int)(num_online_cpus())); adapter->tx_desc_count = I40EVF_DEFAULT_TXD; adapter->rx_desc_count = I40EVF_DEFAULT_RXD; err = i40evf_init_interrupt_scheme(adapter); if (err) goto err_sw_init; i40evf_map_rings_to_vectors(adapter); if (adapter->vf_res->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE; err = i40evf_request_misc_irq(adapter); if (err) goto err_sw_init; netif_carrier_off(netdev); if (!adapter->netdev_registered) { err = register_netdev(netdev); if (err) goto err_register; } adapter->netdev_registered = true; netif_tx_stop_all_queues(netdev); dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr); if (netdev->features & NETIF_F_GRO) dev_info(&pdev->dev, "GRO is enabled\n"); adapter->state = __I40EVF_DOWN; set_bit(__I40E_DOWN, &adapter->vsi.state); i40evf_misc_irq_enable(adapter); if (RSS_AQ(adapter)) { adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS; mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); } else { i40evf_init_rss(adapter); } return; restart: schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(30)); return; err_register: i40evf_free_misc_irq(adapter); err_sw_init: i40evf_reset_interrupt_capability(adapter); err_alloc: kfree(adapter->vf_res); adapter->vf_res = NULL; err: /* Things went into the weeds, so try again later */ if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) { dev_err(&pdev->dev, "Failed to communicate with PF; waiting before retry\n"); adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; i40evf_shutdown_adminq(hw); adapter->state = __I40EVF_STARTUP; schedule_delayed_work(&adapter->init_task, HZ * 5); return; } schedule_delayed_work(&adapter->init_task, HZ); } /** * i40evf_shutdown - Shutdown the device in preparation for a reboot * @pdev: pci device structure **/ static void i40evf_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct i40evf_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); if (netif_running(netdev)) i40evf_close(netdev); /* Prevent the watchdog from running. */ adapter->state = __I40EVF_REMOVE; adapter->aq_required = 0; #ifdef CONFIG_PM pci_save_state(pdev); #endif pci_disable_device(pdev); } /** * i40evf_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in i40evf_pci_tbl * * Returns 0 on success, negative on failure * * i40evf_probe initializes an adapter identified by a pci_dev structure. * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. **/ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct i40evf_adapter *adapter = NULL; struct i40e_hw *hw = NULL; int err; err = pci_enable_device(pdev); if (err) return err; err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (err) { err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); goto err_dma; } } err = pci_request_regions(pdev, i40evf_driver_name); if (err) { dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); goto err_pci_reg; } pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); netdev = alloc_etherdev_mq(sizeof(struct i40evf_adapter), MAX_QUEUES); if (!netdev) { err = -ENOMEM; goto err_alloc_etherdev; } SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; hw = &adapter->hw; hw->back = adapter; adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; adapter->state = __I40EVF_STARTUP; /* Call save state here because it relies on the adapter struct. */ pci_save_state(pdev); hw->hw_addr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (!hw->hw_addr) { err = -EIO; goto err_ioremap; } hw->vendor_id = pdev->vendor; hw->device_id = pdev->device; pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); hw->subsystem_vendor_id = pdev->subsystem_vendor; hw->subsystem_device_id = pdev->subsystem_device; hw->bus.device = PCI_SLOT(pdev->devfn); hw->bus.func = PCI_FUNC(pdev->devfn); /* set up the locks for the AQ, do this only once in probe * and destroy them only once in remove */ mutex_init(&hw->aq.asq_mutex); mutex_init(&hw->aq.arq_mutex); INIT_LIST_HEAD(&adapter->mac_filter_list); INIT_LIST_HEAD(&adapter->vlan_filter_list); INIT_WORK(&adapter->reset_task, i40evf_reset_task); INIT_WORK(&adapter->adminq_task, i40evf_adminq_task); INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task); INIT_DELAYED_WORK(&adapter->init_task, i40evf_init_task); schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(5 * (pdev->devfn & 0x07))); return 0; err_ioremap: free_netdev(netdev); err_alloc_etherdev: pci_release_regions(pdev); err_pci_reg: err_dma: pci_disable_device(pdev); return err; } #ifdef CONFIG_PM /** * i40evf_suspend - Power management suspend routine * @pdev: PCI device information struct * @state: unused * * Called when the system (VM) is entering sleep/suspend. **/ static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct i40evf_adapter *adapter = netdev_priv(netdev); int retval = 0; netif_device_detach(netdev); if (netif_running(netdev)) { rtnl_lock(); i40evf_down(adapter); rtnl_unlock(); } i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); retval = pci_save_state(pdev); if (retval) return retval; pci_disable_device(pdev); return 0; } /** * i40evf_resume - Power management resume routine * @pdev: PCI device information struct * * Called when the system (VM) is resumed from sleep/suspend. **/ static int i40evf_resume(struct pci_dev *pdev) { struct i40evf_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; u32 err; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* pci_restore_state clears dev->state_saved so call * pci_save_state to restore it. */ pci_save_state(pdev); err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, "Cannot enable PCI device from suspend.\n"); return err; } pci_set_master(pdev); rtnl_lock(); err = i40evf_set_interrupt_capability(adapter); if (err) { rtnl_unlock(); dev_err(&pdev->dev, "Cannot enable MSI-X interrupts.\n"); return err; } err = i40evf_request_misc_irq(adapter); rtnl_unlock(); if (err) { dev_err(&pdev->dev, "Cannot get interrupt vector.\n"); return err; } schedule_work(&adapter->reset_task); netif_device_attach(netdev); return err; } #endif /* CONFIG_PM */ /** * i40evf_remove - Device Removal Routine * @pdev: PCI device information struct * * i40evf_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. The could be caused by a * Hot-Plug event, or because the driver is going to be removed from * memory. **/ static void i40evf_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); if (adapter->netdev_registered) { unregister_netdev(netdev); adapter->netdev_registered = false; } /* Shut down all the garbage mashers on the detention level */ adapter->state = __I40EVF_REMOVE; adapter->aq_required = 0; i40evf_request_reset(adapter); msleep(50); /* If the FW isn't responding, kick it once, but only once. */ if (!i40evf_asq_done(hw)) { i40evf_request_reset(adapter); msleep(50); } if (adapter->msix_entries) { i40evf_misc_irq_disable(adapter); i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); i40evf_free_q_vectors(adapter); } if (adapter->watchdog_timer.function) del_timer_sync(&adapter->watchdog_timer); flush_scheduled_work(); /* Clear user configurations for RSS */ i40evf_clear_rss_config_user(&adapter->vsi); if (hw->aq.asq.count) i40evf_shutdown_adminq(hw); /* destroy the locks only once, here */ mutex_destroy(&hw->aq.arq_mutex); mutex_destroy(&hw->aq.asq_mutex); iounmap(hw->hw_addr); pci_release_regions(pdev); i40evf_free_all_tx_resources(adapter); i40evf_free_all_rx_resources(adapter); i40evf_free_queues(adapter); kfree(adapter->vf_res); /* If we got removed before an up/down sequence, we've got a filter * hanging out there that we need to get rid of. */ list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { list_del(&f->list); kfree(f); } list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { list_del(&f->list); kfree(f); } free_netdev(netdev); pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } static struct pci_driver i40evf_driver = { .name = i40evf_driver_name, .id_table = i40evf_pci_tbl, .probe = i40evf_probe, .remove = i40evf_remove, #ifdef CONFIG_PM .suspend = i40evf_suspend, .resume = i40evf_resume, #endif .shutdown = i40evf_shutdown, }; /** * i40e_init_module - Driver Registration Routine * * i40e_init_module is the first routine called when the driver is * loaded. All it does is register with the PCI subsystem. **/ static int __init i40evf_init_module(void) { int ret; pr_info("i40evf: %s - version %s\n", i40evf_driver_string, i40evf_driver_version); pr_info("%s\n", i40evf_copyright); i40evf_wq = create_singlethread_workqueue(i40evf_driver_name); if (!i40evf_wq) { pr_err("%s: Failed to create workqueue\n", i40evf_driver_name); return -ENOMEM; } ret = pci_register_driver(&i40evf_driver); return ret; } module_init(i40evf_init_module); /** * i40e_exit_module - Driver Exit Cleanup Routine * * i40e_exit_module is called just before the driver is removed * from memory. **/ static void __exit i40evf_exit_module(void) { pci_unregister_driver(&i40evf_driver); destroy_workqueue(i40evf_wq); } module_exit(i40evf_exit_module); /* i40evf_main.c */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
You can’t perform that action at this time.