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:
Bob Peterson 2017-03-24 09:22:07 -04:00
commit c369898759
437 changed files with 28932 additions and 10124 deletions

View File

@ -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

View File

@ -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"

View File

@ -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>;
};
};

View File

@ -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>;
};

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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)

View File

@ -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__ */

View File

@ -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"

View File

@ -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.

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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 */

View 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);
}

View File

@ -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,

View File

@ -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,

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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/

View File

@ -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;

View File

@ -1 +1,2 @@
source "drivers/net/ethernet/apm/xgene/Kconfig"
source "drivers/net/ethernet/apm/xgene-v2/Kconfig"

View File

@ -3,3 +3,4 @@
#
obj-$(CONFIG_NET_XGENE) += xgene/
obj-$(CONFIG_NET_XGENE_V2) += xgene-v2/

View 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.

View 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

View 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;
}

View 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__ */

View 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);
}

View 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__ */

View 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");

View 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__ */

View 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);
}

View 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__ */

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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");

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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,

View File

@ -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) \

View File

@ -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:

View File

@ -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(

View File

@ -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;

View File

@ -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)

View File

@ -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)
{

View File

@ -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 =

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -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",

View File

@ -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;
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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, &params);
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, &params);
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);

View File

@ -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 {

View File

@ -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;

View File

@ -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 */

View File

@ -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, &regs->fmbm_rfne);
/* Parser Next Engine NIA */
iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME, &regs->fmbm_rfpne);
/* Enqueue NIA */
iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->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, &regs->fmpr_pcac);
while (cnt-- > 0 &&
(ioread32be(&regs->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, &regs->fmpr_pcac);
while (cnt-- > 0 &&
!(ioread32be(&regs->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, &regs->pmda[i].ssa);
iowrite32be(0xffffffff, &regs->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);

View File

@ -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"

View File

@ -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"
/*************************************************/

View File

@ -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);

View File

@ -1052,4 +1052,5 @@ struct ibmvnic_adapter {
struct work_struct ibmvnic_xport;
struct tasklet_struct tasklet;
bool failover;
bool is_closed;
};

View File

@ -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,

View File

@ -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

View File

@ -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];
};

View File

@ -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(&params, 0, sizeof(params));
i40e_client_get_params(vsi, &params);
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,
&params);
}
}
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, &params, sizeof(struct i40e_params));
cdev->client->ops->l2_param_change(&cdev->lan_info, cdev->client,
&params);
}
/**
* 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);

View File

@ -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 */
};

View File

@ -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(&copy_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(&copy_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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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
/**

View File

@ -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

View File

@ -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];
};

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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