mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
Merge commit 'f9fe1c1' into for-next
Andreas Gruenbacher added function rhashtable_lookup_get_insert_fast to rhashtable.h. That patch went into the net-next tree. In a subsequent patch, GFS2 makes use of this new function. Therefore, we needed a merge commit to make the new function available to GFS2. Signed-off-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
commit
c369898759
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
Required properties:
|
||||
- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
|
||||
"brcm,genet-v3", "brcm,genet-v4".
|
||||
"brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5".
|
||||
- reg: address and length of the register set for the device
|
||||
- interrupts: must be two cells, the first cell is the general purpose
|
||||
interrupt line, while the second cell is the interrupt for the ring
|
||||
RX and TX queues operating in ring mode
|
||||
- interrupts and/or interrupts-extended: must be two cells, the first cell
|
||||
is the general purpose interrupt line, while the second cell is the
|
||||
interrupt for the ring RX and TX queues operating in ring mode. An
|
||||
optional third interrupt cell for Wake-on-LAN can be specified.
|
||||
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
for information on the property specifics.
|
||||
- phy-mode: see ethernet.txt file in the same directory
|
||||
- #address-cells: should be 1
|
||||
- #size-cells: should be 1
|
||||
|
|
@ -29,15 +32,15 @@ Optional properties:
|
|||
|
||||
Required child nodes:
|
||||
|
||||
- mdio bus node: this node should always be present regarless of the PHY
|
||||
- mdio bus node: this node should always be present regardless of the PHY
|
||||
configuration of the GENET instance
|
||||
|
||||
MDIO bus node required properties:
|
||||
|
||||
- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
|
||||
parent node compatible property (e.g: brcm,genet-v4 pairs with
|
||||
brcm,genet-mdio-v4)
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5", the version
|
||||
has to match the parent node compatible property (e.g: brcm,genet-v4 pairs
|
||||
with brcm,genet-mdio-v4)
|
||||
- reg: address and length relative to the parent node base register address
|
||||
- #address-cells: address cell for MDIO bus addressing, should be 1
|
||||
- #size-cells: size of the cells for MDIO bus addressing, should be 0
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
Required properties:
|
||||
- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
|
||||
- reg: address and length of the regsiter set for the device, first one is the
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5" or
|
||||
"brcm,unimac-mdio"
|
||||
- reg: address and length of the register set for the device, first one is the
|
||||
base register, and the second one is optional and for indirect accesses to
|
||||
larger than 16-bits MDIO transactions
|
||||
- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"
|
||||
|
|
|
|||
|
|
@ -1,17 +1,28 @@
|
|||
* Marvell Armada 375 Ethernet Controller (PPv2)
|
||||
* Marvell Armada 375 Ethernet Controller (PPv2.1)
|
||||
Marvell Armada 7K/8K Ethernet Controller (PPv2.2)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be "marvell,armada-375-pp2"
|
||||
- compatible: should be one of:
|
||||
"marvell,armada-375-pp2"
|
||||
"marvell,armada-7k-pp2"
|
||||
- reg: addresses and length of the register sets for the device.
|
||||
Must contain the following register sets:
|
||||
For "marvell,armada-375-pp2", must contain the following register
|
||||
sets:
|
||||
- common controller registers
|
||||
- LMS registers
|
||||
In addition, at least one port register set is required.
|
||||
- clocks: a pointer to the reference clocks for this device, consequently:
|
||||
- main controller clock
|
||||
- GOP clock
|
||||
- clock-names: names of used clocks, must be "pp_clk" and "gop_clk".
|
||||
- one register area per Ethernet port
|
||||
For "marvell,armada-7k-pp2", must contain the following register
|
||||
sets:
|
||||
- packet processor registers
|
||||
- networking interfaces registers
|
||||
|
||||
- clocks: pointers to the reference clocks for this device, consequently:
|
||||
- main controller clock (for both armada-375-pp2 and armada-7k-pp2)
|
||||
- GOP clock (for both armada-375-pp2 and armada-7k-pp2)
|
||||
- MG clock (only for armada-7k-pp2)
|
||||
- clock-names: names of used clocks, must be "pp_clk", "gop_clk" and
|
||||
"mg_clk" (the latter only for armada-7k-pp2).
|
||||
|
||||
The ethernet ports are represented by subnodes. At least one port is
|
||||
required.
|
||||
|
|
@ -19,8 +30,10 @@ required.
|
|||
Required properties (port):
|
||||
|
||||
- interrupts: interrupt for the port
|
||||
- port-id: should be '0' or '1' for ethernet ports, and '2' for the
|
||||
loopback port
|
||||
- port-id: ID of the port from the MAC point of view
|
||||
- gop-port-id: only for marvell,armada-7k-pp2, ID of the port from the
|
||||
GOP (Group Of Ports) point of view. This ID is used to index the
|
||||
per-port registers in the second register area.
|
||||
- phy-mode: See ethernet.txt file in the same directory
|
||||
|
||||
Optional properties (port):
|
||||
|
|
@ -29,7 +42,7 @@ Optional properties (port):
|
|||
- phy: a phandle to a phy node defining the PHY address (as the reg
|
||||
property, a single integer).
|
||||
|
||||
Example:
|
||||
Example for marvell,armada-375-pp2:
|
||||
|
||||
ethernet@f0000 {
|
||||
compatible = "marvell,armada-375-pp2";
|
||||
|
|
@ -57,3 +70,30 @@ ethernet@f0000 {
|
|||
phy-mode = "gmii";
|
||||
};
|
||||
};
|
||||
|
||||
Example for marvell,armada-7k-pp2:
|
||||
|
||||
cpm_ethernet: ethernet@0 {
|
||||
compatible = "marvell,armada-7k-pp22";
|
||||
reg = <0x0 0x100000>, <0x129000 0xb000>;
|
||||
clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>, <&cpm_syscon0 1 5>;
|
||||
clock-names = "pp_clk", "gop_clk", "gp_clk";
|
||||
|
||||
eth0: eth0 {
|
||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
port-id = <0>;
|
||||
gop-port-id = <0>;
|
||||
};
|
||||
|
||||
eth1: eth1 {
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
port-id = <1>;
|
||||
gop-port-id = <2>;
|
||||
};
|
||||
|
||||
eth2: eth2 {
|
||||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
|
||||
port-id = <2>;
|
||||
gop-port-id = <3>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ Optional properties:
|
|||
clocks may be specified in derived bindings.
|
||||
- clock-names: One name for each entry in the clocks property, the
|
||||
first one should be "stmmaceth" and the second one should be "pclk".
|
||||
- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
|
||||
available this clock is used for programming the Timestamp Addend Register.
|
||||
If not passed then the system clock will be used and this is fine on some
|
||||
- ptp_ref: this is the PTP reference clock; in case of the PTP is available
|
||||
this clock is used for programming the Timestamp Addend Register. If not
|
||||
passed then the system clock will be used and this is fine on some
|
||||
platforms.
|
||||
- tx-fifo-depth: See ethernet.txt file in the same directory
|
||||
- rx-fifo-depth: See ethernet.txt file in the same directory
|
||||
|
|
@ -72,7 +72,43 @@ Optional properties:
|
|||
- snps,mb: mixed-burst
|
||||
- snps,rb: rebuild INCRx Burst
|
||||
- mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
|
||||
|
||||
- Multiple RX Queues parameters: below the list of all the parameters to
|
||||
configure the multiple RX queues:
|
||||
- snps,rx-queues-to-use: number of RX queues to be used in the driver
|
||||
- Choose one of these RX scheduling algorithms:
|
||||
- snps,rx-sched-sp: Strict priority
|
||||
- snps,rx-sched-wsp: Weighted Strict priority
|
||||
- For each RX queue
|
||||
- Choose one of these modes:
|
||||
- snps,dcb-algorithm: Queue to be enabled as DCB
|
||||
- snps,avb-algorithm: Queue to be enabled as AVB
|
||||
- snps,map-to-dma-channel: Channel to map
|
||||
- Specifiy specific packet routing:
|
||||
- snps,route-avcp: AV Untagged Control packets
|
||||
- snps,route-ptp: PTP Packets
|
||||
- snps,route-dcbcp: DCB Control Packets
|
||||
- snps,route-up: Untagged Packets
|
||||
- snps,route-multi-broad: Multicast & Broadcast Packets
|
||||
- snps,priority: RX queue priority (Range: 0x0 to 0xF)
|
||||
- Multiple TX Queues parameters: below the list of all the parameters to
|
||||
configure the multiple TX queues:
|
||||
- snps,tx-queues-to-use: number of TX queues to be used in the driver
|
||||
- Choose one of these TX scheduling algorithms:
|
||||
- snps,tx-sched-wrr: Weighted Round Robin
|
||||
- snps,tx-sched-wfq: Weighted Fair Queuing
|
||||
- snps,tx-sched-dwrr: Deficit Weighted Round Robin
|
||||
- snps,tx-sched-sp: Strict priority
|
||||
- For each TX queue
|
||||
- snps,weight: TX queue weight (if using a DCB weight algorithm)
|
||||
- Choose one of these modes:
|
||||
- snps,dcb-algorithm: TX queue will be working in DCB
|
||||
- snps,avb-algorithm: TX queue will be working in AVB
|
||||
- Configure Credit Base Shaper (if AVB Mode selected):
|
||||
- snps,send_slope: enable Low Power Interface
|
||||
- snps,idle_slope: unlock on WoL
|
||||
- snps,high_credit: max write outstanding req. limit
|
||||
- snps,low_credit: max read outstanding req. limit
|
||||
- snps,priority: TX queue priority (Range: 0x0 to 0xF)
|
||||
Examples:
|
||||
|
||||
stmmac_axi_setup: stmmac-axi-config {
|
||||
|
|
@ -81,6 +117,35 @@ Examples:
|
|||
snps,blen = <256 128 64 32 0 0 0>;
|
||||
};
|
||||
|
||||
mtl_rx_setup: rx-queues-config {
|
||||
snps,rx-queues-to-use = <1>;
|
||||
snps,rx-sched-sp;
|
||||
queue0 {
|
||||
snps,dcb-algorithm;
|
||||
snps,map-to-dma-channel = <0x0>;
|
||||
snps,priority = <0x0>;
|
||||
};
|
||||
};
|
||||
|
||||
mtl_tx_setup: tx-queues-config {
|
||||
snps,tx-queues-to-use = <2>;
|
||||
snps,tx-sched-wrr;
|
||||
queue0 {
|
||||
snps,weight = <0x10>;
|
||||
snps,dcb-algorithm;
|
||||
snps,priority = <0x0>;
|
||||
};
|
||||
|
||||
queue1 {
|
||||
snps,avb-algorithm;
|
||||
snps,send_slope = <0x1000>;
|
||||
snps,idle_slope = <0x1000>;
|
||||
snps,high_credit = <0x3E800>;
|
||||
snps,low_credit = <0xFFC18000>;
|
||||
snps,priority = <0x1>;
|
||||
};
|
||||
};
|
||||
|
||||
gmac0: ethernet@e0800000 {
|
||||
compatible = "st,spear600-gmac";
|
||||
reg = <0xe0800000 0x8000>;
|
||||
|
|
@ -104,4 +169,6 @@ Examples:
|
|||
phy1: ethernet-phy@0 {
|
||||
};
|
||||
};
|
||||
snps,mtl-rx-config = <&mtl_rx_setup>;
|
||||
snps,mtl-tx-config = <&mtl_tx_setup>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -73,6 +73,14 @@ fib_multipath_use_neigh - BOOLEAN
|
|||
0 - disabled
|
||||
1 - enabled
|
||||
|
||||
fib_multipath_hash_policy - INTEGER
|
||||
Controls which hash policy to use for multipath routes. Only valid
|
||||
for kernels built with CONFIG_IP_ROUTE_MULTIPATH enabled.
|
||||
Default: 0 (Layer 3)
|
||||
Possible values:
|
||||
0 - Layer 3
|
||||
1 - Layer 4
|
||||
|
||||
route/max_size - INTEGER
|
||||
Maximum number of routes allowed in the kernel. Increase
|
||||
this when using large numbers of interfaces and/or routes.
|
||||
|
|
@ -640,11 +648,6 @@ tcp_tso_win_divisor - INTEGER
|
|||
building larger TSO frames.
|
||||
Default: 3
|
||||
|
||||
tcp_tw_recycle - BOOLEAN
|
||||
Enable fast recycling TIME-WAIT sockets. Default value is 0.
|
||||
It should not be changed without advice/request of technical
|
||||
experts.
|
||||
|
||||
tcp_tw_reuse - BOOLEAN
|
||||
Allow to reuse TIME-WAIT sockets for new connections when it is
|
||||
safe from protocol viewpoint. Default value is 0.
|
||||
|
|
|
|||
|
|
@ -175,6 +175,14 @@ nat_icmp_send - BOOLEAN
|
|||
for VS/NAT when the load balancer receives packets from real
|
||||
servers but the connection entries don't exist.
|
||||
|
||||
pmtu_disc - BOOLEAN
|
||||
0 - disabled
|
||||
not 0 - enabled (default)
|
||||
|
||||
By default, reject with FRAG_NEEDED all DF packets that exceed
|
||||
the PMTU, irrespective of the forwarding method. For TUN method
|
||||
the flag can be disabled to fragment such packets.
|
||||
|
||||
secure_tcp - INTEGER
|
||||
0 - disabled (default)
|
||||
|
||||
|
|
@ -185,15 +193,59 @@ secure_tcp - INTEGER
|
|||
The value definition is the same as that of drop_entry and
|
||||
drop_packet.
|
||||
|
||||
sync_threshold - INTEGER
|
||||
default 3
|
||||
sync_threshold - vector of 2 INTEGERs: sync_threshold, sync_period
|
||||
default 3 50
|
||||
|
||||
It sets synchronization threshold, which is the minimum number
|
||||
of incoming packets that a connection needs to receive before
|
||||
the connection will be synchronized. A connection will be
|
||||
synchronized, every time the number of its incoming packets
|
||||
modulus 50 equals the threshold. The range of the threshold is
|
||||
from 0 to 49.
|
||||
It sets synchronization threshold, which is the minimum number
|
||||
of incoming packets that a connection needs to receive before
|
||||
the connection will be synchronized. A connection will be
|
||||
synchronized, every time the number of its incoming packets
|
||||
modulus sync_period equals the threshold. The range of the
|
||||
threshold is from 0 to sync_period.
|
||||
|
||||
When sync_period and sync_refresh_period are 0, send sync only
|
||||
for state changes or only once when pkts matches sync_threshold
|
||||
|
||||
sync_refresh_period - UNSIGNED INTEGER
|
||||
default 0
|
||||
|
||||
In seconds, difference in reported connection timer that triggers
|
||||
new sync message. It can be used to avoid sync messages for the
|
||||
specified period (or half of the connection timeout if it is lower)
|
||||
if connection state is not changed since last sync.
|
||||
|
||||
This is useful for normal connections with high traffic to reduce
|
||||
sync rate. Additionally, retry sync_retries times with period of
|
||||
sync_refresh_period/8.
|
||||
|
||||
sync_retries - INTEGER
|
||||
default 0
|
||||
|
||||
Defines sync retries with period of sync_refresh_period/8. Useful
|
||||
to protect against loss of sync messages. The range of the
|
||||
sync_retries is from 0 to 3.
|
||||
|
||||
sync_qlen_max - UNSIGNED LONG
|
||||
|
||||
Hard limit for queued sync messages that are not sent yet. It
|
||||
defaults to 1/32 of the memory pages but actually represents
|
||||
number of messages. It will protect us from allocating large
|
||||
parts of memory when the sending rate is lower than the queuing
|
||||
rate.
|
||||
|
||||
sync_sock_size - INTEGER
|
||||
default 0
|
||||
|
||||
Configuration of SNDBUF (master) or RCVBUF (slave) socket limit.
|
||||
Default value is 0 (preserve system defaults).
|
||||
|
||||
sync_ports - INTEGER
|
||||
default 1
|
||||
|
||||
The number of threads that master and backup servers can use for
|
||||
sync traffic. Every thread will use single UDP port, thread 0 will
|
||||
use the default port 8848 while last thread will use port
|
||||
8848+sync_ports-1.
|
||||
|
||||
snat_reroute - BOOLEAN
|
||||
0 - disabled
|
||||
|
|
|
|||
|
|
@ -19,6 +19,25 @@ platform_labels - INTEGER
|
|||
Possible values: 0 - 1048575
|
||||
Default: 0
|
||||
|
||||
ip_ttl_propagate - BOOL
|
||||
Control whether TTL is propagated from the IPv4/IPv6 header to
|
||||
the MPLS header on imposing labels and propagated from the
|
||||
MPLS header to the IPv4/IPv6 header on popping the last label.
|
||||
|
||||
If disabled, the MPLS transport network will appear as a
|
||||
single hop to transit traffic.
|
||||
|
||||
0 - disabled / RFC 3443 [Short] Pipe Model
|
||||
1 - enabled / RFC 3443 Uniform Model (default)
|
||||
|
||||
default_ttl - BOOL
|
||||
Default TTL value to use for MPLS packets where it cannot be
|
||||
propagated from an IP header, either because one isn't present
|
||||
or ip_ttl_propagate has been disabled.
|
||||
|
||||
Possible values: 1 - 255
|
||||
Default: 255
|
||||
|
||||
conf/<interface>/input - BOOL
|
||||
Control whether packets can be input on this interface.
|
||||
|
||||
|
|
|
|||
13
MAINTAINERS
13
MAINTAINERS
|
|
@ -896,12 +896,19 @@ F: arch/arm64/boot/dts/apm/
|
|||
APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
|
||||
M: Iyappan Subramanian <isubramanian@apm.com>
|
||||
M: Keyur Chudgar <kchudgar@apm.com>
|
||||
M: Quan Nguyen <qnguyen@apm.com>
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/apm/xgene/
|
||||
F: drivers/net/phy/mdio-xgene.c
|
||||
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
|
||||
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
|
||||
|
||||
APPLIED MICRO (APM) X-GENE SOC ETHERNET (V2) DRIVER
|
||||
M: Iyappan Subramanian <isubramanian@apm.com>
|
||||
M: Keyur Chudgar <kchudgar@apm.com>
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/apm/xgene-v2/
|
||||
|
||||
APPLIED MICRO (APM) X-GENE SOC PMU
|
||||
M: Tai Nguyen <ttnguyen@apm.com>
|
||||
S: Supported
|
||||
|
|
@ -11061,6 +11068,12 @@ F: include/linux/dma/dw.h
|
|||
F: include/linux/platform_data/dma-dw.h
|
||||
F: drivers/dma/dw/
|
||||
|
||||
SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
|
||||
M: Jie Deng <jiedeng@synopsys.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/synopsys/
|
||||
|
||||
SYNOPSYS DESIGNWARE I2C DRIVER
|
||||
M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
|
|
|
|||
|
|
@ -2267,9 +2267,8 @@ static int amb_probe(struct pci_dev *pci_dev,
|
|||
dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
|
||||
dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
|
||||
|
||||
init_timer(&dev->housekeeping);
|
||||
dev->housekeeping.function = do_housekeeping;
|
||||
dev->housekeeping.data = (unsigned long) dev;
|
||||
setup_timer(&dev->housekeeping, do_housekeeping,
|
||||
(unsigned long)dev);
|
||||
mod_timer(&dev->housekeeping, jiffies);
|
||||
|
||||
// enable host interrupts
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "hyperv_vmbus.h"
|
||||
|
||||
#define VMBUS_PKT_TRAILER 8
|
||||
|
||||
/*
|
||||
* When we write to the ring buffer, check if the host needs to
|
||||
* be signaled. Here is the details of this protocol:
|
||||
|
|
@ -336,6 +338,12 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_cached_read_index(struct hv_ring_buffer_info *rbi)
|
||||
{
|
||||
rbi->cached_read_index = rbi->ring_buffer->read_index;
|
||||
}
|
||||
|
||||
int hv_ringbuffer_read(struct vmbus_channel *channel,
|
||||
void *buffer, u32 buflen, u32 *buffer_actual_len,
|
||||
u64 *requestid, bool raw)
|
||||
|
|
@ -366,7 +374,8 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
|
|||
return ret;
|
||||
}
|
||||
|
||||
init_cached_read_index(channel);
|
||||
init_cached_read_index(inring_info);
|
||||
|
||||
next_read_location = hv_get_next_read_location(inring_info);
|
||||
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
|
||||
sizeof(desc),
|
||||
|
|
@ -410,3 +419,86 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine number of bytes available in ring buffer after
|
||||
* the current iterator (priv_read_index) location.
|
||||
*
|
||||
* This is similar to hv_get_bytes_to_read but with private
|
||||
* read index instead.
|
||||
*/
|
||||
static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
|
||||
{
|
||||
u32 priv_read_loc = rbi->priv_read_index;
|
||||
u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
|
||||
|
||||
if (write_loc >= priv_read_loc)
|
||||
return write_loc - priv_read_loc;
|
||||
else
|
||||
return (rbi->ring_datasize - priv_read_loc) + write_loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get first vmbus packet from ring buffer after read_index
|
||||
*
|
||||
* If ring buffer is empty, returns NULL and no other action needed.
|
||||
*/
|
||||
struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
|
||||
/* set state for later hv_signal_on_read() */
|
||||
init_cached_read_index(rbi);
|
||||
|
||||
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
|
||||
return NULL;
|
||||
|
||||
return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
|
||||
|
||||
/*
|
||||
* Get next vmbus packet from ring buffer.
|
||||
*
|
||||
* Advances the current location (priv_read_index) and checks for more
|
||||
* data. If the end of the ring buffer is reached, then return NULL.
|
||||
*/
|
||||
struct vmpacket_descriptor *
|
||||
__hv_pkt_iter_next(struct vmbus_channel *channel,
|
||||
const struct vmpacket_descriptor *desc)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
u32 packetlen = desc->len8 << 3;
|
||||
u32 dsize = rbi->ring_datasize;
|
||||
|
||||
/* bump offset to next potential packet */
|
||||
rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
|
||||
if (rbi->priv_read_index >= dsize)
|
||||
rbi->priv_read_index -= dsize;
|
||||
|
||||
/* more data? */
|
||||
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
|
||||
return NULL;
|
||||
else
|
||||
return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
|
||||
|
||||
/*
|
||||
* Update host ring buffer after iterating over packets.
|
||||
*/
|
||||
void hv_pkt_iter_close(struct vmbus_channel *channel)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
|
||||
/*
|
||||
* Make sure all reads are done before we update the read index since
|
||||
* the writer may start writing to the read area once the read index
|
||||
* is updated.
|
||||
*/
|
||||
virt_rmb();
|
||||
rbi->ring_buffer->read_index = rbi->priv_read_index;
|
||||
|
||||
hv_signal_on_read(channel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_pkt_iter_close);
|
||||
|
|
|
|||
|
|
@ -587,9 +587,8 @@ void qedr_affiliated_event(void *context, u8 e_code, void *fw_handle)
|
|||
#define EVENT_TYPE_CQ 1
|
||||
#define EVENT_TYPE_QP 2
|
||||
struct qedr_dev *dev = (struct qedr_dev *)context;
|
||||
union event_ring_data *data = fw_handle;
|
||||
u64 roce_handle64 = ((u64)data->roce_handle.hi << 32) +
|
||||
data->roce_handle.lo;
|
||||
struct regpair *async_handle = (struct regpair *)fw_handle;
|
||||
u64 roce_handle64 = ((u64) async_handle->hi << 32) + async_handle->lo;
|
||||
u8 event_type = EVENT_TYPE_NOT_DEFINED;
|
||||
struct ib_event event;
|
||||
struct ib_cq *ibcq;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@
|
|||
#include <linux/qed/qed_chain.h>
|
||||
#include <linux/qed/qed_roce_if.h>
|
||||
#include <linux/qed/qede_roce.h>
|
||||
#include "qedr_hsi.h"
|
||||
#include <linux/qed/roce_common.h>
|
||||
#include "qedr_hsi_rdma.h"
|
||||
|
||||
#define QEDR_MODULE_VERSION "8.10.10.0"
|
||||
#define QEDR_NODE_DESC "QLogic 579xx RoCE HCA"
|
||||
|
|
|
|||
|
|
@ -43,14 +43,11 @@
|
|||
#include <rdma/ib_addr.h>
|
||||
#include <rdma/ib_cache.h>
|
||||
|
||||
#include "qedr_hsi.h"
|
||||
#include <linux/qed/qed_if.h>
|
||||
#include <linux/qed/qed_roce_if.h>
|
||||
#include "qedr.h"
|
||||
#include "qedr_hsi.h"
|
||||
#include "verbs.h"
|
||||
#include <rdma/qedr-abi.h>
|
||||
#include "qedr_hsi.h"
|
||||
#include "qedr_cm.h"
|
||||
|
||||
void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info)
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
/* QLogic qedr NIC Driver
|
||||
* Copyright (c) 2015-2016 QLogic Corporation
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and /or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef __QED_HSI_ROCE__
|
||||
#define __QED_HSI_ROCE__
|
||||
|
||||
#include <linux/qed/common_hsi.h>
|
||||
#include <linux/qed/roce_common.h>
|
||||
#include "qedr_hsi_rdma.h"
|
||||
|
||||
/* Affiliated asynchronous events / errors enumeration */
|
||||
enum roce_async_events_type {
|
||||
ROCE_ASYNC_EVENT_NONE = 0,
|
||||
ROCE_ASYNC_EVENT_COMM_EST = 1,
|
||||
ROCE_ASYNC_EVENT_SQ_DRAINED,
|
||||
ROCE_ASYNC_EVENT_SRQ_LIMIT,
|
||||
ROCE_ASYNC_EVENT_LAST_WQE_REACHED,
|
||||
ROCE_ASYNC_EVENT_CQ_ERR,
|
||||
ROCE_ASYNC_EVENT_LOCAL_INVALID_REQUEST_ERR,
|
||||
ROCE_ASYNC_EVENT_LOCAL_CATASTROPHIC_ERR,
|
||||
ROCE_ASYNC_EVENT_LOCAL_ACCESS_ERR,
|
||||
ROCE_ASYNC_EVENT_QP_CATASTROPHIC_ERR,
|
||||
ROCE_ASYNC_EVENT_CQ_OVERFLOW_ERR,
|
||||
ROCE_ASYNC_EVENT_SRQ_EMPTY,
|
||||
MAX_ROCE_ASYNC_EVENTS_TYPE
|
||||
};
|
||||
|
||||
#endif /* __QED_HSI_ROCE__ */
|
||||
|
|
@ -43,7 +43,8 @@
|
|||
#include <rdma/ib_addr.h>
|
||||
#include <rdma/ib_cache.h>
|
||||
|
||||
#include "qedr_hsi.h"
|
||||
#include <linux/qed/common_hsi.h>
|
||||
#include "qedr_hsi_rdma.h"
|
||||
#include <linux/qed/qed_if.h>
|
||||
#include "qedr.h"
|
||||
#include "verbs.h"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ config MISDN_HFCPCI
|
|||
|
||||
config MISDN_HFCMULTI
|
||||
tristate "Support for HFC multiport cards (HFC-4S/8S/E1)"
|
||||
depends on PCI || 8xx
|
||||
depends on PCI || CPM1
|
||||
depends on MISDN
|
||||
help
|
||||
Enable support for cards with Cologne Chip AG's HFC multiport
|
||||
|
|
@ -27,8 +27,8 @@ config MISDN_HFCMULTI_8xx
|
|||
bool "Support for XHFC embedded board in HFC multiport driver"
|
||||
depends on MISDN
|
||||
depends on MISDN_HFCMULTI
|
||||
depends on 8xx
|
||||
default 8xx
|
||||
depends on CPM1
|
||||
default CPM1
|
||||
help
|
||||
Enable support for the XHFC embedded solution from Speech Design.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <asm/8xx_immap.h>
|
||||
#include <asm/cpm1.h>
|
||||
|
||||
/* Change this to the value used by your board */
|
||||
#ifndef IMAP_ADDR
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ enum ad_link_speed_type {
|
|||
AD_LINK_SPEED_2500MBPS,
|
||||
AD_LINK_SPEED_10000MBPS,
|
||||
AD_LINK_SPEED_20000MBPS,
|
||||
AD_LINK_SPEED_25000MBPS,
|
||||
AD_LINK_SPEED_40000MBPS,
|
||||
AD_LINK_SPEED_56000MBPS,
|
||||
AD_LINK_SPEED_100000MBPS,
|
||||
|
|
@ -260,6 +261,7 @@ static inline int __check_agg_selection_timer(struct port *port)
|
|||
* %AD_LINK_SPEED_2500MBPS,
|
||||
* %AD_LINK_SPEED_10000MBPS
|
||||
* %AD_LINK_SPEED_20000MBPS
|
||||
* %AD_LINK_SPEED_25000MBPS
|
||||
* %AD_LINK_SPEED_40000MBPS
|
||||
* %AD_LINK_SPEED_56000MBPS
|
||||
* %AD_LINK_SPEED_100000MBPS
|
||||
|
|
@ -302,6 +304,10 @@ static u16 __get_link_speed(struct port *port)
|
|||
speed = AD_LINK_SPEED_20000MBPS;
|
||||
break;
|
||||
|
||||
case SPEED_25000:
|
||||
speed = AD_LINK_SPEED_25000MBPS;
|
||||
break;
|
||||
|
||||
case SPEED_40000:
|
||||
speed = AD_LINK_SPEED_40000MBPS;
|
||||
break;
|
||||
|
|
@ -707,6 +713,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
|
|||
case AD_LINK_SPEED_20000MBPS:
|
||||
bandwidth = nports * 20000;
|
||||
break;
|
||||
case AD_LINK_SPEED_25000MBPS:
|
||||
bandwidth = nports * 25000;
|
||||
break;
|
||||
case AD_LINK_SPEED_40000MBPS:
|
||||
bandwidth = nports * 40000;
|
||||
break;
|
||||
|
|
@ -1052,8 +1061,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
|
|||
port->sm_rx_state = AD_RX_INITIALIZE;
|
||||
port->sm_vars |= AD_PORT_CHURNED;
|
||||
/* check if port is not enabled */
|
||||
} else if (!(port->sm_vars & AD_PORT_BEGIN)
|
||||
&& !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED))
|
||||
} else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled)
|
||||
port->sm_rx_state = AD_RX_PORT_DISABLED;
|
||||
/* check if new lacpdu arrived */
|
||||
else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) ||
|
||||
|
|
@ -1081,11 +1089,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
|
|||
/* if no lacpdu arrived and no timer is on */
|
||||
switch (port->sm_rx_state) {
|
||||
case AD_RX_PORT_DISABLED:
|
||||
if (port->sm_vars & AD_PORT_MOVED)
|
||||
port->sm_rx_state = AD_RX_INITIALIZE;
|
||||
else if (port->is_enabled
|
||||
&& (port->sm_vars
|
||||
& AD_PORT_LACP_ENABLED))
|
||||
if (port->is_enabled &&
|
||||
(port->sm_vars & AD_PORT_LACP_ENABLED))
|
||||
port->sm_rx_state = AD_RX_EXPIRED;
|
||||
else if (port->is_enabled
|
||||
&& ((port->sm_vars
|
||||
|
|
@ -1115,7 +1120,6 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
|
|||
port->sm_vars &= ~AD_PORT_SELECTED;
|
||||
__record_default(port);
|
||||
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
|
||||
port->sm_vars &= ~AD_PORT_MOVED;
|
||||
port->sm_rx_state = AD_RX_PORT_DISABLED;
|
||||
|
||||
/* Fall Through */
|
||||
|
|
|
|||
|
|
@ -201,12 +201,6 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(0);
|
|||
|
||||
unsigned int bond_net_id __read_mostly;
|
||||
|
||||
static __be32 arp_target[BOND_MAX_ARP_TARGETS];
|
||||
static int arp_ip_count;
|
||||
static int bond_mode = BOND_MODE_ROUNDROBIN;
|
||||
static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
|
||||
static int lacp_fast;
|
||||
|
||||
/*-------------------------- Forward declarations ---------------------------*/
|
||||
|
||||
static int bond_init(struct net_device *bond_dev);
|
||||
|
|
@ -2575,10 +2569,8 @@ static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
|
|||
* arp is transmitted to generate traffic. see activebackup_arp_monitor for
|
||||
* arp monitoring in active backup mode.
|
||||
*/
|
||||
static void bond_loadbalance_arp_mon(struct work_struct *work)
|
||||
static void bond_loadbalance_arp_mon(struct bonding *bond)
|
||||
{
|
||||
struct bonding *bond = container_of(work, struct bonding,
|
||||
arp_work.work);
|
||||
struct slave *slave, *oldcurrent;
|
||||
struct list_head *iter;
|
||||
int do_failover = 0, slave_state_changed = 0;
|
||||
|
|
@ -2916,10 +2908,8 @@ static bool bond_ab_arp_probe(struct bonding *bond)
|
|||
return should_notify_rtnl;
|
||||
}
|
||||
|
||||
static void bond_activebackup_arp_mon(struct work_struct *work)
|
||||
static void bond_activebackup_arp_mon(struct bonding *bond)
|
||||
{
|
||||
struct bonding *bond = container_of(work, struct bonding,
|
||||
arp_work.work);
|
||||
bool should_notify_peers = false;
|
||||
bool should_notify_rtnl = false;
|
||||
int delta_in_ticks;
|
||||
|
|
@ -2972,6 +2962,17 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
static void bond_arp_monitor(struct work_struct *work)
|
||||
{
|
||||
struct bonding *bond = container_of(work, struct bonding,
|
||||
arp_work.work);
|
||||
|
||||
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
|
||||
bond_activebackup_arp_mon(bond);
|
||||
else
|
||||
bond_loadbalance_arp_mon(bond);
|
||||
}
|
||||
|
||||
/*-------------------------- netdev event handling --------------------------*/
|
||||
|
||||
/* Change device name */
|
||||
|
|
@ -3228,10 +3229,7 @@ static void bond_work_init_all(struct bonding *bond)
|
|||
bond_resend_igmp_join_requests_delayed);
|
||||
INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
|
||||
INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
|
||||
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
|
||||
INIT_DELAYED_WORK(&bond->arp_work, bond_activebackup_arp_mon);
|
||||
else
|
||||
INIT_DELAYED_WORK(&bond->arp_work, bond_loadbalance_arp_mon);
|
||||
INIT_DELAYED_WORK(&bond->arp_work, bond_arp_monitor);
|
||||
INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
|
||||
INIT_DELAYED_WORK(&bond->slave_arr_work, bond_slave_arr_handler);
|
||||
}
|
||||
|
|
@ -3266,8 +3264,6 @@ static int bond_open(struct net_device *bond_dev)
|
|||
}
|
||||
}
|
||||
|
||||
bond_work_init_all(bond);
|
||||
|
||||
if (bond_is_lb(bond)) {
|
||||
/* bond_alb_initialize must be called before the timer
|
||||
* is started.
|
||||
|
|
@ -4252,6 +4248,12 @@ static int bond_check_params(struct bond_params *params)
|
|||
int arp_all_targets_value;
|
||||
u16 ad_actor_sys_prio = 0;
|
||||
u16 ad_user_port_key = 0;
|
||||
__be32 arp_target[BOND_MAX_ARP_TARGETS];
|
||||
int arp_ip_count;
|
||||
int bond_mode = BOND_MODE_ROUNDROBIN;
|
||||
int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
|
||||
int lacp_fast = 0;
|
||||
int tlb_dynamic_lb = 0;
|
||||
|
||||
/* Convert string parameters. */
|
||||
if (mode) {
|
||||
|
|
@ -4564,6 +4566,17 @@ static int bond_check_params(struct bond_params *params)
|
|||
}
|
||||
ad_user_port_key = valptr->value;
|
||||
|
||||
if (bond_mode == BOND_MODE_TLB) {
|
||||
bond_opt_initstr(&newval, "default");
|
||||
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_TLB_DYNAMIC_LB),
|
||||
&newval);
|
||||
if (!valptr) {
|
||||
pr_err("Error: No tlb_dynamic_lb default value");
|
||||
return -EINVAL;
|
||||
}
|
||||
tlb_dynamic_lb = valptr->value;
|
||||
}
|
||||
|
||||
if (lp_interval == 0) {
|
||||
pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
|
||||
INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
|
||||
|
|
@ -4591,7 +4604,7 @@ static int bond_check_params(struct bond_params *params)
|
|||
params->min_links = min_links;
|
||||
params->lp_interval = lp_interval;
|
||||
params->packets_per_slave = packets_per_slave;
|
||||
params->tlb_dynamic_lb = 1; /* Default value */
|
||||
params->tlb_dynamic_lb = tlb_dynamic_lb;
|
||||
params->ad_actor_sys_prio = ad_actor_sys_prio;
|
||||
eth_zero_addr(params->ad_actor_system);
|
||||
params->ad_user_port_key = ad_user_port_key;
|
||||
|
|
@ -4687,6 +4700,8 @@ int bond_create(struct net *net, const char *name)
|
|||
|
||||
netif_carrier_off(bond_dev);
|
||||
|
||||
bond_work_init_all(bond);
|
||||
|
||||
rtnl_unlock();
|
||||
if (res < 0)
|
||||
bond_destructor(bond_dev);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
|
||||
mv88e6xxx-objs := chip.o
|
||||
mv88e6xxx-objs += global1.o
|
||||
mv88e6xxx-objs += global1_atu.o
|
||||
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o
|
||||
mv88e6xxx-objs += port.o
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -38,4 +38,15 @@ int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
|
|||
int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
|
||||
|
||||
int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all);
|
||||
int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,
|
||||
unsigned int msecs);
|
||||
int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
struct mv88e6xxx_atu_entry *entry);
|
||||
int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
struct mv88e6xxx_atu_entry *entry);
|
||||
int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all);
|
||||
int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
|
||||
bool all);
|
||||
|
||||
#endif /* _MV88E6XXX_GLOBAL1_H */
|
||||
|
|
|
|||
300
drivers/net/dsa/mv88e6xxx/global1_atu.c
Normal file
300
drivers/net/dsa/mv88e6xxx/global1_atu.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Marvell 88E6xxx Address Translation Unit (ATU) support
|
||||
*
|
||||
* Copyright (c) 2008 Marvell Semiconductor
|
||||
* Copyright (c) 2017 Savoir-faire Linux, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "mv88e6xxx.h"
|
||||
#include "global1.h"
|
||||
|
||||
/* Offset 0x01: ATU FID Register */
|
||||
|
||||
static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid)
|
||||
{
|
||||
return mv88e6xxx_g1_write(chip, GLOBAL_ATU_FID, fid & 0xfff);
|
||||
}
|
||||
|
||||
/* Offset 0x0A: ATU Control Register */
|
||||
|
||||
int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all)
|
||||
{
|
||||
u16 val;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (learn2all)
|
||||
val |= GLOBAL_ATU_CONTROL_LEARN2ALL;
|
||||
else
|
||||
val &= ~GLOBAL_ATU_CONTROL_LEARN2ALL;
|
||||
|
||||
return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
|
||||
}
|
||||
|
||||
int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,
|
||||
unsigned int msecs)
|
||||
{
|
||||
const unsigned int coeff = chip->info->age_time_coeff;
|
||||
const unsigned int min = 0x01 * coeff;
|
||||
const unsigned int max = 0xff * coeff;
|
||||
u8 age_time;
|
||||
u16 val;
|
||||
int err;
|
||||
|
||||
if (msecs < min || msecs > max)
|
||||
return -ERANGE;
|
||||
|
||||
/* Round to nearest multiple of coeff */
|
||||
age_time = (msecs + coeff / 2) / coeff;
|
||||
|
||||
err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* AgeTime is 11:4 bits */
|
||||
val &= ~0xff0;
|
||||
val |= age_time << 4;
|
||||
|
||||
return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
|
||||
}
|
||||
|
||||
/* Offset 0x0B: ATU Operation Register */
|
||||
|
||||
static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
|
||||
{
|
||||
return mv88e6xxx_g1_wait(chip, GLOBAL_ATU_OP, GLOBAL_ATU_OP_BUSY);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
|
||||
{
|
||||
u16 val;
|
||||
int err;
|
||||
|
||||
/* FID bits are dispatched all around gradually as more are supported */
|
||||
if (mv88e6xxx_num_databases(chip) > 256) {
|
||||
err = mv88e6xxx_g1_atu_fid_write(chip, fid);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
if (mv88e6xxx_num_databases(chip) > 16) {
|
||||
/* ATU DBNum[7:4] are located in ATU Control 15:12 */
|
||||
err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = (val & 0x0fff) | ((fid << 8) & 0xf000);
|
||||
err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ATU DBNum[3:0] are located in ATU Operation 3:0 */
|
||||
op |= fid & 0xf;
|
||||
}
|
||||
|
||||
err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_OP, op);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mv88e6xxx_g1_atu_op_wait(chip);
|
||||
}
|
||||
|
||||
/* Offset 0x0C: ATU Data Register */
|
||||
|
||||
static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
|
||||
struct mv88e6xxx_atu_entry *entry)
|
||||
{
|
||||
u16 val;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_DATA, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
entry->state = val & 0xf;
|
||||
if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
|
||||
if (val & GLOBAL_ATU_DATA_TRUNK)
|
||||
entry->trunk = true;
|
||||
|
||||
entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
|
||||
struct mv88e6xxx_atu_entry *entry)
|
||||
{
|
||||
u16 data = entry->state & 0xf;
|
||||
|
||||
if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
|
||||
if (entry->trunk)
|
||||
data |= GLOBAL_ATU_DATA_TRUNK;
|
||||
|
||||
data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4;
|
||||
}
|
||||
|
||||
return mv88e6xxx_g1_write(chip, GLOBAL_ATU_DATA, data);
|
||||
}
|
||||
|
||||
/* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1
|
||||
* Offset 0x0E: ATU MAC Address Register Bytes 2 & 3
|
||||
* Offset 0x0F: ATU MAC Address Register Bytes 4 & 5
|
||||
*/
|
||||
|
||||
static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip,
|
||||
struct mv88e6xxx_atu_entry *entry)
|
||||
{
|
||||
u16 val;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_MAC_01 + i, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
entry->mac[i * 2] = val >> 8;
|
||||
entry->mac[i * 2 + 1] = val & 0xff;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip,
|
||||
struct mv88e6xxx_atu_entry *entry)
|
||||
{
|
||||
u16 val;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1];
|
||||
err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_MAC_01 + i, val);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Address Translation Unit operations */
|
||||
|
||||
int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
struct mv88e6xxx_atu_entry *entry)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_op_wait(chip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Write the MAC address to iterate from only once */
|
||||
if (entry->state == GLOBAL_ATU_DATA_STATE_UNUSED) {
|
||||
err = mv88e6xxx_g1_atu_mac_write(chip, entry);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_data_read(chip, entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mv88e6xxx_g1_atu_mac_read(chip, entry);
|
||||
}
|
||||
|
||||
int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
struct mv88e6xxx_atu_entry *entry)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_op_wait(chip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_mac_write(chip, entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_data_write(chip, entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_LOAD_DB);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
struct mv88e6xxx_atu_entry *entry,
|
||||
bool all)
|
||||
{
|
||||
u16 op;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_op_wait(chip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mv88e6xxx_g1_atu_data_write(chip, entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Flush/Move all or non-static entries from all or a given database */
|
||||
if (all && fid)
|
||||
op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB;
|
||||
else if (fid)
|
||||
op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
|
||||
else if (all)
|
||||
op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL;
|
||||
else
|
||||
op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC;
|
||||
|
||||
return mv88e6xxx_g1_atu_op(chip, fid, op);
|
||||
}
|
||||
|
||||
int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all)
|
||||
{
|
||||
struct mv88e6xxx_atu_entry entry = {
|
||||
.state = 0, /* Null EntryState means Flush */
|
||||
};
|
||||
|
||||
return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
int from_port, int to_port, bool all)
|
||||
{
|
||||
struct mv88e6xxx_atu_entry entry = { 0 };
|
||||
unsigned long mask;
|
||||
int shift;
|
||||
|
||||
if (!chip->info->atu_move_port_mask)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mask = chip->info->atu_move_port_mask;
|
||||
shift = bitmap_weight(&mask, 16);
|
||||
|
||||
entry.state = 0xf, /* Full EntryState means Move */
|
||||
entry.portvec = from_port & mask;
|
||||
entry.portvec |= (to_port & mask) << shift;
|
||||
|
||||
return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
|
||||
}
|
||||
|
||||
int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
|
||||
bool all)
|
||||
{
|
||||
int from_port = port;
|
||||
int to_port = chip->info->atu_move_port_mask;
|
||||
|
||||
return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all);
|
||||
}
|
||||
|
|
@ -132,18 +132,19 @@
|
|||
#define PORT_CONTROL_TAG_IF_BOTH BIT(6)
|
||||
#define PORT_CONTROL_USE_IP BIT(5)
|
||||
#define PORT_CONTROL_USE_TAG BIT(4)
|
||||
#define PORT_CONTROL_FORWARD_UNKNOWN_MC BIT(3)
|
||||
#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2)
|
||||
#define PORT_CONTROL_NOT_EGRESS_UNKNOWN_DA (0x0 << 2)
|
||||
#define PORT_CONTROL_NOT_EGRESS_UNKNOWN_MULTICAST_DA (0x1 << 2)
|
||||
#define PORT_CONTROL_NOT_EGRESS_UNKNOWN_UNITCAST_DA (0x2 << 2)
|
||||
#define PORT_CONTROL_EGRESS_ALL_UNKNOWN_DA (0x3 << 2)
|
||||
#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2)
|
||||
#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2)
|
||||
#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2)
|
||||
#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2)
|
||||
#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2)
|
||||
#define PORT_CONTROL_STATE_MASK 0x03
|
||||
#define PORT_CONTROL_STATE_DISABLED 0x00
|
||||
#define PORT_CONTROL_STATE_BLOCKING 0x01
|
||||
#define PORT_CONTROL_STATE_LEARNING 0x02
|
||||
#define PORT_CONTROL_STATE_FORWARDING 0x03
|
||||
#define PORT_CONTROL_1 0x05
|
||||
#define PORT_CONTROL_1_MESSAGE_PORT BIT(15)
|
||||
#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0)
|
||||
#define PORT_BASE_VLAN 0x06
|
||||
#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12)
|
||||
|
|
@ -166,7 +167,6 @@
|
|||
#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8)
|
||||
#define PORT_CONTROL_2_MAP_DA BIT(7)
|
||||
#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6)
|
||||
#define PORT_CONTROL_2_FORWARD_UNKNOWN BIT(6)
|
||||
#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5)
|
||||
#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4)
|
||||
#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f
|
||||
|
|
@ -181,6 +181,7 @@
|
|||
#define PORT_ATU_CONTROL 0x0c
|
||||
#define PORT_PRI_OVERRIDE 0x0d
|
||||
#define PORT_ETH_TYPE 0x0f
|
||||
#define PORT_ETH_TYPE_DEFAULT 0x9100
|
||||
#define PORT_IN_DISCARD_LO 0x10
|
||||
#define PORT_IN_DISCARD_HI 0x11
|
||||
#define PORT_IN_FILTERED 0x12
|
||||
|
|
@ -551,7 +552,6 @@ enum mv88e6xxx_cap {
|
|||
|
||||
#define MV88E6XXX_FLAG_SERDES BIT_ULL(MV88E6XXX_CAP_SERDES)
|
||||
|
||||
#define MV88E6XXX_FLAG_G1_ATU_FID BIT_ULL(MV88E6XXX_CAP_G1_ATU_FID)
|
||||
#define MV88E6XXX_FLAG_G1_VTU_FID BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID)
|
||||
|
||||
#define MV88E6XXX_FLAG_GLOBAL2 BIT_ULL(MV88E6XXX_CAP_GLOBAL2)
|
||||
|
|
@ -594,8 +594,7 @@ enum mv88e6xxx_cap {
|
|||
MV88E6XXX_FLAGS_MULTI_CHIP)
|
||||
|
||||
#define MV88E6XXX_FLAGS_FAMILY_6097 \
|
||||
(MV88E6XXX_FLAG_G1_ATU_FID | \
|
||||
MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
(MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
MV88E6XXX_FLAG_GLOBAL2 | \
|
||||
MV88E6XXX_FLAG_G2_INT | \
|
||||
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
|
||||
|
|
@ -608,8 +607,7 @@ enum mv88e6xxx_cap {
|
|||
MV88E6XXX_FLAGS_PVT)
|
||||
|
||||
#define MV88E6XXX_FLAGS_FAMILY_6165 \
|
||||
(MV88E6XXX_FLAG_G1_ATU_FID | \
|
||||
MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
(MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
MV88E6XXX_FLAG_GLOBAL2 | \
|
||||
MV88E6XXX_FLAG_G2_INT | \
|
||||
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
|
||||
|
|
@ -641,7 +639,6 @@ enum mv88e6xxx_cap {
|
|||
|
||||
#define MV88E6XXX_FLAGS_FAMILY_6341 \
|
||||
(MV88E6XXX_FLAG_EEE | \
|
||||
MV88E6XXX_FLAG_G1_ATU_FID | \
|
||||
MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
MV88E6XXX_FLAG_GLOBAL2 | \
|
||||
MV88E6XXX_FLAG_G2_INT | \
|
||||
|
|
@ -654,8 +651,7 @@ enum mv88e6xxx_cap {
|
|||
MV88E6XXX_FLAGS_SERDES)
|
||||
|
||||
#define MV88E6XXX_FLAGS_FAMILY_6351 \
|
||||
(MV88E6XXX_FLAG_G1_ATU_FID | \
|
||||
MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
(MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
MV88E6XXX_FLAG_GLOBAL2 | \
|
||||
MV88E6XXX_FLAG_G2_INT | \
|
||||
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
|
||||
|
|
@ -669,7 +665,6 @@ enum mv88e6xxx_cap {
|
|||
|
||||
#define MV88E6XXX_FLAGS_FAMILY_6352 \
|
||||
(MV88E6XXX_FLAG_EEE | \
|
||||
MV88E6XXX_FLAG_G1_ATU_FID | \
|
||||
MV88E6XXX_FLAG_G1_VTU_FID | \
|
||||
MV88E6XXX_FLAG_GLOBAL2 | \
|
||||
MV88E6XXX_FLAG_G2_INT | \
|
||||
|
|
@ -707,14 +702,18 @@ struct mv88e6xxx_info {
|
|||
unsigned int g1_irqs;
|
||||
enum dsa_tag_protocol tag_protocol;
|
||||
unsigned long long flags;
|
||||
|
||||
/* Mask for FromPort and ToPort value of PortVec used in ATU Move
|
||||
* operation. 0 means that the ATU Move operation is not supported.
|
||||
*/
|
||||
u8 atu_move_port_mask;
|
||||
const struct mv88e6xxx_ops *ops;
|
||||
};
|
||||
|
||||
struct mv88e6xxx_atu_entry {
|
||||
u16 fid;
|
||||
u8 state;
|
||||
bool trunk;
|
||||
u16 portv_trunkid;
|
||||
u16 portvec;
|
||||
u8 mac[ETH_ALEN];
|
||||
};
|
||||
|
||||
|
|
@ -864,14 +863,16 @@ struct mv88e6xxx_ops {
|
|||
|
||||
int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port,
|
||||
enum mv88e6xxx_frame_mode mode);
|
||||
int (*port_set_egress_unknowns)(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on);
|
||||
int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast);
|
||||
int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port,
|
||||
u16 etype);
|
||||
int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port);
|
||||
|
||||
int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port);
|
||||
int (*port_pause_config)(struct mv88e6xxx_chip *chip, int port);
|
||||
int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port);
|
||||
int (*port_disable_pri_override)(struct mv88e6xxx_chip *chip, int port);
|
||||
|
||||
/* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc.
|
||||
* Some chips allow this to be configured on specific ports.
|
||||
|
|
@ -944,6 +945,11 @@ static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip)
|
|||
return chip->info->num_ports;
|
||||
}
|
||||
|
||||
static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip)
|
||||
{
|
||||
return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0);
|
||||
}
|
||||
|
||||
int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
|
||||
int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
|
||||
int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
|
||||
|
|
|
|||
|
|
@ -497,8 +497,8 @@ int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
|
|||
return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
|
||||
}
|
||||
|
||||
int mv88e6085_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on)
|
||||
static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,
|
||||
int port, bool unicast)
|
||||
{
|
||||
int err;
|
||||
u16 reg;
|
||||
|
|
@ -507,7 +507,7 @@ int mv88e6085_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (on)
|
||||
if (unicast)
|
||||
reg |= PORT_CONTROL_FORWARD_UNKNOWN;
|
||||
else
|
||||
reg &= ~PORT_CONTROL_FORWARD_UNKNOWN;
|
||||
|
|
@ -515,8 +515,8 @@ int mv88e6085_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
|||
return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
|
||||
}
|
||||
|
||||
int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on)
|
||||
int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast)
|
||||
{
|
||||
int err;
|
||||
u16 reg;
|
||||
|
|
@ -525,21 +525,45 @@ int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (on)
|
||||
reg |= PORT_CONTROL_EGRESS_ALL_UNKNOWN_DA;
|
||||
reg &= ~PORT_CONTROL_EGRESS_FLOODS_MASK;
|
||||
|
||||
if (unicast && multicast)
|
||||
reg |= PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA;
|
||||
else if (unicast)
|
||||
reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA;
|
||||
else if (multicast)
|
||||
reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA;
|
||||
else
|
||||
reg &= ~PORT_CONTROL_EGRESS_ALL_UNKNOWN_DA;
|
||||
reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA;
|
||||
|
||||
return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
|
||||
}
|
||||
|
||||
/* Offset 0x05: Port Control 1 */
|
||||
|
||||
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
|
||||
bool message_port)
|
||||
{
|
||||
u16 val;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (message_port)
|
||||
val |= PORT_CONTROL_1_MESSAGE_PORT;
|
||||
else
|
||||
val &= ~PORT_CONTROL_1_MESSAGE_PORT;
|
||||
|
||||
return mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, val);
|
||||
}
|
||||
|
||||
/* Offset 0x06: Port Based VLAN Map */
|
||||
|
||||
int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
|
||||
{
|
||||
const u16 mask = GENMASK(mv88e6xxx_num_ports(chip) - 1, 0);
|
||||
const u16 mask = mv88e6xxx_port_mask(chip);
|
||||
u16 reg;
|
||||
int err;
|
||||
|
||||
|
|
@ -672,8 +696,8 @@ static const char * const mv88e6xxx_port_8021q_mode_names[] = {
|
|||
[PORT_CONTROL_2_8021Q_SECURE] = "Secure",
|
||||
};
|
||||
|
||||
int mv88e6095_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on)
|
||||
static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,
|
||||
int port, bool multicast)
|
||||
{
|
||||
int err;
|
||||
u16 reg;
|
||||
|
|
@ -682,14 +706,26 @@ int mv88e6095_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (on)
|
||||
reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
|
||||
if (multicast)
|
||||
reg |= PORT_CONTROL_2_DEFAULT_FORWARD;
|
||||
else
|
||||
reg &= ~PORT_CONTROL_2_FORWARD_UNKNOWN;
|
||||
reg &= ~PORT_CONTROL_2_DEFAULT_FORWARD;
|
||||
|
||||
return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg);
|
||||
}
|
||||
|
||||
int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mv88e6185_port_set_forward_unknown(chip, port, unicast);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mv88e6185_port_set_default_forward(chip, port, multicast);
|
||||
}
|
||||
|
||||
int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
|
||||
int upstream_port)
|
||||
{
|
||||
|
|
@ -769,6 +805,20 @@ int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
|
|||
return mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL, 0x0001);
|
||||
}
|
||||
|
||||
/* Offset 0x0C: Port ATU Control */
|
||||
|
||||
int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
return mv88e6xxx_port_write(chip, port, PORT_ATU_CONTROL, 0);
|
||||
}
|
||||
|
||||
/* Offset 0x0D: (Priority) Override Register */
|
||||
|
||||
int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
|
||||
{
|
||||
return mv88e6xxx_port_write(chip, port, PORT_PRI_OVERRIDE, 0);
|
||||
}
|
||||
|
||||
/* Offset 0x0f: Port Ether type */
|
||||
|
||||
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
|
||||
|
|
|
|||
|
|
@ -56,14 +56,14 @@ int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
|
|||
enum mv88e6xxx_frame_mode mode);
|
||||
int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
|
||||
enum mv88e6xxx_frame_mode mode);
|
||||
int mv88e6085_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on);
|
||||
int mv88e6095_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on);
|
||||
int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
|
||||
bool on);
|
||||
int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast);
|
||||
int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast);
|
||||
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
|
||||
u16 etype);
|
||||
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
|
||||
bool message_port);
|
||||
int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
|
||||
|
|
@ -75,4 +75,8 @@ int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
|
|||
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
|
||||
int upstream_port);
|
||||
|
||||
int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port);
|
||||
|
||||
#endif /* _MV88E6XXX_PORT_H */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
|
||||
|
|
@ -125,6 +126,7 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
dstats->tx_bytes += skb->len;
|
||||
u64_stats_update_end(&dstats->syncp);
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -304,8 +306,21 @@ static void dummy_get_drvinfo(struct net_device *dev,
|
|||
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
||||
}
|
||||
|
||||
static int dummy_get_ts_info(struct net_device *dev,
|
||||
struct ethtool_ts_info *ts_info)
|
||||
{
|
||||
ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
|
||||
ts_info->phc_index = -1;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static const struct ethtool_ops dummy_ethtool_ops = {
|
||||
.get_drvinfo = dummy_get_drvinfo,
|
||||
.get_ts_info = dummy_get_ts_info,
|
||||
};
|
||||
|
||||
static void dummy_free_netdev(struct net_device *dev)
|
||||
|
|
|
|||
|
|
@ -180,5 +180,6 @@ source "drivers/net/ethernet/via/Kconfig"
|
|||
source "drivers/net/ethernet/wiznet/Kconfig"
|
||||
source "drivers/net/ethernet/xilinx/Kconfig"
|
||||
source "drivers/net/ethernet/xircom/Kconfig"
|
||||
source "drivers/net/ethernet/synopsys/Kconfig"
|
||||
|
||||
endif # ETHERNET
|
||||
|
|
|
|||
|
|
@ -91,3 +91,4 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/
|
|||
obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
|
||||
obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
|
||||
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
|
||||
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
|
||||
|
|
|
|||
|
|
@ -1854,7 +1854,8 @@ static int xgbe_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
|
|||
if (tc_to_netdev->type != TC_SETUP_MQPRIO)
|
||||
return -EINVAL;
|
||||
|
||||
tc = tc_to_netdev->tc;
|
||||
tc_to_netdev->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
tc = tc_to_netdev->mqprio->num_tc;
|
||||
|
||||
if (tc > pdata->hw_feat.tc_cnt)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
source "drivers/net/ethernet/apm/xgene/Kconfig"
|
||||
source "drivers/net/ethernet/apm/xgene-v2/Kconfig"
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_NET_XGENE) += xgene/
|
||||
obj-$(CONFIG_NET_XGENE_V2) += xgene-v2/
|
||||
|
|
|
|||
11
drivers/net/ethernet/apm/xgene-v2/Kconfig
Normal file
11
drivers/net/ethernet/apm/xgene-v2/Kconfig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
config NET_XGENE_V2
|
||||
tristate "APM X-Gene SoC Ethernet-v2 Driver"
|
||||
depends on HAS_DMA
|
||||
depends on ARCH_XGENE || COMPILE_TEST
|
||||
help
|
||||
This is the Ethernet driver for the on-chip ethernet interface
|
||||
which uses a linked list of DMA descriptor architecture (v2) for
|
||||
APM X-Gene SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here. This module will
|
||||
be called xgene-enet-v2.
|
||||
6
drivers/net/ethernet/apm/xgene-v2/Makefile
Normal file
6
drivers/net/ethernet/apm/xgene-v2/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Makefile for APM X-Gene Ethernet v2 driver
|
||||
#
|
||||
|
||||
xgene-enet-v2-objs := main.o mac.o enet.o ring.o
|
||||
obj-$(CONFIG_NET_XGENE_V2) += xgene-enet-v2.o
|
||||
71
drivers/net/ethernet/apm/xgene-v2/enet.c
Normal file
71
drivers/net/ethernet/apm/xgene-v2/enet.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void xge_wr_csr(struct xge_pdata *pdata, u32 offset, u32 val)
|
||||
{
|
||||
void __iomem *addr = pdata->resources.base_addr + offset;
|
||||
|
||||
iowrite32(val, addr);
|
||||
}
|
||||
|
||||
u32 xge_rd_csr(struct xge_pdata *pdata, u32 offset)
|
||||
{
|
||||
void __iomem *addr = pdata->resources.base_addr + offset;
|
||||
|
||||
return ioread32(addr);
|
||||
}
|
||||
|
||||
int xge_port_reset(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
|
||||
xge_wr_csr(pdata, ENET_SRST, 0x3);
|
||||
xge_wr_csr(pdata, ENET_SRST, 0x2);
|
||||
xge_wr_csr(pdata, ENET_SRST, 0x0);
|
||||
|
||||
xge_wr_csr(pdata, ENET_SHIM, DEVM_ARAUX_COH | DEVM_AWAUX_COH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xge_traffic_resume(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
|
||||
xge_wr_csr(pdata, CFG_FORCE_LINK_STATUS_EN, 1);
|
||||
xge_wr_csr(pdata, FORCE_LINK_STATUS, 1);
|
||||
|
||||
xge_wr_csr(pdata, CFG_LINK_AGGR_RESUME, 1);
|
||||
xge_wr_csr(pdata, RX_DV_GATE_REG, 1);
|
||||
}
|
||||
|
||||
int xge_port_init(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
|
||||
pdata->phy_speed = SPEED_1000;
|
||||
xge_mac_init(pdata);
|
||||
xge_traffic_resume(ndev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
43
drivers/net/ethernet/apm/xgene-v2/enet.h
Normal file
43
drivers/net/ethernet/apm/xgene-v2/enet.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __XGENE_ENET_V2_ENET_H__
|
||||
#define __XGENE_ENET_V2_ENET_H__
|
||||
|
||||
#define ENET_CLKEN 0xc008
|
||||
#define ENET_SRST 0xc000
|
||||
#define ENET_SHIM 0xc010
|
||||
#define CFG_MEM_RAM_SHUTDOWN 0xd070
|
||||
#define BLOCK_MEM_RDY 0xd074
|
||||
|
||||
#define DEVM_ARAUX_COH BIT(19)
|
||||
#define DEVM_AWAUX_COH BIT(3)
|
||||
|
||||
#define CFG_FORCE_LINK_STATUS_EN 0x229c
|
||||
#define FORCE_LINK_STATUS 0x22a0
|
||||
#define CFG_LINK_AGGR_RESUME 0x27c8
|
||||
#define RX_DV_GATE_REG 0x2dfc
|
||||
|
||||
void xge_wr_csr(struct xge_pdata *pdata, u32 offset, u32 val);
|
||||
u32 xge_rd_csr(struct xge_pdata *pdata, u32 offset);
|
||||
int xge_port_reset(struct net_device *ndev);
|
||||
|
||||
#endif /* __XGENE_ENET_V2_ENET__H__ */
|
||||
116
drivers/net/ethernet/apm/xgene-v2/mac.c
Normal file
116
drivers/net/ethernet/apm/xgene-v2/mac.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void xge_mac_reset(struct xge_pdata *pdata)
|
||||
{
|
||||
xge_wr_csr(pdata, MAC_CONFIG_1, SOFT_RESET);
|
||||
xge_wr_csr(pdata, MAC_CONFIG_1, 0);
|
||||
}
|
||||
|
||||
static void xge_mac_set_speed(struct xge_pdata *pdata)
|
||||
{
|
||||
u32 icm0, icm2, ecm0, mc2;
|
||||
u32 intf_ctrl, rgmii;
|
||||
|
||||
icm0 = xge_rd_csr(pdata, ICM_CONFIG0_REG_0);
|
||||
icm2 = xge_rd_csr(pdata, ICM_CONFIG2_REG_0);
|
||||
ecm0 = xge_rd_csr(pdata, ECM_CONFIG0_REG_0);
|
||||
rgmii = xge_rd_csr(pdata, RGMII_REG_0);
|
||||
mc2 = xge_rd_csr(pdata, MAC_CONFIG_2);
|
||||
intf_ctrl = xge_rd_csr(pdata, INTERFACE_CONTROL);
|
||||
icm2 |= CFG_WAITASYNCRD_EN;
|
||||
|
||||
switch (pdata->phy_speed) {
|
||||
case SPEED_10:
|
||||
SET_REG_BITS(&mc2, INTF_MODE, 1);
|
||||
SET_REG_BITS(&intf_ctrl, HD_MODE, 0);
|
||||
SET_REG_BITS(&icm0, CFG_MACMODE, 0);
|
||||
SET_REG_BITS(&icm2, CFG_WAITASYNCRD, 500);
|
||||
SET_REG_BIT(&rgmii, CFG_SPEED_125, 0);
|
||||
break;
|
||||
case SPEED_100:
|
||||
SET_REG_BITS(&mc2, INTF_MODE, 1);
|
||||
SET_REG_BITS(&intf_ctrl, HD_MODE, 1);
|
||||
SET_REG_BITS(&icm0, CFG_MACMODE, 1);
|
||||
SET_REG_BITS(&icm2, CFG_WAITASYNCRD, 80);
|
||||
SET_REG_BIT(&rgmii, CFG_SPEED_125, 0);
|
||||
break;
|
||||
default:
|
||||
SET_REG_BITS(&mc2, INTF_MODE, 2);
|
||||
SET_REG_BITS(&intf_ctrl, HD_MODE, 2);
|
||||
SET_REG_BITS(&icm0, CFG_MACMODE, 2);
|
||||
SET_REG_BITS(&icm2, CFG_WAITASYNCRD, 16);
|
||||
SET_REG_BIT(&rgmii, CFG_SPEED_125, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
mc2 |= FULL_DUPLEX | CRC_EN | PAD_CRC;
|
||||
SET_REG_BITS(&ecm0, CFG_WFIFOFULLTHR, 0x32);
|
||||
|
||||
xge_wr_csr(pdata, MAC_CONFIG_2, mc2);
|
||||
xge_wr_csr(pdata, INTERFACE_CONTROL, intf_ctrl);
|
||||
xge_wr_csr(pdata, RGMII_REG_0, rgmii);
|
||||
xge_wr_csr(pdata, ICM_CONFIG0_REG_0, icm0);
|
||||
xge_wr_csr(pdata, ICM_CONFIG2_REG_0, icm2);
|
||||
xge_wr_csr(pdata, ECM_CONFIG0_REG_0, ecm0);
|
||||
}
|
||||
|
||||
void xge_mac_set_station_addr(struct xge_pdata *pdata)
|
||||
{
|
||||
u8 *dev_addr = pdata->ndev->dev_addr;
|
||||
u32 addr0, addr1;
|
||||
|
||||
addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
|
||||
(dev_addr[1] << 8) | dev_addr[0];
|
||||
addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16);
|
||||
|
||||
xge_wr_csr(pdata, STATION_ADDR0, addr0);
|
||||
xge_wr_csr(pdata, STATION_ADDR1, addr1);
|
||||
}
|
||||
|
||||
void xge_mac_init(struct xge_pdata *pdata)
|
||||
{
|
||||
xge_mac_reset(pdata);
|
||||
xge_mac_set_speed(pdata);
|
||||
xge_mac_set_station_addr(pdata);
|
||||
}
|
||||
|
||||
void xge_mac_enable(struct xge_pdata *pdata)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
data = xge_rd_csr(pdata, MAC_CONFIG_1);
|
||||
data |= TX_EN | RX_EN;
|
||||
xge_wr_csr(pdata, MAC_CONFIG_1, data);
|
||||
|
||||
data = xge_rd_csr(pdata, MAC_CONFIG_1);
|
||||
}
|
||||
|
||||
void xge_mac_disable(struct xge_pdata *pdata)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
data = xge_rd_csr(pdata, MAC_CONFIG_1);
|
||||
data &= ~(TX_EN | RX_EN);
|
||||
xge_wr_csr(pdata, MAC_CONFIG_1, data);
|
||||
}
|
||||
110
drivers/net/ethernet/apm/xgene-v2/mac.h
Normal file
110
drivers/net/ethernet/apm/xgene-v2/mac.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __XGENE_ENET_V2_MAC_H__
|
||||
#define __XGENE_ENET_V2_MAC_H__
|
||||
|
||||
/* Register offsets */
|
||||
#define MAC_CONFIG_1 0xa000
|
||||
#define MAC_CONFIG_2 0xa004
|
||||
#define MII_MGMT_CONFIG 0xa020
|
||||
#define MII_MGMT_COMMAND 0xa024
|
||||
#define MII_MGMT_ADDRESS 0xa028
|
||||
#define MII_MGMT_CONTROL 0xa02c
|
||||
#define MII_MGMT_STATUS 0xa030
|
||||
#define MII_MGMT_INDICATORS 0xa034
|
||||
#define INTERFACE_CONTROL 0xa038
|
||||
#define STATION_ADDR0 0xa040
|
||||
#define STATION_ADDR1 0xa044
|
||||
#define RBYT 0xa09c
|
||||
#define RPKT 0xa0a0
|
||||
#define RFCS 0xa0a4
|
||||
|
||||
#define RGMII_REG_0 0x27e0
|
||||
#define ICM_CONFIG0_REG_0 0x2c00
|
||||
#define ICM_CONFIG2_REG_0 0x2c08
|
||||
#define ECM_CONFIG0_REG_0 0x2d00
|
||||
|
||||
/* Register fields */
|
||||
#define SOFT_RESET BIT(31)
|
||||
#define TX_EN BIT(0)
|
||||
#define RX_EN BIT(2)
|
||||
#define PAD_CRC BIT(2)
|
||||
#define CRC_EN BIT(1)
|
||||
#define FULL_DUPLEX BIT(0)
|
||||
|
||||
#define INTF_MODE_POS 8
|
||||
#define INTF_MODE_LEN 2
|
||||
#define HD_MODE_POS 25
|
||||
#define HD_MODE_LEN 2
|
||||
#define CFG_MACMODE_POS 18
|
||||
#define CFG_MACMODE_LEN 2
|
||||
#define CFG_WAITASYNCRD_POS 0
|
||||
#define CFG_WAITASYNCRD_LEN 16
|
||||
#define CFG_SPEED_125_POS 24
|
||||
#define CFG_WFIFOFULLTHR_POS 0
|
||||
#define CFG_WFIFOFULLTHR_LEN 7
|
||||
#define MGMT_CLOCK_SEL_POS 0
|
||||
#define MGMT_CLOCK_SEL_LEN 3
|
||||
#define PHY_ADDR_POS 8
|
||||
#define PHY_ADDR_LEN 5
|
||||
#define REG_ADDR_POS 0
|
||||
#define REG_ADDR_LEN 5
|
||||
#define MII_MGMT_BUSY BIT(0)
|
||||
#define MII_READ_CYCLE BIT(0)
|
||||
#define CFG_WAITASYNCRD_EN BIT(16)
|
||||
|
||||
static inline void xgene_set_reg_bits(u32 *var, int pos, int len, u32 val)
|
||||
{
|
||||
u32 mask = GENMASK(pos + len, pos);
|
||||
|
||||
*var &= ~mask;
|
||||
*var |= ((val << pos) & mask);
|
||||
}
|
||||
|
||||
static inline u32 xgene_get_reg_bits(u32 var, int pos, int len)
|
||||
{
|
||||
u32 mask = GENMASK(pos + len, pos);
|
||||
|
||||
return (var & mask) >> pos;
|
||||
}
|
||||
|
||||
#define SET_REG_BITS(var, field, val) \
|
||||
xgene_set_reg_bits(var, field ## _POS, field ## _LEN, val)
|
||||
|
||||
#define SET_REG_BIT(var, field, val) \
|
||||
xgene_set_reg_bits(var, field ## _POS, 1, val)
|
||||
|
||||
#define GET_REG_BITS(var, field) \
|
||||
xgene_get_reg_bits(var, field ## _POS, field ## _LEN)
|
||||
|
||||
#define GET_REG_BIT(var, field) ((var) & (field))
|
||||
|
||||
struct xge_pdata;
|
||||
|
||||
void xge_mac_reset(struct xge_pdata *pdata);
|
||||
void xge_mac_enable(struct xge_pdata *pdata);
|
||||
void xge_mac_disable(struct xge_pdata *pdata);
|
||||
void xge_mac_init(struct xge_pdata *pdata);
|
||||
int xge_port_init(struct net_device *ndev);
|
||||
void xge_mac_set_station_addr(struct xge_pdata *pdata);
|
||||
|
||||
#endif /* __XGENE_ENET_V2_MAC_H__ */
|
||||
756
drivers/net/ethernet/apm/xgene-v2/main.c
Normal file
756
drivers/net/ethernet/apm/xgene-v2/main.c
Normal file
|
|
@ -0,0 +1,756 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
static const struct acpi_device_id xge_acpi_match[];
|
||||
|
||||
static int xge_get_resources(struct xge_pdata *pdata)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct net_device *ndev;
|
||||
int phy_mode, ret = 0;
|
||||
struct resource *res;
|
||||
struct device *dev;
|
||||
|
||||
pdev = pdata->pdev;
|
||||
dev = &pdev->dev;
|
||||
ndev = pdata->ndev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "Resource enet_csr not defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata->resources.base_addr = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
if (!pdata->resources.base_addr) {
|
||||
dev_err(dev, "Unable to retrieve ENET Port CSR region\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!device_get_mac_address(dev, ndev->dev_addr, ETH_ALEN))
|
||||
eth_hw_addr_random(ndev);
|
||||
|
||||
memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
|
||||
|
||||
phy_mode = device_get_phy_mode(dev);
|
||||
if (phy_mode < 0) {
|
||||
dev_err(dev, "Unable to get phy-connection-type\n");
|
||||
return phy_mode;
|
||||
}
|
||||
pdata->resources.phy_mode = phy_mode;
|
||||
|
||||
if (pdata->resources.phy_mode != PHY_INTERFACE_MODE_RGMII) {
|
||||
dev_err(dev, "Incorrect phy-connection-type specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(dev, "Unable to get ENET IRQ\n");
|
||||
ret = ret ? : -ENXIO;
|
||||
return ret;
|
||||
}
|
||||
pdata->resources.irq = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xge_refill_buffers(struct net_device *ndev, u32 nbuf)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct xge_desc_ring *ring = pdata->rx_ring;
|
||||
const u8 slots = XGENE_ENET_NUM_DESC - 1;
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct xge_raw_desc *raw_desc;
|
||||
u64 addr_lo, addr_hi;
|
||||
u8 tail = ring->tail;
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma_addr;
|
||||
u16 len;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nbuf; i++) {
|
||||
raw_desc = &ring->raw_desc[tail];
|
||||
|
||||
len = XGENE_ENET_STD_MTU;
|
||||
skb = netdev_alloc_skb(ndev, len);
|
||||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
|
||||
dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, dma_addr)) {
|
||||
netdev_err(ndev, "DMA mapping error\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ring->pkt_info[tail].skb = skb;
|
||||
ring->pkt_info[tail].dma_addr = dma_addr;
|
||||
|
||||
addr_hi = GET_BITS(NEXT_DESC_ADDRH, le64_to_cpu(raw_desc->m1));
|
||||
addr_lo = GET_BITS(NEXT_DESC_ADDRL, le64_to_cpu(raw_desc->m1));
|
||||
raw_desc->m1 = cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL, addr_lo) |
|
||||
SET_BITS(NEXT_DESC_ADDRH, addr_hi) |
|
||||
SET_BITS(PKT_ADDRH,
|
||||
upper_32_bits(dma_addr)));
|
||||
|
||||
dma_wmb();
|
||||
raw_desc->m0 = cpu_to_le64(SET_BITS(PKT_ADDRL, dma_addr) |
|
||||
SET_BITS(E, 1));
|
||||
tail = (tail + 1) & slots;
|
||||
}
|
||||
|
||||
ring->tail = tail;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xge_init_hw(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
int ret;
|
||||
|
||||
ret = xge_port_reset(ndev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xge_port_init(ndev);
|
||||
pdata->nbufs = NUM_BUFS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t xge_irq(const int irq, void *data)
|
||||
{
|
||||
struct xge_pdata *pdata = data;
|
||||
|
||||
if (napi_schedule_prep(&pdata->napi)) {
|
||||
xge_intr_disable(pdata);
|
||||
__napi_schedule(&pdata->napi);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int xge_request_irq(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
int ret;
|
||||
|
||||
snprintf(pdata->irq_name, IRQ_ID_SIZE, "%s", ndev->name);
|
||||
|
||||
ret = devm_request_irq(dev, pdata->resources.irq, xge_irq,
|
||||
0, pdata->irq_name, pdata);
|
||||
if (ret)
|
||||
netdev_err(ndev, "Failed to request irq %s\n", pdata->irq_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xge_free_irq(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
|
||||
devm_free_irq(dev, pdata->resources.irq, pdata);
|
||||
}
|
||||
|
||||
static bool is_tx_slot_available(struct xge_raw_desc *raw_desc)
|
||||
{
|
||||
if (GET_BITS(E, le64_to_cpu(raw_desc->m0)) &&
|
||||
(GET_BITS(PKT_SIZE, le64_to_cpu(raw_desc->m0)) == SLOT_EMPTY))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static netdev_tx_t xge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct xge_desc_ring *tx_ring;
|
||||
struct xge_raw_desc *raw_desc;
|
||||
static dma_addr_t dma_addr;
|
||||
u64 addr_lo, addr_hi;
|
||||
void *pkt_buf;
|
||||
u8 tail;
|
||||
u16 len;
|
||||
|
||||
tx_ring = pdata->tx_ring;
|
||||
tail = tx_ring->tail;
|
||||
len = skb_headlen(skb);
|
||||
raw_desc = &tx_ring->raw_desc[tail];
|
||||
|
||||
if (!is_tx_slot_available(raw_desc)) {
|
||||
netif_stop_queue(ndev);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
/* Packet buffers should be 64B aligned */
|
||||
pkt_buf = dma_zalloc_coherent(dev, XGENE_ENET_STD_MTU, &dma_addr,
|
||||
GFP_ATOMIC);
|
||||
if (unlikely(!pkt_buf)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
memcpy(pkt_buf, skb->data, len);
|
||||
|
||||
addr_hi = GET_BITS(NEXT_DESC_ADDRH, le64_to_cpu(raw_desc->m1));
|
||||
addr_lo = GET_BITS(NEXT_DESC_ADDRL, le64_to_cpu(raw_desc->m1));
|
||||
raw_desc->m1 = cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL, addr_lo) |
|
||||
SET_BITS(NEXT_DESC_ADDRH, addr_hi) |
|
||||
SET_BITS(PKT_ADDRH,
|
||||
upper_32_bits(dma_addr)));
|
||||
|
||||
tx_ring->pkt_info[tail].skb = skb;
|
||||
tx_ring->pkt_info[tail].dma_addr = dma_addr;
|
||||
tx_ring->pkt_info[tail].pkt_buf = pkt_buf;
|
||||
|
||||
dma_wmb();
|
||||
|
||||
raw_desc->m0 = cpu_to_le64(SET_BITS(PKT_ADDRL, dma_addr) |
|
||||
SET_BITS(PKT_SIZE, len) |
|
||||
SET_BITS(E, 0));
|
||||
skb_tx_timestamp(skb);
|
||||
xge_wr_csr(pdata, DMATXCTRL, 1);
|
||||
|
||||
tx_ring->tail = (tail + 1) & (XGENE_ENET_NUM_DESC - 1);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static bool is_tx_hw_done(struct xge_raw_desc *raw_desc)
|
||||
{
|
||||
if (GET_BITS(E, le64_to_cpu(raw_desc->m0)) &&
|
||||
!GET_BITS(PKT_SIZE, le64_to_cpu(raw_desc->m0)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void xge_txc_poll(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct xge_desc_ring *tx_ring;
|
||||
struct xge_raw_desc *raw_desc;
|
||||
dma_addr_t dma_addr;
|
||||
struct sk_buff *skb;
|
||||
void *pkt_buf;
|
||||
u32 data;
|
||||
u8 head;
|
||||
|
||||
tx_ring = pdata->tx_ring;
|
||||
head = tx_ring->head;
|
||||
|
||||
data = xge_rd_csr(pdata, DMATXSTATUS);
|
||||
if (!GET_BITS(TXPKTCOUNT, data))
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
raw_desc = &tx_ring->raw_desc[head];
|
||||
|
||||
if (!is_tx_hw_done(raw_desc))
|
||||
break;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
skb = tx_ring->pkt_info[head].skb;
|
||||
dma_addr = tx_ring->pkt_info[head].dma_addr;
|
||||
pkt_buf = tx_ring->pkt_info[head].pkt_buf;
|
||||
pdata->stats.tx_packets++;
|
||||
pdata->stats.tx_bytes += skb->len;
|
||||
dma_free_coherent(dev, XGENE_ENET_STD_MTU, pkt_buf, dma_addr);
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
/* clear pktstart address and pktsize */
|
||||
raw_desc->m0 = cpu_to_le64(SET_BITS(E, 1) |
|
||||
SET_BITS(PKT_SIZE, SLOT_EMPTY));
|
||||
xge_wr_csr(pdata, DMATXSTATUS, 1);
|
||||
|
||||
head = (head + 1) & (XGENE_ENET_NUM_DESC - 1);
|
||||
}
|
||||
|
||||
if (netif_queue_stopped(ndev))
|
||||
netif_wake_queue(ndev);
|
||||
|
||||
tx_ring->head = head;
|
||||
}
|
||||
|
||||
static int xge_rx_poll(struct net_device *ndev, unsigned int budget)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct xge_desc_ring *rx_ring;
|
||||
struct xge_raw_desc *raw_desc;
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma_addr;
|
||||
int processed = 0;
|
||||
u8 head, rx_error;
|
||||
int i, ret;
|
||||
u32 data;
|
||||
u16 len;
|
||||
|
||||
rx_ring = pdata->rx_ring;
|
||||
head = rx_ring->head;
|
||||
|
||||
data = xge_rd_csr(pdata, DMARXSTATUS);
|
||||
if (!GET_BITS(RXPKTCOUNT, data))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < budget; i++) {
|
||||
raw_desc = &rx_ring->raw_desc[head];
|
||||
|
||||
if (GET_BITS(E, le64_to_cpu(raw_desc->m0)))
|
||||
break;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
skb = rx_ring->pkt_info[head].skb;
|
||||
rx_ring->pkt_info[head].skb = NULL;
|
||||
dma_addr = rx_ring->pkt_info[head].dma_addr;
|
||||
len = GET_BITS(PKT_SIZE, le64_to_cpu(raw_desc->m0));
|
||||
dma_unmap_single(dev, dma_addr, XGENE_ENET_STD_MTU,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
rx_error = GET_BITS(D, le64_to_cpu(raw_desc->m2));
|
||||
if (unlikely(rx_error)) {
|
||||
pdata->stats.rx_errors++;
|
||||
dev_kfree_skb_any(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
skb_put(skb, len);
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
|
||||
pdata->stats.rx_packets++;
|
||||
pdata->stats.rx_bytes += len;
|
||||
napi_gro_receive(&pdata->napi, skb);
|
||||
out:
|
||||
ret = xge_refill_buffers(ndev, 1);
|
||||
xge_wr_csr(pdata, DMARXSTATUS, 1);
|
||||
xge_wr_csr(pdata, DMARXCTRL, 1);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
head = (head + 1) & (XGENE_ENET_NUM_DESC - 1);
|
||||
processed++;
|
||||
}
|
||||
|
||||
rx_ring->head = head;
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
static void xge_delete_desc_ring(struct net_device *ndev,
|
||||
struct xge_desc_ring *ring)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
u16 size;
|
||||
|
||||
if (!ring)
|
||||
return;
|
||||
|
||||
size = XGENE_ENET_DESC_SIZE * XGENE_ENET_NUM_DESC;
|
||||
if (ring->desc_addr)
|
||||
dma_free_coherent(dev, size, ring->desc_addr, ring->dma_addr);
|
||||
|
||||
kfree(ring->pkt_info);
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
static void xge_free_buffers(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct xge_desc_ring *ring = pdata->rx_ring;
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XGENE_ENET_NUM_DESC; i++) {
|
||||
skb = ring->pkt_info[i].skb;
|
||||
dma_addr = ring->pkt_info[i].dma_addr;
|
||||
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
dma_unmap_single(dev, dma_addr, XGENE_ENET_STD_MTU,
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void xge_delete_desc_rings(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
|
||||
xge_txc_poll(ndev);
|
||||
xge_delete_desc_ring(ndev, pdata->tx_ring);
|
||||
|
||||
xge_rx_poll(ndev, 64);
|
||||
xge_free_buffers(ndev);
|
||||
xge_delete_desc_ring(ndev, pdata->rx_ring);
|
||||
}
|
||||
|
||||
static struct xge_desc_ring *xge_create_desc_ring(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct xge_desc_ring *ring;
|
||||
u16 size;
|
||||
|
||||
ring = kzalloc(sizeof(struct xge_desc_ring), GFP_KERNEL);
|
||||
if (!ring)
|
||||
return NULL;
|
||||
|
||||
ring->ndev = ndev;
|
||||
|
||||
size = XGENE_ENET_DESC_SIZE * XGENE_ENET_NUM_DESC;
|
||||
ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma_addr,
|
||||
GFP_KERNEL);
|
||||
if (!ring->desc_addr)
|
||||
goto err;
|
||||
|
||||
ring->pkt_info = kcalloc(XGENE_ENET_NUM_DESC, sizeof(struct pkt_info),
|
||||
GFP_KERNEL);
|
||||
if (!ring->pkt_info)
|
||||
goto err;
|
||||
|
||||
xge_setup_desc(ring);
|
||||
|
||||
return ring;
|
||||
|
||||
err:
|
||||
xge_delete_desc_ring(ndev, ring);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int xge_create_desc_rings(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct xge_desc_ring *ring;
|
||||
int ret;
|
||||
|
||||
/* create tx ring */
|
||||
ring = xge_create_desc_ring(ndev);
|
||||
if (!ring)
|
||||
goto err;
|
||||
|
||||
pdata->tx_ring = ring;
|
||||
xge_update_tx_desc_addr(pdata);
|
||||
|
||||
/* create rx ring */
|
||||
ring = xge_create_desc_ring(ndev);
|
||||
if (!ring)
|
||||
goto err;
|
||||
|
||||
pdata->rx_ring = ring;
|
||||
xge_update_rx_desc_addr(pdata);
|
||||
|
||||
ret = xge_refill_buffers(ndev, XGENE_ENET_NUM_DESC);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
xge_delete_desc_rings(ndev);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int xge_open(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
int ret;
|
||||
|
||||
ret = xge_create_desc_rings(ndev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
napi_enable(&pdata->napi);
|
||||
ret = xge_request_irq(ndev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xge_intr_enable(pdata);
|
||||
xge_wr_csr(pdata, DMARXCTRL, 1);
|
||||
xge_mac_enable(pdata);
|
||||
netif_start_queue(ndev);
|
||||
netif_carrier_on(ndev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xge_close(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
|
||||
netif_carrier_off(ndev);
|
||||
netif_stop_queue(ndev);
|
||||
xge_mac_disable(pdata);
|
||||
|
||||
xge_intr_disable(pdata);
|
||||
xge_free_irq(ndev);
|
||||
napi_disable(&pdata->napi);
|
||||
xge_delete_desc_rings(ndev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xge_napi(struct napi_struct *napi, const int budget)
|
||||
{
|
||||
struct net_device *ndev = napi->dev;
|
||||
struct xge_pdata *pdata;
|
||||
int processed;
|
||||
|
||||
pdata = netdev_priv(ndev);
|
||||
|
||||
xge_txc_poll(ndev);
|
||||
processed = xge_rx_poll(ndev, budget);
|
||||
|
||||
if (processed < budget) {
|
||||
napi_complete_done(napi, processed);
|
||||
xge_intr_enable(pdata);
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
static int xge_set_mac_addr(struct net_device *ndev, void *addr)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
int ret;
|
||||
|
||||
ret = eth_mac_addr(ndev, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xge_mac_set_station_addr(pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_tx_pending(struct xge_raw_desc *raw_desc)
|
||||
{
|
||||
if (!GET_BITS(E, le64_to_cpu(raw_desc->m0)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void xge_free_pending_skb(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct device *dev = &pdata->pdev->dev;
|
||||
struct xge_desc_ring *tx_ring;
|
||||
struct xge_raw_desc *raw_desc;
|
||||
dma_addr_t dma_addr;
|
||||
struct sk_buff *skb;
|
||||
void *pkt_buf;
|
||||
int i;
|
||||
|
||||
tx_ring = pdata->tx_ring;
|
||||
|
||||
for (i = 0; i < XGENE_ENET_NUM_DESC; i++) {
|
||||
raw_desc = &tx_ring->raw_desc[i];
|
||||
|
||||
if (!is_tx_pending(raw_desc))
|
||||
continue;
|
||||
|
||||
skb = tx_ring->pkt_info[i].skb;
|
||||
dma_addr = tx_ring->pkt_info[i].dma_addr;
|
||||
pkt_buf = tx_ring->pkt_info[i].pkt_buf;
|
||||
dma_free_coherent(dev, XGENE_ENET_STD_MTU, pkt_buf, dma_addr);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void xge_timeout(struct net_device *ndev)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (netif_running(ndev)) {
|
||||
netif_carrier_off(ndev);
|
||||
netif_stop_queue(ndev);
|
||||
xge_intr_disable(pdata);
|
||||
napi_disable(&pdata->napi);
|
||||
|
||||
xge_wr_csr(pdata, DMATXCTRL, 0);
|
||||
xge_txc_poll(ndev);
|
||||
xge_free_pending_skb(ndev);
|
||||
xge_wr_csr(pdata, DMATXSTATUS, ~0U);
|
||||
|
||||
xge_setup_desc(pdata->tx_ring);
|
||||
xge_update_tx_desc_addr(pdata);
|
||||
xge_mac_init(pdata);
|
||||
|
||||
napi_enable(&pdata->napi);
|
||||
xge_intr_enable(pdata);
|
||||
xge_mac_enable(pdata);
|
||||
netif_start_queue(ndev);
|
||||
netif_carrier_on(ndev);
|
||||
}
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void xge_get_stats64(struct net_device *ndev,
|
||||
struct rtnl_link_stats64 *storage)
|
||||
{
|
||||
struct xge_pdata *pdata = netdev_priv(ndev);
|
||||
struct xge_stats *stats = &pdata->stats;
|
||||
|
||||
storage->tx_packets += stats->tx_packets;
|
||||
storage->tx_bytes += stats->tx_bytes;
|
||||
|
||||
storage->rx_packets += stats->rx_packets;
|
||||
storage->rx_bytes += stats->rx_bytes;
|
||||
storage->rx_errors += stats->rx_errors;
|
||||
}
|
||||
|
||||
static const struct net_device_ops xgene_ndev_ops = {
|
||||
.ndo_open = xge_open,
|
||||
.ndo_stop = xge_close,
|
||||
.ndo_start_xmit = xge_start_xmit,
|
||||
.ndo_set_mac_address = xge_set_mac_addr,
|
||||
.ndo_tx_timeout = xge_timeout,
|
||||
.ndo_get_stats64 = xge_get_stats64,
|
||||
};
|
||||
|
||||
static int xge_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct net_device *ndev;
|
||||
struct xge_pdata *pdata;
|
||||
int ret;
|
||||
|
||||
ndev = alloc_etherdev(sizeof(struct xge_pdata));
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata = netdev_priv(ndev);
|
||||
|
||||
pdata->pdev = pdev;
|
||||
pdata->ndev = ndev;
|
||||
SET_NETDEV_DEV(ndev, dev);
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
ndev->netdev_ops = &xgene_ndev_ops;
|
||||
|
||||
ndev->features |= NETIF_F_GSO |
|
||||
NETIF_F_GRO;
|
||||
|
||||
ret = xge_get_resources(pdata);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ndev->hw_features = ndev->features;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||||
if (ret) {
|
||||
netdev_err(ndev, "No usable DMA configuration\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = xge_init_hw(ndev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
netif_napi_add(ndev, &pdata->napi, xge_napi, NAPI_POLL_WEIGHT);
|
||||
|
||||
netif_carrier_off(ndev);
|
||||
ret = register_netdev(ndev);
|
||||
if (ret) {
|
||||
netdev_err(ndev, "Failed to register netdev\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free_netdev(ndev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xge_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xge_pdata *pdata;
|
||||
struct net_device *ndev;
|
||||
|
||||
pdata = platform_get_drvdata(pdev);
|
||||
ndev = pdata->ndev;
|
||||
|
||||
rtnl_lock();
|
||||
if (netif_running(ndev))
|
||||
dev_close(ndev);
|
||||
rtnl_unlock();
|
||||
|
||||
unregister_netdev(ndev);
|
||||
free_netdev(ndev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xge_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct xge_pdata *pdata;
|
||||
|
||||
pdata = platform_get_drvdata(pdev);
|
||||
if (!pdata)
|
||||
return;
|
||||
|
||||
if (!pdata->ndev)
|
||||
return;
|
||||
|
||||
xge_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id xge_acpi_match[] = {
|
||||
{ "APMC0D80" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, xge_acpi_match);
|
||||
|
||||
static struct platform_driver xge_driver = {
|
||||
.driver = {
|
||||
.name = "xgene-enet-v2",
|
||||
.acpi_match_table = ACPI_PTR(xge_acpi_match),
|
||||
},
|
||||
.probe = xge_probe,
|
||||
.remove = xge_remove,
|
||||
.shutdown = xge_shutdown,
|
||||
};
|
||||
module_platform_driver(xge_driver);
|
||||
|
||||
MODULE_DESCRIPTION("APM X-Gene SoC Ethernet v2 driver");
|
||||
MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>");
|
||||
MODULE_VERSION(XGENE_ENET_V2_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
75
drivers/net/ethernet/apm/xgene-v2/main.h
Normal file
75
drivers/net/ethernet/apm/xgene-v2/main.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __XGENE_ENET_V2_MAIN_H__
|
||||
#define __XGENE_ENET_V2_MAIN_H__
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/phy.h>
|
||||
#include <net/ip.h>
|
||||
#include "mac.h"
|
||||
#include "enet.h"
|
||||
#include "ring.h"
|
||||
|
||||
#define XGENE_ENET_V2_VERSION "v1.0"
|
||||
#define XGENE_ENET_STD_MTU 1536
|
||||
#define XGENE_ENET_MIN_FRAME 60
|
||||
#define IRQ_ID_SIZE 16
|
||||
|
||||
struct xge_resource {
|
||||
void __iomem *base_addr;
|
||||
int phy_mode;
|
||||
u32 irq;
|
||||
};
|
||||
|
||||
struct xge_stats {
|
||||
u64 tx_packets;
|
||||
u64 tx_bytes;
|
||||
u64 rx_packets;
|
||||
u64 rx_bytes;
|
||||
u64 rx_errors;
|
||||
};
|
||||
|
||||
/* ethernet private data */
|
||||
struct xge_pdata {
|
||||
struct xge_resource resources;
|
||||
struct xge_desc_ring *tx_ring;
|
||||
struct xge_desc_ring *rx_ring;
|
||||
struct platform_device *pdev;
|
||||
char irq_name[IRQ_ID_SIZE];
|
||||
struct net_device *ndev;
|
||||
struct napi_struct napi;
|
||||
struct xge_stats stats;
|
||||
int phy_speed;
|
||||
u8 nbufs;
|
||||
};
|
||||
|
||||
#endif /* __XGENE_ENET_V2_MAIN_H__ */
|
||||
81
drivers/net/ethernet/apm/xgene-v2/ring.c
Normal file
81
drivers/net/ethernet/apm/xgene-v2/ring.c
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/* create circular linked list of descriptors */
|
||||
void xge_setup_desc(struct xge_desc_ring *ring)
|
||||
{
|
||||
struct xge_raw_desc *raw_desc;
|
||||
dma_addr_t dma_h, next_dma;
|
||||
u16 offset;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < XGENE_ENET_NUM_DESC; i++) {
|
||||
raw_desc = &ring->raw_desc[i];
|
||||
|
||||
offset = (i + 1) & (XGENE_ENET_NUM_DESC - 1);
|
||||
next_dma = ring->dma_addr + (offset * XGENE_ENET_DESC_SIZE);
|
||||
|
||||
raw_desc->m0 = cpu_to_le64(SET_BITS(E, 1) |
|
||||
SET_BITS(PKT_SIZE, SLOT_EMPTY));
|
||||
dma_h = upper_32_bits(next_dma);
|
||||
raw_desc->m1 = cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL, next_dma) |
|
||||
SET_BITS(NEXT_DESC_ADDRH, dma_h));
|
||||
}
|
||||
}
|
||||
|
||||
void xge_update_tx_desc_addr(struct xge_pdata *pdata)
|
||||
{
|
||||
struct xge_desc_ring *ring = pdata->tx_ring;
|
||||
dma_addr_t dma_addr = ring->dma_addr;
|
||||
|
||||
xge_wr_csr(pdata, DMATXDESCL, dma_addr);
|
||||
xge_wr_csr(pdata, DMATXDESCH, upper_32_bits(dma_addr));
|
||||
|
||||
ring->head = 0;
|
||||
ring->tail = 0;
|
||||
}
|
||||
|
||||
void xge_update_rx_desc_addr(struct xge_pdata *pdata)
|
||||
{
|
||||
struct xge_desc_ring *ring = pdata->rx_ring;
|
||||
dma_addr_t dma_addr = ring->dma_addr;
|
||||
|
||||
xge_wr_csr(pdata, DMARXDESCL, dma_addr);
|
||||
xge_wr_csr(pdata, DMARXDESCH, upper_32_bits(dma_addr));
|
||||
|
||||
ring->head = 0;
|
||||
ring->tail = 0;
|
||||
}
|
||||
|
||||
void xge_intr_enable(struct xge_pdata *pdata)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
data = RX_PKT_RCVD | TX_PKT_SENT;
|
||||
xge_wr_csr(pdata, DMAINTRMASK, data);
|
||||
}
|
||||
|
||||
void xge_intr_disable(struct xge_pdata *pdata)
|
||||
{
|
||||
xge_wr_csr(pdata, DMAINTRMASK, 0);
|
||||
}
|
||||
119
drivers/net/ethernet/apm/xgene-v2/ring.h
Normal file
119
drivers/net/ethernet/apm/xgene-v2/ring.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Applied Micro X-Gene SoC Ethernet v2 Driver
|
||||
*
|
||||
* Copyright (c) 2017, Applied Micro Circuits Corporation
|
||||
* Author(s): Iyappan Subramanian <isubramanian@apm.com>
|
||||
* Keyur Chudgar <kchudgar@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __XGENE_ENET_V2_RING_H__
|
||||
#define __XGENE_ENET_V2_RING_H__
|
||||
|
||||
#define XGENE_ENET_DESC_SIZE 64
|
||||
#define XGENE_ENET_NUM_DESC 256
|
||||
#define NUM_BUFS 8
|
||||
#define SLOT_EMPTY 0xfff
|
||||
|
||||
#define DMATXCTRL 0xa180
|
||||
#define DMATXDESCL 0xa184
|
||||
#define DMATXDESCH 0xa1a0
|
||||
#define DMATXSTATUS 0xa188
|
||||
#define DMARXCTRL 0xa18c
|
||||
#define DMARXDESCL 0xa190
|
||||
#define DMARXDESCH 0xa1a4
|
||||
#define DMARXSTATUS 0xa194
|
||||
#define DMAINTRMASK 0xa198
|
||||
#define DMAINTERRUPT 0xa19c
|
||||
|
||||
#define D_POS 62
|
||||
#define D_LEN 2
|
||||
#define E_POS 63
|
||||
#define E_LEN 1
|
||||
#define PKT_ADDRL_POS 0
|
||||
#define PKT_ADDRL_LEN 32
|
||||
#define PKT_ADDRH_POS 32
|
||||
#define PKT_ADDRH_LEN 10
|
||||
#define PKT_SIZE_POS 32
|
||||
#define PKT_SIZE_LEN 12
|
||||
#define NEXT_DESC_ADDRL_POS 0
|
||||
#define NEXT_DESC_ADDRL_LEN 32
|
||||
#define NEXT_DESC_ADDRH_POS 48
|
||||
#define NEXT_DESC_ADDRH_LEN 10
|
||||
|
||||
#define TXPKTCOUNT_POS 16
|
||||
#define TXPKTCOUNT_LEN 8
|
||||
#define RXPKTCOUNT_POS 16
|
||||
#define RXPKTCOUNT_LEN 8
|
||||
|
||||
#define TX_PKT_SENT BIT(0)
|
||||
#define TX_BUS_ERROR BIT(3)
|
||||
#define RX_PKT_RCVD BIT(4)
|
||||
#define RX_BUS_ERROR BIT(7)
|
||||
#define RXSTATUS_RXPKTRCVD BIT(0)
|
||||
|
||||
struct xge_raw_desc {
|
||||
__le64 m0;
|
||||
__le64 m1;
|
||||
__le64 m2;
|
||||
__le64 m3;
|
||||
__le64 m4;
|
||||
__le64 m5;
|
||||
__le64 m6;
|
||||
__le64 m7;
|
||||
};
|
||||
|
||||
struct pkt_info {
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma_addr;
|
||||
void *pkt_buf;
|
||||
};
|
||||
|
||||
/* software context of a descriptor ring */
|
||||
struct xge_desc_ring {
|
||||
struct net_device *ndev;
|
||||
dma_addr_t dma_addr;
|
||||
u8 head;
|
||||
u8 tail;
|
||||
union {
|
||||
void *desc_addr;
|
||||
struct xge_raw_desc *raw_desc;
|
||||
};
|
||||
struct pkt_info (*pkt_info);
|
||||
};
|
||||
|
||||
static inline u64 xge_set_desc_bits(int pos, int len, u64 val)
|
||||
{
|
||||
return (val & ((1ULL << len) - 1)) << pos;
|
||||
}
|
||||
|
||||
static inline u64 xge_get_desc_bits(int pos, int len, u64 src)
|
||||
{
|
||||
return (src >> pos) & ((1ULL << len) - 1);
|
||||
}
|
||||
|
||||
#define SET_BITS(field, val) \
|
||||
xge_set_desc_bits(field ## _POS, field ## _LEN, val)
|
||||
|
||||
#define GET_BITS(field, src) \
|
||||
xge_get_desc_bits(field ## _POS, field ## _LEN, src)
|
||||
|
||||
void xge_setup_desc(struct xge_desc_ring *ring);
|
||||
void xge_update_tx_desc_addr(struct xge_pdata *pdata);
|
||||
void xge_update_rx_desc_addr(struct xge_pdata *pdata);
|
||||
void xge_intr_enable(struct xge_pdata *pdata);
|
||||
void xge_intr_disable(struct xge_pdata *pdata);
|
||||
|
||||
#endif /* __XGENE_ENET_V2_RING_H__ */
|
||||
|
|
@ -494,7 +494,7 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata)
|
|||
break;
|
||||
}
|
||||
|
||||
mc2 |= FULL_DUPLEX2 | PAD_CRC;
|
||||
mc2 |= FULL_DUPLEX2 | PAD_CRC | LENGTH_CHK;
|
||||
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
|
||||
xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
|
||||
xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
|
||||
|
|
@ -623,6 +623,7 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
|
|||
xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb);
|
||||
cb |= CFG_CLE_BYPASS_EN0;
|
||||
CFG_CLE_IP_PROTOCOL0_SET(&cb, 3);
|
||||
CFG_CLE_IP_HDR_LEN_SET(&cb, 0);
|
||||
xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb);
|
||||
|
||||
xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ enum xgene_enet_rm {
|
|||
#define CFG_RXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 26, 3)
|
||||
|
||||
#define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2)
|
||||
#define CFG_CLE_IP_HDR_LEN_SET(dst, val) xgene_set_bits(dst, val, 8, 5)
|
||||
#define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12)
|
||||
#define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4)
|
||||
#define CFG_CLE_NXTFPSEL0_SET(dst, val) xgene_set_bits(dst, val, 20, 4)
|
||||
|
|
@ -215,6 +216,7 @@ enum xgene_enet_rm {
|
|||
#define ENET_GHD_MODE BIT(26)
|
||||
#define FULL_DUPLEX2 BIT(0)
|
||||
#define PAD_CRC BIT(2)
|
||||
#define LENGTH_CHK BIT(4)
|
||||
#define SCAN_AUTO_INCR BIT(5)
|
||||
#define TBYT_ADDR 0x38
|
||||
#define TPKT_ADDR 0x39
|
||||
|
|
|
|||
|
|
@ -601,14 +601,24 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
|
|||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static void xgene_enet_skip_csum(struct sk_buff *skb)
|
||||
static void xgene_enet_rx_csum(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *ndev = skb->dev;
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
if (!ip_is_fragment(iph) ||
|
||||
(iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) {
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
}
|
||||
if (!(ndev->features & NETIF_F_RXCSUM))
|
||||
return;
|
||||
|
||||
if (skb->protocol != htons(ETH_P_IP))
|
||||
return;
|
||||
|
||||
if (ip_is_fragment(iph))
|
||||
return;
|
||||
|
||||
if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
|
||||
return;
|
||||
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
}
|
||||
|
||||
static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
|
||||
|
|
@ -648,12 +658,24 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
|
|||
buf_pool->head = head;
|
||||
}
|
||||
|
||||
/* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */
|
||||
static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status)
|
||||
{
|
||||
if (status == INGRESS_PKT_LEN && len == ETHER_MIN_PACKET) {
|
||||
if (ntohs(eth_hdr(skb)->h_proto) < 46)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
||||
struct xgene_enet_raw_desc *raw_desc,
|
||||
struct xgene_enet_raw_desc *exp_desc)
|
||||
{
|
||||
struct xgene_enet_desc_ring *buf_pool, *page_pool;
|
||||
u32 datalen, frag_size, skb_index;
|
||||
struct xgene_enet_pdata *pdata;
|
||||
struct net_device *ndev;
|
||||
dma_addr_t dma_addr;
|
||||
struct sk_buff *skb;
|
||||
|
|
@ -666,6 +688,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|||
bool nv;
|
||||
|
||||
ndev = rx_ring->ndev;
|
||||
pdata = netdev_priv(ndev);
|
||||
dev = ndev_to_dev(rx_ring->ndev);
|
||||
buf_pool = rx_ring->buf_pool;
|
||||
page_pool = rx_ring->page_pool;
|
||||
|
|
@ -676,30 +699,29 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|||
skb = buf_pool->rx_skb[skb_index];
|
||||
buf_pool->rx_skb[skb_index] = NULL;
|
||||
|
||||
/* checking for error */
|
||||
status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) ||
|
||||
GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
|
||||
if (unlikely(status > 2)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
|
||||
xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev),
|
||||
status);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* strip off CRC as HW isn't doing this */
|
||||
datalen = xgene_enet_get_data_len(le64_to_cpu(raw_desc->m1));
|
||||
|
||||
nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0));
|
||||
if (!nv)
|
||||
datalen -= 4;
|
||||
|
||||
skb_put(skb, datalen);
|
||||
prefetch(skb->data - NET_IP_ALIGN);
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
|
||||
if (!nv)
|
||||
/* checking for error */
|
||||
status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) |
|
||||
GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
|
||||
if (unlikely(status)) {
|
||||
if (!xgene_enet_errata_10GE_8(skb, datalen, status)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
|
||||
xgene_enet_parse_error(rx_ring, pdata, status);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0));
|
||||
if (!nv) {
|
||||
/* strip off CRC as HW isn't doing this */
|
||||
datalen -= 4;
|
||||
goto skip_jumbo;
|
||||
}
|
||||
|
||||
slots = page_pool->slots - 1;
|
||||
head = page_pool->head;
|
||||
|
|
@ -728,11 +750,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|||
|
||||
skip_jumbo:
|
||||
skb_checksum_none_assert(skb);
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
if (likely((ndev->features & NETIF_F_IP_CSUM) &&
|
||||
skb->protocol == htons(ETH_P_IP))) {
|
||||
xgene_enet_skip_csum(skb);
|
||||
}
|
||||
xgene_enet_rx_csum(skb);
|
||||
|
||||
rx_ring->rx_packets++;
|
||||
rx_ring->rx_bytes += datalen;
|
||||
|
|
@ -2039,7 +2057,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
|
|||
xgene_enet_setup_ops(pdata);
|
||||
|
||||
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
|
||||
ndev->features |= NETIF_F_TSO;
|
||||
ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM;
|
||||
spin_lock_init(&pdata->mss_lock);
|
||||
}
|
||||
ndev->hw_features = ndev->features;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "../../../phy/mdio-xgene.h"
|
||||
|
||||
#define XGENE_DRV_VERSION "v1.0"
|
||||
#define ETHER_MIN_PACKET 64
|
||||
#define XGENE_ENET_STD_MTU 1536
|
||||
#define XGENE_ENET_MAX_MTU 9600
|
||||
#define SKB_BUFFER_SIZE (XGENE_ENET_STD_MTU - NET_IP_ALIGN)
|
||||
|
|
|
|||
|
|
@ -341,8 +341,15 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
|
|||
|
||||
xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data);
|
||||
data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
|
||||
/* Errata 10GE_1 - FIFO threshold default value incorrect */
|
||||
RSIF_CLE_BUFF_THRESH_SET(&data, XG_RSIF_CLE_BUFF_THRESH);
|
||||
xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data);
|
||||
|
||||
/* Errata 10GE_1 - FIFO threshold default value incorrect */
|
||||
xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG1_REG_ADDR, &data);
|
||||
RSIF_PLC_CLE_BUFF_THRESH_SET(&data, XG_RSIF_PLC_CLE_BUFF_THRESH);
|
||||
xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG1_REG_ADDR, data);
|
||||
|
||||
xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data);
|
||||
data |= BIT(12);
|
||||
xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@
|
|||
#define XG_DEF_PAUSE_THRES 0x390
|
||||
#define XG_DEF_PAUSE_OFF_THRES 0x2c0
|
||||
#define XG_RSIF_CONFIG_REG_ADDR 0x00a0
|
||||
#define XG_RSIF_CLE_BUFF_THRESH 0x3
|
||||
#define RSIF_CLE_BUFF_THRESH_SET(dst, val) xgene_set_bits(dst, val, 0, 3)
|
||||
#define XG_RSIF_CONFIG1_REG_ADDR 0x00b8
|
||||
#define XG_RSIF_PLC_CLE_BUFF_THRESH 0x1
|
||||
#define RSIF_PLC_CLE_BUFF_THRESH_SET(dst, val) xgene_set_bits(dst, val, 0, 2)
|
||||
#define XCLE_BYPASS_REG0_ADDR 0x0160
|
||||
#define XCLE_BYPASS_REG1_ADDR 0x0164
|
||||
#define XG_CFG_BYPASS_ADDR 0x0204
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ config TIGON3
|
|||
tristate "Broadcom Tigon3 support"
|
||||
depends on PCI
|
||||
select PHYLIB
|
||||
select HWMON
|
||||
imply PTP_1588_CLOCK
|
||||
---help---
|
||||
This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
|
||||
|
|
@ -117,6 +116,13 @@ config TIGON3
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called tg3. This is recommended.
|
||||
|
||||
config TIGON3_HWMON
|
||||
bool "Broadcom Tigon3 HWMON support"
|
||||
default y
|
||||
depends on TIGON3 && HWMON && !(TIGON3=y && HWMON=m)
|
||||
---help---
|
||||
Say Y if you want to expose the thermal sensor on Tigon3 devices.
|
||||
|
||||
config BNX2X
|
||||
tristate "Broadcom NetXtremeII 10Gb support"
|
||||
depends on PCI
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/brcmphy.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/of_net.h>
|
||||
#include "bgmac.h"
|
||||
|
||||
static inline bool bgmac_is_bcm4707_family(struct bcma_device *core)
|
||||
|
|
@ -114,7 +115,7 @@ static int bgmac_probe(struct bcma_device *core)
|
|||
struct ssb_sprom *sprom = &core->bus->sprom;
|
||||
struct mii_bus *mii_bus;
|
||||
struct bgmac *bgmac;
|
||||
u8 *mac;
|
||||
const u8 *mac = NULL;
|
||||
int err;
|
||||
|
||||
bgmac = bgmac_alloc(&core->dev);
|
||||
|
|
@ -127,21 +128,27 @@ static int bgmac_probe(struct bcma_device *core)
|
|||
|
||||
bcma_set_drvdata(core, bgmac);
|
||||
|
||||
switch (core->core_unit) {
|
||||
case 0:
|
||||
mac = sprom->et0mac;
|
||||
break;
|
||||
case 1:
|
||||
mac = sprom->et1mac;
|
||||
break;
|
||||
case 2:
|
||||
mac = sprom->et2mac;
|
||||
break;
|
||||
default:
|
||||
dev_err(bgmac->dev, "Unsupported core_unit %d\n",
|
||||
core->core_unit);
|
||||
err = -ENOTSUPP;
|
||||
goto err;
|
||||
if (bgmac->dev->of_node)
|
||||
mac = of_get_mac_address(bgmac->dev->of_node);
|
||||
|
||||
/* If no MAC address assigned via device tree, check SPROM */
|
||||
if (!mac) {
|
||||
switch (core->core_unit) {
|
||||
case 0:
|
||||
mac = sprom->et0mac;
|
||||
break;
|
||||
case 1:
|
||||
mac = sprom->et1mac;
|
||||
break;
|
||||
case 2:
|
||||
mac = sprom->et2mac;
|
||||
break;
|
||||
default:
|
||||
dev_err(bgmac->dev, "Unsupported core_unit %d\n",
|
||||
core->core_unit);
|
||||
err = -ENOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ether_addr_copy(bgmac->net_dev->dev_addr, mac);
|
||||
|
|
@ -192,48 +199,16 @@ static int bgmac_probe(struct bcma_device *core)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
|
||||
BGMAC_BFL_ENETROBO);
|
||||
bgmac->has_robosw = !!(sprom->boardflags_lo & BGMAC_BFL_ENETROBO);
|
||||
if (bgmac->has_robosw)
|
||||
dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n");
|
||||
|
||||
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
|
||||
if (sprom->boardflags_lo & BGMAC_BFL_ENETADM)
|
||||
dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
|
||||
|
||||
/* Feature Flags */
|
||||
switch (core->bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47186) {
|
||||
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
}
|
||||
if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM5358)
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
|
||||
break;
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47188) {
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
}
|
||||
break;
|
||||
case BCMA_CHIP_ID_BCM4749:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
if (core->bus->chipinfo.pkg == 10) {
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
}
|
||||
break;
|
||||
switch (ci->id) {
|
||||
/* BCM 471X/535X family */
|
||||
case BCMA_CHIP_ID_BCM4716:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
/* fallthrough */
|
||||
|
|
@ -241,13 +216,19 @@ static int bgmac_probe(struct bcma_device *core)
|
|||
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
break;
|
||||
/* bcm4707_family */
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
case BCMA_CHIP_ID_BCM47094:
|
||||
case BCMA_CHIP_ID_BCM53018:
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
if (ci->pkg == BCMA_PKG_ID_BCM47188 ||
|
||||
ci->pkg == BCMA_PKG_ID_BCM47186) {
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
}
|
||||
if (ci->pkg == BCMA_PKG_ID_BCM5358)
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
|
||||
break;
|
||||
case BCMA_CHIP_ID_BCM53573:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
|
|
@ -264,6 +245,24 @@ static int bgmac_probe(struct bcma_device *core)
|
|||
bgmac->feature_flags |= BGMAC_FEAT_CC7_IF_TYPE_RGMII;
|
||||
}
|
||||
break;
|
||||
case BCMA_CHIP_ID_BCM4749:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
if (ci->pkg == 10) {
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
}
|
||||
break;
|
||||
/* bcm4707_family */
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
case BCMA_CHIP_ID_BCM47094:
|
||||
case BCMA_CHIP_ID_BCM53018:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
||||
break;
|
||||
default:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,12 @@
|
|||
#include <linux/of_net.h>
|
||||
#include "bgmac.h"
|
||||
|
||||
#define NICPM_PADRING_CFG 0x00000004
|
||||
#define NICPM_IOMUX_CTRL 0x00000008
|
||||
|
||||
#define NICPM_PADRING_CFG_INIT_VAL 0x74000000
|
||||
#define NICPM_IOMUX_CTRL_INIT_VAL_AX 0x21880000
|
||||
|
||||
#define NICPM_IOMUX_CTRL_INIT_VAL 0x3196e000
|
||||
#define NICPM_IOMUX_CTRL_SPD_SHIFT 10
|
||||
#define NICPM_IOMUX_CTRL_SPD_10M 0
|
||||
|
|
@ -113,6 +117,10 @@ static void bgmac_nicpm_speed_set(struct net_device *net_dev)
|
|||
if (!bgmac->plat.nicpm_base)
|
||||
return;
|
||||
|
||||
/* SET RGMII IO CONFIG */
|
||||
writel(NICPM_PADRING_CFG_INIT_VAL,
|
||||
bgmac->plat.nicpm_base + NICPM_PADRING_CFG);
|
||||
|
||||
val = NICPM_IOMUX_CTRL_INIT_VAL;
|
||||
switch (bgmac->net_dev->phydev->speed) {
|
||||
default:
|
||||
|
|
@ -244,6 +252,31 @@ static int bgmac_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bgmac_suspend(struct device *dev)
|
||||
{
|
||||
struct bgmac *bgmac = dev_get_drvdata(dev);
|
||||
|
||||
return bgmac_enet_suspend(bgmac);
|
||||
}
|
||||
|
||||
static int bgmac_resume(struct device *dev)
|
||||
{
|
||||
struct bgmac *bgmac = dev_get_drvdata(dev);
|
||||
|
||||
return bgmac_enet_resume(bgmac);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops bgmac_pm_ops = {
|
||||
.suspend = bgmac_suspend,
|
||||
.resume = bgmac_resume
|
||||
};
|
||||
|
||||
#define BGMAC_PM_OPS (&bgmac_pm_ops)
|
||||
#else
|
||||
#define BGMAC_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct of_device_id bgmac_of_enet_match[] = {
|
||||
{.compatible = "brcm,amac",},
|
||||
{.compatible = "brcm,nsp-amac",},
|
||||
|
|
@ -257,6 +290,7 @@ static struct platform_driver bgmac_enet_driver = {
|
|||
.driver = {
|
||||
.name = "bgmac-enet",
|
||||
.of_match_table = bgmac_of_enet_match,
|
||||
.pm = BGMAC_PM_OPS
|
||||
},
|
||||
.probe = bgmac_probe,
|
||||
.remove = bgmac_remove,
|
||||
|
|
|
|||
|
|
@ -1480,6 +1480,7 @@ int bgmac_enet_probe(struct bgmac *bgmac)
|
|||
|
||||
net_dev->irq = bgmac->irq;
|
||||
SET_NETDEV_DEV(net_dev, bgmac->dev);
|
||||
dev_set_drvdata(bgmac->dev, bgmac);
|
||||
|
||||
if (!is_valid_ether_addr(net_dev->dev_addr)) {
|
||||
dev_err(bgmac->dev, "Invalid MAC addr: %pM\n",
|
||||
|
|
@ -1552,5 +1553,55 @@ void bgmac_enet_remove(struct bgmac *bgmac)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bgmac_enet_remove);
|
||||
|
||||
int bgmac_enet_suspend(struct bgmac *bgmac)
|
||||
{
|
||||
if (!netif_running(bgmac->net_dev))
|
||||
return 0;
|
||||
|
||||
phy_stop(bgmac->net_dev->phydev);
|
||||
|
||||
netif_stop_queue(bgmac->net_dev);
|
||||
|
||||
napi_disable(&bgmac->napi);
|
||||
|
||||
netif_tx_lock(bgmac->net_dev);
|
||||
netif_device_detach(bgmac->net_dev);
|
||||
netif_tx_unlock(bgmac->net_dev);
|
||||
|
||||
bgmac_chip_intrs_off(bgmac);
|
||||
bgmac_chip_reset(bgmac);
|
||||
bgmac_dma_cleanup(bgmac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bgmac_enet_suspend);
|
||||
|
||||
int bgmac_enet_resume(struct bgmac *bgmac)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!netif_running(bgmac->net_dev))
|
||||
return 0;
|
||||
|
||||
rc = bgmac_dma_init(bgmac);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
bgmac_chip_init(bgmac);
|
||||
|
||||
napi_enable(&bgmac->napi);
|
||||
|
||||
netif_tx_lock(bgmac->net_dev);
|
||||
netif_device_attach(bgmac->net_dev);
|
||||
netif_tx_unlock(bgmac->net_dev);
|
||||
|
||||
netif_start_queue(bgmac->net_dev);
|
||||
|
||||
phy_start(bgmac->net_dev->phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bgmac_enet_resume);
|
||||
|
||||
MODULE_AUTHOR("Rafał Miłecki");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@
|
|||
|
||||
#define BGMAC_WEIGHT 64
|
||||
|
||||
#define ETHER_MAX_LEN 1518
|
||||
#define ETHER_MAX_LEN (ETH_FRAME_LEN + ETH_FCS_LEN)
|
||||
|
||||
/* Feature Flags */
|
||||
#define BGMAC_FEAT_TX_MASK_SETUP BIT(0)
|
||||
|
|
@ -537,6 +537,8 @@ int bgmac_enet_probe(struct bgmac *bgmac);
|
|||
void bgmac_enet_remove(struct bgmac *bgmac);
|
||||
void bgmac_adjust_link(struct net_device *net_dev);
|
||||
int bgmac_phy_connect_direct(struct bgmac *bgmac);
|
||||
int bgmac_enet_suspend(struct bgmac *bgmac);
|
||||
int bgmac_enet_resume(struct bgmac *bgmac);
|
||||
|
||||
struct mii_bus *bcma_mdio_mii_register(struct bgmac *bgmac);
|
||||
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
|
||||
|
|
|
|||
|
|
@ -4277,7 +4277,10 @@ int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
|
|||
{
|
||||
if (tc->type != TC_SETUP_MQPRIO)
|
||||
return -EINVAL;
|
||||
return bnx2x_setup_tc(dev, tc->tc);
|
||||
|
||||
tc->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
|
||||
return bnx2x_setup_tc(dev, tc->mqprio->num_tc);
|
||||
}
|
||||
|
||||
/* called with rtnl_lock */
|
||||
|
|
|
|||
|
|
@ -6905,7 +6905,9 @@ static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
|
|||
if (ntc->type != TC_SETUP_MQPRIO)
|
||||
return -EINVAL;
|
||||
|
||||
return bnxt_setup_mq_tc(dev, ntc->tc);
|
||||
ntc->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
|
||||
return bnxt_setup_mq_tc(dev, ntc->mqprio->num_tc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
|
|
|
|||
|
|
@ -621,7 +621,7 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
|
|||
|
||||
/* GENET TDMA hardware does not support a configurable timeout, but will
|
||||
* always generate an interrupt either after MBDONE packets have been
|
||||
* transmitted, or when the ring is emtpy.
|
||||
* transmitted, or when the ring is empty.
|
||||
*/
|
||||
if (ec->tx_coalesce_usecs || ec->tx_coalesce_usecs_high ||
|
||||
ec->tx_coalesce_usecs_irq || ec->tx_coalesce_usecs_low)
|
||||
|
|
@ -707,6 +707,19 @@ struct bcmgenet_stats {
|
|||
.reg_offset = offset, \
|
||||
}
|
||||
|
||||
#define STAT_GENET_Q(num) \
|
||||
STAT_GENET_SOFT_MIB("txq" __stringify(num) "_packets", \
|
||||
tx_rings[num].packets), \
|
||||
STAT_GENET_SOFT_MIB("txq" __stringify(num) "_bytes", \
|
||||
tx_rings[num].bytes), \
|
||||
STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_bytes", \
|
||||
rx_rings[num].bytes), \
|
||||
STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_packets", \
|
||||
rx_rings[num].packets), \
|
||||
STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_errors", \
|
||||
rx_rings[num].errors), \
|
||||
STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_dropped", \
|
||||
rx_rings[num].dropped)
|
||||
|
||||
/* There is a 0xC gap between the end of RX and beginning of TX stats and then
|
||||
* between the end of TX stats and the beginning of the RX RUNT
|
||||
|
|
@ -801,6 +814,12 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
|
|||
STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
|
||||
STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed),
|
||||
STAT_GENET_SOFT_MIB("tx_dma_failed", mib.tx_dma_failed),
|
||||
/* Per TX queues */
|
||||
STAT_GENET_Q(0),
|
||||
STAT_GENET_Q(1),
|
||||
STAT_GENET_Q(2),
|
||||
STAT_GENET_Q(3),
|
||||
STAT_GENET_Q(16),
|
||||
};
|
||||
|
||||
#define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats)
|
||||
|
|
@ -1078,8 +1097,17 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv,
|
|||
/* Power down LED */
|
||||
if (priv->hw_params->flags & GENET_HAS_EXT) {
|
||||
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
|
||||
reg |= (EXT_PWR_DOWN_PHY |
|
||||
EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
|
||||
if (GENET_IS_V5(priv))
|
||||
reg |= EXT_PWR_DOWN_PHY_EN |
|
||||
EXT_PWR_DOWN_PHY_RD |
|
||||
EXT_PWR_DOWN_PHY_SD |
|
||||
EXT_PWR_DOWN_PHY_RX |
|
||||
EXT_PWR_DOWN_PHY_TX |
|
||||
EXT_IDDQ_GLBL_PWR;
|
||||
else
|
||||
reg |= EXT_PWR_DOWN_PHY;
|
||||
|
||||
reg |= (EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
|
||||
bcmgenet_phy_power_set(priv->dev, false);
|
||||
|
|
@ -1104,12 +1132,34 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
|
|||
|
||||
switch (mode) {
|
||||
case GENET_POWER_PASSIVE:
|
||||
reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_PHY |
|
||||
EXT_PWR_DOWN_BIAS);
|
||||
/* fallthrough */
|
||||
reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
|
||||
if (GENET_IS_V5(priv)) {
|
||||
reg &= ~(EXT_PWR_DOWN_PHY_EN |
|
||||
EXT_PWR_DOWN_PHY_RD |
|
||||
EXT_PWR_DOWN_PHY_SD |
|
||||
EXT_PWR_DOWN_PHY_RX |
|
||||
EXT_PWR_DOWN_PHY_TX |
|
||||
EXT_IDDQ_GLBL_PWR);
|
||||
reg |= EXT_PHY_RESET;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
mdelay(1);
|
||||
|
||||
reg &= ~EXT_PHY_RESET;
|
||||
} else {
|
||||
reg &= ~EXT_PWR_DOWN_PHY;
|
||||
reg |= EXT_PWR_DN_EN_LD;
|
||||
}
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
bcmgenet_phy_power_set(priv->dev, true);
|
||||
bcmgenet_mii_reset(priv->dev);
|
||||
break;
|
||||
|
||||
case GENET_POWER_CABLE_SENSE:
|
||||
/* enable APD */
|
||||
reg |= EXT_PWR_DN_EN_LD;
|
||||
if (!GENET_IS_V5(priv)) {
|
||||
reg |= EXT_PWR_DN_EN_LD;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
}
|
||||
break;
|
||||
case GENET_POWER_WOL_MAGIC:
|
||||
bcmgenet_wol_power_up_cfg(priv, mode);
|
||||
|
|
@ -1117,39 +1167,20 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
if (mode == GENET_POWER_PASSIVE) {
|
||||
bcmgenet_phy_power_set(priv->dev, true);
|
||||
bcmgenet_mii_reset(priv->dev);
|
||||
}
|
||||
}
|
||||
|
||||
/* ioctl handle special commands that are not present in ethtool. */
|
||||
static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct bcmgenet_priv *priv = netdev_priv(dev);
|
||||
int val = 0;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCGMIIPHY:
|
||||
case SIOCGMIIREG:
|
||||
case SIOCSMIIREG:
|
||||
if (!priv->phydev)
|
||||
val = -ENODEV;
|
||||
else
|
||||
val = phy_mii_ioctl(priv->phydev, rq, cmd);
|
||||
break;
|
||||
if (!priv->phydev)
|
||||
return -ENODEV;
|
||||
|
||||
default:
|
||||
val = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
return phy_mii_ioctl(priv->phydev, rq, cmd);
|
||||
}
|
||||
|
||||
static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
|
||||
|
|
@ -1240,14 +1271,18 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
|
|||
unsigned int txbds_ready;
|
||||
unsigned int txbds_processed = 0;
|
||||
|
||||
/* Compute how many buffers are transmitted since last xmit call */
|
||||
c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
|
||||
c_index &= DMA_C_INDEX_MASK;
|
||||
|
||||
if (likely(c_index >= ring->c_index))
|
||||
txbds_ready = c_index - ring->c_index;
|
||||
/* Clear status before servicing to reduce spurious interrupts */
|
||||
if (ring->index == DESC_INDEX)
|
||||
bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE,
|
||||
INTRL2_CPU_CLEAR);
|
||||
else
|
||||
txbds_ready = (DMA_C_INDEX_MASK + 1) - ring->c_index + c_index;
|
||||
bcmgenet_intrl2_1_writel(priv, (1 << ring->index),
|
||||
INTRL2_CPU_CLEAR);
|
||||
|
||||
/* Compute how many buffers are transmitted since last xmit call */
|
||||
c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX)
|
||||
& DMA_C_INDEX_MASK;
|
||||
txbds_ready = (c_index - ring->c_index) & DMA_C_INDEX_MASK;
|
||||
|
||||
netif_dbg(priv, tx_done, dev,
|
||||
"%s ring=%d old_c_index=%u c_index=%u txbds_ready=%u\n",
|
||||
|
|
@ -1280,15 +1315,15 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
|
|||
}
|
||||
|
||||
ring->free_bds += txbds_processed;
|
||||
ring->c_index = (ring->c_index + txbds_processed) & DMA_C_INDEX_MASK;
|
||||
ring->c_index = c_index;
|
||||
|
||||
dev->stats.tx_packets += pkts_compl;
|
||||
dev->stats.tx_bytes += bytes_compl;
|
||||
ring->packets += pkts_compl;
|
||||
ring->bytes += bytes_compl;
|
||||
|
||||
netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue),
|
||||
pkts_compl, bytes_compl);
|
||||
|
||||
return pkts_compl;
|
||||
return txbds_processed;
|
||||
}
|
||||
|
||||
static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
|
||||
|
|
@ -1657,18 +1692,28 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
|
|||
unsigned long dma_flag;
|
||||
int len;
|
||||
unsigned int rxpktprocessed = 0, rxpkttoprocess;
|
||||
unsigned int p_index;
|
||||
unsigned int p_index, mask;
|
||||
unsigned int discards;
|
||||
unsigned int chksum_ok = 0;
|
||||
|
||||
/* Clear status before servicing to reduce spurious interrupts */
|
||||
if (ring->index == DESC_INDEX) {
|
||||
bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE,
|
||||
INTRL2_CPU_CLEAR);
|
||||
} else {
|
||||
mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index);
|
||||
bcmgenet_intrl2_1_writel(priv,
|
||||
mask,
|
||||
INTRL2_CPU_CLEAR);
|
||||
}
|
||||
|
||||
p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX);
|
||||
|
||||
discards = (p_index >> DMA_P_INDEX_DISCARD_CNT_SHIFT) &
|
||||
DMA_P_INDEX_DISCARD_CNT_MASK;
|
||||
if (discards > ring->old_discards) {
|
||||
discards = discards - ring->old_discards;
|
||||
dev->stats.rx_missed_errors += discards;
|
||||
dev->stats.rx_errors += discards;
|
||||
ring->errors += discards;
|
||||
ring->old_discards += discards;
|
||||
|
||||
/* Clear HW register when we reach 75% of maximum 0xFFFF */
|
||||
|
|
@ -1680,12 +1725,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
|
|||
}
|
||||
|
||||
p_index &= DMA_P_INDEX_MASK;
|
||||
|
||||
if (likely(p_index >= ring->c_index))
|
||||
rxpkttoprocess = p_index - ring->c_index;
|
||||
else
|
||||
rxpkttoprocess = (DMA_C_INDEX_MASK + 1) - ring->c_index +
|
||||
p_index;
|
||||
rxpkttoprocess = (p_index - ring->c_index) & DMA_C_INDEX_MASK;
|
||||
|
||||
netif_dbg(priv, rx_status, dev,
|
||||
"RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
|
||||
|
|
@ -1696,7 +1736,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
|
|||
skb = bcmgenet_rx_refill(priv, cb);
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
dev->stats.rx_dropped++;
|
||||
ring->dropped++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
|
@ -1724,7 +1764,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
|
|||
if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
|
||||
netif_err(priv, rx_status, dev,
|
||||
"dropping fragmented packet!\n");
|
||||
dev->stats.rx_errors++;
|
||||
ring->errors++;
|
||||
dev_kfree_skb_any(skb);
|
||||
goto next;
|
||||
}
|
||||
|
|
@ -1773,8 +1813,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
|
|||
|
||||
/*Finish setting up the received SKB and send it to the kernel*/
|
||||
skb->protocol = eth_type_trans(skb, priv->dev);
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += len;
|
||||
ring->packets++;
|
||||
ring->bytes += len;
|
||||
if (dma_flag & DMA_RX_MULT)
|
||||
dev->stats.multicast++;
|
||||
|
||||
|
|
@ -1912,10 +1952,8 @@ static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
|
|||
/* Mask all interrupts.*/
|
||||
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
|
||||
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
|
||||
bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
|
||||
bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
|
||||
bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
|
||||
bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
|
||||
}
|
||||
|
||||
static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)
|
||||
|
|
@ -1942,8 +1980,6 @@ static int init_umac(struct bcmgenet_priv *priv)
|
|||
int ret;
|
||||
u32 reg;
|
||||
u32 int0_enable = 0;
|
||||
u32 int1_enable = 0;
|
||||
int i;
|
||||
|
||||
dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
|
||||
|
||||
|
|
@ -1970,12 +2006,6 @@ static int init_umac(struct bcmgenet_priv *priv)
|
|||
|
||||
bcmgenet_intr_disable(priv);
|
||||
|
||||
/* Enable Rx default queue 16 interrupts */
|
||||
int0_enable |= UMAC_IRQ_RXDMA_DONE;
|
||||
|
||||
/* Enable Tx default queue 16 interrupts */
|
||||
int0_enable |= UMAC_IRQ_TXDMA_DONE;
|
||||
|
||||
/* Configure backpressure vectors for MoCA */
|
||||
if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
|
||||
reg = bcmgenet_bp_mc_get(priv);
|
||||
|
|
@ -1993,18 +2023,8 @@ static int init_umac(struct bcmgenet_priv *priv)
|
|||
if (priv->hw_params->flags & GENET_HAS_MDIO_INTR)
|
||||
int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
|
||||
|
||||
/* Enable Rx priority queue interrupts */
|
||||
for (i = 0; i < priv->hw_params->rx_queues; ++i)
|
||||
int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
|
||||
|
||||
/* Enable Tx priority queue interrupts */
|
||||
for (i = 0; i < priv->hw_params->tx_queues; ++i)
|
||||
int1_enable |= (1 << i);
|
||||
|
||||
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
|
||||
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
|
||||
|
||||
/* Enable rx/tx engine.*/
|
||||
dev_dbg(kdev, "done init umac\n");
|
||||
|
||||
return 0;
|
||||
|
|
@ -2136,22 +2156,33 @@ static void bcmgenet_init_tx_napi(struct bcmgenet_priv *priv)
|
|||
static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 int0_enable = UMAC_IRQ_TXDMA_DONE;
|
||||
u32 int1_enable = 0;
|
||||
struct bcmgenet_tx_ring *ring;
|
||||
|
||||
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
|
||||
ring = &priv->tx_rings[i];
|
||||
napi_enable(&ring->napi);
|
||||
int1_enable |= (1 << i);
|
||||
}
|
||||
|
||||
ring = &priv->tx_rings[DESC_INDEX];
|
||||
napi_enable(&ring->napi);
|
||||
|
||||
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
|
||||
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
|
||||
}
|
||||
|
||||
static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 int0_disable = UMAC_IRQ_TXDMA_DONE;
|
||||
u32 int1_disable = 0xffff;
|
||||
struct bcmgenet_tx_ring *ring;
|
||||
|
||||
bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
|
||||
bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
|
||||
|
||||
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
|
||||
ring = &priv->tx_rings[i];
|
||||
napi_disable(&ring->napi);
|
||||
|
|
@ -2264,22 +2295,33 @@ static void bcmgenet_init_rx_napi(struct bcmgenet_priv *priv)
|
|||
static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 int0_enable = UMAC_IRQ_RXDMA_DONE;
|
||||
u32 int1_enable = 0;
|
||||
struct bcmgenet_rx_ring *ring;
|
||||
|
||||
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
|
||||
ring = &priv->rx_rings[i];
|
||||
napi_enable(&ring->napi);
|
||||
int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
|
||||
}
|
||||
|
||||
ring = &priv->rx_rings[DESC_INDEX];
|
||||
napi_enable(&ring->napi);
|
||||
|
||||
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
|
||||
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
|
||||
}
|
||||
|
||||
static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 int0_disable = UMAC_IRQ_RXDMA_DONE;
|
||||
u32 int1_disable = 0xffff << UMAC_IRQ1_RX_INTR_SHIFT;
|
||||
struct bcmgenet_rx_ring *ring;
|
||||
|
||||
bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
|
||||
bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
|
||||
|
||||
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
|
||||
ring = &priv->rx_rings[i];
|
||||
napi_disable(&ring->napi);
|
||||
|
|
@ -2634,6 +2676,15 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
|
|||
}
|
||||
}
|
||||
|
||||
if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
|
||||
UMAC_IRQ_PHY_DET_F |
|
||||
UMAC_IRQ_LINK_EVENT |
|
||||
UMAC_IRQ_HFB_SM |
|
||||
UMAC_IRQ_HFB_MM)) {
|
||||
/* all other interested interrupts handled in bottom half */
|
||||
schedule_work(&priv->bcmgenet_irq_work);
|
||||
}
|
||||
|
||||
if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
|
||||
status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
|
||||
wake_up(&priv->wq);
|
||||
|
|
@ -2921,7 +2972,7 @@ static int bcmgenet_close(struct net_device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable MAC transmit. TX DMA disabled have to done before this */
|
||||
/* Disable MAC transmit. TX DMA disabled must be done before this */
|
||||
umac_enable_set(priv, CMD_TX_EN, false);
|
||||
|
||||
/* tx reclaim */
|
||||
|
|
@ -3101,6 +3152,48 @@ static int bcmgenet_set_mac_addr(struct net_device *dev, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct bcmgenet_priv *priv = netdev_priv(dev);
|
||||
unsigned long tx_bytes = 0, tx_packets = 0;
|
||||
unsigned long rx_bytes = 0, rx_packets = 0;
|
||||
unsigned long rx_errors = 0, rx_dropped = 0;
|
||||
struct bcmgenet_tx_ring *tx_ring;
|
||||
struct bcmgenet_rx_ring *rx_ring;
|
||||
unsigned int q;
|
||||
|
||||
for (q = 0; q < priv->hw_params->tx_queues; q++) {
|
||||
tx_ring = &priv->tx_rings[q];
|
||||
tx_bytes += tx_ring->bytes;
|
||||
tx_packets += tx_ring->packets;
|
||||
}
|
||||
tx_ring = &priv->tx_rings[DESC_INDEX];
|
||||
tx_bytes += tx_ring->bytes;
|
||||
tx_packets += tx_ring->packets;
|
||||
|
||||
for (q = 0; q < priv->hw_params->rx_queues; q++) {
|
||||
rx_ring = &priv->rx_rings[q];
|
||||
|
||||
rx_bytes += rx_ring->bytes;
|
||||
rx_packets += rx_ring->packets;
|
||||
rx_errors += rx_ring->errors;
|
||||
rx_dropped += rx_ring->dropped;
|
||||
}
|
||||
rx_ring = &priv->rx_rings[DESC_INDEX];
|
||||
rx_bytes += rx_ring->bytes;
|
||||
rx_packets += rx_ring->packets;
|
||||
rx_errors += rx_ring->errors;
|
||||
rx_dropped += rx_ring->dropped;
|
||||
|
||||
dev->stats.tx_bytes = tx_bytes;
|
||||
dev->stats.tx_packets = tx_packets;
|
||||
dev->stats.rx_bytes = rx_bytes;
|
||||
dev->stats.rx_packets = rx_packets;
|
||||
dev->stats.rx_errors = rx_errors;
|
||||
dev->stats.rx_missed_errors = rx_errors;
|
||||
return &dev->stats;
|
||||
}
|
||||
|
||||
static const struct net_device_ops bcmgenet_netdev_ops = {
|
||||
.ndo_open = bcmgenet_open,
|
||||
.ndo_stop = bcmgenet_close,
|
||||
|
|
@ -3113,6 +3206,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = {
|
|||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = bcmgenet_poll_controller,
|
||||
#endif
|
||||
.ndo_get_stats = bcmgenet_get_stats,
|
||||
};
|
||||
|
||||
/* Array of GENET hardware parameters/characteristics */
|
||||
|
|
@ -3186,6 +3280,25 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
|
|||
.flags = GENET_HAS_40BITS | GENET_HAS_EXT |
|
||||
GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET,
|
||||
},
|
||||
[GENET_V5] = {
|
||||
.tx_queues = 4,
|
||||
.tx_bds_per_q = 32,
|
||||
.rx_queues = 0,
|
||||
.rx_bds_per_q = 0,
|
||||
.bp_in_en_shift = 17,
|
||||
.bp_in_mask = 0x1ffff,
|
||||
.hfb_filter_cnt = 48,
|
||||
.hfb_filter_size = 128,
|
||||
.qtag_mask = 0x3F,
|
||||
.tbuf_offset = 0x0600,
|
||||
.hfb_offset = 0x8000,
|
||||
.hfb_reg_offset = 0xfc00,
|
||||
.rdma_offset = 0x2000,
|
||||
.tdma_offset = 0x4000,
|
||||
.words_per_bd = 3,
|
||||
.flags = GENET_HAS_40BITS | GENET_HAS_EXT |
|
||||
GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET,
|
||||
},
|
||||
};
|
||||
|
||||
/* Infer hardware parameters from the detected GENET version */
|
||||
|
|
@ -3196,26 +3309,22 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
|
|||
u8 major;
|
||||
u16 gphy_rev;
|
||||
|
||||
if (GENET_IS_V4(priv)) {
|
||||
if (GENET_IS_V5(priv) || GENET_IS_V4(priv)) {
|
||||
bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
|
||||
genet_dma_ring_regs = genet_dma_ring_regs_v4;
|
||||
priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
|
||||
priv->version = GENET_V4;
|
||||
} else if (GENET_IS_V3(priv)) {
|
||||
bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
|
||||
genet_dma_ring_regs = genet_dma_ring_regs_v123;
|
||||
priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
|
||||
priv->version = GENET_V3;
|
||||
} else if (GENET_IS_V2(priv)) {
|
||||
bcmgenet_dma_regs = bcmgenet_dma_regs_v2;
|
||||
genet_dma_ring_regs = genet_dma_ring_regs_v123;
|
||||
priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
|
||||
priv->version = GENET_V2;
|
||||
} else if (GENET_IS_V1(priv)) {
|
||||
bcmgenet_dma_regs = bcmgenet_dma_regs_v1;
|
||||
genet_dma_ring_regs = genet_dma_ring_regs_v123;
|
||||
priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
|
||||
priv->version = GENET_V1;
|
||||
}
|
||||
|
||||
/* enum genet_version starts at 1 */
|
||||
|
|
@ -3225,7 +3334,9 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
|
|||
/* Read GENET HW version */
|
||||
reg = bcmgenet_sys_readl(priv, SYS_REV_CTRL);
|
||||
major = (reg >> 24 & 0x0f);
|
||||
if (major == 5)
|
||||
if (major == 6)
|
||||
major = 5;
|
||||
else if (major == 5)
|
||||
major = 4;
|
||||
else if (major == 0)
|
||||
major = 1;
|
||||
|
|
@ -3253,19 +3364,25 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
|
|||
*/
|
||||
gphy_rev = reg & 0xffff;
|
||||
|
||||
if (GENET_IS_V5(priv)) {
|
||||
/* The EPHY revision should come from the MDIO registers of
|
||||
* the PHY not from GENET.
|
||||
*/
|
||||
if (gphy_rev != 0) {
|
||||
pr_warn("GENET is reporting EPHY revision: 0x%04x\n",
|
||||
gphy_rev);
|
||||
}
|
||||
/* This is reserved so should require special treatment */
|
||||
if (gphy_rev == 0 || gphy_rev == 0x01ff) {
|
||||
} else if (gphy_rev == 0 || gphy_rev == 0x01ff) {
|
||||
pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is the good old scheme, just GPHY major, no minor nor patch */
|
||||
if ((gphy_rev & 0xf0) != 0)
|
||||
} else if ((gphy_rev & 0xf0) != 0) {
|
||||
priv->gphy_rev = gphy_rev << 8;
|
||||
|
||||
/* This is the new scheme, GPHY major rolls over with 0x10 = rev G0 */
|
||||
else if ((gphy_rev & 0xff00) != 0)
|
||||
} else if ((gphy_rev & 0xff00) != 0) {
|
||||
priv->gphy_rev = gphy_rev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PHYS_ADDR_T_64BIT
|
||||
if (!(params->flags & GENET_HAS_40BITS))
|
||||
|
|
@ -3295,6 +3412,7 @@ static const struct of_device_id bcmgenet_match[] = {
|
|||
{ .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 },
|
||||
{ .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 },
|
||||
{ .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 },
|
||||
{ .compatible = "brcm,genet-v5", .data = (void *)GENET_V5 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcmgenet_match);
|
||||
|
|
@ -3492,7 +3610,7 @@ static int bcmgenet_suspend(struct device *d)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable MAC transmit. TX DMA disabled have to done before this */
|
||||
/* Disable MAC transmit. TX DMA disabled must be done before this */
|
||||
umac_enable_set(priv, CMD_TX_EN, false);
|
||||
|
||||
/* tx reclaim */
|
||||
|
|
|
|||
|
|
@ -355,8 +355,14 @@ struct bcmgenet_mib_counters {
|
|||
#define EXT_PWR_DN_EN_LD (1 << 3)
|
||||
#define EXT_ENERGY_DET (1 << 4)
|
||||
#define EXT_IDDQ_FROM_PHY (1 << 5)
|
||||
#define EXT_IDDQ_GLBL_PWR (1 << 7)
|
||||
#define EXT_PHY_RESET (1 << 8)
|
||||
#define EXT_ENERGY_DET_MASK (1 << 12)
|
||||
#define EXT_PWR_DOWN_PHY_TX (1 << 16)
|
||||
#define EXT_PWR_DOWN_PHY_RX (1 << 17)
|
||||
#define EXT_PWR_DOWN_PHY_SD (1 << 18)
|
||||
#define EXT_PWR_DOWN_PHY_RD (1 << 19)
|
||||
#define EXT_PWR_DOWN_PHY_EN (1 << 20)
|
||||
|
||||
#define EXT_RGMII_OOB_CTRL 0x0C
|
||||
#define RGMII_LINK (1 << 4)
|
||||
|
|
@ -499,13 +505,15 @@ enum bcmgenet_version {
|
|||
GENET_V1 = 1,
|
||||
GENET_V2,
|
||||
GENET_V3,
|
||||
GENET_V4
|
||||
GENET_V4,
|
||||
GENET_V5
|
||||
};
|
||||
|
||||
#define GENET_IS_V1(p) ((p)->version == GENET_V1)
|
||||
#define GENET_IS_V2(p) ((p)->version == GENET_V2)
|
||||
#define GENET_IS_V3(p) ((p)->version == GENET_V3)
|
||||
#define GENET_IS_V4(p) ((p)->version == GENET_V4)
|
||||
#define GENET_IS_V5(p) ((p)->version == GENET_V5)
|
||||
|
||||
/* Hardware flags */
|
||||
#define GENET_HAS_40BITS (1 << 0)
|
||||
|
|
@ -544,6 +552,8 @@ struct bcmgenet_skb_cb {
|
|||
struct bcmgenet_tx_ring {
|
||||
spinlock_t lock; /* ring lock */
|
||||
struct napi_struct napi; /* NAPI per tx queue */
|
||||
unsigned long packets;
|
||||
unsigned long bytes;
|
||||
unsigned int index; /* ring index */
|
||||
unsigned int queue; /* queue index */
|
||||
struct enet_cb *cbs; /* tx ring buffer control block*/
|
||||
|
|
@ -562,6 +572,10 @@ struct bcmgenet_tx_ring {
|
|||
|
||||
struct bcmgenet_rx_ring {
|
||||
struct napi_struct napi; /* Rx NAPI struct */
|
||||
unsigned long bytes;
|
||||
unsigned long packets;
|
||||
unsigned long errors;
|
||||
unsigned long dropped;
|
||||
unsigned int index; /* Rx ring index */
|
||||
struct enet_cb *cbs; /* Rx ring buffer control block */
|
||||
unsigned int size; /* Rx ring size */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
|
||||
*
|
||||
* Copyright (c) 2014 Broadcom Corporation
|
||||
* Copyright (c) 2014-2017 Broadcom
|
||||
*
|
||||
* 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
|
||||
|
|
@ -127,7 +127,6 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
|
|||
enum bcmgenet_power_mode mode)
|
||||
{
|
||||
struct net_device *dev = priv->dev;
|
||||
u32 cpu_mask_clear;
|
||||
int retries = 0;
|
||||
u32 reg;
|
||||
|
||||
|
|
@ -173,18 +172,12 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
|
|||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
}
|
||||
|
||||
/* Enable the MPD interrupt */
|
||||
cpu_mask_clear = UMAC_IRQ_MPD_R;
|
||||
|
||||
bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
|
||||
enum bcmgenet_power_mode mode)
|
||||
{
|
||||
u32 cpu_mask_set;
|
||||
u32 reg;
|
||||
|
||||
if (mode != GENET_POWER_WOL_MAGIC) {
|
||||
|
|
@ -201,10 +194,4 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
|
|||
reg &= ~CMD_CRC_FWD;
|
||||
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
|
||||
priv->crc_fwd_en = 0;
|
||||
|
||||
/* Stop monitoring magic packet IRQ */
|
||||
cpu_mask_set = UMAC_IRQ_MPD_R;
|
||||
|
||||
/* Stop monitoring magic packet IRQ */
|
||||
bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Broadcom GENET MDIO routines
|
||||
*
|
||||
* Copyright (c) 2014 Broadcom Corporation
|
||||
* Copyright (c) 2014-2017 Broadcom
|
||||
*
|
||||
* 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
|
||||
|
|
@ -195,29 +195,31 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
|
|||
u32 reg = 0;
|
||||
|
||||
/* EXT_GPHY_CTRL is only valid for GENETv4 and onward */
|
||||
if (!GENET_IS_V4(priv))
|
||||
return;
|
||||
if (GENET_IS_V4(priv)) {
|
||||
reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
|
||||
if (enable) {
|
||||
reg &= ~EXT_CK25_DIS;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
mdelay(1);
|
||||
|
||||
reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
|
||||
if (enable) {
|
||||
reg &= ~EXT_CK25_DIS;
|
||||
reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
|
||||
reg |= EXT_GPHY_RESET;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
mdelay(1);
|
||||
|
||||
reg &= ~EXT_GPHY_RESET;
|
||||
} else {
|
||||
reg |= EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN |
|
||||
EXT_GPHY_RESET;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
mdelay(1);
|
||||
reg |= EXT_CK25_DIS;
|
||||
}
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
mdelay(1);
|
||||
|
||||
reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
|
||||
reg |= EXT_GPHY_RESET;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
mdelay(1);
|
||||
|
||||
reg &= ~EXT_GPHY_RESET;
|
||||
udelay(60);
|
||||
} else {
|
||||
reg |= EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN | EXT_GPHY_RESET;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
mdelay(1);
|
||||
reg |= EXT_CK25_DIS;
|
||||
}
|
||||
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
|
||||
udelay(60);
|
||||
}
|
||||
|
||||
static void bcmgenet_internal_phy_setup(struct net_device *dev)
|
||||
|
|
@ -227,10 +229,12 @@ static void bcmgenet_internal_phy_setup(struct net_device *dev)
|
|||
|
||||
/* Power up PHY */
|
||||
bcmgenet_phy_power_set(dev, true);
|
||||
/* enable APD */
|
||||
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
|
||||
reg |= EXT_PWR_DN_EN_LD;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
if (!GENET_IS_V5(priv)) {
|
||||
/* enable APD */
|
||||
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
|
||||
reg |= EXT_PWR_DN_EN_LD;
|
||||
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
|
||||
}
|
||||
bcmgenet_mii_reset(dev);
|
||||
}
|
||||
|
||||
|
|
@ -238,10 +242,12 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
|
|||
{
|
||||
u32 reg;
|
||||
|
||||
/* Speed settings are set in bcmgenet_mii_setup() */
|
||||
reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
|
||||
reg |= LED_ACT_SOURCE_MAC;
|
||||
bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
|
||||
if (!GENET_IS_V5(priv)) {
|
||||
/* Speed settings are set in bcmgenet_mii_setup() */
|
||||
reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
|
||||
reg |= LED_ACT_SOURCE_MAC;
|
||||
bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
|
||||
}
|
||||
|
||||
if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET)
|
||||
fixed_phy_set_link_update(priv->phydev,
|
||||
|
|
|
|||
|
|
@ -825,6 +825,7 @@ static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us)
|
|||
return timeout_us ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TIGON3_HWMON
|
||||
static int tg3_ape_wait_for_event(struct tg3 *tp, u32 timeout_us)
|
||||
{
|
||||
u32 i, apedata;
|
||||
|
|
@ -904,6 +905,7 @@ static int tg3_ape_scratchpad_read(struct tg3 *tp, u32 *data, u32 base_off,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tg3_ape_send_event(struct tg3 *tp, u32 event)
|
||||
{
|
||||
|
|
@ -10744,6 +10746,7 @@ static int tg3_init_hw(struct tg3 *tp, bool reset_phy)
|
|||
return tg3_reset_hw(tp, reset_phy);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TIGON3_HWMON
|
||||
static void tg3_sd_scan_scratchpad(struct tg3 *tp, struct tg3_ocir *ocir)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -10826,6 +10829,10 @@ static void tg3_hwmon_open(struct tg3 *tp)
|
|||
dev_err(&pdev->dev, "Cannot register hwmon device, aborting\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void tg3_hwmon_close(struct tg3 *tp) { }
|
||||
static inline void tg3_hwmon_open(struct tg3 *tp) { }
|
||||
#endif /* CONFIG_TIGON3_HWMON */
|
||||
|
||||
|
||||
#define TG3_STAT_ADD32(PSTAT, REG) \
|
||||
|
|
|
|||
|
|
@ -131,11 +131,20 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr)
|
|||
|
||||
case OCTNET_CMD_CHANGE_MACADDR:
|
||||
mac = ((u8 *)&nctrl->udd[0]) + 2;
|
||||
netif_info(lio, probe, lio->netdev,
|
||||
"MACAddr changed to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
|
||||
mac[0], mac[1],
|
||||
mac[2], mac[3],
|
||||
mac[4], mac[5]);
|
||||
if (nctrl->ncmd.s.param1) {
|
||||
/* vfidx is 0 based, but vf_num (param1) is 1 based */
|
||||
int vfidx = nctrl->ncmd.s.param1 - 1;
|
||||
bool mac_is_admin_assigned = nctrl->ncmd.s.param2;
|
||||
|
||||
if (mac_is_admin_assigned)
|
||||
netif_info(lio, probe, lio->netdev,
|
||||
"MAC Address %pM is configured for VF %d\n",
|
||||
mac, vfidx);
|
||||
} else {
|
||||
netif_info(lio, probe, lio->netdev,
|
||||
" MACAddr changed to %pM\n",
|
||||
mac);
|
||||
}
|
||||
break;
|
||||
|
||||
case OCTNET_CMD_CHANGE_MTU:
|
||||
|
|
|
|||
|
|
@ -213,17 +213,23 @@ static int lio_get_link_ksettings(struct net_device *netdev,
|
|||
struct lio *lio = GET_LIO(netdev);
|
||||
struct octeon_device *oct = lio->oct_dev;
|
||||
struct oct_link_info *linfo;
|
||||
u32 supported, advertising;
|
||||
u32 supported = 0, advertising = 0;
|
||||
|
||||
linfo = &lio->linfo;
|
||||
|
||||
if (linfo->link.s.if_mode == INTERFACE_MODE_XAUI ||
|
||||
linfo->link.s.if_mode == INTERFACE_MODE_RXAUI ||
|
||||
linfo->link.s.if_mode == INTERFACE_MODE_XLAUI ||
|
||||
linfo->link.s.if_mode == INTERFACE_MODE_XFI) {
|
||||
ecmd->base.port = PORT_FIBRE;
|
||||
supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE |
|
||||
SUPPORTED_Pause);
|
||||
advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Pause);
|
||||
|
||||
if (linfo->link.s.speed == SPEED_10000) {
|
||||
supported = SUPPORTED_10000baseT_Full;
|
||||
advertising = ADVERTISED_10000baseT_Full;
|
||||
}
|
||||
|
||||
supported |= SUPPORTED_FIBRE | SUPPORTED_Pause;
|
||||
advertising |= ADVERTISED_Pause;
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
ecmd->link_modes.supported, supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
|
|
|
|||
|
|
@ -60,12 +60,6 @@ MODULE_PARM_DESC(fw_type, "Type of firmware to be loaded. Default \"nic\"");
|
|||
|
||||
static int ptp_enable = 1;
|
||||
|
||||
/* Bit mask values for lio->ifstate */
|
||||
#define LIO_IFSTATE_DROQ_OPS 0x01
|
||||
#define LIO_IFSTATE_REGISTERED 0x02
|
||||
#define LIO_IFSTATE_RUNNING 0x04
|
||||
#define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08
|
||||
|
||||
/* Polling interval for determining when NIC application is alive */
|
||||
#define LIQUIDIO_STARTER_POLL_INTERVAL_MS 100
|
||||
|
||||
|
|
@ -530,36 +524,6 @@ static void liquidio_deinit_pci(void)
|
|||
pci_unregister_driver(&liquidio_pci_driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to check
|
||||
*/
|
||||
static inline int ifstate_check(struct lio *lio, int state_flag)
|
||||
{
|
||||
return atomic_read(&lio->ifstate) & state_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to set
|
||||
*/
|
||||
static inline void ifstate_set(struct lio *lio, int state_flag)
|
||||
{
|
||||
atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) | state_flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief clear interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to clear
|
||||
*/
|
||||
static inline void ifstate_reset(struct lio *lio, int state_flag)
|
||||
{
|
||||
atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) & ~(state_flag)));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Stop Tx queues
|
||||
* @param netdev network device
|
||||
|
|
@ -805,7 +769,7 @@ static int setup_glists(struct octeon_device *oct, struct lio *lio, int num_iqs)
|
|||
}
|
||||
|
||||
for (i = 0; i < num_iqs; i++) {
|
||||
int numa_node = cpu_to_node(i % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
spin_lock_init(&lio->glist_lock[i]);
|
||||
|
||||
|
|
@ -1084,16 +1048,35 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
int i;
|
||||
int num_ioq_vectors;
|
||||
int num_alloc_ioq_vectors;
|
||||
char *queue_irq_names = NULL;
|
||||
char *aux_irq_name = NULL;
|
||||
|
||||
if (OCTEON_CN23XX_PF(oct) && oct->msix_on) {
|
||||
oct->num_msix_irqs = oct->sriov_info.num_pf_rings;
|
||||
/* one non ioq interrupt for handling sli_mac_pf_int_sum */
|
||||
oct->num_msix_irqs += 1;
|
||||
|
||||
/* allocate storage for the names assigned to each irq */
|
||||
oct->irq_name_storage =
|
||||
kcalloc((MAX_IOQ_INTERRUPTS_PER_PF + 1), INTRNAMSIZ,
|
||||
GFP_KERNEL);
|
||||
if (!oct->irq_name_storage) {
|
||||
dev_err(&oct->pci_dev->dev, "Irq name storage alloc failed...\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
aux_irq_name = &queue_irq_names
|
||||
[IRQ_NAME_OFF(MAX_IOQ_INTERRUPTS_PER_PF)];
|
||||
|
||||
oct->msix_entries = kcalloc(
|
||||
oct->num_msix_irqs, sizeof(struct msix_entry), GFP_KERNEL);
|
||||
if (!oct->msix_entries)
|
||||
return 1;
|
||||
if (!oct->msix_entries) {
|
||||
dev_err(&oct->pci_dev->dev, "Memory Alloc failed...\n");
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msix_entries = (struct msix_entry *)oct->msix_entries;
|
||||
/*Assumption is that pf msix vectors start from pf srn to pf to
|
||||
|
|
@ -1111,7 +1094,9 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
dev_err(&oct->pci_dev->dev, "unable to Allocate MSI-X interrupts\n");
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
return 1;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return num_alloc_ioq_vectors;
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON: Enough MSI-X interrupts are allocated...\n");
|
||||
|
||||
|
|
@ -1119,9 +1104,12 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
|
||||
/** For PF, there is one non-ioq interrupt handler */
|
||||
num_ioq_vectors -= 1;
|
||||
|
||||
snprintf(aux_irq_name, INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-aux", oct->octeon_id, oct->pf_num);
|
||||
irqret = request_irq(msix_entries[num_ioq_vectors].vector,
|
||||
liquidio_legacy_intr_handler, 0, "octeon",
|
||||
oct);
|
||||
liquidio_legacy_intr_handler, 0,
|
||||
aux_irq_name, oct);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"OCTEON: Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
|
|
@ -1129,13 +1117,20 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
return 1;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ioq_vectors; i++) {
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(i)], INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->pf_num, i);
|
||||
|
||||
irqret = request_irq(msix_entries[i].vector,
|
||||
liquidio_msix_intr_handler, 0,
|
||||
"octeon", &oct->ioq_vector[i]);
|
||||
&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
&oct->ioq_vector[i]);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"OCTEON: Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
|
|
@ -1155,7 +1150,9 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
return 1;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
oct->ioq_vector[i].vector = msix_entries[i].vector;
|
||||
/* assign the cpu mask for this msix interrupt vector */
|
||||
|
|
@ -1173,15 +1170,29 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
else
|
||||
oct->flags |= LIO_FLAG_MSI_ENABLED;
|
||||
|
||||
/* allocate storage for the names assigned to the irq */
|
||||
oct->irq_name_storage = kcalloc(1, INTRNAMSIZ, GFP_KERNEL);
|
||||
if (!oct->irq_name_storage)
|
||||
return -ENOMEM;
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(0)], INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->pf_num, 0);
|
||||
|
||||
irqret = request_irq(oct->pci_dev->irq,
|
||||
liquidio_legacy_intr_handler, IRQF_SHARED,
|
||||
"octeon", oct);
|
||||
liquidio_legacy_intr_handler,
|
||||
IRQF_SHARED,
|
||||
&queue_irq_names[IRQ_NAME_OFF(0)], oct);
|
||||
if (irqret) {
|
||||
if (oct->flags & LIO_FLAG_MSI_ENABLED)
|
||||
pci_disable_msi(oct->pci_dev);
|
||||
dev_err(&oct->pci_dev->dev, "Request IRQ failed with code: %d\n",
|
||||
irqret);
|
||||
return 1;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1449,6 +1460,9 @@ static void octeon_destroy_resources(struct octeon_device *oct)
|
|||
pci_disable_msi(oct->pci_dev);
|
||||
}
|
||||
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
|
||||
/* fallthrough */
|
||||
case OCT_DEV_MSIX_ALLOC_VECTOR_DONE:
|
||||
if (OCTEON_CN23XX_PF(oct))
|
||||
|
|
@ -2211,8 +2225,8 @@ static void if_cfg_callback(struct octeon_device *oct,
|
|||
|
||||
oct = lio_get_device(ctx->octeon_id);
|
||||
if (resp->status)
|
||||
dev_err(&oct->pci_dev->dev, "nic if cfg instruction failed. Status: %llx\n",
|
||||
CVM_CAST64(resp->status));
|
||||
dev_err(&oct->pci_dev->dev, "nic if cfg instruction failed. Status: 0x%llx (0x%08x)\n",
|
||||
CVM_CAST64(resp->status), status);
|
||||
WRITE_ONCE(ctx->cond, 1);
|
||||
|
||||
snprintf(oct->fw_info.liquidio_firmware_version, 32, "%s",
|
||||
|
|
@ -2555,6 +2569,15 @@ static inline int setup_io_queues(struct octeon_device *octeon_dev,
|
|||
__func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (octeon_dev->ioq_vector) {
|
||||
struct octeon_ioq_vector *ioq_vector;
|
||||
|
||||
ioq_vector = &octeon_dev->ioq_vector[q];
|
||||
netif_set_xps_queue(netdev,
|
||||
&ioq_vector->affinity_mask,
|
||||
ioq_vector->iq_index);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -3596,7 +3619,8 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx,
|
|||
nctrl.ncmd.s.param2 = (is_admin_assigned ? 1 : 0);
|
||||
nctrl.ncmd.s.more = 1;
|
||||
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
|
||||
nctrl.cb_fn = 0;
|
||||
nctrl.netpndev = (u64)netdev;
|
||||
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
|
||||
nctrl.wait_time = LIO_CMD_WAIT_TM;
|
||||
|
||||
nctrl.udd[0] = 0;
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits");
|
|||
|
||||
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
|
||||
|
||||
/* Bit mask values for lio->ifstate */
|
||||
#define LIO_IFSTATE_DROQ_OPS 0x01
|
||||
#define LIO_IFSTATE_REGISTERED 0x02
|
||||
#define LIO_IFSTATE_RUNNING 0x04
|
||||
#define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08
|
||||
|
||||
struct liquidio_if_cfg_context {
|
||||
int octeon_id;
|
||||
|
||||
|
|
@ -335,36 +329,6 @@ static struct pci_driver liquidio_vf_pci_driver = {
|
|||
.err_handler = &liquidio_vf_err_handler, /* For AER */
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief check interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to check
|
||||
*/
|
||||
static int ifstate_check(struct lio *lio, int state_flag)
|
||||
{
|
||||
return atomic_read(&lio->ifstate) & state_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to set
|
||||
*/
|
||||
static void ifstate_set(struct lio *lio, int state_flag)
|
||||
{
|
||||
atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) | state_flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief clear interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to clear
|
||||
*/
|
||||
static void ifstate_reset(struct lio *lio, int state_flag)
|
||||
{
|
||||
atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) & ~(state_flag)));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Stop Tx queues
|
||||
* @param netdev network device
|
||||
|
|
@ -780,6 +744,7 @@ liquidio_msix_intr_handler(int irq __attribute__((unused)), void *dev)
|
|||
static int octeon_setup_interrupt(struct octeon_device *oct)
|
||||
{
|
||||
struct msix_entry *msix_entries;
|
||||
char *queue_irq_names = NULL;
|
||||
int num_alloc_ioq_vectors;
|
||||
int num_ioq_vectors;
|
||||
int irqret;
|
||||
|
|
@ -788,10 +753,25 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
if (oct->msix_on) {
|
||||
oct->num_msix_irqs = oct->sriov_info.rings_per_vf;
|
||||
|
||||
/* allocate storage for the names assigned to each irq */
|
||||
oct->irq_name_storage =
|
||||
kcalloc(MAX_IOQ_INTERRUPTS_PER_VF, INTRNAMSIZ,
|
||||
GFP_KERNEL);
|
||||
if (!oct->irq_name_storage) {
|
||||
dev_err(&oct->pci_dev->dev, "Irq name storage alloc failed...\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
|
||||
oct->msix_entries = kcalloc(
|
||||
oct->num_msix_irqs, sizeof(struct msix_entry), GFP_KERNEL);
|
||||
if (!oct->msix_entries)
|
||||
return 1;
|
||||
if (!oct->msix_entries) {
|
||||
dev_err(&oct->pci_dev->dev, "Memory Alloc failed...\n");
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msix_entries = (struct msix_entry *)oct->msix_entries;
|
||||
|
||||
|
|
@ -805,16 +785,23 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
dev_err(&oct->pci_dev->dev, "unable to Allocate MSI-X interrupts\n");
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
return 1;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return num_alloc_ioq_vectors;
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON: Enough MSI-X interrupts are allocated...\n");
|
||||
|
||||
num_ioq_vectors = oct->num_msix_irqs;
|
||||
|
||||
for (i = 0; i < num_ioq_vectors; i++) {
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(i)], INTRNAMSIZ,
|
||||
"LiquidIO%u-vf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->vf_num, i);
|
||||
|
||||
irqret = request_irq(msix_entries[i].vector,
|
||||
liquidio_msix_intr_handler, 0,
|
||||
"octeon", &oct->ioq_vector[i]);
|
||||
&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
&oct->ioq_vector[i]);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"OCTEON: Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
|
|
@ -830,7 +817,9 @@ static int octeon_setup_interrupt(struct octeon_device *oct)
|
|||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
return 1;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
oct->ioq_vector[i].vector = msix_entries[i].vector;
|
||||
/* assign the cpu mask for this msix interrupt vector */
|
||||
|
|
@ -975,6 +964,8 @@ static void octeon_destroy_resources(struct octeon_device *oct)
|
|||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
}
|
||||
/* Soft reset the octeon device before exiting */
|
||||
if (oct->pci_dev->reset_fn)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,11 @@ enum octeon_tag_type {
|
|||
|
||||
#define BYTES_PER_DHLEN_UNIT 8
|
||||
#define MAX_REG_CNT 2000000U
|
||||
#define INTRNAMSIZ 32
|
||||
#define IRQ_NAME_OFF(i) ((i) * INTRNAMSIZ)
|
||||
#define MAX_IOQ_INTERRUPTS_PER_PF (64 * 2)
|
||||
#define MAX_IOQ_INTERRUPTS_PER_VF (8 * 2)
|
||||
|
||||
|
||||
static inline u32 incr_index(u32 index, u32 count, u32 max)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -793,7 +793,7 @@ int octeon_setup_instr_queues(struct octeon_device *oct)
|
|||
u32 num_descs = 0;
|
||||
u32 iq_no = 0;
|
||||
union oct_txpciq txpciq;
|
||||
int numa_node = cpu_to_node(iq_no % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
if (OCTEON_CN6XXX(oct))
|
||||
num_descs =
|
||||
|
|
@ -837,7 +837,7 @@ int octeon_setup_output_queues(struct octeon_device *oct)
|
|||
u32 num_descs = 0;
|
||||
u32 desc_size = 0;
|
||||
u32 oq_no = 0;
|
||||
int numa_node = cpu_to_node(oq_no % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
if (OCTEON_CN6XXX(oct)) {
|
||||
num_descs =
|
||||
|
|
|
|||
|
|
@ -517,6 +517,9 @@ struct octeon_device {
|
|||
|
||||
void *msix_entries;
|
||||
|
||||
/* when requesting IRQs, the names are stored here */
|
||||
void *irq_name_storage;
|
||||
|
||||
struct octeon_sriov_info sriov_info;
|
||||
|
||||
struct octeon_pf_vf_hs_word pfvf_hsword;
|
||||
|
|
|
|||
|
|
@ -226,8 +226,7 @@ int octeon_init_droq(struct octeon_device *oct,
|
|||
struct octeon_droq *droq;
|
||||
u32 desc_ring_size = 0, c_num_descs = 0, c_buf_size = 0;
|
||||
u32 c_pkts_per_intr = 0, c_refill_threshold = 0;
|
||||
int orig_node = dev_to_node(&oct->pci_dev->dev);
|
||||
int numa_node = cpu_to_node(q_no % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
dev_dbg(&oct->pci_dev->dev, "%s[%d]\n", __func__, q_no);
|
||||
|
||||
|
|
@ -267,13 +266,8 @@ int octeon_init_droq(struct octeon_device *oct,
|
|||
droq->buffer_size = c_buf_size;
|
||||
|
||||
desc_ring_size = droq->max_count * OCT_DROQ_DESC_SIZE;
|
||||
set_dev_node(&oct->pci_dev->dev, numa_node);
|
||||
droq->desc_ring = lio_dma_alloc(oct, desc_ring_size,
|
||||
(dma_addr_t *)&droq->desc_ring_dma);
|
||||
set_dev_node(&oct->pci_dev->dev, orig_node);
|
||||
if (!droq->desc_ring)
|
||||
droq->desc_ring = lio_dma_alloc(oct, desc_ring_size,
|
||||
(dma_addr_t *)&droq->desc_ring_dma);
|
||||
|
||||
if (!droq->desc_ring) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
|
|
@ -970,7 +964,7 @@ int octeon_create_droq(struct octeon_device *oct,
|
|||
u32 desc_size, void *app_ctx)
|
||||
{
|
||||
struct octeon_droq *droq;
|
||||
int numa_node = cpu_to_node(q_no % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
if (oct->droq[q_no]) {
|
||||
dev_dbg(&oct->pci_dev->dev, "Droq already in use. Cannot create droq %d again\n",
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ struct octeon_instr_queue {
|
|||
struct oct_iq_stats stats;
|
||||
|
||||
/** DMA mapped base address of the input descriptor ring. */
|
||||
u64 base_addr_dma;
|
||||
dma_addr_t base_addr_dma;
|
||||
|
||||
/** Application context */
|
||||
void *app_ctx;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@
|
|||
#define LIO_MAX_MTU_SIZE (OCTNET_MAX_FRM_SIZE - OCTNET_FRM_HEADER_SIZE)
|
||||
#define LIO_MIN_MTU_SIZE ETH_MIN_MTU
|
||||
|
||||
/* Bit mask values for lio->ifstate */
|
||||
#define LIO_IFSTATE_DROQ_OPS 0x01
|
||||
#define LIO_IFSTATE_REGISTERED 0x02
|
||||
#define LIO_IFSTATE_RUNNING 0x04
|
||||
#define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08
|
||||
|
||||
struct oct_nic_stats_resp {
|
||||
u64 rh;
|
||||
struct oct_link_stats stats;
|
||||
|
|
@ -438,4 +444,34 @@ static inline void octeon_fast_packet_next(struct octeon_droq *droq,
|
|||
get_rbd(droq->recv_buf_list[idx].buffer), copy_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to check
|
||||
*/
|
||||
static inline int ifstate_check(struct lio *lio, int state_flag)
|
||||
{
|
||||
return atomic_read(&lio->ifstate) & state_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to set
|
||||
*/
|
||||
static inline void ifstate_set(struct lio *lio, int state_flag)
|
||||
{
|
||||
atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) | state_flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief clear interface state
|
||||
* @param lio per-network private data
|
||||
* @param state_flag flag state to clear
|
||||
*/
|
||||
static inline void ifstate_reset(struct lio *lio, int state_flag)
|
||||
{
|
||||
atomic_set(&lio->ifstate, (atomic_read(&lio->ifstate) & ~(state_flag)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,8 +62,7 @@ int octeon_init_instr_queue(struct octeon_device *oct,
|
|||
u32 iq_no = (u32)txpciq.s.q_no;
|
||||
u32 q_size;
|
||||
struct cavium_wq *db_wq;
|
||||
int orig_node = dev_to_node(&oct->pci_dev->dev);
|
||||
int numa_node = cpu_to_node(iq_no % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
if (OCTEON_CN6XXX(oct))
|
||||
conf = &(CFG_GET_IQ_CFG(CHIP_CONF(oct, cn6xxx)));
|
||||
|
|
@ -91,13 +90,7 @@ int octeon_init_instr_queue(struct octeon_device *oct,
|
|||
|
||||
iq->oct_dev = oct;
|
||||
|
||||
set_dev_node(&oct->pci_dev->dev, numa_node);
|
||||
iq->base_addr = lio_dma_alloc(oct, q_size,
|
||||
(dma_addr_t *)&iq->base_addr_dma);
|
||||
set_dev_node(&oct->pci_dev->dev, orig_node);
|
||||
if (!iq->base_addr)
|
||||
iq->base_addr = lio_dma_alloc(oct, q_size,
|
||||
(dma_addr_t *)&iq->base_addr_dma);
|
||||
iq->base_addr = lio_dma_alloc(oct, q_size, &iq->base_addr_dma);
|
||||
if (!iq->base_addr) {
|
||||
dev_err(&oct->pci_dev->dev, "Cannot allocate memory for instr queue %d\n",
|
||||
iq_no);
|
||||
|
|
@ -211,7 +204,7 @@ int octeon_setup_iq(struct octeon_device *oct,
|
|||
void *app_ctx)
|
||||
{
|
||||
u32 iq_no = (u32)txpciq.s.q_no;
|
||||
int numa_node = cpu_to_node(iq_no % num_online_cpus());
|
||||
int numa_node = dev_to_node(&oct->pci_dev->dev);
|
||||
|
||||
if (oct->instr_queue[iq_no]) {
|
||||
dev_dbg(&oct->pci_dev->dev, "IQ is in use. Cannot create the IQ: %d again\n",
|
||||
|
|
|
|||
|
|
@ -69,50 +69,53 @@ int lio_process_ordered_list(struct octeon_device *octeon_dev,
|
|||
int resp_to_process = MAX_ORD_REQS_TO_PROCESS;
|
||||
u32 status;
|
||||
u64 status64;
|
||||
struct octeon_instr_rdp *rdp;
|
||||
u64 rptr;
|
||||
|
||||
ordered_sc_list = &octeon_dev->response_list[OCTEON_ORDERED_SC_LIST];
|
||||
|
||||
do {
|
||||
spin_lock_bh(&ordered_sc_list->lock);
|
||||
|
||||
if (ordered_sc_list->head.next == &ordered_sc_list->head) {
|
||||
if (list_empty(&ordered_sc_list->head)) {
|
||||
spin_unlock_bh(&ordered_sc_list->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sc = (struct octeon_soft_command *)ordered_sc_list->
|
||||
head.next;
|
||||
if (OCTEON_CN23XX_PF(octeon_dev) ||
|
||||
OCTEON_CN23XX_VF(octeon_dev)) {
|
||||
rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd3.rdp;
|
||||
rptr = sc->cmd.cmd3.rptr;
|
||||
} else {
|
||||
rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd2.rdp;
|
||||
rptr = sc->cmd.cmd2.rptr;
|
||||
}
|
||||
sc = list_first_entry(&ordered_sc_list->head,
|
||||
struct octeon_soft_command, node);
|
||||
|
||||
status = OCTEON_REQUEST_PENDING;
|
||||
|
||||
/* check if octeon has finished DMA'ing a response
|
||||
* to where rptr is pointing to
|
||||
*/
|
||||
dma_sync_single_for_cpu(&octeon_dev->pci_dev->dev,
|
||||
rptr, rdp->rlen,
|
||||
DMA_FROM_DEVICE);
|
||||
status64 = *sc->status_word;
|
||||
|
||||
if (status64 != COMPLETION_WORD_INIT) {
|
||||
/* This logic ensures that all 64b have been written.
|
||||
* 1. check byte 0 for non-FF
|
||||
* 2. if non-FF, then swap result from BE to host order
|
||||
* 3. check byte 7 (swapped to 0) for non-FF
|
||||
* 4. if non-FF, use the low 32-bit status code
|
||||
* 5. if either byte 0 or byte 7 is FF, don't use status
|
||||
*/
|
||||
if ((status64 & 0xff) != 0xff) {
|
||||
octeon_swap_8B_data(&status64, 1);
|
||||
if (((status64 & 0xff) != 0xff)) {
|
||||
status = (u32)(status64 &
|
||||
0xffffffffULL);
|
||||
/* retrieve 16-bit firmware status */
|
||||
status = (u32)(status64 & 0xffffULL);
|
||||
if (status) {
|
||||
status =
|
||||
FIRMWARE_STATUS_CODE(status);
|
||||
} else {
|
||||
/* i.e. no error */
|
||||
status = OCTEON_REQUEST_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (force_quit || (sc->timeout &&
|
||||
time_after(jiffies, (unsigned long)sc->timeout))) {
|
||||
dev_err(&octeon_dev->pci_dev->dev, "%s: cmd failed, timeout (%ld, %ld)\n",
|
||||
__func__, (long)jiffies, (long)sc->timeout);
|
||||
status = OCTEON_REQUEST_TIMEOUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ enum {
|
|||
|
||||
/*------------ Error codes used by host driver -----------------*/
|
||||
#define DRIVER_MAJOR_ERROR_CODE 0x0000
|
||||
/*------ Error codes used by firmware (bits 15..0 set by firmware */
|
||||
#define FIRMWARE_MAJOR_ERROR_CODE 0x0001
|
||||
|
||||
/** A value of 0x00000000 indicates no error i.e. success */
|
||||
#define DRIVER_ERROR_NONE 0x00000000
|
||||
|
|
@ -116,6 +118,9 @@ enum {
|
|||
|
||||
};
|
||||
|
||||
#define FIRMWARE_STATUS_CODE(status) \
|
||||
((FIRMWARE_MAJOR_ERROR_CODE << 16) | (status))
|
||||
|
||||
/** Initialize the response lists. The number of response lists to create is
|
||||
* given by count.
|
||||
* @param octeon_dev - the octeon device structure.
|
||||
|
|
|
|||
|
|
@ -1148,14 +1148,14 @@ static int ethoc_probe(struct platform_device *pdev)
|
|||
|
||||
/* Allow the platform setup code to pass in a MAC address. */
|
||||
if (pdata) {
|
||||
memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
|
||||
ether_addr_copy(netdev->dev_addr, pdata->hwaddr);
|
||||
priv->phy_id = pdata->phy_id;
|
||||
} else {
|
||||
const void *mac;
|
||||
|
||||
mac = of_get_mac_address(pdev->dev.of_node);
|
||||
if (mac)
|
||||
memcpy(netdev->dev_addr, mac, IFHWADDRLEN);
|
||||
ether_addr_copy(netdev->dev_addr, mac);
|
||||
priv->phy_id = -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,13 @@ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
|
|||
/* L4 Type field: TCP */
|
||||
#define FM_L4_PARSE_RESULT_TCP 0x20
|
||||
|
||||
/* FD status field indicating whether the FM Parser has attempted to validate
|
||||
* the L4 csum of the frame.
|
||||
* Note that having this bit set doesn't necessarily imply that the checksum
|
||||
* is valid. One would have to check the parse results to find that out.
|
||||
*/
|
||||
#define FM_FD_STAT_L4CV 0x00000004
|
||||
|
||||
#define DPAA_SGT_MAX_ENTRIES 16 /* maximum number of entries in SG Table */
|
||||
#define DPAA_BUFF_RELEASE_MAX 8 /* maximum number of buffers released at once */
|
||||
|
||||
|
|
@ -235,6 +242,7 @@ static int dpaa_netdev_init(struct net_device *net_dev,
|
|||
* For conformity, we'll still declare GSO explicitly.
|
||||
*/
|
||||
net_dev->features |= NETIF_F_GSO;
|
||||
net_dev->features |= NETIF_F_RXCSUM;
|
||||
|
||||
net_dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
|
||||
/* we do not want shared skbs on TX */
|
||||
|
|
@ -334,6 +342,45 @@ static void dpaa_get_stats64(struct net_device *net_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int dpaa_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto,
|
||||
struct tc_to_netdev *tc)
|
||||
{
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
u8 num_tc;
|
||||
int i;
|
||||
|
||||
if (tc->type != TC_SETUP_MQPRIO)
|
||||
return -EINVAL;
|
||||
|
||||
tc->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
num_tc = tc->mqprio->num_tc;
|
||||
|
||||
if (num_tc == priv->num_tc)
|
||||
return 0;
|
||||
|
||||
if (!num_tc) {
|
||||
netdev_reset_tc(net_dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (num_tc > DPAA_TC_NUM) {
|
||||
netdev_err(net_dev, "Too many traffic classes: max %d supported.\n",
|
||||
DPAA_TC_NUM);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
netdev_set_num_tc(net_dev, num_tc);
|
||||
|
||||
for (i = 0; i < num_tc; i++)
|
||||
netdev_set_tc_queue(net_dev, i, DPAA_TC_TXQ_NUM,
|
||||
i * DPAA_TC_TXQ_NUM);
|
||||
|
||||
out:
|
||||
priv->num_tc = num_tc ? : 1;
|
||||
netif_set_real_num_tx_queues(net_dev, priv->num_tc * DPAA_TC_TXQ_NUM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mac_device *dpaa_mac_dev_get(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *of_dev;
|
||||
|
|
@ -557,16 +604,18 @@ static void dpaa_bps_free(struct dpaa_priv *priv)
|
|||
|
||||
/* Use multiple WQs for FQ assignment:
|
||||
* - Tx Confirmation queues go to WQ1.
|
||||
* - Rx Error and Tx Error queues go to WQ2 (giving them a better chance
|
||||
* to be scheduled, in case there are many more FQs in WQ3).
|
||||
* - Rx Default and Tx queues go to WQ3 (no differentiation between
|
||||
* Rx and Tx traffic).
|
||||
* - Rx Error and Tx Error queues go to WQ5 (giving them a better chance
|
||||
* to be scheduled, in case there are many more FQs in WQ6).
|
||||
* - Rx Default goes to WQ6.
|
||||
* - Tx queues go to different WQs depending on their priority. Equal
|
||||
* chunks of NR_CPUS queues go to WQ6 (lowest priority), WQ2, WQ1 and
|
||||
* WQ0 (highest priority).
|
||||
* This ensures that Tx-confirmed buffers are timely released. In particular,
|
||||
* it avoids congestion on the Tx Confirm FQs, which can pile up PFDRs if they
|
||||
* are greatly outnumbered by other FQs in the system, while
|
||||
* dequeue scheduling is round-robin.
|
||||
*/
|
||||
static inline void dpaa_assign_wq(struct dpaa_fq *fq)
|
||||
static inline void dpaa_assign_wq(struct dpaa_fq *fq, int idx)
|
||||
{
|
||||
switch (fq->fq_type) {
|
||||
case FQ_TYPE_TX_CONFIRM:
|
||||
|
|
@ -575,11 +624,33 @@ static inline void dpaa_assign_wq(struct dpaa_fq *fq)
|
|||
break;
|
||||
case FQ_TYPE_RX_ERROR:
|
||||
case FQ_TYPE_TX_ERROR:
|
||||
fq->wq = 2;
|
||||
fq->wq = 5;
|
||||
break;
|
||||
case FQ_TYPE_RX_DEFAULT:
|
||||
fq->wq = 6;
|
||||
break;
|
||||
case FQ_TYPE_TX:
|
||||
fq->wq = 3;
|
||||
switch (idx / DPAA_TC_TXQ_NUM) {
|
||||
case 0:
|
||||
/* Low priority (best effort) */
|
||||
fq->wq = 6;
|
||||
break;
|
||||
case 1:
|
||||
/* Medium priority */
|
||||
fq->wq = 2;
|
||||
break;
|
||||
case 2:
|
||||
/* High priority */
|
||||
fq->wq = 1;
|
||||
break;
|
||||
case 3:
|
||||
/* Very high priority */
|
||||
fq->wq = 0;
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Too many TX FQs: more than %d!\n",
|
||||
DPAA_ETH_TXQ_NUM);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Invalid FQ type %d for FQID %d!\n",
|
||||
|
|
@ -607,7 +678,7 @@ static struct dpaa_fq *dpaa_fq_alloc(struct device *dev,
|
|||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dpaa_assign_wq(dpaa_fq + i);
|
||||
dpaa_assign_wq(dpaa_fq + i, i);
|
||||
|
||||
return dpaa_fq;
|
||||
}
|
||||
|
|
@ -985,7 +1056,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable)
|
|||
/* Initialization common to all ingress queues */
|
||||
if (dpaa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) {
|
||||
initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CONTEXTA);
|
||||
initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE);
|
||||
initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE |
|
||||
QM_FQCTRL_CTXASTASHING);
|
||||
initfq.fqd.context_a.stashing.exclusive =
|
||||
QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX |
|
||||
QM_STASHING_EXCL_ANNOTATION;
|
||||
|
|
@ -1055,9 +1127,9 @@ static int dpaa_fq_free(struct device *dev, struct list_head *list)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq,
|
||||
struct dpaa_fq *defq,
|
||||
struct dpaa_buffer_layout *buf_layout)
|
||||
static int dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq,
|
||||
struct dpaa_fq *defq,
|
||||
struct dpaa_buffer_layout *buf_layout)
|
||||
{
|
||||
struct fman_buffer_prefix_content buf_prefix_content;
|
||||
struct fman_port_params params;
|
||||
|
|
@ -1076,23 +1148,29 @@ static void dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq,
|
|||
params.specific_params.non_rx_params.dflt_fqid = defq->fqid;
|
||||
|
||||
err = fman_port_config(port, ¶ms);
|
||||
if (err)
|
||||
if (err) {
|
||||
pr_err("%s: fman_port_config failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fman_port_cfg_buf_prefix_content(port, &buf_prefix_content);
|
||||
if (err)
|
||||
if (err) {
|
||||
pr_err("%s: fman_port_cfg_buf_prefix_content failed\n",
|
||||
__func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fman_port_init(port);
|
||||
if (err)
|
||||
pr_err("%s: fm_port_init failed\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps,
|
||||
size_t count, struct dpaa_fq *errq,
|
||||
struct dpaa_fq *defq,
|
||||
struct dpaa_buffer_layout *buf_layout)
|
||||
static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps,
|
||||
size_t count, struct dpaa_fq *errq,
|
||||
struct dpaa_fq *defq,
|
||||
struct dpaa_buffer_layout *buf_layout)
|
||||
{
|
||||
struct fman_buffer_prefix_content buf_prefix_content;
|
||||
struct fman_port_rx_params *rx_p;
|
||||
|
|
@ -1120,32 +1198,44 @@ static void dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps,
|
|||
}
|
||||
|
||||
err = fman_port_config(port, ¶ms);
|
||||
if (err)
|
||||
if (err) {
|
||||
pr_err("%s: fman_port_config failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fman_port_cfg_buf_prefix_content(port, &buf_prefix_content);
|
||||
if (err)
|
||||
if (err) {
|
||||
pr_err("%s: fman_port_cfg_buf_prefix_content failed\n",
|
||||
__func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fman_port_init(port);
|
||||
if (err)
|
||||
pr_err("%s: fm_port_init failed\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dpaa_eth_init_ports(struct mac_device *mac_dev,
|
||||
struct dpaa_bp **bps, size_t count,
|
||||
struct fm_port_fqs *port_fqs,
|
||||
struct dpaa_buffer_layout *buf_layout,
|
||||
struct device *dev)
|
||||
static int dpaa_eth_init_ports(struct mac_device *mac_dev,
|
||||
struct dpaa_bp **bps, size_t count,
|
||||
struct fm_port_fqs *port_fqs,
|
||||
struct dpaa_buffer_layout *buf_layout,
|
||||
struct device *dev)
|
||||
{
|
||||
struct fman_port *rxport = mac_dev->port[RX];
|
||||
struct fman_port *txport = mac_dev->port[TX];
|
||||
int err;
|
||||
|
||||
dpaa_eth_init_tx_port(txport, port_fqs->tx_errq,
|
||||
port_fqs->tx_defq, &buf_layout[TX]);
|
||||
dpaa_eth_init_rx_port(rxport, bps, count, port_fqs->rx_errq,
|
||||
port_fqs->rx_defq, &buf_layout[RX]);
|
||||
err = dpaa_eth_init_tx_port(txport, port_fqs->tx_errq,
|
||||
port_fqs->tx_defq, &buf_layout[TX]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = dpaa_eth_init_rx_port(rxport, bps, count, port_fqs->rx_errq,
|
||||
port_fqs->rx_defq, &buf_layout[RX]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dpaa_bman_release(const struct dpaa_bp *dpaa_bp,
|
||||
|
|
@ -1526,6 +1616,23 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
|
|||
return skb;
|
||||
}
|
||||
|
||||
static u8 rx_csum_offload(const struct dpaa_priv *priv, const struct qm_fd *fd)
|
||||
{
|
||||
/* The parser has run and performed L4 checksum validation.
|
||||
* We know there were no parser errors (and implicitly no
|
||||
* L4 csum error), otherwise we wouldn't be here.
|
||||
*/
|
||||
if ((priv->net_dev->features & NETIF_F_RXCSUM) &&
|
||||
(be32_to_cpu(fd->status) & FM_FD_STAT_L4CV))
|
||||
return CHECKSUM_UNNECESSARY;
|
||||
|
||||
/* We're here because either the parser didn't run or the L4 checksum
|
||||
* was not verified. This may include the case of a UDP frame with
|
||||
* checksum zero or an L4 proto other than TCP/UDP
|
||||
*/
|
||||
return CHECKSUM_NONE;
|
||||
}
|
||||
|
||||
/* Build a linear skb around the received buffer.
|
||||
* We are guaranteed there is enough room at the end of the data buffer to
|
||||
* accommodate the shared info area of the skb.
|
||||
|
|
@ -1556,7 +1663,7 @@ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
|
|||
skb_reserve(skb, fd_off);
|
||||
skb_put(skb, qm_fd_get_length(fd));
|
||||
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
skb->ip_summed = rx_csum_offload(priv, fd);
|
||||
|
||||
return skb;
|
||||
|
||||
|
|
@ -1616,7 +1723,7 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
|
|||
if (WARN_ON(unlikely(!skb)))
|
||||
goto free_buffers;
|
||||
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
skb->ip_summed = rx_csum_offload(priv, fd);
|
||||
|
||||
/* Make sure forwarded skbs will have enough space
|
||||
* on Tx, if extra headers are added.
|
||||
|
|
@ -2093,7 +2200,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
|
|||
dma_addr_t addr = qm_fd_addr(fd);
|
||||
enum qm_fd_format fd_format;
|
||||
struct net_device *net_dev;
|
||||
u32 fd_status = fd->status;
|
||||
u32 fd_status;
|
||||
struct dpaa_bp *dpaa_bp;
|
||||
struct dpaa_priv *priv;
|
||||
unsigned int skb_len;
|
||||
|
|
@ -2350,6 +2457,7 @@ static const struct net_device_ops dpaa_ops = {
|
|||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_rx_mode = dpaa_set_rx_mode,
|
||||
.ndo_do_ioctl = dpaa_ioctl,
|
||||
.ndo_setup_tc = dpaa_setup_tc,
|
||||
};
|
||||
|
||||
static int dpaa_napi_add(struct net_device *net_dev)
|
||||
|
|
@ -2624,8 +2732,10 @@ static int dpaa_eth_probe(struct platform_device *pdev)
|
|||
priv->rx_headroom = dpaa_get_headroom(&priv->buf_layout[RX]);
|
||||
|
||||
/* All real interfaces need their ports initialized */
|
||||
dpaa_eth_init_ports(mac_dev, dpaa_bps, DPAA_BPS_NUM, &port_fqs,
|
||||
&priv->buf_layout[0], dev);
|
||||
err = dpaa_eth_init_ports(mac_dev, dpaa_bps, DPAA_BPS_NUM, &port_fqs,
|
||||
&priv->buf_layout[0], dev);
|
||||
if (err)
|
||||
goto init_ports_failed;
|
||||
|
||||
priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv);
|
||||
if (!priv->percpu_priv) {
|
||||
|
|
@ -2638,6 +2748,9 @@ static int dpaa_eth_probe(struct platform_device *pdev)
|
|||
memset(percpu_priv, 0, sizeof(*percpu_priv));
|
||||
}
|
||||
|
||||
priv->num_tc = 1;
|
||||
netif_set_real_num_tx_queues(net_dev, priv->num_tc * DPAA_TC_TXQ_NUM);
|
||||
|
||||
/* Initialize NAPI */
|
||||
err = dpaa_napi_add(net_dev);
|
||||
if (err < 0)
|
||||
|
|
@ -2658,6 +2771,7 @@ static int dpaa_eth_probe(struct platform_device *pdev)
|
|||
napi_add_failed:
|
||||
dpaa_napi_del(net_dev);
|
||||
alloc_percpu_failed:
|
||||
init_ports_failed:
|
||||
dpaa_fq_free(dev, &priv->dpaa_fq_list);
|
||||
fq_alloc_failed:
|
||||
qman_delete_cgr_safe(&priv->ingress_cgr);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,12 @@
|
|||
#include "mac.h"
|
||||
#include "dpaa_eth_trace.h"
|
||||
|
||||
#define DPAA_ETH_TXQ_NUM NR_CPUS
|
||||
/* Number of prioritised traffic classes */
|
||||
#define DPAA_TC_NUM 4
|
||||
/* Number of Tx queues per traffic class */
|
||||
#define DPAA_TC_TXQ_NUM NR_CPUS
|
||||
/* Total number of Tx queues */
|
||||
#define DPAA_ETH_TXQ_NUM (DPAA_TC_NUM * DPAA_TC_TXQ_NUM)
|
||||
|
||||
#define DPAA_BPS_NUM 3 /* number of bpools per interface */
|
||||
|
||||
|
|
@ -152,6 +157,7 @@ struct dpaa_priv {
|
|||
u16 channel;
|
||||
struct list_head dpaa_fq_list;
|
||||
|
||||
u8 num_tc;
|
||||
u32 msg_enable; /* net_device message level */
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#define DMA_OFFSET 0x000C2000
|
||||
#define FPM_OFFSET 0x000C3000
|
||||
#define IMEM_OFFSET 0x000C4000
|
||||
#define HWP_OFFSET 0x000C7000
|
||||
#define CGP_OFFSET 0x000DB000
|
||||
|
||||
/* Exceptions bit map */
|
||||
|
|
@ -218,6 +219,9 @@
|
|||
|
||||
#define QMI_GS_HALT_NOT_BUSY 0x00000002
|
||||
|
||||
/* HWP defines */
|
||||
#define HWP_RPIMAC_PEN 0x00000001
|
||||
|
||||
/* IRAM defines */
|
||||
#define IRAM_IADD_AIE 0x80000000
|
||||
#define IRAM_READY 0x80000000
|
||||
|
|
@ -475,6 +479,12 @@ struct fman_dma_regs {
|
|||
u32 res00e0[0x400 - 56];
|
||||
};
|
||||
|
||||
struct fman_hwp_regs {
|
||||
u32 res0000[0x844 / 4]; /* 0x000..0x843 */
|
||||
u32 fmprrpimac; /* FM Parser Internal memory access control */
|
||||
u32 res[(0x1000 - 0x848) / 4]; /* 0x848..0xFFF */
|
||||
};
|
||||
|
||||
/* Structure that holds current FMan state.
|
||||
* Used for saving run time information.
|
||||
*/
|
||||
|
|
@ -606,6 +616,7 @@ struct fman {
|
|||
struct fman_bmi_regs __iomem *bmi_regs;
|
||||
struct fman_qmi_regs __iomem *qmi_regs;
|
||||
struct fman_dma_regs __iomem *dma_regs;
|
||||
struct fman_hwp_regs __iomem *hwp_regs;
|
||||
fman_exceptions_cb *exception_cb;
|
||||
fman_bus_error_cb *bus_error_cb;
|
||||
/* Spinlock for FMan use */
|
||||
|
|
@ -999,6 +1010,12 @@ static void qmi_init(struct fman_qmi_regs __iomem *qmi_rg,
|
|||
iowrite32be(tmp_reg, &qmi_rg->fmqm_ien);
|
||||
}
|
||||
|
||||
static void hwp_init(struct fman_hwp_regs __iomem *hwp_rg)
|
||||
{
|
||||
/* enable HW Parser */
|
||||
iowrite32be(HWP_RPIMAC_PEN, &hwp_rg->fmprrpimac);
|
||||
}
|
||||
|
||||
static int enable(struct fman *fman, struct fman_cfg *cfg)
|
||||
{
|
||||
u32 cfg_reg = 0;
|
||||
|
|
@ -1195,7 +1212,7 @@ static int fill_soc_specific_params(struct fman_state_struct *state)
|
|||
state->max_num_of_open_dmas = 32;
|
||||
state->fm_port_num_of_cg = 256;
|
||||
state->num_of_rx_ports = 6;
|
||||
state->total_fifo_size = 122 * 1024;
|
||||
state->total_fifo_size = 136 * 1024;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
|
@ -1793,6 +1810,7 @@ static int fman_config(struct fman *fman)
|
|||
fman->bmi_regs = base_addr + BMI_OFFSET;
|
||||
fman->qmi_regs = base_addr + QMI_OFFSET;
|
||||
fman->dma_regs = base_addr + DMA_OFFSET;
|
||||
fman->hwp_regs = base_addr + HWP_OFFSET;
|
||||
fman->base_addr = base_addr;
|
||||
|
||||
spin_lock_init(&fman->spinlock);
|
||||
|
|
@ -2062,6 +2080,9 @@ static int fman_init(struct fman *fman)
|
|||
/* Init QMI Registers */
|
||||
qmi_init(fman->qmi_regs, fman->cfg);
|
||||
|
||||
/* Init HW Parser */
|
||||
hwp_init(fman->hwp_regs);
|
||||
|
||||
err = enable(fman, cfg);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -134,14 +134,14 @@ enum fman_exceptions {
|
|||
struct fman_prs_result {
|
||||
u8 lpid; /* Logical port id */
|
||||
u8 shimr; /* Shim header result */
|
||||
u16 l2r; /* Layer 2 result */
|
||||
u16 l3r; /* Layer 3 result */
|
||||
__be16 l2r; /* Layer 2 result */
|
||||
__be16 l3r; /* Layer 3 result */
|
||||
u8 l4r; /* Layer 4 result */
|
||||
u8 cplan; /* Classification plan id */
|
||||
u16 nxthdr; /* Next Header */
|
||||
u16 cksum; /* Running-sum */
|
||||
__be16 nxthdr; /* Next Header */
|
||||
__be16 cksum; /* Running-sum */
|
||||
/* Flags&fragment-offset field of the last IP-header */
|
||||
u16 flags_frag_off;
|
||||
__be16 flags_frag_off;
|
||||
/* Routing type field of a IPV6 routing extension header */
|
||||
u8 route_type;
|
||||
/* Routing Extension Header Present; last bit is IP valid */
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
|
||||
#define BMI_PORT_REGS_OFFSET 0
|
||||
#define QMI_PORT_REGS_OFFSET 0x400
|
||||
#define HWP_PORT_REGS_OFFSET 0x800
|
||||
|
||||
/* Default values */
|
||||
#define DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN \
|
||||
|
|
@ -182,7 +183,7 @@
|
|||
#define NIA_ENG_BMI 0x00500000
|
||||
#define NIA_ENG_QMI_ENQ 0x00540000
|
||||
#define NIA_ENG_QMI_DEQ 0x00580000
|
||||
|
||||
#define NIA_ENG_HWP 0x00440000
|
||||
#define NIA_BMI_AC_ENQ_FRAME 0x00000002
|
||||
#define NIA_BMI_AC_TX_RELEASE 0x000002C0
|
||||
#define NIA_BMI_AC_RELEASE 0x000000C0
|
||||
|
|
@ -317,6 +318,19 @@ struct fman_port_qmi_regs {
|
|||
u32 fmqm_pndcc; /* PortID n Dequeue Confirm Counter */
|
||||
};
|
||||
|
||||
#define HWP_HXS_COUNT 16
|
||||
#define HWP_HXS_PHE_REPORT 0x00000800
|
||||
#define HWP_HXS_PCAC_PSTAT 0x00000100
|
||||
#define HWP_HXS_PCAC_PSTOP 0x00000001
|
||||
struct fman_port_hwp_regs {
|
||||
struct {
|
||||
u32 ssa; /* Soft Sequence Attachment */
|
||||
u32 lcv; /* Line-up Enable Confirmation Mask */
|
||||
} pmda[HWP_HXS_COUNT]; /* Parse Memory Direct Access Registers */
|
||||
u32 reserved080[(0x3f8 - 0x080) / 4]; /* (0x080-0x3f7) */
|
||||
u32 fmpr_pcac; /* Configuration Access Control */
|
||||
};
|
||||
|
||||
/* QMI dequeue prefetch modes */
|
||||
enum fman_port_deq_prefetch {
|
||||
FMAN_PORT_DEQ_NO_PREFETCH, /* No prefetch mode */
|
||||
|
|
@ -436,6 +450,7 @@ struct fman_port {
|
|||
|
||||
union fman_port_bmi_regs __iomem *bmi_regs;
|
||||
struct fman_port_qmi_regs __iomem *qmi_regs;
|
||||
struct fman_port_hwp_regs __iomem *hwp_regs;
|
||||
|
||||
struct fman_sp_buffer_offsets buffer_offsets;
|
||||
|
||||
|
|
@ -521,9 +536,12 @@ static int init_bmi_rx(struct fman_port *port)
|
|||
/* NIA */
|
||||
tmp = (u32)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
|
||||
|
||||
tmp |= NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME;
|
||||
tmp |= NIA_ENG_HWP;
|
||||
iowrite32be(tmp, ®s->fmbm_rfne);
|
||||
|
||||
/* Parser Next Engine NIA */
|
||||
iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME, ®s->fmbm_rfpne);
|
||||
|
||||
/* Enqueue NIA */
|
||||
iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_rfene);
|
||||
|
||||
|
|
@ -665,6 +683,50 @@ static int init_qmi(struct fman_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void stop_port_hwp(struct fman_port *port)
|
||||
{
|
||||
struct fman_port_hwp_regs __iomem *regs = port->hwp_regs;
|
||||
int cnt = 100;
|
||||
|
||||
iowrite32be(HWP_HXS_PCAC_PSTOP, ®s->fmpr_pcac);
|
||||
|
||||
while (cnt-- > 0 &&
|
||||
(ioread32be(®s->fmpr_pcac) & HWP_HXS_PCAC_PSTAT))
|
||||
udelay(10);
|
||||
if (!cnt)
|
||||
pr_err("Timeout stopping HW Parser\n");
|
||||
}
|
||||
|
||||
static void start_port_hwp(struct fman_port *port)
|
||||
{
|
||||
struct fman_port_hwp_regs __iomem *regs = port->hwp_regs;
|
||||
int cnt = 100;
|
||||
|
||||
iowrite32be(0, ®s->fmpr_pcac);
|
||||
|
||||
while (cnt-- > 0 &&
|
||||
!(ioread32be(®s->fmpr_pcac) & HWP_HXS_PCAC_PSTAT))
|
||||
udelay(10);
|
||||
if (!cnt)
|
||||
pr_err("Timeout starting HW Parser\n");
|
||||
}
|
||||
|
||||
static void init_hwp(struct fman_port *port)
|
||||
{
|
||||
struct fman_port_hwp_regs __iomem *regs = port->hwp_regs;
|
||||
int i;
|
||||
|
||||
stop_port_hwp(port);
|
||||
|
||||
for (i = 0; i < HWP_HXS_COUNT; i++) {
|
||||
/* enable HXS error reporting into FD[STATUS] PHE */
|
||||
iowrite32be(0x00000000, ®s->pmda[i].ssa);
|
||||
iowrite32be(0xffffffff, ®s->pmda[i].lcv);
|
||||
}
|
||||
|
||||
start_port_hwp(port);
|
||||
}
|
||||
|
||||
static int init(struct fman_port *port)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -673,6 +735,8 @@ static int init(struct fman_port *port)
|
|||
switch (port->port_type) {
|
||||
case FMAN_PORT_TYPE_RX:
|
||||
err = init_bmi_rx(port);
|
||||
if (!err)
|
||||
init_hwp(port);
|
||||
break;
|
||||
case FMAN_PORT_TYPE_TX:
|
||||
err = init_bmi_tx(port);
|
||||
|
|
@ -686,7 +750,8 @@ static int init(struct fman_port *port)
|
|||
|
||||
/* Init QMI registers */
|
||||
err = init_qmi(port);
|
||||
return err;
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1247,7 +1312,7 @@ int fman_port_config(struct fman_port *port, struct fman_port_params *params)
|
|||
/* Allocate the FM driver's parameters structure */
|
||||
port->cfg = kzalloc(sizeof(*port->cfg), GFP_KERNEL);
|
||||
if (!port->cfg)
|
||||
goto err_params;
|
||||
return -EINVAL;
|
||||
|
||||
/* Initialize FM port parameters which will be kept by the driver */
|
||||
port->port_type = port->dts_params.type;
|
||||
|
|
@ -1276,6 +1341,7 @@ int fman_port_config(struct fman_port *port, struct fman_port_params *params)
|
|||
/* set memory map pointers */
|
||||
port->bmi_regs = base_addr + BMI_PORT_REGS_OFFSET;
|
||||
port->qmi_regs = base_addr + QMI_PORT_REGS_OFFSET;
|
||||
port->hwp_regs = base_addr + HWP_PORT_REGS_OFFSET;
|
||||
|
||||
port->max_frame_length = DFLT_PORT_MAX_FRAME_LENGTH;
|
||||
/* resource distribution. */
|
||||
|
|
@ -1327,8 +1393,6 @@ int fman_port_config(struct fman_port *port, struct fman_port_params *params)
|
|||
|
||||
err_port_cfg:
|
||||
kfree(port->cfg);
|
||||
err_params:
|
||||
kfree(port);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(fman_port_config);
|
||||
|
|
|
|||
|
|
@ -38,12 +38,6 @@
|
|||
#include <asm/irq.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#ifdef CONFIG_8xx
|
||||
#include <asm/8xx_immap.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/cpm1.h>
|
||||
#endif
|
||||
|
||||
#include "fs_enet.h"
|
||||
#include "fec.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -37,12 +37,6 @@
|
|||
#include <asm/irq.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#ifdef CONFIG_8xx
|
||||
#include <asm/8xx_immap.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/cpm1.h>
|
||||
#endif
|
||||
|
||||
#include "fs_enet.h"
|
||||
|
||||
/*************************************************/
|
||||
|
|
|
|||
|
|
@ -110,6 +110,11 @@ static int ibmvnic_poll(struct napi_struct *napi, int data);
|
|||
static void send_map_query(struct ibmvnic_adapter *adapter);
|
||||
static void send_request_map(struct ibmvnic_adapter *, dma_addr_t, __be32, u8);
|
||||
static void send_request_unmap(struct ibmvnic_adapter *, u8);
|
||||
static void send_login(struct ibmvnic_adapter *adapter);
|
||||
static void send_cap_queries(struct ibmvnic_adapter *adapter);
|
||||
static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
|
||||
static int ibmvnic_init(struct ibmvnic_adapter *);
|
||||
static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *);
|
||||
|
||||
struct ibmvnic_stat {
|
||||
char name[ETH_GSTRING_LEN];
|
||||
|
|
@ -368,6 +373,38 @@ static void free_rx_pool(struct ibmvnic_adapter *adapter,
|
|||
pool->rx_buff = NULL;
|
||||
}
|
||||
|
||||
static int ibmvnic_login(struct net_device *netdev)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
unsigned long timeout = msecs_to_jiffies(30000);
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
|
||||
do {
|
||||
if (adapter->renegotiate) {
|
||||
adapter->renegotiate = false;
|
||||
release_sub_crqs_no_irqs(adapter);
|
||||
|
||||
reinit_completion(&adapter->init_done);
|
||||
send_cap_queries(adapter);
|
||||
if (!wait_for_completion_timeout(&adapter->init_done,
|
||||
timeout)) {
|
||||
dev_err(dev, "Capabilities query timeout\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
reinit_completion(&adapter->init_done);
|
||||
send_login(adapter);
|
||||
if (!wait_for_completion_timeout(&adapter->init_done,
|
||||
timeout)) {
|
||||
dev_err(dev, "Login timeout\n");
|
||||
return -1;
|
||||
}
|
||||
} while (adapter->renegotiate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmvnic_open(struct net_device *netdev)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
|
|
@ -377,8 +414,31 @@ static int ibmvnic_open(struct net_device *netdev)
|
|||
int rxadd_subcrqs;
|
||||
u64 *size_array;
|
||||
int tx_subcrqs;
|
||||
int rc = 0;
|
||||
int i, j;
|
||||
|
||||
if (adapter->is_closed) {
|
||||
rc = ibmvnic_init(adapter);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ibmvnic_login(netdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = netif_set_real_num_tx_queues(netdev, adapter->req_tx_queues);
|
||||
if (rc) {
|
||||
dev_err(dev, "failed to set the number of tx queues\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = init_sub_crq_irqs(adapter);
|
||||
if (rc) {
|
||||
dev_err(dev, "failed to initialize sub crq irqs\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rxadd_subcrqs =
|
||||
be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
|
||||
tx_subcrqs =
|
||||
|
|
@ -473,6 +533,7 @@ static int ibmvnic_open(struct net_device *netdev)
|
|||
ibmvnic_send_crq(adapter, &crq);
|
||||
|
||||
netif_tx_start_all_queues(netdev);
|
||||
adapter->is_closed = false;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -508,24 +569,16 @@ static int ibmvnic_open(struct net_device *netdev)
|
|||
for (i = 0; i < adapter->req_rx_queues; i++)
|
||||
napi_disable(&adapter->napi[i]);
|
||||
alloc_napi_failed:
|
||||
release_sub_crqs(adapter);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int ibmvnic_close(struct net_device *netdev)
|
||||
static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
union ibmvnic_crq crq;
|
||||
int tx_scrqs, rx_scrqs;
|
||||
int i;
|
||||
|
||||
adapter->closing = true;
|
||||
|
||||
for (i = 0; i < adapter->req_rx_queues; i++)
|
||||
napi_disable(&adapter->napi[i]);
|
||||
|
||||
if (!adapter->failover)
|
||||
netif_tx_stop_all_queues(netdev);
|
||||
|
||||
if (adapter->bounce_buffer) {
|
||||
if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
|
||||
dma_unmap_single(&adapter->vdev->dev,
|
||||
|
|
@ -538,33 +591,70 @@ static int ibmvnic_close(struct net_device *netdev)
|
|||
adapter->bounce_buffer = NULL;
|
||||
}
|
||||
|
||||
tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
|
||||
for (i = 0; i < tx_scrqs; i++) {
|
||||
struct ibmvnic_tx_pool *tx_pool = &adapter->tx_pool[i];
|
||||
|
||||
kfree(tx_pool->tx_buff);
|
||||
free_long_term_buff(adapter, &tx_pool->long_term_buff);
|
||||
kfree(tx_pool->free_map);
|
||||
}
|
||||
kfree(adapter->tx_pool);
|
||||
adapter->tx_pool = NULL;
|
||||
|
||||
rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
|
||||
for (i = 0; i < rx_scrqs; i++) {
|
||||
struct ibmvnic_rx_pool *rx_pool = &adapter->rx_pool[i];
|
||||
|
||||
free_rx_pool(adapter, rx_pool);
|
||||
free_long_term_buff(adapter, &rx_pool->long_term_buff);
|
||||
}
|
||||
kfree(adapter->rx_pool);
|
||||
adapter->rx_pool = NULL;
|
||||
|
||||
release_sub_crqs(adapter);
|
||||
ibmvnic_release_crq_queue(adapter);
|
||||
|
||||
if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
|
||||
debugfs_remove_recursive(adapter->debugfs_dir);
|
||||
|
||||
if (adapter->stats_token)
|
||||
dma_unmap_single(dev, adapter->stats_token,
|
||||
sizeof(struct ibmvnic_statistics),
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
if (adapter->ras_comps)
|
||||
dma_free_coherent(dev, adapter->ras_comp_num *
|
||||
sizeof(struct ibmvnic_fw_component),
|
||||
adapter->ras_comps, adapter->ras_comps_tok);
|
||||
|
||||
kfree(adapter->ras_comp_int);
|
||||
}
|
||||
|
||||
static int ibmvnic_close(struct net_device *netdev)
|
||||
{
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
union ibmvnic_crq crq;
|
||||
int i;
|
||||
|
||||
adapter->closing = true;
|
||||
|
||||
for (i = 0; i < adapter->req_rx_queues; i++)
|
||||
napi_disable(&adapter->napi[i]);
|
||||
|
||||
if (!adapter->failover)
|
||||
netif_tx_stop_all_queues(netdev);
|
||||
|
||||
memset(&crq, 0, sizeof(crq));
|
||||
crq.logical_link_state.first = IBMVNIC_CRQ_CMD;
|
||||
crq.logical_link_state.cmd = LOGICAL_LINK_STATE;
|
||||
crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_DN;
|
||||
ibmvnic_send_crq(adapter, &crq);
|
||||
|
||||
for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
|
||||
i++) {
|
||||
kfree(adapter->tx_pool[i].tx_buff);
|
||||
free_long_term_buff(adapter,
|
||||
&adapter->tx_pool[i].long_term_buff);
|
||||
kfree(adapter->tx_pool[i].free_map);
|
||||
}
|
||||
kfree(adapter->tx_pool);
|
||||
adapter->tx_pool = NULL;
|
||||
|
||||
for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
|
||||
i++) {
|
||||
free_rx_pool(adapter, &adapter->rx_pool[i]);
|
||||
free_long_term_buff(adapter,
|
||||
&adapter->rx_pool[i].long_term_buff);
|
||||
}
|
||||
kfree(adapter->rx_pool);
|
||||
adapter->rx_pool = NULL;
|
||||
ibmvnic_release_resources(adapter);
|
||||
|
||||
adapter->is_closed = true;
|
||||
adapter->closing = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3419,8 +3509,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
|
|||
dma_unmap_single(dev, adapter->ip_offload_ctrl_tok,
|
||||
sizeof(adapter->ip_offload_ctrl),
|
||||
DMA_TO_DEVICE);
|
||||
/* We're done with the queries, perform the login */
|
||||
send_login(adapter);
|
||||
complete(&adapter->init_done);
|
||||
break;
|
||||
case REQUEST_RAS_COMP_NUM_RSP:
|
||||
netdev_dbg(netdev, "Got Request RAS Comp Num Response\n");
|
||||
|
|
@ -3700,26 +3789,6 @@ static void handle_crq_init_rsp(struct work_struct *work)
|
|||
goto task_failed;
|
||||
}
|
||||
|
||||
do {
|
||||
if (adapter->renegotiate) {
|
||||
adapter->renegotiate = false;
|
||||
release_sub_crqs_no_irqs(adapter);
|
||||
|
||||
reinit_completion(&adapter->init_done);
|
||||
send_cap_queries(adapter);
|
||||
if (!wait_for_completion_timeout(&adapter->init_done,
|
||||
timeout)) {
|
||||
dev_err(dev, "Passive init timeout\n");
|
||||
goto task_failed;
|
||||
}
|
||||
}
|
||||
} while (adapter->renegotiate);
|
||||
rc = init_sub_crq_irqs(adapter);
|
||||
|
||||
if (rc)
|
||||
goto task_failed;
|
||||
|
||||
netdev->real_num_tx_queues = adapter->req_tx_queues;
|
||||
netdev->mtu = adapter->req_mtu - ETH_HLEN;
|
||||
|
||||
if (adapter->failover) {
|
||||
|
|
@ -3751,14 +3820,65 @@ static void handle_crq_init_rsp(struct work_struct *work)
|
|||
dev_err(dev, "Passive initialization was not successful\n");
|
||||
}
|
||||
|
||||
static int ibmvnic_init(struct ibmvnic_adapter *adapter)
|
||||
{
|
||||
struct device *dev = &adapter->vdev->dev;
|
||||
unsigned long timeout = msecs_to_jiffies(30000);
|
||||
struct dentry *ent;
|
||||
char buf[17]; /* debugfs name buf */
|
||||
int rc;
|
||||
|
||||
rc = ibmvnic_init_crq_queue(adapter);
|
||||
if (rc) {
|
||||
dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
adapter->stats_token = dma_map_single(dev, &adapter->stats,
|
||||
sizeof(struct ibmvnic_statistics),
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, adapter->stats_token)) {
|
||||
ibmvnic_release_crq_queue(adapter);
|
||||
dev_err(dev, "Couldn't map stats buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "ibmvnic_%x", adapter->vdev->unit_address);
|
||||
ent = debugfs_create_dir(buf, NULL);
|
||||
if (!ent || IS_ERR(ent)) {
|
||||
dev_info(dev, "debugfs create directory failed\n");
|
||||
adapter->debugfs_dir = NULL;
|
||||
} else {
|
||||
adapter->debugfs_dir = ent;
|
||||
ent = debugfs_create_file("dump", S_IRUGO,
|
||||
adapter->debugfs_dir,
|
||||
adapter->netdev, &ibmvnic_dump_ops);
|
||||
if (!ent || IS_ERR(ent)) {
|
||||
dev_info(dev, "debugfs create dump file failed\n");
|
||||
adapter->debugfs_dump = NULL;
|
||||
} else {
|
||||
adapter->debugfs_dump = ent;
|
||||
}
|
||||
}
|
||||
|
||||
init_completion(&adapter->init_done);
|
||||
ibmvnic_send_crq_init(adapter);
|
||||
if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
|
||||
dev_err(dev, "Initialization sequence timed out\n");
|
||||
if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
|
||||
debugfs_remove_recursive(adapter->debugfs_dir);
|
||||
ibmvnic_release_crq_queue(adapter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
||||
{
|
||||
unsigned long timeout = msecs_to_jiffies(30000);
|
||||
struct ibmvnic_adapter *adapter;
|
||||
struct net_device *netdev;
|
||||
unsigned char *mac_addr_p;
|
||||
struct dentry *ent;
|
||||
char buf[17]; /* debugfs name buf */
|
||||
int rc;
|
||||
|
||||
dev_dbg(&dev->dev, "entering ibmvnic_probe for UA 0x%x\n",
|
||||
|
|
@ -3796,118 +3916,36 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
|||
|
||||
spin_lock_init(&adapter->stats_lock);
|
||||
|
||||
rc = ibmvnic_init_crq_queue(adapter);
|
||||
if (rc) {
|
||||
dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n", rc);
|
||||
goto free_netdev;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&adapter->errors);
|
||||
INIT_LIST_HEAD(&adapter->inflight);
|
||||
spin_lock_init(&adapter->error_list_lock);
|
||||
spin_lock_init(&adapter->inflight_lock);
|
||||
|
||||
adapter->stats_token = dma_map_single(&dev->dev, &adapter->stats,
|
||||
sizeof(struct ibmvnic_statistics),
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(&dev->dev, adapter->stats_token)) {
|
||||
if (!firmware_has_feature(FW_FEATURE_CMO))
|
||||
dev_err(&dev->dev, "Couldn't map stats buffer\n");
|
||||
rc = -ENOMEM;
|
||||
goto free_crq;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "ibmvnic_%x", dev->unit_address);
|
||||
ent = debugfs_create_dir(buf, NULL);
|
||||
if (!ent || IS_ERR(ent)) {
|
||||
dev_info(&dev->dev, "debugfs create directory failed\n");
|
||||
adapter->debugfs_dir = NULL;
|
||||
} else {
|
||||
adapter->debugfs_dir = ent;
|
||||
ent = debugfs_create_file("dump", S_IRUGO, adapter->debugfs_dir,
|
||||
netdev, &ibmvnic_dump_ops);
|
||||
if (!ent || IS_ERR(ent)) {
|
||||
dev_info(&dev->dev,
|
||||
"debugfs create dump file failed\n");
|
||||
adapter->debugfs_dump = NULL;
|
||||
} else {
|
||||
adapter->debugfs_dump = ent;
|
||||
}
|
||||
}
|
||||
|
||||
init_completion(&adapter->init_done);
|
||||
ibmvnic_send_crq_init(adapter);
|
||||
if (!wait_for_completion_timeout(&adapter->init_done, timeout))
|
||||
return 0;
|
||||
|
||||
do {
|
||||
if (adapter->renegotiate) {
|
||||
adapter->renegotiate = false;
|
||||
release_sub_crqs_no_irqs(adapter);
|
||||
|
||||
reinit_completion(&adapter->init_done);
|
||||
send_cap_queries(adapter);
|
||||
if (!wait_for_completion_timeout(&adapter->init_done,
|
||||
timeout))
|
||||
return 0;
|
||||
}
|
||||
} while (adapter->renegotiate);
|
||||
|
||||
rc = init_sub_crq_irqs(adapter);
|
||||
rc = ibmvnic_init(adapter);
|
||||
if (rc) {
|
||||
dev_err(&dev->dev, "failed to initialize sub crq irqs\n");
|
||||
goto free_debugfs;
|
||||
free_netdev(netdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
netdev->real_num_tx_queues = adapter->req_tx_queues;
|
||||
netdev->mtu = adapter->req_mtu - ETH_HLEN;
|
||||
adapter->is_closed = false;
|
||||
|
||||
rc = register_netdev(netdev);
|
||||
if (rc) {
|
||||
dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
|
||||
goto free_sub_crqs;
|
||||
free_netdev(netdev);
|
||||
return rc;
|
||||
}
|
||||
dev_info(&dev->dev, "ibmvnic registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
free_sub_crqs:
|
||||
release_sub_crqs(adapter);
|
||||
free_debugfs:
|
||||
if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
|
||||
debugfs_remove_recursive(adapter->debugfs_dir);
|
||||
free_crq:
|
||||
ibmvnic_release_crq_queue(adapter);
|
||||
free_netdev:
|
||||
free_netdev(netdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ibmvnic_remove(struct vio_dev *dev)
|
||||
{
|
||||
struct net_device *netdev = dev_get_drvdata(&dev->dev);
|
||||
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
unregister_netdev(netdev);
|
||||
|
||||
release_sub_crqs(adapter);
|
||||
|
||||
ibmvnic_release_crq_queue(adapter);
|
||||
|
||||
if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
|
||||
debugfs_remove_recursive(adapter->debugfs_dir);
|
||||
|
||||
dma_unmap_single(&dev->dev, adapter->stats_token,
|
||||
sizeof(struct ibmvnic_statistics), DMA_FROM_DEVICE);
|
||||
|
||||
if (adapter->ras_comps)
|
||||
dma_free_coherent(&dev->dev,
|
||||
adapter->ras_comp_num *
|
||||
sizeof(struct ibmvnic_fw_component),
|
||||
adapter->ras_comps, adapter->ras_comps_tok);
|
||||
|
||||
kfree(adapter->ras_comp_int);
|
||||
|
||||
free_netdev(netdev);
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -1052,4 +1052,5 @@ struct ibmvnic_adapter {
|
|||
struct work_struct ibmvnic_xport;
|
||||
struct tasklet_struct tasklet;
|
||||
bool failover;
|
||||
bool is_closed;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1226,7 +1226,9 @@ static int __fm10k_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
|
|||
if (tc->type != TC_SETUP_MQPRIO)
|
||||
return -EINVAL;
|
||||
|
||||
return fm10k_setup_tc(dev, tc->tc);
|
||||
tc->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
|
||||
return fm10k_setup_tc(dev, tc->mqprio->num_tc);
|
||||
}
|
||||
|
||||
static void fm10k_assign_l2_accel(struct fm10k_intfc *interface,
|
||||
|
|
|
|||
|
|
@ -208,8 +208,8 @@ struct i40e_fdir_filter {
|
|||
u8 flow_type;
|
||||
u8 ip4_proto;
|
||||
/* TX packet view of src and dst */
|
||||
__be32 dst_ip[4];
|
||||
__be32 src_ip[4];
|
||||
__be32 dst_ip;
|
||||
__be32 src_ip;
|
||||
__be16 src_port;
|
||||
__be16 dst_port;
|
||||
__be32 sctp_v_tag;
|
||||
|
|
@ -244,7 +244,8 @@ struct i40e_tc_configuration {
|
|||
};
|
||||
|
||||
struct i40e_udp_port_config {
|
||||
__be16 index;
|
||||
/* AdminQ command interface expects port number in Host byte order */
|
||||
u16 index;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
|
|
@ -285,7 +286,14 @@ struct i40e_pf {
|
|||
u32 fd_flush_cnt;
|
||||
u32 fd_add_err;
|
||||
u32 fd_atr_cnt;
|
||||
u32 fd_tcp_rule;
|
||||
|
||||
/* Book-keeping of side-band filter count per flow-type.
|
||||
* This is used to detect and handle input set changes for
|
||||
* respective flow-type.
|
||||
*/
|
||||
u16 fd_tcp4_filter_cnt;
|
||||
u16 fd_udp4_filter_cnt;
|
||||
u16 fd_ip4_filter_cnt;
|
||||
|
||||
struct i40e_udp_port_config udp_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
|
||||
u16 pending_udp_bitmap;
|
||||
|
|
@ -348,16 +356,23 @@ struct i40e_pf {
|
|||
#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT_ULL(51)
|
||||
#define I40E_FLAG_HAVE_CRT_RETIMER BIT_ULL(52)
|
||||
#define I40E_FLAG_PTP_L4_CAPABLE BIT_ULL(53)
|
||||
#define I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE BIT_ULL(54)
|
||||
#define I40E_FLAG_CLIENT_RESET BIT_ULL(54)
|
||||
#define I40E_FLAG_TEMP_LINK_POLLING BIT_ULL(55)
|
||||
#define I40E_FLAG_CLIENT_L2_CHANGE BIT_ULL(56)
|
||||
#define I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE BIT_ULL(57)
|
||||
|
||||
/* tracks features that get auto disabled by errors */
|
||||
u64 auto_disable_flags;
|
||||
/* Tracks features that are disabled due to hw limitations.
|
||||
* If a bit is set here, it means that the corresponding
|
||||
* bit in the 'flags' field is cleared i.e that feature
|
||||
* is disabled
|
||||
*/
|
||||
u64 hw_disabled_flags;
|
||||
|
||||
#ifdef I40E_FCOE
|
||||
struct i40e_fcoe fcoe;
|
||||
|
||||
#endif /* I40E_FCOE */
|
||||
struct i40e_client_instance *cinst;
|
||||
bool stat_offsets_loaded;
|
||||
struct i40e_hw_port_stats stats;
|
||||
struct i40e_hw_port_stats stats_offsets;
|
||||
|
|
@ -813,8 +828,7 @@ void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi);
|
|||
void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset);
|
||||
void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs);
|
||||
void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id);
|
||||
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id,
|
||||
enum i40e_client_type type);
|
||||
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id);
|
||||
/**
|
||||
* i40e_irq_dynamic_enable - Enable default interrupt generation settings
|
||||
* @vsi: pointer to a vsi
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ enum i40e_admin_queue_opc {
|
|||
i40e_aqc_opc_list_func_capabilities = 0x000A,
|
||||
i40e_aqc_opc_list_dev_capabilities = 0x000B,
|
||||
|
||||
/* Proxy commands */
|
||||
i40e_aqc_opc_set_proxy_config = 0x0104,
|
||||
i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
|
||||
|
||||
/* LAA */
|
||||
i40e_aqc_opc_mac_address_read = 0x0107,
|
||||
i40e_aqc_opc_mac_address_write = 0x0108,
|
||||
|
|
@ -139,6 +143,10 @@ enum i40e_admin_queue_opc {
|
|||
/* PXE */
|
||||
i40e_aqc_opc_clear_pxe_mode = 0x0110,
|
||||
|
||||
/* WoL commands */
|
||||
i40e_aqc_opc_set_wol_filter = 0x0120,
|
||||
i40e_aqc_opc_get_wake_reason = 0x0121,
|
||||
|
||||
/* internal switch commands */
|
||||
i40e_aqc_opc_get_switch_config = 0x0200,
|
||||
i40e_aqc_opc_add_statistics = 0x0201,
|
||||
|
|
@ -177,6 +185,7 @@ enum i40e_admin_queue_opc {
|
|||
i40e_aqc_opc_remove_control_packet_filter = 0x025B,
|
||||
i40e_aqc_opc_add_cloud_filters = 0x025C,
|
||||
i40e_aqc_opc_remove_cloud_filters = 0x025D,
|
||||
i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
|
||||
|
||||
i40e_aqc_opc_add_mirror_rule = 0x0260,
|
||||
i40e_aqc_opc_delete_mirror_rule = 0x0261,
|
||||
|
|
@ -563,6 +572,56 @@ struct i40e_aqc_clear_pxe {
|
|||
|
||||
I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe);
|
||||
|
||||
/* Set WoL Filter (0x0120) */
|
||||
|
||||
struct i40e_aqc_set_wol_filter {
|
||||
__le16 filter_index;
|
||||
#define I40E_AQC_MAX_NUM_WOL_FILTERS 8
|
||||
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT 15
|
||||
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_MASK (0x1 << \
|
||||
I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT)
|
||||
|
||||
#define I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT 0
|
||||
#define I40E_AQC_SET_WOL_FILTER_INDEX_MASK (0x7 << \
|
||||
I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT)
|
||||
__le16 cmd_flags;
|
||||
#define I40E_AQC_SET_WOL_FILTER 0x8000
|
||||
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000
|
||||
#define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0
|
||||
#define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1
|
||||
__le16 valid_flags;
|
||||
#define I40E_AQC_SET_WOL_FILTER_ACTION_VALID 0x8000
|
||||
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_ACTION_VALID 0x4000
|
||||
u8 reserved[2];
|
||||
__le32 address_high;
|
||||
__le32 address_low;
|
||||
};
|
||||
|
||||
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_wol_filter);
|
||||
|
||||
struct i40e_aqc_set_wol_filter_data {
|
||||
u8 filter[128];
|
||||
u8 mask[16];
|
||||
};
|
||||
|
||||
I40E_CHECK_STRUCT_LEN(0x90, i40e_aqc_set_wol_filter_data);
|
||||
|
||||
/* Get Wake Reason (0x0121) */
|
||||
|
||||
struct i40e_aqc_get_wake_reason_completion {
|
||||
u8 reserved_1[2];
|
||||
__le16 wake_reason;
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT 0
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_MASK (0xFF << \
|
||||
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT)
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT 8
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_MASK (0xFF << \
|
||||
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT)
|
||||
u8 reserved_2[12];
|
||||
};
|
||||
|
||||
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_wake_reason_completion);
|
||||
|
||||
/* Switch configuration commands (0x02xx) */
|
||||
|
||||
/* Used by many indirect commands that only pass an seid and a buffer in the
|
||||
|
|
@ -645,6 +704,8 @@ struct i40e_aqc_set_port_parameters {
|
|||
#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
|
||||
#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
|
||||
__le16 bad_frame_vsi;
|
||||
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_SHIFT 0x0
|
||||
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_MASK 0x3FF
|
||||
__le16 default_seid; /* reserved for command */
|
||||
u8 reserved[10];
|
||||
};
|
||||
|
|
@ -696,6 +757,7 @@ I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
|
|||
/* Set Switch Configuration (direct 0x0205) */
|
||||
struct i40e_aqc_set_switch_config {
|
||||
__le16 flags;
|
||||
/* flags used for both fields below */
|
||||
#define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001
|
||||
#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002
|
||||
__le16 valid_flags;
|
||||
|
|
@ -1844,11 +1906,12 @@ struct i40e_aqc_get_link_status {
|
|||
#define I40E_AQ_CONFIG_FEC_RS_ENA 0x02
|
||||
#define I40E_AQ_CONFIG_CRC_ENA 0x04
|
||||
#define I40E_AQ_CONFIG_PACING_MASK 0x78
|
||||
u8 external_power_ability;
|
||||
u8 power_desc;
|
||||
#define I40E_AQ_LINK_POWER_CLASS_1 0x00
|
||||
#define I40E_AQ_LINK_POWER_CLASS_2 0x01
|
||||
#define I40E_AQ_LINK_POWER_CLASS_3 0x02
|
||||
#define I40E_AQ_LINK_POWER_CLASS_4 0x03
|
||||
#define I40E_AQ_PWR_CLASS_MASK 0x03
|
||||
u8 reserved[4];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -32,16 +32,10 @@
|
|||
#include "i40e_client.h"
|
||||
|
||||
static const char i40e_client_interface_version_str[] = I40E_CLIENT_VERSION_STR;
|
||||
|
||||
static struct i40e_client *registered_client;
|
||||
static LIST_HEAD(i40e_devices);
|
||||
static DEFINE_MUTEX(i40e_device_mutex);
|
||||
|
||||
static LIST_HEAD(i40e_clients);
|
||||
static DEFINE_MUTEX(i40e_client_mutex);
|
||||
|
||||
static LIST_HEAD(i40e_client_instances);
|
||||
static DEFINE_MUTEX(i40e_client_instance_mutex);
|
||||
|
||||
static int i40e_client_virtchnl_send(struct i40e_info *ldev,
|
||||
struct i40e_client *client,
|
||||
u32 vf_id, u8 *msg, u16 len);
|
||||
|
|
@ -66,28 +60,6 @@ static struct i40e_ops i40e_lan_ops = {
|
|||
.update_vsi_ctxt = i40e_client_update_vsi_ctxt,
|
||||
};
|
||||
|
||||
/**
|
||||
* i40e_client_type_to_vsi_type - convert client type to vsi type
|
||||
* @client_type: the i40e_client type
|
||||
*
|
||||
* returns the related vsi type value
|
||||
**/
|
||||
static
|
||||
enum i40e_vsi_type i40e_client_type_to_vsi_type(enum i40e_client_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case I40E_CLIENT_IWARP:
|
||||
return I40E_VSI_IWARP;
|
||||
|
||||
case I40E_CLIENT_VMDQ2:
|
||||
return I40E_VSI_VMDQ2;
|
||||
|
||||
default:
|
||||
pr_err("i40e: Client type unknown\n");
|
||||
return I40E_VSI_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_client_get_params - Get the params that can change at runtime
|
||||
* @vsi: the VSI with the message
|
||||
|
|
@ -134,31 +106,22 @@ int i40e_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params)
|
|||
void
|
||||
i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
struct i40e_client_instance *cdev = pf->cinst;
|
||||
|
||||
if (!vsi)
|
||||
if (!cdev || !cdev->client)
|
||||
return;
|
||||
if (!cdev->client->ops || !cdev->client->ops->virtchnl_receive) {
|
||||
dev_dbg(&pf->pdev->dev,
|
||||
"Cannot locate client instance virtual channel receive routine\n");
|
||||
return;
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if (cdev->lan_info.pf == vsi->back) {
|
||||
if (!cdev->client ||
|
||||
!cdev->client->ops ||
|
||||
!cdev->client->ops->virtchnl_receive) {
|
||||
dev_dbg(&vsi->back->pdev->dev,
|
||||
"Cannot locate client instance virtual channel receive routine\n");
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort virtchnl_receive\n");
|
||||
continue;
|
||||
}
|
||||
cdev->client->ops->virtchnl_receive(&cdev->lan_info,
|
||||
cdev->client,
|
||||
vf_id, msg, len);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
|
||||
dev_dbg(&pf->pdev->dev, "Client is not open, abort virtchnl_receive\n");
|
||||
return;
|
||||
}
|
||||
cdev->client->ops->virtchnl_receive(&cdev->lan_info, cdev->client,
|
||||
vf_id, msg, len);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -169,39 +132,28 @@ i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len)
|
|||
**/
|
||||
void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
struct i40e_client_instance *cdev = pf->cinst;
|
||||
struct i40e_params params;
|
||||
|
||||
if (!vsi)
|
||||
if (!cdev || !cdev->client)
|
||||
return;
|
||||
if (!cdev->client->ops || !cdev->client->ops->l2_param_change) {
|
||||
dev_dbg(&vsi->back->pdev->dev,
|
||||
"Cannot locate client instance l2_param_change routine\n");
|
||||
return;
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if (cdev->lan_info.pf == vsi->back) {
|
||||
if (!cdev->client ||
|
||||
!cdev->client->ops ||
|
||||
!cdev->client->ops->l2_param_change) {
|
||||
dev_dbg(&vsi->back->pdev->dev,
|
||||
"Cannot locate client instance l2_param_change routine\n");
|
||||
continue;
|
||||
}
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
i40e_client_get_params(vsi, ¶ms);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort l2 param change\n");
|
||||
continue;
|
||||
}
|
||||
cdev->lan_info.params = params;
|
||||
cdev->client->ops->l2_param_change(&cdev->lan_info,
|
||||
cdev->client,
|
||||
¶ms);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
|
||||
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort l2 param change\n");
|
||||
return;
|
||||
}
|
||||
memcpy(&cdev->lan_info.params, ¶ms, sizeof(struct i40e_params));
|
||||
cdev->client->ops->l2_param_change(&cdev->lan_info, cdev->client,
|
||||
¶ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_client_release_qvlist
|
||||
* i40e_client_release_qvlist - release MSI-X vector mapping for client
|
||||
* @ldev: pointer to L2 context.
|
||||
*
|
||||
**/
|
||||
|
|
@ -237,26 +189,19 @@ static void i40e_client_release_qvlist(struct i40e_info *ldev)
|
|||
**/
|
||||
void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
struct i40e_client_instance *cdev = pf->cinst;
|
||||
|
||||
if (!vsi)
|
||||
if (!cdev || !cdev->client)
|
||||
return;
|
||||
if (!cdev->client->ops || !cdev->client->ops->close) {
|
||||
dev_dbg(&vsi->back->pdev->dev,
|
||||
"Cannot locate client instance close routine\n");
|
||||
return;
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if (cdev->lan_info.netdev == vsi->netdev) {
|
||||
if (!cdev->client ||
|
||||
!cdev->client->ops || !cdev->client->ops->close) {
|
||||
dev_dbg(&vsi->back->pdev->dev,
|
||||
"Cannot locate client instance close routine\n");
|
||||
continue;
|
||||
}
|
||||
cdev->client->ops->close(&cdev->lan_info, cdev->client,
|
||||
reset);
|
||||
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
|
||||
i40e_client_release_qvlist(&cdev->lan_info);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
cdev->client->ops->close(&cdev->lan_info, cdev->client, reset);
|
||||
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
|
||||
i40e_client_release_qvlist(&cdev->lan_info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -268,30 +213,20 @@ void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset)
|
|||
**/
|
||||
void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_client_instance *cdev = pf->cinst;
|
||||
|
||||
if (!pf)
|
||||
if (!cdev || !cdev->client)
|
||||
return;
|
||||
if (!cdev->client->ops || !cdev->client->ops->vf_reset) {
|
||||
dev_dbg(&pf->pdev->dev,
|
||||
"Cannot locate client instance VF reset routine\n");
|
||||
return;
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if (cdev->lan_info.pf == pf) {
|
||||
if (!cdev->client ||
|
||||
!cdev->client->ops ||
|
||||
!cdev->client->ops->vf_reset) {
|
||||
dev_dbg(&pf->pdev->dev,
|
||||
"Cannot locate client instance VF reset routine\n");
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-reset\n");
|
||||
continue;
|
||||
}
|
||||
cdev->client->ops->vf_reset(&cdev->lan_info,
|
||||
cdev->client, vf_id);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
|
||||
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-reset\n");
|
||||
return;
|
||||
}
|
||||
cdev->client->ops->vf_reset(&cdev->lan_info, cdev->client, vf_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -303,30 +238,21 @@ void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id)
|
|||
**/
|
||||
void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_client_instance *cdev = pf->cinst;
|
||||
|
||||
if (!pf)
|
||||
if (!cdev || !cdev->client)
|
||||
return;
|
||||
if (!cdev->client->ops || !cdev->client->ops->vf_enable) {
|
||||
dev_dbg(&pf->pdev->dev,
|
||||
"Cannot locate client instance VF enable routine\n");
|
||||
return;
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if (cdev->lan_info.pf == pf) {
|
||||
if (!cdev->client ||
|
||||
!cdev->client->ops ||
|
||||
!cdev->client->ops->vf_enable) {
|
||||
dev_dbg(&pf->pdev->dev,
|
||||
"Cannot locate client instance VF enable routine\n");
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-enable\n");
|
||||
continue;
|
||||
}
|
||||
cdev->client->ops->vf_enable(&cdev->lan_info,
|
||||
cdev->client, num_vfs);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-enable\n");
|
||||
return;
|
||||
}
|
||||
cdev->client->ops->vf_enable(&cdev->lan_info, cdev->client, num_vfs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -337,37 +263,25 @@ void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs)
|
|||
* If there is a client of the specified type attached to this PF, call
|
||||
* its vf_capable routine
|
||||
**/
|
||||
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id,
|
||||
enum i40e_client_type type)
|
||||
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_client_instance *cdev = pf->cinst;
|
||||
int capable = false;
|
||||
|
||||
if (!pf)
|
||||
return false;
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if (cdev->lan_info.pf == pf) {
|
||||
if (!cdev->client ||
|
||||
!cdev->client->ops ||
|
||||
!cdev->client->ops->vf_capable ||
|
||||
!(cdev->client->type == type)) {
|
||||
dev_dbg(&pf->pdev->dev,
|
||||
"Cannot locate client instance VF capability routine\n");
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-capable\n");
|
||||
continue;
|
||||
}
|
||||
capable = cdev->client->ops->vf_capable(&cdev->lan_info,
|
||||
cdev->client,
|
||||
vf_id);
|
||||
break;
|
||||
}
|
||||
if (!cdev || !cdev->client)
|
||||
goto out;
|
||||
if (!cdev->client->ops || !cdev->client->ops->vf_capable) {
|
||||
dev_info(&pf->pdev->dev,
|
||||
"Cannot locate client instance VF capability routine\n");
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state))
|
||||
goto out;
|
||||
|
||||
capable = cdev->client->ops->vf_capable(&cdev->lan_info,
|
||||
cdev->client,
|
||||
vf_id);
|
||||
out:
|
||||
return capable;
|
||||
}
|
||||
|
||||
|
|
@ -377,27 +291,19 @@ int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id,
|
|||
* @client: pointer to a client struct in the client list.
|
||||
* @existing: if there was already an existing instance
|
||||
*
|
||||
* Returns cdev ptr on success or if already exists, NULL on failure
|
||||
**/
|
||||
static
|
||||
struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf,
|
||||
struct i40e_client *client,
|
||||
bool *existing)
|
||||
static void i40e_client_add_instance(struct i40e_pf *pf)
|
||||
{
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_client_instance *cdev = NULL;
|
||||
struct netdev_hw_addr *mac = NULL;
|
||||
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
|
||||
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry(cdev, &i40e_client_instances, list) {
|
||||
if ((cdev->lan_info.pf == pf) && (cdev->client == client)) {
|
||||
*existing = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!registered_client || pf->cinst)
|
||||
return;
|
||||
|
||||
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
|
||||
if (!cdev)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
cdev->lan_info.pf = (void *)pf;
|
||||
cdev->lan_info.netdev = vsi->netdev;
|
||||
|
|
@ -417,7 +323,7 @@ struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf,
|
|||
if (i40e_client_get_params(vsi, &cdev->lan_info.params)) {
|
||||
kfree(cdev);
|
||||
cdev = NULL;
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
cdev->lan_info.msix_count = pf->num_iwarp_msix;
|
||||
|
|
@ -430,41 +336,20 @@ struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf,
|
|||
else
|
||||
dev_err(&pf->pdev->dev, "MAC address list is empty!\n");
|
||||
|
||||
cdev->client = client;
|
||||
INIT_LIST_HEAD(&cdev->list);
|
||||
list_add(&cdev->list, &i40e_client_instances);
|
||||
out:
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
return cdev;
|
||||
cdev->client = registered_client;
|
||||
pf->cinst = cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_client_del_instance - removes a client instance from the list
|
||||
* @pf: pointer to the board struct
|
||||
*
|
||||
* Returns 0 on success or non-0 on error
|
||||
**/
|
||||
static
|
||||
int i40e_client_del_instance(struct i40e_pf *pf, struct i40e_client *client)
|
||||
void i40e_client_del_instance(struct i40e_pf *pf)
|
||||
{
|
||||
struct i40e_client_instance *cdev, *tmp;
|
||||
int ret = -ENODEV;
|
||||
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry_safe(cdev, tmp, &i40e_client_instances, list) {
|
||||
if ((cdev->lan_info.pf != pf) || (cdev->client != client))
|
||||
continue;
|
||||
|
||||
dev_info(&pf->pdev->dev, "Deleted instance of Client %s, of dev %d bus=0x%02x func=0x%02x)\n",
|
||||
client->name, pf->hw.pf_id,
|
||||
pf->hw.bus.device, pf->hw.bus.func);
|
||||
list_del(&cdev->list);
|
||||
kfree(cdev);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
return ret;
|
||||
kfree(pf->cinst);
|
||||
pf->cinst = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -473,67 +358,50 @@ int i40e_client_del_instance(struct i40e_pf *pf, struct i40e_client *client)
|
|||
**/
|
||||
void i40e_client_subtask(struct i40e_pf *pf)
|
||||
{
|
||||
struct i40e_client *client = registered_client;
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_client *client;
|
||||
bool existing = false;
|
||||
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
|
||||
int ret = 0;
|
||||
|
||||
if (!(pf->flags & I40E_FLAG_SERVICE_CLIENT_REQUESTED))
|
||||
return;
|
||||
pf->flags &= ~I40E_FLAG_SERVICE_CLIENT_REQUESTED;
|
||||
cdev = pf->cinst;
|
||||
|
||||
/* If we're down or resetting, just bail */
|
||||
if (test_bit(__I40E_DOWN, &pf->state) ||
|
||||
test_bit(__I40E_CONFIG_BUSY, &pf->state))
|
||||
return;
|
||||
|
||||
/* Check client state and instantiate client if client registered */
|
||||
mutex_lock(&i40e_client_mutex);
|
||||
list_for_each_entry(client, &i40e_clients, list) {
|
||||
/* first check client is registered */
|
||||
if (!test_bit(__I40E_CLIENT_REGISTERED, &client->state))
|
||||
continue;
|
||||
if (!client || !cdev)
|
||||
return;
|
||||
|
||||
/* Do we also need the LAN VSI to be up, to create instance */
|
||||
if (!(client->flags & I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE)) {
|
||||
/* check if L2 VSI is up, if not we are not ready */
|
||||
if (test_bit(__I40E_DOWN, &pf->vsi[pf->lan_vsi]->state))
|
||||
continue;
|
||||
} else {
|
||||
dev_warn(&pf->pdev->dev, "This client %s is being instantiated at probe\n",
|
||||
client->name);
|
||||
}
|
||||
|
||||
/* Add the client instance to the instance list */
|
||||
cdev = i40e_client_add_instance(pf, client, &existing);
|
||||
if (!cdev)
|
||||
continue;
|
||||
|
||||
if (!existing) {
|
||||
dev_info(&pf->pdev->dev, "Added instance of Client %s to PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
|
||||
client->name, pf->hw.pf_id,
|
||||
pf->hw.bus.bus_id, pf->hw.bus.device,
|
||||
pf->hw.bus.func);
|
||||
}
|
||||
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state)) {
|
||||
/* Send an Open request to the client */
|
||||
if (client->ops && client->ops->open)
|
||||
ret = client->ops->open(&cdev->lan_info,
|
||||
client);
|
||||
if (!ret) {
|
||||
set_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state);
|
||||
} else {
|
||||
/* remove client instance */
|
||||
i40e_client_del_instance(pf, client);
|
||||
/* Here we handle client opens. If the client is down, but
|
||||
* the netdev is up, then open the client.
|
||||
*/
|
||||
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
|
||||
if (!test_bit(__I40E_DOWN, &vsi->state) &&
|
||||
client->ops && client->ops->open) {
|
||||
set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
|
||||
ret = client->ops->open(&cdev->lan_info, client);
|
||||
if (ret) {
|
||||
/* Remove failed client instance */
|
||||
clear_bit(__I40E_CLIENT_INSTANCE_OPENED,
|
||||
&cdev->state);
|
||||
i40e_client_del_instance(pf);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
} else {
|
||||
/* Likewise for client close. If the client is up, but the netdev
|
||||
* is down, then close the client.
|
||||
*/
|
||||
if (test_bit(__I40E_DOWN, &vsi->state) &&
|
||||
client->ops && client->ops->close) {
|
||||
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
|
||||
client->ops->close(&cdev->lan_info, client, false);
|
||||
i40e_client_release_qvlist(&cdev->lan_info);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&i40e_client_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -601,7 +469,6 @@ int i40e_lan_del_device(struct i40e_pf *pf)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&i40e_device_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -610,22 +477,24 @@ int i40e_lan_del_device(struct i40e_pf *pf)
|
|||
* i40e_client_release - release client specific resources
|
||||
* @client: pointer to the registered client
|
||||
*
|
||||
* Return 0 on success or < 0 on error
|
||||
**/
|
||||
static int i40e_client_release(struct i40e_client *client)
|
||||
static void i40e_client_release(struct i40e_client *client)
|
||||
{
|
||||
struct i40e_client_instance *cdev, *tmp;
|
||||
struct i40e_client_instance *cdev;
|
||||
struct i40e_device *ldev;
|
||||
struct i40e_pf *pf;
|
||||
int ret = 0;
|
||||
|
||||
LIST_HEAD(cdevs_tmp);
|
||||
|
||||
mutex_lock(&i40e_client_instance_mutex);
|
||||
list_for_each_entry_safe(cdev, tmp, &i40e_client_instances, list) {
|
||||
if (strncmp(cdev->client->name, client->name,
|
||||
I40E_CLIENT_STR_LENGTH))
|
||||
mutex_lock(&i40e_device_mutex);
|
||||
list_for_each_entry(ldev, &i40e_devices, list) {
|
||||
pf = ldev->pf;
|
||||
cdev = pf->cinst;
|
||||
if (!cdev)
|
||||
continue;
|
||||
pf = (struct i40e_pf *)cdev->lan_info.pf;
|
||||
|
||||
while (test_and_set_bit(__I40E_SERVICE_SCHED,
|
||||
&pf->state))
|
||||
usleep_range(500, 1000);
|
||||
|
||||
if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
|
||||
if (client->ops && client->ops->close)
|
||||
client->ops->close(&cdev->lan_info, client,
|
||||
|
|
@ -637,18 +506,13 @@ static int i40e_client_release(struct i40e_client *client)
|
|||
"Client %s instance for PF id %d closed\n",
|
||||
client->name, pf->hw.pf_id);
|
||||
}
|
||||
/* delete the client instance from the list */
|
||||
list_move(&cdev->list, &cdevs_tmp);
|
||||
/* delete the client instance */
|
||||
i40e_client_del_instance(pf);
|
||||
dev_info(&pf->pdev->dev, "Deleted client instance of Client %s\n",
|
||||
client->name);
|
||||
clear_bit(__I40E_SERVICE_SCHED, &pf->state);
|
||||
}
|
||||
mutex_unlock(&i40e_client_instance_mutex);
|
||||
|
||||
/* free the client device and release its vsi */
|
||||
list_for_each_entry_safe(cdev, tmp, &cdevs_tmp, list) {
|
||||
kfree(cdev);
|
||||
}
|
||||
return ret;
|
||||
mutex_unlock(&i40e_device_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -664,6 +528,7 @@ static void i40e_client_prepare(struct i40e_client *client)
|
|||
mutex_lock(&i40e_device_mutex);
|
||||
list_for_each_entry(ldev, &i40e_devices, list) {
|
||||
pf = ldev->pf;
|
||||
i40e_client_add_instance(pf);
|
||||
/* Start the client subtask */
|
||||
pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
|
||||
i40e_service_event_schedule(pf);
|
||||
|
|
@ -792,8 +657,8 @@ static void i40e_client_request_reset(struct i40e_info *ldev,
|
|||
break;
|
||||
default:
|
||||
dev_warn(&pf->pdev->dev,
|
||||
"Client %s instance for PF id %d request an unsupported reset: %d.\n",
|
||||
client->name, pf->hw.pf_id, reset_level);
|
||||
"Client for PF id %d requested an unsupported reset: %d.\n",
|
||||
pf->hw.pf_id, reset_level);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -852,8 +717,8 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
|
|||
} else {
|
||||
update = false;
|
||||
dev_warn(&pf->pdev->dev,
|
||||
"Client %s instance for PF id %d request an unsupported Config: %x.\n",
|
||||
client->name, pf->hw.pf_id, flag);
|
||||
"Client for PF id %d request an unsupported Config: %x.\n",
|
||||
pf->hw.pf_id, flag);
|
||||
}
|
||||
|
||||
if (update) {
|
||||
|
|
@ -878,7 +743,6 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
|
|||
int i40e_register_client(struct i40e_client *client)
|
||||
{
|
||||
int ret = 0;
|
||||
enum i40e_vsi_type vsi_type;
|
||||
|
||||
if (!client) {
|
||||
ret = -EIO;
|
||||
|
|
@ -891,11 +755,9 @@ int i40e_register_client(struct i40e_client *client)
|
|||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&i40e_client_mutex);
|
||||
if (i40e_client_is_registered(client)) {
|
||||
if (registered_client) {
|
||||
pr_info("i40e: Client %s has already been registered!\n",
|
||||
client->name);
|
||||
mutex_unlock(&i40e_client_mutex);
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -908,22 +770,11 @@ int i40e_register_client(struct i40e_client *client)
|
|||
client->version.major, client->version.minor,
|
||||
client->version.build,
|
||||
i40e_client_interface_version_str);
|
||||
mutex_unlock(&i40e_client_mutex);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vsi_type = i40e_client_type_to_vsi_type(client->type);
|
||||
if (vsi_type == I40E_VSI_TYPE_UNKNOWN) {
|
||||
pr_info("i40e: Failed to register client %s due to unknown client type %d\n",
|
||||
client->name, client->type);
|
||||
mutex_unlock(&i40e_client_mutex);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
list_add(&client->list, &i40e_clients);
|
||||
set_bit(__I40E_CLIENT_REGISTERED, &client->state);
|
||||
mutex_unlock(&i40e_client_mutex);
|
||||
registered_client = client;
|
||||
|
||||
i40e_client_prepare(client);
|
||||
|
||||
|
|
@ -943,29 +794,21 @@ int i40e_unregister_client(struct i40e_client *client)
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
/* When a unregister request comes through we would have to send
|
||||
* a close for each of the client instances that were opened.
|
||||
* client_release function is called to handle this.
|
||||
*/
|
||||
mutex_lock(&i40e_client_mutex);
|
||||
if (!client || i40e_client_release(client)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* TODO: check if device is in reset, or if that matters? */
|
||||
if (!i40e_client_is_registered(client)) {
|
||||
if (registered_client != client) {
|
||||
pr_info("i40e: Client %s has not been registered\n",
|
||||
client->name);
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
clear_bit(__I40E_CLIENT_REGISTERED, &client->state);
|
||||
list_del(&client->list);
|
||||
pr_info("i40e: Unregistered client %s with return code %d\n",
|
||||
client->name, ret);
|
||||
registered_client = NULL;
|
||||
/* When a unregister request comes through we would have to send
|
||||
* a close for each of the client instances that were opened.
|
||||
* client_release function is called to handle this.
|
||||
*/
|
||||
i40e_client_release(client);
|
||||
|
||||
pr_info("i40e: Unregistered client %s\n", client->name);
|
||||
out:
|
||||
mutex_unlock(&i40e_client_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(i40e_unregister_client);
|
||||
|
|
|
|||
|
|
@ -57,11 +57,6 @@ enum i40e_client_instance_state {
|
|||
__I40E_CLIENT_INSTANCE_OPENED,
|
||||
};
|
||||
|
||||
enum i40e_client_type {
|
||||
I40E_CLIENT_IWARP,
|
||||
I40E_CLIENT_VMDQ2
|
||||
};
|
||||
|
||||
struct i40e_ops;
|
||||
struct i40e_client;
|
||||
|
||||
|
|
@ -214,7 +209,8 @@ struct i40e_client {
|
|||
u32 flags;
|
||||
#define I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0)
|
||||
#define I40E_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2)
|
||||
enum i40e_client_type type;
|
||||
u8 type;
|
||||
#define I40E_CLIENT_IWARP 0
|
||||
const struct i40e_client_ops *ops; /* client ops provided by the client */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, u32 *supported,
|
|||
*
|
||||
**/
|
||||
static void i40e_get_settings_link_up(struct i40e_hw *hw,
|
||||
struct ethtool_cmd *ecmd,
|
||||
struct ethtool_link_ksettings *cmd,
|
||||
struct net_device *netdev,
|
||||
struct i40e_pf *pf)
|
||||
{
|
||||
|
|
@ -395,90 +395,96 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
|
|||
u32 link_speed = hw_link_info->link_speed;
|
||||
u32 e_advertising = 0x0;
|
||||
u32 e_supported = 0x0;
|
||||
u32 supported, advertising;
|
||||
|
||||
ethtool_convert_link_mode_to_legacy_u32(&supported,
|
||||
cmd->link_modes.supported);
|
||||
ethtool_convert_link_mode_to_legacy_u32(&advertising,
|
||||
cmd->link_modes.advertising);
|
||||
|
||||
/* Initialize supported and advertised settings based on phy settings */
|
||||
switch (hw_link_info->phy_type) {
|
||||
case I40E_PHY_TYPE_40GBASE_CR4:
|
||||
case I40E_PHY_TYPE_40GBASE_CR4_CU:
|
||||
ecmd->supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_40000baseCR4_Full;
|
||||
ecmd->advertising = ADVERTISED_Autoneg |
|
||||
ADVERTISED_40000baseCR4_Full;
|
||||
supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_40000baseCR4_Full;
|
||||
advertising = ADVERTISED_Autoneg |
|
||||
ADVERTISED_40000baseCR4_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_XLAUI:
|
||||
case I40E_PHY_TYPE_XLPPI:
|
||||
case I40E_PHY_TYPE_40GBASE_AOC:
|
||||
ecmd->supported = SUPPORTED_40000baseCR4_Full;
|
||||
supported = SUPPORTED_40000baseCR4_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_40GBASE_SR4:
|
||||
ecmd->supported = SUPPORTED_40000baseSR4_Full;
|
||||
supported = SUPPORTED_40000baseSR4_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_40GBASE_LR4:
|
||||
ecmd->supported = SUPPORTED_40000baseLR4_Full;
|
||||
supported = SUPPORTED_40000baseLR4_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_10GBASE_SR:
|
||||
case I40E_PHY_TYPE_10GBASE_LR:
|
||||
case I40E_PHY_TYPE_1000BASE_SX:
|
||||
case I40E_PHY_TYPE_1000BASE_LX:
|
||||
ecmd->supported = SUPPORTED_10000baseT_Full;
|
||||
supported = SUPPORTED_10000baseT_Full;
|
||||
if (hw_link_info->module_type[2] &
|
||||
I40E_MODULE_TYPE_1000BASE_SX ||
|
||||
hw_link_info->module_type[2] &
|
||||
I40E_MODULE_TYPE_1000BASE_LX) {
|
||||
ecmd->supported |= SUPPORTED_1000baseT_Full;
|
||||
supported |= SUPPORTED_1000baseT_Full;
|
||||
if (hw_link_info->requested_speeds &
|
||||
I40E_LINK_SPEED_1GB)
|
||||
ecmd->advertising |= ADVERTISED_1000baseT_Full;
|
||||
advertising |= ADVERTISED_1000baseT_Full;
|
||||
}
|
||||
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB)
|
||||
ecmd->advertising |= ADVERTISED_10000baseT_Full;
|
||||
advertising |= ADVERTISED_10000baseT_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_10GBASE_T:
|
||||
case I40E_PHY_TYPE_1000BASE_T:
|
||||
case I40E_PHY_TYPE_100BASE_TX:
|
||||
ecmd->supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_10000baseT_Full |
|
||||
SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_100baseT_Full;
|
||||
ecmd->advertising = ADVERTISED_Autoneg;
|
||||
supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_10000baseT_Full |
|
||||
SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_100baseT_Full;
|
||||
advertising = ADVERTISED_Autoneg;
|
||||
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB)
|
||||
ecmd->advertising |= ADVERTISED_10000baseT_Full;
|
||||
advertising |= ADVERTISED_10000baseT_Full;
|
||||
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
|
||||
ecmd->advertising |= ADVERTISED_1000baseT_Full;
|
||||
advertising |= ADVERTISED_1000baseT_Full;
|
||||
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_100MB)
|
||||
ecmd->advertising |= ADVERTISED_100baseT_Full;
|
||||
advertising |= ADVERTISED_100baseT_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
|
||||
ecmd->supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_1000baseT_Full;
|
||||
ecmd->advertising = ADVERTISED_Autoneg |
|
||||
ADVERTISED_1000baseT_Full;
|
||||
supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_1000baseT_Full;
|
||||
advertising = ADVERTISED_Autoneg |
|
||||
ADVERTISED_1000baseT_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_10GBASE_CR1_CU:
|
||||
case I40E_PHY_TYPE_10GBASE_CR1:
|
||||
ecmd->supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_10000baseT_Full;
|
||||
ecmd->advertising = ADVERTISED_Autoneg |
|
||||
ADVERTISED_10000baseT_Full;
|
||||
supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_10000baseT_Full;
|
||||
advertising = ADVERTISED_Autoneg |
|
||||
ADVERTISED_10000baseT_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_XAUI:
|
||||
case I40E_PHY_TYPE_XFI:
|
||||
case I40E_PHY_TYPE_SFI:
|
||||
case I40E_PHY_TYPE_10GBASE_SFPP_CU:
|
||||
case I40E_PHY_TYPE_10GBASE_AOC:
|
||||
ecmd->supported = SUPPORTED_10000baseT_Full;
|
||||
ecmd->advertising = SUPPORTED_10000baseT_Full;
|
||||
supported = SUPPORTED_10000baseT_Full;
|
||||
advertising = SUPPORTED_10000baseT_Full;
|
||||
break;
|
||||
case I40E_PHY_TYPE_SGMII:
|
||||
ecmd->supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_1000baseT_Full;
|
||||
supported = SUPPORTED_Autoneg |
|
||||
SUPPORTED_1000baseT_Full;
|
||||
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
|
||||
ecmd->advertising |= ADVERTISED_1000baseT_Full;
|
||||
advertising |= ADVERTISED_1000baseT_Full;
|
||||
if (pf->flags & I40E_FLAG_100M_SGMII_CAPABLE) {
|
||||
ecmd->supported |= SUPPORTED_100baseT_Full;
|
||||
supported |= SUPPORTED_100baseT_Full;
|
||||
if (hw_link_info->requested_speeds &
|
||||
I40E_LINK_SPEED_100MB)
|
||||
ecmd->advertising |= ADVERTISED_100baseT_Full;
|
||||
advertising |= ADVERTISED_100baseT_Full;
|
||||
}
|
||||
break;
|
||||
case I40E_PHY_TYPE_40GBASE_KR4:
|
||||
|
|
@ -486,25 +492,25 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
|
|||
case I40E_PHY_TYPE_10GBASE_KR:
|
||||
case I40E_PHY_TYPE_10GBASE_KX4:
|
||||
case I40E_PHY_TYPE_1000BASE_KX:
|
||||
ecmd->supported |= SUPPORTED_40000baseKR4_Full |
|
||||
SUPPORTED_20000baseKR2_Full |
|
||||
SUPPORTED_10000baseKR_Full |
|
||||
SUPPORTED_10000baseKX4_Full |
|
||||
SUPPORTED_1000baseKX_Full |
|
||||
SUPPORTED_Autoneg;
|
||||
ecmd->advertising |= ADVERTISED_40000baseKR4_Full |
|
||||
ADVERTISED_20000baseKR2_Full |
|
||||
ADVERTISED_10000baseKR_Full |
|
||||
ADVERTISED_10000baseKX4_Full |
|
||||
ADVERTISED_1000baseKX_Full |
|
||||
ADVERTISED_Autoneg;
|
||||
supported |= SUPPORTED_40000baseKR4_Full |
|
||||
SUPPORTED_20000baseKR2_Full |
|
||||
SUPPORTED_10000baseKR_Full |
|
||||
SUPPORTED_10000baseKX4_Full |
|
||||
SUPPORTED_1000baseKX_Full |
|
||||
SUPPORTED_Autoneg;
|
||||
advertising |= ADVERTISED_40000baseKR4_Full |
|
||||
ADVERTISED_20000baseKR2_Full |
|
||||
ADVERTISED_10000baseKR_Full |
|
||||
ADVERTISED_10000baseKX4_Full |
|
||||
ADVERTISED_1000baseKX_Full |
|
||||
ADVERTISED_Autoneg;
|
||||
break;
|
||||
case I40E_PHY_TYPE_25GBASE_KR:
|
||||
case I40E_PHY_TYPE_25GBASE_CR:
|
||||
case I40E_PHY_TYPE_25GBASE_SR:
|
||||
case I40E_PHY_TYPE_25GBASE_LR:
|
||||
ecmd->supported = SUPPORTED_Autoneg;
|
||||
ecmd->advertising = ADVERTISED_Autoneg;
|
||||
supported = SUPPORTED_Autoneg;
|
||||
advertising = ADVERTISED_Autoneg;
|
||||
/* TODO: add speeds when ethtool is ready to support*/
|
||||
break;
|
||||
default:
|
||||
|
|
@ -520,38 +526,43 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
|
|||
i40e_phy_type_to_ethtool(pf, &e_supported,
|
||||
&e_advertising);
|
||||
|
||||
ecmd->supported = ecmd->supported & e_supported;
|
||||
ecmd->advertising = ecmd->advertising & e_advertising;
|
||||
supported = supported & e_supported;
|
||||
advertising = advertising & e_advertising;
|
||||
|
||||
/* Set speed and duplex */
|
||||
switch (link_speed) {
|
||||
case I40E_LINK_SPEED_40GB:
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_40000);
|
||||
cmd->base.speed = SPEED_40000;
|
||||
break;
|
||||
case I40E_LINK_SPEED_25GB:
|
||||
#ifdef SPEED_25000
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_25000);
|
||||
cmd->base.speed = SPEED_25000;
|
||||
#else
|
||||
netdev_info(netdev,
|
||||
"Speed is 25G, display not supported by this version of ethtool.\n");
|
||||
#endif
|
||||
break;
|
||||
case I40E_LINK_SPEED_20GB:
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_20000);
|
||||
cmd->base.speed = SPEED_20000;
|
||||
break;
|
||||
case I40E_LINK_SPEED_10GB:
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_10000);
|
||||
cmd->base.speed = SPEED_10000;
|
||||
break;
|
||||
case I40E_LINK_SPEED_1GB:
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_1000);
|
||||
cmd->base.speed = SPEED_1000;
|
||||
break;
|
||||
case I40E_LINK_SPEED_100MB:
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_100);
|
||||
cmd->base.speed = SPEED_100;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ecmd->duplex = DUPLEX_FULL;
|
||||
cmd->base.duplex = DUPLEX_FULL;
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
|
||||
supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
|
||||
advertising);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -562,18 +573,24 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
|
|||
* Reports link settings that can be determined when link is down
|
||||
**/
|
||||
static void i40e_get_settings_link_down(struct i40e_hw *hw,
|
||||
struct ethtool_cmd *ecmd,
|
||||
struct ethtool_link_ksettings *cmd,
|
||||
struct i40e_pf *pf)
|
||||
{
|
||||
u32 supported, advertising;
|
||||
|
||||
/* link is down and the driver needs to fall back on
|
||||
* supported phy types to figure out what info to display
|
||||
*/
|
||||
i40e_phy_type_to_ethtool(pf, &ecmd->supported,
|
||||
&ecmd->advertising);
|
||||
i40e_phy_type_to_ethtool(pf, &supported, &advertising);
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
|
||||
supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
|
||||
advertising);
|
||||
|
||||
/* With no link speed and duplex are unknown */
|
||||
ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
|
||||
ecmd->duplex = DUPLEX_UNKNOWN;
|
||||
cmd->base.speed = SPEED_UNKNOWN;
|
||||
cmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -583,74 +600,85 @@ static void i40e_get_settings_link_down(struct i40e_hw *hw,
|
|||
*
|
||||
* Reports speed/duplex settings based on media_type
|
||||
**/
|
||||
static int i40e_get_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *ecmd)
|
||||
static int i40e_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_pf *pf = np->vsi->back;
|
||||
struct i40e_hw *hw = &pf->hw;
|
||||
struct i40e_link_status *hw_link_info = &hw->phy.link_info;
|
||||
bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
|
||||
u32 advertising;
|
||||
|
||||
if (link_up)
|
||||
i40e_get_settings_link_up(hw, ecmd, netdev, pf);
|
||||
i40e_get_settings_link_up(hw, cmd, netdev, pf);
|
||||
else
|
||||
i40e_get_settings_link_down(hw, ecmd, pf);
|
||||
i40e_get_settings_link_down(hw, cmd, pf);
|
||||
|
||||
/* Now set the settings that don't rely on link being up/down */
|
||||
/* Set autoneg settings */
|
||||
ecmd->autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
|
||||
cmd->base.autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
|
||||
AUTONEG_ENABLE : AUTONEG_DISABLE);
|
||||
|
||||
switch (hw->phy.media_type) {
|
||||
case I40E_MEDIA_TYPE_BACKPLANE:
|
||||
ecmd->supported |= SUPPORTED_Autoneg |
|
||||
SUPPORTED_Backplane;
|
||||
ecmd->advertising |= ADVERTISED_Autoneg |
|
||||
ADVERTISED_Backplane;
|
||||
ecmd->port = PORT_NONE;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported,
|
||||
Autoneg);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported,
|
||||
Backplane);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Autoneg);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Backplane);
|
||||
cmd->base.port = PORT_NONE;
|
||||
break;
|
||||
case I40E_MEDIA_TYPE_BASET:
|
||||
ecmd->supported |= SUPPORTED_TP;
|
||||
ecmd->advertising |= ADVERTISED_TP;
|
||||
ecmd->port = PORT_TP;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
|
||||
cmd->base.port = PORT_TP;
|
||||
break;
|
||||
case I40E_MEDIA_TYPE_DA:
|
||||
case I40E_MEDIA_TYPE_CX4:
|
||||
ecmd->supported |= SUPPORTED_FIBRE;
|
||||
ecmd->advertising |= ADVERTISED_FIBRE;
|
||||
ecmd->port = PORT_DA;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
|
||||
cmd->base.port = PORT_DA;
|
||||
break;
|
||||
case I40E_MEDIA_TYPE_FIBER:
|
||||
ecmd->supported |= SUPPORTED_FIBRE;
|
||||
ecmd->port = PORT_FIBRE;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
|
||||
cmd->base.port = PORT_FIBRE;
|
||||
break;
|
||||
case I40E_MEDIA_TYPE_UNKNOWN:
|
||||
default:
|
||||
ecmd->port = PORT_OTHER;
|
||||
cmd->base.port = PORT_OTHER;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set transceiver */
|
||||
ecmd->transceiver = XCVR_EXTERNAL;
|
||||
|
||||
/* Set flow control settings */
|
||||
ecmd->supported |= SUPPORTED_Pause;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
|
||||
|
||||
switch (hw->fc.requested_mode) {
|
||||
case I40E_FC_FULL:
|
||||
ecmd->advertising |= ADVERTISED_Pause;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Pause);
|
||||
break;
|
||||
case I40E_FC_TX_PAUSE:
|
||||
ecmd->advertising |= ADVERTISED_Asym_Pause;
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
break;
|
||||
case I40E_FC_RX_PAUSE:
|
||||
ecmd->advertising |= (ADVERTISED_Pause |
|
||||
ADVERTISED_Asym_Pause);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Pause);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
break;
|
||||
default:
|
||||
ecmd->advertising &= ~(ADVERTISED_Pause |
|
||||
ADVERTISED_Asym_Pause);
|
||||
ethtool_convert_link_mode_to_legacy_u32(
|
||||
&advertising, cmd->link_modes.advertising);
|
||||
|
||||
advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
cmd->link_modes.advertising, advertising);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -664,8 +692,8 @@ static int i40e_get_settings(struct net_device *netdev,
|
|||
*
|
||||
* Set speed/duplex per media_types advertised/forced
|
||||
**/
|
||||
static int i40e_set_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *ecmd)
|
||||
static int i40e_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_aq_get_phy_abilities_resp abilities;
|
||||
|
|
@ -673,12 +701,14 @@ static int i40e_set_settings(struct net_device *netdev,
|
|||
struct i40e_pf *pf = np->vsi->back;
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_hw *hw = &pf->hw;
|
||||
struct ethtool_cmd safe_ecmd;
|
||||
struct ethtool_link_ksettings safe_cmd;
|
||||
struct ethtool_link_ksettings copy_cmd;
|
||||
i40e_status status = 0;
|
||||
bool change = false;
|
||||
int err = 0;
|
||||
u8 autoneg;
|
||||
u32 autoneg;
|
||||
u32 advertise;
|
||||
u32 tmp;
|
||||
|
||||
/* Changing port settings is not supported if this isn't the
|
||||
* port's controlling PF
|
||||
|
|
@ -706,23 +736,31 @@ static int i40e_set_settings(struct net_device *netdev,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* get our own copy of the bits to check against */
|
||||
memset(&safe_ecmd, 0, sizeof(struct ethtool_cmd));
|
||||
i40e_get_settings(netdev, &safe_ecmd);
|
||||
/* copy the cmd to copy_cmd to avoid modifying the origin */
|
||||
memcpy(©_cmd, cmd, sizeof(struct ethtool_link_ksettings));
|
||||
|
||||
/* save autoneg and speed out of ecmd */
|
||||
autoneg = ecmd->autoneg;
|
||||
advertise = ecmd->advertising;
|
||||
/* get our own copy of the bits to check against */
|
||||
memset(&safe_cmd, 0, sizeof(struct ethtool_link_ksettings));
|
||||
i40e_get_link_ksettings(netdev, &safe_cmd);
|
||||
|
||||
/* save autoneg and speed out of cmd */
|
||||
autoneg = cmd->base.autoneg;
|
||||
ethtool_convert_link_mode_to_legacy_u32(&advertise,
|
||||
cmd->link_modes.advertising);
|
||||
|
||||
/* set autoneg and speed back to what they currently are */
|
||||
ecmd->autoneg = safe_ecmd.autoneg;
|
||||
ecmd->advertising = safe_ecmd.advertising;
|
||||
copy_cmd.base.autoneg = safe_cmd.base.autoneg;
|
||||
ethtool_convert_link_mode_to_legacy_u32(
|
||||
&tmp, safe_cmd.link_modes.advertising);
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
copy_cmd.link_modes.advertising, tmp);
|
||||
|
||||
ecmd->cmd = safe_ecmd.cmd;
|
||||
/* If ecmd and safe_ecmd are not the same now, then they are
|
||||
copy_cmd.base.cmd = safe_cmd.base.cmd;
|
||||
|
||||
/* If copy_cmd and safe_cmd are not the same now, then they are
|
||||
* trying to set something that we do not support
|
||||
*/
|
||||
if (memcmp(ecmd, &safe_ecmd, sizeof(struct ethtool_cmd)))
|
||||
if (memcmp(©_cmd, &safe_cmd, sizeof(struct ethtool_link_ksettings)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
while (test_bit(__I40E_CONFIG_BUSY, &vsi->state))
|
||||
|
|
@ -745,7 +783,8 @@ static int i40e_set_settings(struct net_device *netdev,
|
|||
/* If autoneg was not already enabled */
|
||||
if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) {
|
||||
/* If autoneg is not supported, return error */
|
||||
if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) {
|
||||
if (!ethtool_link_ksettings_test_link_mode(
|
||||
&safe_cmd, supported, Autoneg)) {
|
||||
netdev_info(netdev, "Autoneg not supported on this phy\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -760,7 +799,8 @@ static int i40e_set_settings(struct net_device *netdev,
|
|||
/* If autoneg is supported 10GBASE_T is the only PHY
|
||||
* that can disable it, so otherwise return error
|
||||
*/
|
||||
if (safe_ecmd.supported & SUPPORTED_Autoneg &&
|
||||
if (ethtool_link_ksettings_test_link_mode(
|
||||
&safe_cmd, supported, Autoneg) &&
|
||||
hw->phy.link_info.phy_type !=
|
||||
I40E_PHY_TYPE_10GBASE_T) {
|
||||
netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
|
||||
|
|
@ -773,7 +813,9 @@ static int i40e_set_settings(struct net_device *netdev,
|
|||
}
|
||||
}
|
||||
|
||||
if (advertise & ~safe_ecmd.supported)
|
||||
ethtool_convert_link_mode_to_legacy_u32(&tmp,
|
||||
safe_cmd.link_modes.supported);
|
||||
if (advertise & ~tmp)
|
||||
return -EINVAL;
|
||||
|
||||
if (advertise & ADVERTISED_100baseT_Full)
|
||||
|
|
@ -1165,6 +1207,11 @@ static int i40e_get_eeprom_len(struct net_device *netdev)
|
|||
struct i40e_hw *hw = &np->vsi->back->hw;
|
||||
u32 val;
|
||||
|
||||
#define X722_EEPROM_SCOPE_LIMIT 0x5B9FFF
|
||||
if (hw->mac.type == I40E_MAC_X722) {
|
||||
val = X722_EEPROM_SCOPE_LIMIT + 1;
|
||||
return val;
|
||||
}
|
||||
val = (rd32(hw, I40E_GLPCI_LBARCTRL)
|
||||
& I40E_GLPCI_LBARCTRL_FL_SIZE_MASK)
|
||||
>> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT;
|
||||
|
|
@ -2359,8 +2406,8 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
|
|||
*/
|
||||
fsp->h_u.tcp_ip4_spec.psrc = rule->dst_port;
|
||||
fsp->h_u.tcp_ip4_spec.pdst = rule->src_port;
|
||||
fsp->h_u.tcp_ip4_spec.ip4src = rule->dst_ip[0];
|
||||
fsp->h_u.tcp_ip4_spec.ip4dst = rule->src_ip[0];
|
||||
fsp->h_u.tcp_ip4_spec.ip4src = rule->dst_ip;
|
||||
fsp->h_u.tcp_ip4_spec.ip4dst = rule->src_ip;
|
||||
|
||||
if (rule->dest_ctl == I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET)
|
||||
fsp->ring_cookie = RX_CLS_FLOW_DISC;
|
||||
|
|
@ -2573,24 +2620,6 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_match_fdir_input_set - Match a new filter against an existing one
|
||||
* @rule: The filter already added
|
||||
* @input: The new filter to comapre against
|
||||
*
|
||||
* Returns true if the two input set match
|
||||
**/
|
||||
static bool i40e_match_fdir_input_set(struct i40e_fdir_filter *rule,
|
||||
struct i40e_fdir_filter *input)
|
||||
{
|
||||
if ((rule->dst_ip[0] != input->dst_ip[0]) ||
|
||||
(rule->src_ip[0] != input->src_ip[0]) ||
|
||||
(rule->dst_port != input->dst_port) ||
|
||||
(rule->src_port != input->src_port))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_update_ethtool_fdir_entry - Updates the fdir filter entry
|
||||
* @vsi: Pointer to the targeted VSI
|
||||
|
|
@ -2626,22 +2655,22 @@ static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,
|
|||
|
||||
/* if there is an old rule occupying our place remove it */
|
||||
if (rule && (rule->fd_id == sw_idx)) {
|
||||
if (input && !i40e_match_fdir_input_set(rule, input))
|
||||
err = i40e_add_del_fdir(vsi, rule, false);
|
||||
else if (!input)
|
||||
err = i40e_add_del_fdir(vsi, rule, false);
|
||||
/* Remove this rule, since we're either deleting it, or
|
||||
* replacing it.
|
||||
*/
|
||||
err = i40e_add_del_fdir(vsi, rule, false);
|
||||
hlist_del(&rule->fdir_node);
|
||||
kfree(rule);
|
||||
pf->fdir_pf_active_filters--;
|
||||
}
|
||||
|
||||
/* If no input this was a delete, err should be 0 if a rule was
|
||||
* successfully found and removed from the list else -EINVAL
|
||||
/* If we weren't given an input, this is a delete, so just return the
|
||||
* error code indicating if there was an entry at the requested slot
|
||||
*/
|
||||
if (!input)
|
||||
return err;
|
||||
|
||||
/* initialize node and set software index */
|
||||
/* Otherwise, install the new rule as requested */
|
||||
INIT_HLIST_NODE(&input->fdir_node);
|
||||
|
||||
/* add filter to the list */
|
||||
|
|
@ -2712,7 +2741,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
|
|||
if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)
|
||||
if (pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED)
|
||||
return -ENOSPC;
|
||||
|
||||
if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
|
||||
|
|
@ -2724,6 +2753,10 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
|
|||
|
||||
fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
|
||||
|
||||
/* Extended MAC field is not supported */
|
||||
if (fsp->flow_type & FLOW_MAC_EXT)
|
||||
return -EINVAL;
|
||||
|
||||
if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
|
||||
pf->hw.func_caps.fd_filters_guaranteed)) {
|
||||
return -EINVAL;
|
||||
|
|
@ -2760,8 +2793,8 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
|
|||
*/
|
||||
input->dst_port = fsp->h_u.tcp_ip4_spec.psrc;
|
||||
input->src_port = fsp->h_u.tcp_ip4_spec.pdst;
|
||||
input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
|
||||
input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
|
||||
input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
|
||||
input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
|
||||
|
||||
if (ntohl(fsp->m_ext.data[1])) {
|
||||
vf_id = ntohl(fsp->h_ext.data[1]);
|
||||
|
|
@ -2781,12 +2814,19 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
|
|||
}
|
||||
|
||||
ret = i40e_add_del_fdir(vsi, input, true);
|
||||
free_input:
|
||||
if (ret)
|
||||
kfree(input);
|
||||
else
|
||||
i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
|
||||
goto free_input;
|
||||
|
||||
/* Add the input filter to the fdir_input_list, possibly replacing
|
||||
* a previous filter. Do not free the input structure after adding it
|
||||
* to the list as this would cause a use-after-free bug.
|
||||
*/
|
||||
i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
free_input:
|
||||
kfree(input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3054,7 +3094,7 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
|
|||
I40E_PRIV_FLAGS_FD_ATR : 0;
|
||||
ret_flags |= pf->flags & I40E_FLAG_VEB_STATS_ENABLED ?
|
||||
I40E_PRIV_FLAGS_VEB_STATS : 0;
|
||||
ret_flags |= pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ?
|
||||
ret_flags |= pf->hw_disabled_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ?
|
||||
0 : I40E_PRIV_FLAGS_HW_ATR_EVICT;
|
||||
if (pf->hw.pf_id == 0) {
|
||||
ret_flags |= pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT ?
|
||||
|
|
@ -3094,7 +3134,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
|
|||
pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
} else {
|
||||
pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
|
||||
/* flush current ATR settings */
|
||||
set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
|
||||
|
|
@ -3139,9 +3179,9 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
|
|||
|
||||
if ((flags & I40E_PRIV_FLAGS_HW_ATR_EVICT) &&
|
||||
(pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
else
|
||||
pf->auto_disable_flags |= I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
pf->hw_disabled_flags |= I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
|
||||
/* if needed, issue reset to cause things to take effect */
|
||||
if (reset_required)
|
||||
|
|
@ -3151,8 +3191,6 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
|
|||
}
|
||||
|
||||
static const struct ethtool_ops i40e_ethtool_ops = {
|
||||
.get_settings = i40e_get_settings,
|
||||
.set_settings = i40e_set_settings,
|
||||
.get_drvinfo = i40e_get_drvinfo,
|
||||
.get_regs_len = i40e_get_regs_len,
|
||||
.get_regs = i40e_get_regs,
|
||||
|
|
@ -3189,6 +3227,8 @@ static const struct ethtool_ops i40e_ethtool_ops = {
|
|||
.set_priv_flags = i40e_set_priv_flags,
|
||||
.get_per_queue_coalesce = i40e_get_per_queue_coalesce,
|
||||
.set_per_queue_coalesce = i40e_set_per_queue_coalesce,
|
||||
.get_link_ksettings = i40e_get_link_ksettings,
|
||||
.set_link_ksettings = i40e_set_link_ksettings,
|
||||
};
|
||||
|
||||
void i40e_set_ethtool_ops(struct net_device *netdev)
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ static const char i40e_driver_string[] =
|
|||
|
||||
#define DRV_KERN "-k"
|
||||
|
||||
#define DRV_VERSION_MAJOR 1
|
||||
#define DRV_VERSION_MINOR 6
|
||||
#define DRV_VERSION_BUILD 27
|
||||
#define DRV_VERSION_MAJOR 2
|
||||
#define DRV_VERSION_MINOR 1
|
||||
#define DRV_VERSION_BUILD 7
|
||||
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
|
||||
__stringify(DRV_VERSION_MINOR) "." \
|
||||
__stringify(DRV_VERSION_BUILD) DRV_KERN
|
||||
|
|
@ -1101,13 +1101,13 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
|
|||
&osd->rx_lpi_count, &nsd->rx_lpi_count);
|
||||
|
||||
if (pf->flags & I40E_FLAG_FD_SB_ENABLED &&
|
||||
!(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
|
||||
!(pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED))
|
||||
nsd->fd_sb_status = true;
|
||||
else
|
||||
nsd->fd_sb_status = false;
|
||||
|
||||
if (pf->flags & I40E_FLAG_FD_ATR_ENABLED &&
|
||||
!(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
!(pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
nsd->fd_atr_status = true;
|
||||
else
|
||||
nsd->fd_atr_status = false;
|
||||
|
|
@ -2487,13 +2487,15 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
|
|||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
|
||||
netdev_info(netdev, "changing MTU from %d to %d\n",
|
||||
netdev->mtu, new_mtu);
|
||||
netdev->mtu = new_mtu;
|
||||
if (netif_running(netdev))
|
||||
i40e_vsi_reinit_locked(vsi);
|
||||
i40e_notify_client_of_l2_param_changes(vsi);
|
||||
pf->flags |= (I40E_FLAG_SERVICE_CLIENT_REQUESTED |
|
||||
I40E_FLAG_CLIENT_L2_CHANGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3281,6 +3283,11 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
|
|||
if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
|
||||
return;
|
||||
|
||||
/* Reset FDir counters as we're replaying all existing filters */
|
||||
pf->fd_tcp4_filter_cnt = 0;
|
||||
pf->fd_udp4_filter_cnt = 0;
|
||||
pf->fd_ip4_filter_cnt = 0;
|
||||
|
||||
hlist_for_each_entry_safe(filter, node,
|
||||
&pf->fdir_filter_list, fdir_node) {
|
||||
i40e_add_del_fdir(vsi, filter, true);
|
||||
|
|
@ -4463,17 +4470,16 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi)
|
|||
**/
|
||||
static void i40e_vsi_close(struct i40e_vsi *vsi)
|
||||
{
|
||||
bool reset = false;
|
||||
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
if (!test_and_set_bit(__I40E_DOWN, &vsi->state))
|
||||
i40e_down(vsi);
|
||||
i40e_vsi_free_irq(vsi);
|
||||
i40e_vsi_free_tx_resources(vsi);
|
||||
i40e_vsi_free_rx_resources(vsi);
|
||||
vsi->current_netdev_flags = 0;
|
||||
if (test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
|
||||
reset = true;
|
||||
i40e_notify_client_of_netdev_close(vsi, reset);
|
||||
pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
|
||||
if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
|
||||
pf->flags |= I40E_FLAG_CLIENT_RESET;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5464,13 +5470,8 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
|
|||
/* replay FDIR SB filters */
|
||||
if (vsi->type == I40E_VSI_FDIR) {
|
||||
/* reset fd counters */
|
||||
pf->fd_add_err = pf->fd_atr_cnt = 0;
|
||||
if (pf->fd_tcp_rule > 0) {
|
||||
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
if (I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
|
||||
pf->fd_tcp_rule = 0;
|
||||
}
|
||||
pf->fd_add_err = 0;
|
||||
pf->fd_atr_cnt = 0;
|
||||
i40e_fdir_filter_restore(vsi);
|
||||
}
|
||||
|
||||
|
|
@ -5542,8 +5543,6 @@ void i40e_down(struct i40e_vsi *vsi)
|
|||
i40e_clean_rx_ring(vsi->rx_rings[i]);
|
||||
}
|
||||
|
||||
i40e_notify_client_of_netdev_close(vsi, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5612,9 +5611,12 @@ static int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
|
|||
struct tc_to_netdev *tc)
|
||||
#endif
|
||||
{
|
||||
if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
|
||||
if (tc->type != TC_SETUP_MQPRIO)
|
||||
return -EINVAL;
|
||||
return i40e_setup_tc(netdev, tc->tc);
|
||||
|
||||
tc->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
|
||||
|
||||
return i40e_setup_tc(netdev, tc->mqprio->num_tc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -5752,7 +5754,11 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf)
|
|||
hlist_del(&filter->fdir_node);
|
||||
kfree(filter);
|
||||
}
|
||||
|
||||
pf->fdir_pf_active_filters = 0;
|
||||
pf->fd_tcp4_filter_cnt = 0;
|
||||
pf->fd_udp4_filter_cnt = 0;
|
||||
pf->fd_ip4_filter_cnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -6021,8 +6027,8 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
|
|||
i40e_service_event_schedule(pf);
|
||||
} else {
|
||||
i40e_pf_unquiesce_all_vsi(pf);
|
||||
/* Notify the client for the DCB changes */
|
||||
i40e_notify_client_of_l2_param_changes(pf->vsi[pf->lan_vsi]);
|
||||
pf->flags |= (I40E_FLAG_SERVICE_CLIENT_REQUESTED |
|
||||
I40E_FLAG_CLIENT_L2_CHANGE);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
|
@ -6144,8 +6150,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
|
|||
(pf->fd_add_err == 0) ||
|
||||
(i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) {
|
||||
if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
|
||||
(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
|
||||
(pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED)) {
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_FD_SB_ENABLED;
|
||||
if (I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
|
||||
}
|
||||
|
|
@ -6156,9 +6162,9 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
|
|||
*/
|
||||
if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
|
||||
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
(pf->fd_tcp_rule == 0)) {
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
(pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
(pf->fd_tcp4_filter_cnt == 0)) {
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
if (I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
|
||||
}
|
||||
|
|
@ -6210,7 +6216,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
|
|||
}
|
||||
|
||||
pf->fd_flush_timestamp = jiffies;
|
||||
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
/* flush all filters */
|
||||
wr32(&pf->hw, I40E_PFQF_CTL_1,
|
||||
I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
|
||||
|
|
@ -6229,8 +6235,8 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
|
|||
} else {
|
||||
/* replay sideband filters */
|
||||
i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]);
|
||||
if (!disable_atr)
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
if (!disable_atr && !pf->fd_tcp4_filter_cnt)
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
|
||||
if (I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
|
||||
|
|
@ -7351,7 +7357,7 @@ static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
|
|||
{
|
||||
struct i40e_hw *hw = &pf->hw;
|
||||
i40e_status ret;
|
||||
__be16 port;
|
||||
u16 port;
|
||||
int i;
|
||||
|
||||
if (!(pf->flags & I40E_FLAG_UDP_FILTER_SYNC))
|
||||
|
|
@ -7375,7 +7381,7 @@ static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
|
|||
"%s %s port %d, index %d failed, err %s aq_err %s\n",
|
||||
pf->udp_ports[i].type ? "vxlan" : "geneve",
|
||||
port ? "add" : "delete",
|
||||
ntohs(port), i,
|
||||
port, i,
|
||||
i40e_stat_str(&pf->hw, ret),
|
||||
i40e_aq_str(&pf->hw,
|
||||
pf->hw.aq.asq_last_status));
|
||||
|
|
@ -7411,7 +7417,18 @@ static void i40e_service_task(struct work_struct *work)
|
|||
i40e_vc_process_vflr_event(pf);
|
||||
i40e_watchdog_subtask(pf);
|
||||
i40e_fdir_reinit_subtask(pf);
|
||||
i40e_client_subtask(pf);
|
||||
if (pf->flags & I40E_FLAG_CLIENT_RESET) {
|
||||
/* Client subtask will reopen next time through. */
|
||||
i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], true);
|
||||
pf->flags &= ~I40E_FLAG_CLIENT_RESET;
|
||||
} else {
|
||||
i40e_client_subtask(pf);
|
||||
if (pf->flags & I40E_FLAG_CLIENT_L2_CHANGE) {
|
||||
i40e_notify_client_of_l2_param_changes(
|
||||
pf->vsi[pf->lan_vsi]);
|
||||
pf->flags &= ~I40E_FLAG_CLIENT_L2_CHANGE;
|
||||
}
|
||||
}
|
||||
i40e_sync_filters_subtask(pf);
|
||||
i40e_sync_udp_filters_subtask(pf);
|
||||
i40e_clean_adminq_subtask(pf);
|
||||
|
|
@ -7809,6 +7826,7 @@ static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors)
|
|||
static int i40e_init_msix(struct i40e_pf *pf)
|
||||
{
|
||||
struct i40e_hw *hw = &pf->hw;
|
||||
int cpus, extra_vectors;
|
||||
int vectors_left;
|
||||
int v_budget, i;
|
||||
int v_actual;
|
||||
|
|
@ -7844,10 +7862,16 @@ static int i40e_init_msix(struct i40e_pf *pf)
|
|||
vectors_left--;
|
||||
}
|
||||
|
||||
/* reserve vectors for the main PF traffic queues */
|
||||
pf->num_lan_msix = min_t(int, num_online_cpus(), vectors_left);
|
||||
/* reserve some vectors for the main PF traffic queues. Initially we
|
||||
* only reserve at most 50% of the available vectors, in the case that
|
||||
* the number of online CPUs is large. This ensures that we can enable
|
||||
* extra features as well. Once we've enabled the other features, we
|
||||
* will use any remaining vectors to reach as close as we can to the
|
||||
* number of online CPUs.
|
||||
*/
|
||||
cpus = num_online_cpus();
|
||||
pf->num_lan_msix = min_t(int, cpus, vectors_left / 2);
|
||||
vectors_left -= pf->num_lan_msix;
|
||||
v_budget += pf->num_lan_msix;
|
||||
|
||||
/* reserve one vector for sideband flow director */
|
||||
if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
|
||||
|
|
@ -7910,6 +7934,23 @@ static int i40e_init_msix(struct i40e_pf *pf)
|
|||
}
|
||||
}
|
||||
|
||||
/* On systems with a large number of SMP cores, we previously limited
|
||||
* the number of vectors for num_lan_msix to be at most 50% of the
|
||||
* available vectors, to allow for other features. Now, we add back
|
||||
* the remaining vectors. However, we ensure that the total
|
||||
* num_lan_msix will not exceed num_online_cpus(). To do this, we
|
||||
* calculate the number of vectors we can add without going over the
|
||||
* cap of CPUs. For systems with a small number of CPUs this will be
|
||||
* zero.
|
||||
*/
|
||||
extra_vectors = min_t(int, cpus - pf->num_lan_msix, vectors_left);
|
||||
pf->num_lan_msix += extra_vectors;
|
||||
vectors_left -= extra_vectors;
|
||||
|
||||
WARN(vectors_left < 0,
|
||||
"Calculation of remaining vectors underflowed. This is an accounting bug when determining total MSI-X vectors.\n");
|
||||
|
||||
v_budget += pf->num_lan_msix;
|
||||
pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
if (!pf->msix_entries)
|
||||
|
|
@ -8360,13 +8401,10 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
|
|||
|
||||
if (vsi->type == I40E_VSI_MAIN) {
|
||||
for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
|
||||
i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i),
|
||||
seed_dw[i]);
|
||||
wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
|
||||
} else if (vsi->type == I40E_VSI_SRIOV) {
|
||||
for (i = 0; i <= I40E_VFQF_HKEY1_MAX_INDEX; i++)
|
||||
i40e_write_rx_ctl(hw,
|
||||
I40E_VFQF_HKEY1(i, vf_id),
|
||||
seed_dw[i]);
|
||||
wr32(hw, I40E_VFQF_HKEY1(i, vf_id), seed_dw[i]);
|
||||
} else {
|
||||
dev_err(&pf->pdev->dev, "Cannot set RSS seed - invalid VSI type\n");
|
||||
}
|
||||
|
|
@ -8384,9 +8422,7 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
|
|||
if (lut_size != I40E_VF_HLUT_ARRAY_SIZE)
|
||||
return -EINVAL;
|
||||
for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
|
||||
i40e_write_rx_ctl(hw,
|
||||
I40E_VFQF_HLUT1(i, vf_id),
|
||||
lut_dw[i]);
|
||||
wr32(hw, I40E_VFQF_HLUT1(i, vf_id), lut_dw[i]);
|
||||
} else {
|
||||
dev_err(&pf->pdev->dev, "Cannot set RSS LUT - invalid VSI type\n");
|
||||
}
|
||||
|
|
@ -8843,9 +8879,9 @@ static int i40e_sw_init(struct i40e_pf *pf)
|
|||
(pf->hw.aq.api_min_ver > 4))) {
|
||||
/* Supported in FW API version higher than 1.4 */
|
||||
pf->flags |= I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
|
||||
pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
pf->hw_disabled_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
} else {
|
||||
pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
pf->hw_disabled_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
|
||||
}
|
||||
|
||||
pf->eeprom_version = 0xDEAD;
|
||||
|
|
@ -8906,14 +8942,14 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
|
|||
i40e_fdir_filter_exit(pf);
|
||||
}
|
||||
pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_FD_SB_ENABLED;
|
||||
/* reset fd counters */
|
||||
pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0;
|
||||
pf->fdir_pf_active_filters = 0;
|
||||
pf->fd_add_err = 0;
|
||||
pf->fd_atr_cnt = 0;
|
||||
/* if ATR was auto disabled it can be re-enabled. */
|
||||
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
(pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED)) {
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
if (I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
|
||||
}
|
||||
|
|
@ -8982,7 +9018,7 @@ static int i40e_set_features(struct net_device *netdev,
|
|||
*
|
||||
* Returns the index number or I40E_MAX_PF_UDP_OFFLOAD_PORTS if port not found
|
||||
**/
|
||||
static u8 i40e_get_udp_port_idx(struct i40e_pf *pf, __be16 port)
|
||||
static u8 i40e_get_udp_port_idx(struct i40e_pf *pf, u16 port)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
|
|
@ -9005,7 +9041,7 @@ static void i40e_udp_tunnel_add(struct net_device *netdev,
|
|||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
__be16 port = ti->port;
|
||||
u16 port = ntohs(ti->port);
|
||||
u8 next_idx;
|
||||
u8 idx;
|
||||
|
||||
|
|
@ -9013,8 +9049,7 @@ static void i40e_udp_tunnel_add(struct net_device *netdev,
|
|||
|
||||
/* Check if port already exists */
|
||||
if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
|
||||
netdev_info(netdev, "port %d already offloaded\n",
|
||||
ntohs(port));
|
||||
netdev_info(netdev, "port %d already offloaded\n", port);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -9023,7 +9058,7 @@ static void i40e_udp_tunnel_add(struct net_device *netdev,
|
|||
|
||||
if (next_idx == I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
|
||||
netdev_info(netdev, "maximum number of offloaded UDP ports reached, not adding port %d\n",
|
||||
ntohs(port));
|
||||
port);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -9057,7 +9092,7 @@ static void i40e_udp_tunnel_del(struct net_device *netdev,
|
|||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
__be16 port = ti->port;
|
||||
u16 port = ntohs(ti->port);
|
||||
u8 idx;
|
||||
|
||||
idx = i40e_get_udp_port_idx(pf, port);
|
||||
|
|
@ -9089,7 +9124,7 @@ static void i40e_udp_tunnel_del(struct net_device *netdev,
|
|||
return;
|
||||
not_found:
|
||||
netdev_warn(netdev, "UDP port %d was not found, not deleting\n",
|
||||
ntohs(port));
|
||||
port);
|
||||
}
|
||||
|
||||
static int i40e_get_phys_port_id(struct net_device *netdev,
|
||||
|
|
@ -9432,10 +9467,10 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
|
|||
if (vsi->type == I40E_VSI_MAIN) {
|
||||
SET_NETDEV_DEV(netdev, &pf->pdev->dev);
|
||||
ether_addr_copy(mac_addr, hw->mac.perm_addr);
|
||||
/* The following steps are necessary to prevent reception
|
||||
* of tagged packets - some older NVM configurations load a
|
||||
* default a MAC-VLAN filter that accepts any tagged packet
|
||||
* which must be replaced by a normal filter.
|
||||
/* The following steps are necessary to properly keep track of
|
||||
* MAC-VLAN filters loaded into firmware - first we remove
|
||||
* filter that is automatically generated by firmware and then
|
||||
* add new filter both to the driver hash table and firmware.
|
||||
*/
|
||||
i40e_rm_default_mac_filter(vsi, mac_addr);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
|
|
|||
|
|
@ -292,14 +292,14 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
|
|||
{
|
||||
enum i40e_status_code ret_code = 0;
|
||||
|
||||
if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
|
||||
ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
|
||||
if (!ret_code) {
|
||||
ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
|
||||
if (!ret_code) {
|
||||
if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
|
||||
ret_code = i40e_read_nvm_word_aq(hw, offset, data);
|
||||
i40e_release_nvm(hw);
|
||||
} else {
|
||||
ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
|
||||
}
|
||||
} else {
|
||||
ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
|
||||
i40e_release_nvm(hw);
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,7 +203,6 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
|
|||
struct i40e_pf *pf = vsi->back;
|
||||
struct udphdr *udp;
|
||||
struct iphdr *ip;
|
||||
bool err = false;
|
||||
u8 *raw_packet;
|
||||
int ret;
|
||||
static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
|
||||
|
|
@ -219,9 +218,9 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
|
|||
udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
|
||||
+ sizeof(struct iphdr));
|
||||
|
||||
ip->daddr = fd_data->dst_ip[0];
|
||||
ip->daddr = fd_data->dst_ip;
|
||||
udp->dest = fd_data->dst_port;
|
||||
ip->saddr = fd_data->src_ip[0];
|
||||
ip->saddr = fd_data->src_ip;
|
||||
udp->source = fd_data->src_port;
|
||||
|
||||
fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
|
||||
|
|
@ -230,7 +229,9 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
|
|||
dev_info(&pf->pdev->dev,
|
||||
"PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
|
||||
fd_data->pctype, fd_data->fd_id, ret);
|
||||
err = true;
|
||||
/* Free the packet buffer since it wasn't added to the ring */
|
||||
kfree(raw_packet);
|
||||
return -EOPNOTSUPP;
|
||||
} else if (I40E_DEBUG_FD & pf->hw.debug_mask) {
|
||||
if (add)
|
||||
dev_info(&pf->pdev->dev,
|
||||
|
|
@ -241,10 +242,13 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
|
|||
"Filter deleted for PCTYPE %d loc = %d\n",
|
||||
fd_data->pctype, fd_data->fd_id);
|
||||
}
|
||||
if (err)
|
||||
kfree(raw_packet);
|
||||
|
||||
return err ? -EOPNOTSUPP : 0;
|
||||
if (add)
|
||||
pf->fd_udp4_filter_cnt++;
|
||||
else
|
||||
pf->fd_udp4_filter_cnt--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define I40E_TCPIP_DUMMY_PACKET_LEN 54
|
||||
|
|
@ -263,7 +267,6 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
|
|||
struct i40e_pf *pf = vsi->back;
|
||||
struct tcphdr *tcp;
|
||||
struct iphdr *ip;
|
||||
bool err = false;
|
||||
u8 *raw_packet;
|
||||
int ret;
|
||||
/* Dummy packet */
|
||||
|
|
@ -281,36 +284,20 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
|
|||
tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
|
||||
+ sizeof(struct iphdr));
|
||||
|
||||
ip->daddr = fd_data->dst_ip[0];
|
||||
ip->daddr = fd_data->dst_ip;
|
||||
tcp->dest = fd_data->dst_port;
|
||||
ip->saddr = fd_data->src_ip[0];
|
||||
ip->saddr = fd_data->src_ip;
|
||||
tcp->source = fd_data->src_port;
|
||||
|
||||
if (add) {
|
||||
pf->fd_tcp_rule++;
|
||||
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
|
||||
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
} else {
|
||||
pf->fd_tcp_rule = (pf->fd_tcp_rule > 0) ?
|
||||
(pf->fd_tcp_rule - 1) : 0;
|
||||
if (pf->fd_tcp_rule == 0) {
|
||||
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
|
||||
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
|
||||
ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
|
||||
|
||||
if (ret) {
|
||||
dev_info(&pf->pdev->dev,
|
||||
"PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
|
||||
fd_data->pctype, fd_data->fd_id, ret);
|
||||
err = true;
|
||||
/* Free the packet buffer since it wasn't added to the ring */
|
||||
kfree(raw_packet);
|
||||
return -EOPNOTSUPP;
|
||||
} else if (I40E_DEBUG_FD & pf->hw.debug_mask) {
|
||||
if (add)
|
||||
dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d loc = %d)\n",
|
||||
|
|
@ -321,10 +308,23 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
|
|||
fd_data->pctype, fd_data->fd_id);
|
||||
}
|
||||
|
||||
if (err)
|
||||
kfree(raw_packet);
|
||||
if (add) {
|
||||
pf->fd_tcp4_filter_cnt++;
|
||||
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
|
||||
pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
} else {
|
||||
pf->fd_tcp4_filter_cnt--;
|
||||
if (pf->fd_tcp4_filter_cnt == 0) {
|
||||
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
|
||||
I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
|
||||
pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
return err ? -EOPNOTSUPP : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define I40E_IP_DUMMY_PACKET_LEN 34
|
||||
|
|
@ -343,7 +343,6 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
|
|||
{
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
struct iphdr *ip;
|
||||
bool err = false;
|
||||
u8 *raw_packet;
|
||||
int ret;
|
||||
int i;
|
||||
|
|
@ -359,18 +358,21 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
|
|||
memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
|
||||
ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
|
||||
|
||||
ip->saddr = fd_data->src_ip[0];
|
||||
ip->daddr = fd_data->dst_ip[0];
|
||||
ip->saddr = fd_data->src_ip;
|
||||
ip->daddr = fd_data->dst_ip;
|
||||
ip->protocol = 0;
|
||||
|
||||
fd_data->pctype = i;
|
||||
ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
|
||||
|
||||
if (ret) {
|
||||
dev_info(&pf->pdev->dev,
|
||||
"PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
|
||||
fd_data->pctype, fd_data->fd_id, ret);
|
||||
err = true;
|
||||
/* The packet buffer wasn't added to the ring so we
|
||||
* need to free it now.
|
||||
*/
|
||||
kfree(raw_packet);
|
||||
return -EOPNOTSUPP;
|
||||
} else if (I40E_DEBUG_FD & pf->hw.debug_mask) {
|
||||
if (add)
|
||||
dev_info(&pf->pdev->dev,
|
||||
|
|
@ -383,10 +385,12 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
|
|||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
kfree(raw_packet);
|
||||
if (add)
|
||||
pf->fd_ip4_filter_cnt++;
|
||||
else
|
||||
pf->fd_ip4_filter_cnt--;
|
||||
|
||||
return err ? -EOPNOTSUPP : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -484,8 +488,8 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
|
|||
pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf);
|
||||
|
||||
if ((rx_desc->wb.qword0.hi_dword.fd_id == 0) &&
|
||||
(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
|
||||
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
(pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED)) {
|
||||
pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
|
||||
set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
|
||||
}
|
||||
|
||||
|
|
@ -498,11 +502,11 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
|
|||
*/
|
||||
if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
|
||||
if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
|
||||
!(pf->auto_disable_flags &
|
||||
!(pf->hw_disabled_flags &
|
||||
I40E_FLAG_FD_SB_ENABLED)) {
|
||||
if (I40E_DEBUG_FD & pf->hw.debug_mask)
|
||||
dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
|
||||
pf->auto_disable_flags |=
|
||||
pf->hw_disabled_flags |=
|
||||
I40E_FLAG_FD_SB_ENABLED;
|
||||
}
|
||||
}
|
||||
|
|
@ -1010,7 +1014,6 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)
|
|||
**/
|
||||
void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
|
||||
{
|
||||
struct device *dev = rx_ring->dev;
|
||||
unsigned long bi_size;
|
||||
u16 i;
|
||||
|
||||
|
|
@ -1030,7 +1033,20 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
|
|||
if (!rx_bi->page)
|
||||
continue;
|
||||
|
||||
dma_unmap_page(dev, rx_bi->dma, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
/* Invalidate cache lines that may have been written to by
|
||||
* device so that we avoid corrupting memory.
|
||||
*/
|
||||
dma_sync_single_range_for_cpu(rx_ring->dev,
|
||||
rx_bi->dma,
|
||||
rx_bi->page_offset,
|
||||
I40E_RXBUFFER_2048,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
/* free resources associated with mapping */
|
||||
dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
|
||||
PAGE_SIZE,
|
||||
DMA_FROM_DEVICE,
|
||||
I40E_RX_DMA_ATTR);
|
||||
__free_pages(rx_bi->page, 0);
|
||||
|
||||
rx_bi->page = NULL;
|
||||
|
|
@ -1159,7 +1175,10 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
|
|||
}
|
||||
|
||||
/* map page for use */
|
||||
dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
dma = dma_map_page_attrs(rx_ring->dev, page, 0,
|
||||
PAGE_SIZE,
|
||||
DMA_FROM_DEVICE,
|
||||
I40E_RX_DMA_ATTR);
|
||||
|
||||
/* if mapping failed free memory back to system since
|
||||
* there isn't much point in holding memory we can't use
|
||||
|
|
@ -1219,6 +1238,12 @@ bool i40e_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
|
|||
if (!i40e_alloc_mapped_page(rx_ring, bi))
|
||||
goto no_buffers;
|
||||
|
||||
/* sync the buffer for use by the device */
|
||||
dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
|
||||
bi->page_offset,
|
||||
I40E_RXBUFFER_2048,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
/* Refresh the desc even if buffer_addrs didn't change
|
||||
* because each write-back erases this info.
|
||||
*/
|
||||
|
|
@ -1685,8 +1710,8 @@ struct sk_buff *i40e_fetch_rx_buffer(struct i40e_ring *rx_ring,
|
|||
rx_ring->rx_stats.page_reuse_count++;
|
||||
} else {
|
||||
/* we are not reusing the buffer so unmap it */
|
||||
dma_unmap_page(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
|
||||
DMA_FROM_DEVICE, I40E_RX_DMA_ATTR);
|
||||
}
|
||||
|
||||
/* clear contents of buffer_info */
|
||||
|
|
@ -2079,7 +2104,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|||
if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
return;
|
||||
|
||||
if ((pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
if ((pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
return;
|
||||
|
||||
/* if sampling is disabled do nothing */
|
||||
|
|
@ -2113,10 +2138,10 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|||
th = (struct tcphdr *)(hdr.network + hlen);
|
||||
|
||||
/* Due to lack of space, no more new filters can be programmed */
|
||||
if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
if (th->syn && (pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED))
|
||||
return;
|
||||
if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
|
||||
(!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) {
|
||||
(!(pf->hw_disabled_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) {
|
||||
/* HW ATR eviction will take care of removing filters on FIN
|
||||
* and RST packets.
|
||||
*/
|
||||
|
|
@ -2179,7 +2204,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|||
I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
|
||||
|
||||
if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
|
||||
(!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)))
|
||||
(!(pf->hw_disabled_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)))
|
||||
dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK;
|
||||
|
||||
fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ enum i40e_dyn_idx_t {
|
|||
#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256
|
||||
#define i40e_rx_desc i40e_32byte_rx_desc
|
||||
|
||||
#define I40E_RX_DMA_ATTR \
|
||||
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
/**
|
||||
* i40e_test_staterr - tests bits in Rx descriptor status and error fields
|
||||
* @rx_desc: pointer to receive descriptor (in le64 format)
|
||||
|
|
|
|||
|
|
@ -702,10 +702,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
|
|||
dev_info(&pf->pdev->dev,
|
||||
"Could not allocate VF broadcast filter\n");
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id),
|
||||
(u32)hena);
|
||||
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id),
|
||||
(u32)(hena >> 32));
|
||||
wr32(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena);
|
||||
wr32(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), (u32)(hena >> 32));
|
||||
}
|
||||
|
||||
/* program mac filter */
|
||||
|
|
@ -1359,7 +1357,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
|
|||
if (!vsi->info.pvid)
|
||||
vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
|
||||
|
||||
if (i40e_vf_client_capable(pf, vf->vf_id, I40E_CLIENT_IWARP) &&
|
||||
if (i40e_vf_client_capable(pf, vf->vf_id) &&
|
||||
(vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_IWARP)) {
|
||||
vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_IWARP;
|
||||
set_bit(I40E_VF_STAT_IWARPENA, &vf->vf_states);
|
||||
|
|
@ -1853,7 +1851,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
|
|||
}
|
||||
|
||||
/* If the VF is not trusted restrict the number of MAC/VLAN it can program */
|
||||
#define I40E_VC_MAX_MAC_ADDR_PER_VF 8
|
||||
#define I40E_VC_MAX_MAC_ADDR_PER_VF 12
|
||||
#define I40E_VC_MAX_VLAN_PER_VF 8
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@
|
|||
obj-$(CONFIG_I40EVF) += i40evf.o
|
||||
|
||||
i40evf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \
|
||||
i40e_txrx.o i40e_common.o i40e_adminq.o
|
||||
i40e_txrx.o i40e_common.o i40e_adminq.o i40evf_client.o
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ enum i40e_admin_queue_opc {
|
|||
i40e_aqc_opc_list_func_capabilities = 0x000A,
|
||||
i40e_aqc_opc_list_dev_capabilities = 0x000B,
|
||||
|
||||
/* Proxy commands */
|
||||
i40e_aqc_opc_set_proxy_config = 0x0104,
|
||||
i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
|
||||
|
||||
/* LAA */
|
||||
i40e_aqc_opc_mac_address_read = 0x0107,
|
||||
i40e_aqc_opc_mac_address_write = 0x0108,
|
||||
|
|
@ -139,6 +143,10 @@ enum i40e_admin_queue_opc {
|
|||
/* PXE */
|
||||
i40e_aqc_opc_clear_pxe_mode = 0x0110,
|
||||
|
||||
/* WoL commands */
|
||||
i40e_aqc_opc_set_wol_filter = 0x0120,
|
||||
i40e_aqc_opc_get_wake_reason = 0x0121,
|
||||
|
||||
/* internal switch commands */
|
||||
i40e_aqc_opc_get_switch_config = 0x0200,
|
||||
i40e_aqc_opc_add_statistics = 0x0201,
|
||||
|
|
@ -177,6 +185,7 @@ enum i40e_admin_queue_opc {
|
|||
i40e_aqc_opc_remove_control_packet_filter = 0x025B,
|
||||
i40e_aqc_opc_add_cloud_filters = 0x025C,
|
||||
i40e_aqc_opc_remove_cloud_filters = 0x025D,
|
||||
i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
|
||||
|
||||
i40e_aqc_opc_add_mirror_rule = 0x0260,
|
||||
i40e_aqc_opc_delete_mirror_rule = 0x0261,
|
||||
|
|
@ -558,6 +567,56 @@ struct i40e_aqc_clear_pxe {
|
|||
|
||||
I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe);
|
||||
|
||||
/* Set WoL Filter (0x0120) */
|
||||
|
||||
struct i40e_aqc_set_wol_filter {
|
||||
__le16 filter_index;
|
||||
#define I40E_AQC_MAX_NUM_WOL_FILTERS 8
|
||||
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT 15
|
||||
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_MASK (0x1 << \
|
||||
I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT)
|
||||
|
||||
#define I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT 0
|
||||
#define I40E_AQC_SET_WOL_FILTER_INDEX_MASK (0x7 << \
|
||||
I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT)
|
||||
__le16 cmd_flags;
|
||||
#define I40E_AQC_SET_WOL_FILTER 0x8000
|
||||
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000
|
||||
#define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0
|
||||
#define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1
|
||||
__le16 valid_flags;
|
||||
#define I40E_AQC_SET_WOL_FILTER_ACTION_VALID 0x8000
|
||||
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_ACTION_VALID 0x4000
|
||||
u8 reserved[2];
|
||||
__le32 address_high;
|
||||
__le32 address_low;
|
||||
};
|
||||
|
||||
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_wol_filter);
|
||||
|
||||
struct i40e_aqc_set_wol_filter_data {
|
||||
u8 filter[128];
|
||||
u8 mask[16];
|
||||
};
|
||||
|
||||
I40E_CHECK_STRUCT_LEN(0x90, i40e_aqc_set_wol_filter_data);
|
||||
|
||||
/* Get Wake Reason (0x0121) */
|
||||
|
||||
struct i40e_aqc_get_wake_reason_completion {
|
||||
u8 reserved_1[2];
|
||||
__le16 wake_reason;
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT 0
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_MASK (0xFF << \
|
||||
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT)
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT 8
|
||||
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_MASK (0xFF << \
|
||||
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT)
|
||||
u8 reserved_2[12];
|
||||
};
|
||||
|
||||
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_wake_reason_completion);
|
||||
|
||||
/* Switch configuration commands (0x02xx) */
|
||||
|
||||
/* Used by many indirect commands that only pass an seid and a buffer in the
|
||||
|
|
@ -640,6 +699,8 @@ struct i40e_aqc_set_port_parameters {
|
|||
#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
|
||||
#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
|
||||
__le16 bad_frame_vsi;
|
||||
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_SHIFT 0x0
|
||||
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_MASK 0x3FF
|
||||
__le16 default_seid; /* reserved for command */
|
||||
u8 reserved[10];
|
||||
};
|
||||
|
|
@ -691,6 +752,7 @@ I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
|
|||
/* Set Switch Configuration (direct 0x0205) */
|
||||
struct i40e_aqc_set_switch_config {
|
||||
__le16 flags;
|
||||
/* flags used for both fields below */
|
||||
#define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001
|
||||
#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002
|
||||
__le16 valid_flags;
|
||||
|
|
@ -1839,11 +1901,12 @@ struct i40e_aqc_get_link_status {
|
|||
#define I40E_AQ_CONFIG_FEC_RS_ENA 0x02
|
||||
#define I40E_AQ_CONFIG_CRC_ENA 0x04
|
||||
#define I40E_AQ_CONFIG_PACING_MASK 0x78
|
||||
u8 external_power_ability;
|
||||
u8 power_desc;
|
||||
#define I40E_AQ_LINK_POWER_CLASS_1 0x00
|
||||
#define I40E_AQ_LINK_POWER_CLASS_2 0x01
|
||||
#define I40E_AQ_LINK_POWER_CLASS_3 0x02
|
||||
#define I40E_AQ_LINK_POWER_CLASS_4 0x03
|
||||
#define I40E_AQ_PWR_CLASS_MASK 0x03
|
||||
u8 reserved[4];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -493,7 +493,6 @@ int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring)
|
|||
**/
|
||||
void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
|
||||
{
|
||||
struct device *dev = rx_ring->dev;
|
||||
unsigned long bi_size;
|
||||
u16 i;
|
||||
|
||||
|
|
@ -513,7 +512,20 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
|
|||
if (!rx_bi->page)
|
||||
continue;
|
||||
|
||||
dma_unmap_page(dev, rx_bi->dma, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
/* Invalidate cache lines that may have been written to by
|
||||
* device so that we avoid corrupting memory.
|
||||
*/
|
||||
dma_sync_single_range_for_cpu(rx_ring->dev,
|
||||
rx_bi->dma,
|
||||
rx_bi->page_offset,
|
||||
I40E_RXBUFFER_2048,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
/* free resources associated with mapping */
|
||||
dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
|
||||
PAGE_SIZE,
|
||||
DMA_FROM_DEVICE,
|
||||
I40E_RX_DMA_ATTR);
|
||||
__free_pages(rx_bi->page, 0);
|
||||
|
||||
rx_bi->page = NULL;
|
||||
|
|
@ -642,7 +654,10 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
|
|||
}
|
||||
|
||||
/* map page for use */
|
||||
dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
dma = dma_map_page_attrs(rx_ring->dev, page, 0,
|
||||
PAGE_SIZE,
|
||||
DMA_FROM_DEVICE,
|
||||
I40E_RX_DMA_ATTR);
|
||||
|
||||
/* if mapping failed free memory back to system since
|
||||
* there isn't much point in holding memory we can't use
|
||||
|
|
@ -702,6 +717,12 @@ bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
|
|||
if (!i40e_alloc_mapped_page(rx_ring, bi))
|
||||
goto no_buffers;
|
||||
|
||||
/* sync the buffer for use by the device */
|
||||
dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
|
||||
bi->page_offset,
|
||||
I40E_RXBUFFER_2048,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
/* Refresh the desc even if buffer_addrs didn't change
|
||||
* because each write-back erases this info.
|
||||
*/
|
||||
|
|
@ -1158,8 +1179,8 @@ struct sk_buff *i40evf_fetch_rx_buffer(struct i40e_ring *rx_ring,
|
|||
rx_ring->rx_stats.page_reuse_count++;
|
||||
} else {
|
||||
/* we are not reusing the buffer so unmap it */
|
||||
dma_unmap_page(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
|
||||
DMA_FROM_DEVICE, I40E_RX_DMA_ATTR);
|
||||
}
|
||||
|
||||
/* clear contents of buffer_info */
|
||||
|
|
|
|||
|
|
@ -120,6 +120,9 @@ enum i40e_dyn_idx_t {
|
|||
#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256
|
||||
#define i40e_rx_desc i40e_32byte_rx_desc
|
||||
|
||||
#define I40E_RX_DMA_ATTR \
|
||||
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
/**
|
||||
* i40e_test_staterr - tests bits in Rx descriptor status and error fields
|
||||
* @rx_desc: pointer to receive descriptor (in le64 format)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ enum i40e_virtchnl_ops {
|
|||
I40E_VIRTCHNL_OP_GET_STATS = 15,
|
||||
I40E_VIRTCHNL_OP_FCOE = 16,
|
||||
I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */
|
||||
I40E_VIRTCHNL_OP_IWARP = 20,
|
||||
I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21,
|
||||
I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22,
|
||||
I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23,
|
||||
I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24,
|
||||
I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25,
|
||||
|
|
@ -393,6 +395,37 @@ struct i40e_virtchnl_pf_event {
|
|||
int severity;
|
||||
};
|
||||
|
||||
/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP
|
||||
* VF uses this message to request PF to map IWARP vectors to IWARP queues.
|
||||
* The request for this originates from the VF IWARP driver through
|
||||
* a client interface between VF LAN and VF IWARP driver.
|
||||
* A vector could have an AEQ and CEQ attached to it although
|
||||
* there is a single AEQ per VF IWARP instance in which case
|
||||
* most vectors will have an INVALID_IDX for aeq and valid idx for ceq.
|
||||
* There will never be a case where there will be multiple CEQs attached
|
||||
* to a single vector.
|
||||
* PF configures interrupt mapping and returns status.
|
||||
*/
|
||||
|
||||
/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
|
||||
* In order for us to keep the interface simple, SW will define a
|
||||
* unique type value for AEQ.
|
||||
*/
|
||||
#define I40E_QUEUE_TYPE_PE_AEQ 0x80
|
||||
#define I40E_QUEUE_INVALID_IDX 0xFFFF
|
||||
|
||||
struct i40e_virtchnl_iwarp_qv_info {
|
||||
u32 v_idx; /* msix_vector */
|
||||
u16 ceq_idx;
|
||||
u16 aeq_idx;
|
||||
u8 itr_idx;
|
||||
};
|
||||
|
||||
struct i40e_virtchnl_iwarp_qvlist_info {
|
||||
u32 num_vectors;
|
||||
struct i40e_virtchnl_iwarp_qv_info qv_info[1];
|
||||
};
|
||||
|
||||
/* VF reset states - these are written into the RSTAT register:
|
||||
* I40E_VFGEN_RSTAT1 on the PF
|
||||
* I40E_VFGEN_RSTAT on the VF
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ struct i40e_vsi {
|
|||
int base_vector;
|
||||
u16 work_limit;
|
||||
u16 qs_handle;
|
||||
void *priv; /* client driver data reference. */
|
||||
};
|
||||
|
||||
/* How many Rx Buffers do we bundle into one write to the hardware ? */
|
||||
|
|
@ -169,6 +170,7 @@ enum i40evf_state_t {
|
|||
|
||||
enum i40evf_critical_section_t {
|
||||
__I40EVF_IN_CRITICAL_TASK, /* cannot be interrupted */
|
||||
__I40EVF_IN_CLIENT_TASK,
|
||||
};
|
||||
/* make common code happy */
|
||||
#define __I40E_DOWN __I40EVF_DOWN
|
||||
|
|
@ -178,6 +180,7 @@ struct i40evf_adapter {
|
|||
struct timer_list watchdog_timer;
|
||||
struct work_struct reset_task;
|
||||
struct work_struct adminq_task;
|
||||
struct delayed_work client_task;
|
||||
struct delayed_work init_task;
|
||||
struct i40e_q_vector *q_vectors;
|
||||
struct list_head vlan_filter_list;
|
||||
|
|
@ -195,7 +198,10 @@ struct i40evf_adapter {
|
|||
u64 hw_csum_rx_error;
|
||||
u32 rx_desc_count;
|
||||
int num_msix_vectors;
|
||||
int num_iwarp_msix;
|
||||
int iwarp_base_vector;
|
||||
u32 client_pending;
|
||||
struct i40e_client_instance *cinst;
|
||||
struct msix_entry *msix_entries;
|
||||
|
||||
u32 flags;
|
||||
|
|
@ -211,8 +217,11 @@ struct i40evf_adapter {
|
|||
#define I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE BIT(12)
|
||||
#define I40EVF_FLAG_ADDR_SET_BY_PF BIT(13)
|
||||
#define I40EVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(14)
|
||||
#define I40EVF_FLAG_PROMISC_ON BIT(15)
|
||||
#define I40EVF_FLAG_ALLMULTI_ON BIT(16)
|
||||
#define I40EVF_FLAG_CLIENT_NEEDS_OPEN BIT(15)
|
||||
#define I40EVF_FLAG_CLIENT_NEEDS_CLOSE BIT(16)
|
||||
#define I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS BIT(17)
|
||||
#define I40EVF_FLAG_PROMISC_ON BIT(18)
|
||||
#define I40EVF_FLAG_ALLMULTI_ON BIT(19)
|
||||
/* duplicates for common code */
|
||||
#define I40E_FLAG_FDIR_ATR_ENABLED 0
|
||||
#define I40E_FLAG_DCB_ENABLED 0
|
||||
|
|
@ -258,10 +267,11 @@ struct i40evf_adapter {
|
|||
bool link_up;
|
||||
enum i40e_aq_link_speed link_speed;
|
||||
enum i40e_virtchnl_ops current_op;
|
||||
#define CLIENT_ENABLED(_a) ((_a)->vf_res ? \
|
||||
#define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \
|
||||
(_a)->vf_res->vf_offload_flags & \
|
||||
I40E_VIRTCHNL_VF_OFFLOAD_IWARP : \
|
||||
0)
|
||||
#define CLIENT_ENABLED(_a) ((_a)->cinst)
|
||||
/* RSS by the PF should be preferred over RSS via other methods. */
|
||||
#define RSS_PF(_a) ((_a)->vf_res->vf_offload_flags & \
|
||||
I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF)
|
||||
|
|
@ -292,6 +302,12 @@ struct i40evf_adapter {
|
|||
|
||||
/* Ethtool Private Flags */
|
||||
|
||||
/* lan device */
|
||||
struct i40e_device {
|
||||
struct list_head list;
|
||||
struct i40evf_adapter *vf;
|
||||
};
|
||||
|
||||
/* needed by i40evf_ethtool.c */
|
||||
extern char i40evf_driver_name[];
|
||||
extern const char i40evf_driver_version[];
|
||||
|
|
@ -337,4 +353,11 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
|
|||
enum i40e_virtchnl_ops v_opcode,
|
||||
i40e_status v_retval, u8 *msg, u16 msglen);
|
||||
int i40evf_config_rss(struct i40evf_adapter *adapter);
|
||||
int i40evf_lan_add_device(struct i40evf_adapter *adapter);
|
||||
int i40evf_lan_del_device(struct i40evf_adapter *adapter);
|
||||
void i40evf_client_subtask(struct i40evf_adapter *adapter);
|
||||
void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len);
|
||||
void i40evf_notify_client_l2_params(struct i40e_vsi *vsi);
|
||||
void i40evf_notify_client_open(struct i40e_vsi *vsi);
|
||||
void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset);
|
||||
#endif /* _I40EVF_H_ */
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user