mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "net: aquantia: support for 32-bit ARM target"
This commit is contained in:
commit
e35b5d5867
56 changed files with 27467 additions and 0 deletions
|
|
@ -23,4 +23,12 @@ config AQTION
|
|||
---help---
|
||||
This enables the support for the aQuantia AQtion(tm) Ethernet card.
|
||||
|
||||
config AQFWD
|
||||
tristate "aQuantia Forwarding driver"
|
||||
depends on PCI && (X86_64 || ARM64 || ARM )
|
||||
---help---
|
||||
This enables the support for forwarding driver for the aQuantia AQtion(tm) Ethernet card.
|
||||
|
||||
source "drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_AQUANTIA
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_AQTION) += atlantic/
|
||||
obj-$(CONFIG_AQFWD) += atlantic-fwd/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,283 @@
|
|||
|
||||
|
||||
|
||||
Supported hardware
|
||||
------------------
|
||||
|
||||
AQC-107 / -108 / -109, revisions B0 / B1. FW versions 1.x / 2.x / 3.x
|
||||
supported
|
||||
|
||||
|
||||
|
||||
Features / acceleration
|
||||
-----------------------
|
||||
|
||||
- Message-signalled interrupts
|
||||
- Hardware VLAN tag offloads
|
||||
- Hardware checksum offloads:
|
||||
- IPv4 header checksums
|
||||
- UDP / TCP checksums with IPv4 and IPv6
|
||||
- Hardware LSO for TCP v4/v6
|
||||
- Hardware LRO for TCP v4/v6
|
||||
- Coalescing TCP segments with TCP options not supported due to a
|
||||
HW limitation
|
||||
- Software GRO using the Linux NAPI GRO interface
|
||||
- Hardware Rx header splitting
|
||||
- RSS over up to 8 queues using MSI-X
|
||||
- Linear skb receive mode
|
||||
- N-tuple Rx filters
|
||||
- Runtime power management
|
||||
- Hardware MACSEC offload
|
||||
|
||||
|
||||
Building and installation
|
||||
-------------------------
|
||||
|
||||
1. Unpack the archive into a directory of your choice.
|
||||
|
||||
2. Change to that directory and compile the module:
|
||||
$ make [KDIR=<path to kernel headers>]
|
||||
|
||||
Explicitly specifying KDIR is only necessary when the headers can't
|
||||
be found automatically via the
|
||||
/lib/modules/`uname -r`/{build,source} symlinks
|
||||
|
||||
3. Load the module
|
||||
# insmod atlnew.ko [<module parameters>]
|
||||
|
||||
4. Unload the module
|
||||
# rmmod atlnew
|
||||
|
||||
|
||||
|
||||
Device configuration
|
||||
--------------------
|
||||
|
||||
# ip link set up dev <ifname>
|
||||
# ip addr add <IP addr>/<CIDR prefix length> brd + dev <ifname>
|
||||
|
||||
Add a VLAN ID:
|
||||
# ip link add link <ifname> name <ifname>.<VLAN id> type vlan id <VLAN id>
|
||||
# ip link set up dev <ifname>.<VLAN id>
|
||||
|
||||
Remove a VLAN ID:
|
||||
# ip link del dev <ifname>.<VLAN id>
|
||||
|
||||
|
||||
|
||||
Module parameters
|
||||
-----------------
|
||||
|
||||
Module parameters may be specified at module load time on the insmod
|
||||
command line or via modprobe.conf files. Some parameters marked as
|
||||
[RW] below can also be changed at run time via files in
|
||||
/sys/module/atlnew/parameters directory
|
||||
|
||||
- msi = < 1 | 0 > (default: 1) [RO]
|
||||
Enable use of MSI interrupts.
|
||||
|
||||
- rx_refill_batch = <num> (default: 16) [RW]
|
||||
Number of cleaned Rx ring descriptors to trigger Rx refill
|
||||
|
||||
- tx_clean_budget = <num> (default: 256) [RW]
|
||||
Max number of processed Tx descriptors to clean in one pass of
|
||||
NAPI poll
|
||||
|
||||
- max_queues = <num> (default: 8) [RO]
|
||||
Max number of RSS queues. The actual number of queues will the
|
||||
minimum of this parameter and the number of logical CPUs in
|
||||
the system.
|
||||
|
||||
- rx_linear = <0 | 1> (default: 0)
|
||||
Enables linear skb receive mode. Frames larger than
|
||||
ATL_RX_BUF_SIZE defined in atl_ring.h will be dropped.
|
||||
|
||||
- min_intr_delay (default: 10) [RW]
|
||||
When an interrupt is about to be asserted on an LRO-enabled
|
||||
queue, LRO requires some lead time to close and flush
|
||||
in-progress flows. This parameter sets the LRO interrupt delay
|
||||
and provides the lower boundary for interrupt coalescing
|
||||
delays settable via ethtool. When modified, the new value
|
||||
takes effect on interface down/up cycle or on setting an
|
||||
interrupt coalescing delay via ethtool.
|
||||
|
||||
- rx_mod_hyst (default: 10) [RW]
|
||||
- tx_mod_hyst (default: 10) [RW]
|
||||
Each ring has two interrupt coalescing timers. When an
|
||||
interrupt-causing event happens, they're initialized with
|
||||
values called minimum and maximum respectively. The former
|
||||
timer is restarted each time another such event happens, while
|
||||
the latter keeps running. When either timer reaches zero, the
|
||||
interrupt is reported to the host. The minimum value is set
|
||||
via ethtool. These module parameters set the difference
|
||||
between the maximum and minimum values for Rx and Tx
|
||||
paths. When modified, the new max values go into effect upon
|
||||
interface down/up cycle or upon modifying ethtool interrupt
|
||||
coalescing settings.
|
||||
|
||||
- keep_link = < 1 | 0 > (default: 0) [RO]
|
||||
When set to 1, the ethernet link is established at PCI probe
|
||||
time, and is not dropped on ifdown. This allows the rings
|
||||
allocated to forwarding engines to handle traffic even when
|
||||
linux network interface is down.
|
||||
|
||||
- sleep_delay = (default: 10000) [RW]
|
||||
Delay in ms after link goes down to suspend the device if runtime power
|
||||
management is turned on.
|
||||
|
||||
- macsec_bridge = < 1 | 0 > (default: 1) [RO]
|
||||
When set to 0, several SecY can be created, macsec will filter by source mac
|
||||
address to apply apropriate SecY.
|
||||
By default, only 1 SecY can be created, macsec will handle all packets.
|
||||
|
||||
- rx/tx_ring_size = <8..8184> (default: 4096) [RO]
|
||||
Default size for the rings.
|
||||
|
||||
VLAN filters
|
||||
------------
|
||||
|
||||
Sixteen VLAN filters are programmable via the ethtool -N interface using
|
||||
locations 0 through 15. The only flow-type supported is ether and only
|
||||
VLAN id can be matched.
|
||||
|
||||
For VLAN filters only, it's possible not to specify an explicit
|
||||
filter location. In this case an appropriate location will be assigned
|
||||
automatically.
|
||||
|
||||
These filters are also used for HW filter acceleration for Linux VLAN
|
||||
subdevices. Filters automatically added by Linux VLAN code can be
|
||||
overridden using ethtool subject to restrictions described below:
|
||||
|
||||
* A special ring number 32 is used in ethtool interface to signify
|
||||
'any ring'. An ethtool filter rule with ring set to 32 accepts a
|
||||
packet leaving the ring to be determined using the standard RSS
|
||||
mechanism. VLAN code adds rules in this manner. Such a rule can be
|
||||
modified using ethool to set a specific destination ring.
|
||||
|
||||
* There can't be two filters with the same VID. An attempt to add a
|
||||
duplicate filter using an explicit location different from the
|
||||
location of existing filter with the same VID will fail. When the
|
||||
location is not specified, the existing filter will be modified.
|
||||
|
||||
* An attempt to change the VID of a filter added by VLAN code using an
|
||||
explicit location will fail. Either use a different explicit
|
||||
location or no location.
|
||||
|
||||
* An attempt to delete a rule created by VLAN code will return
|
||||
success, but the rule will remain in place. If a specific ring was
|
||||
set in the rule, it will be reset to 'any ring'.
|
||||
|
||||
* If a VLAN sub-device is added when there're no unused filters, VLAN
|
||||
promiscuous mode will be enabled. This will result in all VIDs being
|
||||
accepted. Filters can still be used to direct specific VIDs to
|
||||
specific rings.
|
||||
|
||||
* Even when all 16 filters are used, attempting to add a rule with a
|
||||
new VID via ethtool will succeed as long as at least one existing
|
||||
filter was set by VLAN code and still has 'any ring' as
|
||||
destination. This filter will be re-used for the new rule and VLAN
|
||||
promiscuous mode will be enabled.
|
||||
|
||||
* When a filter becomes available as a result of a deletion of a VLAN
|
||||
subdevice or a deletion of an ethtool filter rule, and a VLAN
|
||||
promiscuous mode is enabled, the vacated filter will be re-used for
|
||||
another enabled VLAN subdevice. This may result in VLAN promiscuous
|
||||
mode being turned off if that VLAN subdevice was the last one with
|
||||
no filter allocated.
|
||||
|
||||
Ethertype filters
|
||||
-----------------
|
||||
|
||||
Fifteen ethertype filters are programmable via the ethtool -N
|
||||
interface using locations 16 through 30. The only flow-type supported
|
||||
is ether and only the ethertype field can be matched.
|
||||
|
||||
N-tuple filters
|
||||
---------------
|
||||
|
||||
Eight IPv4 n-tuple filters are supported, programmable using ethtool
|
||||
-N command with filter locations 32 through 39.
|
||||
|
||||
Fields that can be matched are source / destination IP addresses, and,
|
||||
for TCP / UDP / SCTP protocols, additionally source / destination
|
||||
ports can be matched. Partial (masked) matches are not supported, a
|
||||
mask for each field must consist of either all ones or all zeroes.
|
||||
|
||||
Each aligned group of four filters (locations 32 through 35 or 36
|
||||
through 39) can alternatively be used as one IPv6 filter, using filter
|
||||
locations 32 or 36.
|
||||
|
||||
|
||||
|
||||
Testing forwarding performance
|
||||
------------------------------
|
||||
|
||||
Since this is a design for a router, the best way to test would be
|
||||
between our aquantia port and another high speed port on the same
|
||||
DUT. However, in the situation where the Aquantia interface is the
|
||||
only high speed one, we have devised the following testing strategy
|
||||
to emulate these two ports on same DUT.
|
||||
|
||||
One of the simplest ways is to set up two VLAN interfaces and forward
|
||||
traffic between them as in the following example:
|
||||
|
||||
Set up two VLANs with examlple ids 42 and 43 on the Aquantia
|
||||
interface, assign the switch port connected to it to both of those
|
||||
VLANs.
|
||||
# ip link set up dev <iface>
|
||||
# ip link add link <iface> name <iface>.42 type vlan id 42
|
||||
# ip link add link <iface> name <iface>.43 type vlan id 43
|
||||
# ip link set up dev <iface>.42
|
||||
# ip link set up dev <iface>.43
|
||||
# ip addr add 10.42.42.1/24 brd + dev <iface>.42
|
||||
# ip addr add 10.42.43.1/24 brd + dev <iface>.43
|
||||
# sysctl net.ipv4.ip_forward=1
|
||||
|
||||
This sets up two VLAN interfaces with VLAN ids 42 and 43 and enables
|
||||
IP routing. Two hosts should be set up to generate and terminate the
|
||||
traffic:
|
||||
|
||||
On a host on the 42 VLAN with IP 10.42.42.xx run
|
||||
$ iperf3 -s
|
||||
On a host on the 43 VLAN run
|
||||
$ iperf3 -c 10.42.42.xx
|
||||
|
||||
Another possibility is to use a single host running Linux as a link
|
||||
partner both generating and terminating the traffic. Two VLAN
|
||||
sub-interfaces should be configured on a high-speed port on that host,
|
||||
belonging to VLAN 42 / IP network 10.42.42/24 and VLAN 43 / IP network
|
||||
10.42.43/24 respectively.
|
||||
|
||||
Since, by default, traffic addressed to one of the local IPs is
|
||||
received locally, a special configuration of Linux policy routing is
|
||||
required to make such traffic actually go out on the wire to the DUT,
|
||||
as described below, where <lp_iface> stands for the chosen network interface:
|
||||
|
||||
# ip rule add table local prio 100
|
||||
# ip rule del table local prio 0
|
||||
# ip rule add iif lo table 42 prio 42
|
||||
# ip link set up dev <lp_iface>
|
||||
|
||||
# ip link add link <lp_iface> name <lp_iface>.42 type vlan id 42
|
||||
# ip link add link <lp_iface> name <lp_iface>.43 type vlan id 43
|
||||
# ip link set up dev <lp_iface>.42
|
||||
# ip link set up dev <lp_iface>.43
|
||||
# ip addr add 10.42.42.10/24 brd + dev <lp_iface>.42
|
||||
# ip addr add 10.42.43.10/24 brd + dev <lp_iface>.43
|
||||
|
||||
# ip route add 10.42.42.10 via 10.42.43.1 table 42
|
||||
# ip route add 10.42.43.10 via 10.42.42.1 table 42
|
||||
|
||||
This routes the locally-originated traffic, that is addressed to the local IP
|
||||
of one of the VLAN interfaces, out via the other VLAN interface, instead of
|
||||
being immediately looped back locally.
|
||||
|
||||
|
||||
$ iperf3 -s
|
||||
|
||||
$ iperf3 -c 10.42.42.10
|
||||
|
||||
The following command can be used to restore the default routing
|
||||
behavior:
|
||||
|
||||
# ip route flush table 42
|
||||
52
drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig
Normal file
52
drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#
|
||||
# Aquantia atlantic-forwarding driver config
|
||||
#
|
||||
|
||||
if AQFWD
|
||||
|
||||
config ATLFWD_FWD
|
||||
bool "Enable forwarding-engine API"
|
||||
default n
|
||||
help
|
||||
|
||||
Say Y to enable the forwarding-engine API
|
||||
|
||||
config ATLFWD_FWD_RXBUF
|
||||
int
|
||||
prompt "Rx buffer space for forwarding engine's rings" if ATLFWD_FWD
|
||||
range 0 320
|
||||
default 160 if ATLFWD_FWD
|
||||
default 0
|
||||
help
|
||||
|
||||
Amount of Rx buffer to reserve for the forwarding-engine
|
||||
rings. This sets the default value of the fwd_rx_buf_reserve
|
||||
module option.
|
||||
|
||||
Value in kiB, 0 to 320, defaults to 160 if forwarding-engine
|
||||
API enabled, 0 otherwise.
|
||||
|
||||
config ATLFWD_FWD_TXBUF
|
||||
int
|
||||
prompt "Tx buffer space for forwarding engine's rings" if ATLFWD_FWD
|
||||
range 0 160
|
||||
default 80 if ATLFWD_FWD
|
||||
default 0
|
||||
help
|
||||
|
||||
Amount of Tx buffer to reserve for the forwarding-engine
|
||||
rings. This sets the default value of the fwd_tx_buf_reserve
|
||||
module option.
|
||||
|
||||
Value in kiB, 0 to 320, defaults to 80 if forwarding-engine
|
||||
API enabled, 0 otherwise.
|
||||
|
||||
config ATLFWD_FWD_NETLINK
|
||||
bool "Enable netlink control socket for forwarding engine"
|
||||
default n
|
||||
depends on ATLFWD_FWD
|
||||
help
|
||||
|
||||
Expose forwarding engine APIs over the netlink socket.
|
||||
|
||||
endif
|
||||
30
drivers/net/ethernet/aquantia/atlantic-fwd/Makefile
Normal file
30
drivers/net/ethernet/aquantia/atlantic-fwd/Makefile
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Atlantic Network Driver
|
||||
#
|
||||
# Copyright(c) 2014-2019 aQuantia Corporation.
|
||||
# Copyright(c) 2019-2020 Marvell International Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
obj-$(CONFIG_AQFWD) += atlantic-fwd.o
|
||||
|
||||
atlantic-fwd-objs := atl_fw.o \
|
||||
atl2_fw.o \
|
||||
atl_hw.o \
|
||||
atl_main.o \
|
||||
atl_ring.o \
|
||||
atl_ethtool.o \
|
||||
atl_trace.o \
|
||||
atl_compat.o \
|
||||
atl_hwmon.o \
|
||||
atl_ptp.o \
|
||||
atl_hw_ptp.o
|
||||
|
||||
atlantic-fwd-$(CONFIG_ATLFWD_FWD) += atl_fwd.o
|
||||
atlantic-fwd-$(CONFIG_ATLFWD_FWD_NETLINK) += atl_fwdnl.o \
|
||||
atl_fwdnl_params.o
|
||||
atlantic-fwd-$(CONFIG_MACSEC) += atl_macsec.o macsec/macsec_api.o
|
||||
|
||||
ccflags-y += -I$(src)
|
||||
968
drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c
Normal file
968
drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c
Normal file
|
|
@ -0,0 +1,968 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "atl_common.h"
|
||||
#include "atl_hw.h"
|
||||
#include "atl2_fw.h"
|
||||
#include "atl_fw.h"
|
||||
|
||||
#define ATL2_FW_READ_TRY_MAX 1000
|
||||
|
||||
#define atl2_shared_buffer_write(HW, ITEM, VARIABLE) \
|
||||
atl2_mif_shared_buf_write(HW,\
|
||||
(offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
|
||||
(u32 *)&VARIABLE, sizeof(VARIABLE) / sizeof(u32))
|
||||
|
||||
#define atl2_shared_buffer_get(HW, ITEM, VARIABLE) \
|
||||
atl2_mif_shared_buf_get(HW, \
|
||||
(offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
|
||||
(u32 *)&VARIABLE, \
|
||||
sizeof(VARIABLE) / sizeof(u32))
|
||||
|
||||
/* This should never be used on non atomic fields,
|
||||
* treat any > u32 read as non atomic.
|
||||
*/
|
||||
#define atl2_shared_buffer_read(HW, ITEM, VARIABLE) \
|
||||
{\
|
||||
BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \
|
||||
sizeof(u32)) != 0,\
|
||||
"Non aligned read " # ITEM);\
|
||||
BUILD_BUG_ON_MSG(sizeof(VARIABLE) > sizeof(u32),\
|
||||
"Non atomic read " # ITEM);\
|
||||
atl2_mif_shared_buf_read(HW, \
|
||||
(offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
|
||||
(u32 *)&VARIABLE, \
|
||||
sizeof(VARIABLE) / sizeof(u32));\
|
||||
}
|
||||
|
||||
static void atl2_mif_shared_buf_get(struct atl_hw *hw, int offset,
|
||||
u32 *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
data[i] = atl_read(hw, ATL2_MIF_SHARED_BUFFER_IN(offset + i));
|
||||
}
|
||||
|
||||
static void atl2_mif_shared_boot_buf_write(struct atl_hw *hw, int offset,
|
||||
u32 *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len / sizeof(u32); i++)
|
||||
atl_write(hw, ATL2_MIF_SHARED_BUFFER_BOOT(i), data[i]);
|
||||
}
|
||||
|
||||
static void atl2_mif_shared_buf_write(struct atl_hw *hw, int offset,
|
||||
u32 *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
atl_write(hw, ATL2_MIF_SHARED_BUFFER_IN(offset + i),
|
||||
data[i]);
|
||||
}
|
||||
|
||||
static void atl2_mif_shared_buf_read(struct atl_hw *hw, int offset,
|
||||
u32 *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
data[i] = atl_read(hw, ATL2_MIF_SHARED_BUFFER_OUT(offset + i));
|
||||
}
|
||||
|
||||
static void atl2_mif_host_finished_write_set(struct atl_hw *hw, u32 finish)
|
||||
{
|
||||
atl_write_bits(hw, ATL2_MIF_HOST_FINISHED_WRITE, 0, 1, finish);
|
||||
}
|
||||
|
||||
static u32 atl2_mif_mcp_finished_read_get(struct atl_hw *hw)
|
||||
{
|
||||
return atl_read(hw, ATL2_MIF_MCP_FINISHED_READ) & 1;
|
||||
}
|
||||
|
||||
#define atl2_shared_buffer_read_safe(HW, ITEM, DATA) \
|
||||
_atl2_shared_buffer_read_safe((HW), \
|
||||
(offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
|
||||
sizeof(((struct fw_interface_out *)0)->ITEM) / sizeof(u32),\
|
||||
(DATA))
|
||||
|
||||
/* There are two 16bit transaction counters. The one is incremented at start of
|
||||
* changing non atomic value, the other one - at the end. So we need to wait for
|
||||
* ma moment when they are equal each other at the reading non atomic memory and
|
||||
* at the end of read.
|
||||
*/
|
||||
static int _atl2_shared_buffer_read_safe(struct atl_hw *hw,
|
||||
uint32_t offset, uint32_t dwords,
|
||||
void *data)
|
||||
{
|
||||
struct transaction_counter_s tid1, tid2;
|
||||
int cnt = 0;
|
||||
|
||||
do {
|
||||
do {
|
||||
atl2_shared_buffer_read(hw, transaction_id, tid1);
|
||||
cnt++;
|
||||
if (cnt > ATL2_FW_READ_TRY_MAX)
|
||||
return -ETIME;
|
||||
if (tid1.transaction_cnt_a != tid1.transaction_cnt_b)
|
||||
udelay(1);
|
||||
} while (tid1.transaction_cnt_a != tid1.transaction_cnt_b);
|
||||
|
||||
atl2_mif_shared_buf_read(hw, offset, (u32 *)data, dwords);
|
||||
|
||||
atl2_shared_buffer_read(hw, transaction_id, tid2);
|
||||
|
||||
cnt++;
|
||||
//TODO: no much sense to handle these errors
|
||||
// therefore put WARN here to make it visible
|
||||
if (cnt > ATL2_FW_READ_TRY_MAX)
|
||||
return -ETIME;
|
||||
} while (tid2.transaction_cnt_a != tid2.transaction_cnt_b ||
|
||||
tid1.transaction_cnt_a != tid2.transaction_cnt_a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int atl2_shared_buffer_finish_ack(struct atl_hw *hw)
|
||||
{
|
||||
u32 val;
|
||||
int err = 0;
|
||||
|
||||
atl2_mif_host_finished_write_set(hw, 1U);
|
||||
|
||||
busy_wait(1000, udelay(100), val,
|
||||
atl2_mif_mcp_finished_read_get(hw),
|
||||
val != 0);
|
||||
|
||||
if (val != 0)
|
||||
err = -ETIME;
|
||||
WARN(err, "atl2_shared_buffer_finish_ack");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int atl2_fw_get_filter_caps(struct atl_hw *hw)
|
||||
{
|
||||
struct atl_nic *nic = container_of(hw, struct atl_nic, hw);
|
||||
struct filter_caps_s filter_caps;
|
||||
u32 tag_top;
|
||||
int err;
|
||||
|
||||
err = atl2_shared_buffer_read_safe(hw, filter_caps, &filter_caps);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hw->art_base_index = filter_caps.rslv_tbl_base_index * 8;
|
||||
hw->art_available = filter_caps.rslv_tbl_count * 8;
|
||||
if (hw->art_available == 0)
|
||||
hw->art_available = 128;
|
||||
nic->rxf_flex.available = 1;
|
||||
nic->rxf_flex.base_index = filter_caps.flexible_filter_mask >> 1;
|
||||
nic->rxf_mac.base_index = filter_caps.l2_filters_base_index;
|
||||
nic->rxf_mac.available = filter_caps.l2_filter_count;
|
||||
nic->rxf_etype.base_index = filter_caps.ethertype_filter_base_index;
|
||||
nic->rxf_etype.available = filter_caps.ethertype_filter_count;
|
||||
nic->rxf_etype.tag_top =
|
||||
(nic->rxf_etype.available >= ATL2_RPF_ETYPE_TAGS) ?
|
||||
(ATL2_RPF_ETYPE_TAGS) : (ATL2_RPF_ETYPE_TAGS >> 1);
|
||||
nic->rxf_vlan.base_index = filter_caps.vlan_filter_base_index;
|
||||
/* 0 - no tag, 1 - reserved for vlan-filter-offload filters */
|
||||
tag_top = (filter_caps.vlan_filter_count == ATL_VLAN_FLT_NUM) ?
|
||||
(ATL_VLAN_FLT_NUM - 2) :
|
||||
(ATL_VLAN_FLT_NUM / 2 - 2);
|
||||
nic->rxf_vlan.available = min_t(u32, filter_caps.vlan_filter_count - 2,
|
||||
tag_top);
|
||||
nic->rxf_ntuple.l3_v4_base_index = filter_caps.l3_ip4_filter_base_index;
|
||||
nic->rxf_ntuple.l3_v4_available = min_t(u32,
|
||||
filter_caps.l3_ip4_filter_count,
|
||||
ATL_NTUPLE_FLT_NUM - 1);
|
||||
nic->rxf_ntuple.l3_v6_base_index = filter_caps.l3_ip6_filter_base_index;
|
||||
nic->rxf_ntuple.l3_v6_available = filter_caps.l3_ip6_filter_count;
|
||||
nic->rxf_ntuple.l4_base_index = filter_caps.l4_filter_base_index;
|
||||
nic->rxf_ntuple.l4_available = min_t(u32, filter_caps.l4_filter_count,
|
||||
ATL_NTUPLE_FLT_NUM - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __atl2_fw_wait_init(struct atl_hw *hw)
|
||||
{
|
||||
struct request_policy_s request_policy;
|
||||
struct link_control_s link_control;
|
||||
uint32_t mtu;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON_MSG(sizeof(struct link_options_s) != 0x4,
|
||||
"linkOptions invalid size");
|
||||
BUILD_BUG_ON_MSG(sizeof(struct thermal_shutdown_s) != 0x4,
|
||||
"thermalShutdown invalid size");
|
||||
BUILD_BUG_ON_MSG(sizeof(struct sleep_proxy_s) != 0x958,
|
||||
"sleepProxy invalid size");
|
||||
BUILD_BUG_ON_MSG(sizeof(struct pause_quanta_s) != 0x18,
|
||||
"pauseQuanta invalid size");
|
||||
BUILD_BUG_ON_MSG(sizeof(struct cable_diag_control_s) != 0x4,
|
||||
"cableDiagControl invalid size");
|
||||
BUILD_BUG_ON_MSG(sizeof(struct statistics_s) != 0x70,
|
||||
"statistics_s invalid size");
|
||||
|
||||
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in, mtu) != 0,
|
||||
"mtu invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in, mac_address) != 0x8,
|
||||
"macAddress invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in,
|
||||
link_control) != 0x10,
|
||||
"linkControl invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in,
|
||||
link_options) != 0x18,
|
||||
"linkOptions invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in,
|
||||
thermal_shutdown) != 0x20,
|
||||
"thermalShutdown invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in, sleep_proxy) != 0x28,
|
||||
"sleepProxy invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in,
|
||||
pause_quanta) != 0x984,
|
||||
"pauseQuanta invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_in,
|
||||
cable_diag_control) != 0xA44,
|
||||
"cableDiagControl invalid offset");
|
||||
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out, version) != 0x04,
|
||||
"version invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out, link_status) != 0x14,
|
||||
"linkStatus invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
wol_status) != 0x18,
|
||||
"wolStatus invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
mac_health_monitor) != 0x610,
|
||||
"macHealthMonitor invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
phy_health_monitor) != 0x620,
|
||||
"phyHealthMonitor invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
cable_diag_status) != 0x630,
|
||||
"cableDiagStatus invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
device_link_caps) != 0x648,
|
||||
"deviceLinkCaps invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
sleep_proxy_caps) != 0x650,
|
||||
"sleepProxyCaps invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
lkp_link_caps) != 0x660,
|
||||
"lkpLinkCaps invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out, core_dump) != 0x668,
|
||||
"coreDump invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out, stats) != 0x700,
|
||||
"stats invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out, filter_caps) != 0x774,
|
||||
"filter_caps invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out,
|
||||
management_status) != 0x78c,
|
||||
"management_status invalid offset");
|
||||
BUILD_BUG_ON_MSG(offsetof(struct fw_interface_out, trace) != 0x800,
|
||||
"trace invalid offset");
|
||||
|
||||
err = atl2_fw_get_filter_caps(hw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
atl2_shared_buffer_get(hw, link_control, link_control);
|
||||
link_control.mode = ATL2_HOST_MODE_ACTIVE;
|
||||
atl2_shared_buffer_write(hw, link_control, link_control);
|
||||
|
||||
atl2_shared_buffer_get(hw, mtu, mtu);
|
||||
mtu = ATL_MAX_MTU + ETH_FCS_LEN + ETH_HLEN;
|
||||
atl2_shared_buffer_write(hw, mtu, mtu);
|
||||
|
||||
atl2_shared_buffer_get(hw, request_policy, request_policy);
|
||||
request_policy.bcast.accept = 1;
|
||||
request_policy.bcast.queue_or_tc = 1;
|
||||
request_policy.bcast.rx_queue_tc_index = 0;
|
||||
request_policy.mcast.accept = 1;
|
||||
request_policy.mcast.queue_or_tc = 1;
|
||||
request_policy.mcast.rx_queue_tc_index = 0;
|
||||
request_policy.promisc.queue_or_tc = 1;
|
||||
request_policy.promisc.rx_queue_tc_index = 0;
|
||||
atl2_shared_buffer_write(hw, request_policy, request_policy);
|
||||
|
||||
return atl2_shared_buffer_finish_ack(hw);
|
||||
}
|
||||
|
||||
int atl2_fw_set_filter_policy(struct atl_hw *hw, bool promisc, bool allmulti)
|
||||
{
|
||||
struct request_policy_s request_policy;
|
||||
|
||||
atl2_shared_buffer_get(hw, request_policy, request_policy);
|
||||
|
||||
request_policy.promisc.all = promisc;
|
||||
request_policy.mcast.promisc = allmulti;
|
||||
|
||||
atl2_shared_buffer_write(hw, request_policy, request_policy);
|
||||
return atl2_shared_buffer_finish_ack(hw);
|
||||
}
|
||||
|
||||
static int atl2_fw_deinit(struct atl_hw *hw)
|
||||
{
|
||||
struct link_control_s link_control;
|
||||
int err = 0;
|
||||
|
||||
atl2_shared_buffer_get(hw, link_control, link_control);
|
||||
link_control.mode = ATL2_HOST_MODE_SHUTDOWN;
|
||||
|
||||
atl2_shared_buffer_write(hw, link_control, link_control);
|
||||
err = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline unsigned int atl_link_adv(struct atl_link_state *lstate)
|
||||
{
|
||||
struct atl_hw *hw = container_of(lstate, struct atl_hw, link_state);
|
||||
|
||||
if (lstate->thermal_throttled
|
||||
&& hw->thermal.flags & atl_thermal_throttle)
|
||||
/* FW doesn't provide raw LP's advertized rates, only
|
||||
* the rates adverized both by us and LP. Here we
|
||||
* advertize not just the throttled_to rate, but also
|
||||
* all the lower rates as well. That way if LP changes
|
||||
* or dynamically starts to adverize a lower rate than
|
||||
* throttled_to, we will notice that in
|
||||
* atl_thermal_check() and switch to that lower
|
||||
* rate there.
|
||||
*/
|
||||
return (lstate->advertized & ATL_EEE_MASK) |
|
||||
(BIT(lstate->throttled_to + 1) - 1);
|
||||
|
||||
return lstate->advertized;
|
||||
}
|
||||
|
||||
static bool atl2_fw_set_link_needed(struct atl_link_state *lstate)
|
||||
{
|
||||
struct atl_fc_state *fc = &lstate->fc;
|
||||
bool ret = false;
|
||||
|
||||
if (fc->req != fc->prev_req)
|
||||
ret = true;
|
||||
|
||||
if (atl_link_adv(lstate) != lstate->prev_advertized)
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void atl2_set_rate(struct atl_hw *hw,
|
||||
struct link_options_s *link_options)
|
||||
{
|
||||
unsigned int adv = atl_link_adv(&hw->link_state);
|
||||
|
||||
link_options->rate_10M_hd = !!(adv & BIT(atl_link_type_idx_10m_half));
|
||||
link_options->rate_100M_hd = !!(adv & BIT(atl_link_type_idx_100m_half));
|
||||
link_options->rate_1G_hd = !!(adv & BIT(atl_link_type_idx_1g_half));
|
||||
link_options->rate_10M = !!(adv & BIT(atl_link_type_idx_10m));
|
||||
link_options->rate_100M = !!(adv & BIT(atl_link_type_idx_100m));
|
||||
link_options->rate_1G = !!(adv & BIT(atl_link_type_idx_1g));
|
||||
link_options->rate_2P5G = !!(adv & BIT(atl_link_type_idx_2p5g));
|
||||
link_options->rate_5G = !!(adv & BIT(atl_link_type_idx_5g));
|
||||
link_options->rate_10G = !!(adv & BIT(atl_link_type_idx_10g));
|
||||
link_options->rate_N5G = link_options->rate_5G;
|
||||
link_options->rate_N2P5G = link_options->rate_2P5G;
|
||||
}
|
||||
|
||||
static void atl2_set_eee(struct atl_link_state *lstate,
|
||||
struct link_options_s *link_options, bool eee_enabled)
|
||||
{
|
||||
uint32_t eee_advertized = lstate->advertized >> ATL_EEE_BIT_OFFT;
|
||||
|
||||
if (!eee_enabled) {
|
||||
link_options->eee_100M = 0;
|
||||
link_options->eee_1G = 0;
|
||||
link_options->eee_2P5G = 0;
|
||||
link_options->eee_5G = 0;
|
||||
link_options->eee_10G = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
link_options->eee_100M = !!(eee_advertized & BIT(atl_link_type_idx_100m));
|
||||
link_options->eee_1G = !!(eee_advertized & BIT(atl_link_type_idx_1g));
|
||||
link_options->eee_2P5G = !!(eee_advertized & BIT(atl_link_type_idx_2p5g));
|
||||
link_options->eee_5G = !!(eee_advertized & BIT(atl_link_type_idx_5g));
|
||||
link_options->eee_10G = !!(eee_advertized & BIT(atl_link_type_idx_10g));
|
||||
}
|
||||
|
||||
/* fw lock must be held */
|
||||
static void __atl2_fw_set_link(struct atl_hw *hw)
|
||||
{
|
||||
struct atl_link_state *lstate = &hw->link_state;
|
||||
struct link_options_s link_options;
|
||||
int err = 0;
|
||||
|
||||
atl2_shared_buffer_get(hw, link_options, link_options);
|
||||
|
||||
link_options.pause_rx = link_options.pause_tx = 0;
|
||||
if (lstate->fc.req & atl_fc_rx) {
|
||||
link_options.pause_rx = 1;
|
||||
link_options.pause_tx = 1;
|
||||
}
|
||||
if (lstate->fc.req & atl_fc_tx)
|
||||
link_options.pause_tx ^= 1;
|
||||
|
||||
link_options.link_up = 1;
|
||||
if (lstate->force_off)
|
||||
link_options.link_up = 0;
|
||||
|
||||
atl2_set_rate(hw, &link_options);
|
||||
atl2_set_eee(lstate, &link_options, lstate->eee_enabled);
|
||||
|
||||
atl2_shared_buffer_write(hw, link_options, link_options);
|
||||
err = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
lstate->prev_advertized = atl_link_adv(lstate);
|
||||
lstate->fc.prev_req = lstate->fc.req;
|
||||
}
|
||||
|
||||
static void atl2_fw_set_link(struct atl_hw *hw, bool force)
|
||||
{
|
||||
if (!force && !atl2_fw_set_link_needed(&hw->link_state))
|
||||
return;
|
||||
|
||||
atl_lock_fw(hw);
|
||||
__atl2_fw_set_link(hw);
|
||||
atl_unlock_fw(hw);
|
||||
}
|
||||
|
||||
static u32 a2_fw_caps_to_mask(struct device_link_caps_s *link_caps)
|
||||
{
|
||||
u32 supported = 0;
|
||||
|
||||
if (link_caps->rate_10G)
|
||||
supported |= BIT(atl_link_type_idx_10g);
|
||||
if (link_caps->rate_5G)
|
||||
supported |= BIT(atl_link_type_idx_5g);
|
||||
if (link_caps->rate_2P5G)
|
||||
supported |= BIT(atl_link_type_idx_2p5g);
|
||||
if (link_caps->rate_1G)
|
||||
supported |= BIT(atl_link_type_idx_1g);
|
||||
if (link_caps->rate_100M)
|
||||
supported |= BIT(atl_link_type_idx_100m);
|
||||
if (link_caps->rate_10M)
|
||||
supported |= BIT(atl_link_type_idx_10m);
|
||||
if (link_caps->rate_1G_hd)
|
||||
supported |= BIT(atl_link_type_idx_1g_half);
|
||||
if (link_caps->rate_100M_hd)
|
||||
supported |= BIT(atl_link_type_idx_100m_half);
|
||||
if (link_caps->rate_10M_hd)
|
||||
supported |= BIT(atl_link_type_idx_10m_half);
|
||||
|
||||
if (link_caps->eee_10G)
|
||||
supported |= BIT(atl_link_type_idx_10g) << ATL_EEE_BIT_OFFT;
|
||||
if (link_caps->eee_5G)
|
||||
supported |= BIT(atl_link_type_idx_5g) << ATL_EEE_BIT_OFFT;
|
||||
if (link_caps->eee_2P5G)
|
||||
supported |= BIT(atl_link_type_idx_2p5g) << ATL_EEE_BIT_OFFT;
|
||||
if (link_caps->eee_1G)
|
||||
supported |= BIT(atl_link_type_idx_1g) << ATL_EEE_BIT_OFFT;
|
||||
if (link_caps->eee_100M)
|
||||
supported |= BIT(atl_link_type_idx_100m) << ATL_EEE_BIT_OFFT;
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
static u32 a2_fw_lkp_to_mask(struct lkp_link_caps_s *lkp_link_caps)
|
||||
{
|
||||
u32 rate = 0;
|
||||
|
||||
if (lkp_link_caps->rate_10G)
|
||||
rate |= BIT(atl_link_type_idx_10g);
|
||||
if (lkp_link_caps->rate_5G)
|
||||
rate |= BIT(atl_link_type_idx_5g);
|
||||
if (lkp_link_caps->rate_2P5G)
|
||||
rate |= BIT(atl_link_type_idx_2p5g);
|
||||
if (lkp_link_caps->rate_1G)
|
||||
rate |= BIT(atl_link_type_idx_1g);
|
||||
if (lkp_link_caps->rate_100M)
|
||||
rate |= BIT(atl_link_type_idx_100m);
|
||||
if (lkp_link_caps->rate_10M)
|
||||
rate |= BIT(atl_link_type_idx_10m);
|
||||
if (lkp_link_caps->rate_1G_hd)
|
||||
rate |= BIT(atl_link_type_idx_1g_half);
|
||||
if (lkp_link_caps->rate_100M_hd)
|
||||
rate |= BIT(atl_link_type_idx_100m_half);
|
||||
if (lkp_link_caps->rate_10M_hd)
|
||||
rate |= BIT(atl_link_type_idx_10m_half);
|
||||
|
||||
if (lkp_link_caps->eee_10G)
|
||||
rate |= BIT(atl_link_type_idx_10g) << ATL_EEE_BIT_OFFT;
|
||||
if (lkp_link_caps->eee_5G)
|
||||
rate |= BIT(atl_link_type_idx_5g) << ATL_EEE_BIT_OFFT;
|
||||
if (lkp_link_caps->eee_2P5G)
|
||||
rate |= BIT(atl_link_type_idx_2p5g) << ATL_EEE_BIT_OFFT;
|
||||
if (lkp_link_caps->eee_1G)
|
||||
rate |= BIT(atl_link_type_idx_1g) << ATL_EEE_BIT_OFFT;
|
||||
if (lkp_link_caps->eee_100M)
|
||||
rate |= BIT(atl_link_type_idx_100m) << ATL_EEE_BIT_OFFT;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int __atl2_fw_update_link_status(struct atl_hw *hw)
|
||||
{
|
||||
struct atl_link_state *lstate = &hw->link_state;
|
||||
struct link_status_s link_status;
|
||||
struct lkp_link_caps_s lkp_link_caps;
|
||||
enum atl_fc_mode fc = atl_fc_none;
|
||||
|
||||
atl2_shared_buffer_read(hw, link_status, link_status);
|
||||
|
||||
switch (link_status.link_rate) {
|
||||
case ATL2_FW_LINK_RATE_10G:
|
||||
lstate->link = &atl_link_types[atl_link_type_idx_10g];
|
||||
break;
|
||||
case ATL2_FW_LINK_RATE_5G:
|
||||
lstate->link = &atl_link_types[atl_link_type_idx_5g];
|
||||
break;
|
||||
case ATL2_FW_LINK_RATE_2G5:
|
||||
lstate->link = &atl_link_types[atl_link_type_idx_2p5g];
|
||||
break;
|
||||
case ATL2_FW_LINK_RATE_1G:
|
||||
lstate->link = link_status.duplex ?
|
||||
&atl_link_types[atl_link_type_idx_1g] :
|
||||
&atl_link_types[atl_link_type_idx_1g_half];
|
||||
break;
|
||||
case ATL2_FW_LINK_RATE_100M:
|
||||
lstate->link = link_status.duplex ?
|
||||
&atl_link_types[atl_link_type_idx_100m] :
|
||||
&atl_link_types[atl_link_type_idx_100m_half];
|
||||
break;
|
||||
case ATL2_FW_LINK_RATE_10M:
|
||||
lstate->link = link_status.duplex ?
|
||||
&atl_link_types[atl_link_type_idx_10m] :
|
||||
&atl_link_types[atl_link_type_idx_10m_half];
|
||||
break;
|
||||
default:
|
||||
lstate->link = NULL;
|
||||
}
|
||||
|
||||
if (link_status.pause_rx)
|
||||
fc |= atl_fc_rx;
|
||||
if (link_status.pause_tx)
|
||||
fc |= atl_fc_tx;
|
||||
lstate->fc.cur = fc;
|
||||
lstate->eee = link_status.eee;
|
||||
|
||||
atl2_shared_buffer_read(hw, lkp_link_caps, lkp_link_caps);
|
||||
|
||||
lstate->lp_advertized = a2_fw_lkp_to_mask(&lkp_link_caps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct atl_link_type *atl2_fw_check_link(struct atl_hw *hw)
|
||||
{
|
||||
struct atl_link_type *link;
|
||||
struct atl_link_state *lstate = &hw->link_state;
|
||||
struct phy_health_monitor_s phy_health_monitor;
|
||||
int ret = 0;
|
||||
|
||||
memset(&phy_health_monitor, 0, sizeof(phy_health_monitor));
|
||||
|
||||
atl_lock_fw(hw);
|
||||
|
||||
__atl2_fw_update_link_status(hw);
|
||||
|
||||
ret = atl2_shared_buffer_read_safe(hw, phy_health_monitor,
|
||||
&phy_health_monitor);
|
||||
atl_unlock_fw(hw);
|
||||
|
||||
atl_thermal_check(hw, phy_health_monitor.phy_hot_warning);
|
||||
|
||||
/* Thermal check might have reset link due to throttling */
|
||||
link = lstate->link;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/* fw lock must be held */
|
||||
static int __atl2_fw_get_link_caps(struct atl_hw *hw)
|
||||
{
|
||||
struct device_link_caps_s device_link_caps;
|
||||
struct atl_mcp *mcp = &hw->mcp;
|
||||
unsigned int supported = 0;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
atl2_shared_buffer_read(hw, device_link_caps, device_link_caps);
|
||||
|
||||
mcp->wdog_disabled = true;
|
||||
|
||||
supported = a2_fw_caps_to_mask(&device_link_caps);
|
||||
|
||||
hw->link_state.supported = supported;
|
||||
hw->link_state.lp_lowest = fls(supported) - 1;
|
||||
mcp->caps_low = atl_fw2_wake_on_link_force;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl2_fw_restart_aneg(struct atl_hw *hw)
|
||||
{
|
||||
struct link_options_s link_options;
|
||||
int ret = 0;
|
||||
|
||||
atl2_shared_buffer_get(hw, link_options, link_options);
|
||||
|
||||
link_options.link_renegotiate = 1;
|
||||
|
||||
atl2_shared_buffer_write(hw, link_options, link_options);
|
||||
ret = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
link_options.link_renegotiate = 0;
|
||||
atl2_shared_buffer_write(hw, link_options, link_options);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void atl2_fw_set_default_link(struct atl_hw *hw)
|
||||
{
|
||||
struct atl_link_state *lstate = &hw->link_state;
|
||||
|
||||
lstate->autoneg = true;
|
||||
lstate->advertized = hw->link_state.supported;
|
||||
lstate->fc.req = atl_fc_full;
|
||||
lstate->eee_enabled = 0;
|
||||
lstate->advertized &= ~ATL_EEE_MASK;
|
||||
}
|
||||
|
||||
static int atl2_fw_get_phy_temperature(struct atl_hw *hw, int *temp)
|
||||
{
|
||||
struct phy_health_monitor_s phy_health_monitor;
|
||||
int ret = 0;
|
||||
|
||||
atl_lock_fw(hw);
|
||||
|
||||
ret = atl2_shared_buffer_read_safe(hw, phy_health_monitor,
|
||||
&phy_health_monitor);
|
||||
|
||||
*temp = (int8_t)(phy_health_monitor.phy_temperature) * 1000;
|
||||
|
||||
atl_unlock_fw(hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl2_fw_get_mac_addr(struct atl_hw *hw, uint8_t *mac)
|
||||
{
|
||||
struct mac_address_s mac_address;
|
||||
int err = 0;
|
||||
|
||||
atl2_shared_buffer_get(hw, mac_address, mac_address);
|
||||
|
||||
ether_addr_copy(mac, (u8 *)mac_address.mac_address);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* fw lock must be held */
|
||||
static int __atl2_fw_get_hbeat(struct atl_hw *hw, uint16_t *hbeat)
|
||||
{
|
||||
struct phy_health_monitor_s phy_health_monitor;
|
||||
int ret = 0;
|
||||
|
||||
ret = atl2_shared_buffer_read_safe(hw, phy_health_monitor,
|
||||
&phy_health_monitor);
|
||||
|
||||
*hbeat = phy_health_monitor.phy_heart_beat;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl2_fw_set_phy_loopback(struct atl_nic *nic, u32 mode)
|
||||
{
|
||||
struct device_link_caps_s device_link_caps;
|
||||
bool on = !!(nic->priv_flags & BIT(mode));
|
||||
struct atl_hw *hw = &nic->hw;
|
||||
struct link_options_s link_options;
|
||||
int ret = 0;
|
||||
|
||||
atl_lock_fw(hw);
|
||||
|
||||
atl2_shared_buffer_read(hw, device_link_caps, device_link_caps);
|
||||
atl2_shared_buffer_get(hw, link_options, link_options);
|
||||
|
||||
switch (mode) {
|
||||
case ATL_PF_LPB_INT_PHY:
|
||||
if (!device_link_caps.internal_loopback) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
link_options.internal_loopback = on;
|
||||
break;
|
||||
case ATL_PF_LPB_EXT_PHY:
|
||||
if (!device_link_caps.external_loopback) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
link_options.external_loopback = on;
|
||||
break;
|
||||
}
|
||||
|
||||
atl2_shared_buffer_write(hw, link_options, link_options);
|
||||
ret = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
unlock:
|
||||
atl_unlock_fw(hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl2_fw_enable_wol(struct atl_hw *hw, unsigned int wol_mode)
|
||||
{
|
||||
struct link_options_s link_options;
|
||||
struct link_control_s link_control;
|
||||
struct wake_on_lan_s wake_on_lan;
|
||||
struct mac_address_s mac_address;
|
||||
int ret = 0;
|
||||
|
||||
atl_lock_fw(hw);
|
||||
|
||||
atl2_shared_buffer_get(hw, sleep_proxy, wake_on_lan);
|
||||
|
||||
if (wol_mode & atl_fw_wake_on_link) {
|
||||
wake_on_lan.wake_on_link_up = 1;
|
||||
if (test_bit(ATL_ST_UP, &hw->state))
|
||||
wake_on_lan.restore_link_before_wake = 1;
|
||||
}
|
||||
|
||||
if (wol_mode & atl_fw_wake_on_link_rtpm) {
|
||||
wake_on_lan.wake_on_link_up = 1;
|
||||
}
|
||||
|
||||
if (wol_mode & atl_fw_wake_on_magic) {
|
||||
wake_on_lan.wake_on_magic_packet = 1;
|
||||
if (test_bit(ATL_ST_UP, &hw->state))
|
||||
wake_on_lan.restore_link_before_wake = 1;
|
||||
}
|
||||
|
||||
ether_addr_copy(mac_address.mac_address, hw->mac_addr);
|
||||
|
||||
atl2_shared_buffer_write(hw, mac_address, mac_address);
|
||||
atl2_shared_buffer_write(hw, sleep_proxy, wake_on_lan);
|
||||
atl2_shared_buffer_get(hw, link_control, link_control);
|
||||
link_control.mode = ATL2_HOST_MODE_SLEEP_PROXY;
|
||||
atl2_shared_buffer_write(hw, link_control, link_control);
|
||||
|
||||
atl2_shared_buffer_get(hw, link_options, link_options);
|
||||
link_options.link_up = 1;
|
||||
atl2_shared_buffer_write(hw, link_options, link_options);
|
||||
|
||||
ret = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
atl_unlock_fw(hw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl2_fw_update_thermal(struct atl_hw *hw)
|
||||
{
|
||||
bool enable = !!(hw->thermal.flags & atl_thermal_monitor);
|
||||
struct phy_health_monitor_s phy_health_monitor;
|
||||
struct thermal_shutdown_s thermal_shutdown;
|
||||
int ret = 0;
|
||||
|
||||
memset(&phy_health_monitor, 0, sizeof(phy_health_monitor));
|
||||
|
||||
atl_lock_fw(hw);
|
||||
|
||||
atl2_shared_buffer_get(hw, thermal_shutdown, thermal_shutdown);
|
||||
thermal_shutdown.shutdown_enable = enable;
|
||||
thermal_shutdown.shutdown_temp_threshold = hw->thermal.crit;
|
||||
thermal_shutdown.warning_hot_tempThreshold = hw->thermal.high;
|
||||
thermal_shutdown.warning_cold_temp_threshold = hw->thermal.low;
|
||||
atl2_shared_buffer_write(hw, thermal_shutdown, thermal_shutdown);
|
||||
ret = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
atl2_shared_buffer_read_safe(hw, phy_health_monitor,
|
||||
&phy_health_monitor);
|
||||
atl_unlock_fw(hw);
|
||||
|
||||
/* Thresholds might have changed, recheck state. */
|
||||
atl_thermal_check(hw, phy_health_monitor.phy_hot_warning);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl2_fw_set_pad_stripping(struct atl_hw *hw, bool on)
|
||||
{
|
||||
struct link_control_s link_control;
|
||||
int err = 0;
|
||||
|
||||
atl_lock_fw(hw);
|
||||
|
||||
atl2_shared_buffer_get(hw, link_control, link_control);
|
||||
link_control.enable_frame_padding_removal_rx = on;
|
||||
atl2_shared_buffer_write(hw, link_control, link_control);
|
||||
err = atl2_shared_buffer_finish_ack(hw);
|
||||
|
||||
atl_unlock_fw(hw);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define ATL2_FW_CFG_DUMP_SIZE (4 + (sizeof(struct link_options_s) * 3) + \
|
||||
(sizeof(struct link_control_s) * 3))
|
||||
static int atl2_fw_dump_cfg(struct atl_hw *hw)
|
||||
{
|
||||
if (!hw->mcp.fw_cfg_dump)
|
||||
hw->mcp.fw_cfg_dump = devm_kzalloc(&hw->pdev->dev,
|
||||
ATL2_FW_CFG_DUMP_SIZE,
|
||||
GFP_KERNEL);
|
||||
if (!hw->mcp.fw_cfg_dump)
|
||||
return -ENOMEM;
|
||||
|
||||
/* save link configuration */
|
||||
hw->mcp.fw_cfg_dump[0] = ((2 * 3 * 4) << 16) | 3;
|
||||
hw->mcp.fw_cfg_dump[1] = offsetof(struct fw_interface_in, link_control);
|
||||
atl2_shared_buffer_get(hw, link_control, hw->mcp.fw_cfg_dump[2]);
|
||||
hw->mcp.fw_cfg_dump[3] = ~0;
|
||||
|
||||
hw->mcp.fw_cfg_dump[4] = offsetof(struct fw_interface_in, link_options);
|
||||
atl2_shared_buffer_get(hw, link_options, hw->mcp.fw_cfg_dump[5]);
|
||||
hw->mcp.fw_cfg_dump[6] = ~0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atl2_confirm_buffer_write(struct atl_hw *hw,
|
||||
uint32_t offset, uint32_t len)
|
||||
{
|
||||
struct data_buffer_status_s buffer_status;
|
||||
|
||||
buffer_status.data_offset = offset;
|
||||
buffer_status.data_length = len;
|
||||
atl2_shared_buffer_write(hw, data_buffer_status, buffer_status);
|
||||
}
|
||||
|
||||
static int atl2_fw_restore_cfg(struct atl_hw *hw)
|
||||
{
|
||||
uint32_t req_adr = atl_read(hw, ATL2_MIF_BOOT_READ_REQ_ADR);
|
||||
uint32_t req_len = atl_read(hw, ATL2_MIF_BOOT_READ_REQ_LEN);
|
||||
|
||||
if (req_adr == ATL2_ITI_ADDRESS_START) {
|
||||
struct fw_iti_hdr iti_header;
|
||||
|
||||
memset(&iti_header, 0, sizeof(iti_header));
|
||||
iti_header.instuction_bitmask = BIT(2);
|
||||
iti_header.iti[0].type = 2;
|
||||
iti_header.iti[0].length = ATL2_FW_CFG_DUMP_SIZE;
|
||||
atl2_mif_shared_boot_buf_write(hw, 0, (void *)&iti_header,
|
||||
sizeof(iti_header));
|
||||
atl2_confirm_buffer_write(hw, req_adr, req_len);
|
||||
|
||||
atl2_mif_host_finished_write_set(hw, 1U);
|
||||
|
||||
return 0;
|
||||
} else if (req_adr == ATL2_ITI_ADDRESS_BLOCK_1) {
|
||||
atl2_confirm_buffer_write(hw, req_adr, req_len);
|
||||
atl2_mif_shared_boot_buf_write(hw, 0,
|
||||
(void *)hw->mcp.fw_cfg_dump, ATL2_FW_CFG_DUMP_SIZE);
|
||||
atl2_mif_host_finished_write_set(hw, 1U);
|
||||
return 0;
|
||||
}
|
||||
|
||||
atl_dev_err("FW requests invalid address %#x", req_adr);
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int atl2_fw_set_mediadetect(struct atl_hw *hw, bool on)
|
||||
{
|
||||
struct link_options_s link_options;
|
||||
|
||||
atl2_shared_buffer_get(hw, link_options, link_options);
|
||||
|
||||
link_options.low_power_autoneg = on;
|
||||
|
||||
atl2_shared_buffer_write(hw, link_options, link_options);
|
||||
|
||||
return atl2_shared_buffer_finish_ack(hw);
|
||||
}
|
||||
|
||||
static int atl2_fw_unsupported(struct atl_hw *hw)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int atl2_get_fw_version(struct atl_hw *hw, u32 *fw_version)
|
||||
{
|
||||
struct mac_version_t mac_version;
|
||||
|
||||
atl2_shared_buffer_read(hw, version.mac, mac_version);
|
||||
*fw_version = mac_version.major << 24 | mac_version.minor << 16 |
|
||||
mac_version.build;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct atl_fw_ops atl2_fw_ops = {
|
||||
.__wait_fw_init = __atl2_fw_wait_init,
|
||||
.deinit = atl2_fw_deinit,
|
||||
.set_link = atl2_fw_set_link,
|
||||
.check_link = atl2_fw_check_link,
|
||||
.__get_link_caps = __atl2_fw_get_link_caps,
|
||||
.restart_aneg = atl2_fw_restart_aneg,
|
||||
.set_default_link = atl2_fw_set_default_link,
|
||||
.get_phy_temperature = atl2_fw_get_phy_temperature,
|
||||
.set_mediadetect = atl2_fw_set_mediadetect,
|
||||
.send_macsec_req = (void *)atl2_fw_unsupported,
|
||||
.set_pad_stripping = atl2_fw_set_pad_stripping,
|
||||
.get_mac_addr = atl2_fw_get_mac_addr,
|
||||
.__get_hbeat = __atl2_fw_get_hbeat,
|
||||
.set_phy_loopback = atl2_fw_set_phy_loopback,
|
||||
.enable_wol = atl2_fw_enable_wol,
|
||||
.dump_cfg = (void *)atl2_fw_dump_cfg,
|
||||
.restore_cfg = atl2_fw_restore_cfg,
|
||||
.update_thermal = atl2_fw_update_thermal,
|
||||
};
|
||||
|
||||
int atl2_fw_init(struct atl_hw *hw)
|
||||
{
|
||||
struct atl_mcp *mcp = &hw->mcp;
|
||||
int ret;
|
||||
|
||||
atl2_get_fw_version(hw, &mcp->fw_rev);
|
||||
|
||||
mcp->ops = &atl2_fw_ops;
|
||||
atl_dev_dbg("Detect ATL2FW %x\n", mcp->fw_rev);
|
||||
|
||||
ret = mcp->ops->__wait_fw_init(hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mcp->fw_stat_addr = 0;
|
||||
mcp->rpc_addr = 0;
|
||||
|
||||
ret = mcp->ops->__get_hbeat(hw, &mcp->phy_hbeat);
|
||||
if (ret)
|
||||
return ret;
|
||||
mcp->next_wdog = jiffies + 2 * HZ;
|
||||
|
||||
ret = mcp->ops->__get_link_caps(hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
690
drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.h
Normal file
690
drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.h
Normal file
|
|
@ -0,0 +1,690 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL2_FW_H_
|
||||
#define _ATL2_FW_H_
|
||||
|
||||
/* Start of HW byte packed interface declaration */
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/* F W A P I */
|
||||
|
||||
struct link_options_s {
|
||||
uint32_t link_up:1;
|
||||
uint32_t link_renegotiate:1;
|
||||
uint32_t minimal_link_speed:1;
|
||||
uint32_t internal_loopback:1;
|
||||
uint32_t external_loopback:1;
|
||||
uint32_t rate_10M_hd:1;
|
||||
uint32_t rate_100M_hd:1;
|
||||
uint32_t rate_1G_hd:1;
|
||||
|
||||
|
||||
uint32_t rate_10M:1;
|
||||
uint32_t rate_100M:1;
|
||||
uint32_t rate_1G:1;
|
||||
uint32_t rate_2P5G:1;
|
||||
uint32_t rate_N2P5G:1;
|
||||
uint32_t rate_5G:1;
|
||||
uint32_t rate_N5G:1;
|
||||
uint32_t rate_10G:1;
|
||||
|
||||
uint32_t eee_100M:1;
|
||||
uint32_t eee_1G:1;
|
||||
uint32_t eee_2P5G:1;
|
||||
uint32_t eee_5G:1;
|
||||
uint32_t eee_10G:1;
|
||||
uint32_t rsvd3:2;
|
||||
uint32_t low_power_autoneg:1;
|
||||
|
||||
uint32_t pause_rx:1;
|
||||
uint32_t pause_tx:1;
|
||||
uint32_t rsvd4:1;
|
||||
uint32_t downshift:1;
|
||||
uint32_t downshift_retry:4;
|
||||
};
|
||||
|
||||
struct link_control_s {
|
||||
uint32_t mode:4;
|
||||
|
||||
uint32_t disable_crc_corruption : 1;
|
||||
uint32_t discard_short_frames : 1;
|
||||
uint32_t flow_control_mode : 1;
|
||||
uint32_t disable_length_check : 1;
|
||||
uint32_t discard_errored_frames : 1;
|
||||
uint32_t control_frame_enable : 1;
|
||||
uint32_t enable_tx_padding : 1;
|
||||
uint32_t enable_crc_forwarding : 1;
|
||||
uint32_t enable_frame_padding_removal_rx: 1;
|
||||
uint32_t promiscuous_mode: 1;
|
||||
uint32_t rsvd:18;
|
||||
};
|
||||
|
||||
struct thermal_shutdown_s {
|
||||
uint32_t shutdown_enable :1;
|
||||
uint32_t warning_enable :1;
|
||||
uint32_t rsvd:6;
|
||||
|
||||
uint32_t shutdown_temp_threshold :8;
|
||||
uint32_t warning_cold_temp_threshold :8;
|
||||
uint32_t warning_hot_tempThreshold :8;
|
||||
};
|
||||
|
||||
struct mac_address_s {
|
||||
uint8_t mac_address[6];
|
||||
};
|
||||
|
||||
struct sleep_proxy_s {
|
||||
struct wake_on_lan_s {
|
||||
uint32_t wake_on_magic_packet:1;
|
||||
uint32_t wake_on_pattern:1;
|
||||
uint32_t wake_on_link_up:1;
|
||||
uint32_t wake_on_link_down:1;
|
||||
uint32_t wake_on_ping:1;
|
||||
uint32_t wake_on_timer:1;
|
||||
uint32_t wake_on_link_mac_method:1;
|
||||
uint32_t rsrvd1:1;
|
||||
uint32_t restore_link_before_wake:1;
|
||||
uint32_t rsvd:23;
|
||||
|
||||
uint32_t link_up_timeout;
|
||||
uint32_t link_down_timeout;
|
||||
uint32_t timer;
|
||||
|
||||
struct {
|
||||
uint32_t mask[4];
|
||||
uint32_t crc32;
|
||||
} wake_up_patterns[8];
|
||||
} wake_on_lan;
|
||||
|
||||
struct {
|
||||
uint32_t arp_responder:1;
|
||||
uint32_t echo_responder:1;
|
||||
uint32_t igmp_client:1;
|
||||
uint32_t echo_truncate:1;
|
||||
uint32_t address_guard:1;
|
||||
uint32_t ignore_fragmented:1;
|
||||
uint32_t rsvd:2;
|
||||
uint32_t echo_max_len:16;
|
||||
uint32_t ipv4[8];
|
||||
uint32_t reserved[8];
|
||||
|
||||
} ipv4_offload;
|
||||
|
||||
struct {
|
||||
uint32_t ns_responder:1;
|
||||
uint32_t echo_responder:1;
|
||||
uint32_t mld_client:1;
|
||||
uint32_t echo_truncate:1;
|
||||
uint32_t address_guard:1;
|
||||
uint32_t rsvd:3;
|
||||
uint32_t echo_max_len:16;
|
||||
uint32_t ipv6[16][4];
|
||||
} ipv6_offload;
|
||||
|
||||
struct {
|
||||
uint16_t ports[16];
|
||||
} tcp_port_offload;
|
||||
|
||||
struct {
|
||||
uint16_t ports[16];
|
||||
} udp_port_offload;
|
||||
|
||||
struct ka4_offloads_s {
|
||||
uint32_t retry_count;
|
||||
uint32_t retry_interval;
|
||||
|
||||
struct ka4_offload_s {
|
||||
uint32_t timeout;
|
||||
uint16_t local_port;
|
||||
uint16_t remote_port;
|
||||
uint8_t remote_mac_addr[6];
|
||||
uint32_t rsvd:16;
|
||||
uint32_t rsvd2:32;
|
||||
uint32_t rsvd3:32;
|
||||
uint32_t rsvd4:16;
|
||||
uint16_t win_size;
|
||||
uint32_t seq_num;
|
||||
uint32_t ack_num;
|
||||
uint32_t local_ip;
|
||||
uint32_t remote_ip;
|
||||
} offloads[16];
|
||||
} ka4_offload;
|
||||
|
||||
struct ka6_offloads_s {
|
||||
uint32_t retry_count;
|
||||
uint32_t retry_interval;
|
||||
|
||||
struct ka6_offload_s {
|
||||
uint32_t timeout;
|
||||
uint16_t local_port;
|
||||
uint16_t remote_port;
|
||||
uint8_t remote_mac_addr[6];
|
||||
uint32_t rsvd:16;
|
||||
uint32_t rsvd2:32;
|
||||
uint32_t rsvd3:32;
|
||||
uint32_t rsvd4:16;
|
||||
uint16_t win_size;
|
||||
uint32_t seq_num;
|
||||
uint32_t ack_num;
|
||||
uint32_t local_ip[4];
|
||||
uint32_t remote_ip[4];
|
||||
} offloads[16];
|
||||
} ka6_offload;
|
||||
|
||||
struct {
|
||||
uint32_t rr_count;
|
||||
uint32_t rr_buf_len;
|
||||
uint32_t idx_offset;
|
||||
uint32_t rr__offset;
|
||||
} mdns;
|
||||
/* WARN: where this gap actually is not known */
|
||||
uint32_t reserve_fw_gap:16;
|
||||
};
|
||||
|
||||
struct ptp_s {
|
||||
uint32_t enable:1;
|
||||
};
|
||||
|
||||
struct pause_quanta_s {
|
||||
uint16_t quanta_10M;
|
||||
uint16_t threshold_10M;
|
||||
uint16_t quanta_100M;
|
||||
uint16_t threshold_100M;
|
||||
uint16_t quanta_1G;
|
||||
uint16_t threshold_1G;
|
||||
uint16_t quanta_2P5G;
|
||||
uint16_t threshold_2P5G;
|
||||
uint16_t quanta_5G;
|
||||
uint16_t threshold_5G;
|
||||
uint16_t quanta_10G;
|
||||
uint16_t threshold_10G;
|
||||
};
|
||||
|
||||
struct data_buffer_status_s {
|
||||
uint32_t data_offset;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
struct device_caps_s {
|
||||
uint32_t finite_flashless: 1;
|
||||
uint32_t cable_diag: 1;
|
||||
uint32_t ncsi: 1;
|
||||
uint32_t avb: 1;
|
||||
uint32_t rsvd: 28;
|
||||
uint32_t rsvd2: 32;
|
||||
};
|
||||
|
||||
struct version_s {
|
||||
struct bundle_version_t {
|
||||
uint32_t major:8;
|
||||
uint32_t minor:8;
|
||||
uint32_t build:16;
|
||||
} bundle;
|
||||
struct mac_version_t {
|
||||
uint32_t major:8;
|
||||
uint32_t minor:8;
|
||||
uint32_t build:16;
|
||||
} mac;
|
||||
struct phy_version_t {
|
||||
uint32_t major:8;
|
||||
uint32_t minor:8;
|
||||
uint32_t build:16;
|
||||
} phy;
|
||||
uint32_t rsvd:32;
|
||||
};
|
||||
|
||||
struct link_status_s {
|
||||
uint32_t link_state:4;
|
||||
uint32_t link_rate:4;
|
||||
|
||||
uint32_t pause_tx:1;
|
||||
uint32_t pause_rx:1;
|
||||
uint32_t eee:1;
|
||||
uint32_t duplex:1;
|
||||
uint32_t rsvd:4;
|
||||
|
||||
uint32_t rsvd2:16;
|
||||
};
|
||||
|
||||
struct wol_status_s {
|
||||
uint32_t wake_count:8;
|
||||
uint32_t wake_reason:8;
|
||||
uint32_t wake_up_packet_length :12;
|
||||
uint32_t wake_up_pattern_number :3;
|
||||
uint32_t rsvd:1;
|
||||
uint32_t wake_up_packet[379];
|
||||
};
|
||||
|
||||
struct mac_health_monitor_s {
|
||||
uint32_t mac_ready:1;
|
||||
uint32_t mac_fault:1;
|
||||
uint32_t mac_flashless_finished:1;
|
||||
uint32_t rsvd:5;
|
||||
uint32_t mac_temperature:8;
|
||||
uint32_t mac_heart_beat:16;
|
||||
uint32_t mac_fault_code:16;
|
||||
uint32_t rsvd2:16;
|
||||
};
|
||||
|
||||
struct phy_health_monitor_s {
|
||||
uint32_t phy_ready:1;
|
||||
uint32_t phy_fault:1;
|
||||
uint32_t phy_hot_warning:1;
|
||||
uint32_t rsvd:5;
|
||||
uint32_t phy_temperature:8;
|
||||
uint32_t phy_heart_beat:16;
|
||||
uint32_t phy_fault_code:16;
|
||||
uint32_t rsvd2:16;
|
||||
};
|
||||
|
||||
struct device_link_caps_s {
|
||||
uint32_t rsvd:3;
|
||||
uint32_t internal_loopback:1;
|
||||
uint32_t external_loopback:1;
|
||||
uint32_t rate_10M_hd:1;
|
||||
uint32_t rate_100M_hd:1;
|
||||
uint32_t rate_1G_hd:1;
|
||||
|
||||
uint32_t rate_10M:1;
|
||||
uint32_t rate_100M:1;
|
||||
uint32_t rate_1G:1;
|
||||
uint32_t rate_2P5G:1;
|
||||
uint32_t rate_N2P5G:1;
|
||||
uint32_t rate_5G:1;
|
||||
uint32_t rate_N5G:1;
|
||||
uint32_t rate_10G:1;
|
||||
|
||||
uint32_t rsvd3:1;
|
||||
uint32_t eee_100M:1;
|
||||
uint32_t eee_1G:1;
|
||||
uint32_t eee_2P5G:1;
|
||||
uint32_t rsvd4:1;
|
||||
uint32_t eee_5G:1;
|
||||
uint32_t rsvd5:1;
|
||||
uint32_t eee_10G:1;
|
||||
|
||||
uint32_t pause_rx:1;
|
||||
uint32_t pause_tx:1;
|
||||
uint32_t pfc:1;
|
||||
uint32_t downshift:1;
|
||||
uint32_t downshift_retry:4;
|
||||
};
|
||||
|
||||
struct sleep_proxy_caps_s {
|
||||
uint32_t ipv4_offload:1;
|
||||
uint32_t ipv6_offload:1;
|
||||
uint32_t tcp_port_offload:1;
|
||||
uint32_t udp_port_offload:1;
|
||||
uint32_t ka4_offload:1;
|
||||
uint32_t ka6_offload:1;
|
||||
uint32_t mdns_offload:1;
|
||||
uint32_t wake_on_ping:1;
|
||||
|
||||
uint32_t wake_on_magic_packet:1;
|
||||
uint32_t wake_on_pattern:1;
|
||||
uint32_t wake_on_timer:1;
|
||||
uint32_t wake_on_link:1;
|
||||
uint32_t wake_patterns_count:4;
|
||||
|
||||
uint32_t ipv4_count:8;
|
||||
uint32_t ipv6_count:8;
|
||||
|
||||
uint32_t tcp_port_offload_count:8;
|
||||
uint32_t udp_port_offload_count:8;
|
||||
|
||||
uint32_t tcp4_ka_count:8;
|
||||
uint32_t tcp6_ka_count:8;
|
||||
|
||||
uint32_t igmp_offload:1;
|
||||
uint32_t mld_offload:1;
|
||||
uint32_t rsvd:30;
|
||||
};
|
||||
|
||||
struct lkp_link_caps_s {
|
||||
uint32_t rsvd:5;
|
||||
uint32_t rate_10M_hd:1;
|
||||
uint32_t rate_100M_hd:1;
|
||||
uint32_t rate_1G_hd:1;
|
||||
|
||||
uint32_t rate_10M:1;
|
||||
uint32_t rate_100M:1;
|
||||
uint32_t rate_1G:1;
|
||||
uint32_t rate_2P5G:1;
|
||||
uint32_t rate_N2P5G:1;
|
||||
uint32_t rate_5G:1;
|
||||
uint32_t rate_N5G:1;
|
||||
uint32_t rate_10G:1;
|
||||
|
||||
uint32_t rsvd2:1;
|
||||
uint32_t eee_100M:1;
|
||||
uint32_t eee_1G:1;
|
||||
uint32_t eee_2P5G:1;
|
||||
uint32_t rsvd3:1;
|
||||
uint32_t eee_5G:1;
|
||||
uint32_t rsvd4:1;
|
||||
uint32_t eee_10G:1;
|
||||
|
||||
uint32_t pause_rx:1;
|
||||
uint32_t pause_tx:1;
|
||||
uint32_t rsvd5:6;
|
||||
};
|
||||
|
||||
struct core_dump_s {
|
||||
uint32_t reg0;
|
||||
uint32_t reg1;
|
||||
uint32_t reg2;
|
||||
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
|
||||
uint32_t regs[32];
|
||||
};
|
||||
|
||||
struct trace_s {
|
||||
uint32_t sync_counter;
|
||||
uint32_t mem_buffer[0x1ff];
|
||||
};
|
||||
|
||||
struct cable_diag_control_s {
|
||||
uint32_t toggle :1;
|
||||
uint32_t rsvd:7;
|
||||
uint32_t wait_timeout_sec:8;
|
||||
uint32_t rsvd2:16;
|
||||
|
||||
};
|
||||
|
||||
struct cable_diag_lane_data_s {
|
||||
uint32_t result_code :8;
|
||||
uint32_t dist :8;
|
||||
uint32_t far_dist :8;
|
||||
uint32_t rsvd:8;
|
||||
};
|
||||
|
||||
struct cable_diag_status_s {
|
||||
struct cable_diag_lane_data_s lane_data[4];
|
||||
uint32_t transact_id:8;
|
||||
uint32_t status:4;
|
||||
uint32_t rsvd:20;
|
||||
};
|
||||
|
||||
struct phy_fw_load_status_s {
|
||||
uint32_t phy_fw_load_from_host :1;
|
||||
uint32_t phy_fw_load_from_flash :1;
|
||||
uint32_t phy_fw_load_from_d_c :1;
|
||||
uint32_t phy_load_from_flash_failed :1;
|
||||
uint32_t phy_load_from_host_failed :1;
|
||||
uint32_t phy_load_from_d_c_failed :1;
|
||||
uint32_t phy_hash_validation_failed :1;
|
||||
uint32_t phy_fw_started :1;
|
||||
|
||||
uint32_t phy_stall_timeout :1;
|
||||
uint32_t phy_unstall_timeout :1;
|
||||
uint32_t phy_fw_start_timeout :1;
|
||||
uint32_t phy_iram_load_error :1;
|
||||
uint32_t phy_dram_load_error :1;
|
||||
uint32_t phy_mcp_run_failed :1;
|
||||
uint32_t phy_mcp_stall_failed :1;
|
||||
uint32_t phy_mcp_unstall_failed :1;
|
||||
|
||||
uint32_t phy_wait_for_semaphore :1;
|
||||
uint32_t phy_semaphore_locked :1;
|
||||
uint32_t rsvd :2;
|
||||
uint32_t phy_worst_block_upload_retry_number:4;
|
||||
|
||||
uint32_t phy_worst_upload_block_number :6;
|
||||
uint32_t rsvd2:2;
|
||||
};
|
||||
|
||||
struct statistics_s {
|
||||
struct {
|
||||
uint32_t link_up;
|
||||
uint32_t link_down;
|
||||
} link;
|
||||
|
||||
struct {
|
||||
uint64_t tx_unicast_octets;
|
||||
uint64_t tx_multicast_octets;
|
||||
uint64_t tx_broadcast_octets;
|
||||
uint64_t rx_unicast_octets;
|
||||
uint64_t rx_multicast_octets;
|
||||
uint64_t rx_broadcast_octets;
|
||||
|
||||
uint32_t tx_unicast_frames;
|
||||
uint32_t tx_multicast_frames;
|
||||
uint32_t tx_broadcast_frames;
|
||||
uint32_t tx_errors;
|
||||
|
||||
uint32_t rx_unicast_frames;
|
||||
uint32_t rx_multicast_frames;
|
||||
uint32_t rx_broadcast_frames;
|
||||
uint32_t rx_dropped_frames;
|
||||
uint32_t rx_error_frames;
|
||||
|
||||
uint32_t tx_good_frames;
|
||||
uint32_t rx_good_frames;
|
||||
uint32_t reserve_fw_gap;
|
||||
} msm;
|
||||
uint32_t main_loop_cycles;
|
||||
uint32_t reserve_fw_gap;
|
||||
};
|
||||
|
||||
struct filter_caps_s {
|
||||
uint8_t l2_filters_base_index:6;
|
||||
uint8_t flexible_filter_mask:2;
|
||||
uint8_t l2_filter_count;
|
||||
uint8_t ethertype_filter_base_index;
|
||||
uint8_t ethertype_filter_count;
|
||||
|
||||
uint8_t vlan_filter_base_index;
|
||||
uint8_t vlan_filter_count;
|
||||
uint8_t l3_ip4_filter_base_index:4;
|
||||
uint8_t l3_ip4_filter_count:4;
|
||||
uint8_t l3_ip6_filter_base_index:4;
|
||||
uint8_t l3_ip6_filter_count:4;
|
||||
|
||||
uint8_t l4_filter_base_index:4;
|
||||
uint8_t l4_filter_count:4;
|
||||
uint8_t l4_flex_filter_base_index:4;
|
||||
uint8_t l4_flex_filter_count:4;
|
||||
uint8_t rslv_tbl_base_index;
|
||||
uint8_t rslv_tbl_count;
|
||||
};
|
||||
|
||||
struct request_policy_s {
|
||||
struct {
|
||||
uint8_t all:1;
|
||||
uint8_t rsvd:1;
|
||||
uint8_t rx_queue_tc_index:5;
|
||||
uint8_t queue_or_tc:1;
|
||||
} promisc;
|
||||
|
||||
struct {
|
||||
uint8_t accept:1;
|
||||
uint8_t rsvd:1;
|
||||
uint8_t rx_queue_tc_index:5;
|
||||
uint8_t queue_or_tc:1;
|
||||
} bcast;
|
||||
|
||||
struct {
|
||||
uint8_t accept:1;
|
||||
uint8_t promisc:1;
|
||||
uint8_t rx_queue_tc_index:5;
|
||||
uint8_t queue_or_tc:1;
|
||||
} mcast;
|
||||
|
||||
uint8_t rsvd:8;
|
||||
};
|
||||
|
||||
struct fw_interface_in {
|
||||
uint32_t mtu;
|
||||
uint32_t rsvd1:32;
|
||||
struct mac_address_s mac_address;
|
||||
uint16_t rsvd;
|
||||
struct link_control_s link_control;
|
||||
uint32_t rsvd2:32;
|
||||
struct link_options_s link_options;
|
||||
uint32_t rsvd3:32;
|
||||
struct thermal_shutdown_s thermal_shutdown;
|
||||
uint32_t rsvd4:32;
|
||||
struct sleep_proxy_s sleep_proxy;
|
||||
uint32_t rsvd5:32;
|
||||
struct pause_quanta_s pause_quanta[8];
|
||||
struct cable_diag_control_s cable_diag_control;
|
||||
uint32_t rsvd6:32;
|
||||
struct data_buffer_status_s data_buffer_status;
|
||||
uint32_t rsvd7:32;
|
||||
struct request_policy_s request_policy;
|
||||
};
|
||||
|
||||
struct transaction_counter_s {
|
||||
uint32_t transaction_cnt_a:16;
|
||||
uint32_t transaction_cnt_b:16;
|
||||
};
|
||||
|
||||
struct management_status_s {
|
||||
struct mac_address_s mac_address;
|
||||
uint16_t vlan;
|
||||
|
||||
struct{
|
||||
uint32_t enable : 1;
|
||||
uint32_t rsvd:31;
|
||||
} flags;
|
||||
|
||||
uint32_t rsvd1:32;
|
||||
uint32_t rsvd2:32;
|
||||
uint32_t rsvd3:32;
|
||||
uint32_t rsvd4:32;
|
||||
uint32_t rsvd5:32;
|
||||
};
|
||||
|
||||
struct fw_interface_out {
|
||||
struct transaction_counter_s transaction_id;
|
||||
struct version_s version;
|
||||
struct link_status_s link_status;
|
||||
struct wol_status_s wol_status;
|
||||
uint32_t rsvd:32;
|
||||
uint32_t rsvd2:32;
|
||||
struct mac_health_monitor_s mac_health_monitor;
|
||||
uint32_t rsvd3:32;
|
||||
uint32_t rsvd4:32;
|
||||
struct phy_health_monitor_s phy_health_monitor;
|
||||
uint32_t rsvd5:32;
|
||||
uint32_t rsvd6:32;
|
||||
struct cable_diag_status_s cable_diag_status;
|
||||
uint32_t rsvd7:32;
|
||||
struct device_link_caps_s device_link_caps;
|
||||
uint32_t rsvd8:32;
|
||||
struct sleep_proxy_caps_s sleep_proxy_caps;
|
||||
uint32_t rsvd9:32;
|
||||
struct lkp_link_caps_s lkp_link_caps;
|
||||
uint32_t rsvd10:32;
|
||||
struct core_dump_s core_dump;
|
||||
uint32_t rsvd11:32;
|
||||
struct statistics_s stats;
|
||||
uint32_t rsvd12:32;
|
||||
struct filter_caps_s filter_caps;
|
||||
struct device_caps_s device_caps;
|
||||
uint32_t rsvd13:32;
|
||||
struct management_status_s management_status;
|
||||
uint32_t reserve[21];
|
||||
struct trace_s trace;
|
||||
};
|
||||
|
||||
struct fw_iti_subblock_header {
|
||||
uint32_t type :8;
|
||||
uint32_t length :24;
|
||||
};
|
||||
|
||||
struct fw_iti_hdr {
|
||||
uint32_t instuction_bitmask;
|
||||
uint32_t reserved;
|
||||
struct fw_iti_subblock_header iti[6];
|
||||
};
|
||||
/* End of HW byte packed interface declaration */
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#define ATL2_FW_LINK_RATE_INVALID 0
|
||||
#define ATL2_FW_LINK_RATE_10M 1
|
||||
#define ATL2_FW_LINK_RATE_100M 2
|
||||
#define ATL2_FW_LINK_RATE_1G 3
|
||||
#define ATL2_FW_LINK_RATE_2G5 4
|
||||
#define ATL2_FW_LINK_RATE_5G 5
|
||||
#define ATL2_FW_LINK_RATE_10G 6
|
||||
|
||||
#define ATL2_HOST_MODE_INVALID 0
|
||||
#define ATL2_HOST_MODE_ACTIVE 1
|
||||
#define ATL2_HOST_MODE_SLEEP_PROXY 2
|
||||
#define ATL2_HOST_MODE_LOW_POWER 3
|
||||
#define ATL2_HOST_MODE_SHUTDOWN 4
|
||||
|
||||
#define ATL2_FW_CABLE_STATUS_OPEN_CIRCUIT 7
|
||||
#define ATL2_FW_CABLE_STATUS_HIGH_MISMATCH 6
|
||||
#define ATL2_FW_CABLE_STATUS_LOW_MISMATCH 5
|
||||
#define ATL2_FW_CABLE_STATUS_SHORT_CIRCUIT 4
|
||||
#define ATL2_FW_CABLE_STATUS_PAIR_D 3
|
||||
#define ATL2_FW_CABLE_STATUS_PAIR_C 2
|
||||
#define ATL2_FW_CABLE_STATUS_PAIR_B 1
|
||||
#define ATL2_FW_CABLE_STATUS_OK 0
|
||||
|
||||
#define ATL2_FW_HOST_INTERRUPT_MAC_READY 0x0004
|
||||
#define ATL2_FW_HOST_INTERRUPT_DATA_HANDLED 0x0100
|
||||
#define ATL2_FW_HOST_INTERRUPT_LINK_UP 0x0200
|
||||
#define ATL2_FW_HOST_INTERRUPT_LINK_DOWN 0x0400
|
||||
#define ATL2_FW_HOST_INTERRUPT_PHY_FAULT 0x0800
|
||||
#define ATL2_FW_HOST_INTERRUPT_MAC_FAULT 0x1000
|
||||
#define ATL2_FW_HOST_INTERRUPT_TEMPERATURE_WARNING 0x2000
|
||||
#define ATL2_FW_HOST_INTERRUPT_HEARTBEAT 0x4000
|
||||
|
||||
#define ATL2_ITI_ADDRESS_START 0x100000
|
||||
#define ATL2_ITI_ADDRESS_BLOCK_1 (ATL2_ITI_ADDRESS_START +\
|
||||
sizeof(struct fw_iti_hdr) / sizeof(uint32_t))
|
||||
enum {
|
||||
ATL2_MEMORY_MAILBOX_STATUS_FAIL = 0,
|
||||
ATL2_MEMORY_MAILBOX_STATUS_SUCCESS = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ATL2_MEMORY_MAILBOX_TARGET_MEMORY = 0,
|
||||
ATL2_MEMORY_MAILBOX_TARGET_MDIO = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ATL2_MEMORY_MAILBOX_OPERATION_READ = 0,
|
||||
ATL2_MEMORY_MAILBOX_OPERATION_WRITE = 1
|
||||
};
|
||||
|
||||
enum ATL2_WAKE_REASON {
|
||||
ATL2_WAKE_REASON_UNKNOWN,
|
||||
ATL2_WAKE_REASON_PANIC,
|
||||
ATL2_WAKE_REASON_LINK,
|
||||
ATL2_WAKE_REASON_TIMER,
|
||||
ATL2_WAKE_REASON_RESERVED,
|
||||
ATL2_WAKE_REASON_NAME_GUARD,
|
||||
ATL2_WAKE_REASON_ADDR_GUARD,
|
||||
ATL2_WAKE_REASON_TCPKA,
|
||||
|
||||
ATL2_WAKE_REASON_DATA_FLAG,
|
||||
|
||||
ATL2_WAKE_REASON_PING,
|
||||
ATL2_WAKE_REASON_SYN,
|
||||
ATL2_WAKE_REASON_UDP,
|
||||
ATL2_WAKE_REASON_PATTERN,
|
||||
ATL2_WAKE_REASON_MAGIC_PACKET
|
||||
};
|
||||
|
||||
int atl2_fw_init(struct atl_hw *hw);
|
||||
int atl2_get_fw_version(struct atl_hw *hw, u32 *fw_version);
|
||||
int atl2_fw_set_filter_policy(struct atl_hw *hw, bool promisc, bool allmulti);
|
||||
|
||||
|
||||
#endif
|
||||
446
drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h
Normal file
446
drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_COMMON_H_
|
||||
#define _ATL_COMMON_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#define ATL_VERSION "1.1.11"
|
||||
|
||||
struct atl_nic;
|
||||
|
||||
#include "atl_compat.h"
|
||||
#include "atl_hw.h"
|
||||
#include "atl_log.h"
|
||||
#include "atl_ring_desc.h"
|
||||
#include "atl_stats.h"
|
||||
|
||||
#define ATL_MAX_QUEUES 8
|
||||
|
||||
#include "atl_fwd.h"
|
||||
|
||||
struct atl_ptp;
|
||||
|
||||
enum {
|
||||
ATL_RXF_VLAN_BASE = 0,
|
||||
ATL_RXF_VLAN_MAX = ATL_VLAN_FLT_NUM,
|
||||
ATL_RXF_ETYPE_BASE = ATL_RXF_VLAN_BASE + ATL_RXF_VLAN_MAX,
|
||||
ATL_RXF_ETYPE_MAX = ATL_ETYPE_FLT_NUM,
|
||||
ATL2_RPF_ETYPE_TAGS = 7,
|
||||
ATL_RXF_NTUPLE_BASE = ATL_RXF_ETYPE_BASE + ATL_RXF_ETYPE_MAX,
|
||||
ATL_RXF_NTUPLE_MAX = ATL_NTUPLE_FLT_NUM,
|
||||
ATL_RXF_FLEX_BASE = ATL_RXF_NTUPLE_BASE + ATL_RXF_NTUPLE_MAX,
|
||||
ATL_RXF_FLEX_MAX = 1,
|
||||
};
|
||||
|
||||
enum atl_rxf_common_cmd {
|
||||
ATL_RXF_EN = BIT(31),
|
||||
ATL_RXF_RXQ_MSK = BIT(5) - 1,
|
||||
ATL_RXF_ACT_SHIFT = 16,
|
||||
ATL_RXF_ACT_MASK = BIT(3) - 1,
|
||||
ATL_RXF_ACT_TOHOST = BIT(0) << ATL_RXF_ACT_SHIFT,
|
||||
};
|
||||
|
||||
enum atl_ntuple_cmd {
|
||||
ATL_NTC_EN = ATL_RXF_EN, /* Filter enabled */
|
||||
ATL_NTC_V6 = BIT(30), /* IPv6 mode -- only valid in filters
|
||||
* 0 and 4 */
|
||||
ATL_NTC_SA = BIT(29), /* Match source address */
|
||||
ATL_NTC_DA = BIT(28), /* Match destination address */
|
||||
ATL_NTC_SP = BIT(27), /* Match source port */
|
||||
ATL_NTC_DP = BIT(26), /* Match destination port */
|
||||
ATL_NTC_PROTO = BIT(25), /* Match L4 proto */
|
||||
ATL_NTC_ARP = BIT(24),
|
||||
ATL_NTC_RXQ = BIT(23), /* Assign Rx queue */
|
||||
ATL_NTC_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
||||
ATL_NTC_RXQ_SHIFT = 8,
|
||||
ATL_NTC_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_NTC_RXQ_SHIFT,
|
||||
ATL_NTC_L4_MASK = BIT(3) - 1,
|
||||
ATL_NTC_L4_TCP = 0,
|
||||
ATL_NTC_L4_UDP = 1,
|
||||
ATL_NTC_L4_SCTP = 2,
|
||||
ATL_NTC_L4_ICMP = 3,
|
||||
};
|
||||
|
||||
enum atl2_ntuple_cmd {
|
||||
ATL2_NTC_L3_IPV4_EN = BIT(0), /* Filter enabled */
|
||||
ATL2_NTC_L3_IPV4_SA = BIT(1),
|
||||
ATL2_NTC_L3_IPV4_DA = BIT(2),
|
||||
ATL2_NTC_L3_IPV4_PROTO = BIT(3),
|
||||
ATL2_NTC_L3_IPV4_TAG_SHIFT = 4,
|
||||
ATL2_NTC_L3_IPV4_PROTO_SHIFT = 8,
|
||||
|
||||
ATL2_NTC_L3_IPV6_EN = BIT(0x10), /* Filter enabled */
|
||||
ATL2_NTC_L3_IPV6_SA = BIT(0x11),
|
||||
ATL2_NTC_L3_IPV6_DA = BIT(0x12),
|
||||
ATL2_NTC_L3_IPV6_PROTO = BIT(0x13),
|
||||
ATL2_NTC_L3_IPV6_TAG_SHIFT = 0x14,
|
||||
ATL2_NTC_L3_IPV6_PROTO_SHIFT = 0x18,
|
||||
|
||||
ATL2_NTC_L4_EN = BIT(0), /* Filter enabled */
|
||||
ATL2_NTC_L4_DP = BIT(1),
|
||||
ATL2_NTC_L4_SP = BIT(2),
|
||||
};
|
||||
|
||||
struct atl2_rxf_l3 {
|
||||
union {
|
||||
struct {
|
||||
__be32 dst_ip4;
|
||||
__be32 src_ip4;
|
||||
};
|
||||
struct {
|
||||
__be32 dst_ip6[4];
|
||||
__be32 src_ip6[4];
|
||||
};
|
||||
};
|
||||
u16 proto;
|
||||
u32 cmd;
|
||||
u16 usage;
|
||||
};
|
||||
|
||||
struct atl2_rxf_l4 {
|
||||
__be16 dst_port;
|
||||
__be16 src_port;
|
||||
u32 cmd;
|
||||
u16 usage;
|
||||
};
|
||||
|
||||
struct atl_rxf_ntuple {
|
||||
union {
|
||||
struct {
|
||||
__be32 dst_ip4[ATL_RXF_NTUPLE_MAX];
|
||||
__be32 src_ip4[ATL_RXF_NTUPLE_MAX];
|
||||
};
|
||||
struct {
|
||||
__be32 dst_ip6[ATL_RXF_NTUPLE_MAX][4];
|
||||
__be32 src_ip6[ATL_RXF_NTUPLE_MAX][4];
|
||||
};
|
||||
};
|
||||
__be16 dst_port[ATL_RXF_NTUPLE_MAX];
|
||||
__be16 src_port[ATL_RXF_NTUPLE_MAX];
|
||||
|
||||
struct atl2_rxf_l3 l3v4[ATL_RXF_NTUPLE_MAX];
|
||||
struct atl2_rxf_l3 l3v6[ATL_RXF_NTUPLE_MAX];
|
||||
struct atl2_rxf_l4 l4[ATL_RXF_NTUPLE_MAX];
|
||||
s8 l3_idx[ATL_RXF_NTUPLE_MAX];
|
||||
bool is_ipv6[ATL_RXF_NTUPLE_MAX];
|
||||
s8 l4_idx[ATL_RXF_NTUPLE_MAX];
|
||||
uint32_t cmd[ATL_RXF_NTUPLE_MAX];
|
||||
int count;
|
||||
int l3_v4_base_index;
|
||||
int l3_v4_available;
|
||||
int l3_v6_base_index;
|
||||
int l3_v6_available;
|
||||
int l4_base_index;
|
||||
int l4_available;
|
||||
};
|
||||
|
||||
enum atl_vlan_cmd {
|
||||
ATL_VLAN_EN = ATL_RXF_EN,
|
||||
ATL_VLAN_RXQ = BIT(28),
|
||||
ATL_VLAN_RXQ_SHIFT = 20,
|
||||
ATL_VLAN_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_VLAN_RXQ_SHIFT,
|
||||
ATL_VLAN_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
||||
ATL_VLAN_VID_MASK = BIT(12) - 1,
|
||||
};
|
||||
|
||||
#define ATL_VID_MAP_LEN BITS_TO_LONGS(BIT(12))
|
||||
|
||||
struct atl_rxf_vlan {
|
||||
uint32_t cmd[ATL_RXF_VLAN_MAX];
|
||||
int count;
|
||||
unsigned long map[ATL_VID_MAP_LEN];
|
||||
int vlans_active;
|
||||
int promisc_count;
|
||||
int base_index;
|
||||
int available;
|
||||
};
|
||||
|
||||
enum atl_etype_cmd {
|
||||
ATL_ETYPE_EN = ATL_RXF_EN,
|
||||
ATL_ETYPE_RXQ = BIT(29),
|
||||
ATL_ETYPE_RXQ_SHIFT = 20,
|
||||
ATL_ETYPE_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_ETYPE_RXQ_SHIFT,
|
||||
ATL_ETYPE_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
||||
ATL_ETYPE_VAL_MASK = BIT(16) - 1,
|
||||
};
|
||||
|
||||
struct atl2_tag_policy {
|
||||
u16 action;
|
||||
u16 usage;
|
||||
};
|
||||
|
||||
struct atl_rxf_etype {
|
||||
uint32_t cmd[ATL_RXF_ETYPE_MAX];
|
||||
int count;
|
||||
struct atl2_tag_policy tags_policy[ATL_RXF_ETYPE_MAX];
|
||||
int tag[ATL_RXF_ETYPE_MAX];
|
||||
int base_index;
|
||||
int available;
|
||||
int tag_top;
|
||||
};
|
||||
|
||||
struct atl_rxf_mac {
|
||||
int base_index;
|
||||
int available;
|
||||
};
|
||||
|
||||
enum atl_flex_cmd {
|
||||
ATL_FLEX_EN = ATL_RXF_EN,
|
||||
ATL_FLEX_RXQ = BIT(30),
|
||||
ATL_FLEX_RXQ_SHIFT = 20,
|
||||
ATL_FLEX_RXQ_MASK = ATL_RXF_RXQ_MSK << ATL_FLEX_RXQ_SHIFT,
|
||||
ATL_FLEX_ACT_SHIFT = ATL_RXF_ACT_SHIFT,
|
||||
};
|
||||
|
||||
struct atl_rxf_flex {
|
||||
uint32_t cmd[ATL_RXF_FLEX_MAX];
|
||||
int count;
|
||||
int base_index;
|
||||
int available;
|
||||
};
|
||||
|
||||
struct atl_queue_vec;
|
||||
|
||||
#define ATL_NUM_FWD_RINGS ATL_MAX_QUEUES
|
||||
#define ATL_FWD_RING_BASE ATL_MAX_QUEUES /* Use TC 1 for offload
|
||||
* engine rings */
|
||||
#define ATL_NUM_MSI_VECS 32
|
||||
enum {
|
||||
ATL_IRQ_LINK = 0,
|
||||
ATL_IRQ_PTP,
|
||||
ATL_NUM_NON_RING_IRQS,
|
||||
};
|
||||
|
||||
#define ATL_RXF_RING_ANY 32
|
||||
|
||||
#define ATL_FWD_MSI_BASE (ATL_MAX_QUEUES + ATL_NUM_NON_RING_IRQS)
|
||||
|
||||
enum atl_fwd_dir {
|
||||
ATL_FWDIR_RX = 0,
|
||||
ATL_FWDIR_TX = 1,
|
||||
ATL_FWDIR_NUM,
|
||||
};
|
||||
|
||||
struct atl_fwd {
|
||||
unsigned long ring_map[ATL_FWDIR_NUM];
|
||||
struct atl_fwd_ring *rings[ATL_FWDIR_NUM][ATL_NUM_FWD_RINGS];
|
||||
unsigned long msi_map;
|
||||
struct blocking_notifier_head nh_clients;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ATLFWD_FWD_NETLINK)
|
||||
struct atl_fwdnl {
|
||||
struct atl_desc_ring ring_desc[ATL_NUM_FWD_RINGS * 2];
|
||||
/* State of forced redirections */
|
||||
int force_icmp_via;
|
||||
int force_tx_via;
|
||||
/* Deferred TX head cleanup */
|
||||
struct delayed_work *tx_cleanup_wq;
|
||||
u32 tx_bunch;
|
||||
};
|
||||
#endif /* CONFIG_ATLFWD_FWD_NETLINK */
|
||||
|
||||
struct atl_nic {
|
||||
struct net_device *ndev;
|
||||
|
||||
struct atl_queue_vec *qvecs;
|
||||
int nvecs;
|
||||
struct atl_hw hw;
|
||||
unsigned flags;
|
||||
uint32_t priv_flags;
|
||||
struct timer_list work_timer;
|
||||
int max_mtu;
|
||||
unsigned int requested_nvecs;
|
||||
int requested_rx_size;
|
||||
int requested_tx_size;
|
||||
int rx_intr_delay;
|
||||
int tx_intr_delay;
|
||||
struct atl_global_stats stats;
|
||||
spinlock_t stats_lock;
|
||||
struct work_struct work;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
|
||||
struct atl_fwd fwd;
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_ATLFWD_FWD_NETLINK)
|
||||
struct atl_fwdnl fwdnl;
|
||||
#endif
|
||||
|
||||
struct atl_rxf_ntuple rxf_ntuple;
|
||||
struct atl_rxf_vlan rxf_vlan;
|
||||
struct atl_rxf_etype rxf_etype;
|
||||
struct atl_rxf_mac rxf_mac;
|
||||
struct atl_rxf_flex rxf_flex;
|
||||
|
||||
/* PTP support */
|
||||
struct atl_ptp *ptp;
|
||||
};
|
||||
|
||||
/* Flags only modified with RTNL lock held */
|
||||
enum atl_nic_flags {
|
||||
ATL_FL_MULTIPLE_VECTORS = BIT(0),
|
||||
ATL_FL_WOL = BIT(1),
|
||||
};
|
||||
|
||||
#define ATL_PF(_name) ATL_PF_ ## _name
|
||||
#define ATL_PF_BIT(_name) ATL_PF_ ## _name ## _BIT
|
||||
#define ATL_DEF_PF_BIT(_name) ATL_PF_BIT(_name) = BIT(ATL_PF(_name))
|
||||
|
||||
enum atl_priv_flags {
|
||||
ATL_PF_LPB_SYS_PB,
|
||||
ATL_PF_LPB_SYS_DMA,
|
||||
ATL_PF_LPB_NET_DMA,
|
||||
ATL_PF_LPB_INT_PHY,
|
||||
ATL_PF_LPB_EXT_PHY,
|
||||
ATL_PF_LPI_RX_MAC,
|
||||
ATL_PF_LPI_TX_MAC,
|
||||
ATL_PF_LPI_RX_PHY,
|
||||
ATL_PF_LPI_TX_PHY,
|
||||
ATL_PF_STATS_RESET,
|
||||
ATL_PF_STRIP_PAD,
|
||||
ATL_PF_MEDIA_DETECT,
|
||||
};
|
||||
|
||||
enum atl_priv_flag_bits {
|
||||
ATL_DEF_PF_BIT(LPB_SYS_PB),
|
||||
ATL_DEF_PF_BIT(LPB_SYS_DMA),
|
||||
ATL_DEF_PF_BIT(LPB_NET_DMA),
|
||||
ATL_DEF_PF_BIT(LPB_INT_PHY),
|
||||
ATL_DEF_PF_BIT(LPB_EXT_PHY),
|
||||
|
||||
ATL_PF_LPB_MASK = ATL_PF_BIT(LPB_SYS_DMA) | ATL_PF_BIT(LPB_SYS_PB) |
|
||||
ATL_PF_BIT(LPB_NET_DMA) | ATL_PF_BIT(LPB_INT_PHY) |
|
||||
ATL_PF_BIT(LPB_EXT_PHY),
|
||||
|
||||
ATL_DEF_PF_BIT(LPI_RX_MAC),
|
||||
ATL_DEF_PF_BIT(LPI_TX_MAC),
|
||||
ATL_DEF_PF_BIT(LPI_RX_PHY),
|
||||
ATL_DEF_PF_BIT(LPI_TX_PHY),
|
||||
ATL_PF_LPI_MASK = ATL_PF_BIT(LPI_RX_MAC) | ATL_PF_BIT(LPI_TX_MAC) |
|
||||
ATL_PF_BIT(LPI_RX_PHY) | ATL_PF_BIT(LPI_TX_PHY),
|
||||
|
||||
ATL_DEF_PF_BIT(STATS_RESET),
|
||||
|
||||
ATL_DEF_PF_BIT(STRIP_PAD),
|
||||
ATL_DEF_PF_BIT(MEDIA_DETECT),
|
||||
|
||||
ATL_PF_RW_MASK = ATL_PF_LPB_MASK | ATL_PF_BIT(STATS_RESET) |
|
||||
ATL_PF_BIT(STRIP_PAD) | ATL_PF_BIT(MEDIA_DETECT),
|
||||
ATL_PF_RO_MASK = ATL_PF_LPI_MASK,
|
||||
};
|
||||
|
||||
#define ATL_MAX_MTU (16352 - ETH_FCS_LEN - ETH_HLEN)
|
||||
|
||||
#define ATL_MAX_RING_SIZE (8192 - 8)
|
||||
#define ATL_RING_SIZE 4096
|
||||
|
||||
extern const char atl_driver_name[];
|
||||
|
||||
extern const struct ethtool_ops atl_ethtool_ops;
|
||||
|
||||
extern unsigned int atl_max_queues;
|
||||
extern unsigned int atl_max_queues_non_msi;
|
||||
extern unsigned atl_rx_linear;
|
||||
extern unsigned atl_min_intr_delay;
|
||||
extern bool atl_enable_msi;
|
||||
extern bool atl_wq_non_msi;
|
||||
extern unsigned int atl_tx_clean_budget;
|
||||
extern unsigned int atl_tx_free_low;
|
||||
extern unsigned int atl_tx_free_high;
|
||||
|
||||
#define atl_module_param(_name, _type, _mode) \
|
||||
module_param_named(_name, atl_ ## _name, _type, _mode)
|
||||
|
||||
static inline void atl_intr_enable_non_ring(struct atl_nic *nic)
|
||||
{
|
||||
struct atl_hw *hw = &nic->hw;
|
||||
|
||||
atl_intr_enable(hw, hw->non_ring_intr_mask);
|
||||
}
|
||||
|
||||
static inline void atl_intr_disable_non_ring(struct atl_nic *nic)
|
||||
{
|
||||
struct atl_hw *hw = &nic->hw;
|
||||
|
||||
atl_intr_disable(hw, hw->non_ring_intr_mask);
|
||||
}
|
||||
|
||||
netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
int atl_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid);
|
||||
int atl_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid);
|
||||
void atl_set_rx_mode(struct net_device *ndev);
|
||||
int atl_set_features(struct net_device *ndev, netdev_features_t features);
|
||||
void atl_get_stats64(struct net_device *ndev,
|
||||
struct rtnl_link_stats64 *stats);
|
||||
int atl_setup_datapath(struct atl_nic *nic);
|
||||
void atl_clear_datapath(struct atl_nic *nic);
|
||||
int atl_start_rings(struct atl_nic *nic);
|
||||
void atl_stop_rings(struct atl_nic *nic);
|
||||
void atl_clear_rdm_cache(struct atl_nic *nic);
|
||||
void atl_clear_tdm_cache(struct atl_nic *nic);
|
||||
int atl_alloc_rings(struct atl_nic *nic);
|
||||
void atl_free_rings(struct atl_nic *nic);
|
||||
irqreturn_t atl_ring_irq(int irq, void *priv);
|
||||
void atl_ring_work(struct work_struct *work);
|
||||
void atl_start_hw_global(struct atl_nic *nic);
|
||||
int atl_intr_init(struct atl_nic *nic);
|
||||
void atl_intr_release(struct atl_nic *nic);
|
||||
int atl_hw_reset(struct atl_hw *hw);
|
||||
int atl_fw_init(struct atl_hw *hw);
|
||||
int atl_fw_configure(struct atl_hw *hw);
|
||||
int atl_reconfigure(struct atl_nic *nic);
|
||||
void atl_reset_stats(struct atl_nic *nic);
|
||||
void atl_update_global_stats(struct atl_nic *nic);
|
||||
void atl_set_loopback(struct atl_nic *nic, int idx, bool on);
|
||||
void atl_set_intr_mod(struct atl_nic *nic);
|
||||
void atl_update_ntuple_flt(struct atl_nic *nic, int idx);
|
||||
void atl_set_vlan_promisc(struct atl_hw *hw, int promisc);
|
||||
int atl_hwsem_get(struct atl_hw *hw, int idx);
|
||||
void atl_hwsem_put(struct atl_hw *hw, int idx);
|
||||
int __atl_msm_read(struct atl_hw *hw, uint32_t addr, uint32_t *val);
|
||||
int atl_msm_read(struct atl_hw *hw, uint32_t addr, uint32_t *val);
|
||||
int __atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val);
|
||||
int atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val);
|
||||
int atl_update_eth_stats(struct atl_nic *nic);
|
||||
void atl_adjust_eth_stats(struct atl_ether_stats *stats,
|
||||
struct atl_ether_stats *base, bool add);
|
||||
void atl_fwd_release_rings(struct atl_nic *nic);
|
||||
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
|
||||
enum atl_fwd_notify;
|
||||
int atl_fwd_suspend_rings(struct atl_nic *nic);
|
||||
int atl_fwd_resume_rings(struct atl_nic *nic);
|
||||
void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data);
|
||||
#else
|
||||
static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; }
|
||||
static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; }
|
||||
static inline void atl_fwd_notify(struct atl_nic *nic,
|
||||
enum atl_fwd_notify notif, void *data) {}
|
||||
#endif
|
||||
int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay);
|
||||
void atl_refresh_rxfs(struct atl_nic *nic);
|
||||
void atl_schedule_work(struct atl_nic *nic);
|
||||
int atl_hwmon_init(struct atl_nic *nic);
|
||||
void atl_thermal_check(struct atl_hw *hw, bool alarm);
|
||||
int atl_update_thermal(struct atl_hw *hw);
|
||||
int atl_update_thermal_flag(struct atl_hw *hw, int bit, bool val);
|
||||
int atl_verify_thermal_limits(struct atl_hw *hw, struct atl_thermal *thermal);
|
||||
int atl_do_reset(struct atl_nic *nic);
|
||||
int atl_set_media_detect(struct atl_nic *nic, bool on);
|
||||
|
||||
#endif
|
||||
139
drivers/net/ethernet/aquantia/atlantic-fwd/atl_compat.c
Normal file
139
drivers/net/ethernet/aquantia/atlantic-fwd/atl_compat.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
* Portions Copyright (C) various contributors (see specific commit references)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "atl_common.h"
|
||||
#include "atl_ring.h"
|
||||
#include <linux/msi.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#ifdef ATL_COMPAT_PCI_ALLOC_IRQ_VECTORS
|
||||
|
||||
/* From commit aff171641d181ea573380efc3f559c9de4741fc5 */
|
||||
int atl_compat_pci_irq_vector(struct pci_dev *dev, unsigned int nr)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (dev->msix_enabled) {
|
||||
struct msi_desc *entry;
|
||||
int i = 0;
|
||||
|
||||
for_each_pci_msi_entry(entry, dev) {
|
||||
if (i == nr)
|
||||
return entry->irq;
|
||||
i++;
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dev->msi_enabled) {
|
||||
struct msi_desc *entry = first_pci_msi_entry(dev);
|
||||
|
||||
if (WARN_ON_ONCE(nr >= entry->nvec_used))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (WARN_ON_ONCE(nr > 0))
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return dev->irq + nr;
|
||||
}
|
||||
|
||||
int atl_compat_pci_alloc_irq_vectors(struct pci_dev *dev,
|
||||
unsigned int min_vecs, unsigned int max_vecs, unsigned int flags)
|
||||
{
|
||||
int vecs = -ENOSPC;
|
||||
|
||||
if (flags & PCI_IRQ_MSIX) {
|
||||
struct msix_entry *entries;
|
||||
int i;
|
||||
|
||||
entries = kcalloc(max_vecs, sizeof(*entries), GFP_KERNEL);
|
||||
if (!entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < max_vecs; i++)
|
||||
entries[i].entry = i;
|
||||
|
||||
vecs = pci_enable_msix_range(dev, entries, min_vecs, max_vecs);
|
||||
kfree(entries);
|
||||
if (vecs > 0)
|
||||
return vecs;
|
||||
}
|
||||
|
||||
if (flags & PCI_IRQ_MSI) {
|
||||
vecs = pci_enable_msi_range(dev, min_vecs, max_vecs);
|
||||
if (vecs > 0)
|
||||
return vecs;
|
||||
}
|
||||
|
||||
/* use legacy irq if allowed */
|
||||
if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1) {
|
||||
pci_intx(dev, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return vecs;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ATL_COMPAT_PCI_ENABLE_MSIX_RANGE
|
||||
/* from commit 302a2523c277bea0bbe8340312b09507905849ed */
|
||||
int atl_compat_pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
|
||||
{
|
||||
int nvec = maxvec;
|
||||
int rc;
|
||||
|
||||
if (maxvec < minvec)
|
||||
return -ERANGE;
|
||||
|
||||
do {
|
||||
rc = pci_enable_msi_block(dev, nvec);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
} else if (rc > 0) {
|
||||
if (rc < minvec)
|
||||
return -ENOSPC;
|
||||
nvec = rc;
|
||||
}
|
||||
} while (rc);
|
||||
|
||||
return nvec;
|
||||
}
|
||||
|
||||
int atl_compat_pci_enable_msix_range(struct pci_dev *dev,
|
||||
struct msix_entry *entries,
|
||||
int minvec, int maxvec)
|
||||
{
|
||||
int nvec = maxvec;
|
||||
int rc;
|
||||
|
||||
if (maxvec < minvec)
|
||||
return -ERANGE;
|
||||
|
||||
do {
|
||||
rc = pci_enable_msix(dev, entries, nvec);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
} else if (rc > 0) {
|
||||
if (rc < minvec)
|
||||
return -ENOSPC;
|
||||
nvec = rc;
|
||||
}
|
||||
} while (rc);
|
||||
|
||||
return nvec;
|
||||
}
|
||||
|
||||
#endif
|
||||
495
drivers/net/ethernet/aquantia/atlantic-fwd/atl_compat.h
Normal file
495
drivers/net/ethernet/aquantia/atlantic-fwd/atl_compat.h
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
* Portions Copyright (C) various contributors (see specific commit references)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_COMPAT_H_
|
||||
#define _ATL_COMPAT_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#ifndef IS_REACHABLE
|
||||
#define IS_REACHABLE defined
|
||||
#endif
|
||||
|
||||
/* If the kernel is not RHEL / CentOS, then the 2 identifiers below will be
|
||||
* undefined. Define them this way to simplify the checks below.
|
||||
*/
|
||||
#ifndef RHEL_RELEASE_CODE
|
||||
#define RHEL_RELEASE_CODE 0
|
||||
#endif
|
||||
#ifndef RHEL_RELEASE_VERSION
|
||||
#define RHEL_RELEASE_VERSION(a,b) 1
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
|
||||
#define ATL_HAVE_MINMAX_MTU
|
||||
#elif (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)) && \
|
||||
(RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0))
|
||||
#define ndo_change_mtu ndo_change_mtu_rh74
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)
|
||||
/* introduced in commit 3f1ac7a700d039c61d8d8b99f28d605d489a60cf */
|
||||
#define ATL_HAVE_ETHTOOL_KSETTINGS
|
||||
|
||||
/* introduced in commit 72bb68721f80a1441e871b6afc9ab0b3793d5031 */
|
||||
#define ATL_HAVE_IPV6_NTUPLE
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)
|
||||
/* introduced in commit 892311f66f2411b813ca631009356891a0c2b0a1 */
|
||||
#define ATL_HAVE_RXHASH_TYPE
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)
|
||||
/* introduced in commit 3de0b592394d17b2c41a261a6a493a521213f299 */
|
||||
#define ATL_HAVE_ETHTOOL_RXHASH
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
|
||||
|
||||
/* ->ndo_get_stats64 return type was changed to void in commit
|
||||
* bc1f44709cf27fb2a5766cadafe7e2ad5e9cb221. It's safe to just cast
|
||||
* the pointer to avoid the warning because the only place
|
||||
* ->ndo_get_stats64 was invoked before the change ignored the return
|
||||
* value. */
|
||||
#define ATL_COMPAT_CAST_NDO_GET_STATS64
|
||||
|
||||
#endif /* 4.11.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
|
||||
|
||||
/* introduced in commit 94842b4fc4d6b1691cfc86c6f5251f299d27f4ba */
|
||||
#define ETHTOOL_LINK_MODE_2500baseT_Full_BIT 47
|
||||
#define ETHTOOL_LINK_MODE_5000baseT_Full_BIT 48
|
||||
|
||||
#endif /* 4.10.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
|
||||
|
||||
/* from commit 1dff8083a024650c75a9c961c38082473ceae8cf */
|
||||
#define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x)))
|
||||
#endif /* 4.7.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
|
||||
|
||||
/* from commit d31eb342409b24e3d2e1989c775f3361e93acc08 */
|
||||
/* Helpers to hide struct msi_desc implementation details */
|
||||
#define msi_desc_to_dev(desc) (&(desc)->dev.dev)
|
||||
#define dev_to_msi_list(dev) (&to_pci_dev((dev))->msi_list)
|
||||
#define first_msi_entry(dev) \
|
||||
list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list)
|
||||
#define for_each_msi_entry(desc, dev) \
|
||||
list_for_each_entry((desc), dev_to_msi_list((dev)), list)
|
||||
|
||||
#define first_pci_msi_entry(pdev) first_msi_entry(&(pdev)->dev)
|
||||
#define for_each_pci_msi_entry(desc, pdev) \
|
||||
for_each_msi_entry((desc), &(pdev)->dev)
|
||||
|
||||
static inline struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
|
||||
{
|
||||
return desc->dev;
|
||||
}
|
||||
|
||||
#endif /* 3.19.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,3)
|
||||
/* ->xmit_more introduced in commit
|
||||
* 0b725a2ca61bedc33a2a63d0451d528b268cf975 for 3.18-rc1 */
|
||||
static inline int skb_xmit_more(struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8, 2)
|
||||
static inline int skb_xmit_more(struct sk_buff *skb)
|
||||
{
|
||||
return netdev_xmit_more();
|
||||
}
|
||||
#else /* 3.18.0-5.2.0 for vanilla, anything less than 5.2.0 for RHEL */
|
||||
static inline int skb_xmit_more(struct sk_buff *skb)
|
||||
{
|
||||
return skb->xmit_more;
|
||||
}
|
||||
#endif /* 3.18.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) && \
|
||||
RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7, 3)
|
||||
typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
|
||||
struct sk_buff *skb);
|
||||
static inline u16 atlfwd_nl_pick0(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NB! select_queue_fallback_t MUST be defined before #include on RHEL < 7.3 */
|
||||
#include "atl_fwdnl.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) && \
|
||||
RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7, 3)
|
||||
static inline u16 atlfwd_nl_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return atlfwd_nl_select_queue_fallback(dev, skb, NULL, atlfwd_nl_pick0);
|
||||
}
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) && \
|
||||
RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7, 3)
|
||||
static inline u16 atlfwd_nl_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb, void *accel_priv)
|
||||
{
|
||||
return atlfwd_nl_select_queue_fallback(
|
||||
dev, skb, (struct net_device *)accel_priv, atlfwd_nl_pick0);
|
||||
}
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) && \
|
||||
RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8, 0)
|
||||
static inline u16 atlfwd_nl_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb, void *accel_priv,
|
||||
select_queue_fallback_t fallback)
|
||||
{
|
||||
return atlfwd_nl_select_queue_fallback(
|
||||
dev, skb, (struct net_device *)accel_priv, fallback);
|
||||
}
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
|
||||
static inline u16 atlfwd_nl_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct net_device *sb_dev,
|
||||
select_queue_fallback_t fallback)
|
||||
{
|
||||
return atlfwd_nl_select_queue_fallback(dev, skb, sb_dev, fallback);
|
||||
}
|
||||
#else
|
||||
static inline u16 atlfwd_nl_select_queue(struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct net_device *sb_dev)
|
||||
{
|
||||
return atlfwd_nl_select_queue_fallback(dev, skb, sb_dev,
|
||||
netdev_pick_tx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,6)
|
||||
/* introduced in commit 686fef928bba6be13cabe639f154af7d72b63120 */
|
||||
static inline void timer_setup(struct timer_list *timer,
|
||||
void (*callback)(struct timer_list *), unsigned int flags)
|
||||
{
|
||||
setup_timer(timer, (void (*)(unsigned long))callback,
|
||||
(unsigned long)timer);
|
||||
}
|
||||
|
||||
#define from_timer(var, callback_timer, timer_fieldname) \
|
||||
container_of(callback_timer, typeof(*var), timer_fieldname)
|
||||
#endif /* 4.14.0 && RHEL < 7.6 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5)
|
||||
|
||||
#define ATL_COMPAT_PCI_ALLOC_IRQ_VECTORS
|
||||
int atl_compat_pci_alloc_irq_vectors(struct pci_dev *dev,
|
||||
unsigned int min_vecs, unsigned int max_vecs, unsigned int flags);
|
||||
static inline int pci_alloc_irq_vectors(struct pci_dev *dev,
|
||||
unsigned int min_vecs, unsigned int max_vecs, unsigned int flags)
|
||||
{
|
||||
return atl_compat_pci_alloc_irq_vectors(dev, min_vecs,
|
||||
max_vecs, flags);
|
||||
}
|
||||
|
||||
int atl_compat_pci_irq_vector(struct pci_dev *dev, unsigned int nr);
|
||||
static inline int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
|
||||
{
|
||||
return atl_compat_pci_irq_vector(dev, nr);
|
||||
}
|
||||
|
||||
static inline void pci_free_irq_vectors(struct pci_dev *dev)
|
||||
{
|
||||
pci_disable_msix(dev);
|
||||
pci_disable_msi(dev);
|
||||
}
|
||||
|
||||
/* from commit 4fe0d154880bb6eb833cbe84fa6f385f400f0b9c */
|
||||
#define PCI_IRQ_LEGACY (1 << 0) /* allow legacy interrupts */
|
||||
#define PCI_IRQ_MSI (1 << 1) /* allow MSI interrupts */
|
||||
#define PCI_IRQ_MSIX (1 << 2) /* allow MSI-X interrupts */
|
||||
|
||||
#endif /* 4.8.0 && RHEL < 7.5 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,4)
|
||||
/* from commit be9d2e8927cef02076bb7b5b2637cd9f4be2e8df */
|
||||
static inline int
|
||||
pci_request_mem_regions(struct pci_dev *pdev, const char *name)
|
||||
{
|
||||
return pci_request_selected_regions(pdev,
|
||||
pci_select_bars(pdev, IORESOURCE_MEM), name);
|
||||
}
|
||||
#endif /* 4.8.0 && RHEL < 7.4 */
|
||||
|
||||
#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,3)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0)
|
||||
|
||||
/* from commit fe896d1878949ea92ba547587bc3075cc688fb8f */
|
||||
static inline void page_ref_inc(struct page *page)
|
||||
{
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
|
||||
/* introduced in commit 795bb1c00dd338aa0d12f9a7f1f4776fb3160416 */
|
||||
#define napi_consume_skb(__skb, __budget) dev_consume_skb_any(__skb)
|
||||
|
||||
/* from commit 3f1ac7a700d039c61d8d8b99f28d605d489a60cf */
|
||||
#define ETHTOOL_LINK_MODE_10baseT_Half_BIT 0
|
||||
#define ETHTOOL_LINK_MODE_10baseT_Full_BIT 1
|
||||
#define ETHTOOL_LINK_MODE_100baseT_Half_BIT 2
|
||||
#define ETHTOOL_LINK_MODE_100baseT_Full_BIT 3
|
||||
#define ETHTOOL_LINK_MODE_1000baseT_Half_BIT 4
|
||||
#define ETHTOOL_LINK_MODE_1000baseT_Full_BIT 5
|
||||
#define ETHTOOL_LINK_MODE_10000baseT_Full_BIT 12
|
||||
|
||||
/* IPv6 NFC API introduced in commit
|
||||
* 72bb68721f80a1441e871b6afc9ab0b3793d5031 */
|
||||
|
||||
/* Define the IPv6 constants for kernels not supporting IPv6 in the
|
||||
* NFC API to reduce the number of #ifdefs in the code. The constants
|
||||
* themselves may already be defined for RSS hash management API, so
|
||||
* #undef them first */
|
||||
#undef TCP_V6_FLOW
|
||||
#define TCP_V6_FLOW 0x05
|
||||
|
||||
#undef UDP_V6_FLOW
|
||||
#define UDP_V6_FLOW 0x06
|
||||
|
||||
#undef SCTP_V6_FLOW
|
||||
#define SCTP_V6_FLOW 0x07
|
||||
|
||||
#undef IPV6_USER_FLOW
|
||||
#define IPV6_USER_FLOW 0x0e
|
||||
#define IPV4_USER_FLOW IP_USER_FLOW
|
||||
|
||||
#endif /* 4.6.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
|
||||
|
||||
/* introduced in commit c7f5d105495a38ed09e70d825f75d9d7d5407264
|
||||
* stub it */
|
||||
static inline int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#endif /* 4.5.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
|
||||
|
||||
/* introduced in 2f064f3485cd29633ad1b3cfb00cc519509a3d72
|
||||
* The new implementation can't be used directly as it requires
|
||||
* changes to linux/mm code. Use the old check described in the
|
||||
* commit with older kernels insted. It can lead to false positives,
|
||||
* but as we only use it to determine whether the page is re-usable,
|
||||
* the false positives can only decrease performance. */
|
||||
static inline bool page_is_pfmemalloc(struct page *page)
|
||||
{
|
||||
return page->pfmemalloc && !page->mapping;
|
||||
}
|
||||
#endif /* 4.1.0 */
|
||||
|
||||
#endif /* RHEL_RELEASE_CODE < 7.3 */
|
||||
|
||||
#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,2)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
|
||||
#define ETHTOOL_RX_FLOW_SPEC_RING 0x00000000FFFFFFFFLL
|
||||
#define ETHTOOL_RX_FLOW_SPEC_RING_VF 0x000000FF00000000LL
|
||||
#define ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF 32
|
||||
static inline __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie)
|
||||
{
|
||||
return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie;
|
||||
};
|
||||
static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
|
||||
{
|
||||
return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >>
|
||||
ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
|
||||
};
|
||||
#endif /* 4.2.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
|
||||
|
||||
/* renamed in commit df8a39defad46b83694ea6dd868d332976d62cc0 */
|
||||
#define skb_vlan_tag_present(__skb) vlan_tx_tag_present(__skb)
|
||||
#define skb_vlan_tag_get(__skb) vlan_tx_tag_get(__skb)
|
||||
#endif /* 4.0.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
|
||||
|
||||
/* introduced in commit 1077fa36f23e259858caf6f269a47393a5aff523
|
||||
* use plain rmb() for now*/
|
||||
#define dma_rmb() rmb()
|
||||
|
||||
/* from commit 9c0c112422a2a6b06fcddcaf21957676490cebba */
|
||||
static inline int eth_skb_pad(struct sk_buff *skb)
|
||||
{
|
||||
unsigned int len = ETH_ZLEN;
|
||||
unsigned int size = skb->len;
|
||||
|
||||
if (unlikely(size < len)) {
|
||||
len -= size;
|
||||
if (skb_pad(skb, len))
|
||||
return -ENOMEM;
|
||||
__skb_put(skb, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* introduced in commit 71dfda58aaaf4bf6b1bc59f9d8afa635fa1337d4 */
|
||||
#define __dev_alloc_pages(__flags, __order) __skb_alloc_pages(__flags | __GFP_COMP, NULL, __order)
|
||||
|
||||
/* introduced in commit fd11a83dd3630ec6a60f8a702446532c5c7e1991 */
|
||||
#define napi_alloc_skb(__napi, __len) netdev_alloc_skb_ip_align((__napi)->dev, __len)
|
||||
|
||||
/* introduced in commit 3b47d30396bae4f0bd1ff0dbcd7c4f5077e7df4e */
|
||||
#define napi_complete_done(__napi, __work_done) napi_complete(__napi)
|
||||
|
||||
/* introduced in commit bc9ad166e38ae1cdcb5323a8aa45dff834d68bfa */
|
||||
#define napi_schedule_irqoff(__napi) napi_schedule(__napi)
|
||||
|
||||
/* READ_ONCE() / WRITE_ONCE
|
||||
* from commit 230fa253df6352af12ad0a16128760b5cb3f92df with changes
|
||||
* from 43239cbe79fc369f5d2160bd7f69e28b5c50a58c and
|
||||
* 7bd3e239d6c6d1cad276e8f130b386df4234dcd7 */
|
||||
|
||||
/* READ_ONCE / WRTIE_ONCE were also cherry-picked into 3.12.58 as
|
||||
* b5be8baf9e0d5ea035588a0430b2af4989e07572 and
|
||||
* dda458f0183649e8613a62bb59bec4e5acb883aa */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,58) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
|
||||
|
||||
static __always_inline void __read_once_size(volatile void *p, void *res, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1: *(__u8 *)res = *(volatile __u8 *)p; break;
|
||||
case 2: *(__u16 *)res = *(volatile __u16 *)p; break;
|
||||
case 4: *(__u32 *)res = *(volatile __u32 *)p; break;
|
||||
case 8: *(__u64 *)res = *(volatile __u64 *)p; break;
|
||||
default:
|
||||
barrier();
|
||||
__builtin_memcpy((void *)res, (const void *)p, size);
|
||||
barrier();
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
|
||||
case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
|
||||
case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
|
||||
case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
|
||||
default:
|
||||
barrier();
|
||||
__builtin_memcpy((void *)p, (const void *)res, size);
|
||||
barrier();
|
||||
}
|
||||
}
|
||||
|
||||
#define READ_ONCE(x) \
|
||||
({ typeof(x) __val; __read_once_size(&x, &__val, sizeof(__val)); __val; })
|
||||
|
||||
#define WRITE_ONCE(x, val) \
|
||||
({ typeof(x) __val; __val = val; __write_once_size(&x, &__val, sizeof(__val)); __val; })
|
||||
|
||||
#endif /* 3.12.58 */
|
||||
|
||||
#endif /* 3.19.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
|
||||
|
||||
/* introduced in commit 56193d1bce2b2759cb4bdcc00cd05544894a0c90
|
||||
* pull the whole head buffer len for now*/
|
||||
#define eth_get_headlen(__data, __max_len) (__max_len)
|
||||
|
||||
#endif /* 3.18.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
|
||||
|
||||
/* from commit 286ab723d4b83d37deb4017008ef1444a95cfb0d */
|
||||
static inline void ether_addr_copy(u8 *dst, const u8 *src)
|
||||
{
|
||||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
*(u32 *)dst = *(const u32 *)src;
|
||||
*(u16 *)(dst + 4) = *(const u16 *)(src + 4);
|
||||
#else
|
||||
u16 *a = (u16 *)dst;
|
||||
const u16 *b = (const u16 *)src;
|
||||
|
||||
a[0] = b[0];
|
||||
a[1] = b[1];
|
||||
a[2] = b[2];
|
||||
#endif
|
||||
}
|
||||
|
||||
/* introduced in commit e6247027e5173c00efb2084d688d06ff835bc3b0 */
|
||||
#define dev_consume_skb_any(__skb) dev_kfree_skb_any(__skb)
|
||||
|
||||
/* from commit 09323cc479316e046931a2c679932204b36fea6c */
|
||||
enum pkt_hash_types {
|
||||
PKT_HASH_TYPE_NONE, /* Undefined type */
|
||||
PKT_HASH_TYPE_L2, /* Input: src_MAC, dest_MAC */
|
||||
PKT_HASH_TYPE_L3, /* Input: src_IP, dst_IP */
|
||||
PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */
|
||||
};
|
||||
|
||||
static inline void
|
||||
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
|
||||
{
|
||||
skb->l4_rxhash = (type == PKT_HASH_TYPE_L4);
|
||||
skb->rxhash = hash;
|
||||
}
|
||||
|
||||
/* from commit 302a2523c277bea0bbe8340312b09507905849ed */
|
||||
#define ATL_COMPAT_PCI_ENABLE_MSIX_RANGE
|
||||
int atl_compat_pci_enable_msi_range(struct pci_dev *dev, int minvec,
|
||||
int maxvec);
|
||||
int atl_compat_pci_enable_msix_range(struct pci_dev *dev,
|
||||
struct msix_entry *entries, int minvec, int maxvec);
|
||||
|
||||
static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
|
||||
int maxvec)
|
||||
{
|
||||
return atl_compat_pci_enable_msi_range(dev, minvec, maxvec);
|
||||
}
|
||||
|
||||
static inline int pci_enable_msix_range(struct pci_dev *dev,
|
||||
struct msix_entry *entries, int minvec, int maxvec)
|
||||
{
|
||||
return atl_compat_pci_enable_msix_range(dev, entries, minvec, maxvec);
|
||||
}
|
||||
|
||||
#endif /* 3.14.0 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,27)
|
||||
|
||||
/* from commit 4aa806b771d16b810771d86ce23c4c3160888db3
|
||||
* also cherry-picked into 3.12-stable as
|
||||
* 8bac7a35e60ca70c8d12ddbfdf28a8df5a976b2b */
|
||||
static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
|
||||
{
|
||||
int rc = dma_set_mask(dev, mask);
|
||||
if (rc == 0)
|
||||
dma_set_coherent_mask(dev, mask);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* 3.12.27 */
|
||||
|
||||
#endif /* RHEL_RELEASE_CODE < 7.2 */
|
||||
|
||||
#endif
|
||||
159
drivers/net/ethernet/aquantia/atlantic-fwd/atl_desc.h
Normal file
159
drivers/net/ethernet/aquantia/atlantic-fwd/atl_desc.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_DESC_H_
|
||||
#define _ATL_DESC_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
struct __packed atl_tx_ctx {
|
||||
unsigned long long :40; //0
|
||||
unsigned tun_len:8; //40
|
||||
unsigned out_len:16; //48
|
||||
unsigned type:3; //64
|
||||
unsigned idx:1; //67
|
||||
unsigned vlan_tag:16; //68
|
||||
unsigned cmd:4; //84
|
||||
unsigned l2_len:7; //88
|
||||
unsigned l3_len:9; //95
|
||||
unsigned l4_len:8; //104
|
||||
unsigned mss_len:16; //112
|
||||
};
|
||||
|
||||
struct __packed atl_tx_desc {
|
||||
unsigned long long daddr:64; //0
|
||||
unsigned type:3; //64
|
||||
unsigned :1; //67
|
||||
unsigned len:16; //68
|
||||
unsigned dd:1; //84
|
||||
unsigned eop:1; //85
|
||||
unsigned cmd:8; //86
|
||||
unsigned :14; //94
|
||||
unsigned ct_idx:1; //108
|
||||
unsigned ct_en:1; //109
|
||||
unsigned pay_len:18; //110
|
||||
};
|
||||
|
||||
#define ATL_DATA_PER_TXD 16384 // despite ->len being 16 bits
|
||||
|
||||
enum atl_tx_desc_type {
|
||||
tx_desc_type_desc = 1,
|
||||
tx_desc_type_context = 2,
|
||||
};
|
||||
|
||||
enum atl_tx_desc_cmd {
|
||||
tx_desc_cmd_vlan = 1,
|
||||
tx_desc_cmd_fcs = 2,
|
||||
tx_desc_cmd_ipv4cs = 4,
|
||||
tx_desc_cmd_l4cs = 8,
|
||||
tx_desc_cmd_lso = 0x10,
|
||||
tx_desc_cmd_wb = 0x20,
|
||||
};
|
||||
|
||||
enum atl_tx_ctx_cmd {
|
||||
ctx_cmd_snap = 1, // SNAP / ~802.3
|
||||
ctx_cmd_ipv6 = 2, // IPv6 / ~IPv4
|
||||
ctx_cmd_tcp = 4, // TCP / ~UDP
|
||||
};
|
||||
|
||||
struct __packed atl_rx_desc {
|
||||
uint64_t daddr; //0
|
||||
union {
|
||||
struct {
|
||||
unsigned dd:1; //64
|
||||
uint64_t haddr63:63; //65
|
||||
};
|
||||
uint64_t haddr;
|
||||
};
|
||||
};
|
||||
|
||||
struct __packed atl_rx_desc_wb {
|
||||
unsigned rss_type:4; //0
|
||||
unsigned pkt_type:8; //4
|
||||
unsigned rdm_err:1; //12
|
||||
unsigned :6; //13
|
||||
unsigned rx_cntl:2; //19
|
||||
unsigned sph:1; //21
|
||||
unsigned hdr_len:10; //22
|
||||
unsigned rss_hash:32; //32
|
||||
unsigned dd:1; //64
|
||||
unsigned eop:1; //65
|
||||
unsigned rx_stat:4; //66
|
||||
unsigned rx_estat:6; //70
|
||||
unsigned rsc_cnt:4; //76
|
||||
unsigned pkt_len:16; //80
|
||||
unsigned next_desp:16; //96
|
||||
unsigned vlan_tag:16; //112
|
||||
};
|
||||
|
||||
struct __packed atl_rx_desc_hwts_wb {
|
||||
u32 sec_hw;
|
||||
u32 ns;
|
||||
u32 dd:1;
|
||||
u32 rsvd:1;
|
||||
u32 sec_lw0:30;
|
||||
u32 sec_lw1;
|
||||
};
|
||||
|
||||
enum atl_rx_stat {
|
||||
atl_rx_stat_mac_err = 1,
|
||||
atl_rx_stat_ipv4_err = 2,
|
||||
atl_rx_stat_l4_err = 4,
|
||||
atl_rx_stat_l4_valid = 8,
|
||||
atl_rx_stat_err_msk = atl_rx_stat_mac_err | atl_rx_stat_ipv4_err |
|
||||
atl_rx_stat_l4_err,
|
||||
};
|
||||
|
||||
enum atl_rx_estat {
|
||||
atl_rx_estat_vlan_stripped = 1,
|
||||
atl_rx_estat_l2_ucast_match = 2,
|
||||
atl_rx_estat_vxlan = 1 << 2,
|
||||
atl_rx_estat_nvgre = 2 << 2,
|
||||
atl_rx_estat_geneve = 3 << 2,
|
||||
atl_rx_estat_tun_msk = 3 << 2,
|
||||
atl_rx_estat_outer_ipv4_err = 16,
|
||||
atl_rx_estat_outer_ipv4_valid = 32,
|
||||
};
|
||||
|
||||
enum atl_rx_pkt_type {
|
||||
atl_rx_pkt_type_ipv4 = 0,
|
||||
atl_rx_pkt_type_ipv6 = 1,
|
||||
atl_rx_pkt_type_l3_other = 2,
|
||||
atl_rx_pkt_type_l3_arp = 3,
|
||||
atl_rx_pkt_type_l3_msk = 3,
|
||||
atl_rx_pkt_type_tcp = 0 << 2,
|
||||
atl_rx_pkt_type_udp = 1 << 2 ,
|
||||
atl_rx_pkt_type_sctp = 2 << 2,
|
||||
atl_rx_pkt_type_icmp = 3 << 2,
|
||||
atl_rx_pkt_type_l4_msk = ((1 << 3) - 1) << 2,
|
||||
atl_rx_pkt_type_vlan = 1 << 5,
|
||||
atl_rx_pkt_type_dbl_vlan = 2 << 5,
|
||||
atl_rx_pkt_type_vlan_msk = ((1 << 2) - 1) << 5,
|
||||
};
|
||||
|
||||
#else // defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
#error XXX Fix bigendian bitfields
|
||||
#endif // defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
|
||||
union __packed atl_desc {
|
||||
struct atl_rx_desc rx;
|
||||
union {
|
||||
struct atl_rx_desc_wb wb;
|
||||
struct atl_rx_desc_hwts_wb hwts_wb;
|
||||
};
|
||||
struct atl_tx_ctx ctx;
|
||||
struct atl_tx_desc tx;
|
||||
uint8_t raw[16];
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
421
drivers/net/ethernet/aquantia/atlantic-fwd/atl_drviface.h
Normal file
421
drivers/net/ethernet/aquantia/atlantic-fwd/atl_drviface.h
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_DRVIFACE_H_
|
||||
#define _ATL_DRVIFACE_H_
|
||||
|
||||
typedef uint16_t in_port_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
|
||||
struct __attribute__((packed)) offloadKAv4 {
|
||||
uint32_t timeout;
|
||||
in_port_t local_port;
|
||||
in_port_t remote_port;
|
||||
uint8_t remote_mac_addr[6];
|
||||
uint16_t win_size;
|
||||
uint32_t seq_num;
|
||||
uint32_t ack_num;
|
||||
in_addr_t local_ip;
|
||||
in_addr_t remote_ip;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) offloadKAv6 {
|
||||
uint32_t timeout;
|
||||
in_port_t local_port;
|
||||
in_port_t remote_port;
|
||||
uint8_t remote_mac_addr[6];
|
||||
uint16_t win_size;
|
||||
uint32_t seq_num;
|
||||
uint32_t ack_num;
|
||||
struct in6_addr local_ip;
|
||||
struct in6_addr remote_ip;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) offloadIPInfo {
|
||||
uint8_t v4LocalAddrCount;
|
||||
uint8_t v4AddrCount;
|
||||
uint8_t v6LocalAddrCount;
|
||||
uint8_t v6AddrCount;
|
||||
// FW will add the base to the following offset fields and will treat them as pointers.
|
||||
// The offsets are relative to the start of this struct so that the struct is pretty much self-contained
|
||||
// in_addr_t *
|
||||
uint32_t v4AddrOfft;
|
||||
// uint8_t *
|
||||
uint32_t v4PrefixOfft;
|
||||
// in6_addr *
|
||||
uint32_t v6AddrOfft;
|
||||
// uint8_t *
|
||||
uint32_t v6PrefixOfft;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) offloadPortInfo {
|
||||
uint16_t UDPPortCount;
|
||||
uint16_t TCPPortCount;
|
||||
// in_port_t *
|
||||
uint32_t UDPPortOfft; // See the comment in the offloadIPInfo struct
|
||||
// in_port_t *
|
||||
uint32_t TCPPortOfft;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) offloadKAInfo {
|
||||
uint16_t v4KACount;
|
||||
uint16_t v6KACount;
|
||||
uint32_t retryCount;
|
||||
uint32_t retryInterval;
|
||||
// struct offloadKAv4 *
|
||||
uint32_t v4KAOfft; // See the comment in the offloadIPInfo struct
|
||||
// struct offloadKAv6 *
|
||||
uint32_t v6KAOfft;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) offloadRRInfo {
|
||||
uint32_t RRCount;
|
||||
uint32_t RRBufLen;
|
||||
// Offset to RR index table relative to the start of offloadRRInfo struct. The indices
|
||||
// themselves are relative to the start of RR buffer. FW will add the buffer address
|
||||
// and will treat them as pointers.
|
||||
// uint8_t **
|
||||
uint32_t RRIdxOfft;
|
||||
// Offset to the RR buffer relative to the start of offloadRRInfo struct.
|
||||
// uint8_t *
|
||||
uint32_t RRBufOfft;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) offloadInfo {
|
||||
uint32_t version; // = 0 till it stabilizes some
|
||||
uint32_t len; // The whole structure length including the variable-size buf
|
||||
uint8_t macAddr[8];
|
||||
struct offloadIPInfo ips;
|
||||
struct offloadPortInfo ports;
|
||||
struct offloadKAInfo kas;
|
||||
struct offloadRRInfo rrs;
|
||||
uint8_t buf[0];
|
||||
};
|
||||
|
||||
#define FW_PACK_STRUCT __attribute__((packed))
|
||||
|
||||
#define DRV_REQUEST_SIZE 3072
|
||||
#define DRV_MSG_PING 0x01
|
||||
#define DRV_MSG_ARP 0x02
|
||||
#define DRV_MSG_INJECT 0x03
|
||||
#define DRV_MSG_WOL_ADD 0x04
|
||||
#define DRV_MSG_WOL_REMOVE 0x05
|
||||
#define DRV_MSG_ENABLE_WAKEUP 0x06
|
||||
#define DRV_MSG_MSM 0x07
|
||||
#define DRV_MSG_PROVISIONING 0x08
|
||||
#define DRV_MSG_OFFLOAD_ADD 0x09
|
||||
#define DRV_MSG_OFFLOAD_REMOVE 0x0A
|
||||
#define DRV_MSG_MSM_EX 0x0B
|
||||
#define DRV_MSG_SMBUS_PROXY 0x0C
|
||||
|
||||
#define DRV_PROV_APPLY 1
|
||||
#define DRV_PROV_REPLACE 2
|
||||
#define DRV_PROV_ADD 3
|
||||
|
||||
#define FW_RPC_INJECT_PACKET_LEN 1514U
|
||||
|
||||
typedef enum {
|
||||
EVENT_DRIVER_ENABLE_WOL
|
||||
} eDriverEvent;
|
||||
|
||||
//typedef enum {
|
||||
// HOST_UNINIT = 0,
|
||||
// HOST_RESET,
|
||||
// HOST_INIT,
|
||||
// HOST_RESERVED,
|
||||
// HOST_SLEEP,
|
||||
// HOST_INVALID
|
||||
//} hostState_t;
|
||||
|
||||
struct drvMsgPing {
|
||||
uint32_t ping;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
union IPAddr {
|
||||
struct
|
||||
{
|
||||
uint8_t addr[16];
|
||||
} FW_PACK_STRUCT v6;
|
||||
struct
|
||||
{
|
||||
uint8_t padding[12];
|
||||
uint8_t addr[4];
|
||||
} FW_PACK_STRUCT v4;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgArp {
|
||||
uint8_t macAddr[6];
|
||||
uint32_t uIpAddrCnt;
|
||||
struct
|
||||
{
|
||||
union IPAddr addr;
|
||||
union IPAddr mask;
|
||||
} FW_PACK_STRUCT ip[1];
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgInject {
|
||||
uint32_t len;
|
||||
uint8_t packet[FW_RPC_INJECT_PACKET_LEN];
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
enum ndisPmWoLPacket {
|
||||
ndisPMWoLPacketUnspecified = 0,
|
||||
ndisPMWoLPacketBitmapPattern,
|
||||
ndisPMWoLPacketMagicPacket,
|
||||
ndisPMWoLPacketIPv4TcpSyn,
|
||||
ndisPMWoLPacketIPv6TcpSyn,
|
||||
ndisPMWoLPacketEapolRequestIdMessage,
|
||||
ndisPMWoLPacketMaximum
|
||||
};
|
||||
|
||||
enum aqPmWoLPacket {
|
||||
aqPMWoLPacketUnspecified = 0x10000,
|
||||
aqPMWoLPacketArp,
|
||||
aqPMWoLPacketIPv4Ping,
|
||||
aqPMWoLPacketIpv6NsPacket,
|
||||
aqPMWoLPacketIpv6Ping,
|
||||
aqPMWoLReasonLinkUp,
|
||||
aqPMWoLReasonLinkDown,
|
||||
aqPMWoLPacketMaximum
|
||||
};
|
||||
|
||||
enum ndisPmProtocolOffloadType {
|
||||
ndisPMProtocolOffloadIdUnspecified,
|
||||
ndisPMProtocolOffloadIdIPv4ARP,
|
||||
ndisPMProtocolOffloadIdIPv6NS,
|
||||
ndisPMProtocolOffload80211RSNRekey,
|
||||
ndisPMProtocolOffloadIdMaximum
|
||||
};
|
||||
|
||||
struct drvMsgEnableWakeup {
|
||||
uint32_t patternMaskWindows;
|
||||
uint32_t patternMaskAquantia;
|
||||
uint32_t patternMaskOther;
|
||||
uint32_t offloadsMaskWindows;
|
||||
uint32_t offloadsMaskAquantia;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddIpv4TcpSynWoLPacketParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4SourceAddress;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4DestAddress;
|
||||
union {
|
||||
uint8_t v8[2];
|
||||
uint16_t v16;
|
||||
} TCPSourcePortNumber;
|
||||
union {
|
||||
uint8_t v8[2];
|
||||
uint16_t v16;
|
||||
} TCPDestPortNumber;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddIpv6TcpSynWoLPacketParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} IPv6SourceAddress;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} IPv6DestAddress;
|
||||
union {
|
||||
uint8_t v8[2];
|
||||
uint16_t v16;
|
||||
} TCPSourcePortNumber;
|
||||
union {
|
||||
uint8_t v8[2];
|
||||
uint16_t v16;
|
||||
} TCPDestPortNumber;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddIpv4PingWoLPacketParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4SourceAddress;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4DestAddress;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddIpv6PingWoLPacketParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} IPv6SourceAddress;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} IPv6DestAddress;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddEapolRequestIdMessageWoLPacketParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4SourceAddress;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4DestAddress;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddBitmapPattern {
|
||||
uint32_t Flags;
|
||||
uint32_t MaskOffset;
|
||||
uint32_t MaskSize;
|
||||
uint32_t PatternOffset;
|
||||
uint32_t PatternSize;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddMagicPacketPattern {
|
||||
uint8_t macAddr[6];
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddArpWoLPacketParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[4];
|
||||
uint32_t v32;
|
||||
} IPv4Address;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddLinkUpWoLParameters {
|
||||
uint32_t timeout;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAddLinkDownWoLParameters {
|
||||
uint32_t timeout;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLAdd {
|
||||
uint32_t priority; // Currently not used
|
||||
uint32_t packetType; // One of ndisPmWoLPacket or aqPmWoLPacket
|
||||
uint32_t patternId; // Id to save - will be used in remove message
|
||||
uint32_t nextWoLPatternOffset; // For chaining multiple additions in one request
|
||||
|
||||
// Depends on `parrernId`
|
||||
union _WOL_PATTERN {
|
||||
struct drvMsgWoLAddIpv4TcpSynWoLPacketParameters wolIpv4TcpSyn;
|
||||
struct drvMsgWoLAddIpv6TcpSynWoLPacketParameters wolIpv6TcpSyn;
|
||||
struct drvMsgWoLAddEapolRequestIdMessageWoLPacketParameters wolEapolRequestIdMessage;
|
||||
struct drvMsgWoLAddBitmapPattern wolBitmap;
|
||||
struct drvMsgWoLAddMagicPacketPattern wolMagicPacket;
|
||||
struct drvMsgWoLAddIpv4PingWoLPacketParameters wolIpv4Ping;
|
||||
struct drvMsgWoLAddIpv6PingWoLPacketParameters wolIpv6Ping;
|
||||
struct drvMsgWoLAddArpWoLPacketParameters wolArp;
|
||||
struct drvMsgWoLAddLinkUpWoLParameters wolLinkUpReason;
|
||||
struct drvMsgWoLAddLinkDownWoLParameters wolLinkDownReason;
|
||||
} wolPattern;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgWoLRemove {
|
||||
uint32_t id;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct ipv4ArpParameters {
|
||||
uint32_t flags;
|
||||
uint8_t remoteIPv4Address[4];
|
||||
uint8_t hostIPv4Address[4];
|
||||
uint8_t macAddress[6];
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct ipv6NsParameters {
|
||||
uint32_t flags;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} remoteIPv6Address;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} solicitedNodeIPv6Address;
|
||||
union {
|
||||
uint8_t v8[16];
|
||||
uint32_t v32[4];
|
||||
} targetIPv6Addresses[2];
|
||||
uint8_t macAddress[6];
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgOffloadAdd {
|
||||
uint32_t priority;
|
||||
uint32_t protocolOffloadType;
|
||||
uint32_t protocolOffloadId;
|
||||
uint32_t nextProtocolOffloadOffset;
|
||||
union {
|
||||
struct ipv4ArpParameters ipv4Arp;
|
||||
struct ipv6NsParameters ipv6Ns;
|
||||
} wolOffload;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsgOffloadRemove {
|
||||
uint32_t id;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
struct drvMsmSettings {
|
||||
uint32_t msmReg054;
|
||||
uint32_t msmReg058;
|
||||
uint32_t msmReg05c;
|
||||
uint32_t msmReg060;
|
||||
uint32_t msmReg064;
|
||||
uint32_t msmReg068;
|
||||
uint32_t msmReg06c;
|
||||
uint32_t msmReg070;
|
||||
uint32_t flags; // Valid for message DRV_MSG_MSM_EX only
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
//struct drvMsgProvisioning {
|
||||
// uint32_t command;
|
||||
// uint32_t len;
|
||||
// provList_t list;
|
||||
//} FW_PACK_STRUCT;
|
||||
|
||||
//struct drvMsgSmbusProxy {
|
||||
// uint32_t typeMsg;
|
||||
// union {
|
||||
// struct smbusProxyWrite smbWrite;
|
||||
// struct smbusProxyRead smbRead;
|
||||
// struct smbusProxyGetStatus smbStatus;
|
||||
// struct smbusProxyReadResp smbReadResp;
|
||||
// } FW_PACK_STRUCT;
|
||||
//} FW_PACK_STRUCT;
|
||||
|
||||
struct drvIface {
|
||||
uint32_t msgId;
|
||||
|
||||
union {
|
||||
struct drvMsgPing msgPing;
|
||||
struct drvMsgArp msgArp;
|
||||
struct drvMsgInject msgInject;
|
||||
struct drvMsgWoLAdd msgWoLAdd;
|
||||
struct drvMsgWoLRemove msgWoLRemove;
|
||||
struct drvMsgEnableWakeup msgEnableWakeup;
|
||||
struct drvMsmSettings msgMsm;
|
||||
// struct drvMsgProvisioning msgProvisioning;
|
||||
struct drvMsgOffloadAdd msgOffloadAdd;
|
||||
struct drvMsgOffloadRemove msgOffloadRemove;
|
||||
// struct drvMsgSmbusProxy msgSmbusProxy;
|
||||
struct offloadInfo fw2xOffloads;
|
||||
} FW_PACK_STRUCT;
|
||||
} FW_PACK_STRUCT;
|
||||
|
||||
#endif
|
||||
3108
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c
Normal file
3108
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c
Normal file
File diff suppressed because it is too large
Load diff
25
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.h
Normal file
25
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_ETHTOOL_H_
|
||||
#define _ATL_ETHTOOL_H_
|
||||
|
||||
enum atl_rxf_type {
|
||||
ATL_RXF_VLAN = 0,
|
||||
ATL_RXF_ETYPE,
|
||||
ATL_RXF_NTUPLE,
|
||||
ATL_RXF_FLEX,
|
||||
};
|
||||
|
||||
s8 atl_reserve_filter(enum atl_rxf_type type);
|
||||
void atl_release_filter(enum atl_rxf_type type);
|
||||
|
||||
#endif
|
||||
1215
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c
Normal file
1215
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c
Normal file
File diff suppressed because it is too large
Load diff
304
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h
Normal file
304
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_FW_H_
|
||||
#define _ATL_FW_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
struct atl_hw;
|
||||
struct atl_nic;
|
||||
|
||||
struct atl_mcp {
|
||||
uint32_t fw_rev;
|
||||
struct atl_fw_ops *ops;
|
||||
uint32_t fw_stat_addr;
|
||||
uint32_t rpc_addr;
|
||||
uint32_t fw_settings_addr;
|
||||
uint32_t fw_settings_len;
|
||||
uint32_t req_high;
|
||||
uint32_t req_high_mask; /* Clears link rate-dependend bits */
|
||||
uint32_t caps_low;
|
||||
uint32_t caps_high;
|
||||
uint32_t caps_ex;
|
||||
struct mutex lock;
|
||||
unsigned long next_wdog;
|
||||
bool wdog_disabled;
|
||||
uint16_t phy_hbeat;
|
||||
uint32_t *fw_cfg_dump;
|
||||
};
|
||||
|
||||
struct atl_link_type {
|
||||
unsigned speed;
|
||||
bool duplex;
|
||||
unsigned ethtool_idx;
|
||||
uint32_t fw_bits[2];
|
||||
const char *name;
|
||||
};
|
||||
|
||||
enum atl_link_type_index {
|
||||
atl_link_type_idx_10m,
|
||||
atl_link_type_idx_100m,
|
||||
atl_link_type_idx_1g,
|
||||
atl_link_type_idx_2p5g,
|
||||
atl_link_type_idx_5g,
|
||||
atl_link_type_idx_10g,
|
||||
atl_link_type_idx_10m_half,
|
||||
atl_link_type_idx_100m_half,
|
||||
atl_link_type_idx_1g_half,
|
||||
};
|
||||
|
||||
extern struct atl_link_type atl_link_types[];
|
||||
extern const int atl_num_rates;
|
||||
|
||||
struct atl_fw2_thermal_cfg {
|
||||
uint32_t msg_id;
|
||||
uint8_t shutdown_temp;
|
||||
uint8_t high_temp;
|
||||
uint8_t normal_temp;
|
||||
};
|
||||
|
||||
#define atl_for_each_rate(idx, type) \
|
||||
for (idx = 0, type = atl_link_types; \
|
||||
idx < atl_num_rates; \
|
||||
idx++, type++)
|
||||
|
||||
#define atl_define_bit(_name, _bit) \
|
||||
_name ## _shift = (_bit), \
|
||||
_name = BIT(_name ## _shift),
|
||||
|
||||
enum atl_fw2_opts {
|
||||
atl_define_bit(atl_fw2_pause, 3)
|
||||
atl_define_bit(atl_fw2_asym_pause, 4)
|
||||
atl_fw2_pause_mask = atl_fw2_pause | atl_fw2_asym_pause,
|
||||
atl_define_bit(atl_fw2_fw_request, 12)
|
||||
atl_define_bit(atl_fw2_macsec, 15)
|
||||
atl_define_bit(atl_fw2_wake_on_link, 16)
|
||||
atl_define_bit(atl_fw2_wake_on_link_force, 17)
|
||||
atl_define_bit(atl_fw2_phy_temp, 18)
|
||||
atl_define_bit(atl_fw2_set_thermal, 21)
|
||||
atl_define_bit(atl_fw2_link_drop, 22)
|
||||
atl_define_bit(atl_fw2_nic_proxy, 0x17)
|
||||
atl_define_bit(atl_fw2_wol, 0x18)
|
||||
atl_define_bit(atl_fw2_thermal_alarm, 29)
|
||||
atl_define_bit(atl_fw2_statistics, 30)
|
||||
};
|
||||
|
||||
enum atl_fw2_ex_caps {
|
||||
atl_define_bit(atl_fw2_ex_caps_phy_ptp_en, 16)
|
||||
atl_define_bit(atl_fw2_ex_caps_ptp_gpio_en, 20)
|
||||
atl_define_bit(atl_fw2_ex_caps_phy_ctrl_ts_pin, 22)
|
||||
atl_define_bit(atl_fw2_ex_caps_wol_ex, 23)
|
||||
atl_define_bit(atl_fw2_ex_caps_mac_heartbeat, 25)
|
||||
atl_define_bit(atl_fw2_ex_caps_msm_settings_apply, 26)
|
||||
};
|
||||
|
||||
enum atl_fw2_wol_ex {
|
||||
atl_define_bit(atl_fw2_wol_ex_wake_on_link_keep_rate, 0)
|
||||
atl_define_bit(atl_fw2_wol_ex_wake_on_magic_keep_rate, 1)
|
||||
};
|
||||
|
||||
enum atl_fw2_stat_offt {
|
||||
atl_fw2_stat_phy_hbeat = 0x4c,
|
||||
atl_fw2_stat_temp = 0x50,
|
||||
atl_fw2_stat_ptp_offset = 0x64,
|
||||
atl_fw2_stat_lcaps = 0x84,
|
||||
atl_fw2_stat_settings_addr = 0x10c,
|
||||
atl_fw2_stat_settings_len = 0x110,
|
||||
atl_fw2_stat_caps_ex = 0x114,
|
||||
atl_fw2_stat_gpio_pin = 0x118,
|
||||
};
|
||||
|
||||
enum atl_fw2_settings_offt {
|
||||
atl_fw2_setings_msm_opts = 0x90,
|
||||
atl_fw2_setings_media_detect = 0x98,
|
||||
atl_fw2_setings_wol_ex = 0x9c,
|
||||
};
|
||||
|
||||
enum atl_fw2_msm_opts {
|
||||
atl_define_bit(atl_fw2_settings_msm_opts_strip_pad, 0)
|
||||
};
|
||||
|
||||
enum atl_fw2_fw_request {
|
||||
atl_fw2_msm_settings_apply = 0x20,
|
||||
};
|
||||
|
||||
enum atl_fc_mode {
|
||||
atl_fc_none = 0,
|
||||
atl_define_bit(atl_fc_rx, 0)
|
||||
atl_define_bit(atl_fc_tx, 1)
|
||||
atl_fc_full = atl_fc_rx | atl_fc_tx,
|
||||
};
|
||||
|
||||
enum atl_thermal_flags {
|
||||
atl_define_bit(atl_thermal_monitor, 0)
|
||||
atl_define_bit(atl_thermal_throttle, 1)
|
||||
atl_define_bit(atl_thermal_ignore_lims, 2)
|
||||
};
|
||||
|
||||
struct atl_fc_state {
|
||||
enum atl_fc_mode req;
|
||||
enum atl_fc_mode prev_req;
|
||||
enum atl_fc_mode cur;
|
||||
};
|
||||
|
||||
enum atl_wake_flags {
|
||||
atl_fw_wake_on_link = WAKE_PHY,
|
||||
atl_fw_wake_on_magic = WAKE_MAGIC,
|
||||
atl_fw_wake_on_link_rtpm = BIT(10),
|
||||
};
|
||||
|
||||
#define ATL_EEE_BIT_OFFT 16
|
||||
#define ATL_EEE_MASK ~(BIT(ATL_EEE_BIT_OFFT) - 1)
|
||||
|
||||
struct atl_link_state{
|
||||
/* The following three bitmaps use alt_link_types[] indices
|
||||
* as link bit positions. Conversion to/from ethtool bits is
|
||||
* done in atl_ethtool.c. */
|
||||
unsigned supported;
|
||||
unsigned advertized;
|
||||
unsigned lp_advertized;
|
||||
unsigned prev_advertized;
|
||||
int lp_lowest; /* Idx of lowest rate advertized by
|
||||
* link partner in atl_link_types[] */
|
||||
int throttled_to; /* Idx of the rate we're throttled to */
|
||||
bool force_off;
|
||||
bool thermal_throttled;
|
||||
bool autoneg;
|
||||
bool eee;
|
||||
bool eee_enabled;
|
||||
bool ptp_available;
|
||||
bool ptp_datapath_up;
|
||||
struct atl_link_type *link;
|
||||
struct atl_fc_state fc;
|
||||
};
|
||||
|
||||
enum macsec_msg_type {
|
||||
macsec_cfg_msg = 0,
|
||||
macsec_add_rx_sc_msg,
|
||||
macsec_add_tx_sc_msg,
|
||||
macsec_add_rx_sa_msg,
|
||||
macsec_add_tx_sa_msg,
|
||||
macsec_get_stats_msg,
|
||||
};
|
||||
|
||||
struct __packed macsec_cfg_request {
|
||||
u32 enabled;
|
||||
u32 egress_threshold;
|
||||
u32 ingress_threshold;
|
||||
u32 interrupts_enabled;
|
||||
};
|
||||
|
||||
struct __packed macsec_msg_fw_request {
|
||||
u32 msg_id; /* not used */
|
||||
u32 msg_type;
|
||||
|
||||
struct macsec_cfg_request cfg;
|
||||
};
|
||||
|
||||
struct __packed macsec_msg_fw_response {
|
||||
u32 result;
|
||||
};
|
||||
|
||||
enum atl_gpio_pin_function {
|
||||
GPIO_PIN_FUNCTION_NC,
|
||||
GPIO_PIN_FUNCTION_VAUX_ENABLE,
|
||||
GPIO_PIN_FUNCTION_EFUSE_BURN_ENABLE,
|
||||
GPIO_PIN_FUNCTION_SFP_PLUS_DETECT,
|
||||
GPIO_PIN_FUNCTION_TX_DISABLE,
|
||||
GPIO_PIN_FUNCTION_RATE_SEL_0,
|
||||
GPIO_PIN_FUNCTION_RATE_SEL_1,
|
||||
GPIO_PIN_FUNCTION_TX_FAULT,
|
||||
GPIO_PIN_FUNCTION_PTP0,
|
||||
GPIO_PIN_FUNCTION_PTP1,
|
||||
GPIO_PIN_FUNCTION_PTP2,
|
||||
GPIO_PIN_FUNCTION_SIZE
|
||||
};
|
||||
|
||||
struct __packed atl_ptp_offset_info {
|
||||
u16 ingress_100;
|
||||
u16 egress_100;
|
||||
u16 ingress_1000;
|
||||
u16 egress_1000;
|
||||
u16 ingress_2500;
|
||||
u16 egress_2500;
|
||||
u16 ingress_5000;
|
||||
u16 egress_5000;
|
||||
u16 ingress_10000;
|
||||
u16 egress_10000;
|
||||
};
|
||||
|
||||
enum ptp_msg_type {
|
||||
ptp_gpio_ctrl_msg = 0x11,
|
||||
ptp_adj_freq_msg = 0x12,
|
||||
ptp_adj_clock_msg = 0x13,
|
||||
};
|
||||
|
||||
struct __packed ptp_gpio_ctrl {
|
||||
u32 index;
|
||||
u32 period;
|
||||
u64 start;
|
||||
};
|
||||
|
||||
struct __packed ptp_adj_freq {
|
||||
u32 ns_mac;
|
||||
u32 fns_mac;
|
||||
u32 ns_phy;
|
||||
u32 fns_phy;
|
||||
u32 mac_ns_adj;
|
||||
u32 mac_fns_adj;
|
||||
};
|
||||
|
||||
struct __packed ptp_adj_clock {
|
||||
u32 ns;
|
||||
u32 sec;
|
||||
int sign;
|
||||
};
|
||||
|
||||
struct __packed ptp_msg_fw_request {
|
||||
u32 msg_id;
|
||||
union {
|
||||
struct ptp_gpio_ctrl gpio_ctrl;
|
||||
struct ptp_adj_freq adj_freq;
|
||||
struct ptp_adj_clock adj_clock;
|
||||
};
|
||||
};
|
||||
|
||||
struct atl_fw_ops {
|
||||
void (*set_link)(struct atl_hw *hw, bool force);
|
||||
struct atl_link_type *(*check_link)(struct atl_hw *hw);
|
||||
int (*__wait_fw_init)(struct atl_hw *hw);
|
||||
int (*__get_link_caps)(struct atl_hw *hw);
|
||||
int (*restart_aneg)(struct atl_hw *hw);
|
||||
void (*set_default_link)(struct atl_hw *hw);
|
||||
int (*enable_wol)(struct atl_hw *hw, unsigned int wol_mode);
|
||||
int (*get_phy_temperature)(struct atl_hw *hw, int *temp);
|
||||
int (*dump_cfg)(struct atl_hw *hw);
|
||||
int (*restore_cfg)(struct atl_hw *hw);
|
||||
int (*set_phy_loopback)(struct atl_nic *nic, u32 mode);
|
||||
int (*set_mediadetect)(struct atl_hw *hw, bool on);
|
||||
int (*set_pad_stripping)(struct atl_hw *hw, bool on);
|
||||
int (*send_macsec_req)(struct atl_hw *hw,
|
||||
struct macsec_msg_fw_request *msg,
|
||||
struct macsec_msg_fw_response *resp);
|
||||
int (*__get_hbeat)(struct atl_hw *hw, uint16_t *hbeat);
|
||||
int (*get_mac_addr)(struct atl_hw *hw, uint8_t *buf);
|
||||
int (*update_thermal)(struct atl_hw *hw);
|
||||
int (*send_ptp_req)(struct atl_hw *hw, struct ptp_msg_fw_request *msg);
|
||||
void (*set_ptp)(struct atl_hw *hw, bool on);
|
||||
int (*deinit)(struct atl_hw *hw);
|
||||
};
|
||||
|
||||
int atl_read_mcp_word(struct atl_hw *hw, uint32_t offt, uint32_t *val);
|
||||
|
||||
#endif
|
||||
905
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c
Normal file
905
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c
Normal file
|
|
@ -0,0 +1,905 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2018 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include "atl_common.h"
|
||||
#include "atl_desc.h"
|
||||
|
||||
static const char *atl_fwd_dir_str(struct atl_fwd_ring *ring)
|
||||
{
|
||||
return ring->flags & ATL_FWR_TX ? "Tx" : "Rx";
|
||||
}
|
||||
|
||||
static int atl_fwd_ring_tx(struct atl_fwd_ring *ring)
|
||||
{
|
||||
return !!(ring->flags & ATL_FWR_TX);
|
||||
}
|
||||
|
||||
static void *atl_fwd_frag_vaddr(struct atl_fwd_buf_frag *frag,
|
||||
struct atl_fwd_mem_ops *ops)
|
||||
{
|
||||
if (ops->alloc_buf)
|
||||
return frag->buf;
|
||||
|
||||
return page_to_virt(frag->page);
|
||||
}
|
||||
|
||||
static int atl_fwd_get_frag(struct atl_fwd_ring *ring, int idx)
|
||||
{
|
||||
struct page *pg;
|
||||
dma_addr_t daddr = 0;
|
||||
struct device *dev = &ring->nic->hw.pdev->dev;
|
||||
struct atl_fwd_bufs *bufs = ring->bufs;
|
||||
struct atl_fwd_buf_frag *frag = &bufs->frags[idx];
|
||||
struct atl_fwd_mem_ops *ops = ring->mem_ops;
|
||||
|
||||
if (ops->alloc_buf) {
|
||||
void *buf = ops->alloc_buf(dev, bufs->frag_size,
|
||||
&daddr, GFP_KERNEL, ops);
|
||||
|
||||
if (!IS_ERR_OR_NULL(buf)) {
|
||||
frag->buf = buf;
|
||||
frag->daddr = daddr;
|
||||
return 0;
|
||||
} else
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
|
||||
pg = __dev_alloc_pages(GFP_KERNEL, bufs->order);
|
||||
if (!pg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(ring->flags & ATL_FWR_DONT_DMA_MAP)) {
|
||||
daddr = dma_map_page(dev, pg, 0, PAGE_SIZE << bufs->order,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
if (dma_mapping_error(dev, daddr)) {
|
||||
__free_pages(pg, bufs->order);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
frag->daddr = daddr;
|
||||
frag->page = pg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atl_fwd_free_bufs(struct atl_fwd_ring *ring)
|
||||
{
|
||||
struct atl_nic *nic = ring->nic;
|
||||
struct device *dev = &nic->hw.pdev->dev;
|
||||
struct atl_fwd_bufs *bufs = ring->bufs;
|
||||
struct atl_fwd_mem_ops *ops = ring->mem_ops;
|
||||
int ring_size = ring->hw.size;
|
||||
int order;
|
||||
size_t frag_size;
|
||||
int i;
|
||||
|
||||
if (!bufs)
|
||||
return;
|
||||
|
||||
order = bufs->order;
|
||||
frag_size = bufs->frag_size;
|
||||
|
||||
if (bufs->daddr_vec)
|
||||
dma_free_coherent(dev, ring_size * sizeof(dma_addr_t),
|
||||
bufs->daddr_vec, bufs->daddr_vec_base);
|
||||
|
||||
if (ring->flags & ATL_FWR_WANT_VIRT_BUF_VEC)
|
||||
kfree(bufs->vaddr_vec);
|
||||
|
||||
for (i = 0; i < bufs->num_pages; i++) {
|
||||
struct atl_fwd_buf_frag *frag = &bufs->frags[i];
|
||||
|
||||
if (ops->free_buf) {
|
||||
if (frag->buf)
|
||||
ops->free_buf(frag->buf, dev, frag_size,
|
||||
frag->daddr, ops);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frag->page) {
|
||||
if (!(ring->flags & ATL_FWR_DONT_DMA_MAP))
|
||||
dma_unmap_page(dev, frag->daddr,
|
||||
PAGE_SIZE << order,
|
||||
DMA_FROM_DEVICE);
|
||||
__free_pages(frag->page, order);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(bufs);
|
||||
ring->bufs = NULL;
|
||||
}
|
||||
|
||||
static int atl_fwd_alloc_bufs(struct atl_fwd_ring *ring, int order)
|
||||
{
|
||||
struct atl_nic *nic = ring->nic;
|
||||
int flags = ring->flags;
|
||||
int ring_size = ring->hw.size;
|
||||
int buf_size = ring->buf_size;
|
||||
struct device *dev = &nic->hw.pdev->dev;
|
||||
struct atl_fwd_mem_ops *ops = ring->mem_ops;
|
||||
struct atl_fwd_buf_frag *frag;
|
||||
struct atl_fwd_bufs *bufs;
|
||||
int num_pages, i;
|
||||
int ret;
|
||||
unsigned int pg_off = 0;
|
||||
bool want_dvec = !!(flags & ATL_FWR_WANT_DMA_BUF_VEC);
|
||||
bool want_vvec = !!(flags & ATL_FWR_WANT_VIRT_BUF_VEC);
|
||||
size_t frag_size;
|
||||
|
||||
if (!(flags & ATL_FWR_ALLOC_BUFS))
|
||||
return 0;
|
||||
|
||||
if (flags & ATL_FWR_CONTIG_BUFS) {
|
||||
frag_size = buf_size * ring_size;
|
||||
order = get_order(frag_size);
|
||||
num_pages = 1;
|
||||
} else {
|
||||
int bufs_per_page;
|
||||
|
||||
frag_size = PAGE_SIZE << order;
|
||||
bufs_per_page = frag_size / buf_size;
|
||||
num_pages = ring_size / bufs_per_page +
|
||||
!!(ring_size % bufs_per_page);
|
||||
}
|
||||
|
||||
bufs = kzalloc(sizeof(*bufs) +
|
||||
sizeof(struct atl_fwd_buf_frag) * num_pages,
|
||||
GFP_KERNEL);
|
||||
if (!bufs) {
|
||||
atl_nic_err("%s: couldn't alloc buffers structure\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ring->bufs = bufs;
|
||||
bufs->num_pages = num_pages;
|
||||
bufs->order = order;
|
||||
bufs->frag_size = frag_size;
|
||||
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
ret = atl_fwd_get_frag(ring, i);
|
||||
if (ret) {
|
||||
atl_nic_err("%s: couldn't alloc buffer page (order %d)\n",
|
||||
__func__, order);
|
||||
goto free;
|
||||
}
|
||||
}
|
||||
|
||||
frag = &bufs->frags[0];
|
||||
|
||||
if (want_dvec) {
|
||||
ret = -ENOMEM;
|
||||
bufs->daddr_vec = dma_alloc_coherent(dev,
|
||||
ring_size * sizeof(dma_addr_t),
|
||||
&bufs->daddr_vec_base, GFP_KERNEL);
|
||||
if (!bufs->daddr_vec) {
|
||||
atl_nic_err("%s: couldn't alloc DMA addr table\n",
|
||||
__func__);
|
||||
goto free;
|
||||
}
|
||||
} else
|
||||
bufs->daddr_vec_base = frag[0].daddr;
|
||||
|
||||
if (want_vvec) {
|
||||
ret = -ENOMEM;
|
||||
bufs->vaddr_vec = kcalloc(ring_size, sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
if (!bufs->vaddr_vec) {
|
||||
atl_nic_err("%s: couldn't alloc virtual addr table\n",
|
||||
__func__);
|
||||
goto free;
|
||||
}
|
||||
} else
|
||||
bufs->vaddr_vec = atl_fwd_frag_vaddr(frag, ops);
|
||||
|
||||
if (!(want_dvec || want_vvec))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ring_size; i++) {
|
||||
dma_addr_t daddr = frag->daddr + pg_off;
|
||||
|
||||
if (want_dvec)
|
||||
bufs->daddr_vec[i] = daddr;
|
||||
if (want_vvec)
|
||||
bufs->vaddr_vec[i] = atl_fwd_frag_vaddr(frag, ops) +
|
||||
pg_off;
|
||||
|
||||
pg_off += buf_size;
|
||||
if (pg_off + buf_size <= frag_size)
|
||||
continue;
|
||||
|
||||
frag++;
|
||||
pg_off = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
atl_fwd_free_bufs(ring);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void atl_fwd_update_im(struct atl_fwd_ring *ring)
|
||||
{
|
||||
struct atl_hw *hw = &ring->nic->hw;
|
||||
int idx = ring->idx;
|
||||
uint32_t addr, tx_reg;
|
||||
|
||||
if (hw->chip_id == ATL_ANTIGUA)
|
||||
tx_reg = ATL2_TX_INTR_MOD_CTRL(idx);
|
||||
else
|
||||
tx_reg = ATL_TX_INTR_MOD_CTRL(idx);
|
||||
addr = atl_fwd_ring_tx(ring) ? tx_reg :
|
||||
ATL_RX_INTR_MOD_CTRL(idx);
|
||||
|
||||
atl_write(hw, addr, (ring->intr_mod_max / 2) << 0x10 |
|
||||
(ring->intr_mod_min / 2) << 8 | 2);
|
||||
}
|
||||
|
||||
static void atl_fwd_init_descr(struct atl_fwd_ring *fwd_ring)
|
||||
{
|
||||
struct atl_hw_ring *ring = &fwd_ring->hw;
|
||||
int dir_tx = atl_fwd_ring_tx(fwd_ring);
|
||||
struct atl_fwd_buf_frag *frag = NULL;
|
||||
int buf_size = fwd_ring->buf_size;
|
||||
int ring_size = ring->size;
|
||||
size_t frag_size = 0;
|
||||
unsigned int pg_off;
|
||||
int i;
|
||||
|
||||
memset(ring->descs, 0, ring_size * sizeof(*ring->descs));
|
||||
|
||||
if (!(fwd_ring->flags & ATL_FWR_ALLOC_BUFS))
|
||||
return;
|
||||
|
||||
frag = &fwd_ring->bufs->frags[0];
|
||||
frag_size = fwd_ring->bufs->frag_size;
|
||||
|
||||
if (!(fwd_ring->flags & ATL_FWR_DONT_DMA_MAP)) {
|
||||
for (pg_off = 0, i = 0; i < ring_size; i++) {
|
||||
union atl_desc *desc = &ring->descs[i];
|
||||
dma_addr_t daddr = frag->daddr + pg_off;
|
||||
|
||||
if (dir_tx) {
|
||||
/* init both daddr and dd for both cases:
|
||||
* daddr for head pointer writeback
|
||||
* dd for the descriptor writeback */
|
||||
desc->tx.daddr = daddr;
|
||||
desc->tx.dd = 1;
|
||||
} else {
|
||||
desc->rx.daddr = daddr;
|
||||
}
|
||||
|
||||
pg_off += buf_size;
|
||||
if (pg_off + buf_size <= frag_size)
|
||||
continue;
|
||||
|
||||
frag++;
|
||||
pg_off = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void atl_fwd_init_ring(struct atl_fwd_ring *fwd_ring)
|
||||
{
|
||||
struct atl_hw *hw = &fwd_ring->nic->hw;
|
||||
struct atl_hw_ring *ring = &fwd_ring->hw;
|
||||
unsigned int flags = fwd_ring->flags;
|
||||
int dir_tx = atl_fwd_ring_tx(fwd_ring);
|
||||
int idx = fwd_ring->idx;
|
||||
int lxo_bit = !!(flags & ATL_FWR_LXO);
|
||||
|
||||
/* Reinit descriptors as they could be stale after hardware reset */
|
||||
atl_fwd_init_descr(fwd_ring);
|
||||
|
||||
atl_write(hw, ATL_RING_BASE_LSW(ring), ring->daddr);
|
||||
atl_write(hw, ATL_RING_BASE_MSW(ring), upper_32_bits(ring->daddr));
|
||||
|
||||
if (dir_tx) {
|
||||
atl_write(hw, ATL_TX_RING_THRESH(ring),
|
||||
8 << 8 | 8 << 0x10 | 24 << 0x18);
|
||||
atl_write(hw, ATL_TX_RING_CTL(ring), ring->size);
|
||||
|
||||
atl_write_bit(hw, ATL_TX_LSO_CTRL, idx, lxo_bit);
|
||||
} else {
|
||||
uint32_t ctrl = ring->size |
|
||||
!!(flags & ATL_FWR_VLAN) << 29;
|
||||
|
||||
atl_write(hw, ATL_RX_RING_BUF_SIZE(ring),
|
||||
fwd_ring->buf_size / 1024);
|
||||
atl_write(hw, ATL_RX_RING_THRESH(ring),
|
||||
8 << 0x10 | 24 << 0x18);
|
||||
atl_write(hw, ATL_RX_RING_TAIL(ring), ring->size - 1);
|
||||
atl_write(hw, ATL_RX_RING_CTL(ring), ctrl);
|
||||
|
||||
if (lxo_bit)
|
||||
atl_write_bits(hw, ATL_RX_LRO_PKT_LIM(idx),
|
||||
(idx & 7) * 4, 2, 3);
|
||||
|
||||
atl_write_bit(hw, ATL_RX_LRO_CTRL1, idx, lxo_bit);
|
||||
atl_write_bit(hw, ATL_INTR_RSC_EN, idx, lxo_bit);
|
||||
}
|
||||
|
||||
atl_fwd_update_im(fwd_ring);
|
||||
}
|
||||
|
||||
void atl_fwd_release_ring(struct atl_fwd_ring *ring)
|
||||
{
|
||||
struct atl_nic *nic = ring->nic;
|
||||
int idx = ring->idx;
|
||||
int dir_tx = atl_fwd_ring_tx(ring);
|
||||
struct atl_fwd *fwd = &nic->fwd;
|
||||
unsigned long *map = &fwd->ring_map[dir_tx];
|
||||
struct atl_fwd_ring **rings = fwd->rings[dir_tx];
|
||||
struct atl_fwd_mem_ops *ops = ring->mem_ops;
|
||||
struct device *dev = &nic->hw.pdev->dev;
|
||||
struct atl_hw_ring *hwring = &ring->hw;
|
||||
|
||||
atl_fwd_disable_ring(ring);
|
||||
|
||||
if (ring->evt) {
|
||||
atl_fwd_disable_event(ring->evt);
|
||||
atl_fwd_release_event(ring->evt);
|
||||
}
|
||||
|
||||
atl_do_reset(nic);
|
||||
|
||||
__clear_bit(idx, map);
|
||||
rings[idx - ATL_FWD_RING_BASE] = NULL;
|
||||
atl_fwd_free_bufs(ring);
|
||||
if (ops->free_descs)
|
||||
ops->free_descs(hwring->descs, dev,
|
||||
hwring->size * sizeof(*hwring->descs), hwring->daddr,
|
||||
ops);
|
||||
else
|
||||
atl_free_descs(nic, &ring->hw, 0);
|
||||
kfree(ring);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_release_ring);
|
||||
|
||||
static unsigned int atl_fwd_rx_mod_max = 25, atl_fwd_rx_mod_min = 15,
|
||||
atl_fwd_tx_mod_max = 25, atl_fwd_tx_mod_min = 15;
|
||||
atl_module_param(fwd_rx_mod_max, uint, 0644);
|
||||
atl_module_param(fwd_rx_mod_min, uint, 0644);
|
||||
atl_module_param(fwd_tx_mod_max, uint, 0644);
|
||||
atl_module_param(fwd_tx_mod_min, uint, 0644);
|
||||
|
||||
static struct atl_fwd_mem_ops null_ops;
|
||||
|
||||
struct atl_fwd_ring *atl_fwd_request_ring(struct net_device *ndev,
|
||||
int flags, int ring_size, int buf_size, int page_order,
|
||||
struct atl_fwd_mem_ops *ops)
|
||||
{
|
||||
struct atl_nic *nic = netdev_priv(ndev);
|
||||
struct atl_fwd *fwd = &nic->fwd;
|
||||
int dir_tx = !!(flags & ATL_FWR_TX);
|
||||
unsigned long *map = &fwd->ring_map[dir_tx];
|
||||
struct atl_fwd_ring **rings = fwd->rings[dir_tx], *ring;
|
||||
struct device *dev = &nic->hw.pdev->dev;
|
||||
struct atl_hw_ring *hwring;
|
||||
int ret = -ENOMEM;
|
||||
int idx;
|
||||
|
||||
if (ring_size & 7 || ring_size > ATL_MAX_RING_SIZE) {
|
||||
atl_nic_err("%s: bad ring size %d, must be no more than %d and a multiple of 8\n",
|
||||
__func__, ring_size, ATL_MAX_RING_SIZE);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (buf_size & 1023 || buf_size > 16 * 1024) {
|
||||
atl_nic_err("%s: bad buffer size %d, must be no more than 16k and a multiple of 1024\n",
|
||||
__func__, buf_size);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (!ops)
|
||||
ops = &null_ops;
|
||||
|
||||
if ((ops->alloc_buf && !ops->free_buf) ||
|
||||
(ops->free_buf && !ops->alloc_buf)) {
|
||||
atl_nic_err("%s: must provide either both buffer allocator and deallocator or none\n",
|
||||
__func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if ((ops->alloc_descs && !ops->free_descs) ||
|
||||
(ops->free_descs && !ops->alloc_descs)) {
|
||||
atl_nic_err("%s: must provide either both descriptor ring allocator and deallocator or none\n",
|
||||
__func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if ((flags & (ATL_FWR_WANT_DMA_BUF_VEC | ATL_FWR_DONT_DMA_MAP)) ==
|
||||
(ATL_FWR_WANT_DMA_BUF_VEC | ATL_FWR_DONT_DMA_MAP)) {
|
||||
atl_nic_err("%s: ATL_FWR_WANT_DMA_BUF_VEC and ATL_FWR_DONT_DMA_MAP flags are mutually exclusive\n",
|
||||
__func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
idx = find_next_zero_bit(map, ATL_FWD_RING_BASE + ATL_NUM_FWD_RINGS,
|
||||
ATL_FWD_RING_BASE);
|
||||
if (idx >= ATL_FWD_RING_BASE + ATL_NUM_FWD_RINGS) {
|
||||
atl_nic_err("%s: no more rings available\n", __func__);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
|
||||
if (!ring) {
|
||||
atl_nic_err("%s: couldn't alloc ring structure\n", __func__);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ring->nic = nic;
|
||||
ring->idx = idx;
|
||||
ring->flags = flags;
|
||||
hwring = &ring->hw;
|
||||
hwring->size = ring_size;
|
||||
ring->buf_size = buf_size;
|
||||
ring->mem_ops = ops;
|
||||
|
||||
if (ops->alloc_descs) {
|
||||
void *descs;
|
||||
dma_addr_t daddr;
|
||||
|
||||
descs = ops->alloc_descs(dev,
|
||||
ring_size * sizeof(*hwring->descs), &daddr, GFP_KERNEL,
|
||||
ops);
|
||||
if (!IS_ERR_OR_NULL(descs)) {
|
||||
hwring->descs = descs;
|
||||
hwring->daddr = daddr;
|
||||
ret = 0;
|
||||
} else
|
||||
ret = PTR_ERR(descs);
|
||||
} else
|
||||
ret = atl_alloc_descs(nic, hwring, 0);
|
||||
|
||||
if (ret) {
|
||||
atl_nic_err("%s: couldn't alloc the ring\n", __func__);
|
||||
goto free_ring;
|
||||
}
|
||||
|
||||
hwring->reg_base = dir_tx ? ATL_TX_RING(idx) : ATL_RX_RING(idx);
|
||||
|
||||
ret = atl_fwd_alloc_bufs(ring, page_order);
|
||||
if (ret)
|
||||
goto free_descs;
|
||||
|
||||
__set_bit(idx, map);
|
||||
rings[idx - ATL_FWD_RING_BASE] = ring;
|
||||
|
||||
if (dir_tx) {
|
||||
ring->intr_mod_max = atl_fwd_tx_mod_max;
|
||||
ring->intr_mod_min = atl_fwd_tx_mod_min;
|
||||
} else {
|
||||
ring->intr_mod_max = atl_fwd_rx_mod_max;
|
||||
ring->intr_mod_min = atl_fwd_rx_mod_min;
|
||||
}
|
||||
|
||||
atl_fwd_init_ring(ring);
|
||||
return ring;
|
||||
|
||||
free_descs:
|
||||
if (ops->free_descs)
|
||||
ops->free_descs(hwring->descs, dev,
|
||||
hwring->size * sizeof(*hwring->descs), hwring->daddr,
|
||||
ops);
|
||||
else
|
||||
atl_free_descs(nic, hwring, 0);
|
||||
|
||||
free_ring:
|
||||
kfree(ring);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_request_ring);
|
||||
|
||||
int atl_fwd_set_ring_intr_mod(struct atl_fwd_ring *ring, int min, int max)
|
||||
{
|
||||
struct atl_nic *nic = ring->nic;
|
||||
if (atl_fwd_ring_tx(ring) && ring->evt &&
|
||||
ring->evt->flags & ATL_FWD_EVT_TXWB) {
|
||||
struct atl_nic *nic = ring->nic;
|
||||
|
||||
atl_nic_err("%s: Interrupt moderation not supported for head pointer writeback events\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (min >= 0) {
|
||||
if (min > 511) {
|
||||
atl_nic_err("%s: min delay out of range (0..511): %d\n",
|
||||
__func__, min);
|
||||
return -EINVAL;
|
||||
}
|
||||
ring->intr_mod_min = min;
|
||||
}
|
||||
|
||||
if (max >= 0) {
|
||||
if (max > 1023) {
|
||||
atl_nic_err("%s: max delay out of range (0..1023): %d\n",
|
||||
__func__, max);
|
||||
return -EINVAL;
|
||||
}
|
||||
ring->intr_mod_max = max;
|
||||
}
|
||||
|
||||
atl_fwd_update_im(ring);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_set_ring_intr_mod);
|
||||
|
||||
void atl_fwd_release_rings(struct atl_nic *nic)
|
||||
{
|
||||
struct atl_fwd_ring *ring;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) {
|
||||
ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM];
|
||||
if (ring)
|
||||
atl_fwd_release_ring(ring);
|
||||
}
|
||||
}
|
||||
|
||||
int atl_fwd_enable_ring(struct atl_fwd_ring *ring)
|
||||
{
|
||||
struct atl_hw *hw = &ring->nic->hw;
|
||||
|
||||
atl_set_bits(hw, ATL_RING_CTL(&ring->hw), BIT(31));
|
||||
atl_clear_bits(hw, ATL_RING_CTL(&ring->hw), BIT(30));
|
||||
ring->state |= ATL_FWR_ST_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_enable_ring);
|
||||
|
||||
void atl_fwd_disable_ring(struct atl_fwd_ring *ring)
|
||||
{
|
||||
struct atl_hw *hw = &ring->nic->hw;
|
||||
|
||||
if (!(ring->state & ATL_FWR_ST_ENABLED))
|
||||
return;
|
||||
|
||||
atl_clear_bits(hw, ATL_RING_CTL(&ring->hw), BIT(31));
|
||||
atl_set_bits(hw, ATL_RING_CTL(&ring->hw), BIT(30));
|
||||
ring->state &= ~ATL_FWR_ST_ENABLED;
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_disable_ring);
|
||||
|
||||
static void __iomem *atl_msix_bar(struct atl_nic *nic)
|
||||
{
|
||||
struct pci_dev *pdev = nic->hw.pdev;
|
||||
struct msi_desc *msi;
|
||||
|
||||
if (!pdev->msix_enabled)
|
||||
return NULL;
|
||||
|
||||
msi = list_first_entry(dev_to_msi_list(&pdev->dev),
|
||||
struct msi_desc, list);
|
||||
return msi->mask_base;
|
||||
}
|
||||
|
||||
static int atl_fwd_set_msix_vec(struct atl_nic *nic, struct atl_fwd_event *evt)
|
||||
{
|
||||
int idx = evt->idx;
|
||||
uint64_t addr = evt->msi_addr;
|
||||
uint32_t data = evt->msi_data;
|
||||
uint32_t ctrl;
|
||||
void __iomem *desc = atl_msix_bar(nic);
|
||||
|
||||
if (!desc)
|
||||
return -EIO;
|
||||
|
||||
desc += idx * PCI_MSIX_ENTRY_SIZE;
|
||||
|
||||
/* MSI-X table updates must be atomic, so mask first */
|
||||
ctrl = readl(desc + PCI_MSIX_ENTRY_VECTOR_CTRL);
|
||||
writel(ctrl | PCI_MSIX_ENTRY_CTRL_MASKBIT,
|
||||
desc + PCI_MSIX_ENTRY_VECTOR_CTRL);
|
||||
|
||||
/* Program the vector */
|
||||
writel(addr & (BIT_ULL(32) - 1), desc + PCI_MSIX_ENTRY_LOWER_ADDR);
|
||||
writel(addr >> 32, desc + PCI_MSIX_ENTRY_UPPER_ADDR);
|
||||
writel(data, desc + PCI_MSIX_ENTRY_DATA);
|
||||
|
||||
/* Unmask */
|
||||
writel(ctrl & ~PCI_MSIX_ENTRY_CTRL_MASKBIT,
|
||||
desc + PCI_MSIX_ENTRY_VECTOR_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atl_fwd_release_event(struct atl_fwd_event *evt)
|
||||
{
|
||||
struct atl_fwd_ring *ring = evt->ring;
|
||||
struct atl_nic *nic = ring->nic;
|
||||
unsigned long *map = &nic->fwd.msi_map;
|
||||
int idx = evt->idx;
|
||||
|
||||
if (ring->evt != evt) {
|
||||
atl_nic_err("%s: attempt to release unset event\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
atl_fwd_disable_event(evt);
|
||||
|
||||
ring->evt = NULL;
|
||||
|
||||
if (evt->flags & ATL_FWD_EVT_TXWB)
|
||||
return;
|
||||
|
||||
__clear_bit(idx, map);
|
||||
atl_set_intr_bits(&nic->hw, ring->idx,
|
||||
atl_fwd_ring_tx(ring) ? -1 : ATL_NUM_MSI_VECS,
|
||||
atl_fwd_ring_tx(ring) ? ATL_NUM_MSI_VECS : -1);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_release_event);
|
||||
|
||||
static int atl_fwd_init_event(struct atl_fwd_event *evt)
|
||||
{
|
||||
struct atl_fwd_ring *ring = evt->ring;
|
||||
int dir_tx = atl_fwd_ring_tx(ring);
|
||||
struct atl_nic *nic = ring->nic;
|
||||
struct atl_hw *hw = &nic->hw;
|
||||
bool tx_wb = !!(evt->flags & ATL_FWD_EVT_TXWB);
|
||||
int idx;
|
||||
int ret;
|
||||
|
||||
if (tx_wb) {
|
||||
struct atl_hw_ring *hwring = &ring->hw;
|
||||
|
||||
atl_write(hw, ATL_TX_RING_HEAD_WB_LSW(hwring),
|
||||
evt->tx_head_wrb);
|
||||
atl_write(hw, ATL_TX_RING_HEAD_WB_MSW(hwring),
|
||||
upper_32_bits(evt->tx_head_wrb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
idx = evt->idx;
|
||||
|
||||
ret = atl_fwd_set_msix_vec(nic, evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atl_set_intr_bits(&nic->hw, ring->idx,
|
||||
dir_tx ? -1 : idx,
|
||||
dir_tx ? idx : -1);
|
||||
|
||||
atl_write_bit(hw, ATL_INTR_AUTO_CLEAR, idx, 1);
|
||||
atl_write_bit(hw, ATL_INTR_AUTO_MASK, idx,
|
||||
!!(evt->flags & ATL_FWD_EVT_AUTOMASK));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atl_fwd_request_event(struct atl_fwd_event *evt)
|
||||
{
|
||||
struct atl_fwd_ring *ring = evt->ring;
|
||||
struct atl_nic *nic = ring->nic;
|
||||
unsigned long *map = &nic->fwd.msi_map;
|
||||
bool tx_wb = !!(evt->flags & ATL_FWD_EVT_TXWB);
|
||||
int idx;
|
||||
int ret;
|
||||
|
||||
if (ring->evt) {
|
||||
atl_nic_err("%s: event already set for %s ring %d\n",
|
||||
__func__, atl_fwd_dir_str(ring), ring->idx);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (!tx_wb && !(nic->flags & ATL_FL_MULTIPLE_VECTORS)) {
|
||||
atl_nic_err("%s: MSI-X interrupts are disabled\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tx_wb && !atl_fwd_ring_tx(ring)) {
|
||||
atl_nic_err("%s: head pointer writeback events supported "
|
||||
"on Tx rings only\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((evt->flags & (ATL_FWD_EVT_TXWB | ATL_FWD_EVT_AUTOMASK)) ==
|
||||
(ATL_FWD_EVT_TXWB | ATL_FWD_EVT_AUTOMASK)) {
|
||||
atl_nic_err("%s: event automasking supported "
|
||||
"for MSI events only\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ring->evt = evt;
|
||||
|
||||
if (tx_wb) {
|
||||
ret = atl_fwd_init_event(evt);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
idx = find_next_zero_bit(map, ATL_NUM_MSI_VECS, ATL_FWD_MSI_BASE);
|
||||
if (idx >= ATL_NUM_MSI_VECS) {
|
||||
atl_nic_err("%s: no MSI vectors left\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
evt->idx = idx;
|
||||
|
||||
ret = atl_fwd_init_event(evt);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
__set_bit(idx, map);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ring->evt = NULL;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_request_event);
|
||||
|
||||
int atl_fwd_enable_event(struct atl_fwd_event *evt)
|
||||
{
|
||||
struct atl_fwd_ring *ring = evt->ring;
|
||||
struct atl_hw *hw = &ring->nic->hw;
|
||||
|
||||
if (evt->flags & ATL_FWD_EVT_TXWB) {
|
||||
if (ring->state & ATL_FWR_ST_ENABLED)
|
||||
return -EINVAL;
|
||||
|
||||
atl_write_bit(hw, ATL_TX_RING_CTL(&ring->hw), 28, 1);
|
||||
ring->state |= ATL_FWR_ST_EVT_ENABLED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
atl_intr_enable(hw, BIT(evt->idx));
|
||||
ring->state |= ATL_FWR_ST_EVT_ENABLED;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_enable_event);
|
||||
|
||||
int atl_fwd_disable_event(struct atl_fwd_event *evt)
|
||||
{
|
||||
struct atl_fwd_ring *ring = evt->ring;
|
||||
struct atl_hw *hw = &ring->nic->hw;
|
||||
|
||||
if (evt->flags & ATL_FWD_EVT_TXWB) {
|
||||
if (ring->state & ATL_FWR_ST_ENABLED)
|
||||
return -EINVAL;
|
||||
|
||||
atl_write_bit(hw, ATL_TX_RING_CTL(&ring->hw), 28, 0);
|
||||
ring->state &= ~ATL_FWR_ST_EVT_ENABLED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
atl_intr_disable(hw, BIT(evt->idx));
|
||||
ring->state &= ~ATL_FWR_ST_EVT_ENABLED;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_disable_event);
|
||||
|
||||
int atl_fwd_receive_skb(struct net_device *ndev, struct sk_buff *skb)
|
||||
{
|
||||
struct atl_nic *nic = netdev_priv(ndev);
|
||||
|
||||
nic->stats.rx_fwd.packets++;
|
||||
nic->stats.rx_fwd.bytes += skb->len;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
return netif_rx(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_receive_skb);
|
||||
|
||||
int atl_fwd_napi_receive_skb(struct net_device *ndev, struct sk_buff *skb)
|
||||
{
|
||||
struct atl_nic *nic = netdev_priv(ndev);
|
||||
|
||||
nic->stats.rx_fwd.packets++;
|
||||
nic->stats.rx_fwd.bytes += skb->len;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
return netif_receive_skb(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_napi_receive_skb);
|
||||
|
||||
int atl_fwd_transmit_skb(struct net_device *ndev, struct sk_buff *skb)
|
||||
{
|
||||
skb->dev = ndev;
|
||||
return dev_queue_xmit(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_transmit_skb);
|
||||
|
||||
int atl_fwd_register_notifier(struct net_device *ndev,
|
||||
struct notifier_block *n)
|
||||
{
|
||||
struct atl_nic *nic = netdev_priv(ndev);
|
||||
struct atl_fwd *fwd = &nic->fwd;
|
||||
|
||||
return blocking_notifier_chain_register(&fwd->nh_clients, n);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_register_notifier);
|
||||
|
||||
int atl_fwd_unregister_notifier(struct net_device *ndev,
|
||||
struct notifier_block *n)
|
||||
{
|
||||
struct atl_nic *nic = netdev_priv(ndev);
|
||||
struct atl_fwd *fwd = &nic->fwd;
|
||||
|
||||
return blocking_notifier_chain_unregister(&fwd->nh_clients, n);
|
||||
}
|
||||
EXPORT_SYMBOL(atl_fwd_unregister_notifier);
|
||||
|
||||
void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data)
|
||||
{
|
||||
blocking_notifier_call_chain(&nic->fwd.nh_clients, notif, data);
|
||||
}
|
||||
|
||||
int atl_fwd_reconfigure_rings(struct atl_nic *nic)
|
||||
{
|
||||
struct atl_fwd_ring *ring;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) {
|
||||
ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM];
|
||||
|
||||
if (!ring)
|
||||
continue;
|
||||
|
||||
atl_fwd_init_ring(ring);
|
||||
|
||||
if (ring->evt) {
|
||||
ret = atl_fwd_init_event(ring->evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ring->state & ATL_FWR_ST_EVT_ENABLED) {
|
||||
ret = atl_fwd_enable_event(ring->evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atl_fwd_suspend_rings(struct atl_nic *nic)
|
||||
{
|
||||
atl_fwd_notify(nic, ATL_FWD_NOTIFY_RESET_PREPARE, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atl_fwd_resume_rings(struct atl_nic *nic)
|
||||
{
|
||||
struct atl_fwd_ring *ring;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = atl_fwd_reconfigure_rings(nic);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
atl_fwd_notify(nic, ATL_FWD_NOTIFY_RESET_COMPLETE, NULL);
|
||||
|
||||
for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) {
|
||||
ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM];
|
||||
|
||||
if (!ring)
|
||||
continue;
|
||||
|
||||
if ((ring->state & ATL_FWR_ST_ENABLED))
|
||||
atl_fwd_enable_ring(ring);
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
408
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h
Normal file
408
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2018 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_FWD_H_
|
||||
#define _ATL_FWD_H_
|
||||
|
||||
#include "atl_common.h"
|
||||
|
||||
/* Each incompatible API change bumps the API version */
|
||||
#define ATL_FWD_API_VERSION 3
|
||||
|
||||
struct atl_fwd_event;
|
||||
|
||||
struct atl_fwd_buf_frag {
|
||||
union {
|
||||
void *buf; /* Valid when custom allocator is
|
||||
* used */
|
||||
struct page *page; /* Valid otherwise */
|
||||
};
|
||||
dma_addr_t daddr;
|
||||
};
|
||||
|
||||
/**
|
||||
* atl_fwd_rxbufs - offload engine's ring's Rx buffers
|
||||
*
|
||||
* Buffers are allocated by the driver when a ring is created
|
||||
*
|
||||
* The entire buffer space for the ring may optionally be
|
||||
* allocated as a single physically-contiguous block.
|
||||
*
|
||||
* Descriptors are overwritten with the write-back descriptor
|
||||
* format on Rx and optionally on Tx. To simplify Rx descriptor
|
||||
* refill by the offload engine, vectors containing virtual
|
||||
* addresses and DMA-addresses of each buffer are provided in
|
||||
* @vaddr_vec and @daddr_vec respectively if
|
||||
* @ATL_FWR_WANT_VIRT_BUF_VEC or @ATL_FWR_WANT_DMA_BUF_VEC
|
||||
* flags are set on @atl_fwd_request_ring().
|
||||
*
|
||||
* If the resepective buffer vector request flags are not set,
|
||||
* @daddr_vec_base contains the DMA address of the first buffer
|
||||
* page and @vaddr_vec contains its virtual address.
|
||||
*
|
||||
* @daddr_vec_base: DMA address of the base of the @daddr_vec
|
||||
* @daddr_vec: A vector of buffers' DMA ddresses
|
||||
* @vaddr_vec: A vector of buffers' virtual addresses
|
||||
* or first buffer's virtual address
|
||||
* depending on ring flags
|
||||
*/
|
||||
struct atl_fwd_bufs {
|
||||
dma_addr_t daddr_vec_base;
|
||||
dma_addr_t *daddr_vec;
|
||||
void **vaddr_vec;
|
||||
|
||||
/* The following is not part of API and subject to change */
|
||||
int num_pages;
|
||||
int order;
|
||||
size_t frag_size;
|
||||
struct atl_fwd_buf_frag frags[0];
|
||||
};
|
||||
|
||||
union atl_desc;
|
||||
|
||||
/**
|
||||
* atl_hw_ring - low leverl descriptor ring structure
|
||||
*
|
||||
* @descs: Pointer to the descriptor ring
|
||||
* @size: Number of descriptors in the ring
|
||||
* @reg_base: Offset of ring's register block from start of
|
||||
* BAR 0
|
||||
* @daddr: DMA address of the ring
|
||||
*/
|
||||
/* atl_hw_ring defined in "atl_hw.h" */
|
||||
|
||||
/**
|
||||
*
|
||||
* atl_fwd_mem_ops - memory management handlers for the ring
|
||||
*
|
||||
* Custom memory allocators may be provided to
|
||||
* @atl_fwd_request_ring() to allocate the memory for the
|
||||
* descriptor ring and buffers.
|
||||
*
|
||||
* Unless @ATL_FWR_DONT_DMA_MAP is included in flags on
|
||||
* @atl_fwd_request_ring() call, the buffer allocator must also
|
||||
* DMA-map the memory they allocate. If @ATL_FWR_DONT_DMA_MAP is
|
||||
* set, @daddr parameter may be ignored by the buffer allocator
|
||||
* and should be ignored by the deallocator.
|
||||
*
|
||||
* The ring allocator must DMA-map the memory unconditionally
|
||||
* because the mapping is required to program the hardware ring
|
||||
* registers.
|
||||
*
|
||||
* A private data pointer @private is reserved for offload
|
||||
* engine's use. A pointer to the ops struct is provided to each
|
||||
* allocator / deallocator so they can get to the private
|
||||
* data. The @ops argument can be ignored by allocator /
|
||||
* deallocator functions if access to private data is not needed.
|
||||
*
|
||||
* Either both allocator and deallocator or none of them must be
|
||||
* provided for each memory type.
|
||||
*
|
||||
* Deallocator functions may ignore the size parameter.
|
||||
*/
|
||||
struct atl_fwd_mem_ops {
|
||||
void *(*alloc_descs)(struct device *dev, size_t size, dma_addr_t *daddr,
|
||||
gfp_t gfp, struct atl_fwd_mem_ops *ops);
|
||||
void *(*alloc_buf)(struct device *dev, size_t size, dma_addr_t *daddr,
|
||||
gfp_t gfp, struct atl_fwd_mem_ops *ops);
|
||||
void (*free_descs)(void *buf, struct device *dev, size_t size,
|
||||
dma_addr_t daddr, struct atl_fwd_mem_ops *ops);
|
||||
void (*free_buf)(void *buf, struct device *dev, size_t size,
|
||||
dma_addr_t daddr, struct atl_fwd_mem_ops *ops);
|
||||
void *private;
|
||||
};
|
||||
|
||||
/**
|
||||
* atl_fwd_ring - Offload engine-controlled ring
|
||||
*
|
||||
* Buffer space is allocated by the driver on ring creation.
|
||||
*
|
||||
* @hw: Low-level ring information
|
||||
* @evt: Ring's event, either an MSI-X vector (either
|
||||
* Tx or Rx) or head pointer writeback address
|
||||
* (Tx ring only). NULL on ring allocation, set
|
||||
* by atl_fwd_request_event()
|
||||
* @bufs: Ring's buffers. Allocated only if
|
||||
* @ATL_FWR_ALLOC_BUFS flag is set on ring
|
||||
* request.
|
||||
* @nic: struct atl_nic backreference
|
||||
* @idx: Ring index
|
||||
* @mem_ops: Memory allocators provided at ring creation
|
||||
*/
|
||||
struct atl_fwd_ring {
|
||||
struct atl_hw_ring hw;
|
||||
struct atl_fwd_event *evt;
|
||||
struct atl_fwd_bufs *bufs;
|
||||
struct atl_nic *nic;
|
||||
int idx;
|
||||
struct atl_fwd_mem_ops *mem_ops;
|
||||
|
||||
/* The following is not part of API and subject to change */
|
||||
unsigned int flags;
|
||||
unsigned long state;
|
||||
int buf_size;
|
||||
unsigned intr_mod_min;
|
||||
unsigned intr_mod_max;
|
||||
};
|
||||
|
||||
enum atl_fwd_event_flags {
|
||||
ATL_FWD_EVT_TXWB = BIT(0), /* Event type: 0 for MSI, 1 for Tx
|
||||
* head WB */
|
||||
ATL_FWD_EVT_AUTOMASK = BIT(1), /* Disable event after
|
||||
* raising, MSI only. */
|
||||
};
|
||||
|
||||
/**
|
||||
* atl_fwd_event - Ring's notification event
|
||||
*
|
||||
* @flags Event type and flags
|
||||
* @ring Ring backreference
|
||||
* @msi_addr MSI message address
|
||||
* @msi_data MSI message data
|
||||
* @idx MSI index (0 .. 31)
|
||||
* @tx_head_wrb Tx head writeback location
|
||||
*/
|
||||
struct atl_fwd_event {
|
||||
enum atl_fwd_event_flags flags;
|
||||
struct atl_fwd_ring *ring;
|
||||
union {
|
||||
struct {
|
||||
dma_addr_t msi_addr;
|
||||
uint32_t msi_data;
|
||||
int idx;
|
||||
};
|
||||
dma_addr_t tx_head_wrb;
|
||||
};
|
||||
};
|
||||
|
||||
enum atl_fwd_ring_flags {
|
||||
ATL_FWR_TX = BIT(0), /* Direction: 0 for Rx, 1 for Tx */
|
||||
ATL_FWR_VLAN = BIT(1), /* Enable VLAN tag stripping / insertion */
|
||||
ATL_FWR_LXO = BIT(2), /* Enable LRO / LSO */
|
||||
ATL_FWR_ALLOC_BUFS = BIT(3), /* Allocate buffers */
|
||||
ATL_FWR_CONTIG_BUFS = BIT(4), /* Alloc buffers as physically
|
||||
* contiguous. May fail if
|
||||
* total buffer space required
|
||||
* is larger than a max-order
|
||||
* compound page. */
|
||||
ATL_FWR_WANT_VIRT_BUF_VEC = BIT(5), /* Alloc and fill
|
||||
* per-buffer virtual address
|
||||
* vectors. If unset, first
|
||||
* buffer's vaddr is provided
|
||||
* in ring's @vaddr_vec */
|
||||
ATL_FWR_WANT_DMA_BUF_VEC = BIT(6), /* Alloc and fill
|
||||
* per-buffer DMA address
|
||||
* vectors. If unset, first
|
||||
* buffer's daddr is provided
|
||||
* in ring's
|
||||
* @daddr_vec_base */
|
||||
ATL_FWR_DONT_DMA_MAP = BIT(7), /* Don't DMA-map buffers, the
|
||||
* caller will take care of
|
||||
* that. Mutually exclusive
|
||||
* with
|
||||
* @ATL_FWR_WANT_DMA_BUF_VECS
|
||||
* If an external buffer
|
||||
* allocator is provided to
|
||||
* @atl_fwd_request_ring()
|
||||
* along with this flag, the
|
||||
* allocator need not provide
|
||||
* the DMA address. */
|
||||
};
|
||||
|
||||
/**
|
||||
* atl_fwd_request_ring() - Create a ring for an offload engine
|
||||
*
|
||||
* @ndev: network device
|
||||
* @flags: ring flags
|
||||
* @ring_size: number of descriptors
|
||||
* @buf_size: individual buffer's size
|
||||
* @page_order: page order to use when @ATL_FWR_CONTIG_BUFS is
|
||||
* not set
|
||||
* @mem_ops: optional custom memory allocators, may be NULL
|
||||
*
|
||||
* atl_fwd_request_ring() creates a ring for an offload engine,
|
||||
* allocates buffer memory if @ATL_FWR_ALLOC_BUFS flag is set,
|
||||
* initializes ring's registers, and, unless the @ATL_FWR_DONT_DMA_MAP
|
||||
* flag is set, fills the address fields in descriptors. Ring is
|
||||
* inactive until explicitly enabled via atl_fwd_enable_ring().
|
||||
*
|
||||
* Buffers can be allocated either as a single physically-contiguous
|
||||
* compound page, or as a sequence of compound pages of @page_order
|
||||
* order. In the latter case, depending on the requested buffer size,
|
||||
* tweaking the page order allows to pack buffers into buffer pages
|
||||
* with less wasted space.
|
||||
*
|
||||
* Returns the ring pointer on success, ERR_PTR(error code) on failure
|
||||
*/
|
||||
struct atl_fwd_ring *atl_fwd_request_ring(struct net_device *ndev,
|
||||
int flags, int ring_size, int buf_size, int page_order,
|
||||
struct atl_fwd_mem_ops *mem_ops);
|
||||
|
||||
/**
|
||||
* atl_fwd_release_ring() - Free offload engine's ring
|
||||
*
|
||||
* @ring: ring to be freed
|
||||
*
|
||||
* Stops the ring, frees buffers if they were allocated, disables and
|
||||
* releases ring's event if non-NULL, and frees the ring.
|
||||
*/
|
||||
void atl_fwd_release_ring(struct atl_fwd_ring *ring);
|
||||
|
||||
/**
|
||||
* atl_fwd_set_ring_intr_mod() - Set ring's interrupt moderation
|
||||
* delays
|
||||
*
|
||||
* @ring: ring
|
||||
* @min: min delay (0 - 511 uS)
|
||||
* @max: max delay (0 - 1023 uS)
|
||||
*
|
||||
* Each ring has two configurable interrupt moderation timers. When an
|
||||
* interrupt condition occurs (write-back of the final descriptor of a
|
||||
* packet on receive, or writeback on a transmit descriptor with WB
|
||||
* bit set), the min timer is restarted unconditionally and max timer
|
||||
* is started only if it's not running yet. When any of the timers
|
||||
* expires, the interrupt is signalled.
|
||||
*
|
||||
* Thus if a single interrupt event occurs it will be subjected to min
|
||||
* delay. If subsequent events keep occuring with intervals less than
|
||||
* min_delay between each other, the interrupt will be triggered
|
||||
* max_delay after the initial event.
|
||||
*
|
||||
* Delays are internally represented in units of 2 microseconds, so
|
||||
* the values supplied are rounded down to an even value.
|
||||
*
|
||||
* When called with negative @min or @max, the corresponding setting
|
||||
* is left unchanged.
|
||||
*
|
||||
* Interrupt moderation is only supported for MSI-X vectors, not head
|
||||
* pointer writeback events.
|
||||
*
|
||||
* Returns 0 on success or -EINVAL on attempt to set moderation delays
|
||||
* for a ring with attached Tx WB event or when a requested delay is
|
||||
* out of range.
|
||||
*/
|
||||
int atl_fwd_set_ring_intr_mod(struct atl_fwd_ring *ring, int min, int max);
|
||||
|
||||
/**
|
||||
* atl_fwd_enable_channel() - Enable offload engine's ring
|
||||
*
|
||||
* @ring: ring to be enabled
|
||||
*
|
||||
* Starts the ring. Returns 0 on success or negative error code.
|
||||
*/
|
||||
int atl_fwd_enable_ring(struct atl_fwd_ring *ring);
|
||||
/**
|
||||
* atl_fwd_disable_channel() - Disable offload engine's ring
|
||||
*
|
||||
* @ring: ring to be disabled
|
||||
*
|
||||
* Stops the ring.
|
||||
*/
|
||||
void atl_fwd_disable_ring(struct atl_fwd_ring *ring);
|
||||
|
||||
/**
|
||||
* atl_fwd_request_event() - Creates and attaches a ring notification
|
||||
* event
|
||||
*
|
||||
* @evt: event structure
|
||||
*
|
||||
* Caller must allocate a struct atl_fwd_event and fill the @flags,
|
||||
* @ring and either @tx_head_wrb or @msi_addr and @msi_data depending
|
||||
* on the type bit in @flags. Event is created in disabled state.
|
||||
*
|
||||
* For an MSI event type, an MSI vector table slot is
|
||||
* allocated and programmed, and it's index is saved in @evt->idx.
|
||||
*
|
||||
* @evt is then attached to the ring.
|
||||
*
|
||||
* Returns 0 on success or negative error code.
|
||||
*/
|
||||
int atl_fwd_request_event(struct atl_fwd_event *evt);
|
||||
|
||||
/**
|
||||
* atl_fwd_release_event() - Release a ring notification event
|
||||
*
|
||||
* @evt: event structure
|
||||
*
|
||||
* Disables the event if enabled, frees the MSI vector for an MSI-type
|
||||
* event and detaches @evt from the ring. The @evt structure itself is
|
||||
* not freed.
|
||||
*/
|
||||
void atl_fwd_release_event(struct atl_fwd_event *evt);
|
||||
|
||||
/**
|
||||
* atl_fwd_enable_event() - Enable a ring event
|
||||
*
|
||||
* @evt: event structure
|
||||
*
|
||||
* Enables the event.
|
||||
*
|
||||
* Returns 0 on success or negative error code.
|
||||
*/
|
||||
int atl_fwd_enable_event(struct atl_fwd_event *evt);
|
||||
|
||||
/**
|
||||
* atl_fwd_disable_event() - Disable a ring event
|
||||
*
|
||||
* @evt: event structure
|
||||
*
|
||||
* Disables the event.
|
||||
*
|
||||
* Returns 0 on success or negative error code.
|
||||
*/
|
||||
int atl_fwd_disable_event(struct atl_fwd_event *evt);
|
||||
|
||||
int atl_fwd_receive_skb(struct net_device *ndev, struct sk_buff *skb);
|
||||
int atl_fwd_transmit_skb(struct net_device *ndev, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* atl_fwd_napi_receive_skb() - post skb to the network stack
|
||||
*
|
||||
* @ndev: network device
|
||||
* @skb: buffer to post
|
||||
*
|
||||
* This function may only be called from softirq context and interrupts
|
||||
* should be enabled.
|
||||
*/
|
||||
int atl_fwd_napi_receive_skb(struct net_device *ndev, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* atl_fwd_register_notifier() - Register notifier for reset of device
|
||||
*
|
||||
* @ndev: network device
|
||||
* @n: notifier block
|
||||
*
|
||||
* Register for notification on reset of device. The notifier callback
|
||||
* receives a pointer to the affected device. Notification callback is
|
||||
* expected to be synchronous. The receiver shall perform the expected actions
|
||||
* upon the notification according to the notification type.
|
||||
*
|
||||
* Returns 0 on success or negative error code.
|
||||
*/
|
||||
int atl_fwd_register_notifier(struct net_device *ndev,
|
||||
struct notifier_block *n);
|
||||
int atl_fwd_unregister_notifier(struct net_device *ndev,
|
||||
struct notifier_block *n);
|
||||
enum atl_fwd_notify {
|
||||
ATL_FWD_NOTIFY_RESET_PREPARE, /* receiver shall stop traffic and */
|
||||
/* disable rings */
|
||||
ATL_FWD_NOTIFY_RESET_COMPLETE, /* receiver shall refill descriptors and */
|
||||
/* enable rings */
|
||||
ATL_FWD_NOTIFY_MACSEC_ON,
|
||||
ATL_FWD_NOTIFY_MACSEC_OFF,
|
||||
};
|
||||
|
||||
enum atl_fwd_ring_state {
|
||||
ATL_FWR_ST_ENABLED = BIT(0),
|
||||
ATL_FWR_ST_EVT_ENABLED = BIT(1),
|
||||
};
|
||||
|
||||
#endif
|
||||
1815
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.c
Normal file
1815
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.c
Normal file
File diff suppressed because it is too large
Load diff
122
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.h
Normal file
122
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_FWDNL_H_
|
||||
#define _ATL_FWDNL_H_
|
||||
|
||||
/* family name */
|
||||
#define ATL_FWD_GENL_NAME "atl_fwd"
|
||||
|
||||
/* commands */
|
||||
enum atlfwd_nl_command {
|
||||
ATL_FWD_CMD_UNSPEC,
|
||||
|
||||
ATL_FWD_CMD_REQUEST_RING,
|
||||
ATL_FWD_CMD_RELEASE_RING,
|
||||
ATL_FWD_CMD_ENABLE_RING,
|
||||
ATL_FWD_CMD_DISABLE_RING,
|
||||
|
||||
ATL_FWD_CMD_DISABLE_REDIRECTIONS,
|
||||
ATL_FWD_CMD_FORCE_ICMP_TX_VIA,
|
||||
ATL_FWD_CMD_FORCE_TX_VIA,
|
||||
|
||||
ATL_FWD_CMD_RING_STATUS,
|
||||
|
||||
ATL_FWD_CMD_DUMP_RING,
|
||||
ATL_FWD_CMD_SET_TX_BUNCH,
|
||||
|
||||
ATL_FWD_CMD_REQUEST_EVENT,
|
||||
ATL_FWD_CMD_RELEASE_EVENT,
|
||||
ATL_FWD_CMD_ENABLE_EVENT,
|
||||
ATL_FWD_CMD_DISABLE_EVENT,
|
||||
|
||||
ATL_FWD_CMD_GET_RX_QUEUE,
|
||||
ATL_FWD_CMD_GET_TX_QUEUE,
|
||||
|
||||
/* keep last */
|
||||
NUM_ATL_FWD_CMD,
|
||||
ATL_FWD_CMD_MAX = NUM_ATL_FWD_CMD - 1
|
||||
};
|
||||
|
||||
enum atlfwd_nl_attribute {
|
||||
ATL_FWD_ATTR_INVALID,
|
||||
|
||||
ATL_FWD_ATTR_IFNAME,
|
||||
|
||||
/* REQUEST_RING attributes */
|
||||
ATL_FWD_ATTR_FLAGS,
|
||||
ATL_FWD_ATTR_RING_SIZE,
|
||||
ATL_FWD_ATTR_BUF_SIZE,
|
||||
ATL_FWD_ATTR_PAGE_ORDER,
|
||||
|
||||
/* RELEASE_RING attributes */
|
||||
ATL_FWD_ATTR_RING_INDEX,
|
||||
/* ENABLE_RING / DISABLE_RING use RING_INDEX attribute above */
|
||||
|
||||
/* RING_STATUS reply attributes */
|
||||
ATL_FWD_ATTR_RING_STATUS,
|
||||
ATL_FWD_ATTR_RING_IS_TX,
|
||||
ATL_FWD_ATTR_RING_FLAGS,
|
||||
|
||||
/* ATL_FWD_CMD_SET_TX_BUNCH atributes */
|
||||
ATL_FWD_ATTR_TX_BUNCH_SIZE,
|
||||
|
||||
/* ATL_FWD_CMD_GET_(RX|TX)_QUEUE attributes */
|
||||
ATL_FWD_ATTR_QUEUE_INDEX,
|
||||
|
||||
/* keep last */
|
||||
NUM_ATL_FWD_ATTR,
|
||||
ATL_FWD_ATTR_MAX = NUM_ATL_FWD_ATTR - 1
|
||||
};
|
||||
|
||||
enum atlfwd_nl_ring_status {
|
||||
ATL_FWD_RING_STATUS_INVALID,
|
||||
|
||||
ATL_FWD_RING_STATUS_RELEASED,
|
||||
ATL_FWD_RING_STATUS_CREATED_DISABLED,
|
||||
ATL_FWD_RING_STATUS_ENABLED,
|
||||
|
||||
/* keep last */
|
||||
NUM_ATL_FWD_RING_STATUS,
|
||||
ATL_FWD_RING_STATUS_MAX = NUM_ATL_FWD_RING_STATUS - 1
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
struct atl_fwd_ring;
|
||||
struct atl_desc_ring;
|
||||
|
||||
int atlfwd_nl_init(void);
|
||||
void atlfwd_nl_on_probe(struct net_device *ndev);
|
||||
void atlfwd_nl_on_remove(struct net_device *ndev);
|
||||
int atlfwd_nl_on_open(struct net_device *ndev);
|
||||
void atlfwd_nl_exit(void);
|
||||
|
||||
netdev_tx_t atlfwd_nl_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
u16 atlfwd_nl_select_queue_fallback(struct net_device *dev, struct sk_buff *skb,
|
||||
struct net_device *arg3,
|
||||
select_queue_fallback_t fallback);
|
||||
|
||||
bool atlfwd_nl_is_tx_fwd_ring_created(struct net_device *ndev,
|
||||
const int fwd_ring_index);
|
||||
bool atlfwd_nl_is_rx_fwd_ring_created(struct net_device *ndev,
|
||||
const int fwd_ring_index);
|
||||
|
||||
struct atl_fwd_ring *atlfwd_nl_get_fwd_ring(struct net_device *ndev,
|
||||
const int ring_index);
|
||||
struct atl_desc_ring *atlfwd_nl_get_fwd_ring_desc(struct atl_fwd_ring *ring);
|
||||
|
||||
bool is_atlfwd_device(const struct net_device *dev);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
150
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl_params.c
Normal file
150
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl_params.c
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "atl_common.h"
|
||||
|
||||
unsigned int atlfwd_nl_tx_clean_threshold_msec = 200;
|
||||
unsigned int atlfwd_nl_tx_clean_threshold_frac = 8;
|
||||
bool atlfwd_nl_speculative_queue_stop = true;
|
||||
unsigned int altfwd_nl_rx_poll_interval_msec = 200;
|
||||
int atlfwd_nl_rx_clean_budget = NAPI_POLL_WEIGHT;
|
||||
|
||||
typedef void (*for_each_func_t)(struct net_device *ndev);
|
||||
static void for_each_atlfwd_device(for_each_func_t f)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
struct net *ns;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_net_rcu (ns) {
|
||||
for_each_netdev_rcu (ns, ndev) {
|
||||
if (!is_atlfwd_device(ndev))
|
||||
continue;
|
||||
|
||||
f(ndev);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void force_tx_housekeeping(struct net_device *ndev)
|
||||
{
|
||||
struct atl_nic *nic = netdev_priv(ndev);
|
||||
|
||||
/* Schedule for ASAP execution */
|
||||
schedule_delayed_work(nic->fwdnl.tx_cleanup_wq, 0);
|
||||
}
|
||||
|
||||
static void force_rx_polling(struct net_device *ndev)
|
||||
{
|
||||
struct atl_desc_ring *desc = NULL;
|
||||
struct atl_fwd_ring *ring = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != ATL_NUM_FWD_RINGS; i++) {
|
||||
if (!atlfwd_nl_is_rx_fwd_ring_created(ndev, i))
|
||||
continue;
|
||||
|
||||
ring = atlfwd_nl_get_fwd_ring(ndev, i);
|
||||
if (unlikely(!(ring->state & ATL_FWR_ST_ENABLED)))
|
||||
continue;
|
||||
|
||||
desc = atlfwd_nl_get_fwd_ring_desc(ring);
|
||||
if (likely(desc != NULL && desc->rx_poll_timer != NULL)) {
|
||||
desc->rx_poll_timer->expires =
|
||||
jiffies +
|
||||
msecs_to_jiffies(
|
||||
altfwd_nl_rx_poll_interval_msec);
|
||||
add_timer(desc->rx_poll_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tx_clean_threshold_msec_set(const char *val,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
unsigned int msec;
|
||||
int ret = kstrtouint(val, 10, &msec);
|
||||
|
||||
if (unlikely(ret != 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (msec != 0 && atlfwd_nl_tx_clean_threshold_msec == 0) {
|
||||
/* Force extra TX housekeeping, if threshold is re-enabled */
|
||||
for_each_atlfwd_device(force_tx_housekeeping);
|
||||
}
|
||||
|
||||
return param_set_uint(val, kp);
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops fwdnl_tx_clean_threshold_msec_ops = {
|
||||
.set = tx_clean_threshold_msec_set,
|
||||
.get = param_get_uint,
|
||||
};
|
||||
|
||||
static int tx_clean_threshold_frac_set(const char *val,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
unsigned int frac;
|
||||
int ret = kstrtouint(val, 10, &frac);
|
||||
|
||||
if (unlikely(ret != 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (frac != 0 && atlfwd_nl_tx_clean_threshold_frac == 0) {
|
||||
/* Force extra TX housekeeping, if threshold is re-enabled */
|
||||
for_each_atlfwd_device(force_tx_housekeeping);
|
||||
}
|
||||
|
||||
return param_set_uint(val, kp);
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops fwdnl_tx_clean_threshold_frac_ops = {
|
||||
.set = tx_clean_threshold_frac_set,
|
||||
.get = param_get_uint,
|
||||
};
|
||||
|
||||
static int rx_poll_interval_msec_set(const char *val,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
unsigned int msec;
|
||||
int ret = kstrtouint(val, 10, &msec);
|
||||
|
||||
if (unlikely(ret != 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (msec != 0 && altfwd_nl_rx_poll_interval_msec == 0) {
|
||||
/* Kick off RX polling, if polling is re-enabled */
|
||||
for_each_atlfwd_device(force_rx_polling);
|
||||
}
|
||||
|
||||
return param_set_uint(val, kp);
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops fwdnl_rx_poll_interval_msec_ops = {
|
||||
.set = rx_poll_interval_msec_set,
|
||||
.get = param_get_uint,
|
||||
};
|
||||
|
||||
module_param_cb(fwdnl_tx_clean_threshold_msec,
|
||||
&fwdnl_tx_clean_threshold_msec_ops,
|
||||
&atlfwd_nl_tx_clean_threshold_msec, 0644);
|
||||
module_param_cb(fwdnl_tx_clean_threshold_frac,
|
||||
&fwdnl_tx_clean_threshold_frac_ops,
|
||||
&atlfwd_nl_tx_clean_threshold_frac, 0644);
|
||||
module_param_named(fwdnl_speculative_queue_stop,
|
||||
atlfwd_nl_speculative_queue_stop, bool, 0644);
|
||||
module_param_cb(fwdnl_rx_poll_interval_msec, &fwdnl_rx_poll_interval_msec_ops,
|
||||
&altfwd_nl_rx_poll_interval_msec, 0644);
|
||||
module_param_named(fwdnl_rx_clean_budget, atlfwd_nl_rx_clean_budget, int, 0644);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_FWDNL_PARAMS_H_
|
||||
#define _ATL_FWDNL_PARAMS_H_
|
||||
|
||||
extern unsigned int atlfwd_nl_tx_clean_threshold_msec;
|
||||
extern unsigned int atlfwd_nl_tx_clean_threshold_frac;
|
||||
extern bool atlfwd_nl_speculative_queue_stop;
|
||||
extern unsigned int altfwd_nl_rx_poll_interval_msec;
|
||||
extern int atlfwd_nl_rx_clean_budget;
|
||||
|
||||
#endif
|
||||
1602
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c
Normal file
1602
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c
Normal file
File diff suppressed because it is too large
Load diff
382
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h
Normal file
382
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.h
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_HW_H_
|
||||
#define _ATL_HW_H_
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "atl_fw.h"
|
||||
#include "atl_macsec.h"
|
||||
#include "atl_regs.h"
|
||||
|
||||
union atl_desc;
|
||||
struct atl_nic;
|
||||
|
||||
#define PCI_VENDOR_ID_AQUANTIA 0x1d6a
|
||||
|
||||
/* clock is 3.2 ns*/
|
||||
#define ATL_HW_CLOCK_TO_US(clk) (clk * 32 / 10000)
|
||||
|
||||
#define ATL2_ACTION(ACTION, RSS, INDEX, VALID, TS_VALID) \
|
||||
((((ACTION & 0x3U) << 8) | \
|
||||
((RSS & 0x1U) << 7) | \
|
||||
((INDEX & 0x3FU) << 2) | \
|
||||
((TS_VALID & 0x1U) << 1)) | \
|
||||
((VALID & 0x1U) << 0))
|
||||
|
||||
#define ATL2_ACTION_DROP ATL2_ACTION(0, 0, 0, 1, 0)
|
||||
#define ATL2_ACTION_DISABLE ATL2_ACTION(0, 0, 0, 0, 0)
|
||||
#define ATL2_ACTION_ASSIGN_QUEUE(QUEUE) ATL2_ACTION(1, 0, (QUEUE), 1, 0)
|
||||
#define ATL2_ACTION_ASSIGN_TC(TC) ATL2_ACTION(1, 1, (TC), 1, 0)
|
||||
|
||||
enum {
|
||||
ATL2_RPF_L2_PROMISC_OFF_INDEX = 0,
|
||||
ATL2_RPF_VLAN_PROMISC_OFF_INDEX,
|
||||
ATL2_RPF_L3L4_USER_INDEX,
|
||||
ATL2_RPF_ET_PCP_USER_INDEX = ATL2_RPF_L3L4_USER_INDEX + 16,
|
||||
ATL2_RPF_VLAN_USER_INDEX = ATL2_RPF_ET_PCP_USER_INDEX + 16,
|
||||
ATL2_RPF_FLEX_USER_INDEX = ATL2_RPF_VLAN_USER_INDEX + 16,
|
||||
ATL2_RPF_DEFAULT_RULE_INDEX = ATL2_RPF_FLEX_USER_INDEX + 1,
|
||||
};
|
||||
|
||||
#define ATL2_RPF_TAG_UC_OFFSET 0x0
|
||||
#define ATL2_RPF_TAG_ALLMC_OFFSET 0x6
|
||||
#define ATL2_RPF_TAG_ET_OFFSET 0x7
|
||||
#define ATL2_RPF_TAG_VLAN_OFFSET 0xA
|
||||
#define ATL2_RPF_TAG_UNTAG_OFFSET 0xE
|
||||
#define ATL2_RPF_TAG_L3_V4_OFFSET 0xF
|
||||
#define ATL2_RPF_TAG_L3_V6_OFFSET 0x12
|
||||
#define ATL2_RPF_TAG_L4_OFFSET 0x15
|
||||
#define ATL2_RPF_TAG_L4_FLEX_OFFSET 0x18
|
||||
#define ATL2_RPF_TAG_FLEX_OFFSET 0x1B
|
||||
#define ATL2_RPF_TAG_PCP_OFFSET 0x1D
|
||||
|
||||
#define ATL2_RPF_TAG_UC_MASK (0x0000003F << ATL2_RPF_TAG_UC_OFFSET)
|
||||
#define ATL2_RPF_TAG_ALLMC_MASK (0x00000001 << ATL2_RPF_TAG_ALLMC_OFFSET)
|
||||
#define ATL2_RPF_TAG_UNTAG_MASK (0x00000001 << ATL2_RPF_TAG_UNTAG_OFFSET)
|
||||
#define ATL2_RPF_TAG_VLAN_MASK (0x0000000F << ATL2_RPF_TAG_VLAN_OFFSET)
|
||||
#define ATL2_RPF_TAG_ET_MASK (0x00000007 << ATL2_RPF_TAG_ET_OFFSET)
|
||||
#define ATL2_RPF_TAG_L3_V4_MASK (0x00000007 << ATL2_RPF_TAG_L3_V4_OFFSET)
|
||||
#define ATL2_RPF_TAG_L3_V6_MASK (0x00000007 << ATL2_RPF_TAG_L3_V6_OFFSET)
|
||||
#define ATL2_RPF_TAG_L4_MASK (0x00000007 << ATL2_RPF_TAG_L4_OFFSET)
|
||||
#define ATL2_RPF_TAG_FLEX_MASK (0x00000003 << ATL2_RPF_TAG_FLEX_OFFSET)
|
||||
#define ATL2_RPF_TAG_PCP_MASK (0x00000007 << ATL2_RPF_TAG_PCP_OFFSET)
|
||||
|
||||
#define ATL2_RPF_TAG_BASE_BC (1 << ATL2_RPF_TAG_UC_OFFSET)
|
||||
#define ATL2_RPF_TAG_BASE_UC (2 << ATL2_RPF_TAG_UC_OFFSET)
|
||||
|
||||
#define ATL2_FW_HOSTLOAD_REQ_LEN_MAX 0x1000
|
||||
|
||||
#define busy_wait(tries, wait, lvalue, fetch, cond) \
|
||||
({ \
|
||||
uint32_t _dummy = 0; \
|
||||
int i = (tries); \
|
||||
int orig = i; \
|
||||
(void)_dummy; \
|
||||
do { \
|
||||
wait; \
|
||||
(lvalue) = (fetch); \
|
||||
} while ((cond) && --i); \
|
||||
(orig - i); \
|
||||
})
|
||||
|
||||
enum atl_chip {
|
||||
ATL_UNKNOWN,
|
||||
ATL_ATLANTIC,
|
||||
ATL_ANTIGUA,
|
||||
};
|
||||
|
||||
struct atl_thermal {
|
||||
unsigned flags;
|
||||
uint8_t crit;
|
||||
uint8_t high;
|
||||
uint8_t low;
|
||||
};
|
||||
|
||||
extern struct atl_thermal atl_def_thermal;
|
||||
|
||||
enum atl_nic_state {
|
||||
ATL_ST_ENABLED,
|
||||
ATL_ST_CONFIGURED,
|
||||
ATL_ST_RINGS_RUNNING,
|
||||
/* ATL_ST_FWD_RINGS_RUNNING, */
|
||||
ATL_ST_UP,
|
||||
ATL_ST_WORK_SCHED,
|
||||
ATL_ST_UPDATE_LINK,
|
||||
ATL_ST_RESETTING,
|
||||
ATL_ST_RESET_NEEDED,
|
||||
ATL_ST_GLOBAL_CONF_NEEDED,
|
||||
ATL_ST_START_NEEDED,
|
||||
ATL_ST_DETACHED,
|
||||
};
|
||||
|
||||
#define ATL_WAKE_SUPPORTED (WAKE_MAGIC | WAKE_PHY)
|
||||
struct atl_hw {
|
||||
atomic_t flags;
|
||||
uint8_t __iomem *regs;
|
||||
struct pci_dev *pdev;
|
||||
unsigned long state;
|
||||
enum atl_chip chip_id;
|
||||
u32 chip_rev;
|
||||
bool new_rpf;
|
||||
struct atl_link_state link_state;
|
||||
uint32_t lpi_timer;
|
||||
unsigned wol_mode;
|
||||
struct atl_mcp mcp;
|
||||
uint32_t non_ring_intr_mask;
|
||||
uint8_t mac_addr[ETH_ALEN];
|
||||
#define ATL_RSS_KEY_SIZE 40
|
||||
uint8_t rss_key[ATL_RSS_KEY_SIZE];
|
||||
#define ATL_RSS_TBL_SIZE (1 << 6)
|
||||
uint8_t rss_tbl[ATL_RSS_TBL_SIZE];
|
||||
struct atl_thermal thermal;
|
||||
#if IS_ENABLED(CONFIG_MACSEC) && defined(NETIF_F_HW_MACSEC)
|
||||
struct atl_macsec_cfg macsec_cfg;
|
||||
#endif
|
||||
s64 ptp_clk_offset;
|
||||
int art_base_index;
|
||||
int art_available;
|
||||
};
|
||||
|
||||
struct atl_hw_ring {
|
||||
union atl_desc *descs;
|
||||
uint32_t size;
|
||||
uint32_t reg_base;
|
||||
dma_addr_t daddr;
|
||||
};
|
||||
|
||||
enum mcp_area {
|
||||
MCP_AREA_CONFIG = 0x80000000,
|
||||
MCP_AREA_SETTINGS = 0x20000000,
|
||||
};
|
||||
|
||||
#define offset_ptr(ptr, ring, amount) \
|
||||
({ \
|
||||
struct atl_hw_ring *hw_ring = (ring); \
|
||||
uint32_t size = hw_ring->size; \
|
||||
\
|
||||
uint32_t res = (ptr) + (amount); \
|
||||
if ((int32_t)res < 0) \
|
||||
res += size; \
|
||||
else if (res >= size) \
|
||||
res -= size; \
|
||||
res; \
|
||||
})
|
||||
|
||||
void atl_check_unplug(struct atl_hw *hw, uint32_t addr);
|
||||
|
||||
static inline uint32_t atl_read(struct atl_hw *hw, uint32_t addr)
|
||||
{
|
||||
uint8_t __iomem *base = READ_ONCE(hw->regs);
|
||||
uint32_t val = 0xffffffff;
|
||||
|
||||
if (unlikely(!base))
|
||||
return val;
|
||||
|
||||
val = readl(base + addr);
|
||||
if (unlikely(val == 0xffffffff))
|
||||
atl_check_unplug(hw, addr);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void atl_write(struct atl_hw *hw, uint32_t addr, uint32_t val)
|
||||
{
|
||||
uint8_t __iomem *base = READ_ONCE(hw->regs);
|
||||
|
||||
if (unlikely(!base))
|
||||
return;
|
||||
|
||||
writel(val, base + addr);
|
||||
}
|
||||
|
||||
|
||||
static inline void atl_write_mask_bits(struct atl_hw *hw, uint32_t addr,
|
||||
uint32_t mask, uint32_t val)
|
||||
{
|
||||
atl_write(hw, addr,
|
||||
(atl_read(hw, addr) & ~mask) | (val & mask));
|
||||
}
|
||||
|
||||
static inline void atl_write_bits(struct atl_hw *hw, uint32_t addr,
|
||||
uint32_t shift, uint32_t width, uint32_t val)
|
||||
{
|
||||
uint32_t mask = ((1u << width) - 1) << shift;
|
||||
|
||||
atl_write(hw, addr,
|
||||
(atl_read(hw, addr) & ~mask) | ((val << shift) & mask));
|
||||
}
|
||||
|
||||
static inline void atl_write_bit(struct atl_hw *hw, uint32_t addr,
|
||||
uint32_t shift, uint32_t val)
|
||||
{
|
||||
atl_write_bits(hw, addr, shift, 1, val);
|
||||
}
|
||||
|
||||
static inline void atl_set_bits(struct atl_hw *hw, uint32_t addr,
|
||||
uint32_t bits)
|
||||
{
|
||||
atl_write(hw, addr, atl_read(hw, addr) | bits);
|
||||
}
|
||||
|
||||
static inline void atl_clear_bits(struct atl_hw *hw, uint32_t addr,
|
||||
uint32_t bits)
|
||||
{
|
||||
atl_write(hw, addr, atl_read(hw, addr) & ~bits);
|
||||
}
|
||||
|
||||
static inline void atl_intr_enable(struct atl_hw *hw, uint32_t mask)
|
||||
{
|
||||
atl_write(hw, ATL_INTR_MSK_SET, mask);
|
||||
}
|
||||
|
||||
static inline void atl_intr_disable(struct atl_hw *hw, uint32_t mask)
|
||||
{
|
||||
atl_write(hw, ATL_INTR_MSK_CLEAR, mask);
|
||||
}
|
||||
|
||||
static inline void atl_intr_disable_all(struct atl_hw *hw)
|
||||
{
|
||||
atl_intr_disable(hw, 0xffffffff);
|
||||
}
|
||||
|
||||
static inline unsigned atl_fw_major(struct atl_hw *hw)
|
||||
{
|
||||
return (hw->mcp.fw_rev >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static inline void atl_init_rss_table(struct atl_hw *hw, int nvecs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATL_RSS_TBL_SIZE; i++)
|
||||
hw->rss_tbl[i] = i % nvecs;
|
||||
}
|
||||
|
||||
int atl2_act_rslvr_table_set(struct atl_hw *hw, u8 location,
|
||||
u32 tag, u32 mask, u32 action);
|
||||
static inline void atl2_rpf_vlan_flr_tag_set(struct atl_hw *hw, u32 tag,
|
||||
u32 filter)
|
||||
{
|
||||
atl_write_bits(hw, ATL_RX_VLAN_FLT(filter), 12, 4, tag);
|
||||
}
|
||||
|
||||
static inline void atl2_rpf_etht_flr_tag_set(struct atl_hw *hw, u32 tag,
|
||||
u32 filter)
|
||||
{
|
||||
atl_write_bits(hw, ATL2_RX_ETYPE_TAG(filter), 0, 3, tag);
|
||||
}
|
||||
|
||||
static inline void atl2_rpf_l3_v4_da_set(struct atl_hw *hw, u32 filter, u32 val)
|
||||
{
|
||||
u32 dword = filter % 4;
|
||||
u32 addr_set = 6 + ((filter < 4) ? (0) : (1));
|
||||
|
||||
atl_write(hw, ATL2_RPF_L3_DA(addr_set) + 4 * dword, swab32(val));
|
||||
}
|
||||
|
||||
static inline void atl2_rpf_l3_v4_sa_set(struct atl_hw *hw, u32 filter, u32 val)
|
||||
{
|
||||
u32 dword = filter % 4;
|
||||
u32 addr_set = 6 + ((filter < 4) ? (0) : (1));
|
||||
|
||||
atl_write(hw, ATL2_RPF_L3_SA(addr_set) + 4 * dword, swab32(val));
|
||||
}
|
||||
|
||||
static inline void atl2_rpf_l3_v6_sa_set(struct atl_hw *hw, u32 filter,
|
||||
u32 val[4])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
atl_write(hw, ATL2_RPF_L3_SA(filter) + 4 * i, swab32(val[i]));
|
||||
}
|
||||
|
||||
static inline void atl2_rpf_l3_v6_da_set(struct atl_hw *hw, u32 filter,
|
||||
u32 val[4])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
atl_write(hw, ATL2_RPF_L3_DA(filter) + 4 * i, swab32(val[i]));
|
||||
}
|
||||
|
||||
static inline void atl2_rpf_flex_flr_tag_set(struct atl_hw *hw, u32 tag,
|
||||
u32 filter)
|
||||
{
|
||||
atl_write_bits(hw, ATL_RX_FLEX_FLT_CTRL(filter), 0x19, 2, tag);
|
||||
}
|
||||
|
||||
int atl_read_mcp_mem(struct atl_hw *hw, uint32_t mcp_addr, void *host_addr,
|
||||
unsigned size);
|
||||
int atl_hwinit(struct atl_hw *hw, enum atl_chip chip_id);
|
||||
void atl_refresh_link(struct atl_nic *nic);
|
||||
void atl_set_rss_key(struct atl_hw *hw);
|
||||
int atl_set_rss_tbl(struct atl_hw *hw);
|
||||
void atl_set_uc_flt(struct atl_hw *hw, int idx, uint8_t mac_addr[ETH_ALEN]);
|
||||
|
||||
int atl_alloc_descs(struct atl_nic *nic, struct atl_hw_ring *ring, size_t extra);
|
||||
void atl_free_descs(struct atl_nic *nic, struct atl_hw_ring *ring, size_t extra);
|
||||
void atl_set_intr_bits(struct atl_hw *hw, int idx, int rxbit, int txbit);
|
||||
int atl_alloc_link_intr(struct atl_nic *nic);
|
||||
void atl_free_link_intr(struct atl_nic *nic);
|
||||
int atl_write_mcp_mem(struct atl_hw *hw, uint32_t offt, void *addr,
|
||||
size_t size, enum mcp_area area);
|
||||
|
||||
static inline int atl_write_fwcfg_word(struct atl_hw *hw, uint32_t offt,
|
||||
uint32_t val)
|
||||
{
|
||||
return atl_write_mcp_mem(hw, offt, &val, sizeof(val), MCP_AREA_CONFIG);
|
||||
}
|
||||
|
||||
static inline int atl_write_fwsettings_word(struct atl_hw *hw, uint32_t offt,
|
||||
uint32_t val)
|
||||
{
|
||||
return atl_write_mcp_mem(hw, offt, &val, sizeof(val), MCP_AREA_SETTINGS);
|
||||
}
|
||||
|
||||
static inline int atl_read_fwstat_word(struct atl_hw *hw, uint32_t offt,
|
||||
uint32_t *val)
|
||||
{
|
||||
return atl_read_mcp_word(hw, offt + hw->mcp.fw_stat_addr, val);
|
||||
}
|
||||
|
||||
static inline int atl_read_rpc_mem(struct atl_hw *hw, uint32_t offt,
|
||||
uint32_t *val, size_t length)
|
||||
{
|
||||
return atl_read_mcp_mem(hw, offt + hw->mcp.rpc_addr, val, length);
|
||||
}
|
||||
|
||||
static inline int atl_read_fwsettings_word(struct atl_hw *hw, uint32_t offt,
|
||||
uint32_t *val)
|
||||
{
|
||||
if (offt >= hw->mcp.fw_settings_len)
|
||||
return -EINVAL;
|
||||
|
||||
return atl_read_mcp_word(hw, offt + hw->mcp.fw_settings_addr, val);
|
||||
}
|
||||
|
||||
static inline void atl_lock_fw(struct atl_hw *hw)
|
||||
{
|
||||
mutex_lock(&hw->mcp.lock);
|
||||
}
|
||||
|
||||
static inline void atl_unlock_fw(struct atl_hw *hw)
|
||||
{
|
||||
mutex_unlock(&hw->mcp.lock);
|
||||
}
|
||||
|
||||
void atl_fw_watchdog(struct atl_hw *hw);
|
||||
|
||||
#endif
|
||||
247
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.c
Normal file
247
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.c
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/mdio.h>
|
||||
|
||||
#include "atl_hw_ptp.h"
|
||||
#include "atl_desc.h"
|
||||
#include "atl_mdio.h"
|
||||
|
||||
#define FRAC_PER_NS 0x100000000LL
|
||||
|
||||
#define ATL_HW_MAC_COUNTER_HZ 312500000ll
|
||||
#define ATL_HW_PHY_COUNTER_HZ 160000000ll
|
||||
|
||||
/* register address for bitfield PTP Digital Clock Read Enable */
|
||||
#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR 0x00004628
|
||||
/* lower bit position of bitfield PTP Digital Clock Read Enable */
|
||||
#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT 4
|
||||
/* width of bitfield PTP Digital Clock Read Enable */
|
||||
#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_WIDTH 1
|
||||
|
||||
/* register address for ptp counter reading */
|
||||
#define HW_ATL_PCS_PTP_TS_VAL_ADDR(index) (0x00004900 + (index) * 0x4)
|
||||
|
||||
static void hw_atl_pcs_ptp_clock_read_enable(struct atl_hw *hw,
|
||||
u32 ptp_clock_read_enable)
|
||||
{
|
||||
atl_write_bits(hw, HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR,
|
||||
HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT,
|
||||
HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_WIDTH,
|
||||
ptp_clock_read_enable);
|
||||
}
|
||||
|
||||
static u32 hw_atl_pcs_ptp_clock_get(struct atl_hw *hw, u32 index)
|
||||
{
|
||||
return atl_read(hw, HW_ATL_PCS_PTP_TS_VAL_ADDR(index));
|
||||
}
|
||||
|
||||
#define get_ptp_ts_val_u64(self, indx) \
|
||||
((u64)(hw_atl_pcs_ptp_clock_get(self, indx) & 0xffff))
|
||||
|
||||
void hw_atl_get_ptp_ts(struct atl_hw *hw, u64 *stamp)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
hw_atl_pcs_ptp_clock_read_enable(hw, 1);
|
||||
hw_atl_pcs_ptp_clock_read_enable(hw, 0);
|
||||
ns = (get_ptp_ts_val_u64(hw, 0) +
|
||||
(get_ptp_ts_val_u64(hw, 1) << 16)) * NSEC_PER_SEC +
|
||||
(get_ptp_ts_val_u64(hw, 3) +
|
||||
(get_ptp_ts_val_u64(hw, 4) << 16));
|
||||
|
||||
*stamp = ns + hw->ptp_clk_offset;
|
||||
}
|
||||
|
||||
static void hw_atl_adj_params_get(u64 freq, s64 adj, u32 *ns, u32 *fns)
|
||||
{
|
||||
/* For accuracy, the digit is extended */
|
||||
s64 base_ns = ((adj + NSEC_PER_SEC) * NSEC_PER_SEC);
|
||||
u64 nsi_frac = 0;
|
||||
u64 nsi;
|
||||
|
||||
base_ns = div64_s64(base_ns, freq);
|
||||
nsi = div64_u64(base_ns, NSEC_PER_SEC);
|
||||
|
||||
if (base_ns != nsi * NSEC_PER_SEC) {
|
||||
s64 divisor = div64_s64((s64)NSEC_PER_SEC * NSEC_PER_SEC,
|
||||
base_ns - nsi * NSEC_PER_SEC);
|
||||
nsi_frac = div64_s64(FRAC_PER_NS * NSEC_PER_SEC, divisor);
|
||||
}
|
||||
|
||||
*ns = (u32)nsi;
|
||||
*fns = (u32)nsi_frac;
|
||||
}
|
||||
|
||||
static void
|
||||
hw_atl_mac_adj_param_calc(struct ptp_adj_freq *ptp_adj_freq, u64 phyfreq,
|
||||
u64 macfreq)
|
||||
{
|
||||
s64 adj_fns_val;
|
||||
s64 fns_in_sec_phy = phyfreq * (ptp_adj_freq->fns_phy +
|
||||
FRAC_PER_NS * ptp_adj_freq->ns_phy);
|
||||
s64 fns_in_sec_mac = macfreq * (ptp_adj_freq->fns_mac +
|
||||
FRAC_PER_NS * ptp_adj_freq->ns_mac);
|
||||
s64 fault_in_sec_phy = FRAC_PER_NS * NSEC_PER_SEC - fns_in_sec_phy;
|
||||
s64 fault_in_sec_mac = FRAC_PER_NS * NSEC_PER_SEC - fns_in_sec_mac;
|
||||
/* MAC MCP counter freq is macfreq / 4 */
|
||||
s64 diff_in_mcp_overflow = (fault_in_sec_mac - fault_in_sec_phy) *
|
||||
4 * FRAC_PER_NS;
|
||||
|
||||
diff_in_mcp_overflow = div64_s64(diff_in_mcp_overflow,
|
||||
ATL_HW_MAC_COUNTER_HZ);
|
||||
adj_fns_val = (ptp_adj_freq->fns_mac + FRAC_PER_NS *
|
||||
ptp_adj_freq->ns_mac) + diff_in_mcp_overflow;
|
||||
|
||||
ptp_adj_freq->mac_ns_adj = div64_s64(adj_fns_val, FRAC_PER_NS);
|
||||
ptp_adj_freq->mac_fns_adj = adj_fns_val - ptp_adj_freq->mac_ns_adj *
|
||||
FRAC_PER_NS;
|
||||
}
|
||||
|
||||
int hw_atl_adj_sys_clock(struct atl_hw *hw, s64 delta)
|
||||
{
|
||||
hw->ptp_clk_offset += delta;
|
||||
|
||||
atl_write(hw, ATL_RX_SPARE_CTRL0, lower_32_bits(hw->ptp_clk_offset));
|
||||
atl_write(hw, ATL_RX_SPARE_CTRL1, upper_32_bits(hw->ptp_clk_offset));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_atl_ts_to_sys_clock(struct atl_hw *hw, u64 ts, u64 *time)
|
||||
{
|
||||
*time = hw->ptp_clk_offset + ts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_atl_adj_clock_freq(struct atl_hw *hw, s32 ppb)
|
||||
{
|
||||
struct ptp_msg_fw_request fwreq;
|
||||
struct atl_mcp *mcp = &hw->mcp;
|
||||
|
||||
memset(&fwreq, 0, sizeof(fwreq));
|
||||
|
||||
fwreq.msg_id = ptp_adj_freq_msg;
|
||||
hw_atl_adj_params_get(ATL_HW_MAC_COUNTER_HZ, ppb,
|
||||
&fwreq.adj_freq.ns_mac,
|
||||
&fwreq.adj_freq.fns_mac);
|
||||
hw_atl_adj_params_get(ATL_HW_PHY_COUNTER_HZ, ppb,
|
||||
&fwreq.adj_freq.ns_phy,
|
||||
&fwreq.adj_freq.fns_phy);
|
||||
hw_atl_mac_adj_param_calc(&fwreq.adj_freq,
|
||||
ATL_HW_PHY_COUNTER_HZ,
|
||||
ATL_HW_MAC_COUNTER_HZ);
|
||||
|
||||
return mcp->ops->send_ptp_req(hw, &fwreq);
|
||||
}
|
||||
|
||||
int hw_atl_gpio_pulse(struct atl_hw *hw, u32 index, u64 start, u32 period)
|
||||
{
|
||||
struct ptp_msg_fw_request fwreq;
|
||||
struct atl_mcp *mcp = &hw->mcp;
|
||||
|
||||
memset(&fwreq, 0, sizeof(fwreq));
|
||||
|
||||
fwreq.msg_id = ptp_gpio_ctrl_msg;
|
||||
fwreq.gpio_ctrl.index = index;
|
||||
fwreq.gpio_ctrl.period = period;
|
||||
/* Apply time offset */
|
||||
fwreq.gpio_ctrl.start = start;
|
||||
|
||||
return mcp->ops->send_ptp_req(hw, &fwreq);
|
||||
}
|
||||
|
||||
int hw_atl_extts_gpio_enable(struct atl_hw *hw, u32 index, u32 enable)
|
||||
{
|
||||
/* Enable/disable Sync1588 GPIO Timestamping */
|
||||
return atl_mdio_write(hw, 0, MDIO_MMD_PCS, 0xc611, enable ? 0x71 : 0);
|
||||
}
|
||||
|
||||
int hw_atl_get_sync_ts(struct atl_hw *hw, u64 *ts)
|
||||
{
|
||||
u16 nsec_l = 0;
|
||||
u16 nsec_h = 0;
|
||||
u16 sec_l = 0;
|
||||
u16 sec_h = 0;
|
||||
int ret;
|
||||
|
||||
if (!ts)
|
||||
return -1;
|
||||
|
||||
/* PTP external GPIO clock seconds count 15:0 */
|
||||
ret = atl_mdio_read(hw, 0, MDIO_MMD_PCS, 0xc914, &sec_l);
|
||||
/* PTP external GPIO clock seconds count 31:16 */
|
||||
if (!ret)
|
||||
ret = atl_mdio_read(hw, 0, MDIO_MMD_PCS, 0xc915, &sec_h);
|
||||
/* PTP external GPIO clock nanoseconds count 15:0 */
|
||||
if (!ret)
|
||||
ret = atl_mdio_read(hw, 0, MDIO_MMD_PCS, 0xc916, &nsec_l);
|
||||
/* PTP external GPIO clock nanoseconds count 31:16 */
|
||||
if (!ret)
|
||||
ret = atl_mdio_read(hw, 0, MDIO_MMD_PCS, 0xc917, &nsec_h);
|
||||
|
||||
*ts = ((u64)nsec_h << 16) + nsec_l + (((u64)sec_h << 16) + sec_l) * NSEC_PER_SEC;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u16 hw_atl_rx_extract_ts(struct atl_hw *hw, u8 *p, unsigned int len,
|
||||
u64 *timestamp)
|
||||
{
|
||||
unsigned int offset = 14;
|
||||
struct ethhdr *eth;
|
||||
u64 sec;
|
||||
u8 *ptr;
|
||||
u32 ns;
|
||||
|
||||
if (len <= offset || !timestamp)
|
||||
return 0;
|
||||
|
||||
/* The TIMESTAMP in the end of package has following format:
|
||||
* (big-endian)
|
||||
* struct {
|
||||
* uint64_t sec;
|
||||
* uint32_t ns;
|
||||
* uint16_t stream_id;
|
||||
* };
|
||||
*/
|
||||
ptr = p + (len - offset);
|
||||
memcpy(&sec, ptr, sizeof(sec));
|
||||
ptr += sizeof(sec);
|
||||
memcpy(&ns, ptr, sizeof(ns));
|
||||
|
||||
sec = be64_to_cpu(sec) & 0xffffffffffffllu;
|
||||
ns = be32_to_cpu(ns);
|
||||
*timestamp = sec * NSEC_PER_SEC + ns + hw->ptp_clk_offset;
|
||||
|
||||
eth = (struct ethhdr *)p;
|
||||
|
||||
return (eth->h_proto == htons(ETH_P_1588)) ? 12 : 14;
|
||||
}
|
||||
|
||||
void hw_atl_extract_hwts(struct atl_hw *hw, struct atl_rx_desc_hwts_wb *hwts_wb,
|
||||
u64 *timestamp)
|
||||
{
|
||||
u64 tmp, sec, ns;
|
||||
|
||||
sec = 0;
|
||||
tmp = hwts_wb->sec_lw0 & 0x3ff;
|
||||
sec += tmp;
|
||||
tmp = (u64)((hwts_wb->sec_lw1 >> 16) & 0xffff) << 10;
|
||||
sec += tmp;
|
||||
tmp = (u64)(hwts_wb->sec_hw & 0xfff) << 26;
|
||||
sec += tmp;
|
||||
tmp = (u64)((hwts_wb->sec_hw >> 22) & 0x3ff) << 38;
|
||||
sec += tmp;
|
||||
ns = sec * NSEC_PER_SEC + hwts_wb->ns;
|
||||
if (timestamp)
|
||||
*timestamp = ns + hw->ptp_clk_offset;
|
||||
}
|
||||
31
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.h
Normal file
31
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_HW_PTP_H_
|
||||
#define _ATL_HW_PTP_H_
|
||||
|
||||
#include "atl_hw.h"
|
||||
|
||||
struct atl_rx_desc_hwts_wb;
|
||||
|
||||
void hw_atl_get_ptp_ts(struct atl_hw *hw, u64 *stamp);
|
||||
int hw_atl_adj_sys_clock(struct atl_hw *hw, s64 delta);
|
||||
int hw_atl_ts_to_sys_clock(struct atl_hw *hw, u64 ts, u64 *time);
|
||||
int hw_atl_adj_clock_freq(struct atl_hw *hw, s32 ppb);
|
||||
int hw_atl_gpio_pulse(struct atl_hw *hw, u32 index, u64 start, u32 period);
|
||||
int hw_atl_extts_gpio_enable(struct atl_hw *hw, u32 index, u32 enable);
|
||||
int hw_atl_get_sync_ts(struct atl_hw *hw, u64 *ts);
|
||||
u16 hw_atl_rx_extract_ts(struct atl_hw *hw, u8 *p, unsigned int len,
|
||||
u64 *timestamp);
|
||||
void hw_atl_extract_hwts(struct atl_hw *hw, struct atl_rx_desc_hwts_wb *hwts_wb,
|
||||
u64 *timestamp);
|
||||
|
||||
#endif
|
||||
214
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c
Normal file
214
drivers/net/ethernet/aquantia/atlantic-fwd/atl_hwmon.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2018 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "atl_common.h"
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0)
|
||||
|
||||
static ssize_t atl_hwmon_set_flag(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
|
||||
struct atl_hw *hw = dev_get_drvdata(dev);
|
||||
bool val;
|
||||
int ret;
|
||||
|
||||
if (strtobool(buf, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = atl_update_thermal_flag(hw, sattr->index, val);
|
||||
|
||||
return ret ?: size;
|
||||
}
|
||||
|
||||
static ssize_t atl_hwmon_show_flag(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
|
||||
struct atl_hw *hw = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
!!(hw->thermal.flags & BIT(sattr->index)));
|
||||
}
|
||||
|
||||
#define ATL_HWMON_BIT_ATTR(_name, _bit) \
|
||||
SENSOR_DEVICE_ATTR(_name, S_IRUGO | S_IWUSR, atl_hwmon_show_flag, \
|
||||
atl_hwmon_set_flag, _bit)
|
||||
|
||||
static ATL_HWMON_BIT_ATTR(monitor, atl_thermal_monitor_shift);
|
||||
static ATL_HWMON_BIT_ATTR(throttle, atl_thermal_throttle_shift);
|
||||
static ATL_HWMON_BIT_ATTR(ignore_lims, atl_thermal_ignore_lims_shift);
|
||||
|
||||
static struct attribute *atl_hwmon_attrs[] = {
|
||||
&sensor_dev_attr_monitor.dev_attr.attr,
|
||||
&sensor_dev_attr_throttle.dev_attr.attr,
|
||||
&sensor_dev_attr_ignore_lims.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(atl_hwmon);
|
||||
|
||||
static char *atl_hwmon_labels[] = {
|
||||
"PHY Temperature",
|
||||
};
|
||||
|
||||
static const uint32_t atl_hwmon_temp_config[] = {
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_MAX_ALARM,
|
||||
0,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info atl_hwmon_temp = {
|
||||
.type = hwmon_temp,
|
||||
.config = atl_hwmon_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *atl_hwmon_info[] = {
|
||||
&atl_hwmon_temp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static umode_t atl_hwmon_is_visible(const void *p,
|
||||
enum hwmon_sensor_types type, uint32_t attr, int channel)
|
||||
{
|
||||
if (type != hwmon_temp)
|
||||
return 0;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input: case hwmon_temp_max_alarm: case hwmon_temp_label:
|
||||
return S_IRUGO;
|
||||
|
||||
case hwmon_temp_crit: case hwmon_temp_max: case hwmon_temp_max_hyst:
|
||||
return S_IRUGO | S_IWUSR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atl_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
uint32_t attr, int channel, long *val)
|
||||
{
|
||||
struct atl_hw *hw = dev_get_drvdata(dev);
|
||||
int temp, ret;
|
||||
|
||||
if (type != hwmon_temp)
|
||||
return -EINVAL;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
ret = hw->mcp.ops->get_phy_temperature(hw, &temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = temp;
|
||||
break;
|
||||
|
||||
case hwmon_temp_crit:
|
||||
*val = hw->thermal.crit * 1000;
|
||||
break;
|
||||
|
||||
case hwmon_temp_max:
|
||||
*val = hw->thermal.high * 1000;
|
||||
break;
|
||||
|
||||
case hwmon_temp_max_hyst:
|
||||
*val = hw->thermal.low * 1000;
|
||||
break;
|
||||
|
||||
case hwmon_temp_max_alarm:
|
||||
*val = hw->link_state.thermal_throttled;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atl_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
uint32_t attr, int channel, long val)
|
||||
{
|
||||
struct atl_hw *hw = dev_get_drvdata(dev);
|
||||
uint8_t *ptr, old;
|
||||
int ret;
|
||||
|
||||
if (type != hwmon_temp)
|
||||
return -EINVAL;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_crit:
|
||||
ptr = &hw->thermal.crit;
|
||||
break;
|
||||
|
||||
case hwmon_temp_max:
|
||||
ptr = &hw->thermal.high;
|
||||
break;
|
||||
|
||||
case hwmon_temp_max_hyst:
|
||||
ptr = &hw->thermal.low;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
old = *ptr;
|
||||
*ptr = val / 1000;
|
||||
|
||||
ret = atl_update_thermal(hw);
|
||||
if (ret)
|
||||
*ptr = old;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atl_hwmon_read_string(struct device *dev,
|
||||
enum hwmon_sensor_types type, u32 attr, int channel, const char **str)
|
||||
{
|
||||
if (type != hwmon_temp || attr != hwmon_temp_label)
|
||||
return -EINVAL;
|
||||
|
||||
*str = atl_hwmon_labels[channel];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops atl_hwmon_ops = {
|
||||
.is_visible = atl_hwmon_is_visible,
|
||||
.read = atl_hwmon_read,
|
||||
.read_string = atl_hwmon_read_string,
|
||||
.write = atl_hwmon_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info atl_hwmon = {
|
||||
.ops = &atl_hwmon_ops,
|
||||
.info = atl_hwmon_info,
|
||||
};
|
||||
|
||||
int atl_hwmon_init(struct atl_nic *nic)
|
||||
{
|
||||
struct device *hwmon_dev;
|
||||
struct atl_hw *hw = &nic->hw;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(&hw->pdev->dev,
|
||||
nic->ndev->name, hw, &atl_hwmon, atl_hwmon_groups);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int atl_hwmon_init(struct atl_nic *nic)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
77
drivers/net/ethernet/aquantia/atlantic-fwd/atl_log.h
Normal file
77
drivers/net/ethernet/aquantia/atlantic-fwd/atl_log.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_LOG_H_
|
||||
#define _ATL_LOG_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
/* Logging conveniency macros.
|
||||
*
|
||||
* atl_dev_xxx are for low-level contexts and implicitly reference
|
||||
* struct atl_hw *hw;
|
||||
*
|
||||
* atl_nic_xxx are for high-level contexts and implicitly reference
|
||||
* struct atl_nic *nic;
|
||||
*/
|
||||
#define atl_dev_dbg(fmt, args...) \
|
||||
dev_dbg(&hw->pdev->dev, fmt, ## args)
|
||||
#define atl_dev_info(fmt, args...) \
|
||||
dev_info(&hw->pdev->dev, fmt, ## args)
|
||||
#define atl_dev_warn(fmt, args...) \
|
||||
dev_warn(&hw->pdev->dev, fmt, ## args)
|
||||
#define atl_dev_err(fmt, args...) \
|
||||
dev_err(&hw->pdev->dev, fmt, ## args)
|
||||
|
||||
#define atl_nic_dbg(fmt, args...) \
|
||||
dev_dbg(&nic->hw.pdev->dev, fmt, ## args)
|
||||
#define atl_nic_info(fmt, args...) \
|
||||
dev_info(&nic->hw.pdev->dev, fmt, ## args)
|
||||
#define atl_nic_warn(fmt, args...) \
|
||||
dev_warn(&nic->hw.pdev->dev, fmt, ## args)
|
||||
#define atl_nic_err(fmt, args...) \
|
||||
dev_err(&nic->hw.pdev->dev, fmt, ## args)
|
||||
|
||||
#define atl_dev_init_warn(fmt, args...) \
|
||||
do { \
|
||||
if (hw) \
|
||||
atl_dev_warn(fmt, ## args); \
|
||||
else \
|
||||
printk(KERN_WARNING "%s: " fmt, atl_driver_name, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define atl_dev_init_err(fmt, args...) \
|
||||
do { \
|
||||
if (hw) \
|
||||
atl_dev_err(fmt, ## args); \
|
||||
else \
|
||||
printk(KERN_ERR "%s: " fmt, atl_driver_name, ##args); \
|
||||
} while (0)
|
||||
|
||||
#else /* __KERNEL__ */
|
||||
|
||||
/* Logging is disabled in case of unit tests */
|
||||
#define atl_dev_dbg(fmt, args...)
|
||||
#define atl_dev_info(fmt, args...)
|
||||
#define atl_dev_warn(fmt, args...)
|
||||
#define atl_dev_err(fmt, args...)
|
||||
#define atl_nic_dbg(fmt, args...)
|
||||
#define atl_nic_info(fmt, args...)
|
||||
#define atl_nic_warn(fmt, args...)
|
||||
#define atl_nic_err(fmt, args...)
|
||||
#define atl_dev_init_warn(fmt, args...)
|
||||
#define atl_dev_init_err(fmt, args...)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _ATL_LOG_H_ */
|
||||
1738
drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c
Normal file
1738
drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c
Normal file
File diff suppressed because it is too large
Load diff
139
drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.h
Normal file
139
drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_MACSEC_H_
|
||||
#define _ATL_MACSEC_H_
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#if IS_ENABLED(CONFIG_MACSEC) && defined(NETIF_F_HW_MACSEC)
|
||||
|
||||
#include "net/macsec.h"
|
||||
|
||||
struct atl_hw;
|
||||
struct atl_nic;
|
||||
|
||||
#define ATL_MACSEC_MAX_SC 32
|
||||
#define ATL_MACSEC_MAX_SA 32
|
||||
|
||||
enum atl_macsec_sc_sa {
|
||||
atl_macsec_sa_sc_4sa_8sc,
|
||||
atl_macsec_sa_sc_not_used,
|
||||
atl_macsec_sa_sc_2sa_16sc,
|
||||
atl_macsec_sa_sc_1sa_32sc,
|
||||
};
|
||||
|
||||
struct atl_macsec_common_stats {
|
||||
/* Ingress Common Counters */
|
||||
struct {
|
||||
u64 ctl_pkts;
|
||||
u64 tagged_miss_pkts;
|
||||
u64 untagged_miss_pkts;
|
||||
u64 notag_pkts;
|
||||
u64 untagged_pkts;
|
||||
u64 bad_tag_pkts;
|
||||
u64 no_sci_pkts;
|
||||
u64 unknown_sci_pkts;
|
||||
u64 ctrl_prt_pass_pkts;
|
||||
u64 unctrl_prt_pass_pkts;
|
||||
u64 ctrl_prt_fail_pkts;
|
||||
u64 unctrl_prt_fail_pkts;
|
||||
u64 too_long_pkts;
|
||||
u64 igpoc_ctl_pkts;
|
||||
u64 ecc_error_pkts;
|
||||
u64 unctrl_hit_drop_redir;
|
||||
} in;
|
||||
|
||||
/* Egress Common Counters */
|
||||
struct {
|
||||
u64 ctl_pkts;
|
||||
u64 unknown_sa_pkts;
|
||||
u64 untagged_pkts;
|
||||
u64 too_long;
|
||||
u64 ecc_error_pkts;
|
||||
u64 unctrl_hit_drop_redir;
|
||||
} out;
|
||||
};
|
||||
|
||||
/* Ingress SA Counters */
|
||||
struct atl_macsec_rx_sa_stats {
|
||||
u64 untagged_hit_pkts;
|
||||
u64 ctrl_hit_drop_redir_pkts;
|
||||
u64 not_using_sa;
|
||||
u64 unused_sa;
|
||||
u64 not_valid_pkts;
|
||||
u64 invalid_pkts;
|
||||
u64 ok_pkts;
|
||||
u64 late_pkts;
|
||||
u64 delayed_pkts;
|
||||
u64 unchecked_pkts;
|
||||
u64 validated_octets;
|
||||
u64 decrypted_octets;
|
||||
};
|
||||
|
||||
/* Egress SA Counters */
|
||||
struct atl_macsec_tx_sa_stats {
|
||||
u64 sa_hit_drop_redirect;
|
||||
u64 sa_protected2_pkts;
|
||||
u64 sa_protected_pkts;
|
||||
u64 sa_encrypted_pkts;
|
||||
};
|
||||
|
||||
/* Egress SC Counters */
|
||||
struct atl_macsec_tx_sc_stats {
|
||||
u64 sc_protected_pkts;
|
||||
u64 sc_encrypted_pkts;
|
||||
u64 sc_protected_octets;
|
||||
u64 sc_encrypted_octets;
|
||||
};
|
||||
|
||||
struct atl_macsec_txsc {
|
||||
u32 hw_sc_idx;
|
||||
unsigned long tx_sa_idx_busy;
|
||||
const struct macsec_secy *sw_secy;
|
||||
/* It is not OK to store key in driver but it is until ... */
|
||||
u8 tx_sa_key[MACSEC_NUM_AN][MACSEC_KEYID_LEN];
|
||||
struct atl_macsec_tx_sc_stats stats;
|
||||
struct atl_macsec_tx_sa_stats tx_sa_stats[MACSEC_NUM_AN];
|
||||
};
|
||||
|
||||
struct atl_macsec_rxsc {
|
||||
u32 hw_sc_idx;
|
||||
unsigned long rx_sa_idx_busy;
|
||||
const struct macsec_secy *sw_secy;
|
||||
const struct macsec_rx_sc *sw_rxsc;
|
||||
/* TODO: we shouldn't store keys in the driver */
|
||||
u8 rx_sa_key[MACSEC_NUM_AN][MACSEC_KEYID_LEN];
|
||||
struct atl_macsec_rx_sa_stats rx_sa_stats[MACSEC_NUM_AN];
|
||||
};
|
||||
|
||||
struct atl_macsec_cfg {
|
||||
enum atl_macsec_sc_sa sc_sa;
|
||||
/* Egress channel configuration */
|
||||
unsigned long txsc_idx_busy;
|
||||
struct atl_macsec_txsc atl_txsc[ATL_MACSEC_MAX_SC];
|
||||
/* Ingress channel configuration */
|
||||
unsigned long rxsc_idx_busy;
|
||||
struct atl_macsec_rxsc atl_rxsc[ATL_MACSEC_MAX_SC];
|
||||
struct atl_macsec_common_stats stats;
|
||||
};
|
||||
|
||||
extern const struct macsec_ops atl_macsec_ops;
|
||||
|
||||
int atl_init_macsec(struct atl_hw *hw);
|
||||
void atl_macsec_work(struct atl_nic *nic);
|
||||
int atl_macsec_rx_sa_cnt(struct atl_hw *hw);
|
||||
int atl_macsec_tx_sc_cnt(struct atl_hw *hw);
|
||||
int atl_macsec_tx_sa_cnt(struct atl_hw *hw);
|
||||
int atl_macsec_update_stats(struct atl_hw *hw);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ATL_MACSEC_H_ */
|
||||
1073
drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c
Normal file
1073
drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c
Normal file
File diff suppressed because it is too large
Load diff
28
drivers/net/ethernet/aquantia/atlantic-fwd/atl_mdio.h
Normal file
28
drivers/net/ethernet/aquantia/atlantic-fwd/atl_mdio.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_MDIO_H_
|
||||
#define _ATL_MDIO_H_
|
||||
|
||||
#include "atl_hw.h"
|
||||
|
||||
int atl_mdio_hwsem_get(struct atl_hw *hw);
|
||||
void atl_mdio_hwsem_put(struct atl_hw *hw);
|
||||
int __atl_mdio_read(struct atl_hw *hw, uint8_t prtad, uint8_t mmd,
|
||||
uint16_t addr, uint16_t *val);
|
||||
int atl_mdio_read(struct atl_hw *hw, uint8_t prtad, uint8_t mmd,
|
||||
uint16_t addr, uint16_t *val);
|
||||
int __atl_mdio_write(struct atl_hw *hw, uint8_t prtad, uint8_t mmd,
|
||||
uint16_t addr, uint16_t val);
|
||||
int atl_mdio_write(struct atl_hw *hw, uint8_t prtad, uint8_t mmd,
|
||||
uint16_t addr, uint16_t val);
|
||||
|
||||
#endif /* _ATL_MDIO_H_ */
|
||||
1328
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.c
Normal file
1328
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.c
Normal file
File diff suppressed because it is too large
Load diff
65
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.h
Normal file
65
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2014-2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef ATL_PTP_H
|
||||
#define ATL_PTP_H
|
||||
|
||||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "atl_compat.h"
|
||||
|
||||
struct atl_nic;
|
||||
struct atl_queue_vec;
|
||||
|
||||
/* Common functions */
|
||||
int atl_ptp_init(struct atl_nic *nic);
|
||||
int atl_ptp_register(struct atl_nic *nic);
|
||||
|
||||
void atl_ptp_unregister(struct atl_nic *nic);
|
||||
void atl_ptp_free(struct atl_nic *nic);
|
||||
|
||||
int atl_ptp_irq_alloc(struct atl_nic *nic);
|
||||
void atl_ptp_irq_free(struct atl_nic *nic);
|
||||
|
||||
int atl_ptp_ring_alloc(struct atl_nic *nic);
|
||||
void atl_ptp_ring_free(struct atl_nic *nic);
|
||||
|
||||
int atl_ptp_ring_start(struct atl_nic *nic);
|
||||
void atl_ptp_ring_stop(struct atl_nic *nic);
|
||||
|
||||
void atl_ptp_work(struct atl_nic *nic);
|
||||
|
||||
void atl_ptp_tm_offset_set(struct atl_nic *nic, unsigned int mbps);
|
||||
|
||||
void atl_ptp_clock_init(struct atl_nic *nic);
|
||||
|
||||
int atl_ptp_qvec_intr(struct atl_queue_vec *qvec);
|
||||
|
||||
/* Traffic processing functions */
|
||||
netdev_tx_t atl_ptp_start_xmit(struct atl_nic *nic, struct sk_buff *skb);
|
||||
void atl_ptp_tx_hwtstamp(struct atl_nic *nic, u64 timestamp);
|
||||
|
||||
/* Check for PTP availability before calling! */
|
||||
void atl_ptp_hwtstamp_config_get(struct atl_nic *nic,
|
||||
struct hwtstamp_config *config);
|
||||
int atl_ptp_hwtstamp_config_set(struct atl_nic *nic,
|
||||
struct hwtstamp_config *config);
|
||||
|
||||
/* Return whether ring belongs to PTP or not*/
|
||||
bool atl_is_ptp_ring(struct atl_nic *nic, struct atl_desc_ring *ring);
|
||||
u16 atl_ptp_extract_ts(struct atl_nic *nic, struct sk_buff *skb, u8 *p,
|
||||
unsigned int len);
|
||||
|
||||
struct ptp_clock *atl_ptp_get_ptp_clock(struct atl_nic *nic);
|
||||
|
||||
int atl_ptp_link_change(struct atl_nic *nic);
|
||||
|
||||
#endif /* ATL_PTP_H */
|
||||
224
drivers/net/ethernet/aquantia/atlantic-fwd/atl_regs.h
Normal file
224
drivers/net/ethernet/aquantia/atlantic-fwd/atl_regs.h
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_REGS_H_
|
||||
#define _ATL_REGS_H_
|
||||
|
||||
#define ATL_REG_STRIDE(base, stride, idx) ((base) + (stride) * (idx))
|
||||
|
||||
/* Ring registers common for Rx and Tx */
|
||||
#define ATL_RING_OFFT(ring, offt) \
|
||||
(((struct atl_hw_ring *)(ring))->reg_base + (offt))
|
||||
#define ATL_RING_BASE_LSW(ring) ATL_RING_OFFT(ring, 0)
|
||||
#define ATL_RING_BASE_MSW(ring) ATL_RING_OFFT(ring, 4)
|
||||
#define ATL_RING_CTL(ring) ATL_RING_OFFT(ring, 8)
|
||||
#define ATL_RING_HEAD(ring) ATL_RING_OFFT(ring, 0xc)
|
||||
#define ATL_RING_TAIL(ring) ATL_RING_OFFT(ring, 0x10)
|
||||
#define ATL_RING_STS(ring) ATL_RING_OFFT(ring, 0x14)
|
||||
|
||||
/* MIF @ 0x0000*/
|
||||
#define ATL_GLOBAL_STD_CTRL 0
|
||||
#define ATL_GLOBAL_FW_ID 0xc
|
||||
#define ATL_GLOBAL_CHIP_ID 0x10
|
||||
#define ATL_GLOBAL_CHIP_REV 0x14
|
||||
#define ATL_GLOBAL_FW_IMAGE_ID 0x18
|
||||
#define ATL_GLOBAL_MIF_ID 0x1c
|
||||
#define ATL_GLOBAL_MBOX_CTRL 0x200
|
||||
#define ATL_GLOBAL_MBOX_CRC 0x204
|
||||
#define ATL_GLOBAL_MBOX_ADDR 0x208
|
||||
#define ATL_GLOBAL_MBOX_DATA 0x20c
|
||||
#define ATL_GLOBAL_MDIO_CTL 0x280
|
||||
#define ATL_GLOBAL_MDIO_CMD 0x284
|
||||
#define ATL_GLOBAL_MDIO_WDATA 0x288
|
||||
#define ATL_GLOBAL_MDIO_ADDR 0x28c
|
||||
#define ATL_GLOBAL_MDIO_RDATA 0x290
|
||||
#define ATL2_MIF_BOOT_READ_REQ_ADR 0x328
|
||||
#define ATL2_MIF_BOOT_READ_REQ_LEN 0x32c
|
||||
#define ATL2_MIF_BOOT_REG_ADR 0x3040
|
||||
#define ATL2_MCP_HOST_REQ_INT 0x0F00
|
||||
#define ATL2_MCP_HOST_REQ_INT_CLR 0x0F08
|
||||
#define ATL2_MCP_HOST_REQ_INT_MASK(idx) ATL_REG_STRIDE(0x0f0c, 4, (idx))
|
||||
#define ATL2_MIF_SHARED_BUFFER_BOOT(idx) ATL_REG_STRIDE(0x00010000, 0x4, (idx))
|
||||
#define ATL2_MIF_SHARED_BUFFER_IN(idx) ATL_REG_STRIDE(0x00012000, 0x4, (idx))
|
||||
#define ATL2_MIF_SHARED_BUFFER_OUT(idx) ATL_REG_STRIDE(0x00013000, 0x4, (idx))
|
||||
#define ATL2_MIF_HOST_FINISHED_WRITE 0x0e00
|
||||
#define ATL2_MIF_MCP_FINISHED_READ 0x0e04
|
||||
|
||||
/* Scratch pads numbered starting from 1 */
|
||||
#define ATL_MCP_SCRATCH(idx) ATL_REG_STRIDE(0x300 - 0x4, 0x4, idx)
|
||||
#define ATL_MCP_SEM(idx) ATL_REG_STRIDE(0x3a0, 0x4, idx)
|
||||
#define ATL_MCP_SEM_MDIO 0
|
||||
#define ATL_MCP_SEM_MSM 1
|
||||
#define ATL_MCP_SEM_MEM 2
|
||||
#define ATL2_MCP_SEM_ACT_RSLVR 3
|
||||
#define ATL_GLOBAL_CTRL2 0x404
|
||||
#define ATL_GLOBAL_DAISY_CHAIN_STS1 0x704
|
||||
|
||||
enum mcp_scratchpad {
|
||||
FW2_MBOX_DATA = 11, /* 0x328 */
|
||||
FW2_MBOX_CMD = 12, /* 0x32c */
|
||||
FW2_RPC_DATA = 14, /* 0x334 */
|
||||
FW_STAT_STRUCT = 25, /* 0x360 */
|
||||
FW2_EFUSE_SHADOW = 26, /* 0x364 */
|
||||
FW1_LINK_REQ = 27,
|
||||
FW2_LINK_REQ_LOW = 27, /* 0x368 */
|
||||
FW1_LINK_STS = 28,
|
||||
FW2_LINK_REQ_HIGH = 28, /* 0x36c */
|
||||
FW2_LINK_RES_LOW = 29, /* 0x370 */
|
||||
FW1_EFUSE_SHADOW = 30,
|
||||
FW2_LINK_RES_HIGH = 30, /* 0x374 */
|
||||
FW3_EXT_REQ = 31, /* 0x378 */
|
||||
FW3_EXT_RES = 32, /* 0x37c */
|
||||
RBL_STS = 35, /* 0x388 */
|
||||
};
|
||||
|
||||
/* INTR @ 0x2000 */
|
||||
#define ATL_INTR_STS 0x2000
|
||||
#define ATL_INTR_MSK 0x2010
|
||||
#define ATL_INTR_MSK_SET 0x2060
|
||||
#define ATL_INTR_MSK_CLEAR 0x2070
|
||||
#define ATL_INTR_AUTO_CLEAR 0x2080
|
||||
#define ATL_INTR_AUTO_MASK 0x2090
|
||||
#define ATL_INTR_RING_INTR_MAP(idx) ATL_REG_STRIDE(0x2100, 0x4, (idx) >> 1)
|
||||
#define ATL_INTR_GEN_INTR_MAP4 0x218c
|
||||
#define ATL_INTR_RSC_EN 0x2200
|
||||
#define ATL_INTR_RSC_DELAY 0x2204
|
||||
#define ATL_INTR_CTRL 0x2300
|
||||
#define ATL_INTR_THRTL(idx) ATL_REG_STRIDE(0x2800, 4, idx)
|
||||
|
||||
/* MPI @ 0x4000 */
|
||||
#define ATL_MPI_CTRL1 0x4000
|
||||
#define ATL_MPI_MSM_CTRL 0x4018
|
||||
#define ATL_MPI_MSM_ADDR 0x4400
|
||||
#define ATL_MPI_MSM_WR 0x4404
|
||||
#define ATL_MPI_MSM_RD 0x4408
|
||||
|
||||
/* RX @ 0x5000 */
|
||||
#define ATL_RX_CTRL1 0x5000
|
||||
#define ATL_RX_SPARE_CTRL0 0x50A0
|
||||
#define ATL_RX_SPARE_CTRL1 0x50A4
|
||||
#define ATL2_RX_FLT_L2_BC_TAG 0x50F0
|
||||
#define ATL_RX_FLT_CTRL1 0x5100
|
||||
#define ATL_RX_FLT_CTRL2 0x5104
|
||||
#define ATL_UC_FLT_NUM 37
|
||||
#define ATL_RX_UC_FLT_REG1(idx) ATL_REG_STRIDE(0x5110, 8, idx)
|
||||
#define ATL_RX_UC_FLT_REG2(idx) ATL_REG_STRIDE(0x5114, 8, idx)
|
||||
#define ATL_MC_FLT_NUM 8
|
||||
#define ATL_RX_MC_FLT(idx) ATL_REG_STRIDE(0x5250, 4, idx)
|
||||
#define ATL_RX_MC_FLT_MSK 0x5270
|
||||
#define ATL_RX_VLAN_FLT_CTRL1 0x5280
|
||||
#define ATL_VLAN_FLT_NUM 16
|
||||
#define ATL_RX_VLAN_FLT(idx) ATL_REG_STRIDE(0x5290, 4, idx)
|
||||
#define ATL_RX_ETYPE_FLT(idx) ATL_REG_STRIDE(0x5300, 4, idx)
|
||||
#define ATL2_RX_ETYPE_TAG(idx) ATL_REG_STRIDE(0x5340, 4, idx)
|
||||
#define ATL_ETYPE_FLT_NUM 16
|
||||
#define ATL_NTUPLE_CTRL(idx) ATL_REG_STRIDE(0x5380, 4, idx)
|
||||
#define ATL_NTUPLE_SADDR(idx) ATL_REG_STRIDE(0x53b0, 4, idx)
|
||||
#define ATL_NTUPLE_DADDR(idx) ATL_REG_STRIDE(0x53d0, 4, idx)
|
||||
#define ATL_NTUPLE_SPORT(idx) ATL_REG_STRIDE(0x5400, 4, idx)
|
||||
#define ATL_NTUPLE_DPORT(idx) ATL_REG_STRIDE(0x5420, 4, idx)
|
||||
#define ATL_NTUPLE_FLT_NUM 8
|
||||
#define ATL_NTUPLE_V6_FLT_NUM 2
|
||||
#define ATL_RX_FLEX_FLT_CTRL(idx) ATL_REG_STRIDE(0x5460, 0x20, idx)
|
||||
#define ATL_FLEX_FLT_NUM 2
|
||||
#define ATL_RX_RSS_CTRL 0x54c0
|
||||
#define ATL_RX_RSS_KEY_ADDR 0x54d0
|
||||
#define ATL_RX_RSS_KEY_WR_DATA 0x54d4
|
||||
#define ATL_RX_RSS_KEY_RD_DATA 0x54d8
|
||||
#define ATL_RX_RSS_TBL_ADDR 0x54e0
|
||||
#define ATL_RX_RSS_TBL_WR_DATA 0x54e4
|
||||
#define ATL_RX_RSS_TBL_RD_DATA 0x54e8
|
||||
#define ATL2_RX_RSS_HASH_TYPE_ADR 0x54C8
|
||||
#define ATL_RX_RPF_DBG_CNT_CTRL 0x5518
|
||||
#define ATL_RX_RPF_HOST_CNT_LO 0x552c
|
||||
#define ATL_RX_RPF_HOST_CNT_HI 0x5530
|
||||
#define ATL_RX_RPF_LOST_CNT_LO 0x554c
|
||||
#define ATL_RX_RPF_LOST_CNT_HI 0x5550
|
||||
#define ATL_RX_PO_CTRL1 0x5580
|
||||
#define ATL_RX_LRO_CTRL1 0x5590
|
||||
#define ATL_RX_LRO_CTRL2 0x5594
|
||||
#define ATL_RX_LRO_PKT_LIM_EN 0x5598
|
||||
#define ATL_RX_LRO_PKT_LIM(idx) ATL_REG_STRIDE(0x55a0, 4, (idx) >> 3)
|
||||
#define ATL_RX_LRO_TMRS 0x5620
|
||||
#define ATL_RX_PBUF_CTRL1 0x5700
|
||||
#define ATL_RX_PBUF_REG1(idx) ATL_REG_STRIDE(0x5710, 0x10, idx)
|
||||
#define ATL_RX_PBUF_REG2(idx) ATL_REG_STRIDE(0x5714, 0x10, idx)
|
||||
#define ATL2_RX_Q_TO_TC_MAP(tc) ATL_REG_STRIDE(0x5900, 0x4, tc)
|
||||
#define ATL_RX_INTR_CTRL 0x5a30
|
||||
#define ATL_RX_INTR_MOD_CTRL(idx) ATL_REG_STRIDE(0x5a40, 4, idx)
|
||||
#define ATL2_RPF_RSS_REDIR(TC, INDEX) (0x6200 + \
|
||||
(0x100 * (TC > 3 ? 1 : 0)) + (INDEX) * 4)
|
||||
#define ATL2_RPF_L3_FLT(filter) ATL_REG_STRIDE(0x6500, 0x4, filter)
|
||||
#define ATL2_RPF_L3_SA(filter) ATL_REG_STRIDE(0x6400, 0x10, filter)
|
||||
#define ATL2_RPF_L3_DA(filter) ATL_REG_STRIDE(0x6480, 0x10, filter)
|
||||
#define ATL2_RPF_L4_FLT(filter) ATL_REG_STRIDE(0x6520, 0x4, filter)
|
||||
#define ATL2_RPF_REC_TAB_EN 0x00006ff0
|
||||
#define ATL2_RPF_ACT_RSLVR_REQ_TAG(filter) ATL_REG_STRIDE(0x14000, 0x10, filter)
|
||||
#define ATL2_RPF_ACT_RSLVR_TAG_MASK(filter) ATL_REG_STRIDE(0x14004, 0x10, filter)
|
||||
#define ATL2_RPF_ACT_RSLVR_ACTN(filter) ATL_REG_STRIDE(0x14008, 0x10, filter)
|
||||
|
||||
/* Rx rings */
|
||||
#define ATL_RX_RING(idx) ATL_REG_STRIDE(0x5b00, 0x20, idx)
|
||||
#define ATL_RX_RING_BASE_LSW(ring) ATL_RING_BASE_LSW(ring)
|
||||
#define ATL_RX_RING_BASE_MSW(ring) ATL_RING_BASE_MSW(ring)
|
||||
#define ATL_RX_RING_CTL(ring) ATL_RING_CTL(ring)
|
||||
#define ATL_RX_RING_HEAD(ring) ATL_RING_HEAD(ring)
|
||||
#define ATL_RX_RING_TAIL(ring) ATL_RING_TAIL(ring)
|
||||
#define ATL_RX_RING_STS(ring) ATL_RING_STS(ring)
|
||||
#define ATL_RX_RING_BUF_SIZE(ring) ATL_RING_OFFT(ring, 0x18)
|
||||
#define ATL_RX_RING_THRESH(ring) ATL_RING_OFFT(ring, 0x1c)
|
||||
|
||||
#define ATL_RX_DMA_STATS_CNT7 0x6818
|
||||
|
||||
/* TX @ 0x7000 */
|
||||
#define ATL_TX_CTRL1 0x7000
|
||||
#define ATL_TX_PO_CTRL1 0x7800
|
||||
#define ATL_TX_LSO_CTRL 0x7810
|
||||
#define ATL_TX_LSO_TCP_CTRL1 0x7820
|
||||
#define ATL_TX_LSO_TCP_CTRL2 0x7824
|
||||
#define ATL_TX_PBUF_CTRL1 0x7900
|
||||
#define ATL_TX_PBUF_REG1(idx) ATL_REG_STRIDE(0x7910, 0x10, idx)
|
||||
#define ATL_TX_PBUF_REG2(idx) ATL_REG_STRIDE(0x7914, 0x10, idx)
|
||||
#define ATL_TX_INTR_CTRL 0x7b40
|
||||
#define ATL2_TX_Q_TO_TC_MAP(tc) ATL_REG_STRIDE(0x799c, 0x4, tc)
|
||||
|
||||
/* Tx rings */
|
||||
#define ATL_TX_RING(idx) ATL_REG_STRIDE(0x7c00, 0x40, idx)
|
||||
#define ATL_TX_RING_BASE_LSW(ring) ATL_RING_BASE_LSW(ring)
|
||||
#define ATL_TX_RING_BASE_MSW(ring) ATL_RING_BASE_MSW(ring)
|
||||
#define ATL_TX_RING_CTL(ring) ATL_RING_CTL(ring)
|
||||
#define ATL_TX_RING_HEAD(ring) ATL_RING_HEAD(ring)
|
||||
#define ATL_TX_RING_TAIL(ring) ATL_RING_TAIL(ring)
|
||||
#define ATL_TX_RING_STS(ring) ATL_RING_STS(ring)
|
||||
#define ATL_TX_RING_THRESH(ring) ATL_RING_OFFT(ring, 0x18)
|
||||
#define ATL_TX_RING_HEAD_WB_LSW(ring) ATL_RING_OFFT(ring, 0x1c)
|
||||
#define ATL_TX_RING_HEAD_WB_MSW(ring) ATL_RING_OFFT(ring, 0x20)
|
||||
|
||||
#define ATL_TX_INTR_MOD_CTRL(idx) ATL_REG_STRIDE(0x8980, 0x4, idx)
|
||||
#define ATL2_TX_INTR_MOD_CTRL(idx) ATL_REG_STRIDE(0x7c28, 0x40, idx)
|
||||
|
||||
/* MSM */
|
||||
#define ATL_MSM_GEN_CTRL 0x8
|
||||
#define ATL_MSM_GEN_STS 0x40
|
||||
#define ATL_MSM_TX_LPI_DELAY 0x78
|
||||
#define ATL_MSM_CTR_RX_PKTS_GOOD 0x88
|
||||
#define ATL_MSM_CTR_RX_FCS_ERRS 0x90
|
||||
#define ATL_MSM_CTR_RX_ALIGN_ERRS 0x98
|
||||
#define ATL_MSM_CTR_TX_PAUSE 0xa0
|
||||
#define ATL_MSM_CTR_RX_PAUSE 0xa8
|
||||
#define ATL_MSM_CTR_RX_OCTETS_LO 0xd8
|
||||
#define ATL_MSM_CTR_RX_OCTETS_HI 0xdc
|
||||
#define ATL_MSM_CTR_RX_MULTICAST 0xE8
|
||||
#define ATL_MSM_CTR_RX_BROADCAST 0xF0
|
||||
#define ATL_MSM_CTR_RX_ERRS 0x120
|
||||
|
||||
|
||||
#endif
|
||||
2199
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c
Normal file
2199
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c
Normal file
File diff suppressed because it is too large
Load diff
235
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.h
Normal file
235
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.h
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_RING_H_
|
||||
#define _ATL_RING_H_
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include "atl_common.h"
|
||||
#include "atl_desc.h"
|
||||
#include "atl_ring_desc.h"
|
||||
#include "atl_ptp.h"
|
||||
|
||||
//#define ATL_RINGS_IN_UC_MEM
|
||||
|
||||
#define ATL_TX_DESC_WB
|
||||
//#define ATL_TX_HEAD_WB
|
||||
|
||||
#define ATL_RX_HEADROOM (NET_SKB_PAD + NET_IP_ALIGN)
|
||||
#define ATL_RX_TAILROOM 64u
|
||||
#define ATL_RX_HEAD_ORDER 0
|
||||
#define ATL_RX_DATA_ORDER 0
|
||||
|
||||
/* Header space in skb. Must be a multiple of L1_CACHE_BYTES */
|
||||
#define ATL_RX_HDR_SIZE 256u
|
||||
#define ATL_RX_HDR_OVRHD SKB_DATA_ALIGN(ATL_RX_HEADROOM + \
|
||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
#define ATL_RX_BUF_SIZE 2048
|
||||
|
||||
#define ATL_MAX_RX_LINEAR_MTU (ATL_RX_BUF_SIZE - ETH_HLEN)
|
||||
|
||||
#define ring_space(ring) \
|
||||
({ \
|
||||
struct atl_desc_ring *__ring = (ring); \
|
||||
uint32_t space = READ_ONCE(__ring->head) - \
|
||||
READ_ONCE(__ring->tail) - 1; \
|
||||
(int32_t)space < 0 ? space + __ring->hw.size : space; \
|
||||
})
|
||||
|
||||
#define ring_occupied(ring) \
|
||||
({ \
|
||||
struct atl_desc_ring *__ring = (ring); \
|
||||
uint32_t occupied = READ_ONCE(__ring->tail) - \
|
||||
READ_ONCE(__ring->head); \
|
||||
(int32_t)occupied < 0 ? occupied + __ring->hw.size \
|
||||
: occupied; \
|
||||
})
|
||||
|
||||
#define bump_ptr(ptr, ring, amount) \
|
||||
({ \
|
||||
struct atl_desc_ring *__ring = (ring); \
|
||||
uint32_t __res = offset_ptr(ptr, &__ring->hw, amount); \
|
||||
(ptr) = __res; \
|
||||
__res; \
|
||||
})
|
||||
|
||||
/* These don't have to be atomic, because Tx tail is only adjusted
|
||||
* in ndo->start_xmit which is serialized by the stack and the rest are
|
||||
* only adjusted in NAPI poll which is serialized by NAPI */
|
||||
#define bump_tail(ring, amount) do { \
|
||||
struct atl_desc_ring *__ring = (ring); \
|
||||
uint32_t __ptr = READ_ONCE(__ring->tail); \
|
||||
__ring->tail = offset_ptr(__ptr, &__ring->hw, amount);\
|
||||
} while (0)
|
||||
|
||||
#define bump_head(ring, amount) do { \
|
||||
struct atl_desc_ring *__ring = (ring); \
|
||||
uint32_t __ptr = READ_ONCE(__ring->head); \
|
||||
__ring->head = offset_ptr(__ptr, &__ring->hw, amount);\
|
||||
} while (0)
|
||||
|
||||
struct atl_rxpage {
|
||||
struct page *page;
|
||||
dma_addr_t daddr;
|
||||
unsigned mapcount; /* not atomic_t because accesses are
|
||||
* serialized by NAPI */
|
||||
unsigned order;
|
||||
};
|
||||
|
||||
struct atl_pgref {
|
||||
struct atl_rxpage *rxpage;
|
||||
unsigned pg_off;
|
||||
};
|
||||
|
||||
struct atl_cb {
|
||||
struct atl_pgref pgref;
|
||||
bool head;
|
||||
};
|
||||
#define ATL_CB(skb) ((struct atl_cb *)(skb)->cb)
|
||||
|
||||
struct atl_rxbuf {
|
||||
struct sk_buff *skb;
|
||||
struct atl_pgref head;
|
||||
struct atl_pgref data;
|
||||
};
|
||||
|
||||
struct atl_txbuf {
|
||||
struct sk_buff *skb;
|
||||
uint32_t last; /* index of eop descriptor */
|
||||
unsigned bytes;
|
||||
unsigned packets;
|
||||
DEFINE_DMA_UNMAP_ADDR(daddr);
|
||||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
};
|
||||
|
||||
struct legacy_irq_work {
|
||||
struct work_struct work;
|
||||
|
||||
struct napi_struct *napi;
|
||||
};
|
||||
static inline struct legacy_irq_work *to_irq_work(struct work_struct *work)
|
||||
{
|
||||
return container_of(work, struct legacy_irq_work, work);
|
||||
};
|
||||
|
||||
enum atl_queue_type {
|
||||
ATL_QUEUE_REGULAR,
|
||||
ATL_QUEUE_PTP,
|
||||
ATL_QUEUE_HWTS,
|
||||
};
|
||||
|
||||
struct ____cacheline_aligned atl_queue_vec {
|
||||
struct atl_desc_ring tx;
|
||||
struct atl_desc_ring rx;
|
||||
struct napi_struct napi;
|
||||
struct atl_nic *nic;
|
||||
unsigned idx;
|
||||
char name[IFNAMSIZ + 10];
|
||||
cpumask_t affinity_hint;
|
||||
enum atl_queue_type type;
|
||||
struct work_struct *work;
|
||||
};
|
||||
|
||||
#define atl_for_each_qvec(nic, qvec) \
|
||||
for (qvec = &(nic)->qvecs[0]; \
|
||||
qvec < &(nic)->qvecs[(nic)->nvecs]; qvec++)
|
||||
|
||||
static inline struct atl_hw *ring_hw(struct atl_desc_ring *ring)
|
||||
{
|
||||
return &ring->nic->hw;
|
||||
}
|
||||
|
||||
void atl_init_qvec(struct atl_nic *nic, struct atl_queue_vec *qvec, int idx);
|
||||
int atl_alloc_qvec(struct atl_queue_vec *qvec);
|
||||
void atl_free_qvec(struct atl_queue_vec *qvec);
|
||||
int atl_start_qvec(struct atl_queue_vec *qvec);
|
||||
void atl_stop_qvec(struct atl_queue_vec *qvec);
|
||||
int atl_poll_qvec(struct atl_queue_vec *qvec, int budget);
|
||||
|
||||
static inline int atl_qvec_intr(struct atl_queue_vec *qvec)
|
||||
{
|
||||
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
|
||||
if (unlikely(qvec->idx >= qvec->nic->nvecs))
|
||||
return atl_ptp_qvec_intr(qvec);
|
||||
#endif
|
||||
|
||||
return qvec->idx + ATL_NUM_NON_RING_IRQS;
|
||||
}
|
||||
|
||||
static inline void *atl_buf_vaddr(struct atl_pgref *pgref)
|
||||
{
|
||||
return page_to_virt(pgref->rxpage->page) + pgref->pg_off;
|
||||
}
|
||||
|
||||
static inline dma_addr_t atl_buf_daddr(struct atl_pgref *pgref)
|
||||
{
|
||||
return pgref->rxpage->daddr + pgref->pg_off;
|
||||
}
|
||||
|
||||
void atl_get_ring_stats(struct atl_desc_ring *ring,
|
||||
struct atl_ring_stats *stats);
|
||||
#define atl_update_ring_stat(ring, stat, delta) \
|
||||
do { \
|
||||
struct atl_desc_ring *_ring = (ring); \
|
||||
\
|
||||
u64_stats_update_begin(&_ring->syncp); \
|
||||
_ring->stats.stat += (delta); \
|
||||
u64_stats_update_end(&_ring->syncp); \
|
||||
} while (0)
|
||||
|
||||
int atl_init_rx_ring(struct atl_desc_ring *rx);
|
||||
int atl_init_tx_ring(struct atl_desc_ring *tx);
|
||||
|
||||
netdev_tx_t atl_map_skb(struct sk_buff *skb, struct atl_desc_ring *ring);
|
||||
int atl_tx_full(struct atl_desc_ring *ring, int needed);
|
||||
|
||||
typedef int (*rx_skb_handler_t)(struct atl_desc_ring *ring,
|
||||
struct sk_buff *skb);
|
||||
int atl_clean_rx(struct atl_desc_ring *ring, int budget,
|
||||
rx_skb_handler_t rx_skb_func);
|
||||
int atl_clean_hwts_rx(struct atl_desc_ring *ring, int budget);
|
||||
void atl_clear_rx_bufs(struct atl_desc_ring *ring);
|
||||
|
||||
#ifdef ATL_RINGS_IN_UC_MEM
|
||||
|
||||
#define DECLARE_SCRATCH_DESC(_name) union atl_desc _name
|
||||
#define DESC_PTR(_ring, _idx, _scratch) (&(_scratch))
|
||||
#define COMMIT_DESC(_ring, _idx, _scratch) \
|
||||
(_ring)->hw.descs[_idx] = (_scratch)
|
||||
#define FETCH_DESC(_ring, _idx, _scratch) \
|
||||
do { \
|
||||
(_scratch) = READ_ONCE((_ring)->hw.descs[_idx]); \
|
||||
dma_rmb(); \
|
||||
} while(0)
|
||||
|
||||
#define DESC_RMB()
|
||||
|
||||
#else // ATL_RINGS_IN_UC_MEM
|
||||
|
||||
#define DECLARE_SCRATCH_DESC(_name)
|
||||
#define DESC_PTR(_ring, _idx, _scratch) (&(_ring)->hw.descs[_idx])
|
||||
#define COMMIT_DESC(_ring, _idx, _scratch)
|
||||
#define FETCH_DESC(_ring, _idx, _scratch)
|
||||
#define DESC_RMB() dma_rmb()
|
||||
|
||||
#endif // ATL_RINGS_IN_UC_MEM
|
||||
|
||||
#ifdef ATL_TX_HEAD_WB
|
||||
#error Head ptr writeback not implemented
|
||||
#elif !defined(ATL_TX_DESC_WB)
|
||||
static inline uint32_t atl_get_tx_head(struct atl_desc_ring *ring)
|
||||
{
|
||||
return atl_read(ring_hw(ring), ATL_TX_RING_HEAD(ring->idx)) & 0x1fff;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
55
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring_desc.h
Normal file
55
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring_desc.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_RING_DESC_H_
|
||||
#define _ATL_RING_DESC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
|
||||
#include "atl_desc.h"
|
||||
#include "atl_hw.h"
|
||||
#include "atl_stats.h"
|
||||
|
||||
struct atl_nic;
|
||||
struct atl_fwd_event;
|
||||
|
||||
struct atl_desc_ring {
|
||||
struct atl_hw_ring hw;
|
||||
struct atl_nic *nic;
|
||||
uint32_t head;
|
||||
uint32_t tail;
|
||||
union {
|
||||
/* Rx ring only */
|
||||
uint32_t next_to_recycle;
|
||||
/* Tx ring only, template desc for atl_map_tx_skb() */
|
||||
union atl_desc desc;
|
||||
};
|
||||
union {
|
||||
struct atl_rxbuf *rxbufs;
|
||||
struct atl_txbuf *txbufs;
|
||||
void *bufs;
|
||||
};
|
||||
struct atl_queue_vec *qvec;
|
||||
struct u64_stats_sync syncp;
|
||||
struct atl_ring_stats stats;
|
||||
#if IS_ENABLED(CONFIG_ATLFWD_FWD_NETLINK)
|
||||
u32 tx_hw_head;
|
||||
union {
|
||||
struct atl_fwd_event *tx_evt;
|
||||
struct atl_fwd_event *rx_evt;
|
||||
};
|
||||
/* RX ring polling */
|
||||
struct timer_list *rx_poll_timer;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* _ATL_RING_DESC_H_ */
|
||||
87
drivers/net/ethernet/aquantia/atlantic-fwd/atl_stats.h
Normal file
87
drivers/net/ethernet/aquantia/atlantic-fwd/atl_stats.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATL_STATS_H_
|
||||
#define _ATL_STATS_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct atl_rx_ring_stats {
|
||||
uint64_t packets;
|
||||
uint64_t bytes;
|
||||
uint64_t linear_dropped;
|
||||
uint64_t alloc_skb_failed;
|
||||
uint64_t reused_head_page;
|
||||
uint64_t reused_data_page;
|
||||
uint64_t alloc_head_page;
|
||||
uint64_t alloc_data_page;
|
||||
uint64_t alloc_head_page_failed;
|
||||
uint64_t alloc_data_page_failed;
|
||||
uint64_t non_eop_descs;
|
||||
uint64_t mac_err;
|
||||
uint64_t csum_err;
|
||||
uint64_t multicast;
|
||||
};
|
||||
|
||||
struct atl_rx_fwd_ring_stats {
|
||||
uint64_t packets;
|
||||
uint64_t bytes;
|
||||
};
|
||||
|
||||
struct atl_tx_ring_stats {
|
||||
uint64_t packets;
|
||||
uint64_t bytes;
|
||||
uint64_t tx_busy;
|
||||
uint64_t tx_restart;
|
||||
uint64_t dma_map_failed;
|
||||
};
|
||||
|
||||
struct atl_ring_stats {
|
||||
union {
|
||||
struct atl_rx_ring_stats rx;
|
||||
struct atl_tx_ring_stats tx;
|
||||
};
|
||||
};
|
||||
|
||||
struct atl_ether_stats {
|
||||
uint64_t rx_pause;
|
||||
uint64_t tx_pause;
|
||||
uint64_t rx_ether_drops;
|
||||
uint64_t rx_ether_octets;
|
||||
uint64_t rx_ether_pkts;
|
||||
uint64_t rx_ether_broacasts;
|
||||
uint64_t rx_ether_multicasts;
|
||||
uint64_t rx_ether_crc_align_errs;
|
||||
uint64_t rx_filter_host;
|
||||
uint64_t rx_filter_lost;
|
||||
};
|
||||
|
||||
struct atl_global_stats {
|
||||
struct atl_rx_ring_stats rx;
|
||||
struct atl_tx_ring_stats tx;
|
||||
struct atl_rx_fwd_ring_stats rx_fwd;
|
||||
|
||||
/* MSM counters can't be reset without full HW reset, so
|
||||
* store them in relative form:
|
||||
* eth[i] == HW_counter - eth_base[i]
|
||||
*/
|
||||
struct atl_ether_stats eth;
|
||||
struct atl_ether_stats eth_base;
|
||||
};
|
||||
|
||||
struct atl_fwd_ring;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ATLFWD_FWD_NETLINK)
|
||||
void atl_fwd_get_ring_stats(struct atl_fwd_ring *ring,
|
||||
struct atl_ring_stats *stats);
|
||||
#endif
|
||||
|
||||
#endif /* _ATL_STATS_H_ */
|
||||
16
drivers/net/ethernet/aquantia/atlantic-fwd/atl_trace.c
Normal file
16
drivers/net/ethernet/aquantia/atlantic-fwd/atl_trace.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "atl_trace.h"
|
||||
274
drivers/net/ethernet/aquantia/atlantic-fwd/atl_trace.h
Normal file
274
drivers/net/ethernet/aquantia/atlantic-fwd/atl_trace.h
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2017 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM atlnew
|
||||
|
||||
#if !defined(_ATL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _ATL_TRACE_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include "atl_desc.h"
|
||||
|
||||
DECLARE_EVENT_CLASS(atl_dma_map_class,
|
||||
TP_PROTO(int frag_idx, int ring_idx, dma_addr_t daddr, size_t size, struct sk_buff *skb,
|
||||
void *vaddr),
|
||||
TP_ARGS(frag_idx, ring_idx, daddr, size, skb, vaddr),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, frag_idx)
|
||||
__field(int, ring_idx)
|
||||
__field(dma_addr_t, daddr)
|
||||
__field(size_t, size)
|
||||
__field(struct sk_buff *, skb)
|
||||
__field(void *, vaddr)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->frag_idx = frag_idx;
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->daddr = daddr;
|
||||
__entry->size = size;
|
||||
__entry->skb = skb;
|
||||
__entry->vaddr = vaddr;
|
||||
),
|
||||
TP_printk("idx %d ring idx %d daddr %pad len %#zx skb %p vaddr %p",
|
||||
__entry->frag_idx, __entry->ring_idx, &__entry->daddr,
|
||||
__entry->size, __entry->skb, __entry->vaddr)
|
||||
);
|
||||
|
||||
#define DEFINE_MAP_EVENT(name) \
|
||||
DEFINE_EVENT(atl_dma_map_class, name, \
|
||||
TP_PROTO(int frag_idx, int ring_idx, \
|
||||
dma_addr_t daddr, size_t size, \
|
||||
struct sk_buff *skb, void *vaddr), \
|
||||
TP_ARGS(frag_idx, ring_idx, daddr, size, skb, vaddr))
|
||||
|
||||
DEFINE_MAP_EVENT(atl_dma_map_head);
|
||||
DEFINE_MAP_EVENT(atl_dma_map_frag);
|
||||
DEFINE_MAP_EVENT(atl_dma_map_rxbuf);
|
||||
|
||||
DECLARE_EVENT_CLASS(atl_dma_unmap_class,
|
||||
TP_PROTO(int frag_idx, int ring_idx, dma_addr_t daddr, size_t size,
|
||||
struct sk_buff *skb),
|
||||
TP_ARGS(frag_idx, ring_idx, daddr, size, skb),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, frag_idx)
|
||||
__field(int, ring_idx)
|
||||
__field(dma_addr_t, daddr)
|
||||
__field(size_t, size)
|
||||
__field(struct sk_buff *, skb)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->frag_idx = frag_idx;
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->daddr = daddr;
|
||||
__entry->size = size;
|
||||
__entry->skb = skb;
|
||||
),
|
||||
TP_printk("idx %d ring idx %d daddr %pad len %#zx skb %p",
|
||||
__entry->frag_idx, __entry->ring_idx, &__entry->daddr,
|
||||
__entry->size, __entry->skb)
|
||||
);
|
||||
|
||||
#define DEFINE_UNMAP_EVENT(name) \
|
||||
DEFINE_EVENT(atl_dma_unmap_class, name, \
|
||||
TP_PROTO(int frag_idx, int ring_idx, dma_addr_t daddr, \
|
||||
size_t size, struct sk_buff *skb), \
|
||||
TP_ARGS(frag_idx, ring_idx, daddr, size, skb))
|
||||
|
||||
DEFINE_UNMAP_EVENT(atl_dma_unmap_head);
|
||||
DEFINE_UNMAP_EVENT(atl_dma_unmap_frag);
|
||||
DEFINE_UNMAP_EVENT(atl_dma_unmap_rxbuf);
|
||||
|
||||
TRACE_EVENT(atl_fill_rx_desc,
|
||||
TP_PROTO(int ring_idx, struct atl_rx_desc *desc),
|
||||
TP_ARGS(ring_idx, desc),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, ring_idx)
|
||||
__field(dma_addr_t, daddr)
|
||||
__field(dma_addr_t, haddr)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->daddr = desc->daddr;
|
||||
__entry->haddr = desc->haddr;
|
||||
),
|
||||
TP_printk("[%d] daddr %pad", __entry->ring_idx, &__entry->daddr)
|
||||
);
|
||||
|
||||
TRACE_EVENT(atl_sync_rx_range,
|
||||
TP_PROTO(int ring_idx, dma_addr_t daddr, unsigned long pg_off,
|
||||
size_t size),
|
||||
TP_ARGS(ring_idx, daddr, pg_off, size),
|
||||
TP_STRUCT__entry(
|
||||
__field(int, ring_idx)
|
||||
__field(dma_addr_t, daddr)
|
||||
__field(unsigned long, pg_off)
|
||||
__field(size_t, size)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->daddr = daddr;
|
||||
__entry->pg_off = pg_off;
|
||||
__entry->size = size;
|
||||
),
|
||||
TP_printk("[%d] daddr %pad pg_off %#lx size %#zx", __entry->ring_idx,
|
||||
&__entry->daddr, __entry->pg_off, __entry->size)
|
||||
);
|
||||
|
||||
#define DESCR_FIELD(DESCR, BIT_BEGIN, BIT_END) \
|
||||
((DESCR >> BIT_END) &\
|
||||
(BIT_ULL(BIT_BEGIN - BIT_END + 1) - 1))
|
||||
|
||||
TRACE_EVENT(atl_rx_descr,
|
||||
TP_PROTO(int ring_idx, unsigned int pointer, u64 *descr),
|
||||
TP_ARGS(ring_idx, pointer, descr),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, ring_idx)
|
||||
__field(unsigned int, pointer)
|
||||
__field(u8, dd)
|
||||
__field(u8, eop)
|
||||
__field(u8, rx_stat)
|
||||
__field(u8, rx_estat)
|
||||
__field(u8, rsc_cnt)
|
||||
__field(u16, pkt_len)
|
||||
__field(u16, next_desp)
|
||||
__field(u16, vlan_tag)
|
||||
|
||||
__field(u8, rss_type)
|
||||
__field(u8, pkt_type)
|
||||
__field(u8, rsvd)
|
||||
__field(u8, rx_cntl)
|
||||
__field(u8, sph)
|
||||
__field(u16, hdr_len)
|
||||
__field(u32, rss_hash)
|
||||
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->pointer = pointer;
|
||||
__entry->rss_hash = DESCR_FIELD(descr[0], 63, 32);
|
||||
__entry->hdr_len = DESCR_FIELD(descr[0], 31, 22);
|
||||
__entry->sph = DESCR_FIELD(descr[0], 21, 21);
|
||||
__entry->rx_cntl = DESCR_FIELD(descr[0], 20, 19);
|
||||
__entry->rsvd = DESCR_FIELD(descr[0], 18, 12);
|
||||
__entry->pkt_type = DESCR_FIELD(descr[0], 11, 4);
|
||||
__entry->rss_type = DESCR_FIELD(descr[0], 3, 0);
|
||||
|
||||
__entry->vlan_tag = DESCR_FIELD(descr[1], 63, 48);
|
||||
__entry->next_desp = DESCR_FIELD(descr[1], 47, 32);
|
||||
__entry->pkt_len = DESCR_FIELD(descr[1], 31, 16);
|
||||
__entry->rsc_cnt = DESCR_FIELD(descr[1], 15, 12);
|
||||
__entry->rx_estat = DESCR_FIELD(descr[1], 11, 6);
|
||||
__entry->rx_stat = DESCR_FIELD(descr[1], 5, 2);
|
||||
__entry->eop = DESCR_FIELD(descr[1], 1, 1);
|
||||
__entry->dd = DESCR_FIELD(descr[1], 0, 0);
|
||||
),
|
||||
TP_printk("ring=%d descr=%u rss_hash=0x%x hdr_len=%u sph=%u rx_cntl=%u rsvd=0x%x pkt_type=%u rss_type=%u vlan_tag=%u next_desp=%u pkt_len=%u rsc_cnt=%u rx_estat=0x%x rx_stat=0x%x eop=%u dd=%u",
|
||||
__entry->ring_idx, __entry->pointer, __entry->rss_hash,
|
||||
__entry->hdr_len, __entry->sph, __entry->rx_cntl,
|
||||
__entry->rsvd, __entry->pkt_type, __entry->rss_type,
|
||||
__entry->vlan_tag, __entry->next_desp, __entry->pkt_len,
|
||||
__entry->rsc_cnt, __entry->rx_estat, __entry->rx_stat,
|
||||
__entry->eop, __entry->dd)
|
||||
);
|
||||
|
||||
TRACE_EVENT(atl_tx_descr,
|
||||
TP_PROTO(int ring_idx, unsigned int pointer, u64 *descr),
|
||||
TP_ARGS(ring_idx, pointer, descr),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, ring_idx)
|
||||
__field(unsigned int, pointer)
|
||||
/* Tx Descriptor */
|
||||
__field(u64, data_buf_addr)
|
||||
__field(u32, pay_len)
|
||||
__field(u8, ct_en)
|
||||
__field(u8, ct_idx)
|
||||
__field(u16, rsvd2)
|
||||
__field(u8, tx_cmd)
|
||||
__field(u8, eop)
|
||||
__field(u8, dd)
|
||||
__field(u16, buf_len)
|
||||
__field(u8, rsvd1)
|
||||
__field(u8, des_typ)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->pointer = pointer;
|
||||
__entry->data_buf_addr = descr[0];
|
||||
__entry->pay_len = DESCR_FIELD(descr[1], 63, 46);
|
||||
__entry->ct_en = DESCR_FIELD(descr[1], 45, 45);
|
||||
__entry->ct_idx = DESCR_FIELD(descr[1], 44, 44);
|
||||
__entry->rsvd2 = DESCR_FIELD(descr[1], 43, 30);
|
||||
__entry->tx_cmd = DESCR_FIELD(descr[1], 29, 22);
|
||||
__entry->eop = DESCR_FIELD(descr[1], 21, 21);
|
||||
__entry->dd = DESCR_FIELD(descr[1], 20, 20);
|
||||
__entry->buf_len = DESCR_FIELD(descr[1], 19, 4);
|
||||
__entry->rsvd1 = DESCR_FIELD(descr[1], 3, 3);
|
||||
__entry->des_typ = DESCR_FIELD(descr[1], 2, 0);
|
||||
|
||||
),
|
||||
TP_printk("ring=%d descr=%u pay_len=%u ct_en=%u ct_idx=%u rsvd2=0x%x tx_cmd=0x%x eop=%u dd=%u buf_len=%u rsvd1=%u des_typ=0x%x",
|
||||
__entry->ring_idx, __entry->pointer, __entry->pay_len,
|
||||
__entry->ct_en, __entry->ct_idx, __entry->rsvd2,
|
||||
__entry->tx_cmd, __entry->eop, __entry->dd, __entry->buf_len,
|
||||
__entry->rsvd1, __entry->des_typ)
|
||||
);
|
||||
|
||||
|
||||
TRACE_EVENT(atl_tx_context_descr,
|
||||
TP_PROTO(int ring_idx, unsigned int pointer, u64 *descr),
|
||||
TP_ARGS(ring_idx, pointer, descr),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, ring_idx)
|
||||
__field(unsigned int, pointer)
|
||||
/* Tx Context Descriptor */
|
||||
__field(u8, out_len)
|
||||
__field(u8, tun_len)
|
||||
__field(u64, resvd3)
|
||||
__field(u16, mss_len)
|
||||
__field(u8, l4_len)
|
||||
__field(u8, l3_len)
|
||||
__field(u8, l2_len)
|
||||
__field(u8, ct_cmd)
|
||||
__field(u16, vlan_tag)
|
||||
__field(u8, ct_idx)
|
||||
__field(u8, des_typ)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ring_idx = ring_idx;
|
||||
__entry->pointer = pointer;
|
||||
__entry->out_len = DESCR_FIELD(descr[0], 63, 56);
|
||||
__entry->tun_len = DESCR_FIELD(descr[0], 55, 48);
|
||||
__entry->resvd3 = DESCR_FIELD(descr[0], 47, 0);
|
||||
__entry->mss_len = DESCR_FIELD(descr[1], 63, 48);
|
||||
__entry->l4_len = DESCR_FIELD(descr[1], 47, 40);
|
||||
__entry->l3_len = DESCR_FIELD(descr[1], 39, 31);
|
||||
__entry->l2_len = DESCR_FIELD(descr[1], 30, 24);
|
||||
__entry->ct_cmd = DESCR_FIELD(descr[1], 23, 20);
|
||||
__entry->vlan_tag = DESCR_FIELD(descr[1], 19, 4);
|
||||
__entry->ct_idx = DESCR_FIELD(descr[1], 3, 3);
|
||||
__entry->des_typ = DESCR_FIELD(descr[1], 2, 0);
|
||||
),
|
||||
TP_printk("ring=%d descr=%u out_len=%u tun_len=%u resvd3=%llu mss_len=%u l4_len=%u l3_len=%u l2_len=0x%x ct_cmd=%u vlan_tag=%u ct_idx=%u des_typ=0x%x",
|
||||
__entry->ring_idx, __entry->pointer, __entry->out_len,
|
||||
__entry->tun_len, __entry->resvd3, __entry->mss_len,
|
||||
__entry->l4_len, __entry->l3_len, __entry->l2_len,
|
||||
__entry->ct_cmd, __entry->vlan_tag, __entry->ct_idx,
|
||||
__entry->des_typ)
|
||||
);
|
||||
|
||||
#endif /* _ATL_TRACE_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE atl_trace
|
||||
#include <trace/define_trace.h>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Atlantic Network Driver
|
||||
#
|
||||
# Copyright (C) 2019 aQuantia Corporation
|
||||
# Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
PKGCONFIG?=$(shell which pkg-config)
|
||||
ifeq ($(PKGCONFIG),)
|
||||
$(info Do you have pkg-config installed? If not, install it, e.g. on Ubuntu)
|
||||
$(info $$ apt install pkg-config)
|
||||
$(error pkg-config not found)
|
||||
endif
|
||||
LIBMNL_EXISTS=$(shell $(PKGCONFIG) --exists libmnl && echo "yes" || echo "no")
|
||||
ifeq ($(LIBMNL_EXISTS),no)
|
||||
$(info Do you have libmnl-dev installed? If not, install it, e.g. on Ubuntu)
|
||||
$(info $$ apt install libmnl-dev)
|
||||
$(error libmnl not found)
|
||||
endif
|
||||
|
||||
CFLAGS+=-Wall -Werror -Wfatal-errors $(shell $(PKGCONFIG) --cflags libmnl) -I..
|
||||
LDLIBS+=$(shell $(PKGCONFIG) --libs libmnl)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: atlfwdtool
|
||||
|
||||
atlfwdtool: atlfwdtool.c atlfwd_args.c atlfwd_msg.c atlfwd_reply.c
|
||||
$(LINK.c) $^ $(LDLIBS) -o $@
|
||||
|
||||
clean:
|
||||
$(RM) atlfwdtool
|
||||
$(RM) *.o
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "atlfwd_args.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libmnl/libmnl.h"
|
||||
|
||||
static void print_usage(const char *binname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-d devname] [-v] command <command_args>\n\n",
|
||||
binname);
|
||||
fprintf(stderr, "%s\n", "Options:");
|
||||
fprintf(stderr, "\t%s\n",
|
||||
"-d devname\t- specify device name to work with");
|
||||
fprintf(stderr, "\t%s\n", "-v\t\t- verbose mode");
|
||||
fprintf(stderr, "%s\n", "");
|
||||
fprintf(stderr, "%s\n", "Supported commands:");
|
||||
fprintf(stderr, "\t%s\n",
|
||||
"request_ring <flags> <ring_size> <buf_size> <page_order>");
|
||||
fprintf(stderr, "\t%s\n", "release_ring <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "enable_ring <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "disable_ring <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "dump_ring <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "request_event <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "release_event <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "enable_event <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "disable_event <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "get_rx_queue_index <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "get_tx_queue_index <ring_index>");
|
||||
fprintf(stderr, "%s\n", "");
|
||||
fprintf(stderr, "\t%s\n", "force_icmp_tx_via <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "force_tx_via <ring_index>");
|
||||
fprintf(stderr, "\t%s\n", "disable_redirections");
|
||||
fprintf(stderr, "%s\n", "");
|
||||
fprintf(stderr, "\t%s\n", "ring_status [<ring_index>]");
|
||||
fprintf(stderr, "\t%s\n", "set_tx_bunch <bunch_size>");
|
||||
}
|
||||
|
||||
#define STR_EQUAL(s1, s2) (strncmp((s1), (s2), MNL_ARRAY_SIZE((s2))) == 0)
|
||||
|
||||
static enum atlfwd_nl_command get_command(const char *str)
|
||||
{
|
||||
static const char cmd_req_ring[] = "request_ring";
|
||||
static const char cmd_rel_ring[] = "release_ring";
|
||||
static const char cmd_enable_ring[] = "enable_ring";
|
||||
static const char cmd_disable_ring[] = "disable_ring";
|
||||
static const char cmd_req_event[] = "request_event";
|
||||
static const char cmd_rel_event[] = "release_event";
|
||||
static const char cmd_enable_event[] = "enable_event";
|
||||
static const char cmd_disable_event[] = "disable_event";
|
||||
static const char cmd_dump_ring[] = "dump_ring";
|
||||
static const char cmd_get_rx_queue[] = "get_rx_queue_index";
|
||||
static const char cmd_get_tx_queue[] = "get_tx_queue_index";
|
||||
static const char cmd_disable_redirections[] = "disable_redirections";
|
||||
static const char cmd_force_icmp_tx_via[] = "force_icmp_tx_via";
|
||||
static const char cmd_force_tx_via[] = "force_tx_via";
|
||||
static const char cmd_ring_status[] = "ring_status";
|
||||
static const char cmd_set_tx_bunch[] = "set_tx_bunch";
|
||||
|
||||
if (STR_EQUAL(str, cmd_req_ring))
|
||||
return ATL_FWD_CMD_REQUEST_RING;
|
||||
|
||||
if (STR_EQUAL(str, cmd_rel_ring))
|
||||
return ATL_FWD_CMD_RELEASE_RING;
|
||||
|
||||
if (STR_EQUAL(str, cmd_enable_ring))
|
||||
return ATL_FWD_CMD_ENABLE_RING;
|
||||
|
||||
if (STR_EQUAL(str, cmd_disable_ring))
|
||||
return ATL_FWD_CMD_DISABLE_RING;
|
||||
|
||||
if (STR_EQUAL(str, cmd_dump_ring))
|
||||
return ATL_FWD_CMD_DUMP_RING;
|
||||
|
||||
if (STR_EQUAL(str, cmd_get_rx_queue))
|
||||
return ATL_FWD_CMD_GET_RX_QUEUE;
|
||||
|
||||
if (STR_EQUAL(str, cmd_get_tx_queue))
|
||||
return ATL_FWD_CMD_GET_TX_QUEUE;
|
||||
|
||||
if (STR_EQUAL(str, cmd_req_event))
|
||||
return ATL_FWD_CMD_REQUEST_EVENT;
|
||||
|
||||
if (STR_EQUAL(str, cmd_rel_event))
|
||||
return ATL_FWD_CMD_RELEASE_EVENT;
|
||||
|
||||
if (STR_EQUAL(str, cmd_enable_event))
|
||||
return ATL_FWD_CMD_ENABLE_EVENT;
|
||||
|
||||
if (STR_EQUAL(str, cmd_disable_event))
|
||||
return ATL_FWD_CMD_DISABLE_EVENT;
|
||||
|
||||
if (STR_EQUAL(str, cmd_disable_redirections))
|
||||
return ATL_FWD_CMD_DISABLE_REDIRECTIONS;
|
||||
|
||||
if (STR_EQUAL(str, cmd_force_icmp_tx_via))
|
||||
return ATL_FWD_CMD_FORCE_ICMP_TX_VIA;
|
||||
|
||||
if (STR_EQUAL(str, cmd_force_tx_via))
|
||||
return ATL_FWD_CMD_FORCE_TX_VIA;
|
||||
|
||||
if (STR_EQUAL(str, cmd_ring_status))
|
||||
return ATL_FWD_CMD_RING_STATUS;
|
||||
|
||||
if (STR_EQUAL(str, cmd_set_tx_bunch))
|
||||
return ATL_FWD_CMD_SET_TX_BUNCH;
|
||||
|
||||
return ATL_FWD_CMD_UNSPEC;
|
||||
}
|
||||
|
||||
static const char *get_arg(const int argc, char **argv)
|
||||
{
|
||||
if (argc == optind) {
|
||||
/* not enough arguments => exit immediately */
|
||||
print_usage(argv[0]);
|
||||
exit(EINVAL);
|
||||
}
|
||||
|
||||
return argv[optind++];
|
||||
}
|
||||
|
||||
static const char *get_last_arg(const int argc, char **argv)
|
||||
{
|
||||
const char *result = get_arg(argc, argv);
|
||||
|
||||
if (optind != argc) {
|
||||
/* too many arguments => exit immediately */
|
||||
print_usage(argv[0]);
|
||||
exit(EINVAL);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct atlfwd_args *parse_args(const int argc, char **argv)
|
||||
{
|
||||
static struct atlfwd_args parsed_args;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:v")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
parsed_args.devname = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
parsed_args.verbose = true;
|
||||
break;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
parsed_args.cmd = get_command(get_arg(argc, argv));
|
||||
|
||||
switch (parsed_args.cmd) {
|
||||
case ATL_FWD_CMD_REQUEST_RING:
|
||||
parsed_args.flags = (uint32_t)atoi(get_arg(argc, argv));
|
||||
parsed_args.ring_size = (uint32_t)atoi(get_arg(argc, argv));
|
||||
parsed_args.buf_size = (uint32_t)atoi(get_arg(argc, argv));
|
||||
parsed_args.page_order =
|
||||
(uint32_t)atoi(get_last_arg(argc, argv));
|
||||
break;
|
||||
case ATL_FWD_CMD_RING_STATUS:
|
||||
if (optind == argc) {
|
||||
parsed_args.ring_index = -1;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_RELEASE_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_ENABLE_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_DISABLE_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_DUMP_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_REQUEST_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_RELEASE_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_ENABLE_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_DISABLE_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_GET_RX_QUEUE:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_GET_TX_QUEUE:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_FORCE_ICMP_TX_VIA:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_FORCE_TX_VIA:
|
||||
parsed_args.ring_index =
|
||||
(int32_t)atoi(get_last_arg(argc, argv));
|
||||
break;
|
||||
case ATL_FWD_CMD_SET_TX_BUNCH:
|
||||
parsed_args.tx_bunch = (uint32_t)atoi(get_last_arg(argc, argv));
|
||||
break;
|
||||
case ATL_FWD_CMD_DISABLE_REDIRECTIONS:
|
||||
break;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &parsed_args;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATLFWD_ARGS_H_
|
||||
#define _ATLFWD_ARGS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "atl_fwdnl.h"
|
||||
|
||||
struct atlfwd_args {
|
||||
char *devname;
|
||||
bool verbose;
|
||||
enum atlfwd_nl_command cmd;
|
||||
union {
|
||||
struct {
|
||||
uint32_t flags;
|
||||
uint32_t ring_size;
|
||||
uint32_t buf_size;
|
||||
uint32_t page_order;
|
||||
};
|
||||
int32_t ring_index;
|
||||
uint32_t tx_bunch;
|
||||
};
|
||||
};
|
||||
|
||||
struct atlfwd_args *parse_args(const int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATLFWD_CTX_H_
|
||||
#define _ATLFWD_CTX_H_
|
||||
|
||||
#include "libmnl/libmnl.h"
|
||||
#include "linux/genetlink.h"
|
||||
|
||||
#include "atl_fwdnl.h"
|
||||
|
||||
struct nl_context {
|
||||
struct mnl_socket *sock;
|
||||
unsigned int port;
|
||||
unsigned int seq;
|
||||
char *msgbuf;
|
||||
unsigned int msgbufsize;
|
||||
struct nlmsghdr *nlhdr;
|
||||
struct genlmsghdr *gnlhdr;
|
||||
int family_id;
|
||||
char *devname;
|
||||
int verbose;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "atlfwd_msg.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int atlnl_msg_alloc(struct nl_context *ctx, const int msg_type, const int cmd,
|
||||
const unsigned int flags, const int version)
|
||||
{
|
||||
ctx->msgbuf = malloc(MNL_SOCKET_BUFFER_SIZE);
|
||||
if (!ctx->msgbuf)
|
||||
return -ENOMEM;
|
||||
ctx->msgbufsize = MNL_SOCKET_BUFFER_SIZE;
|
||||
memset(ctx->msgbuf, 0, MNL_SOCKET_BUFFER_SIZE);
|
||||
|
||||
struct nlmsghdr *nlhdr = mnl_nlmsg_put_header(ctx->msgbuf);
|
||||
|
||||
nlhdr->nlmsg_type = msg_type;
|
||||
nlhdr->nlmsg_flags = flags;
|
||||
nlhdr->nlmsg_seq = ++ctx->seq;
|
||||
ctx->nlhdr = nlhdr;
|
||||
|
||||
struct genlmsghdr *gnlhdr =
|
||||
mnl_nlmsg_put_extra_header(nlhdr, sizeof(*gnlhdr));
|
||||
|
||||
gnlhdr->cmd = cmd;
|
||||
gnlhdr->version = version;
|
||||
ctx->gnlhdr = gnlhdr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atlnl_msg_realloc(struct nl_context *ctx, const unsigned int new_size)
|
||||
{
|
||||
const unsigned int old_size = ctx->msgbufsize;
|
||||
unsigned int nlhdr_offset = (char *)ctx->nlhdr - ctx->msgbuf;
|
||||
unsigned int gnlhdr_offset = (char *)ctx->gnlhdr - ctx->msgbuf;
|
||||
char *new_buff = realloc(ctx->msgbuf, new_size);
|
||||
|
||||
if (!new_buff)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(new_buff + old_size, 0, new_size - old_size);
|
||||
ctx->msgbuf = new_buff;
|
||||
ctx->msgbufsize = new_size;
|
||||
ctx->nlhdr = (struct nlmsghdr *)(new_buff + nlhdr_offset);
|
||||
ctx->gnlhdr = (struct genlmsghdr *)(new_buff + gnlhdr_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atlnl_msg_free(struct nl_context *ctx)
|
||||
{
|
||||
if (ctx->msgbuf)
|
||||
free(ctx->msgbuf);
|
||||
|
||||
ctx->msgbuf = NULL;
|
||||
ctx->msgbufsize = 0;
|
||||
ctx->nlhdr = NULL;
|
||||
ctx->gnlhdr = NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATLFWD_MSG_H_
|
||||
#define _ATLFWD_MSG_H_
|
||||
|
||||
#include "atlfwd_ctx.h"
|
||||
|
||||
int atlnl_msg_alloc(struct nl_context *ctx, const int msg_type, const int cmd,
|
||||
const unsigned int flags, const int version);
|
||||
int atlnl_msg_realloc(struct nl_context *ctx, const unsigned int new_size);
|
||||
void atlnl_msg_free(struct nl_context *ctx);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "atlfwd_reply.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "atlfwd_msg.h"
|
||||
|
||||
int atlnl_process_ack(struct nl_context *ctx, const ssize_t len)
|
||||
{
|
||||
struct nlmsgerr *nlerr = mnl_nlmsg_get_payload(ctx->nlhdr);
|
||||
unsigned int tlv_offset = sizeof(*nlerr);
|
||||
|
||||
if (len < NLMSG_HDRLEN + tlv_offset)
|
||||
return -EFAULT;
|
||||
|
||||
#ifdef NLM_F_ACK_TLVS
|
||||
if (ctx->nlhdr->nlmsg_flags & NLM_F_ACK_TLVS) {
|
||||
if (!(ctx->nlhdr->nlmsg_flags & NLM_F_CAPPED))
|
||||
tlv_offset += MNL_ALIGN(
|
||||
mnl_nlmsg_get_payload_len(&nlerr->msg));
|
||||
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each(attr, ctx->nlhdr, tlv_offset)
|
||||
{
|
||||
if (mnl_attr_get_type(attr) == NLMSGERR_ATTR_MSG &&
|
||||
(ctx->verbose || nlerr->error)) {
|
||||
const char *msg = mnl_attr_get_str(attr);
|
||||
|
||||
fprintf(stderr, "netlink %s: %s\n",
|
||||
nlerr->error ? "error" : "warning",
|
||||
msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nlerr->error) {
|
||||
errno = -nlerr->error;
|
||||
perror("netlink error");
|
||||
} else if (ctx->verbose) {
|
||||
printf("%s\n", "got ack");
|
||||
}
|
||||
|
||||
return nlerr->error;
|
||||
}
|
||||
|
||||
int atlnl_process_reply(struct nl_context *ctx, mnl_cb_t reply_cb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
atlnl_msg_realloc(ctx, 4096);
|
||||
do {
|
||||
ssize_t len = mnl_socket_recvfrom(ctx->sock, ctx->msgbuf,
|
||||
ctx->msgbufsize);
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (len < NLMSG_HDRLEN)
|
||||
return -EFAULT;
|
||||
|
||||
ctx->nlhdr = (struct nlmsghdr *)ctx->msgbuf;
|
||||
if (ctx->nlhdr->nlmsg_type == NLMSG_ERROR)
|
||||
return atlnl_process_ack(ctx, len);
|
||||
|
||||
ctx->gnlhdr = mnl_nlmsg_get_payload(ctx->nlhdr);
|
||||
ret = mnl_cb_run(ctx->msgbuf, len, ctx->seq, ctx->port,
|
||||
reply_cb, ctx);
|
||||
} while (ret > 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ATLFWD_REPLY_H_
|
||||
#define _ATLFWD_REPLY_H_
|
||||
|
||||
#include "atlfwd_ctx.h"
|
||||
|
||||
int atlnl_process_ack(struct nl_context *ctx, const ssize_t len);
|
||||
int atlnl_process_reply(struct nl_context *ctx, mnl_cb_t reply_cb);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,418 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "atlfwd_args.h"
|
||||
#include "atlfwd_ctx.h"
|
||||
#include "atlfwd_msg.h"
|
||||
#include "atlfwd_reply.h"
|
||||
|
||||
#define ATL_FWD_CMD_STR(cmd)\
|
||||
[cmd] = #cmd
|
||||
static const char *cmd_str[NUM_ATL_FWD_CMD] = {
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_REQUEST_RING),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_RELEASE_RING),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_ENABLE_RING),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_DISABLE_RING),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_DISABLE_REDIRECTIONS),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_FORCE_ICMP_TX_VIA),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_FORCE_TX_VIA),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_RING_STATUS),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_DUMP_RING),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_SET_TX_BUNCH),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_REQUEST_EVENT),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_RELEASE_EVENT),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_ENABLE_EVENT),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_DISABLE_EVENT),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_GET_RX_QUEUE),
|
||||
ATL_FWD_CMD_STR(ATL_FWD_CMD_GET_TX_QUEUE),
|
||||
};
|
||||
#define ATL_FWD_ATTR_STR(attr)\
|
||||
[attr] = #attr
|
||||
static const char *attr_str[NUM_ATL_FWD_ATTR] = {
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_FLAGS),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_RING_SIZE),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_BUF_SIZE),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_PAGE_ORDER),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_RING_INDEX),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_RING_STATUS),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_RING_IS_TX),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_RING_FLAGS),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_TX_BUNCH_SIZE),
|
||||
ATL_FWD_ATTR_STR(ATL_FWD_ATTR_QUEUE_INDEX),
|
||||
};
|
||||
|
||||
/* get atl_fwd family id */
|
||||
static int atlnl_family_cb(const struct nlmsghdr *nlhdr, void *data)
|
||||
{
|
||||
struct nl_context *ctx = (struct nl_context *)data;
|
||||
const struct nlattr *attr;
|
||||
|
||||
ctx->family_id = 0;
|
||||
mnl_attr_for_each(attr, nlhdr, GENL_HDRLEN)
|
||||
{
|
||||
if (mnl_attr_get_type(attr) == CTRL_ATTR_FAMILY_ID) {
|
||||
ctx->family_id = mnl_attr_get_u16(attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (ctx->family_id ? MNL_CB_OK : MNL_CB_ERROR);
|
||||
}
|
||||
|
||||
static int atlnl_get_family_id(struct nl_context *ctx)
|
||||
{
|
||||
int ret = atlnl_msg_alloc(ctx, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
|
||||
NLM_F_REQUEST | NLM_F_ACK, 1);
|
||||
if (ctx->verbose)
|
||||
printf("calling %s\n", "CTRL_CMD_GETFAMILY");
|
||||
if (ret != 0)
|
||||
goto err_msgfree;
|
||||
|
||||
mnl_attr_put_strz(ctx->nlhdr, CTRL_ATTR_FAMILY_NAME, ATL_FWD_GENL_NAME);
|
||||
|
||||
if (mnl_socket_sendto(ctx->sock, ctx->nlhdr, ctx->nlhdr->nlmsg_len) < 0)
|
||||
goto err_msgfree;
|
||||
|
||||
ret = atlnl_process_reply(ctx, atlnl_family_cb);
|
||||
if (ret < 0)
|
||||
goto err_msgfree;
|
||||
|
||||
ret = ctx->family_id ? 0 : -EADDRNOTAVAIL;
|
||||
|
||||
if (ctx->verbose)
|
||||
printf("family id: %d\n", ctx->family_id);
|
||||
|
||||
err_msgfree:
|
||||
atlnl_msg_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atlnl_reqring_cb(const struct nlmsghdr *nlhdr, void *data)
|
||||
{
|
||||
const struct nlattr *attr;
|
||||
int ring_index = -1;
|
||||
|
||||
mnl_attr_for_each(attr, nlhdr, GENL_HDRLEN)
|
||||
{
|
||||
if (mnl_attr_get_type(attr) == ATL_FWD_ATTR_RING_INDEX) {
|
||||
ring_index = (int)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ring_index == -1) {
|
||||
fprintf(stderr, "Error: %s attribute is missing in reply\n",
|
||||
attr_str[ATL_FWD_ATTR_RING_INDEX]);
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
printf("Ring index: %d\n", ring_index);
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int atlnl_getqueue_cb(const struct nlmsghdr *nlhdr, void *data)
|
||||
{
|
||||
const struct nlattr *attr;
|
||||
int queue = -1;
|
||||
|
||||
mnl_attr_for_each(attr, nlhdr, GENL_HDRLEN)
|
||||
{
|
||||
if (mnl_attr_get_type(attr) == ATL_FWD_ATTR_QUEUE_INDEX) {
|
||||
queue = (int)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (queue == -1) {
|
||||
fprintf(stderr, "Error: %s attribute is missing in reply\n",
|
||||
attr_str[ATL_FWD_ATTR_QUEUE_INDEX]);
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
printf("%d\n", queue);
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static bool is_ring_created(const enum atlfwd_nl_ring_status ring_status)
|
||||
{
|
||||
switch (ring_status) {
|
||||
case ATL_FWD_RING_STATUS_CREATED_DISABLED:
|
||||
case ATL_FWD_RING_STATUS_ENABLED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *
|
||||
ring_status_string(const enum atlfwd_nl_ring_status ring_status)
|
||||
{
|
||||
static const char *status_str[NUM_ATL_FWD_RING_STATUS] = {
|
||||
[ATL_FWD_RING_STATUS_INVALID] = "invalid status",
|
||||
[ATL_FWD_RING_STATUS_RELEASED] = "released",
|
||||
[ATL_FWD_RING_STATUS_CREATED_DISABLED] = "disabled",
|
||||
[ATL_FWD_RING_STATUS_ENABLED] = "enabled",
|
||||
};
|
||||
|
||||
return (ring_status < NUM_ATL_FWD_RING_STATUS ?
|
||||
status_str[ring_status] :
|
||||
status_str[ATL_FWD_RING_STATUS_INVALID]);
|
||||
}
|
||||
|
||||
struct ring_status {
|
||||
enum atlfwd_nl_ring_status status;
|
||||
bool is_tx;
|
||||
int size;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
static void print_ring_status(const int ring_index,
|
||||
const struct ring_status *status)
|
||||
{
|
||||
char prefix[16];
|
||||
|
||||
snprintf(prefix, MNL_ARRAY_SIZE(prefix), "fwd_ring_%d_", ring_index);
|
||||
|
||||
printf("%sstatus:\t%s\n", prefix, ring_status_string(status->status));
|
||||
printf("%sdirection:\t%s\n", prefix, status->is_tx ? "tx" : "rx");
|
||||
if (is_ring_created(status->status)) {
|
||||
printf("%sflags:\t%d\n", prefix, status->flags);
|
||||
printf("%ssize:\t%d\n", prefix, status->size);
|
||||
} else {
|
||||
printf("%sflags:\t%s\n", prefix, "n/a");
|
||||
printf("%ssize:\t%s\n", prefix, "n/a");
|
||||
}
|
||||
}
|
||||
|
||||
static int atlnl_ringstatus_cb(const struct nlmsghdr *nlhdr, void *data)
|
||||
{
|
||||
const struct nlattr *attr;
|
||||
int ring_index = -1;
|
||||
struct ring_status status = {
|
||||
.status = ATL_FWD_RING_STATUS_INVALID,
|
||||
.is_tx = false,
|
||||
.size = 0,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
mnl_attr_for_each(attr, nlhdr, GENL_HDRLEN)
|
||||
{
|
||||
switch (mnl_attr_get_type(attr)) {
|
||||
case ATL_FWD_ATTR_RING_INDEX:
|
||||
if (ring_index >= 0)
|
||||
print_ring_status(ring_index, &status);
|
||||
ring_index = (int)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
case ATL_FWD_ATTR_RING_STATUS:
|
||||
status.status = (int)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
case ATL_FWD_ATTR_RING_IS_TX:
|
||||
status.is_tx = (bool)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
case ATL_FWD_ATTR_RING_SIZE:
|
||||
status.size = (int)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
case ATL_FWD_ATTR_RING_FLAGS:
|
||||
status.flags = (unsigned int)mnl_attr_get_u32(attr);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: %s\n",
|
||||
"Unexpected attribute in reply");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ring_index == -1) {
|
||||
fprintf(stderr, "Error: %s\n", "Incorrect reply");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
print_ring_status(ring_index, &status);
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int atlnl_cmd_generic_u32_args(struct nl_context *ctx,
|
||||
const enum atlfwd_nl_command cmd,
|
||||
mnl_cb_t reply_cb, const int attr_count,
|
||||
...)
|
||||
{
|
||||
int ret = atlnl_msg_alloc(ctx, ctx->family_id, cmd,
|
||||
NLM_F_REQUEST | NLM_F_ACK, 1);
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error: %s\n", "message allocation failed.");
|
||||
goto err_msgfree;
|
||||
}
|
||||
|
||||
if (ctx->verbose)
|
||||
printf("calling %s\n",
|
||||
cmd_str[cmd] ? cmd_str[cmd] : "unknown command");
|
||||
|
||||
if (ctx->devname != NULL)
|
||||
mnl_attr_put_strz(ctx->nlhdr, ATL_FWD_ATTR_IFNAME,
|
||||
ctx->devname);
|
||||
|
||||
va_start(args, attr_count);
|
||||
for (i = 0; i != attr_count; i++) {
|
||||
const enum atlfwd_nl_attribute attr =
|
||||
va_arg(args, enum atlfwd_nl_attribute);
|
||||
const uint32_t value = va_arg(args, uint32_t);
|
||||
|
||||
mnl_attr_put_u32(ctx->nlhdr, attr, value);
|
||||
|
||||
if (ctx->verbose)
|
||||
printf("\t(%s: %u)\n",
|
||||
attr_str[attr] ? attr_str[attr] :
|
||||
"unknown attribute",
|
||||
value);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if (mnl_socket_sendto(ctx->sock, ctx->nlhdr, ctx->nlhdr->nlmsg_len) < 0)
|
||||
goto err_msgfree;
|
||||
|
||||
ret = atlnl_process_reply(ctx, reply_cb);
|
||||
|
||||
err_msgfree:
|
||||
atlnl_msg_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct atlfwd_args *args = parse_args(argc, argv);
|
||||
static struct nl_context nlctx;
|
||||
int result = EINVAL;
|
||||
int ret = 0;
|
||||
|
||||
if (!args)
|
||||
return result;
|
||||
|
||||
nlctx.devname = args->devname;
|
||||
nlctx.verbose = args->verbose;
|
||||
|
||||
result = ECONNREFUSED;
|
||||
|
||||
/* open socket */
|
||||
nlctx.sock = mnl_socket_open(NETLINK_GENERIC);
|
||||
if (!nlctx.sock)
|
||||
return result;
|
||||
|
||||
#ifdef NETLINK_EXT_ACK
|
||||
/* request extended acknowledgment */
|
||||
unsigned int true_val = 1;
|
||||
ret = mnl_socket_setsockopt(nlctx.sock, NETLINK_EXT_ACK, &true_val,
|
||||
sizeof(true_val));
|
||||
if (ret < 0)
|
||||
goto err_sockclose;
|
||||
#endif
|
||||
|
||||
/* bind and get the port id */
|
||||
ret = mnl_socket_bind(nlctx.sock, 0, MNL_SOCKET_AUTOPID);
|
||||
if (ret < 0) {
|
||||
result = -ret;
|
||||
goto err_sockclose;
|
||||
}
|
||||
nlctx.port = mnl_socket_get_portid(nlctx.sock);
|
||||
|
||||
/* parse command line options */
|
||||
result = EINVAL;
|
||||
|
||||
/* obtain family id by name */
|
||||
ret = atlnl_get_family_id(&nlctx);
|
||||
if (ret < 0)
|
||||
goto err_sockclose;
|
||||
|
||||
/* process command(s) */
|
||||
switch (args->cmd) {
|
||||
case ATL_FWD_CMD_REQUEST_RING:
|
||||
ret = atlnl_cmd_generic_u32_args(
|
||||
&nlctx, args->cmd, atlnl_reqring_cb, 4,
|
||||
ATL_FWD_ATTR_FLAGS, args->flags, ATL_FWD_ATTR_RING_SIZE,
|
||||
args->ring_size, ATL_FWD_ATTR_BUF_SIZE, args->buf_size,
|
||||
ATL_FWD_ATTR_PAGE_ORDER, args->page_order);
|
||||
break;
|
||||
case ATL_FWD_CMD_RELEASE_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_ENABLE_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_DISABLE_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_DUMP_RING:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_REQUEST_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_RELEASE_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_ENABLE_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_DISABLE_EVENT:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_FORCE_ICMP_TX_VIA:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_FORCE_TX_VIA:
|
||||
ret = atlnl_cmd_generic_u32_args(&nlctx, args->cmd, NULL, 1,
|
||||
ATL_FWD_ATTR_RING_INDEX,
|
||||
(uint32_t)args->ring_index);
|
||||
break;
|
||||
case ATL_FWD_CMD_GET_RX_QUEUE:
|
||||
/* fall through */
|
||||
case ATL_FWD_CMD_GET_TX_QUEUE:
|
||||
ret = atlnl_cmd_generic_u32_args(&nlctx, args->cmd,
|
||||
atlnl_getqueue_cb, 1,
|
||||
ATL_FWD_ATTR_RING_INDEX,
|
||||
(uint32_t)args->ring_index);
|
||||
break;
|
||||
case ATL_FWD_CMD_RING_STATUS:
|
||||
if (args->ring_index < 0)
|
||||
ret = atlnl_cmd_generic_u32_args(
|
||||
&nlctx, args->cmd, atlnl_ringstatus_cb, 0);
|
||||
else
|
||||
ret = atlnl_cmd_generic_u32_args(
|
||||
&nlctx, args->cmd, atlnl_ringstatus_cb, 1,
|
||||
ATL_FWD_ATTR_RING_INDEX,
|
||||
(uint32_t)args->ring_index);
|
||||
break;
|
||||
case ATL_FWD_CMD_DISABLE_REDIRECTIONS:
|
||||
ret = atlnl_cmd_generic_u32_args(&nlctx, args->cmd, NULL, 0);
|
||||
break;
|
||||
case ATL_FWD_CMD_SET_TX_BUNCH:
|
||||
ret = atlnl_cmd_generic_u32_args(&nlctx, args->cmd, NULL, 1,
|
||||
ATL_FWD_ATTR_TX_BUNCH_SIZE,
|
||||
args->tx_bunch);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown command %d\n", args->cmd);
|
||||
goto err_sockclose;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
if (ret < 0) {
|
||||
result = -ret;
|
||||
perror("cmd error");
|
||||
}
|
||||
|
||||
err_sockclose:
|
||||
mnl_socket_close(nlctx.sock);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef MSS_EGRESS_REGS_HEADER
|
||||
#define MSS_EGRESS_REGS_HEADER
|
||||
|
||||
#define MSS_EGRESS_CTL_REGISTER_ADDR 0x00005002
|
||||
#define MSS_EGRESS_SA_EXPIRED_STATUS_REGISTER_ADDR 0x00005060
|
||||
#define MSS_EGRESS_SA_THRESHOLD_EXPIRED_STATUS_REGISTER_ADDR 0x00005062
|
||||
#define MSS_EGRESS_LUT_ADDR_CTL_REGISTER_ADDR 0x00005080
|
||||
#define MSS_EGRESS_LUT_CTL_REGISTER_ADDR 0x00005081
|
||||
#define MSS_EGRESS_LUT_DATA_CTL_REGISTER_ADDR 0x000050A0
|
||||
|
||||
struct mss_egress_ctl_register {
|
||||
union {
|
||||
struct {
|
||||
unsigned int soft_reset : 1;
|
||||
unsigned int drop_kay_packet : 1;
|
||||
unsigned int drop_egprc_lut_miss : 1;
|
||||
unsigned int gcm_start : 1;
|
||||
unsigned int gcm_test_mode : 1;
|
||||
unsigned int unmatched_use_sc_0 : 1;
|
||||
unsigned int drop_invalid_sa_sc_packets : 1;
|
||||
unsigned int reserved0 : 1;
|
||||
/* Should always be set to 0. */
|
||||
unsigned int external_classification_enable : 1;
|
||||
unsigned int icv_lsb_8bytes_enable : 1;
|
||||
unsigned int high_prio : 1;
|
||||
unsigned int clear_counter : 1;
|
||||
unsigned int clear_global_time : 1;
|
||||
unsigned int ethertype_explicit_sectag_lsb : 3;
|
||||
} bits_0;
|
||||
unsigned short word_0;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
unsigned int ethertype_explicit_sectag_msb : 13;
|
||||
unsigned int reserved0 : 3;
|
||||
} bits_1;
|
||||
unsigned short word_1;
|
||||
};
|
||||
};
|
||||
|
||||
struct mss_egress_lut_addr_ctl_register {
|
||||
union {
|
||||
struct {
|
||||
unsigned int lut_addr : 9;
|
||||
unsigned int reserved0 : 3;
|
||||
/* 0x0 : Egress MAC Control FIlter (CTLF) LUT
|
||||
* 0x1 : Egress Classification LUT
|
||||
* 0x2 : Egress SC/SA LUT
|
||||
* 0x3 : Egress SMIB
|
||||
*/
|
||||
unsigned int lut_select : 4;
|
||||
} bits_0;
|
||||
unsigned short word_0;
|
||||
};
|
||||
};
|
||||
|
||||
struct mss_egress_lut_ctl_register {
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved0 : 14;
|
||||
unsigned int lut_read : 1;
|
||||
unsigned int lut_write : 1;
|
||||
} bits_0;
|
||||
unsigned short word_0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* MSS_EGRESS_REGS_HEADER */
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef MSS_INGRESS_REGS_HEADER
|
||||
#define MSS_INGRESS_REGS_HEADER
|
||||
|
||||
#define SEC_INGRESS_PACKET_EDIT_CTL_REGISTER_ADDR 0x00007035
|
||||
#define MSS_INGRESS_CTL_REGISTER_ADDR 0x0000800E
|
||||
#define MSS_INGRESS_LUT_ADDR_CTL_REGISTER_ADDR 0x00008080
|
||||
#define MSS_INGRESS_LUT_CTL_REGISTER_ADDR 0x00008081
|
||||
#define MSS_INGRESS_LUT_DATA_CTL_REGISTER_ADDR 0x000080A0
|
||||
|
||||
struct mss_ingress_ctl_register {
|
||||
union {
|
||||
struct {
|
||||
unsigned int soft_reset : 1;
|
||||
unsigned int operation_point_to_point : 1;
|
||||
unsigned int create_sci : 1;
|
||||
/* Unused */
|
||||
unsigned int mask_short_length_error : 1;
|
||||
unsigned int drop_kay_packet : 1;
|
||||
unsigned int drop_igprc_miss : 1;
|
||||
/* Unused */
|
||||
unsigned int check_icv : 1;
|
||||
unsigned int clear_global_time : 1;
|
||||
unsigned int clear_count : 1;
|
||||
unsigned int high_prio : 1;
|
||||
unsigned int remove_sectag : 1;
|
||||
unsigned int global_validate_frames : 2;
|
||||
unsigned int icv_lsb_8bytes_enabled : 1;
|
||||
unsigned int reserved0 : 2;
|
||||
} bits_0;
|
||||
unsigned short word_0;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved0 : 16;
|
||||
} bits_1;
|
||||
unsigned short word_1;
|
||||
};
|
||||
};
|
||||
|
||||
struct mss_ingress_lut_addr_ctl_register {
|
||||
union {
|
||||
struct {
|
||||
unsigned int lut_addr : 9;
|
||||
unsigned int reserved0 : 3;
|
||||
/* 0x0 : Ingress Pre-Security MAC Control FIlter
|
||||
* (IGPRCTLF) LUT
|
||||
* 0x1 : Ingress Pre-Security Classification LUT (IGPRC)
|
||||
* 0x2 : Ingress Packet Format (IGPFMT) SAKey LUT
|
||||
* 0x3 : Ingress Packet Format (IGPFMT) SC/SA LUT
|
||||
* 0x4 : Ingress Post-Security Classification LUT
|
||||
* (IGPOC)
|
||||
* 0x5 : Ingress Post-Security MAC Control Filter
|
||||
* (IGPOCTLF) LUT
|
||||
* 0x6 : Ingress MIB (IGMIB)
|
||||
*/
|
||||
unsigned int lut_select : 4;
|
||||
} bits_0;
|
||||
unsigned short word_0;
|
||||
};
|
||||
};
|
||||
|
||||
struct mss_ingress_lut_ctl_register {
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved0 : 14;
|
||||
unsigned int lut_read : 1;
|
||||
unsigned int lut_write : 1;
|
||||
} bits_0;
|
||||
unsigned short word_0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* MSS_INGRESS_REGS_HEADER */
|
||||
2976
drivers/net/ethernet/aquantia/atlantic-fwd/macsec/macsec_api.c
Normal file
2976
drivers/net/ethernet/aquantia/atlantic-fwd/macsec/macsec_api.c
Normal file
File diff suppressed because it is too large
Load diff
334
drivers/net/ethernet/aquantia/atlantic-fwd/macsec/macsec_api.h
Normal file
334
drivers/net/ethernet/aquantia/atlantic-fwd/macsec/macsec_api.h
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MACSEC_API_H__
|
||||
#define __MACSEC_API_H__
|
||||
|
||||
#include "atl_hw.h"
|
||||
#include "macsec_struct.h"
|
||||
|
||||
#define NUMROWS_INGRESSPRECTLFRECORD 24
|
||||
#define ROWOFFSET_INGRESSPRECTLFRECORD 0
|
||||
|
||||
#define NUMROWS_INGRESSPRECLASSRECORD 48
|
||||
#define ROWOFFSET_INGRESSPRECLASSRECORD 0
|
||||
|
||||
#define NUMROWS_INGRESSPOSTCLASSRECORD 48
|
||||
#define ROWOFFSET_INGRESSPOSTCLASSRECORD 0
|
||||
|
||||
#define NUMROWS_INGRESSSCRECORD 32
|
||||
#define ROWOFFSET_INGRESSSCRECORD 0
|
||||
|
||||
#define NUMROWS_INGRESSSARECORD 32
|
||||
#define ROWOFFSET_INGRESSSARECORD 32
|
||||
|
||||
#define NUMROWS_INGRESSSAKEYRECORD 32
|
||||
#define ROWOFFSET_INGRESSSAKEYRECORD 0
|
||||
|
||||
#define NUMROWS_INGRESSPOSTCTLFRECORD 24
|
||||
#define ROWOFFSET_INGRESSPOSTCTLFRECORD 0
|
||||
|
||||
#define NUMROWS_EGRESSCTLFRECORD 24
|
||||
#define ROWOFFSET_EGRESSCTLFRECORD 0
|
||||
|
||||
#define NUMROWS_EGRESSCLASSRECORD 48
|
||||
#define ROWOFFSET_EGRESSCLASSRECORD 0
|
||||
|
||||
#define NUMROWS_EGRESSSCRECORD 32
|
||||
#define ROWOFFSET_EGRESSSCRECORD 0
|
||||
|
||||
#define NUMROWS_EGRESSSARECORD 32
|
||||
#define ROWOFFSET_EGRESSSARECORD 32
|
||||
|
||||
#define NUMROWS_EGRESSSAKEYRECORD 32
|
||||
#define ROWOFFSET_EGRESSSAKEYRECORD 96
|
||||
|
||||
/*! Read the raw table data from the specified row of the Egress CTL
|
||||
* Filter table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 23).
|
||||
*/
|
||||
int aq_mss_get_egress_ctlf_record(struct atl_hw *hw,
|
||||
struct aq_mss_egress_ctlf_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Egress CTL Filter table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 23).
|
||||
*/
|
||||
int aq_mss_set_egress_ctlf_record(struct atl_hw *hw,
|
||||
const struct aq_mss_egress_ctlf_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Egress
|
||||
* Packet Classifier table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 47).
|
||||
*/
|
||||
int aq_mss_get_egress_class_record(struct atl_hw *hw,
|
||||
struct aq_mss_egress_class_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Egress Packet Classifier table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write (max 47).
|
||||
*/
|
||||
int aq_mss_set_egress_class_record(struct atl_hw *hw,
|
||||
const struct aq_mss_egress_class_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Egress SC
|
||||
* Lookup table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_egress_sc_record(struct atl_hw *hw,
|
||||
struct aq_mss_egress_sc_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Egress SC Lookup table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write (max 31).
|
||||
*/
|
||||
int aq_mss_set_egress_sc_record(struct atl_hw *hw,
|
||||
const struct aq_mss_egress_sc_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Egress SA
|
||||
* Lookup table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_egress_sa_record(struct atl_hw *hw,
|
||||
struct aq_mss_egress_sa_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Egress SA Lookup table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write (max 31).
|
||||
*/
|
||||
int aq_mss_set_egress_sa_record(struct atl_hw *hw,
|
||||
const struct aq_mss_egress_sa_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Egress SA
|
||||
* Key Lookup table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_egress_sakey_record(struct atl_hw *hw,
|
||||
struct aq_mss_egress_sakey_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Egress SA Key Lookup table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write (max 31).
|
||||
*/
|
||||
int aq_mss_set_egress_sakey_record(struct atl_hw *hw,
|
||||
const struct aq_mss_egress_sakey_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress
|
||||
* Pre-MACSec CTL Filter table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 23).
|
||||
*/
|
||||
int aq_mss_get_ingress_prectlf_record(struct atl_hw *hw,
|
||||
struct aq_mss_ingress_prectlf_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress Pre-MACSec CTL Filter table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 23).
|
||||
*/
|
||||
int aq_mss_set_ingress_prectlf_record(
|
||||
struct atl_hw *hw, const struct aq_mss_ingress_prectlf_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress
|
||||
* Pre-MACSec Packet Classifier table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 47).
|
||||
*/
|
||||
int aq_mss_get_ingress_preclass_record(
|
||||
struct atl_hw *hw, struct aq_mss_ingress_preclass_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress Pre-MACSec Packet Classifier table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 47).
|
||||
*/
|
||||
int aq_mss_set_ingress_preclass_record(
|
||||
struct atl_hw *hw, const struct aq_mss_ingress_preclass_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress SC
|
||||
* Lookup table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_ingress_sc_record(struct atl_hw *hw,
|
||||
struct aq_mss_ingress_sc_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress SC Lookup table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 31).
|
||||
*/
|
||||
int aq_mss_set_ingress_sc_record(struct atl_hw *hw,
|
||||
const struct aq_mss_ingress_sc_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress SA
|
||||
* Lookup table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_ingress_sa_record(struct atl_hw *hw,
|
||||
struct aq_mss_ingress_sa_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress SA Lookup table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 31).
|
||||
*/
|
||||
int aq_mss_set_ingress_sa_record(struct atl_hw *hw,
|
||||
const struct aq_mss_ingress_sa_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress SA
|
||||
* Key Lookup table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_ingress_sakey_record(struct atl_hw *hw,
|
||||
struct aq_mss_ingress_sakey_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress SA Key Lookup table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 31).
|
||||
*/
|
||||
int aq_mss_set_ingress_sakey_record(
|
||||
struct atl_hw *hw, const struct aq_mss_ingress_sakey_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress
|
||||
* Post-MACSec Packet Classifier table, and unpack it into the
|
||||
* fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 48).
|
||||
*/
|
||||
int aq_mss_get_ingress_postclass_record(
|
||||
struct atl_hw *hw, struct aq_mss_ingress_postclass_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress Post-MACSec Packet Classifier table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 48).
|
||||
*/
|
||||
int aq_mss_set_ingress_postclass_record(
|
||||
struct atl_hw *hw, const struct aq_mss_ingress_postclass_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the raw table data from the specified row of the Ingress
|
||||
* Post-MACSec CTL Filter table, and unpack it into the fields of rec.
|
||||
* rec - [OUT] The raw table row data will be unpacked into the fields of rec.
|
||||
* table_index - The table row to read (max 23).
|
||||
*/
|
||||
int aq_mss_get_ingress_postctlf_record(
|
||||
struct atl_hw *hw, struct aq_mss_ingress_postctlf_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Pack the fields of rec, and write the packed data into the
|
||||
* specified row of the Ingress Post-MACSec CTL Filter table.
|
||||
* rec - [IN] The bitfield values to write to the table row.
|
||||
* table_index - The table row to write(max 23).
|
||||
*/
|
||||
int aq_mss_set_ingress_postctlf_record(
|
||||
struct atl_hw *hw, const struct aq_mss_ingress_postctlf_record *rec,
|
||||
u16 table_index);
|
||||
|
||||
/*! Read the counters for the specified SC, and unpack them into the
|
||||
* fields of counters.
|
||||
* counters - [OUT] The raw table row data will be unpacked here.
|
||||
* sc_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_egress_sc_counters(struct atl_hw *hw,
|
||||
struct aq_mss_egress_sc_counters *counters,
|
||||
u16 sc_index);
|
||||
|
||||
/*! Read the counters for the specified SA, and unpack them into the
|
||||
* fields of counters.
|
||||
* counters - [OUT] The raw table row data will be unpacked here.
|
||||
* sa_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_egress_sa_counters(struct atl_hw *hw,
|
||||
struct aq_mss_egress_sa_counters *counters,
|
||||
u16 sa_index);
|
||||
|
||||
/*! Read the counters for the common egress counters, and unpack them
|
||||
* into the fields of counters.
|
||||
* counters - [OUT] The raw table row data will be unpacked here.
|
||||
*/
|
||||
int aq_mss_get_egress_common_counters(
|
||||
struct atl_hw *hw, struct aq_mss_egress_common_counters *counters);
|
||||
|
||||
/*! Clear all Egress counters to 0.*/
|
||||
int aq_mss_clear_egress_counters(struct atl_hw *hw);
|
||||
|
||||
/*! Read the counters for the specified SA, and unpack them into the
|
||||
* fields of counters.
|
||||
* counters - [OUT] The raw table row data will be unpacked here.
|
||||
* sa_index - The table row to read (max 31).
|
||||
*/
|
||||
int aq_mss_get_ingress_sa_counters(struct atl_hw *hw,
|
||||
struct aq_mss_ingress_sa_counters *counters,
|
||||
u16 sa_index);
|
||||
|
||||
/*! Read the counters for the common ingress counters, and unpack them
|
||||
* into the fields of counters.
|
||||
* counters - [OUT] The raw table row data will be unpacked here.
|
||||
*/
|
||||
int aq_mss_get_ingress_common_counters(
|
||||
struct atl_hw *hw, struct aq_mss_ingress_common_counters *counters);
|
||||
|
||||
/*! Clear all Ingress counters to 0. */
|
||||
int aq_mss_clear_ingress_counters(struct atl_hw *hw);
|
||||
|
||||
/*! Get Egress SA expired. */
|
||||
int aq_mss_get_egress_sa_expired(struct atl_hw *hw, u32 *expired);
|
||||
/*! Get Egress SA threshold expired. */
|
||||
int aq_mss_get_egress_sa_threshold_expired(struct atl_hw *hw,
|
||||
u32 *expired);
|
||||
/*! Set Egress SA expired. */
|
||||
int aq_mss_set_egress_sa_expired(struct atl_hw *hw, u32 expired);
|
||||
/*! Set Egress SA threshold expired. */
|
||||
int aq_mss_set_egress_sa_threshold_expired(struct atl_hw *hw, u32 expired);
|
||||
|
||||
/*! Set Drop IGPRC miss packets */
|
||||
int aq_mss_set_drop_igprc_miss_packets(struct atl_hw *hw, bool drop);
|
||||
|
||||
/*! Set Packet Edit Control register */
|
||||
int aq_mss_set_packet_edit_control(struct atl_hw *hw, u32 control);
|
||||
|
||||
#endif /* __MACSEC_API_H__ */
|
||||
|
|
@ -0,0 +1,920 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Atlantic Network Driver
|
||||
*
|
||||
* Copyright (C) 2019 aQuantia Corporation
|
||||
* Copyright (C) 2019-2020 Marvell International Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _MACSEC_STRUCT_H_
|
||||
#define _MACSEC_STRUCT_H_
|
||||
|
||||
/*! Represents the bitfields of a single row in the Egress CTL Filter
|
||||
* table.
|
||||
*/
|
||||
struct aq_mss_egress_ctlf_record {
|
||||
/*! This is used to store the 48 bit value used to compare SA, DA or
|
||||
* halfDA+half SA value.
|
||||
*/
|
||||
u32 sa_da[2];
|
||||
/*! This is used to store the 16 bit ethertype value used for
|
||||
* comparison.
|
||||
*/
|
||||
u32 eth_type;
|
||||
/*! The match mask is per-nibble. 0 means don't care, i.e. every value
|
||||
* will match successfully. The total data is 64 bit, i.e. 16 nibbles
|
||||
* masks.
|
||||
*/
|
||||
u32 match_mask;
|
||||
/*! 0: No compare, i.e. This entry is not used
|
||||
* 1: compare DA only
|
||||
* 2: compare SA only
|
||||
* 3: compare half DA + half SA
|
||||
* 4: compare ether type only
|
||||
* 5: compare DA + ethertype
|
||||
* 6: compare SA + ethertype
|
||||
* 7: compare DA+ range.
|
||||
*/
|
||||
u32 match_type;
|
||||
/*! 0: Bypass the remaining modules if matched.
|
||||
* 1: Forward to next module for more classifications.
|
||||
*/
|
||||
u32 action;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Egress Packet
|
||||
* Classifier table.
|
||||
*/
|
||||
struct aq_mss_egress_class_record {
|
||||
/*! VLAN ID field. */
|
||||
u32 vlan_id;
|
||||
/*! VLAN UP field. */
|
||||
u32 vlan_up;
|
||||
/*! VLAN Present in the Packet. */
|
||||
u32 vlan_valid;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 3. */
|
||||
u32 byte3;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 2. */
|
||||
u32 byte2;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 1. */
|
||||
u32 byte1;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 0. */
|
||||
u32 byte0;
|
||||
/*! The 8 bit TCI field used to compare with extracted value. */
|
||||
u32 tci;
|
||||
/*! The 64 bit SCI field in the SecTAG. */
|
||||
u32 sci[2];
|
||||
/*! The 16 bit Ethertype (in the clear) field used to compare with
|
||||
* extracted value.
|
||||
*/
|
||||
u32 eth_type;
|
||||
/*! This is to specify the 40bit SNAP header if the SNAP header's mask
|
||||
* is enabled.
|
||||
*/
|
||||
u32 snap[2];
|
||||
/*! This is to specify the 24bit LLC header if the LLC header's mask is
|
||||
* enabled.
|
||||
*/
|
||||
u32 llc;
|
||||
/*! The 48 bit MAC_SA field used to compare with extracted value. */
|
||||
u32 mac_sa[2];
|
||||
/*! The 48 bit MAC_DA field used to compare with extracted value. */
|
||||
u32 mac_da[2];
|
||||
/*! The 32 bit Packet number used to compare with extracted value. */
|
||||
u32 pn;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte3_location;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of extracted byte pointed by byte 3 location.
|
||||
*/
|
||||
u32 byte3_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte2_location;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of extracted byte pointed by byte 2 location.
|
||||
*/
|
||||
u32 byte2_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte1_location;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of extracted byte pointed by byte 1 location.
|
||||
*/
|
||||
u32 byte1_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte0_location;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of extracted byte pointed by byte 0 location.
|
||||
*/
|
||||
u32 byte0_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of extracted VLAN ID field.
|
||||
*/
|
||||
u32 vlan_id_mask;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of extracted VLAN UP field.
|
||||
*/
|
||||
u32 vlan_up_mask;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of extracted VLAN Valid field.
|
||||
*/
|
||||
u32 vlan_valid_mask;
|
||||
/*! This is bit mask to enable comparison the 8 bit TCI field,
|
||||
* including the AN field.
|
||||
* For explicit SECTAG, AN is hardware controlled. For sending
|
||||
* packet w/ explicit SECTAG, rest of the TCI fields are directly
|
||||
* from the SECTAG.
|
||||
*/
|
||||
u32 tci_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of SCI
|
||||
* Note: If this field is not 0, this means the input packet's
|
||||
* SECTAG is explicitly tagged and MACSEC module will only update
|
||||
* the MSDU.
|
||||
* PN number is hardware controlled.
|
||||
*/
|
||||
u32 sci_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of Ethertype.
|
||||
*/
|
||||
u32 eth_type_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care and no SNAP header exist.
|
||||
* 1: compare the SNAP header.
|
||||
* If this bit is set to 1, the extracted filed will assume the
|
||||
* SNAP header exist as encapsulated in 802.3 (RFC 1042). I.E. the
|
||||
* next 5 bytes after the the LLC header is SNAP header.
|
||||
*/
|
||||
u32 snap_mask;
|
||||
/*! 0: don't care and no LLC header exist.
|
||||
* 1: compare the LLC header.
|
||||
* If this bit is set to 1, the extracted filed will assume the
|
||||
* LLC header exist as encapsulated in 802.3 (RFC 1042). I.E. the
|
||||
* next three bytes after the 802.3MAC header is LLC header.
|
||||
*/
|
||||
u32 llc_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of MAC_SA.
|
||||
*/
|
||||
u32 sa_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of MAC_DA.
|
||||
*/
|
||||
u32 da_mask;
|
||||
/*! Mask is per-byte. */
|
||||
u32 pn_mask;
|
||||
/*! Reserved. This bit should be always 0. */
|
||||
u32 eight02dot2;
|
||||
/*! 1: For explicit sectag case use TCI_SC from table
|
||||
* 0: use TCI_SC from explicit sectag.
|
||||
*/
|
||||
u32 tci_sc;
|
||||
/*! 1: For explicit sectag case,use TCI_V,ES,SCB,E,C from table
|
||||
* 0: use TCI_V,ES,SCB,E,C from explicit sectag.
|
||||
*/
|
||||
u32 tci_87543;
|
||||
/*! 1: indicates that incoming packet has explicit sectag. */
|
||||
u32 exp_sectag_en;
|
||||
/*! If packet matches and tagged as controlled-packet, this SC/SA
|
||||
* index is used for later SC and SA table lookup.
|
||||
*/
|
||||
u32 sc_idx;
|
||||
/*! This field is used to specify how many SA entries are
|
||||
* associated with 1 SC entry.
|
||||
* 2'b00: 1 SC has 4 SA.
|
||||
* SC index is equivalent to {SC_Index[4:2], 1'b0}.
|
||||
* SA index is equivalent to {SC_Index[4:2], SC entry's current AN[1:0]
|
||||
* 2'b10: 1 SC has 2 SA.
|
||||
* SC index is equivalent to SC_Index[4:1]
|
||||
* SA index is equivalent to {SC_Index[4:1], SC entry's current AN[0]}
|
||||
* 2'b11: 1 SC has 1 SA. No SC entry exists for the specific SA.
|
||||
* SA index is equivalent to SC_Index[4:0]
|
||||
* Note: if specified as 2'b11, hardware AN roll over is not
|
||||
* supported.
|
||||
*/
|
||||
u32 sc_sa;
|
||||
/*! 0: the packets will be sent to MAC FIFO
|
||||
* 1: The packets will be sent to Debug/Loopback FIFO.
|
||||
* If the above's action is drop, this bit has no meaning.
|
||||
*/
|
||||
u32 debug;
|
||||
/*! 0: forward to remaining modules
|
||||
* 1: bypass the next encryption modules. This packet is considered
|
||||
* un-control packet.
|
||||
* 2: drop
|
||||
* 3: Reserved.
|
||||
*/
|
||||
u32 action;
|
||||
/*! 0: Not valid entry. This entry is not used
|
||||
* 1: valid entry.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Egress SC Lookup table. */
|
||||
struct aq_mss_egress_sc_record {
|
||||
/*! This is to specify when the SC was first used. Set by HW. */
|
||||
u32 start_time;
|
||||
/*! This is to specify when the SC was last used. Set by HW. */
|
||||
u32 stop_time;
|
||||
/*! This is to specify which of the SA entries are used by current HW.
|
||||
* Note: This value need to be set by SW after reset. It will be
|
||||
* automatically updated by HW, if AN roll over is enabled.
|
||||
*/
|
||||
u32 curr_an;
|
||||
/*! 0: Clear the SA Valid Bit after PN expiry.
|
||||
* 1: Do not Clear the SA Valid bit after PN expiry of the current SA.
|
||||
* When the Enable AN roll over is set, S/W does not need to
|
||||
* program the new SA's and the H/W will automatically roll over
|
||||
* between the SA's without session expiry.
|
||||
* For normal operation, Enable AN Roll over will be set to '0'
|
||||
* and in which case, the SW needs to program the new SA values
|
||||
* after the current PN expires.
|
||||
*/
|
||||
u32 an_roll;
|
||||
/*! This is the TCI field used if packet is not explicitly tagged. */
|
||||
u32 tci;
|
||||
/*! This value indicates the offset where the decryption will start.
|
||||
* [[Values of 0, 4, 8-50].
|
||||
*/
|
||||
u32 enc_off;
|
||||
/*! 0: Do not protect frames, all the packets will be forwarded
|
||||
* unchanged. MIB counter (OutPktsUntagged) will be updated.
|
||||
* 1: Protect.
|
||||
*/
|
||||
u32 protect;
|
||||
/*! 0: when none of the SA related to SC has inUse set.
|
||||
* 1: when either of the SA related to the SC has inUse set.
|
||||
* This bit is set by HW.
|
||||
*/
|
||||
u32 recv;
|
||||
/*! 0: H/W Clears this bit on the first use.
|
||||
* 1: SW updates this entry, when programming the SC Table.
|
||||
*/
|
||||
u32 fresh;
|
||||
/*! AES Key size
|
||||
* 00 - 128bits
|
||||
* 01 - 192bits
|
||||
* 10 - 256bits
|
||||
* 11 - Reserved.
|
||||
*/
|
||||
u32 sak_len;
|
||||
/*! 0: Invalid SC
|
||||
* 1: Valid SC.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Egress SA Lookup table. */
|
||||
struct aq_mss_egress_sa_record {
|
||||
/*! This is to specify when the SC was first used. Set by HW. */
|
||||
u32 start_time;
|
||||
/*! This is to specify when the SC was last used. Set by HW. */
|
||||
u32 stop_time;
|
||||
/*! This is set by SW and updated by HW to store the Next PN number
|
||||
* used for encryption.
|
||||
*/
|
||||
u32 next_pn;
|
||||
/*! The Next_PN number is going to wrapped around from 0xFFFF_FFFF
|
||||
* to 0. set by HW.
|
||||
*/
|
||||
u32 sat_pn;
|
||||
/*! 0: This SA is in use.
|
||||
* 1: This SA is Fresh and set by SW.
|
||||
*/
|
||||
u32 fresh;
|
||||
/*! 0: Invalid SA
|
||||
* 1: Valid SA.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Egress SA Key
|
||||
* Lookup table.
|
||||
*/
|
||||
struct aq_mss_egress_sakey_record {
|
||||
/*! Key for AES-GCM processing. */
|
||||
u32 key[8];
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress Pre-MACSec
|
||||
* CTL Filter table.
|
||||
*/
|
||||
struct aq_mss_ingress_prectlf_record {
|
||||
/*! This is used to store the 48 bit value used to compare SA, DA
|
||||
* or halfDA+half SA value.
|
||||
*/
|
||||
u32 sa_da[2];
|
||||
/*! This is used to store the 16 bit ethertype value used for
|
||||
* comparison.
|
||||
*/
|
||||
u32 eth_type;
|
||||
/*! The match mask is per-nibble. 0 means don't care, i.e. every
|
||||
* value will match successfully. The total data is 64 bit, i.e.
|
||||
* 16 nibbles masks.
|
||||
*/
|
||||
u32 match_mask;
|
||||
/*! 0: No compare, i.e. This entry is not used
|
||||
* 1: compare DA only
|
||||
* 2: compare SA only
|
||||
* 3: compare half DA + half SA
|
||||
* 4: compare ether type only
|
||||
* 5: compare DA + ethertype
|
||||
* 6: compare SA + ethertype
|
||||
* 7: compare DA+ range.
|
||||
*/
|
||||
u32 match_type;
|
||||
/*! 0: Bypass the remaining modules if matched.
|
||||
* 1: Forward to next module for more classifications.
|
||||
*/
|
||||
u32 action;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress Pre-MACSec
|
||||
* Packet Classifier table.
|
||||
*/
|
||||
struct aq_mss_ingress_preclass_record {
|
||||
/*! The 64 bit SCI field used to compare with extracted value.
|
||||
* Should have SCI value in case TCI[SCI_SEND] == 0. This will be
|
||||
* used for ICV calculation.
|
||||
*/
|
||||
u32 sci[2];
|
||||
/*! The 8 bit TCI field used to compare with extracted value. */
|
||||
u32 tci;
|
||||
/*! 8 bit encryption offset. */
|
||||
u32 encr_offset;
|
||||
/*! The 16 bit Ethertype (in the clear) field used to compare with
|
||||
* extracted value.
|
||||
*/
|
||||
u32 eth_type;
|
||||
/*! This is to specify the 40bit SNAP header if the SNAP header's
|
||||
* mask is enabled.
|
||||
*/
|
||||
u32 snap[2];
|
||||
/*! This is to specify the 24bit LLC header if the LLC header's
|
||||
* mask is enabled.
|
||||
*/
|
||||
u32 llc;
|
||||
/*! The 48 bit MAC_SA field used to compare with extracted value. */
|
||||
u32 mac_sa[2];
|
||||
/*! The 48 bit MAC_DA field used to compare with extracted value. */
|
||||
u32 mac_da[2];
|
||||
/*! 0: this is to compare with non-LPBK packet
|
||||
* 1: this is to compare with LPBK packet.
|
||||
* This value is used to compare with a controlled-tag which goes
|
||||
* with the packet when looped back from Egress port.
|
||||
*/
|
||||
u32 lpbk_packet;
|
||||
/*! The value of this bit mask will affects how the SC index and SA
|
||||
* index created.
|
||||
* 2'b00: 1 SC has 4 SA.
|
||||
* SC index is equivalent to {SC_Index[4:2], 1'b0}.
|
||||
* SA index is equivalent to {SC_Index[4:2], SECTAG's AN[1:0]}
|
||||
* Here AN bits are not compared.
|
||||
* 2'b10: 1 SC has 2 SA.
|
||||
* SC index is equivalent to SC_Index[4:1]
|
||||
* SA index is equivalent to {SC_Index[4:1], SECTAG's AN[0]}
|
||||
* Compare AN[1] field only
|
||||
* 2'b11: 1 SC has 1 SA. No SC entry exists for the specific SA.
|
||||
* SA index is equivalent to SC_Index[4:0]
|
||||
* AN[1:0] bits are compared.
|
||||
* NOTE: This design is to supports different usage of AN. User
|
||||
* can either ping-pong buffer 2 SA by using only the AN[0] bit.
|
||||
* Or use 4 SA per SC by use AN[1:0] bits. Or even treat each SA
|
||||
* as independent. i.e. AN[1:0] is just another matching pointer
|
||||
* to select SA.
|
||||
*/
|
||||
u32 an_mask;
|
||||
/*! This is bit mask to enable comparison the upper 6 bits TCI
|
||||
* field, which does not include the AN field.
|
||||
* 0: don't compare
|
||||
* 1: enable comparison of the bits.
|
||||
*/
|
||||
u32 tci_mask;
|
||||
/*! 0: don't care
|
||||
* 1: enable comparison of SCI.
|
||||
*/
|
||||
u32 sci_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of Ethertype.
|
||||
*/
|
||||
u32 eth_type_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care and no SNAP header exist.
|
||||
* 1: compare the SNAP header.
|
||||
* If this bit is set to 1, the extracted filed will assume the
|
||||
* SNAP header exist as encapsulated in 802.3 (RFC 1042). I.E. the
|
||||
* next 5 bytes after the the LLC header is SNAP header.
|
||||
*/
|
||||
u32 snap_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care and no LLC header exist.
|
||||
* 1: compare the LLC header.
|
||||
* If this bit is set to 1, the extracted filed will assume the
|
||||
* LLC header exist as encapsulated in 802.3 (RFC 1042). I.E. the
|
||||
* next three bytes after the 802.3MAC header is LLC header.
|
||||
*/
|
||||
u32 llc_mask;
|
||||
/*! Reserved. This bit should be always 0. */
|
||||
u32 _802_2_encapsulate;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of MAC_SA.
|
||||
*/
|
||||
u32 sa_mask;
|
||||
/*! Mask is per-byte.
|
||||
* 0: don't care
|
||||
* 1: enable comparison of MAC_DA.
|
||||
*/
|
||||
u32 da_mask;
|
||||
/*! 0: don't care
|
||||
* 1: enable checking if this is loopback packet or not.
|
||||
*/
|
||||
u32 lpbk_mask;
|
||||
/*! If packet matches and tagged as controlled-packet. This SC/SA
|
||||
* index is used for later SC and SA table lookup.
|
||||
*/
|
||||
u32 sc_idx;
|
||||
/*! 0: the packets will be sent to MAC FIFO
|
||||
* 1: The packets will be sent to Debug/Loopback FIFO.
|
||||
* If the above's action is drop. This bit has no meaning.
|
||||
*/
|
||||
u32 proc_dest;
|
||||
/*! 0: Process: Forward to next two modules for 802.1AE decryption.
|
||||
* 1: Process but keep SECTAG: Forward to next two modules for
|
||||
* 802.1AE decryption but keep the MACSEC header with added error
|
||||
* code information. ICV will be stripped for all control packets.
|
||||
* 2: Bypass: Bypass the next two decryption modules but processed
|
||||
* by post-classification.
|
||||
* 3: Drop: drop this packet and update counts accordingly.
|
||||
*/
|
||||
u32 action;
|
||||
/*! 0: This is a controlled-port packet if matched.
|
||||
* 1: This is an uncontrolled-port packet if matched.
|
||||
*/
|
||||
u32 ctrl_unctrl;
|
||||
/*! Use the SCI value from the Table if 'SC' bit of the input
|
||||
* packet is not present.
|
||||
*/
|
||||
u32 sci_from_table;
|
||||
/*! Reserved. */
|
||||
u32 reserved;
|
||||
/*! 0: Not valid entry. This entry is not used
|
||||
* 1: valid entry.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress SC Lookup table. */
|
||||
struct aq_mss_ingress_sc_record {
|
||||
/*! This is to specify when the SC was first used. Set by HW. */
|
||||
u32 stop_time;
|
||||
/*! This is to specify when the SC was first used. Set by HW. */
|
||||
u32 start_time;
|
||||
/*! 0: Strict
|
||||
* 1: Check
|
||||
* 2: Disabled.
|
||||
*/
|
||||
u32 validate_frames;
|
||||
/*! 1: Replay control enabled.
|
||||
* 0: replay control disabled.
|
||||
*/
|
||||
u32 replay_protect;
|
||||
/*! This is to specify the window range for anti-replay. Default is 0.
|
||||
* 0: is strict order enforcement.
|
||||
*/
|
||||
u32 anti_replay_window;
|
||||
/*! 0: when none of the SA related to SC has inUse set.
|
||||
* 1: when either of the SA related to the SC has inUse set.
|
||||
* This bit is set by HW.
|
||||
*/
|
||||
u32 receiving;
|
||||
/*! 0: when hardware processed the SC for the first time, it clears
|
||||
* this bit
|
||||
* 1: This bit is set by SW, when it sets up the SC.
|
||||
*/
|
||||
u32 fresh;
|
||||
/*! 0: The AN number will not automatically roll over if Next_PN is
|
||||
* saturated.
|
||||
* 1: The AN number will automatically roll over if Next_PN is
|
||||
* saturated.
|
||||
* Rollover is valid only after expiry. Normal roll over between
|
||||
* SA's should be normal process.
|
||||
*/
|
||||
u32 an_rol;
|
||||
/*! Reserved. */
|
||||
u32 reserved;
|
||||
/*! 0: Invalid SC
|
||||
* 1: Valid SC.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress SA Lookup table. */
|
||||
struct aq_mss_ingress_sa_record {
|
||||
/*! This is to specify when the SC was first used. Set by HW. */
|
||||
u32 stop_time;
|
||||
/*! This is to specify when the SC was first used. Set by HW. */
|
||||
u32 start_time;
|
||||
/*! This is updated by HW to store the expected NextPN number for
|
||||
* anti-replay.
|
||||
*/
|
||||
u32 next_pn;
|
||||
/*! The Next_PN number is going to wrapped around from 0XFFFF_FFFF
|
||||
* to 0. set by HW.
|
||||
*/
|
||||
u32 sat_nextpn;
|
||||
/*! 0: This SA is not yet used.
|
||||
* 1: This SA is inUse.
|
||||
*/
|
||||
u32 in_use;
|
||||
/*! 0: when hardware processed the SC for the first time, it clears
|
||||
* this timer
|
||||
* 1: This bit is set by SW, when it sets up the SC.
|
||||
*/
|
||||
u32 fresh;
|
||||
/*! Reserved. */
|
||||
u32 reserved;
|
||||
/*! 0: Invalid SA.
|
||||
* 1: Valid SA.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress SA Key
|
||||
* Lookup table.
|
||||
*/
|
||||
struct aq_mss_ingress_sakey_record {
|
||||
/*! Key for AES-GCM processing. */
|
||||
u32 key[8];
|
||||
/*! AES key size
|
||||
* 00 - 128bits
|
||||
* 01 - 192bits
|
||||
* 10 - 256bits
|
||||
* 11 - reserved.
|
||||
*/
|
||||
u32 key_len;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress Post-
|
||||
* MACSec Packet Classifier table.
|
||||
*/
|
||||
struct aq_mss_ingress_postclass_record {
|
||||
/*! The 8 bit value used to compare with extracted value for byte 0. */
|
||||
u32 byte0;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 1. */
|
||||
u32 byte1;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 2. */
|
||||
u32 byte2;
|
||||
/*! The 8 bit value used to compare with extracted value for byte 3. */
|
||||
u32 byte3;
|
||||
/*! Ethertype in the packet. */
|
||||
u32 eth_type;
|
||||
/*! Ether Type value > 1500 (0x5dc). */
|
||||
u32 eth_type_valid;
|
||||
/*! VLAN ID after parsing. */
|
||||
u32 vlan_id;
|
||||
/*! VLAN priority after parsing. */
|
||||
u32 vlan_up;
|
||||
/*! Valid VLAN coding. */
|
||||
u32 vlan_valid;
|
||||
/*! SA index. */
|
||||
u32 sai;
|
||||
/*! SAI hit, i.e. controlled packet. */
|
||||
u32 sai_hit;
|
||||
/*! Mask for payload ethertype field. */
|
||||
u32 eth_type_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte3_location;
|
||||
/*! Mask for Byte Offset 3. */
|
||||
u32 byte3_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte2_location;
|
||||
/*! Mask for Byte Offset 2. */
|
||||
u32 byte2_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte1_location;
|
||||
/*! Mask for Byte Offset 1. */
|
||||
u32 byte1_mask;
|
||||
/*! 0~63: byte location used extracted by packets comparator, which
|
||||
* can be anything from the first 64 bytes of the MAC packets.
|
||||
* This byte location counted from MAC' DA address. i.e. set to 0
|
||||
* will point to byte 0 of DA address.
|
||||
*/
|
||||
u32 byte0_location;
|
||||
/*! Mask for Byte Offset 0. */
|
||||
u32 byte0_mask;
|
||||
/*! Mask for Ethertype valid field. Indicates 802.3 vs. Other. */
|
||||
u32 eth_type_valid_mask;
|
||||
/*! Mask for VLAN ID field. */
|
||||
u32 vlan_id_mask;
|
||||
/*! Mask for VLAN UP field. */
|
||||
u32 vlan_up_mask;
|
||||
/*! Mask for VLAN valid field. */
|
||||
u32 vlan_valid_mask;
|
||||
/*! Mask for SAI. */
|
||||
u32 sai_mask;
|
||||
/*! Mask for SAI_HIT. */
|
||||
u32 sai_hit_mask;
|
||||
/*! Action if only first level matches and second level does not.
|
||||
* 0: pass
|
||||
* 1: drop (fail).
|
||||
*/
|
||||
u32 firstlevel_actions;
|
||||
/*! Action if both first and second level matched.
|
||||
* 0: pass
|
||||
* 1: drop (fail).
|
||||
*/
|
||||
u32 secondlevel_actions;
|
||||
/*! Reserved. */
|
||||
u32 reserved;
|
||||
/*! 0: Not valid entry. This entry is not used
|
||||
* 1: valid entry.
|
||||
*/
|
||||
u32 valid;
|
||||
};
|
||||
|
||||
/*! Represents the bitfields of a single row in the Ingress Post-
|
||||
* MACSec CTL Filter table.
|
||||
*/
|
||||
struct aq_mss_ingress_postctlf_record {
|
||||
/*! This is used to store the 48 bit value used to compare SA, DA
|
||||
* or halfDA+half SA value.
|
||||
*/
|
||||
u32 sa_da[2];
|
||||
/*! This is used to store the 16 bit ethertype value used for
|
||||
* comparison.
|
||||
*/
|
||||
u32 eth_type;
|
||||
/*! The match mask is per-nibble. 0 means don't care, i.e. every
|
||||
* value will match successfully. The total data is 64 bit, i.e.
|
||||
* 16 nibbles masks.
|
||||
*/
|
||||
u32 match_mask;
|
||||
/*! 0: No compare, i.e. This entry is not used
|
||||
* 1: compare DA only
|
||||
* 2: compare SA only
|
||||
* 3: compare half DA + half SA
|
||||
* 4: compare ether type only
|
||||
* 5: compare DA + ethertype
|
||||
* 6: compare SA + ethertype
|
||||
* 7: compare DA+ range.
|
||||
*/
|
||||
u32 match_type;
|
||||
/*! 0: Bypass the remaining modules if matched.
|
||||
* 1: Forward to next module for more classifications.
|
||||
*/
|
||||
u32 action;
|
||||
};
|
||||
|
||||
/*! Represents the Egress MIB counters for a single SC. Counters are
|
||||
* 64 bits, lower 32 bits in field[0].
|
||||
*/
|
||||
struct aq_mss_egress_sc_counters {
|
||||
/*! The number of integrity protected but not encrypted packets
|
||||
* for this transmitting SC.
|
||||
*/
|
||||
u32 sc_protected_pkts[2];
|
||||
/*! The number of integrity protected and encrypted packets for
|
||||
* this transmitting SC.
|
||||
*/
|
||||
u32 sc_encrypted_pkts[2];
|
||||
/*! The number of plain text octets that are integrity protected
|
||||
* but not encrypted on the transmitting SC.
|
||||
*/
|
||||
u32 sc_protected_octets[2];
|
||||
/*! The number of plain text octets that are integrity protected
|
||||
* and encrypted on the transmitting SC.
|
||||
*/
|
||||
u32 sc_encrypted_octets[2];
|
||||
};
|
||||
|
||||
/*! Represents the Egress MIB counters for a single SA. Counters are
|
||||
* 64 bits, lower 32 bits in field[0].
|
||||
*/
|
||||
struct aq_mss_egress_sa_counters {
|
||||
/*! The number of dropped packets for this transmitting SA. */
|
||||
u32 sa_hit_drop_redirect[2];
|
||||
/*! TODO */
|
||||
u32 sa_protected2_pkts[2];
|
||||
/*! The number of integrity protected but not encrypted packets
|
||||
* for this transmitting SA.
|
||||
*/
|
||||
u32 sa_protected_pkts[2];
|
||||
/*! The number of integrity protected and encrypted packets for
|
||||
* this transmitting SA.
|
||||
*/
|
||||
u32 sa_encrypted_pkts[2];
|
||||
};
|
||||
|
||||
/*! Represents the common Egress MIB counters; the counter not
|
||||
* associated with a particular SC/SA. Counters are 64 bits, lower 32
|
||||
* bits in field[0].
|
||||
*/
|
||||
struct aq_mss_egress_common_counters {
|
||||
/*! The number of transmitted packets classified as MAC_CTL packets. */
|
||||
u32 ctl_pkt[2];
|
||||
/*! The number of transmitted packets that did not match any rows
|
||||
* in the Egress Packet Classifier table.
|
||||
*/
|
||||
u32 unknown_sa_pkts[2];
|
||||
/*! The number of transmitted packets where the SC table entry has
|
||||
* protect=0 (so packets are forwarded unchanged).
|
||||
*/
|
||||
u32 untagged_pkts[2];
|
||||
/*! The number of transmitted packets discarded because the packet
|
||||
* length is greater than the ifMtu of the Common Port interface.
|
||||
*/
|
||||
u32 too_long[2];
|
||||
/*! The number of transmitted packets for which table memory was
|
||||
* affected by an ECC error during processing.
|
||||
*/
|
||||
u32 ecc_error_pkts[2];
|
||||
/*! The number of transmitted packets for where the matched row in
|
||||
* the Egress Packet Classifier table has action=drop.
|
||||
*/
|
||||
u32 unctrl_hit_drop_redir[2];
|
||||
};
|
||||
|
||||
/*! Represents the Ingress MIB counters for a single SA. Counters are
|
||||
* 64 bits, lower 32 bits in field[0].
|
||||
*/
|
||||
struct aq_mss_ingress_sa_counters {
|
||||
/*! For this SA, the number of received packets without a SecTAG. */
|
||||
u32 untagged_hit_pkts[2];
|
||||
/*! For this SA, the number of received packets that were dropped. */
|
||||
u32 ctrl_hit_drop_redir_pkts[2];
|
||||
/*! For this SA which is not currently in use, the number of
|
||||
* received packets that have been discarded, and have either the
|
||||
* packets encrypted or the matched row in the Ingress SC Lookup
|
||||
* table has validate_frames=Strict.
|
||||
*/
|
||||
u32 not_using_sa[2];
|
||||
/*! For this SA which is not currently in use, the number of
|
||||
* received, unencrypted, packets with the matched row in the
|
||||
* Ingress SC Lookup table has validate_frames!=Strict.
|
||||
*/
|
||||
u32 unused_sa[2];
|
||||
/*! For this SA, the number discarded packets with the condition
|
||||
* that the packets are not valid and one of the following
|
||||
* conditions are true: either the matched row in the Ingress SC
|
||||
* Lookup table has validate_frames=Strict or the packets
|
||||
* encrypted.
|
||||
*/
|
||||
u32 not_valid_pkts[2];
|
||||
/*! For this SA, the number of packets with the condition that the
|
||||
* packets are not valid and the matched row in the Ingress SC
|
||||
* Lookup table has validate_frames=Check.
|
||||
*/
|
||||
u32 invalid_pkts[2];
|
||||
/*! For this SA, the number of validated packets. */
|
||||
u32 ok_pkts[2];
|
||||
/*! For this SC, the number of received packets that have been
|
||||
* discarded with the condition: the matched row in the Ingress
|
||||
* SC Lookup table has replay_protect=1 and the PN of the packet
|
||||
* is lower than the lower bound replay check PN.
|
||||
*/
|
||||
u32 late_pkts[2];
|
||||
/*! For this SA, the number of packets with the condition that the
|
||||
* PN of the packets is lower than the lower bound replay
|
||||
* protection PN.
|
||||
*/
|
||||
u32 delayed_pkts[2];
|
||||
/*! For this SC, the number of packets with the following condition:
|
||||
* - the matched row in the Ingress SC Lookup table has
|
||||
* replay_protect=0 or
|
||||
* - the matched row in the Ingress SC Lookup table has
|
||||
* replay_protect=1 and the packet is not encrypted and the
|
||||
* integrity check has failed or
|
||||
* - the matched row in the Ingress SC Lookup table has
|
||||
* replay_protect=1 and the packet is encrypted and integrity
|
||||
* check has failed.
|
||||
*/
|
||||
u32 unchecked_pkts[2];
|
||||
/*! The number of octets of plaintext recovered from received
|
||||
* packets that were integrity protected but not encrypted.
|
||||
*/
|
||||
u32 validated_octets[2];
|
||||
/*! The number of octets of plaintext recovered from received
|
||||
* packets that were integrity protected and encrypted.
|
||||
*/
|
||||
u32 decrypted_octets[2];
|
||||
};
|
||||
|
||||
/*! Represents the common Ingress MIB counters; the counter not
|
||||
* associated with a particular SA. Counters are 64 bits, lower 32
|
||||
* bits in field[0].
|
||||
*/
|
||||
struct aq_mss_ingress_common_counters {
|
||||
/*! The number of received packets classified as MAC_CTL packets. */
|
||||
u32 ctl_pkts[2];
|
||||
/*! The number of received packets with the MAC security tag
|
||||
* (SecTAG), not matching any rows in the Ingress Pre-MACSec
|
||||
* Packet Classifier table.
|
||||
*/
|
||||
u32 tagged_miss_pkts[2];
|
||||
/*! The number of received packets without the MAC security tag
|
||||
* (SecTAG), not matching any rows in the Ingress Pre-MACSec
|
||||
* Packet Classifier table.
|
||||
*/
|
||||
u32 untagged_miss_pkts[2];
|
||||
/*! The number of received packets discarded without the MAC
|
||||
* security tag (SecTAG) and with the matched row in the Ingress
|
||||
* SC Lookup table having validate_frames=Strict.
|
||||
*/
|
||||
u32 notag_pkts[2];
|
||||
/*! The number of received packets without the MAC security tag
|
||||
* (SecTAG) and with the matched row in the Ingress SC Lookup
|
||||
* table having validate_frames!=Strict.
|
||||
*/
|
||||
u32 untagged_pkts[2];
|
||||
/*! The number of received packets discarded with an invalid
|
||||
* SecTAG or a zero value PN or an invalid ICV.
|
||||
*/
|
||||
u32 bad_tag_pkts[2];
|
||||
/*! The number of received packets discarded with unknown SCI
|
||||
* information with the condition:
|
||||
* the matched row in the Ingress SC Lookup table has
|
||||
* validate_frames=Strict or the C bit in the SecTAG is set.
|
||||
*/
|
||||
u32 no_sci_pkts[2];
|
||||
/*! The number of received packets with unknown SCI with the condition:
|
||||
* The matched row in the Ingress SC Lookup table has
|
||||
* validate_frames!=Strict and the C bit in the SecTAG is not set.
|
||||
*/
|
||||
u32 unknown_sci_pkts[2];
|
||||
/*! The number of received packets by the controlled port service
|
||||
* that passed the Ingress Post-MACSec Packet Classifier table
|
||||
* check.
|
||||
*/
|
||||
u32 ctrl_prt_pass_pkts[2];
|
||||
/*! The number of received packets by the uncontrolled port
|
||||
* service that passed the Ingress Post-MACSec Packet Classifier
|
||||
* table check.
|
||||
*/
|
||||
u32 unctrl_prt_pass_pkts[2];
|
||||
/*! The number of received packets by the controlled port service
|
||||
* that failed the Ingress Post-MACSec Packet Classifier table
|
||||
* check.
|
||||
*/
|
||||
u32 ctrl_prt_fail_pkts[2];
|
||||
/*! The number of received packets by the uncontrolled port
|
||||
* service that failed the Ingress Post-MACSec Packet Classifier
|
||||
* table check.
|
||||
*/
|
||||
u32 unctrl_prt_fail_pkts[2];
|
||||
/*! The number of received packets discarded because the packet
|
||||
* length is greater than the ifMtu of the Common Port interface.
|
||||
*/
|
||||
u32 too_long_pkts[2];
|
||||
/*! The number of received packets classified as MAC_CTL by the
|
||||
* Ingress Post-MACSec CTL Filter table.
|
||||
*/
|
||||
u32 igpoc_ctl_pkts[2];
|
||||
/*! The number of received packets for which table memory was
|
||||
* affected by an ECC error during processing.
|
||||
*/
|
||||
u32 ecc_error_pkts[2];
|
||||
/*! The number of received packets by the uncontrolled port
|
||||
* service that were dropped.
|
||||
*/
|
||||
u32 unctrl_hit_drop_redir[2];
|
||||
};
|
||||
|
||||
#endif
|
||||
352
drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt
Normal file
352
drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
Version 1.1.11
|
||||
==============
|
||||
[ATLDRV-1567] - forwarding driver issue with adj_freq
|
||||
|
||||
Version 1.1.10
|
||||
==============
|
||||
[ATLDRV-1559] - Add support of icmp proto to the rx filters
|
||||
[ATLDRV-1401] - A2: Filtering
|
||||
[ATLDRV-1513] - PM runtime failure
|
||||
|
||||
Version 1.1.9
|
||||
=============
|
||||
[ATLDRV-1505] - FWD: New dev ids
|
||||
[ATLDRV-1529] - FWD: Segmentation fault occurs for user operations
|
||||
[ATLDRV-1542] - FWD: build fails on 5.8-rcX
|
||||
[ATLDRV-1552] - Fwd: build fails with old gcc
|
||||
[ATLDRV-1553] - Fwd: BUG message when LOCKDEP is enabled
|
||||
|
||||
Version 1.1.8
|
||||
=============
|
||||
[ATLDRV-1438] - Fwd: port PTP from Linux driver
|
||||
|
||||
Version 1.1.7
|
||||
=============
|
||||
[ATLDRV-1469] - AQ083: After suspend resume EAPOL frames is not received
|
||||
[ATLDRV-1497] - Incorrect temperature is displayed in hwmon
|
||||
[ATLDRV-1519] - AQ086: Configuring default ring size
|
||||
|
||||
Version 1.1.6
|
||||
=============
|
||||
[ATLDRV-1355] - Sporadically unable to set EEE
|
||||
[ATLDRV-1407] - AQ078: Link comes back up after rmmod
|
||||
[ATLDRV-1416] - Failed probe during stress remove/rescan
|
||||
[ATLDRV-1435] - AQ080: MACSEC offload packet loss under concurrent streams
|
||||
[ATLDRV-1436] - AQ079: non-MACSEC_Data packets received in macsec0
|
||||
[ATLDRV-1456] - FWD: BUG: KASAN: use-after-free in atl_remove+0x1c9/0x220 [atlantic_fwd]
|
||||
[ATLDRV-1458] - AQ082: Accounting for RX bytes and packets
|
||||
[ATLDRV-1441] - FWD: Run Flexera Code Insight
|
||||
[ATLDRV-1457] - FWD: Linux-5.7.0 support
|
||||
|
||||
Version 1.1.5
|
||||
=============
|
||||
[ATLDRV-1382] - Failed install Driver 1.1.4 on Antigua
|
||||
[ATLDRV-1384] - WOL does not work on Antigua
|
||||
|
||||
Version 1.1.4
|
||||
==============
|
||||
[ATLDRV-1371] - Add supported eee with 2.5G and 5G
|
||||
[ATLDRV-1376] - Send notification when macsec offload turned on/off
|
||||
[ATLDRV-1378] - check FW capability instead of FW version for MSM Apply Settings
|
||||
|
||||
Version 1.1.3
|
||||
==============
|
||||
[ATLDRV-1185] - Enable stripping of padding doesnt work on Felicity card
|
||||
[ATLDRV-1351] - Problem with setting mtu
|
||||
[ATLDRV-1352] - Implement stripping of padding
|
||||
[ATLDRV-1354] - Incorrect thermal thresholds
|
||||
[ATLDRV-1359] - Secure all packets when macsec service ON
|
||||
|
||||
Version 1.1.2
|
||||
==============
|
||||
[ATLDRV-1348] - FWD: IPv6 and L4 ntuple filters not work
|
||||
|
||||
Version 1.1.1
|
||||
==============
|
||||
[ATLDRV-1315] - driver 1.1.0 crashes at start on A1
|
||||
[ATLDRV-1317] - A2: Incorrect ntuple L4 filter behavior
|
||||
[ATLDRV-1325] - A2: can not turn off flow control on Antigua
|
||||
[ATLDRV-1326] - A2: Cannot get EEE settings on Antigua
|
||||
[ATLDRV-1331] - A2: update reset sequence
|
||||
|
||||
Version 1.1.0
|
||||
==============
|
||||
[ATLDRV-1210] - A2: FWD: Basic functionality and bringup
|
||||
[ATLDRV-1212] - A2: FWD: RX flow filters infrastructure
|
||||
|
||||
|
||||
Version 1.0.31
|
||||
==============
|
||||
[ATLDRV-1243] - Clean up MACsec implementation
|
||||
[ATLDRV-1135] - ethtool shows incorrect Flow Control information
|
||||
[ATLDRV-1229] - HW access on mdo_dev_stop(ctx->prepare)
|
||||
[ATLDRV-1256] - AQ072: Static analysis error in atl_setup_datapath()
|
||||
[ATLDRV-1303] - Make driver C90 compilable
|
||||
[ATLDRV-1064] - Fwd: Software flowcontrol workaround adaptations
|
||||
|
||||
Version 1.0.30
|
||||
==============
|
||||
[ATLDRV-1217] - FWD driver refactoring for unit tests
|
||||
[ATLDRV-1102] - TCP/UDP checksum workaround for non-zero padded packets doesn't work
|
||||
[ATLDRV-1138] - vlan promiscuous mode is not enabled, when deleting the last vlan interface
|
||||
[ATLDRV-1139] - after ifconfig -multicast Unicast filters registers have valid values for multicast addresses
|
||||
[ATLDRV-1174] - FWD: deleting MacSec iface doesn't clear Ingress/Egress SA and SAKey records
|
||||
[ATLDRV-1193] - No link UP if driver was started in MSI mode before being started in legacy mode
|
||||
[ATLDRV-1208] - Driver crashes after link down up in D3 state
|
||||
[ATLDRV-1209] - FWD: Kernel panic after configuring macsec
|
||||
[ATLDRV-1218] - Kernel panic upon macsec0 deletion
|
||||
[ATLDRV-1220] - AQ069: atl_fwd_receive_skb() support NAPI
|
||||
[ATLDRV-1222] - atl_rotate_keys() produces unexpected results for 192-bit keys (24-bytes)
|
||||
[ATLDRV-1194] - Add trace of descriptors for normal traffic
|
||||
|
||||
Version 1.0.29
|
||||
==============
|
||||
[ATLDRV-1139] - after ifconfig -multicast Unicast filters registers have valid values for multicast addresses
|
||||
[ATLDRV-1170] - macsec key cleaned on SA updates
|
||||
[ATLDRV-1171] - AQ066: MSI index leak for head pointer writeback event
|
||||
[ATLDRV-1172] - AQ068: shift-count-overflow error in DESCR_FIELD()
|
||||
[ATLDRV-1187] - atlfwdtool not compiled on Centos
|
||||
[ATLDRV-1186] - FWD: MACsec offload (cleanup)
|
||||
|
||||
Version 1.0.28
|
||||
==============
|
||||
[ATLDRV-1128] - Traffic ingress on FWD ring
|
||||
[ATLDRV-1157] - Apply upstream patch for macsec offload to 4.14
|
||||
[ATLDRV-1158] - Implement Macsec EGRESS offload
|
||||
[ATLDRV-1159] - Implement Macsec INGRESS offload
|
||||
[ATLDRV-1160] - Provide macsec statistics to ethtool -s
|
||||
[ATLDRV-1161] - Add get_tx_queue_index command to atlfwdtool
|
||||
[ATLDRV-1153] - traffic dropped when lro enabled
|
||||
[ATLDRV-777] - FWD: BCM: Better support for systems with legacy interrupts
|
||||
|
||||
Version 1.0.27
|
||||
==============
|
||||
[ATLDRV-1132] - Media detect is disabled after sleep
|
||||
[ATLDRV-1129] - Add support for egress FWD queue pause/resume
|
||||
|
||||
Version 1.0.26
|
||||
==============
|
||||
[ATLDRV-660] - Wrong device ids are present in atl_main.c
|
||||
[ATLDRV-1113] - VLAN-PROMISC is turned off when PROMISC flag is set
|
||||
[ATLDRV-1124] - link is not up at 2.5G speed
|
||||
[ATLDRV-1105] - Allocate/destroy/disable/enable channels
|
||||
[ATLDRV-1114] - Send traffic via FWD ring
|
||||
[ATLDRV-1116] - Add support for FWD rings status / stats via ethtool
|
||||
[ATLDRV-1120] - reproduce descriptor writeback on disabled ring
|
||||
[ATLDRV-1126] - Print statistics for created FWD rings only
|
||||
|
||||
Version 1.0.25
|
||||
==============
|
||||
[ATLDRV-1118] - Page fault in atl_fwd_init_ring() upon ring creation (ATL_FWR_ALLOC_BUFS is not set)
|
||||
[ATLDRV-1119] - AQ058: again Bug CR 2491137 - Crash caused due to 32 Tx descs are zero'ed
|
||||
|
||||
Version 1.0.24
|
||||
==============
|
||||
[ATLDRV-1112] - descriptor corruption after suspend/resume
|
||||
[ATLDRV-1097] - EEE must be disabled by-default
|
||||
[ATLDRV-1099] - Strange EEE configuration behavior
|
||||
[ATLDRV-1107] - Strange message in dmesg
|
||||
[ATLDRV-1108] - FW not loaded after FWD driver unloaded on B0
|
||||
[ATLDRV-899] - Fwd driver: add more loopbacks to ethtool private flags
|
||||
[ATLDRV-1057] - Support for network loopback
|
||||
|
||||
Version 1.0.23
|
||||
==============
|
||||
[ATLDRV-983] - runtime D3 support
|
||||
[ATLDRV-1023] - AQ056: Wake on link race condition with host power manament
|
||||
|
||||
Version 1.0.22
|
||||
==============
|
||||
fix build of fwd api
|
||||
|
||||
Version 1.0.21
|
||||
==============
|
||||
[ATLDRV-871] - pause frame does not turn off
|
||||
[ATLDRV-994] - failed set StripEtherPadding
|
||||
[ATLDRV-1062] - FWD: IPA: AQ058: Crash caused due to 32 Tx descs are zero'ed
|
||||
[ATLDRV-1066] - AQ062: atl_update_eth_stats() - sleeping function called from invalid context
|
||||
[ATLDRV-1067] - AQ061: AQC FWD ring descriptor memory reset
|
||||
[ATLDRV-1068] - AQ060: AQC Rx accessing buffer address from previous atl_fwd_request_ring()
|
||||
[ATLDRV-1075] - AQ063: v1.0.20 driver - atl_update_thermal_flag() missing atl_unlock_fw()
|
||||
[ATLDRV-803] - AQ040: Validation for Interrupt Moderation in FWD API
|
||||
[ATLDRV-1022] - Media detect control
|
||||
|
||||
|
||||
Version 1.0.20
|
||||
==============
|
||||
net: aquantia: Re-initialize fwd rings on driver resume
|
||||
Do entire suspend from dev_pm_ops->suspend() (AQ052)
|
||||
Prevent atl_update_global_stats() calls when suspended (AQ056) (ATLDRV-1021)
|
||||
Implement thermal throttling (ATLDRV-1009)
|
||||
Add log message when high temperature treshold is reached (ATLDRV-998))
|
||||
Implement FW heartbeat watchdog (AQ010) (ATLDRV-502)
|
||||
Workaround checksum offload bugs (ATLDRV-1013)
|
||||
|
||||
Version 1.0.19
|
||||
==============
|
||||
Fix freeing of buf vaddr vector in FWD API (AQ050)
|
||||
Add a private data pointer to atl_fwd_mem_ops (AQ051)
|
||||
Implement wake-on-link-up support (AQ049)
|
||||
Introduce the forwarding engine API versioning (AQ048)
|
||||
Fix build errors (AQ047)
|
||||
Delay enabling bus-mastering until after reset sequence (AQ045)
|
||||
Validate interrupt moderation delays in FWD API (AQ040)
|
||||
|
||||
Version 1.0.18
|
||||
==============
|
||||
Fix double free in the new fwd ring memory allocation code.
|
||||
Fix 32-bit warnings (AQ036)
|
||||
Add a pointer for forwarding engine's private data. (AQ043)
|
||||
|
||||
Version 1.0.17
|
||||
==============
|
||||
Add compatibility to kernel 4.1
|
||||
create empty atl_hwmon_init for old kernels
|
||||
Fix legacy interrupt handling
|
||||
Fix MSM register writes
|
||||
Free link interrupt before reconfiguring the rings
|
||||
Implement FW settings table access
|
||||
Use new FW interface to control ethernet padding stripping
|
||||
Disable LRO by default until all issues are resolved.
|
||||
Clamp max number of rings as reported by ethtool to num_present_cpus() (AQ037)
|
||||
Use __GFP_NOWARN for Rx buffers only in NAPI poll (AQ037)
|
||||
Put PHY into low-power state on ifdown or disabling link
|
||||
Improve error reporting for forwarding-engine ring creation (AQ041)
|
||||
Allow custom memory allocators for atl_fwd_request_ring() (AQ041)
|
||||
|
||||
Version 1.0.16
|
||||
==============
|
||||
Introduce the config options for forwarding API (AQ033)
|
||||
Implement catchall ethtool filter (AQ034)
|
||||
Fix MSI-X vectors being disabled on cpu unplug (AQ032)
|
||||
Fix Kconfig changes for AQ033
|
||||
|
||||
Version 1.0.15
|
||||
==============
|
||||
Reset statistics via private flag
|
||||
Implement interrupt moderation for offload engine's rings
|
||||
Introduce a FW mutex, handle link interrupts in a workqueue
|
||||
Implement PHY temperature sensor
|
||||
Report ring's and buffer's physical addresses on fwd ring request
|
||||
Implement ethtool control for stripping Rx ethernet frame's padding
|
||||
|
||||
Version 1.0.14
|
||||
==============
|
||||
Remove old IPA implementation (replaced by atl_fwd.[ch])
|
||||
Fix forwarding engine interface
|
||||
Change the driver name to reflect the new module name
|
||||
Implement Linux PM support
|
||||
Implement WoL support
|
||||
|
||||
Version 1.0.13
|
||||
==============
|
||||
Integrate Linux VLAN filter hw acceleration with ethtool filters
|
||||
Rename the module to atlantic-fwd
|
||||
|
||||
Version 1.0.12
|
||||
==============
|
||||
Expose PHY LPI state via ethtool private flags
|
||||
|
||||
Version 1.0.11
|
||||
==============
|
||||
Minor IPA interface fixes
|
||||
Turn on/off Rx XOFF flow control when needed
|
||||
Fix advertizing EEE link modes and show LPI timer
|
||||
Add some HW counters from RMON MIB
|
||||
Add Host and Lost counters to statistics
|
||||
Add more Felicity PCI IDs
|
||||
Add ethtool private flags tracking LPI state
|
||||
|
||||
Version 1.0.10
|
||||
==============
|
||||
Add module parameter to force align IP headers
|
||||
|
||||
Version 1.0.9
|
||||
==============
|
||||
Add AQC100 / -111 / -112 IDs
|
||||
Fix adding vlan with vlan id > 64
|
||||
Fix ethtool IPv4 filter reporting (AQ022)
|
||||
Implement ethtool interface for ethertype filters.
|
||||
Restore backward compat for Linux 4.4
|
||||
|
||||
Version 1.0.8
|
||||
==============
|
||||
Fix checkpatch.pl and smatch warnings and errors
|
||||
|
||||
Version 1.0.7
|
||||
==============
|
||||
Make Tx ring free space watermarks configurable
|
||||
Misc filter fixes
|
||||
Implement ethtool interface for VLAN filters
|
||||
Implement pause statistics
|
||||
|
||||
Version 1.0.6
|
||||
==============
|
||||
Implement compat fixes for kernels without IPv6 ethtool NFC API
|
||||
|
||||
Version 1.0.5
|
||||
==============
|
||||
Fix ifdown / ifup link state race
|
||||
Fix autoneg re-enable on pre-ethtool_ksettings kernels
|
||||
Implement n-tuple Rx filters
|
||||
Misc clean-ups
|
||||
|
||||
Version 1.0.4
|
||||
==============
|
||||
Switch to using spin lock for updating global stats
|
||||
Fix out-of-bounds dma_sync_single_range() for packet header
|
||||
Fix an Rx error corner case
|
||||
Refactor delayed dma-unmapping of headers for RSC
|
||||
Implement HW loopbacks
|
||||
Implement interrupt coalescing ethtool method
|
||||
|
||||
Version 1.0.3
|
||||
==============
|
||||
Fix crash in mutex_lock on init
|
||||
Add compat cast for ->ndo_get_stats64 for old kernels
|
||||
Get rid of struct atl_common_stats
|
||||
Refactor ring structure to remove the need for -fplan9-extensions
|
||||
Drop -fplan9-extensions
|
||||
|
||||
Version 1.0.2
|
||||
==============
|
||||
Implement setting the MAC address
|
||||
Rework VLAN filters
|
||||
Implement per-ring counters
|
||||
Fix Tx queue start / stop handling
|
||||
Implement basic netdev stats
|
||||
Implement ethtool stats
|
||||
|
||||
Version 1.0.1
|
||||
==============
|
||||
Update the README
|
||||
Refactor the ring structure
|
||||
Fix LRO timers timebase
|
||||
Initial Qualcomm IPA support
|
||||
Refactor Link management
|
||||
Implement Flow Control
|
||||
Implement EEE
|
||||
Set default link on init
|
||||
Implement dynamic datapath reconfiguration
|
||||
Implement ethtool -> [gs]et_ringparam, set_channels
|
||||
|
||||
Version 1.0.0
|
||||
==============
|
||||
Add dma-mapping tracepoints
|
||||
Implement VLAN offloads
|
||||
Implement promiscuous mode and UC / MC filters
|
||||
Implement HW header splitting, fix Rx buffer mgmt for RSC
|
||||
Fix multicast filter support
|
||||
Implement new reset sequence
|
||||
Implement multi-fw switch
|
||||
Implement new link management
|
||||
Introduce link interrupt
|
||||
Implement ethtool set_settings and _ksettings variants
|
||||
Implement multiring support
|
||||
Implement RSS support
|
||||
Enable jumbo frames
|
||||
Fix ethtool RSS methods
|
||||
Add RDM / TDM descriptor thresholds
|
||||
Switch to INTR block based interrupt throttling
|
||||
Enable LRO
|
||||
Implement linear skb mode
|
||||
Loading…
Reference in a new issue