Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Highlights: 1) Support SPI based w5100 devices, from Akinobu Mita. 2) Partial Segmentation Offload, from Alexander Duyck. 3) Add GMAC4 support to stmmac driver, from Alexandre TORGUE. 4) Allow cls_flower stats offload, from Amir Vadai. 5) Implement bpf blinding, from Daniel Borkmann. 6) Optimize _ASYNC_ bit twiddling on sockets, unless the socket is actually using FASYNC these atomics are superfluous. From Eric Dumazet. 7) Run TCP more preemptibly, also from Eric Dumazet. 8) Support LED blinking, EEPROM dumps, and rxvlan offloading in mlx5e driver, from Gal Pressman. 9) Allow creating ppp devices via rtnetlink, from Guillaume Nault. 10) Improve BPF usage documentation, from Jesper Dangaard Brouer. 11) Support tunneling offloads in qed, from Manish Chopra. 12) aRFS offloading in mlx5e, from Maor Gottlieb. 13) Add RFS and RPS support to SCTP protocol, from Marcelo Ricardo Leitner. 14) Add MSG_EOR support to TCP, this allows controlling packet coalescing on application record boundaries for more accurate socket timestamp sampling. From Martin KaFai Lau. 15) Fix alignment of 64-bit netlink attributes across the board, from Nicolas Dichtel. 16) Per-vlan stats in bridging, from Nikolay Aleksandrov. 17) Several conversions of drivers to ethtool ksettings, from Philippe Reynes. 18) Checksum neutral ILA in ipv6, from Tom Herbert. 19) Factorize all of the various marvell dsa drivers into one, from Vivien Didelot 20) Add VF support to qed driver, from Yuval Mintz" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1649 commits) Revert "phy dp83867: Fix compilation with CONFIG_OF_MDIO=m" Revert "phy dp83867: Make rgmii parameters optional" r8169: default to 64-bit DMA on recent PCIe chips phy dp83867: Make rgmii parameters optional phy dp83867: Fix compilation with CONFIG_OF_MDIO=m bpf: arm64: remove callee-save registers use for tmp registers asix: Fix offset calculation in asix_rx_fixup() causing slow transmissions switchdev: pass pointer to fib_info instead of copy net_sched: close another race condition in tcf_mirred_release() tipc: fix nametable publication field in nl compat drivers: net: Don't print unpopulated net_device name qed: add support for dcbx. ravb: Add missing free_irq() calls to ravb_close() qed: Remove a stray tab net: ethernet: fec-mpc52xx: use phy_ethtool_{get|set}_link_ksettings net: ethernet: fec-mpc52xx: use phydev from struct net_device bpf, doc: fix typo on bpf_asm descriptions stmmac: hardware TX COE doesn't work when force_thresh_dma_mode is set net: ethernet: fs-enet: use phy_ethtool_{get|set}_link_ksettings net: ethernet: fs-enet: use phydev from struct net_device ...
This commit is contained in:
commit
a7fd20d1c4
|
@ -75,7 +75,6 @@
|
|||
<chapter>
|
||||
<title>Device registration</title>
|
||||
!Pinclude/net/cfg80211.h Device registration
|
||||
!Finclude/net/cfg80211.h ieee80211_band
|
||||
!Finclude/net/cfg80211.h ieee80211_channel_flags
|
||||
!Finclude/net/cfg80211.h ieee80211_channel
|
||||
!Finclude/net/cfg80211.h ieee80211_rate_flags
|
||||
|
@ -136,6 +135,7 @@
|
|||
!Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt
|
||||
!Finclude/net/cfg80211.h cfg80211_ibss_joined
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_result
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_roamed
|
||||
!Finclude/net/cfg80211.h cfg80211_disconnected
|
||||
!Finclude/net/cfg80211.h cfg80211_ready_on_channel
|
||||
|
|
|
@ -505,6 +505,8 @@ int main(int argc, char *argv[])
|
|||
if (!loop)
|
||||
goto done;
|
||||
break;
|
||||
case TASKSTATS_TYPE_NULL:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown nested"
|
||||
" nla_type %d\n",
|
||||
|
@ -512,7 +514,8 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
len2 += NLA_ALIGN(na->nla_len);
|
||||
na = (struct nlattr *) ((char *) na + len2);
|
||||
na = (struct nlattr *)((char *)na +
|
||||
NLA_ALIGN(na->nla_len));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
btmrvl
|
||||
------
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : must be "btmrvl,cfgdata"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- btmrvl,cal-data : Calibration data downloaded to the device during
|
||||
initialization. This is an array of 28 values(u8).
|
||||
|
||||
- btmrvl,gpio-gap : gpio and gap (in msecs) combination to be
|
||||
configured.
|
||||
|
||||
Example:
|
||||
|
||||
GPIO pin 13 is configured as a wakeup source and GAP is set to 100 msecs
|
||||
in below example.
|
||||
|
||||
btmrvl {
|
||||
compatible = "btmrvl,cfgdata";
|
||||
|
||||
btmrvl,cal-data = /bits/ 8 <
|
||||
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
|
||||
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
|
||||
0x00 0x00 0xf0 0x00>;
|
||||
btmrvl,gpio-gap = <0x0d64>;
|
||||
};
|
|
@ -18,6 +18,8 @@ Required properties for all the ethernet interfaces:
|
|||
- First is the Rx interrupt. This irq is mandatory.
|
||||
- Second is the Tx completion interrupt.
|
||||
This is supported only on SGMII based 1GbE and 10GbE interfaces.
|
||||
- channel: Ethernet to CPU, start channel (prefetch buffer) number
|
||||
- Must map to the first irq and irqs must be sequential
|
||||
- port-id: Port number (0 or 1)
|
||||
- clocks: Reference to the clock entry.
|
||||
- local-mac-address: MAC address assigned to this device
|
||||
|
|
|
@ -31,8 +31,6 @@ A switch child node has the following optional property:
|
|||
switch. Must be set if the switch can not detect
|
||||
the presence and/or size of a connected EEPROM,
|
||||
otherwise optional.
|
||||
- reset-gpios : phandle and specifier to a gpio line connected to
|
||||
reset pin of the switch chip.
|
||||
|
||||
A switch may have multiple "port" children nodes
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
Marvell DSA Switch Device Tree Bindings
|
||||
---------------------------------------
|
||||
|
||||
WARNING: This binding is currently unstable. Do not program it into a
|
||||
FLASH never to be changed again. Once this binding is stable, this
|
||||
warning will be removed.
|
||||
|
||||
If you need a stable binding, use the old dsa.txt binding.
|
||||
|
||||
Marvell Switches are MDIO devices. The following properties should be
|
||||
placed as a child node of an mdio device.
|
||||
|
||||
The properties described here are those specific to Marvell devices.
|
||||
Additional required and optional properties can be found in dsa.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be one of "marvell,mv88e6085",
|
||||
- reg : Address on the MII bus for the switch.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : Should be a gpio specifier for a reset line
|
||||
|
||||
Example:
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
switch0: switch@0 {
|
||||
compatible = "marvell,mv88e6085";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
|
@ -7,19 +7,45 @@ Required properties:
|
|||
- mode: dsa fabric mode string. only support one of dsaf modes like these:
|
||||
"2port-64vf",
|
||||
"6port-16rss",
|
||||
"6port-16vf".
|
||||
"6port-16vf",
|
||||
"single-port".
|
||||
- interrupt-parent: the interrupt parent of this device.
|
||||
- interrupts: should contain the DSA Fabric and rcb interrupt.
|
||||
- reg: specifies base physical address(es) and size of the device registers.
|
||||
The first region is external interface control register base and size.
|
||||
The second region is SerDes base register and size.
|
||||
The first region is external interface control register base and size(optional,
|
||||
only used when subctrl-syscon does not exist). It is recommended using
|
||||
subctrl-syscon rather than this address.
|
||||
The second region is SerDes base register and size(optional, only used when
|
||||
serdes-syscon in port node does not exist). It is recommended using
|
||||
serdes-syscon rather than this address.
|
||||
The third region is the PPE register base and size.
|
||||
The fourth region is dsa fabric base register and size.
|
||||
The fifth region is cpld base register and size, it is not required if do not use cpld.
|
||||
- phy-handle: phy handle of physicl port, 0 if not any phy device. see ethernet.txt [1].
|
||||
The fourth region is dsa fabric base register and size. It is not required for
|
||||
single-port mode.
|
||||
- reg-names: may be ppe-base and(or) dsaf-base. It is used to find the
|
||||
corresponding reg's index.
|
||||
|
||||
- phy-handle: phy handle of physical port, 0 if not any phy device. It is optional
|
||||
attribute. If port node exists, phy-handle in each port node will be used.
|
||||
see ethernet.txt [1].
|
||||
- subctrl-syscon: is syscon handle for external interface control register.
|
||||
- reset-field-offset: is offset of reset field. Its value depends on the hardware
|
||||
user manual.
|
||||
- buf-size: rx buffer size, should be 16-1024.
|
||||
- desc-num: number of description in TX and RX queue, should be 512, 1024, 2048 or 4096.
|
||||
|
||||
- port: subnodes of dsaf. A dsaf node may contain several port nodes(Depending
|
||||
on mode of dsaf). Port node contain some attributes listed below:
|
||||
- reg: is physical port index in one dsaf.
|
||||
- phy-handle: phy handle of physical port. It is not required if there isn't
|
||||
phy device. see ethernet.txt [1].
|
||||
- serdes-syscon: is syscon handle for SerDes register.
|
||||
- cpld-syscon: is syscon handle + register offset pair for cpld register. It is
|
||||
not required if there isn't cpld device.
|
||||
- port-rst-offset: is offset of reset field for each port in dsaf. Its value
|
||||
depends on the hardware user manual.
|
||||
- port-mode-offset: is offset of port mode field for each port in dsaf. Its
|
||||
value depends on the hardware user manual.
|
||||
|
||||
[1] Documentation/devicetree/bindings/net/phy.txt
|
||||
|
||||
Example:
|
||||
|
@ -28,11 +54,11 @@ dsaf0: dsa@c7000000 {
|
|||
compatible = "hisilicon,hns-dsaf-v1";
|
||||
mode = "6port-16rss";
|
||||
interrupt-parent = <&mbigen_dsa>;
|
||||
reg = <0x0 0xC0000000 0x0 0x420000
|
||||
0x0 0xC2000000 0x0 0x300000
|
||||
0x0 0xc5000000 0x0 0x890000
|
||||
reg = <0x0 0xc5000000 0x0 0x890000
|
||||
0x0 0xc7000000 0x0 0x60000>;
|
||||
phy-handle = <0 0 0 0 &soc0_phy4 &soc0_phy5 0 0>;
|
||||
reg-names = "ppe-base", "dsaf-base";
|
||||
subctrl-syscon = <&subctrl>;
|
||||
reset-field-offset = 0;
|
||||
interrupts = <131 4>,<132 4>, <133 4>,<134 4>,
|
||||
<135 4>,<136 4>, <137 4>,<138 4>,
|
||||
<139 4>,<140 4>, <141 4>,<142 4>,
|
||||
|
@ -43,4 +69,15 @@ dsaf0: dsa@c7000000 {
|
|||
buf-size = <4096>;
|
||||
desc-num = <1024>;
|
||||
dma-coherent;
|
||||
|
||||
port@0 {
|
||||
reg = 0;
|
||||
phy-handle = <&phy0>;
|
||||
serdes-syscon = <&serdes>;
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = 1;
|
||||
serdes-syscon = <&serdes>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -36,6 +36,34 @@ Required properties:
|
|||
| | | | | |
|
||||
external port
|
||||
|
||||
This attribute is remained for compatible purpose. It is not recommended to
|
||||
use it in new code.
|
||||
|
||||
- port-idx-in-ae: is the index of port provided by AE.
|
||||
In NIC mode of DSAF, all 6 PHYs of service DSAF are taken as ethernet ports
|
||||
to the CPU. The port-idx-in-ae can be 0 to 5. Here is the diagram:
|
||||
+-----+---------------+
|
||||
| CPU |
|
||||
+-+-+-+---+-+-+-+-+-+-+
|
||||
| | | | | | | |
|
||||
debug debug service
|
||||
port port port
|
||||
(0) (0) (0-5)
|
||||
|
||||
In Switch mode of DSAF, all 6 PHYs of service DSAF are taken as physical
|
||||
ports connected to a LAN Switch while the CPU side assume itself have one
|
||||
single NIC connected to this switch. In this case, the port-idx-in-ae
|
||||
will be 0 only.
|
||||
+-----+-----+------+------+
|
||||
| CPU |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| | service| port(0)
|
||||
debug debug +------------+
|
||||
port port | switch |
|
||||
(0) (0) +-+-+-+-+-+-++
|
||||
| | | | | |
|
||||
external port
|
||||
|
||||
- local-mac-address: mac addr of the ethernet interface
|
||||
|
||||
Example:
|
||||
|
@ -43,6 +71,6 @@ Example:
|
|||
ethernet@0{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <0>;
|
||||
port-idx-in-ae = <0>;
|
||||
local-mac-address = [a2 14 e4 4b 56 76];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
Marvell 8897/8997 (sd8897/sd8997) bluetooth SDIO devices
|
||||
------
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be one of the following:
|
||||
* "marvell,sd8897-bt"
|
||||
* "marvell,sd8997-bt"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- marvell,cal-data: Calibration data downloaded to the device during
|
||||
initialization. This is an array of 28 values(u8).
|
||||
|
||||
- marvell,wakeup-pin: It represents wakeup pin number of the bluetooth chip.
|
||||
firmware will use the pin to wakeup host system.
|
||||
- marvell,wakeup-gap-ms: wakeup gap represents wakeup latency of the host
|
||||
platform. The value will be configured to firmware. This
|
||||
is needed to work chip's sleep feature as expected.
|
||||
- interrupt-parent: phandle of the parent interrupt controller
|
||||
- interrupts : interrupt pin number to the cpu. Driver will request an irq based
|
||||
on this interrupt number. During system suspend, the irq will be
|
||||
enabled so that the bluetooth chip can wakeup host platform under
|
||||
certain condition. During system resume, the irq will be disabled
|
||||
to make sure unnecessary interrupt is not received.
|
||||
|
||||
Example:
|
||||
|
||||
IRQ pin 119 is used as system wakeup source interrupt.
|
||||
wakeup pin 13 and gap 100ms are configured so that firmware can wakeup host
|
||||
using this device side pin and wakeup latency.
|
||||
calibration data is also available in below example.
|
||||
|
||||
&mmc3 {
|
||||
status = "okay";
|
||||
vmmc-supply = <&wlan_en_reg>;
|
||||
bus-width = <4>;
|
||||
cap-power-off-card;
|
||||
keep-power-in-suspend;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
btmrvl: bluetooth@2 {
|
||||
compatible = "marvell,sd8897-bt";
|
||||
reg = <2>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <119 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
marvell,cal-data = /bits/ 8 <
|
||||
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
|
||||
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
|
||||
0x00 0x00 0xf0 0x00>;
|
||||
marvell,wakeup-pin = <0x0d>;
|
||||
marvell,wakeup-gap-ms = <0x64>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
* Microchip ENC28J60
|
||||
|
||||
This is a standalone 10 MBit ethernet controller with SPI interface.
|
||||
|
||||
For each device connected to a SPI bus, define a child node within
|
||||
the SPI master node.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "microchip,enc28j60"
|
||||
- reg: Specify the SPI chip select the ENC28J60 is wired to
|
||||
- interrupt-parent: Specify the phandle of the source interrupt, see interrupt
|
||||
binding documentation for details. Usually this is the GPIO bank
|
||||
the interrupt line is wired to.
|
||||
- interrupts: Specify the interrupt index within the interrupt controller (referred
|
||||
to above in interrupt-parent) and interrupt type. The ENC28J60 natively
|
||||
generates falling edge interrupts, however, additional board logic
|
||||
might invert the signal.
|
||||
- pinctrl-names: List of assigned state names, see pinctrl binding documentation.
|
||||
- pinctrl-0: List of phandles to configure the GPIO pin used as interrupt line,
|
||||
see also generic and your platform specific pinctrl binding
|
||||
documentation.
|
||||
|
||||
Optional properties:
|
||||
- spi-max-frequency: Maximum frequency of the SPI bus when accessing the ENC28J60.
|
||||
According to the ENC28J80 datasheet, the chip allows a maximum of 20 MHz, however,
|
||||
board designs may need to limit this value.
|
||||
- local-mac-address: See ethernet.txt in the same directory.
|
||||
|
||||
|
||||
Example (for NXP i.MX28 with pin control stuff for GPIO irq):
|
||||
|
||||
ssp2: ssp@80014000 {
|
||||
compatible = "fsl,imx28-spi";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi2_pins_b &spi2_sck_cfg>;
|
||||
status = "okay";
|
||||
|
||||
enc28j60: ethernet@0 {
|
||||
compatible = "microchip,enc28j60";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&enc28j60_pins>;
|
||||
reg = <0>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
|
||||
spi-max-frequency = <12000000>;
|
||||
};
|
||||
};
|
||||
|
||||
pinctrl@80018000 {
|
||||
enc28j60_pins: enc28j60_pins@0 {
|
||||
reg = <0>;
|
||||
fsl,pinmux-ids = <
|
||||
MX28_PAD_AUART0_RTS__GPIO_3_3 /* Interrupt */
|
||||
>;
|
||||
fsl,drive-strength = <MXS_DRIVE_4mA>;
|
||||
fsl,voltage = <MXS_VOLTAGE_HIGH>;
|
||||
fsl,pull-up = <MXS_PULL_DISABLE>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
* NXP Semiconductors PN532 NFC Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nxp,pn532-i2c" or "nxp,pn533-i2c".
|
||||
- clock-frequency: I²C work frequency.
|
||||
- reg: address on the bus
|
||||
- interrupt-parent: phandle for the interrupt gpio controller
|
||||
- interrupts: GPIO interrupt to which the chip is connected
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
- pinctrl-names: Contains only one value - "default".
|
||||
- pintctrl-0: Specifies the pin control groups used for this controller.
|
||||
|
||||
Example (for ARM-based BeagleBone with PN532 on I2C2):
|
||||
|
||||
&i2c2 {
|
||||
|
||||
status = "okay";
|
||||
|
||||
pn532: pn532@24 {
|
||||
|
||||
compatible = "nxp,pn532-i2c";
|
||||
|
||||
reg = <0x24>;
|
||||
clock-frequency = <400000>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
};
|
||||
};
|
|
@ -35,6 +35,8 @@ Optional Properties:
|
|||
- broken-turn-around: If set, indicates the PHY device does not correctly
|
||||
release the turn around line low at the end of a MDIO transaction.
|
||||
|
||||
- reset-gpios: Reference to a GPIO used to reset the phy.
|
||||
|
||||
Example:
|
||||
|
||||
ethernet-phy@0 {
|
||||
|
@ -42,4 +44,5 @@ ethernet-phy@0 {
|
|||
interrupt-parent = <40000>;
|
||||
interrupts = <35 1>;
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
|
|
@ -59,6 +59,8 @@ Optional properties:
|
|||
- snps,fb: fixed-burst
|
||||
- snps,mb: mixed-burst
|
||||
- snps,rb: rebuild INCRx Burst
|
||||
- snps,tso: this enables the TSO feature otherwise it will be managed by
|
||||
MAC HW capability register.
|
||||
- mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
|
||||
|
||||
Examples:
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
Marvell 8897/8997 (sd8897/sd8997) SDIO devices
|
||||
------
|
||||
|
||||
This node provides properties for controlling the marvell sdio wireless device.
|
||||
The node is expected to be specified as a child node to the SDIO controller that
|
||||
connects the device to the system.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be one of the following:
|
||||
* "marvell,sd8897"
|
||||
* "marvell,sd8997"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- marvell,caldata* : A series of properties with marvell,caldata prefix,
|
||||
represent calibration data downloaded to the device during
|
||||
initialization. This is an array of unsigned 8-bit values.
|
||||
the properties should follow below property name and
|
||||
corresponding array length:
|
||||
"marvell,caldata-txpwrlimit-2g" (length = 566).
|
||||
"marvell,caldata-txpwrlimit-5g-sub0" (length = 502).
|
||||
"marvell,caldata-txpwrlimit-5g-sub1" (length = 688).
|
||||
"marvell,caldata-txpwrlimit-5g-sub2" (length = 750).
|
||||
"marvell,caldata-txpwrlimit-5g-sub3" (length = 502).
|
||||
- marvell,wakeup-pin : a wakeup pin number of wifi chip which will be configured
|
||||
to firmware. Firmware will wakeup the host using this pin
|
||||
during suspend/resume.
|
||||
- interrupt-parent: phandle of the parent interrupt controller
|
||||
- interrupts : interrupt pin number to the cpu. driver will request an irq based on
|
||||
this interrupt number. during system suspend, the irq will be enabled
|
||||
so that the wifi chip can wakeup host platform under certain condition.
|
||||
during system resume, the irq will be disabled to make sure
|
||||
unnecessary interrupt is not received.
|
||||
|
||||
Example:
|
||||
|
||||
Tx power limit calibration data is configured in below example.
|
||||
The calibration data is an array of unsigned values, the length
|
||||
can vary between hw versions.
|
||||
IRQ pin 38 is used as system wakeup source interrupt. wakeup pin 3 is configured
|
||||
so that firmware can wakeup host using this device side pin.
|
||||
|
||||
&mmc3 {
|
||||
status = "okay";
|
||||
vmmc-supply = <&wlan_en_reg>;
|
||||
bus-width = <4>;
|
||||
cap-power-off-card;
|
||||
keep-power-in-suspend;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
mwifiex: wifi@1 {
|
||||
compatible = "marvell,sd8897";
|
||||
reg = <1>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
marvell,caldata_00_txpwrlimit_2g_cfg_set = /bits/ 8 <
|
||||
0x01 0x00 0x06 0x00 0x08 0x02 0x89 0x01>;
|
||||
marvell,wakeup-pin = <3>;
|
||||
};
|
||||
};
|
|
@ -5,12 +5,18 @@ Required properties:
|
|||
* "qcom,ath10k"
|
||||
* "qcom,ipq4019-wifi"
|
||||
|
||||
PCI based devices uses compatible string "qcom,ath10k" and takes only
|
||||
calibration data via "qcom,ath10k-calibration-data". Rest of the properties
|
||||
are not applicable for PCI based devices.
|
||||
PCI based devices uses compatible string "qcom,ath10k" and takes calibration
|
||||
data along with board specific data via "qcom,ath10k-calibration-data".
|
||||
Rest of the properties are not applicable for PCI based devices.
|
||||
|
||||
AHB based devices (i.e. ipq4019) uses compatible string "qcom,ipq4019-wifi"
|
||||
and also uses most of the properties defined in this doc.
|
||||
and also uses most of the properties defined in this doc (except
|
||||
"qcom,ath10k-calibration-data"). It uses "qcom,ath10k-pre-calibration-data"
|
||||
to carry pre calibration data.
|
||||
|
||||
In general, entry "qcom,ath10k-pre-calibration-data" and
|
||||
"qcom,ath10k-calibration-data" conflict with each other and only one
|
||||
can be provided per device.
|
||||
|
||||
Optional properties:
|
||||
- reg: Address and length of the register set for the device.
|
||||
|
@ -35,8 +41,11 @@ Optional properties:
|
|||
- qcom,msi_addr: MSI interrupt address.
|
||||
- qcom,msi_base: Base value to add before writing MSI data into
|
||||
MSI address register.
|
||||
- qcom,ath10k-calibration-data : calibration data as an array, the
|
||||
length can vary between hw versions
|
||||
- qcom,ath10k-calibration-data : calibration data + board specific data
|
||||
as an array, the length can vary between
|
||||
hw versions.
|
||||
- qcom,ath10k-pre-calibration-data : pre calibration data as an array,
|
||||
the length can vary between hw versions.
|
||||
|
||||
Example (to supply the calibration data alone):
|
||||
|
||||
|
@ -105,5 +114,5 @@ wifi0: wifi@a000000 {
|
|||
"legacy";
|
||||
qcom,msi_addr = <0x0b006040>;
|
||||
qcom,msi_base = <0x40>;
|
||||
qcom,ath10k-calibration-data = [ 01 02 03 ... ];
|
||||
qcom,ath10k-pre-calibration-data = [ 01 02 03 ... ];
|
||||
};
|
||||
|
|
|
@ -1880,8 +1880,8 @@ or more peers on the local network.
|
|||
|
||||
The ARP monitor relies on the device driver itself to verify
|
||||
that traffic is flowing. In particular, the driver must keep up to
|
||||
date the last receive time, dev->last_rx, and transmit start time,
|
||||
dev->trans_start. If these are not updated by the driver, then the
|
||||
date the last receive time, dev->last_rx. Drivers that use NETIF_F_LLTX
|
||||
flag must also update netdev_queue->trans_start. If they do not, then the
|
||||
ARP monitor will immediately fail any slaves using that driver, and
|
||||
those slaves will stay down. If networking monitoring (tcpdump, etc)
|
||||
shows the ARP requests and replies on the network, then it may be that
|
||||
|
|
|
@ -38,7 +38,7 @@ Implementation details
|
|||
======================
|
||||
|
||||
The driver is located in drivers/net/dsa/bcm_sf2.c and is implemented as a DSA
|
||||
driver; see Documentation/networking/dsa/dsa.txt for details on the subsytem
|
||||
driver; see Documentation/networking/dsa/dsa.txt for details on the subsystem
|
||||
and what it provides.
|
||||
|
||||
The SF2 switch is configured to enable a Broadcom specific 4-bytes switch tag
|
||||
|
|
|
@ -334,7 +334,7 @@ more specifically with its VLAN filtering portion when configuring VLANs on top
|
|||
of per-port slave network devices. Since DSA primarily deals with
|
||||
MDIO-connected switches, although not exclusively, SWITCHDEV's
|
||||
prepare/abort/commit phases are often simplified into a prepare phase which
|
||||
checks whether the operation is supporte by the DSA switch driver, and a commit
|
||||
checks whether the operation is supported by the DSA switch driver, and a commit
|
||||
phase which applies the changes.
|
||||
|
||||
As of today, the only SWITCHDEV objects supported by DSA are the FDB and VLAN
|
||||
|
@ -533,7 +533,7 @@ Bridge layer
|
|||
out at the switch hardware for the switch to (re) learn MAC addresses behind
|
||||
this port.
|
||||
|
||||
- port_stp_update: bridge layer function invoked when a given switch port STP
|
||||
- port_stp_state_set: bridge layer function invoked when a given switch port STP
|
||||
state is computed by the bridge layer and should be propagated to switch
|
||||
hardware to forward/block/learn traffic. The switch driver is responsible for
|
||||
computing a STP state change based on current and asked parameters and perform
|
||||
|
@ -542,6 +542,12 @@ Bridge layer
|
|||
Bridge VLAN filtering
|
||||
---------------------
|
||||
|
||||
- port_vlan_prepare: bridge layer function invoked when the bridge prepares the
|
||||
configuration of a VLAN on the given port. If the operation is not supported
|
||||
by the hardware, this function should return -EOPNOTSUPP to inform the bridge
|
||||
code to fallback to a software implementation. No hardware setup must be done
|
||||
in this function. See port_vlan_add for this and details.
|
||||
|
||||
- port_vlan_add: bridge layer function invoked when a VLAN is configured
|
||||
(tagged or untagged) for the given switch port
|
||||
|
||||
|
@ -552,6 +558,12 @@ Bridge VLAN filtering
|
|||
function that the driver has to call for each VLAN the given port is a member
|
||||
of. A switchdev object is used to carry the VID and bridge flags.
|
||||
|
||||
- port_fdb_prepare: bridge layer function invoked when the bridge prepares the
|
||||
installation of a Forwarding Database entry. If the operation is not
|
||||
supported, this function should return -EOPNOTSUPP to inform the bridge code
|
||||
to fallback to a software implementation. No hardware setup must be done in
|
||||
this function. See port_fdb_add for this and details.
|
||||
|
||||
- port_fdb_add: bridge layer function invoked when the bridge wants to install a
|
||||
Forwarding Database entry, the switch hardware should be programmed with the
|
||||
specified address in the specified VLAN Id in the forwarding database
|
||||
|
@ -565,6 +577,10 @@ of DSA, would be the its port-based VLAN, used by the associated bridge device.
|
|||
the specified MAC address from the specified VLAN ID if it was mapped into
|
||||
this port forwarding database
|
||||
|
||||
- port_fdb_dump: bridge layer function invoked with a switchdev callback
|
||||
function that the driver has to call for each MAC address known to be behind
|
||||
the given port. A switchdev object is used to carry the VID and FDB info.
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
|
|
|
@ -216,14 +216,14 @@ opcodes as defined in linux/filter.h stand for:
|
|||
|
||||
jmp 6 Jump to label
|
||||
ja 6 Jump to label
|
||||
jeq 7, 8 Jump on k == A
|
||||
jneq 8 Jump on k != A
|
||||
jne 8 Jump on k != A
|
||||
jlt 8 Jump on k < A
|
||||
jle 8 Jump on k <= A
|
||||
jgt 7, 8 Jump on k > A
|
||||
jge 7, 8 Jump on k >= A
|
||||
jset 7, 8 Jump on k & A
|
||||
jeq 7, 8 Jump on A == k
|
||||
jneq 8 Jump on A != k
|
||||
jne 8 Jump on A != k
|
||||
jlt 8 Jump on A < k
|
||||
jle 8 Jump on A <= k
|
||||
jgt 7, 8 Jump on A > k
|
||||
jge 7, 8 Jump on A >= k
|
||||
jset 7, 8 Jump on A & k
|
||||
|
||||
add 0, 4 A + <x>
|
||||
sub 0, 4 A - <x>
|
||||
|
@ -1095,6 +1095,87 @@ all use cases.
|
|||
|
||||
See details of eBPF verifier in kernel/bpf/verifier.c
|
||||
|
||||
Direct packet access
|
||||
--------------------
|
||||
In cls_bpf and act_bpf programs the verifier allows direct access to the packet
|
||||
data via skb->data and skb->data_end pointers.
|
||||
Ex:
|
||||
1: r4 = *(u32 *)(r1 +80) /* load skb->data_end */
|
||||
2: r3 = *(u32 *)(r1 +76) /* load skb->data */
|
||||
3: r5 = r3
|
||||
4: r5 += 14
|
||||
5: if r5 > r4 goto pc+16
|
||||
R1=ctx R3=pkt(id=0,off=0,r=14) R4=pkt_end R5=pkt(id=0,off=14,r=14) R10=fp
|
||||
6: r0 = *(u16 *)(r3 +12) /* access 12 and 13 bytes of the packet */
|
||||
|
||||
this 2byte load from the packet is safe to do, since the program author
|
||||
did check 'if (skb->data + 14 > skb->data_end) goto err' at insn #5 which
|
||||
means that in the fall-through case the register R3 (which points to skb->data)
|
||||
has at least 14 directly accessible bytes. The verifier marks it
|
||||
as R3=pkt(id=0,off=0,r=14).
|
||||
id=0 means that no additional variables were added to the register.
|
||||
off=0 means that no additional constants were added.
|
||||
r=14 is the range of safe access which means that bytes [R3, R3 + 14) are ok.
|
||||
Note that R5 is marked as R5=pkt(id=0,off=14,r=14). It also points
|
||||
to the packet data, but constant 14 was added to the register, so
|
||||
it now points to 'skb->data + 14' and accessible range is [R5, R5 + 14 - 14)
|
||||
which is zero bytes.
|
||||
|
||||
More complex packet access may look like:
|
||||
R0=imm1 R1=ctx R3=pkt(id=0,off=0,r=14) R4=pkt_end R5=pkt(id=0,off=14,r=14) R10=fp
|
||||
6: r0 = *(u8 *)(r3 +7) /* load 7th byte from the packet */
|
||||
7: r4 = *(u8 *)(r3 +12)
|
||||
8: r4 *= 14
|
||||
9: r3 = *(u32 *)(r1 +76) /* load skb->data */
|
||||
10: r3 += r4
|
||||
11: r2 = r1
|
||||
12: r2 <<= 48
|
||||
13: r2 >>= 48
|
||||
14: r3 += r2
|
||||
15: r2 = r3
|
||||
16: r2 += 8
|
||||
17: r1 = *(u32 *)(r1 +80) /* load skb->data_end */
|
||||
18: if r2 > r1 goto pc+2
|
||||
R0=inv56 R1=pkt_end R2=pkt(id=2,off=8,r=8) R3=pkt(id=2,off=0,r=8) R4=inv52 R5=pkt(id=0,off=14,r=14) R10=fp
|
||||
19: r1 = *(u8 *)(r3 +4)
|
||||
The state of the register R3 is R3=pkt(id=2,off=0,r=8)
|
||||
id=2 means that two 'r3 += rX' instructions were seen, so r3 points to some
|
||||
offset within a packet and since the program author did
|
||||
'if (r3 + 8 > r1) goto err' at insn #18, the safe range is [R3, R3 + 8).
|
||||
The verifier only allows 'add' operation on packet registers. Any other
|
||||
operation will set the register state to 'unknown_value' and it won't be
|
||||
available for direct packet access.
|
||||
Operation 'r3 += rX' may overflow and become less than original skb->data,
|
||||
therefore the verifier has to prevent that. So it tracks the number of
|
||||
upper zero bits in all 'uknown_value' registers, so when it sees
|
||||
'r3 += rX' instruction and rX is more than 16-bit value, it will error as:
|
||||
"cannot add integer value with N upper zero bits to ptr_to_packet"
|
||||
Ex. after insn 'r4 = *(u8 *)(r3 +12)' (insn #7 above) the state of r4 is
|
||||
R4=inv56 which means that upper 56 bits on the register are guaranteed
|
||||
to be zero. After insn 'r4 *= 14' the state becomes R4=inv52, since
|
||||
multiplying 8-bit value by constant 14 will keep upper 52 bits as zero.
|
||||
Similarly 'r2 >>= 48' will make R2=inv48, since the shift is not sign
|
||||
extending. This logic is implemented in evaluate_reg_alu() function.
|
||||
|
||||
The end result is that bpf program author can access packet directly
|
||||
using normal C code as:
|
||||
void *data = (void *)(long)skb->data;
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
struct eth_hdr *eth = data;
|
||||
struct iphdr *iph = data + sizeof(*eth);
|
||||
struct udphdr *udp = data + sizeof(*eth) + sizeof(*iph);
|
||||
|
||||
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*udp) > data_end)
|
||||
return 0;
|
||||
if (eth->h_proto != htons(ETH_P_IP))
|
||||
return 0;
|
||||
if (iph->protocol != IPPROTO_UDP || iph->ihl != 5)
|
||||
return 0;
|
||||
if (udp->dest == 53 || udp->source == 9)
|
||||
...;
|
||||
which makes such programs easier to write comparing to LD_ABS insn
|
||||
and significantly faster.
|
||||
|
||||
eBPF maps
|
||||
---------
|
||||
'maps' is a generic storage of different types for sharing data between kernel
|
||||
|
@ -1293,5 +1374,5 @@ to give potential BPF hackers or security auditors a better overview of
|
|||
the underlying architecture.
|
||||
|
||||
Jay Schulist <jschlst@samba.org>
|
||||
Daniel Borkmann <dborkman@redhat.com>
|
||||
Alexei Starovoitov <ast@plumgrid.com>
|
||||
Daniel Borkmann <daniel@iogearbox.net>
|
||||
Alexei Starovoitov <ast@kernel.org>
|
||||
|
|
|
@ -33,7 +33,8 @@ my_dumping_routine(struct sk_buff *skb, ...)
|
|||
{
|
||||
struct gnet_dump dump;
|
||||
|
||||
if (gnet_stats_start_copy(skb, TCA_STATS2, &mystruct->lock, &dump) < 0)
|
||||
if (gnet_stats_start_copy(skb, TCA_STATS2, &mystruct->lock, &dump,
|
||||
TCA_PAD) < 0)
|
||||
goto rtattr_failure;
|
||||
|
||||
if (gnet_stats_copy_basic(&dump, &mystruct->bstats) < 0 ||
|
||||
|
@ -56,7 +57,8 @@ existing TLV types.
|
|||
my_dumping_routine(struct sk_buff *skb, ...)
|
||||
{
|
||||
if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
|
||||
TCA_XSTATS, &mystruct->lock, &dump) < 0)
|
||||
TCA_XSTATS, &mystruct->lock, &dump,
|
||||
TCA_PAD) < 0)
|
||||
goto rtattr_failure;
|
||||
...
|
||||
}
|
||||
|
|
|
@ -63,6 +63,16 @@ fwmark_reflect - BOOLEAN
|
|||
fwmark of the packet they are replying to.
|
||||
Default: 0
|
||||
|
||||
fib_multipath_use_neigh - BOOLEAN
|
||||
Use status of existing neighbor entry when determining nexthop for
|
||||
multipath routes. If disabled, neighbor information is not used and
|
||||
packets could be directed to a failed nexthop. Only valid for kernels
|
||||
built with CONFIG_IP_ROUTE_MULTIPATH enabled.
|
||||
Default: 0 (disabled)
|
||||
Possible values:
|
||||
0 - disabled
|
||||
1 - enabled
|
||||
|
||||
route/max_size - INTEGER
|
||||
Maximum number of routes allowed in the kernel. Increase
|
||||
this when using large numbers of interfaces and/or routes.
|
||||
|
|
|
@ -37,14 +37,27 @@ radiotap headers and used to control injection:
|
|||
HT rate for the transmission (only for devices without own rate control).
|
||||
Also some flags are parsed
|
||||
|
||||
IEEE80211_TX_RC_SHORT_GI: use short guard interval
|
||||
IEEE80211_TX_RC_40_MHZ_WIDTH: send in HT40 mode
|
||||
IEEE80211_RADIOTAP_MCS_SGI: use short guard interval
|
||||
IEEE80211_RADIOTAP_MCS_BW_40: send in HT40 mode
|
||||
|
||||
* IEEE80211_RADIOTAP_DATA_RETRIES
|
||||
|
||||
number of retries when either IEEE80211_RADIOTAP_RATE or
|
||||
IEEE80211_RADIOTAP_MCS was used
|
||||
|
||||
* IEEE80211_RADIOTAP_VHT
|
||||
|
||||
VHT mcs and number of streams used in the transmission (only for devices
|
||||
without own rate control). Also other fields are parsed
|
||||
|
||||
flags field
|
||||
IEEE80211_RADIOTAP_VHT_FLAG_SGI: use short guard interval
|
||||
|
||||
bandwidth field
|
||||
1: send using 40MHz channel width
|
||||
4: send using 80MHz channel width
|
||||
11: send using 160MHz channel width
|
||||
|
||||
The injection code can also skip all other currently defined radiotap fields
|
||||
facilitating replay of captured radiotap headers directly.
|
||||
|
||||
|
|
|
@ -131,13 +131,11 @@ stack. Driver should not change behaviour based on them.
|
|||
|
||||
* LLTX driver (deprecated for hardware drivers)
|
||||
|
||||
NETIF_F_LLTX should be set in drivers that implement their own locking in
|
||||
transmit path or don't need locking at all (e.g. software tunnels).
|
||||
In ndo_start_xmit, it is recommended to use a try_lock and return
|
||||
NETDEV_TX_LOCKED when the spin lock fails. The locking should also properly
|
||||
protect against other callbacks (the rules you need to find out).
|
||||
NETIF_F_LLTX is meant to be used by drivers that don't need locking at all,
|
||||
e.g. software tunnels.
|
||||
|
||||
Don't use it for new drivers.
|
||||
This is also used in a few legacy drivers that implement their
|
||||
own locking, don't use it for new (hardware) drivers.
|
||||
|
||||
* netns-local device
|
||||
|
||||
|
|
|
@ -69,10 +69,9 @@ ndo_start_xmit:
|
|||
|
||||
When the driver sets NETIF_F_LLTX in dev->features this will be
|
||||
called without holding netif_tx_lock. In this case the driver
|
||||
has to lock by itself when needed. It is recommended to use a try lock
|
||||
for this and return NETDEV_TX_LOCKED when the spin lock fails.
|
||||
The locking there should also properly protect against
|
||||
set_rx_mode. Note that the use of NETIF_F_LLTX is deprecated.
|
||||
has to lock by itself when needed.
|
||||
The locking there should also properly protect against
|
||||
set_rx_mode. WARNING: use of NETIF_F_LLTX is deprecated.
|
||||
Don't use it for new drivers.
|
||||
|
||||
Context: Process with BHs disabled or BH (timer),
|
||||
|
@ -83,8 +82,6 @@ ndo_start_xmit:
|
|||
o NETDEV_TX_BUSY Cannot transmit packet, try later
|
||||
Usually a bug, means queue start/stop flow control is broken in
|
||||
the driver. Note: the driver must NOT put the skb in its DMA ring.
|
||||
o NETDEV_TX_LOCKED Locking failed, please retry quickly.
|
||||
Only valid when NETIF_F_LLTX is set.
|
||||
|
||||
ndo_tx_timeout:
|
||||
Synchronization: netif_tx_lock spinlock; all TX queues frozen.
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
Segmentation Offloads in the Linux Networking Stack
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document describes a set of techniques in the Linux networking stack
|
||||
to take advantage of segmentation offload capabilities of various NICs.
|
||||
|
||||
The following technologies are described:
|
||||
* TCP Segmentation Offload - TSO
|
||||
* UDP Fragmentation Offload - UFO
|
||||
* IPIP, SIT, GRE, and UDP Tunnel Offloads
|
||||
* Generic Segmentation Offload - GSO
|
||||
* Generic Receive Offload - GRO
|
||||
* Partial Generic Segmentation Offload - GSO_PARTIAL
|
||||
|
||||
TCP Segmentation Offload
|
||||
========================
|
||||
|
||||
TCP segmentation allows a device to segment a single frame into multiple
|
||||
frames with a data payload size specified in skb_shinfo()->gso_size.
|
||||
When TCP segmentation requested the bit for either SKB_GSO_TCP or
|
||||
SKB_GSO_TCP6 should be set in skb_shinfo()->gso_type and
|
||||
skb_shinfo()->gso_size should be set to a non-zero value.
|
||||
|
||||
TCP segmentation is dependent on support for the use of partial checksum
|
||||
offload. For this reason TSO is normally disabled if the Tx checksum
|
||||
offload for a given device is disabled.
|
||||
|
||||
In order to support TCP segmentation offload it is necessary to populate
|
||||
the network and transport header offsets of the skbuff so that the device
|
||||
drivers will be able determine the offsets of the IP or IPv6 header and the
|
||||
TCP header. In addition as CHECKSUM_PARTIAL is required csum_start should
|
||||
also point to the TCP header of the packet.
|
||||
|
||||
For IPv4 segmentation we support one of two types in terms of the IP ID.
|
||||
The default behavior is to increment the IP ID with every segment. If the
|
||||
GSO type SKB_GSO_TCP_FIXEDID is specified then we will not increment the IP
|
||||
ID and all segments will use the same IP ID. If a device has
|
||||
NETIF_F_TSO_MANGLEID set then the IP ID can be ignored when performing TSO
|
||||
and we will either increment the IP ID for all frames, or leave it at a
|
||||
static value based on driver preference.
|
||||
|
||||
UDP Fragmentation Offload
|
||||
=========================
|
||||
|
||||
UDP fragmentation offload allows a device to fragment an oversized UDP
|
||||
datagram into multiple IPv4 fragments. Many of the requirements for UDP
|
||||
fragmentation offload are the same as TSO. However the IPv4 ID for
|
||||
fragments should not increment as a single IPv4 datagram is fragmented.
|
||||
|
||||
IPIP, SIT, GRE, UDP Tunnel, and Remote Checksum Offloads
|
||||
========================================================
|
||||
|
||||
In addition to the offloads described above it is possible for a frame to
|
||||
contain additional headers such as an outer tunnel. In order to account
|
||||
for such instances an additional set of segmentation offload types were
|
||||
introduced including SKB_GSO_IPIP, SKB_GSO_SIT, SKB_GSO_GRE, and
|
||||
SKB_GSO_UDP_TUNNEL. These extra segmentation types are used to identify
|
||||
cases where there are more than just 1 set of headers. For example in the
|
||||
case of IPIP and SIT we should have the network and transport headers moved
|
||||
from the standard list of headers to "inner" header offsets.
|
||||
|
||||
Currently only two levels of headers are supported. The convention is to
|
||||
refer to the tunnel headers as the outer headers, while the encapsulated
|
||||
data is normally referred to as the inner headers. Below is the list of
|
||||
calls to access the given headers:
|
||||
|
||||
IPIP/SIT Tunnel:
|
||||
Outer Inner
|
||||
MAC skb_mac_header
|
||||
Network skb_network_header skb_inner_network_header
|
||||
Transport skb_transport_header
|
||||
|
||||
UDP/GRE Tunnel:
|
||||
Outer Inner
|
||||
MAC skb_mac_header skb_inner_mac_header
|
||||
Network skb_network_header skb_inner_network_header
|
||||
Transport skb_transport_header skb_inner_transport_header
|
||||
|
||||
In addition to the above tunnel types there are also SKB_GSO_GRE_CSUM and
|
||||
SKB_GSO_UDP_TUNNEL_CSUM. These two additional tunnel types reflect the
|
||||
fact that the outer header also requests to have a non-zero checksum
|
||||
included in the outer header.
|
||||
|
||||
Finally there is SKB_GSO_REMCSUM which indicates that a given tunnel header
|
||||
has requested a remote checksum offload. In this case the inner headers
|
||||
will be left with a partial checksum and only the outer header checksum
|
||||
will be computed.
|
||||
|
||||
Generic Segmentation Offload
|
||||
============================
|
||||
|
||||
Generic segmentation offload is a pure software offload that is meant to
|
||||
deal with cases where device drivers cannot perform the offloads described
|
||||
above. What occurs in GSO is that a given skbuff will have its data broken
|
||||
out over multiple skbuffs that have been resized to match the MSS provided
|
||||
via skb_shinfo()->gso_size.
|
||||
|
||||
Before enabling any hardware segmentation offload a corresponding software
|
||||
offload is required in GSO. Otherwise it becomes possible for a frame to
|
||||
be re-routed between devices and end up being unable to be transmitted.
|
||||
|
||||
Generic Receive Offload
|
||||
=======================
|
||||
|
||||
Generic receive offload is the complement to GSO. Ideally any frame
|
||||
assembled by GRO should be segmented to create an identical sequence of
|
||||
frames using GSO, and any sequence of frames segmented by GSO should be
|
||||
able to be reassembled back to the original by GRO. The only exception to
|
||||
this is IPv4 ID in the case that the DF bit is set for a given IP header.
|
||||
If the value of the IPv4 ID is not sequentially incrementing it will be
|
||||
altered so that it is when a frame assembled via GRO is segmented via GSO.
|
||||
|
||||
Partial Generic Segmentation Offload
|
||||
====================================
|
||||
|
||||
Partial generic segmentation offload is a hybrid between TSO and GSO. What
|
||||
it effectively does is take advantage of certain traits of TCP and tunnels
|
||||
so that instead of having to rewrite the packet headers for each segment
|
||||
only the inner-most transport header and possibly the outer-most network
|
||||
header need to be updated. This allows devices that do not support tunnel
|
||||
offloads or tunnel offloads with checksum to still make use of segmentation.
|
||||
|
||||
With the partial offload what occurs is that all headers excluding the
|
||||
inner transport header are updated such that they will contain the correct
|
||||
values for if the header was simply duplicated. The one exception to this
|
||||
is the outer IPv4 ID field. It is up to the device drivers to guarantee
|
||||
that the IPv4 ID field is incremented in the case that a given header does
|
||||
not have the DF bit set.
|
|
@ -1,6 +1,6 @@
|
|||
STMicroelectronics 10/100/1000 Synopsys Ethernet driver
|
||||
|
||||
Copyright (C) 2007-2014 STMicroelectronics Ltd
|
||||
Copyright (C) 2007-2015 STMicroelectronics Ltd
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
|
||||
This is the driver for the MAC 10/100/1000 on-chip Ethernet controllers
|
||||
|
@ -138,6 +138,8 @@ struct plat_stmmacenet_data {
|
|||
int (*init)(struct platform_device *pdev, void *priv);
|
||||
void (*exit)(struct platform_device *pdev, void *priv);
|
||||
void *bsp_priv;
|
||||
int has_gmac4;
|
||||
bool tso_en;
|
||||
};
|
||||
|
||||
Where:
|
||||
|
@ -181,6 +183,8 @@ Where:
|
|||
registers. init/exit callbacks should not use or modify
|
||||
platform data.
|
||||
o bsp_priv: another private pointer.
|
||||
o has_gmac4: uses GMAC4 core.
|
||||
o tso_en: Enables TSO (TCP Segmentation Offload) feature.
|
||||
|
||||
For MDIO bus The we have:
|
||||
|
||||
|
@ -278,6 +282,13 @@ Please see the following document:
|
|||
o stmmac_ethtool.c: to implement the ethtool support;
|
||||
o stmmac.h: private driver structure;
|
||||
o common.h: common definitions and VFTs;
|
||||
o mmc_core.c/mmc.h: Management MAC Counters;
|
||||
o stmmac_hwtstamp.c: HW timestamp support for PTP;
|
||||
o stmmac_ptp.c: PTP 1588 clock;
|
||||
o dwmac-<XXX>.c: these are for the platform glue-logic file; e.g. dwmac-sti.c
|
||||
for STMicroelectronics SoCs.
|
||||
|
||||
- GMAC 3.x
|
||||
o descs.h: descriptor structure definitions;
|
||||
o dwmac1000_core.c: dwmac GiGa core functions;
|
||||
o dwmac1000_dma.c: dma functions for the GMAC chip;
|
||||
|
@ -289,11 +300,32 @@ Please see the following document:
|
|||
o enh_desc.c: functions for handling enhanced descriptors;
|
||||
o norm_desc.c: functions for handling normal descriptors;
|
||||
o chain_mode.c/ring_mode.c:: functions to manage RING/CHAINED modes;
|
||||
o mmc_core.c/mmc.h: Management MAC Counters;
|
||||
o stmmac_hwtstamp.c: HW timestamp support for PTP;
|
||||
o stmmac_ptp.c: PTP 1588 clock;
|
||||
o dwmac-<XXX>.c: these are for the platform glue-logic file; e.g. dwmac-sti.c
|
||||
for STMicroelectronics SoCs.
|
||||
|
||||
- GMAC4.x generation
|
||||
o dwmac4_core.c: dwmac GMAC4.x core functions;
|
||||
o dwmac4_desc.c: functions for handling GMAC4.x descriptors;
|
||||
o dwmac4_descs.h: descriptor definitions;
|
||||
o dwmac4_dma.c: dma functions for the GMAC4.x chip;
|
||||
o dwmac4_dma.h: dma definitions for the GMAC4.x chip;
|
||||
o dwmac4.h: core definitions for the GMAC4.x chip;
|
||||
o dwmac4_lib.c: generic GMAC4.x functions;
|
||||
|
||||
4.12) TSO support (GMAC4.x)
|
||||
|
||||
TSO (Tcp Segmentation Offload) feature is supported by GMAC 4.x chip family.
|
||||
When a packet is sent through TCP protocol, the TCP stack ensures that
|
||||
the SKB provided to the low level driver (stmmac in our case) matches with
|
||||
the maximum frame len (IP header + TCP header + payload <= 1500 bytes (for
|
||||
MTU set to 1500)). It means that if an application using TCP want to send a
|
||||
packet which will have a length (after adding headers) > 1514 the packet
|
||||
will be split in several TCP packets: The data payload is split and headers
|
||||
(TCP/IP ..) are added. It is done by software.
|
||||
|
||||
When TSO is enabled, the TCP stack doesn't care about the maximum frame
|
||||
length and provide SKB packet to stmmac as it is. The GMAC IP will have to
|
||||
perform the segmentation by it self to match with maximum frame length.
|
||||
|
||||
This feature can be enabled in device tree through "snps,tso" entry.
|
||||
|
||||
5) Debug Information
|
||||
|
||||
|
|
|
@ -89,6 +89,18 @@ Typically, the management port is not participating in offloaded data plane and
|
|||
is loaded with a different driver, such as a NIC driver, on the management port
|
||||
device.
|
||||
|
||||
Switch ID
|
||||
^^^^^^^^^
|
||||
|
||||
The switchdev driver must implement the switchdev op switchdev_port_attr_get
|
||||
for SWITCHDEV_ATTR_ID_PORT_PARENT_ID for each port netdev, returning the same
|
||||
physical ID for each port of a switch. The ID must be unique between switches
|
||||
on the same system. The ID does not need to be unique between switches on
|
||||
different systems.
|
||||
|
||||
The switch ID is used to locate ports on a switch and to know if aggregated
|
||||
ports belong to the same switch.
|
||||
|
||||
Port Netdev Naming
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -104,25 +116,13 @@ external configuration. For example, if a physical 40G port is split logically
|
|||
into 4 10G ports, resulting in 4 port netdevs, the device can give a unique
|
||||
name for each port using port PHYS name. The udev rule would be:
|
||||
|
||||
SUBSYSTEM=="net", ACTION=="add", DRIVER="<driver>", ATTR{phys_port_name}!="", \
|
||||
NAME="$attr{phys_port_name}"
|
||||
SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}=="<phys_switch_id>", \
|
||||
ATTR{phys_port_name}!="", NAME="swX$attr{phys_port_name}"
|
||||
|
||||
Suggested naming convention is "swXpYsZ", where X is the switch name or ID, Y
|
||||
is the port name or ID, and Z is the sub-port name or ID. For example, sw1p1s0
|
||||
would be sub-port 0 on port 1 on switch 1.
|
||||
|
||||
Switch ID
|
||||
^^^^^^^^^
|
||||
|
||||
The switchdev driver must implement the switchdev op switchdev_port_attr_get
|
||||
for SWITCHDEV_ATTR_ID_PORT_PARENT_ID for each port netdev, returning the same
|
||||
physical ID for each port of a switch. The ID must be unique between switches
|
||||
on the same system. The ID does not need to be unique between switches on
|
||||
different systems.
|
||||
|
||||
The switch ID is used to locate ports on a switch and to know if aggregated
|
||||
ports belong to the same switch.
|
||||
|
||||
Port Features
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -44,11 +44,17 @@ timeval of SO_TIMESTAMP (ms).
|
|||
Supports multiple types of timestamp requests. As a result, this
|
||||
socket option takes a bitmap of flags, not a boolean. In
|
||||
|
||||
err = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (void *) val, &val);
|
||||
err = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (void *) val,
|
||||
sizeof(val));
|
||||
|
||||
val is an integer with any of the following bits set. Setting other
|
||||
bit returns EINVAL and does not change the current state.
|
||||
|
||||
The socket option configures timestamp generation for individual
|
||||
sk_buffs (1.3.1), timestamp reporting to the socket's error
|
||||
queue (1.3.2) and options (1.3.3). Timestamp generation can also
|
||||
be enabled for individual sendmsg calls using cmsg (1.3.4).
|
||||
|
||||
|
||||
1.3.1 Timestamp Generation
|
||||
|
||||
|
@ -71,13 +77,16 @@ SOF_TIMESTAMPING_RX_SOFTWARE:
|
|||
kernel receive stack.
|
||||
|
||||
SOF_TIMESTAMPING_TX_HARDWARE:
|
||||
Request tx timestamps generated by the network adapter.
|
||||
Request tx timestamps generated by the network adapter. This flag
|
||||
can be enabled via both socket options and control messages.
|
||||
|
||||
SOF_TIMESTAMPING_TX_SOFTWARE:
|
||||
Request tx timestamps when data leaves the kernel. These timestamps
|
||||
are generated in the device driver as close as possible, but always
|
||||
prior to, passing the packet to the network interface. Hence, they
|
||||
require driver support and may not be available for all devices.
|
||||
This flag can be enabled via both socket options and control messages.
|
||||
|
||||
|
||||
SOF_TIMESTAMPING_TX_SCHED:
|
||||
Request tx timestamps prior to entering the packet scheduler. Kernel
|
||||
|
@ -90,7 +99,8 @@ SOF_TIMESTAMPING_TX_SCHED:
|
|||
machines with virtual devices where a transmitted packet travels
|
||||
through multiple devices and, hence, multiple packet schedulers,
|
||||
a timestamp is generated at each layer. This allows for fine
|
||||
grained measurement of queuing delay.
|
||||
grained measurement of queuing delay. This flag can be enabled
|
||||
via both socket options and control messages.
|
||||
|
||||
SOF_TIMESTAMPING_TX_ACK:
|
||||
Request tx timestamps when all data in the send buffer has been
|
||||
|
@ -99,6 +109,7 @@ SOF_TIMESTAMPING_TX_ACK:
|
|||
over-report measurement, because the timestamp is generated when all
|
||||
data up to and including the buffer at send() was acknowledged: the
|
||||
cumulative acknowledgment. The mechanism ignores SACK and FACK.
|
||||
This flag can be enabled via both socket options and control messages.
|
||||
|
||||
|
||||
1.3.2 Timestamp Reporting
|
||||
|
@ -183,6 +194,37 @@ having access to the contents of the original packet, so cannot be
|
|||
combined with SOF_TIMESTAMPING_OPT_TSONLY.
|
||||
|
||||
|
||||
1.3.4. Enabling timestamps via control messages
|
||||
|
||||
In addition to socket options, timestamp generation can be requested
|
||||
per write via cmsg, only for SOF_TIMESTAMPING_TX_* (see Section 1.3.1).
|
||||
Using this feature, applications can sample timestamps per sendmsg()
|
||||
without paying the overhead of enabling and disabling timestamps via
|
||||
setsockopt:
|
||||
|
||||
struct msghdr *msg;
|
||||
...
|
||||
cmsg = CMSG_FIRSTHDR(msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SO_TIMESTAMPING;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(__u32));
|
||||
*((__u32 *) CMSG_DATA(cmsg)) = SOF_TIMESTAMPING_TX_SCHED |
|
||||
SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_TX_ACK;
|
||||
err = sendmsg(fd, msg, 0);
|
||||
|
||||
The SOF_TIMESTAMPING_TX_* flags set via cmsg will override
|
||||
the SOF_TIMESTAMPING_TX_* flags set via setsockopt.
|
||||
|
||||
Moreover, applications must still enable timestamp reporting via
|
||||
setsockopt to receive timestamps:
|
||||
|
||||
__u32 val = SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_OPT_ID /* or any other flag */;
|
||||
err = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (void *) val,
|
||||
sizeof(val));
|
||||
|
||||
|
||||
1.4 Bytestream Timestamps
|
||||
|
||||
The SO_TIMESTAMPING interface supports timestamping of bytes in a
|
||||
|
|
|
@ -43,6 +43,17 @@ Values :
|
|||
1 - enable the JIT
|
||||
2 - enable the JIT and ask the compiler to emit traces on kernel log.
|
||||
|
||||
bpf_jit_harden
|
||||
--------------
|
||||
|
||||
This enables hardening for the Berkeley Packet Filter Just in Time compiler.
|
||||
Supported are eBPF JIT backends. Enabling hardening trades off performance,
|
||||
but can mitigate JIT spraying.
|
||||
Values :
|
||||
0 - disable JIT hardening (default value)
|
||||
1 - enable JIT hardening for unprivileged users only
|
||||
2 - enable JIT hardening for all users
|
||||
|
||||
dev_weight
|
||||
--------------
|
||||
|
||||
|
|
18
MAINTAINERS
18
MAINTAINERS
|
@ -1472,7 +1472,10 @@ F: arch/arm/boot/dts/qcom-*.dts
|
|||
F: arch/arm/boot/dts/qcom-*.dtsi
|
||||
F: arch/arm/mach-qcom/
|
||||
F: arch/arm64/boot/dts/qcom/*
|
||||
F: drivers/i2c/busses/i2c-qup.c
|
||||
F: drivers/clk/qcom/
|
||||
F: drivers/soc/qcom/
|
||||
F: drivers/spi/spi-qup.c
|
||||
F: drivers/tty/serial/msm_serial.h
|
||||
F: drivers/tty/serial/msm_serial.c
|
||||
F: drivers/*/pm8???-*
|
||||
|
@ -2205,10 +2208,13 @@ BATMAN ADVANCED
|
|||
M: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
M: Simon Wunderlich <sw@simonwunderlich.de>
|
||||
M: Antonio Quartulli <a@unstable.cc>
|
||||
L: b.a.t.m.a.n@lists.open-mesh.org
|
||||
L: b.a.t.m.a.n@lists.open-mesh.org (moderated for non-subscribers)
|
||||
W: https://www.open-mesh.org/
|
||||
Q: https://patchwork.open-mesh.org/project/batman/list/
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-class-net-batman-adv
|
||||
F: Documentation/ABI/testing/sysfs-class-net-mesh
|
||||
F: Documentation/networking/batman-adv.txt
|
||||
F: net/batman-adv/
|
||||
|
||||
BAYCOM/HDLCDRV DRIVERS FOR AX.25
|
||||
|
@ -3350,6 +3356,7 @@ F: Documentation/powerpc/cxlflash.txt
|
|||
|
||||
STMMAC ETHERNET DRIVER
|
||||
M: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
M: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
L: netdev@vger.kernel.org
|
||||
W: http://www.stlinux.com
|
||||
S: Supported
|
||||
|
@ -5755,13 +5762,6 @@ F: drivers/char/hw_random/ixp4xx-rng.c
|
|||
|
||||
INTEL ETHERNET DRIVERS
|
||||
M: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
|
||||
R: Jesse Brandeburg <jesse.brandeburg@intel.com>
|
||||
R: Shannon Nelson <shannon.nelson@intel.com>
|
||||
R: Carolyn Wyborny <carolyn.wyborny@intel.com>
|
||||
R: Don Skidmore <donald.c.skidmore@intel.com>
|
||||
R: Bruce Allan <bruce.w.allan@intel.com>
|
||||
R: John Ronciak <john.ronciak@intel.com>
|
||||
R: Mitch Williams <mitch.a.williams@intel.com>
|
||||
L: intel-wired-lan@lists.osuosl.org (moderated for non-subscribers)
|
||||
W: http://www.intel.com/support/feedback.htm
|
||||
W: http://e1000.sourceforge.net/
|
||||
|
@ -9500,7 +9500,7 @@ F: drivers/net/wireless/realtek/rtlwifi/rtl8192ce/
|
|||
RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
|
||||
M: Jes Sorensen <Jes.Sorensen@redhat.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8xxxu-devel
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/realtek/rtl8xxxu/
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ config ARM
|
|||
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARM_SMCCC if CPU_V7
|
||||
select HAVE_BPF_JIT
|
||||
select HAVE_CBPF_JIT
|
||||
select HAVE_CC_STACKPROTECTOR
|
||||
select HAVE_CONTEXT_TRACKING
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
|
|
|
@ -91,10 +91,7 @@ CONFIG_SATA_AHCI=y
|
|||
CONFIG_SATA_MV=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_NET_DSA_MV88E6060=y
|
||||
CONFIG_NET_DSA_MV88E6131=y
|
||||
CONFIG_NET_DSA_MV88E6123=y
|
||||
CONFIG_NET_DSA_MV88E6171=y
|
||||
CONFIG_NET_DSA_MV88E6352=y
|
||||
CONFIG_NET_DSA_MV88E6XXX=y
|
||||
CONFIG_MV643XX_ETH=y
|
||||
CONFIG_R8169=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
|
|
|
@ -66,7 +66,7 @@ CONFIG_SATA_AHCI=y
|
|||
CONFIG_AHCI_MVEBU=y
|
||||
CONFIG_SATA_MV=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_NET_DSA_MV88E6171=y
|
||||
CONFIG_NET_DSA_MV88E6XXX=y
|
||||
CONFIG_MV643XX_ETH=y
|
||||
CONFIG_MVNETA=y
|
||||
CONFIG_MVPP2=y
|
||||
|
|
|
@ -85,8 +85,7 @@ CONFIG_ATA=y
|
|||
CONFIG_SATA_MV=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_MII=y
|
||||
CONFIG_NET_DSA_MV88E6131=y
|
||||
CONFIG_NET_DSA_MV88E6123=y
|
||||
CONFIG_NET_DSA_MV88E6XXX=y
|
||||
CONFIG_MV643XX_ETH=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
# CONFIG_INPUT_MOUSEDEV is not set
|
||||
|
|
|
@ -61,7 +61,7 @@ config ARM64
|
|||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
select HAVE_ARM_SMCCC
|
||||
select HAVE_BPF_JIT
|
||||
select HAVE_EBPF_JIT
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
select HAVE_CC_STACKPROTECTOR
|
||||
select HAVE_CMPXCHG_DOUBLE
|
||||
|
|
|
@ -653,6 +653,7 @@
|
|||
<0 113 4>,
|
||||
<0 114 4>,
|
||||
<0 115 4>;
|
||||
channel = <12>;
|
||||
port-id = <1>;
|
||||
dma-coherent;
|
||||
clocks = <&xge1clk 0>;
|
||||
|
|
|
@ -993,6 +993,7 @@
|
|||
<0x0 0x65 0x4>,
|
||||
<0x0 0x66 0x4>,
|
||||
<0x0 0x67 0x4>;
|
||||
channel = <0>;
|
||||
dma-coherent;
|
||||
clocks = <&xge0clk 0>;
|
||||
/* mac address will be overwritten by the bootloader */
|
||||
|
|
|
@ -24,17 +24,19 @@ soc0: soc@000000000 {
|
|||
};
|
||||
|
||||
dsaf0: dsa@c7000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "hisilicon,hns-dsaf-v1";
|
||||
mode = "6port-16rss";
|
||||
interrupt-parent = <&mbigen_dsa>;
|
||||
|
||||
reg = <0x0 0xC0000000 0x0 0x420000
|
||||
0x0 0xC2000000 0x0 0x300000
|
||||
0x0 0xc5000000 0x0 0x890000
|
||||
reg = <0x0 0xc5000000 0x0 0x890000
|
||||
0x0 0xc7000000 0x0 0x60000
|
||||
>;
|
||||
|
||||
phy-handle = <0 0 0 0 &soc0_phy0 &soc0_phy1 0 0>;
|
||||
reg-names = "ppe-base","dsaf-base";
|
||||
subctrl-syscon = <&dsaf_subctrl>;
|
||||
reset-field-offset = <0>;
|
||||
interrupts = <
|
||||
/* [14] ge fifo err 8 / xge 6**/
|
||||
149 0x4 150 0x4 151 0x4 152 0x4
|
||||
|
@ -122,12 +124,31 @@ soc0: soc@000000000 {
|
|||
buf-size = <4096>;
|
||||
desc-num = <1024>;
|
||||
dma-coherent;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
serdes-syscon = <&serdes_ctrl0>;
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
serdes-syscon = <&serdes_ctrl0>;
|
||||
};
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
phy-handle = <&soc0_phy0>;
|
||||
serdes-syscon = <&serdes_ctrl1>;
|
||||
};
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
phy-handle = <&soc0_phy1>;
|
||||
serdes-syscon = <&serdes_ctrl1>;
|
||||
};
|
||||
};
|
||||
|
||||
eth0: ethernet@0{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <0>;
|
||||
port-idx-in-ae = <0>;
|
||||
local-mac-address = [00 00 00 01 00 58];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
|
@ -135,56 +156,25 @@ soc0: soc@000000000 {
|
|||
eth1: ethernet@1{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <1>;
|
||||
port-idx-in-ae = <1>;
|
||||
local-mac-address = [00 00 00 01 00 59];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
eth2: ethernet@2{
|
||||
eth2: ethernet@4{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <2>;
|
||||
port-idx-in-ae = <4>;
|
||||
local-mac-address = [00 00 00 01 00 5a];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
eth3: ethernet@3{
|
||||
eth3: ethernet@5{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <3>;
|
||||
port-idx-in-ae = <5>;
|
||||
local-mac-address = [00 00 00 01 00 5b];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
eth4: ethernet@4{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <4>;
|
||||
local-mac-address = [00 00 00 01 00 5c];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
eth5: ethernet@5{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <5>;
|
||||
local-mac-address = [00 00 00 01 00 5d];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
eth6: ethernet@6{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <6>;
|
||||
local-mac-address = [00 00 00 01 00 5e];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
eth7: ethernet@7{
|
||||
compatible = "hisilicon,hns-nic-v1";
|
||||
ae-handle = <&dsaf0>;
|
||||
port-id = <7>;
|
||||
local-mac-address = [00 00 00 01 00 5f];
|
||||
status = "disabled";
|
||||
dma-coherent;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
int bpf_jit_enable __read_mostly;
|
||||
|
||||
#define TMP_REG_1 (MAX_BPF_REG + 0)
|
||||
#define TMP_REG_2 (MAX_BPF_REG + 1)
|
||||
#define TMP_REG_1 (MAX_BPF_JIT_REG + 0)
|
||||
#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
|
||||
|
||||
/* Map BPF registers to A64 registers */
|
||||
static const int bpf2a64[] = {
|
||||
|
@ -51,15 +51,16 @@ static const int bpf2a64[] = {
|
|||
[BPF_REG_9] = A64_R(22),
|
||||
/* read-only frame pointer to access stack */
|
||||
[BPF_REG_FP] = A64_R(25),
|
||||
/* temporary register for internal BPF JIT */
|
||||
[TMP_REG_1] = A64_R(23),
|
||||
[TMP_REG_2] = A64_R(24),
|
||||
/* temporary registers for internal BPF JIT */
|
||||
[TMP_REG_1] = A64_R(10),
|
||||
[TMP_REG_2] = A64_R(11),
|
||||
/* temporary register for blinding constants */
|
||||
[BPF_REG_AX] = A64_R(9),
|
||||
};
|
||||
|
||||
struct jit_ctx {
|
||||
const struct bpf_prog *prog;
|
||||
int idx;
|
||||
int tmp_used;
|
||||
int epilogue_offset;
|
||||
int *offset;
|
||||
u32 *image;
|
||||
|
@ -152,8 +153,6 @@ static void build_prologue(struct jit_ctx *ctx)
|
|||
const u8 r8 = bpf2a64[BPF_REG_8];
|
||||
const u8 r9 = bpf2a64[BPF_REG_9];
|
||||
const u8 fp = bpf2a64[BPF_REG_FP];
|
||||
const u8 tmp1 = bpf2a64[TMP_REG_1];
|
||||
const u8 tmp2 = bpf2a64[TMP_REG_2];
|
||||
|
||||
/*
|
||||
* BPF prog stack layout
|
||||
|
@ -165,7 +164,7 @@ static void build_prologue(struct jit_ctx *ctx)
|
|||
* | ... | callee saved registers
|
||||
* +-----+
|
||||
* | | x25/x26
|
||||
* BPF fp register => -80:+-----+ <= (BPF_FP)
|
||||
* BPF fp register => -64:+-----+ <= (BPF_FP)
|
||||
* | |
|
||||
* | ... | BPF prog stack
|
||||
* | |
|
||||
|
@ -187,8 +186,6 @@ static void build_prologue(struct jit_ctx *ctx)
|
|||
/* Save callee-saved register */
|
||||
emit(A64_PUSH(r6, r7, A64_SP), ctx);
|
||||
emit(A64_PUSH(r8, r9, A64_SP), ctx);
|
||||
if (ctx->tmp_used)
|
||||
emit(A64_PUSH(tmp1, tmp2, A64_SP), ctx);
|
||||
|
||||
/* Save fp (x25) and x26. SP requires 16 bytes alignment */
|
||||
emit(A64_PUSH(fp, A64_R(26), A64_SP), ctx);
|
||||
|
@ -208,8 +205,6 @@ static void build_epilogue(struct jit_ctx *ctx)
|
|||
const u8 r8 = bpf2a64[BPF_REG_8];
|
||||
const u8 r9 = bpf2a64[BPF_REG_9];
|
||||
const u8 fp = bpf2a64[BPF_REG_FP];
|
||||
const u8 tmp1 = bpf2a64[TMP_REG_1];
|
||||
const u8 tmp2 = bpf2a64[TMP_REG_2];
|
||||
|
||||
/* We're done with BPF stack */
|
||||
emit(A64_ADD_I(1, A64_SP, A64_SP, STACK_SIZE), ctx);
|
||||
|
@ -218,8 +213,6 @@ static void build_epilogue(struct jit_ctx *ctx)
|
|||
emit(A64_POP(fp, A64_R(26), A64_SP), ctx);
|
||||
|
||||
/* Restore callee-saved register */
|
||||
if (ctx->tmp_used)
|
||||
emit(A64_POP(tmp1, tmp2, A64_SP), ctx);
|
||||
emit(A64_POP(r8, r9, A64_SP), ctx);
|
||||
emit(A64_POP(r6, r7, A64_SP), ctx);
|
||||
|
||||
|
@ -315,7 +308,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
emit(A64_UDIV(is64, dst, dst, src), ctx);
|
||||
break;
|
||||
case BPF_MOD:
|
||||
ctx->tmp_used = 1;
|
||||
emit(A64_UDIV(is64, tmp, dst, src), ctx);
|
||||
emit(A64_MUL(is64, tmp, tmp, src), ctx);
|
||||
emit(A64_SUB(is64, dst, dst, tmp), ctx);
|
||||
|
@ -388,49 +380,41 @@ emit_bswap_uxt:
|
|||
/* dst = dst OP imm */
|
||||
case BPF_ALU | BPF_ADD | BPF_K:
|
||||
case BPF_ALU64 | BPF_ADD | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_ADD(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_SUB | BPF_K:
|
||||
case BPF_ALU64 | BPF_SUB | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_SUB(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_AND | BPF_K:
|
||||
case BPF_ALU64 | BPF_AND | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_AND(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_OR | BPF_K:
|
||||
case BPF_ALU64 | BPF_OR | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_ORR(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_XOR | BPF_K:
|
||||
case BPF_ALU64 | BPF_XOR | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_EOR(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_MUL | BPF_K:
|
||||
case BPF_ALU64 | BPF_MUL | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_MUL(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_DIV | BPF_K:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_UDIV(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_MOD | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(is64, tmp2, imm, ctx);
|
||||
emit(A64_UDIV(is64, tmp, dst, tmp2), ctx);
|
||||
emit(A64_MUL(is64, tmp, tmp, tmp2), ctx);
|
||||
|
@ -501,12 +485,10 @@ emit_cond_jmp:
|
|||
case BPF_JMP | BPF_JNE | BPF_K:
|
||||
case BPF_JMP | BPF_JSGT | BPF_K:
|
||||
case BPF_JMP | BPF_JSGE | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(1, tmp, imm, ctx);
|
||||
emit(A64_CMP(1, dst, tmp), ctx);
|
||||
goto emit_cond_jmp;
|
||||
case BPF_JMP | BPF_JSET | BPF_K:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(1, tmp, imm, ctx);
|
||||
emit(A64_TST(1, dst, tmp), ctx);
|
||||
goto emit_cond_jmp;
|
||||
|
@ -516,7 +498,6 @@ emit_cond_jmp:
|
|||
const u8 r0 = bpf2a64[BPF_REG_0];
|
||||
const u64 func = (u64)__bpf_call_base + imm;
|
||||
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i64(tmp, func, ctx);
|
||||
emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
|
||||
emit(A64_MOV(1, A64_FP, A64_SP), ctx);
|
||||
|
@ -562,7 +543,6 @@ emit_cond_jmp:
|
|||
case BPF_LDX | BPF_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_MEM | BPF_B:
|
||||
case BPF_LDX | BPF_MEM | BPF_DW:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
switch (BPF_SIZE(code)) {
|
||||
case BPF_W:
|
||||
|
@ -586,7 +566,6 @@ emit_cond_jmp:
|
|||
case BPF_ST | BPF_MEM | BPF_B:
|
||||
case BPF_ST | BPF_MEM | BPF_DW:
|
||||
/* Load imm to a register then store it */
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(1, tmp2, off, ctx);
|
||||
emit_a64_mov_i(1, tmp, imm, ctx);
|
||||
switch (BPF_SIZE(code)) {
|
||||
|
@ -610,7 +589,6 @@ emit_cond_jmp:
|
|||
case BPF_STX | BPF_MEM | BPF_H:
|
||||
case BPF_STX | BPF_MEM | BPF_B:
|
||||
case BPF_STX | BPF_MEM | BPF_DW:
|
||||
ctx->tmp_used = 1;
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
switch (BPF_SIZE(code)) {
|
||||
case BPF_W:
|
||||
|
@ -762,31 +740,45 @@ void bpf_jit_compile(struct bpf_prog *prog)
|
|||
/* Nothing to do here. We support Internal BPF. */
|
||||
}
|
||||
|
||||
void bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct bpf_binary_header *header;
|
||||
bool tmp_blinded = false;
|
||||
struct jit_ctx ctx;
|
||||
int image_size;
|
||||
u8 *image_ptr;
|
||||
|
||||
if (!bpf_jit_enable)
|
||||
return;
|
||||
return orig_prog;
|
||||
|
||||
if (!prog || !prog->len)
|
||||
return;
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.prog = prog;
|
||||
|
||||
ctx.offset = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
|
||||
if (ctx.offset == NULL)
|
||||
return;
|
||||
if (ctx.offset == NULL) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 1. Initial fake pass to compute ctx->idx. */
|
||||
|
||||
/* Fake pass to fill in ctx->offset and ctx->tmp_used. */
|
||||
if (build_body(&ctx))
|
||||
goto out;
|
||||
/* Fake pass to fill in ctx->offset. */
|
||||
if (build_body(&ctx)) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
build_prologue(&ctx);
|
||||
|
||||
|
@ -797,8 +789,10 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
|
|||
image_size = sizeof(u32) * ctx.idx;
|
||||
header = bpf_jit_binary_alloc(image_size, &image_ptr,
|
||||
sizeof(u32), jit_fill_hole);
|
||||
if (header == NULL)
|
||||
goto out;
|
||||
if (header == NULL) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
/* 2. Now, the actual pass. */
|
||||
|
||||
|
@ -809,7 +803,8 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
|
|||
|
||||
if (build_body(&ctx)) {
|
||||
bpf_jit_binary_free(header);
|
||||
goto out;
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
build_epilogue(&ctx);
|
||||
|
@ -817,7 +812,8 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
|
|||
/* 3. Extra pass to validate JITed code. */
|
||||
if (validate_code(&ctx)) {
|
||||
bpf_jit_binary_free(header);
|
||||
goto out;
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
/* And we're done. */
|
||||
|
@ -829,8 +825,14 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
|
|||
set_memory_ro((unsigned long)header, header->pages);
|
||||
prog->bpf_func = (void *)ctx.image;
|
||||
prog->jited = 1;
|
||||
out:
|
||||
|
||||
out_off:
|
||||
kfree(ctx.offset);
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
}
|
||||
|
||||
void bpf_jit_free(struct bpf_prog *prog)
|
||||
|
|
|
@ -15,7 +15,7 @@ config MIPS
|
|||
select HAVE_ARCH_KGDB
|
||||
select HAVE_ARCH_SECCOMP_FILTER
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_BPF_JIT if !CPU_MICROMIPS
|
||||
select HAVE_CBPF_JIT if !CPU_MICROMIPS
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_DYNAMIC_FTRACE
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
|
|
|
@ -126,7 +126,7 @@ config PPC
|
|||
select IRQ_FORCED_THREADING
|
||||
select HAVE_RCU_TABLE_FREE if SMP
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_BPF_JIT
|
||||
select HAVE_CBPF_JIT
|
||||
select HAVE_ARCH_JUMP_LABEL
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
||||
select ARCH_HAS_GCOV_PROFILE_ALL
|
||||
|
|
|
@ -126,7 +126,7 @@ config S390
|
|||
select HAVE_ARCH_SOFT_DIRTY
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
|
||||
select HAVE_EBPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
|
||||
select HAVE_CMPXCHG_DOUBLE
|
||||
select HAVE_CMPXCHG_LOCAL
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
|
|
|
@ -54,16 +54,17 @@ struct bpf_jit {
|
|||
#define SEEN_FUNC 16 /* calls C functions */
|
||||
#define SEEN_TAIL_CALL 32 /* code uses tail calls */
|
||||
#define SEEN_SKB_CHANGE 64 /* code changes skb data */
|
||||
#define SEEN_REG_AX 128 /* code uses constant blinding */
|
||||
#define SEEN_STACK (SEEN_FUNC | SEEN_MEM | SEEN_SKB)
|
||||
|
||||
/*
|
||||
* s390 registers
|
||||
*/
|
||||
#define REG_W0 (__MAX_BPF_REG+0) /* Work register 1 (even) */
|
||||
#define REG_W1 (__MAX_BPF_REG+1) /* Work register 2 (odd) */
|
||||
#define REG_SKB_DATA (__MAX_BPF_REG+2) /* SKB data register */
|
||||
#define REG_L (__MAX_BPF_REG+3) /* Literal pool register */
|
||||
#define REG_15 (__MAX_BPF_REG+4) /* Register 15 */
|
||||
#define REG_W0 (MAX_BPF_JIT_REG + 0) /* Work register 1 (even) */
|
||||
#define REG_W1 (MAX_BPF_JIT_REG + 1) /* Work register 2 (odd) */
|
||||
#define REG_SKB_DATA (MAX_BPF_JIT_REG + 2) /* SKB data register */
|
||||
#define REG_L (MAX_BPF_JIT_REG + 3) /* Literal pool register */
|
||||
#define REG_15 (MAX_BPF_JIT_REG + 4) /* Register 15 */
|
||||
#define REG_0 REG_W0 /* Register 0 */
|
||||
#define REG_1 REG_W1 /* Register 1 */
|
||||
#define REG_2 BPF_REG_1 /* Register 2 */
|
||||
|
@ -88,6 +89,8 @@ static const int reg2hex[] = {
|
|||
[BPF_REG_9] = 10,
|
||||
/* BPF stack pointer */
|
||||
[BPF_REG_FP] = 13,
|
||||
/* Register for blinding (shared with REG_SKB_DATA) */
|
||||
[BPF_REG_AX] = 12,
|
||||
/* SKB data pointer */
|
||||
[REG_SKB_DATA] = 12,
|
||||
/* Work registers for s390x backend */
|
||||
|
@ -385,7 +388,7 @@ static void save_restore_regs(struct bpf_jit *jit, int op)
|
|||
/*
|
||||
* For SKB access %b1 contains the SKB pointer. For "bpf_jit.S"
|
||||
* we store the SKB header length on the stack and the SKB data
|
||||
* pointer in REG_SKB_DATA.
|
||||
* pointer in REG_SKB_DATA if BPF_REG_AX is not used.
|
||||
*/
|
||||
static void emit_load_skb_data_hlen(struct bpf_jit *jit)
|
||||
{
|
||||
|
@ -397,9 +400,10 @@ static void emit_load_skb_data_hlen(struct bpf_jit *jit)
|
|||
offsetof(struct sk_buff, data_len));
|
||||
/* stg %w1,ST_OFF_HLEN(%r0,%r15) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15, STK_OFF_HLEN);
|
||||
/* lg %skb_data,data_off(%b1) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0,
|
||||
BPF_REG_1, offsetof(struct sk_buff, data));
|
||||
if (!(jit->seen & SEEN_REG_AX))
|
||||
/* lg %skb_data,data_off(%b1) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0,
|
||||
BPF_REG_1, offsetof(struct sk_buff, data));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -487,6 +491,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
|
|||
s32 imm = insn->imm;
|
||||
s16 off = insn->off;
|
||||
|
||||
if (dst_reg == BPF_REG_AX || src_reg == BPF_REG_AX)
|
||||
jit->seen |= SEEN_REG_AX;
|
||||
switch (insn->code) {
|
||||
/*
|
||||
* BPF_MOV
|
||||
|
@ -1188,7 +1194,7 @@ call_fn:
|
|||
/*
|
||||
* Implicit input:
|
||||
* BPF_REG_6 (R7) : skb pointer
|
||||
* REG_SKB_DATA (R12): skb data pointer
|
||||
* REG_SKB_DATA (R12): skb data pointer (if no BPF_REG_AX)
|
||||
*
|
||||
* Calculated input:
|
||||
* BPF_REG_2 (R3) : offset of byte(s) to fetch in skb
|
||||
|
@ -1209,6 +1215,11 @@ call_fn:
|
|||
/* agfr %b2,%src (%src is s32 here) */
|
||||
EMIT4(0xb9180000, BPF_REG_2, src_reg);
|
||||
|
||||
/* Reload REG_SKB_DATA if BPF_REG_AX is used */
|
||||
if (jit->seen & SEEN_REG_AX)
|
||||
/* lg %skb_data,data_off(%b6) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0,
|
||||
BPF_REG_6, offsetof(struct sk_buff, data));
|
||||
/* basr %b5,%w1 (%b5 is call saved) */
|
||||
EMIT2(0x0d00, BPF_REG_5, REG_W1);
|
||||
|
||||
|
@ -1262,37 +1273,62 @@ void bpf_jit_compile(struct bpf_prog *fp)
|
|||
/*
|
||||
* Compile eBPF program "fp"
|
||||
*/
|
||||
void bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
{
|
||||
struct bpf_prog *tmp, *orig_fp = fp;
|
||||
struct bpf_binary_header *header;
|
||||
bool tmp_blinded = false;
|
||||
struct bpf_jit jit;
|
||||
int pass;
|
||||
|
||||
if (!bpf_jit_enable)
|
||||
return;
|
||||
return orig_fp;
|
||||
|
||||
tmp = bpf_jit_blind_constants(fp);
|
||||
/*
|
||||
* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_fp;
|
||||
if (tmp != fp) {
|
||||
tmp_blinded = true;
|
||||
fp = tmp;
|
||||
}
|
||||
|
||||
memset(&jit, 0, sizeof(jit));
|
||||
jit.addrs = kcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
|
||||
if (jit.addrs == NULL)
|
||||
return;
|
||||
if (jit.addrs == NULL) {
|
||||
fp = orig_fp;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Three initial passes:
|
||||
* - 1/2: Determine clobbered registers
|
||||
* - 3: Calculate program size and addrs arrray
|
||||
*/
|
||||
for (pass = 1; pass <= 3; pass++) {
|
||||
if (bpf_jit_prog(&jit, fp))
|
||||
if (bpf_jit_prog(&jit, fp)) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Final pass: Allocate and generate program
|
||||
*/
|
||||
if (jit.size >= BPF_SIZE_MAX)
|
||||
if (jit.size >= BPF_SIZE_MAX) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
}
|
||||
header = bpf_jit_binary_alloc(jit.size, &jit.prg_buf, 2, jit_fill_hole);
|
||||
if (!header)
|
||||
if (!header) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
if (bpf_jit_prog(&jit, fp))
|
||||
}
|
||||
if (bpf_jit_prog(&jit, fp)) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
}
|
||||
if (bpf_jit_enable > 1) {
|
||||
bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf);
|
||||
if (jit.prg_buf)
|
||||
|
@ -1305,6 +1341,11 @@ void bpf_int_jit_compile(struct bpf_prog *fp)
|
|||
}
|
||||
free_addrs:
|
||||
kfree(jit.addrs);
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(fp, fp == orig_fp ?
|
||||
tmp : orig_fp);
|
||||
return fp;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -32,7 +32,7 @@ config SPARC
|
|||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select GENERIC_PCI_IOMAP
|
||||
select HAVE_NMI_WATCHDOG if SPARC64
|
||||
select HAVE_BPF_JIT
|
||||
select HAVE_CBPF_JIT
|
||||
select HAVE_DEBUG_BUGVERBOSE
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_CLOCKEVENTS
|
||||
|
|
|
@ -221,8 +221,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
|
|||
CONFIG_TUN=y
|
||||
CONFIG_VETH=m
|
||||
CONFIG_NET_DSA_MV88E6060=y
|
||||
CONFIG_NET_DSA_MV88E6131=y
|
||||
CONFIG_NET_DSA_MV88E6123=y
|
||||
CONFIG_NET_DSA_MV88E6XXX=y
|
||||
CONFIG_SKY2=y
|
||||
CONFIG_PTP_1588_CLOCK_TILEGX=y
|
||||
# CONFIG_WLAN is not set
|
||||
|
|
|
@ -340,8 +340,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
|
|||
CONFIG_TUN=y
|
||||
CONFIG_VETH=m
|
||||
CONFIG_NET_DSA_MV88E6060=y
|
||||
CONFIG_NET_DSA_MV88E6131=y
|
||||
CONFIG_NET_DSA_MV88E6123=y
|
||||
CONFIG_NET_DSA_MV88E6XXX=y
|
||||
# CONFIG_NET_VENDOR_3COM is not set
|
||||
CONFIG_E1000E=y
|
||||
# CONFIG_WLAN is not set
|
||||
|
|
|
@ -223,7 +223,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (len == skb->len) {
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
netif_start_queue(dev);
|
||||
|
||||
/* this is normally done in the interrupt when tx finishes */
|
||||
|
@ -252,7 +252,7 @@ static void uml_net_set_multicast_list(struct net_device *dev)
|
|||
|
||||
static void uml_net_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ config X86
|
|||
select HAVE_ARCH_SOFT_DIRTY if X86_64
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
select HAVE_BPF_JIT if X86_64
|
||||
select HAVE_EBPF_JIT if X86_64
|
||||
select HAVE_CC_STACKPROTECTOR
|
||||
select HAVE_CMPXCHG_DOUBLE
|
||||
select HAVE_CMPXCHG_LOCAL
|
||||
|
|
|
@ -110,11 +110,16 @@ static void bpf_flush_icache(void *start, void *end)
|
|||
((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
|
||||
|
||||
/* pick a register outside of BPF range for JIT internal work */
|
||||
#define AUX_REG (MAX_BPF_REG + 1)
|
||||
#define AUX_REG (MAX_BPF_JIT_REG + 1)
|
||||
|
||||
/* the following table maps BPF registers to x64 registers.
|
||||
* x64 register r12 is unused, since if used as base address register
|
||||
* in load/store instructions, it always needs an extra byte of encoding
|
||||
/* The following table maps BPF registers to x64 registers.
|
||||
*
|
||||
* x64 register r12 is unused, since if used as base address
|
||||
* register in load/store instructions, it always needs an
|
||||
* extra byte of encoding and is callee saved.
|
||||
*
|
||||
* r9 caches skb->len - skb->data_len
|
||||
* r10 caches skb->data, and used for blinding (if enabled)
|
||||
*/
|
||||
static const int reg2hex[] = {
|
||||
[BPF_REG_0] = 0, /* rax */
|
||||
|
@ -128,6 +133,7 @@ static const int reg2hex[] = {
|
|||
[BPF_REG_8] = 6, /* r14 callee saved */
|
||||
[BPF_REG_9] = 7, /* r15 callee saved */
|
||||
[BPF_REG_FP] = 5, /* rbp readonly */
|
||||
[BPF_REG_AX] = 2, /* r10 temp register */
|
||||
[AUX_REG] = 3, /* r11 temp register */
|
||||
};
|
||||
|
||||
|
@ -141,7 +147,8 @@ static bool is_ereg(u32 reg)
|
|||
BIT(AUX_REG) |
|
||||
BIT(BPF_REG_7) |
|
||||
BIT(BPF_REG_8) |
|
||||
BIT(BPF_REG_9));
|
||||
BIT(BPF_REG_9) |
|
||||
BIT(BPF_REG_AX));
|
||||
}
|
||||
|
||||
/* add modifiers if 'reg' maps to x64 registers r8..r15 */
|
||||
|
@ -182,6 +189,7 @@ static void jit_fill_hole(void *area, unsigned int size)
|
|||
struct jit_context {
|
||||
int cleanup_addr; /* epilogue code offset */
|
||||
bool seen_ld_abs;
|
||||
bool seen_ax_reg;
|
||||
};
|
||||
|
||||
/* maximum number of bytes emitted while JITing one eBPF insn */
|
||||
|
@ -345,6 +353,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
|||
struct bpf_insn *insn = bpf_prog->insnsi;
|
||||
int insn_cnt = bpf_prog->len;
|
||||
bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0);
|
||||
bool seen_ax_reg = ctx->seen_ax_reg | (oldproglen == 0);
|
||||
bool seen_exit = false;
|
||||
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
|
||||
int i, cnt = 0;
|
||||
|
@ -367,6 +376,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
|||
int ilen;
|
||||
u8 *func;
|
||||
|
||||
if (dst_reg == BPF_REG_AX || src_reg == BPF_REG_AX)
|
||||
ctx->seen_ax_reg = seen_ax_reg = true;
|
||||
|
||||
switch (insn->code) {
|
||||
/* ALU */
|
||||
case BPF_ALU | BPF_ADD | BPF_X:
|
||||
|
@ -1002,6 +1014,10 @@ common_load:
|
|||
* sk_load_* helpers also use %r10 and %r9d.
|
||||
* See bpf_jit.S
|
||||
*/
|
||||
if (seen_ax_reg)
|
||||
/* r10 = skb->data, mov %r10, off32(%rbx) */
|
||||
EMIT3_off32(0x4c, 0x8b, 0x93,
|
||||
offsetof(struct sk_buff, data));
|
||||
EMIT1_off32(0xE8, jmp_offset); /* call */
|
||||
break;
|
||||
|
||||
|
@ -1073,25 +1089,37 @@ void bpf_jit_compile(struct bpf_prog *prog)
|
|||
{
|
||||
}
|
||||
|
||||
void bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_binary_header *header = NULL;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
int proglen, oldproglen = 0;
|
||||
struct jit_context ctx = {};
|
||||
bool tmp_blinded = false;
|
||||
u8 *image = NULL;
|
||||
int *addrs;
|
||||
int pass;
|
||||
int i;
|
||||
|
||||
if (!bpf_jit_enable)
|
||||
return;
|
||||
return orig_prog;
|
||||
|
||||
if (!prog || !prog->len)
|
||||
return;
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
|
||||
addrs = kmalloc(prog->len * sizeof(*addrs), GFP_KERNEL);
|
||||
if (!addrs)
|
||||
return;
|
||||
if (!addrs) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Before first pass, make a rough estimation of addrs[]
|
||||
* each bpf instruction is translated to less than 64 bytes
|
||||
|
@ -1113,21 +1141,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
|
|||
image = NULL;
|
||||
if (header)
|
||||
bpf_jit_binary_free(header);
|
||||
goto out;
|
||||
prog = orig_prog;
|
||||
goto out_addrs;
|
||||
}
|
||||
if (image) {
|
||||
if (proglen != oldproglen) {
|
||||
pr_err("bpf_jit: proglen=%d != oldproglen=%d\n",
|
||||
proglen, oldproglen);
|
||||
goto out;
|
||||
prog = orig_prog;
|
||||
goto out_addrs;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (proglen == oldproglen) {
|
||||
header = bpf_jit_binary_alloc(proglen, &image,
|
||||
1, jit_fill_hole);
|
||||
if (!header)
|
||||
goto out;
|
||||
if (!header) {
|
||||
prog = orig_prog;
|
||||
goto out_addrs;
|
||||
}
|
||||
}
|
||||
oldproglen = proglen;
|
||||
}
|
||||
|
@ -1141,8 +1173,14 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
|
|||
prog->bpf_func = (void *)image;
|
||||
prog->jited = 1;
|
||||
}
|
||||
out:
|
||||
|
||||
out_addrs:
|
||||
kfree(addrs);
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
}
|
||||
|
||||
void bpf_jit_free(struct bpf_prog *fp)
|
||||
|
|
|
@ -428,7 +428,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (len == skb->len) {
|
||||
lp->stats.tx_packets++;
|
||||
lp->stats.tx_bytes += skb->len;
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
netif_start_queue(dev);
|
||||
|
||||
/* this is normally done in the interrupt when tx finishes */
|
||||
|
|
|
@ -3633,14 +3633,15 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
|
|||
goto nla_put_failure;
|
||||
if (nla_put_u32(skb, T_sib_reason, sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) ||
|
||||
nla_put_u32(skb, T_current_state, device->state.i) ||
|
||||
nla_put_u64(skb, T_ed_uuid, device->ed_uuid) ||
|
||||
nla_put_u64(skb, T_capacity, drbd_get_capacity(device->this_bdev)) ||
|
||||
nla_put_u64(skb, T_send_cnt, device->send_cnt) ||
|
||||
nla_put_u64(skb, T_recv_cnt, device->recv_cnt) ||
|
||||
nla_put_u64(skb, T_read_cnt, device->read_cnt) ||
|
||||
nla_put_u64(skb, T_writ_cnt, device->writ_cnt) ||
|
||||
nla_put_u64(skb, T_al_writ_cnt, device->al_writ_cnt) ||
|
||||
nla_put_u64(skb, T_bm_writ_cnt, device->bm_writ_cnt) ||
|
||||
nla_put_u64_0pad(skb, T_ed_uuid, device->ed_uuid) ||
|
||||
nla_put_u64_0pad(skb, T_capacity,
|
||||
drbd_get_capacity(device->this_bdev)) ||
|
||||
nla_put_u64_0pad(skb, T_send_cnt, device->send_cnt) ||
|
||||
nla_put_u64_0pad(skb, T_recv_cnt, device->recv_cnt) ||
|
||||
nla_put_u64_0pad(skb, T_read_cnt, device->read_cnt) ||
|
||||
nla_put_u64_0pad(skb, T_writ_cnt, device->writ_cnt) ||
|
||||
nla_put_u64_0pad(skb, T_al_writ_cnt, device->al_writ_cnt) ||
|
||||
nla_put_u64_0pad(skb, T_bm_writ_cnt, device->bm_writ_cnt) ||
|
||||
nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&device->ap_bio_cnt)) ||
|
||||
nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&device->ap_pending_cnt)) ||
|
||||
nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&device->rs_pending_cnt)))
|
||||
|
@ -3657,13 +3658,16 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
|
|||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u32(skb, T_disk_flags, device->ldev->md.flags) ||
|
||||
nla_put_u64(skb, T_bits_total, drbd_bm_bits(device)) ||
|
||||
nla_put_u64(skb, T_bits_oos, drbd_bm_total_weight(device)))
|
||||
nla_put_u64_0pad(skb, T_bits_total, drbd_bm_bits(device)) ||
|
||||
nla_put_u64_0pad(skb, T_bits_oos,
|
||||
drbd_bm_total_weight(device)))
|
||||
goto nla_put_failure;
|
||||
if (C_SYNC_SOURCE <= device->state.conn &&
|
||||
C_PAUSED_SYNC_T >= device->state.conn) {
|
||||
if (nla_put_u64(skb, T_bits_rs_total, device->rs_total) ||
|
||||
nla_put_u64(skb, T_bits_rs_failed, device->rs_failed))
|
||||
if (nla_put_u64_0pad(skb, T_bits_rs_total,
|
||||
device->rs_total) ||
|
||||
nla_put_u64_0pad(skb, T_bits_rs_failed,
|
||||
device->rs_failed))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,7 @@ static const struct usb_device_id ath3k_table[] = {
|
|||
{ USB_DEVICE(0x13d3, 0x3432) },
|
||||
{ USB_DEVICE(0x13d3, 0x3472) },
|
||||
{ USB_DEVICE(0x13d3, 0x3474) },
|
||||
{ USB_DEVICE(0x13d3, 0x3487) },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE02C) },
|
||||
|
@ -188,6 +189,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
|
|||
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU22 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
|
||||
|
@ -206,7 +208,8 @@ static int ath3k_load_firmware(struct usb_device *udev,
|
|||
const struct firmware *firmware)
|
||||
{
|
||||
u8 *send_buf;
|
||||
int err, pipe, len, size, sent = 0;
|
||||
int len = 0;
|
||||
int err, pipe, size, sent = 0;
|
||||
int count = firmware->size;
|
||||
|
||||
BT_DBG("udev %p", udev);
|
||||
|
@ -302,7 +305,8 @@ static int ath3k_load_fwfile(struct usb_device *udev,
|
|||
const struct firmware *firmware)
|
||||
{
|
||||
u8 *send_buf;
|
||||
int err, pipe, len, size, count, sent = 0;
|
||||
int len = 0;
|
||||
int err, pipe, size, count, sent = 0;
|
||||
int ret;
|
||||
|
||||
count = firmware->size;
|
||||
|
|
|
@ -23,6 +23,17 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#define BTM_HEADER_LEN 4
|
||||
#define BTM_UPLD_SIZE 2312
|
||||
|
|
|
@ -510,34 +510,39 @@ static int btmrvl_download_cal_data(struct btmrvl_private *priv,
|
|||
static int btmrvl_check_device_tree(struct btmrvl_private *priv)
|
||||
{
|
||||
struct device_node *dt_node;
|
||||
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
|
||||
u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE];
|
||||
int ret;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
u16 gpio, gap;
|
||||
|
||||
for_each_compatible_node(dt_node, NULL, "btmrvl,cfgdata") {
|
||||
ret = of_property_read_u32(dt_node, "btmrvl,gpio-gap", &val);
|
||||
if (!ret)
|
||||
priv->btmrvl_dev.gpio_gap = val;
|
||||
if (card->plt_of_node) {
|
||||
dt_node = card->plt_of_node;
|
||||
ret = of_property_read_u16(dt_node, "marvell,wakeup-pin",
|
||||
&gpio);
|
||||
if (ret)
|
||||
gpio = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
|
||||
|
||||
ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data",
|
||||
ret = of_property_read_u16(dt_node, "marvell,wakeup-gap-ms",
|
||||
&gap);
|
||||
if (ret)
|
||||
gap = (u8)(priv->btmrvl_dev.gpio_gap & 0x00ff);
|
||||
|
||||
priv->btmrvl_dev.gpio_gap = (gpio << 8) + gap;
|
||||
|
||||
ret = of_property_read_u8_array(dt_node, "marvell,cal-data",
|
||||
cal_data + BT_CAL_HDR_LEN,
|
||||
BT_CAL_DATA_SIZE);
|
||||
if (ret) {
|
||||
of_node_put(dt_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BT_DBG("Use cal data from device tree");
|
||||
ret = btmrvl_download_cal_data(priv, cal_data,
|
||||
BT_CAL_DATA_SIZE);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
BT_ERR("Fail to download calibrate data");
|
||||
of_node_put(dt_node);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btmrvl_setup(struct hci_dev *hdev)
|
||||
|
|
|
@ -52,6 +52,68 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = {
|
|||
{"EXTLAST", NULL, 0, 0xFE},
|
||||
};
|
||||
|
||||
static const struct of_device_id btmrvl_sdio_of_match_table[] = {
|
||||
{ .compatible = "marvell,sd8897-bt" },
|
||||
{ .compatible = "marvell,sd8997-bt" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
|
||||
{
|
||||
struct btmrvl_plt_wake_cfg *cfg = priv;
|
||||
|
||||
if (cfg->irq_bt >= 0) {
|
||||
pr_info("%s: wake by bt", __func__);
|
||||
cfg->wake_by_bt = true;
|
||||
disable_irq_nosync(irq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* This function parses device tree node using mmc subnode devicetree API.
|
||||
* The device node is saved in card->plt_of_node.
|
||||
* If the device tree node exists and includes interrupts attributes, this
|
||||
* function will request platform specific wakeup interrupt.
|
||||
*/
|
||||
static int btmrvl_sdio_probe_of(struct device *dev,
|
||||
struct btmrvl_sdio_card *card)
|
||||
{
|
||||
struct btmrvl_plt_wake_cfg *cfg;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node ||
|
||||
!of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
|
||||
pr_err("sdio platform data not available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
card->plt_of_node = dev->of_node;
|
||||
|
||||
card->plt_wake_cfg = devm_kzalloc(dev, sizeof(*card->plt_wake_cfg),
|
||||
GFP_KERNEL);
|
||||
cfg = card->plt_wake_cfg;
|
||||
if (cfg && card->plt_of_node) {
|
||||
cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0);
|
||||
if (!cfg->irq_bt) {
|
||||
dev_err(dev, "fail to parse irq_bt from device tree");
|
||||
} else {
|
||||
ret = devm_request_irq(dev, cfg->irq_bt,
|
||||
btmrvl_wake_irq_bt,
|
||||
IRQF_TRIGGER_LOW,
|
||||
"bt_wake", cfg);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to request irq_bt %d (%d)\n",
|
||||
cfg->irq_bt, ret);
|
||||
}
|
||||
disable_irq(cfg->irq_bt);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The btmrvl_sdio_remove() callback function is called
|
||||
* when user removes this module from kernel space or ejects
|
||||
* the card from the slot. The driver handles these 2 cases
|
||||
|
@ -1464,6 +1526,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
|
|||
|
||||
btmrvl_sdio_enable_host_int(card);
|
||||
|
||||
/* Device tree node parsing and platform specific configuration*/
|
||||
btmrvl_sdio_probe_of(&func->dev, card);
|
||||
|
||||
priv = btmrvl_add_card(card);
|
||||
if (!priv) {
|
||||
BT_ERR("Initializing card failed!");
|
||||
|
@ -1544,6 +1609,13 @@ static int btmrvl_sdio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Enable platform specific wakeup interrupt */
|
||||
if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) {
|
||||
card->plt_wake_cfg->wake_by_bt = false;
|
||||
enable_irq(card->plt_wake_cfg->irq_bt);
|
||||
enable_irq_wake(card->plt_wake_cfg->irq_bt);
|
||||
}
|
||||
|
||||
priv = card->priv;
|
||||
priv->adapter->is_suspending = true;
|
||||
hcidev = priv->btmrvl_dev.hcidev;
|
||||
|
@ -1606,6 +1678,13 @@ static int btmrvl_sdio_resume(struct device *dev)
|
|||
BT_DBG("%s: SDIO resume", hcidev->name);
|
||||
hci_resume_dev(hcidev);
|
||||
|
||||
/* Disable platform specific wakeup interrupt */
|
||||
if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) {
|
||||
disable_irq_wake(card->plt_wake_cfg->irq_bt);
|
||||
if (!card->plt_wake_cfg->wake_by_bt)
|
||||
disable_irq(card->plt_wake_cfg->irq_bt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,10 @@
|
|||
|
||||
#define FIRMWARE_READY 0xfedc
|
||||
|
||||
struct btmrvl_plt_wake_cfg {
|
||||
int irq_bt;
|
||||
bool wake_by_bt;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_card_reg {
|
||||
u8 cfg;
|
||||
|
@ -97,6 +101,8 @@ struct btmrvl_sdio_card {
|
|||
u16 sd_blksz_fw_dl;
|
||||
u8 rx_unit;
|
||||
struct btmrvl_private *priv;
|
||||
struct device_node *plt_of_node;
|
||||
struct btmrvl_plt_wake_cfg *plt_wake_cfg;
|
||||
};
|
||||
|
||||
struct btmrvl_sdio_device {
|
||||
|
|
|
@ -236,6 +236,7 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
||||
|
@ -2001,12 +2002,13 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
|
||||
* supported by this firmware loading method. This check has been
|
||||
* put in place to ensure correct forward compatibility options
|
||||
* when newer hardware variants come along.
|
||||
/* At the moment the iBT 3.0 hardware variants 0x0b (LnP/SfP)
|
||||
* and 0x0c (WsP) are supported by this firmware loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
if (ver.hw_variant != 0x0b) {
|
||||
if (ver.hw_variant != 0x0b && ver.hw_variant != 0x0c) {
|
||||
BT_ERR("%s: Unsupported Intel hardware variant (%u)",
|
||||
hdev->name, ver.hw_variant);
|
||||
return -EINVAL;
|
||||
|
|
|
@ -825,6 +825,7 @@ static const struct acpi_device_id bcm_acpi_match[] = {
|
|||
{ "BCM2E64", 0 },
|
||||
{ "BCM2E65", 0 },
|
||||
{ "BCM2E67", 0 },
|
||||
{ "BCM2E71", 0 },
|
||||
{ "BCM2E7B", 0 },
|
||||
{ "BCM2E7C", 0 },
|
||||
{ },
|
||||
|
|
|
@ -102,13 +102,12 @@ static const u16 crc_table[] = {
|
|||
/* Initialise the crc calculator */
|
||||
#define BCSP_CRC_INIT(x) x = 0xffff
|
||||
|
||||
/*
|
||||
Update crc with next data byte
|
||||
|
||||
Implementation note
|
||||
The data byte is treated as two nibbles. The crc is generated
|
||||
in reverse, i.e., bits are fed into the register from the top.
|
||||
*/
|
||||
/* Update crc with next data byte
|
||||
*
|
||||
* Implementation note
|
||||
* The data byte is treated as two nibbles. The crc is generated
|
||||
* in reverse, i.e., bits are fed into the register from the top.
|
||||
*/
|
||||
static void bcsp_crc_update(u16 *crc, u8 d)
|
||||
{
|
||||
u16 reg = *crc;
|
||||
|
@ -223,9 +222,10 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
|
|||
}
|
||||
|
||||
/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
|
||||
(because bytes 0xc0 and 0xdb are escaped, worst case is
|
||||
when the packet is all made of 0xc0 and 0xdb :) )
|
||||
+ 2 (0xc0 delimiters at start and end). */
|
||||
* (because bytes 0xc0 and 0xdb are escaped, worst case is
|
||||
* when the packet is all made of 0xc0 and 0xdb :) )
|
||||
* + 2 (0xc0 delimiters at start and end).
|
||||
*/
|
||||
|
||||
nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
|
@ -285,7 +285,7 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
|
|||
struct bcsp_struct *bcsp = hu->priv;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb;
|
||||
|
||||
|
||||
/* First of all, check for unreliable messages in the queue,
|
||||
since they have priority */
|
||||
|
||||
|
@ -305,8 +305,9 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
|
|||
}
|
||||
|
||||
/* Now, try to send a reliable pkt. We can only send a
|
||||
reliable packet if the number of packets sent but not yet ack'ed
|
||||
is < than the winsize */
|
||||
* reliable packet if the number of packets sent but not yet ack'ed
|
||||
* is < than the winsize
|
||||
*/
|
||||
|
||||
spin_lock_irqsave_nested(&bcsp->unack.lock, flags, SINGLE_DEPTH_NESTING);
|
||||
|
||||
|
@ -332,12 +333,14 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
|
|||
spin_unlock_irqrestore(&bcsp->unack.lock, flags);
|
||||
|
||||
/* We could not send a reliable packet, either because there are
|
||||
none or because there are too many unack'ed pkts. Did we receive
|
||||
any packets we have not acknowledged yet ? */
|
||||
* none or because there are too many unack'ed pkts. Did we receive
|
||||
* any packets we have not acknowledged yet ?
|
||||
*/
|
||||
|
||||
if (bcsp->txack_req) {
|
||||
/* if so, craft an empty ACK pkt and send it on BCSP unreliable
|
||||
channel 0 */
|
||||
* channel 0
|
||||
*/
|
||||
struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
|
||||
return nskb;
|
||||
}
|
||||
|
@ -399,8 +402,9 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
|
|||
}
|
||||
|
||||
/* Handle BCSP link-establishment packets. When we
|
||||
detect a "sync" packet, symptom that the BT module has reset,
|
||||
we do nothing :) (yet) */
|
||||
* detect a "sync" packet, symptom that the BT module has reset,
|
||||
* we do nothing :) (yet)
|
||||
*/
|
||||
static void bcsp_handle_le_pkt(struct hci_uart *hu)
|
||||
{
|
||||
struct bcsp_struct *bcsp = hu->priv;
|
||||
|
@ -462,7 +466,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
|
|||
case 0xdd:
|
||||
memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
|
||||
if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
|
||||
bcsp->rx_state != BCSP_W4_CRC)
|
||||
bcsp->rx_state != BCSP_W4_CRC)
|
||||
bcsp_crc_update(&bcsp->message_crc, 0xdb);
|
||||
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
|
||||
bcsp->rx_count--;
|
||||
|
@ -534,7 +538,7 @@ static void bcsp_complete_rx_pkt(struct hci_uart *hu)
|
|||
} else {
|
||||
BT_ERR("Packet for unknown channel (%u %s)",
|
||||
bcsp->rx_skb->data[1] & 0x0f,
|
||||
bcsp->rx_skb->data[0] & 0x80 ?
|
||||
bcsp->rx_skb->data[0] & 0x80 ?
|
||||
"reliable" : "unreliable");
|
||||
kfree_skb(bcsp->rx_skb);
|
||||
}
|
||||
|
@ -562,7 +566,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
|||
struct bcsp_struct *bcsp = hu->priv;
|
||||
const unsigned char *ptr;
|
||||
|
||||
BT_DBG("hu %p count %d rx_state %d rx_count %ld",
|
||||
BT_DBG("hu %p count %d rx_state %d rx_count %ld",
|
||||
hu, count, bcsp->rx_state, bcsp->rx_count);
|
||||
|
||||
ptr = data;
|
||||
|
@ -591,7 +595,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
|||
continue;
|
||||
}
|
||||
if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */
|
||||
&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
|
||||
&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
|
||||
BT_ERR("Out-of-order packet arrived, got %u expected %u",
|
||||
bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
|
||||
|
||||
|
@ -601,7 +605,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
|||
continue;
|
||||
}
|
||||
bcsp->rx_state = BCSP_W4_DATA;
|
||||
bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) +
|
||||
bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) +
|
||||
(bcsp->rx_skb->data[2] << 4); /* May be 0 */
|
||||
continue;
|
||||
|
||||
|
@ -615,7 +619,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
|||
|
||||
case BCSP_W4_CRC:
|
||||
if (bitrev16(bcsp->message_crc) != bscp_get_crc(bcsp)) {
|
||||
BT_ERR ("Checksum failed: computed %04x received %04x",
|
||||
BT_ERR("Checksum failed: computed %04x received %04x",
|
||||
bitrev16(bcsp->message_crc),
|
||||
bscp_get_crc(bcsp));
|
||||
|
||||
|
@ -653,8 +657,9 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
|
|||
BCSP_CRC_INIT(bcsp->message_crc);
|
||||
|
||||
/* Do not increment ptr or decrement count
|
||||
* Allocate packet. Max len of a BCSP pkt=
|
||||
* 0xFFF (payload) +4 (header) +2 (crc) */
|
||||
* Allocate packet. Max len of a BCSP pkt=
|
||||
* 0xFFF (payload) +4 (header) +2 (crc)
|
||||
*/
|
||||
|
||||
bcsp->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC);
|
||||
if (!bcsp->rx_skb) {
|
||||
|
|
|
@ -1210,8 +1210,7 @@ static int intel_probe(struct platform_device *pdev)
|
|||
|
||||
idev->pdev = pdev;
|
||||
|
||||
idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
idev->reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(idev->reset)) {
|
||||
dev_err(&pdev->dev, "Unable to retrieve gpio\n");
|
||||
return PTR_ERR(idev->reset);
|
||||
|
@ -1223,8 +1222,7 @@ static int intel_probe(struct platform_device *pdev)
|
|||
|
||||
dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
|
||||
|
||||
host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
|
||||
GPIOD_IN);
|
||||
host_wake = devm_gpiod_get(&pdev->dev, "host-wake", GPIOD_IN);
|
||||
if (IS_ERR(host_wake)) {
|
||||
dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
|
||||
goto no_irq;
|
||||
|
|
|
@ -227,7 +227,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
|
|||
tty_ldisc_flush(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
|
||||
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
hu->proto->flush(hu);
|
||||
|
||||
return 0;
|
||||
|
@ -492,7 +492,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
|||
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
|
||||
if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) {
|
||||
if (hdev) {
|
||||
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||
hci_unregister_dev(hdev);
|
||||
|
@ -500,6 +500,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
|||
}
|
||||
hu->proto->close(hu);
|
||||
}
|
||||
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
|
||||
|
||||
kfree(hu);
|
||||
}
|
||||
|
@ -526,7 +527,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
|
|||
if (tty != hu->tty)
|
||||
return;
|
||||
|
||||
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
|
||||
|
@ -550,7 +551,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
|
|||
if (!hu || tty != hu->tty)
|
||||
return;
|
||||
|
||||
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
|
||||
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
return;
|
||||
|
||||
/* It does not need a lock here as it is already protected by a mutex in
|
||||
|
@ -638,9 +639,11 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
|
|||
return err;
|
||||
|
||||
hu->proto = p;
|
||||
set_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
|
||||
err = hci_uart_register_dev(hu);
|
||||
if (err) {
|
||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
p->close(hu);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ struct hci_uart {
|
|||
/* HCI_UART proto flag bits */
|
||||
#define HCI_UART_PROTO_SET 0
|
||||
#define HCI_UART_REGISTERED 1
|
||||
#define HCI_UART_PROTO_READY 2
|
||||
|
||||
/* TX states */
|
||||
#define HCI_UART_SENDING 1
|
||||
|
|
|
@ -50,6 +50,7 @@ struct vhci_data {
|
|||
wait_queue_head_t read_wait;
|
||||
struct sk_buff_head readq;
|
||||
|
||||
struct mutex open_mutex;
|
||||
struct delayed_work open_timeout;
|
||||
};
|
||||
|
||||
|
@ -87,12 +88,15 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct sk_buff *skb;
|
||||
__u8 dev_type;
|
||||
|
||||
if (data->hdev)
|
||||
return -EBADFD;
|
||||
|
||||
/* bits 0-1 are dev_type (BR/EDR or AMP) */
|
||||
dev_type = opcode & 0x03;
|
||||
|
||||
|
@ -151,6 +155,17 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->open_mutex);
|
||||
err = __vhci_create_device(data, opcode);
|
||||
mutex_unlock(&data->open_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||
struct iov_iter *from)
|
||||
{
|
||||
|
@ -189,11 +204,6 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
|
|||
break;
|
||||
|
||||
case HCI_VENDOR_PKT:
|
||||
if (data->hdev) {
|
||||
kfree_skb(skb);
|
||||
return -EBADFD;
|
||||
}
|
||||
|
||||
cancel_delayed_work_sync(&data->open_timeout);
|
||||
|
||||
opcode = *((__u8 *) skb->data);
|
||||
|
@ -320,6 +330,7 @@ static int vhci_open(struct inode *inode, struct file *file)
|
|||
skb_queue_head_init(&data->readq);
|
||||
init_waitqueue_head(&data->read_wait);
|
||||
|
||||
mutex_init(&data->open_mutex);
|
||||
INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
|
||||
|
||||
file->private_data = data;
|
||||
|
@ -333,15 +344,18 @@ static int vhci_open(struct inode *inode, struct file *file)
|
|||
static int vhci_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct vhci_data *data = file->private_data;
|
||||
struct hci_dev *hdev = data->hdev;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
cancel_delayed_work_sync(&data->open_timeout);
|
||||
|
||||
hdev = data->hdev;
|
||||
|
||||
if (hdev) {
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
skb_queue_purge(&data->readq);
|
||||
file->private_data = NULL;
|
||||
kfree(data);
|
||||
|
||||
|
|
|
@ -3969,7 +3969,7 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
|
|||
dev_kfree_skb(skb);
|
||||
|
||||
/* save start time for transmit timeout detection */
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
|
||||
/* start hardware transmitter if necessary */
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
|
@ -4032,7 +4032,7 @@ static int hdlcdev_open(struct net_device *dev)
|
|||
tty_kref_put(tty);
|
||||
|
||||
/* enable network layer transmit */
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
netif_start_queue(dev);
|
||||
|
||||
/* inform generic HDLC layer of current DCD status */
|
||||
|
|
|
@ -1023,7 +1023,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
|
|||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
dev->netdev->trans_start = jiffies;
|
||||
netif_trans_update(dev->netdev);
|
||||
out:
|
||||
if (free)
|
||||
fwnet_free_ptask(ptask);
|
||||
|
|
|
@ -1863,7 +1863,7 @@ static enum i40iw_status_code i40iw_virtchnl_send(struct i40iw_sc_dev *dev,
|
|||
}
|
||||
|
||||
/* client interface functions */
|
||||
static struct i40e_client_ops i40e_ops = {
|
||||
static const struct i40e_client_ops i40e_ops = {
|
||||
.open = i40iw_open,
|
||||
.close = i40iw_close,
|
||||
.l2_param_change = i40iw_l2param_change,
|
||||
|
|
|
@ -419,7 +419,8 @@ static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
|
|||
}
|
||||
|
||||
static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
|
||||
enum mlx4_ib_qp_type type, struct mlx4_ib_qp *qp)
|
||||
enum mlx4_ib_qp_type type, struct mlx4_ib_qp *qp,
|
||||
bool shrink_wqe)
|
||||
{
|
||||
int s;
|
||||
|
||||
|
@ -477,7 +478,7 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
|
|||
* We set WQE size to at least 64 bytes, this way stamping
|
||||
* invalidates each WQE.
|
||||
*/
|
||||
if (dev->dev->caps.fw_ver >= MLX4_FW_VER_WQE_CTRL_NEC &&
|
||||
if (shrink_wqe && dev->dev->caps.fw_ver >= MLX4_FW_VER_WQE_CTRL_NEC &&
|
||||
qp->sq_signal_bits && BITS_PER_LONG == 64 &&
|
||||
type != MLX4_IB_QPT_SMI && type != MLX4_IB_QPT_GSI &&
|
||||
!(type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_PROXY_SMI |
|
||||
|
@ -642,6 +643,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
|
|||
{
|
||||
int qpn;
|
||||
int err;
|
||||
struct ib_qp_cap backup_cap;
|
||||
struct mlx4_ib_sqp *sqp;
|
||||
struct mlx4_ib_qp *qp;
|
||||
enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type;
|
||||
|
@ -775,7 +777,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
|
|||
goto err;
|
||||
}
|
||||
|
||||
err = set_kernel_sq_size(dev, &init_attr->cap, qp_type, qp);
|
||||
memcpy(&backup_cap, &init_attr->cap, sizeof(backup_cap));
|
||||
err = set_kernel_sq_size(dev, &init_attr->cap,
|
||||
qp_type, qp, true);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
|
@ -787,9 +791,20 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
|
|||
*qp->db.db = 0;
|
||||
}
|
||||
|
||||
if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf, gfp)) {
|
||||
err = -ENOMEM;
|
||||
goto err_db;
|
||||
if (mlx4_buf_alloc(dev->dev, qp->buf_size, qp->buf_size,
|
||||
&qp->buf, gfp)) {
|
||||
memcpy(&init_attr->cap, &backup_cap,
|
||||
sizeof(backup_cap));
|
||||
err = set_kernel_sq_size(dev, &init_attr->cap, qp_type,
|
||||
qp, false);
|
||||
if (err)
|
||||
goto err_db;
|
||||
|
||||
if (mlx4_buf_alloc(dev->dev, qp->buf_size,
|
||||
PAGE_SIZE * 2, &qp->buf, gfp)) {
|
||||
err = -ENOMEM;
|
||||
goto err_db;
|
||||
}
|
||||
}
|
||||
|
||||
err = mlx4_mtt_init(dev->dev, qp->buf.npages, qp->buf.page_shift,
|
||||
|
|
|
@ -1438,7 +1438,8 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
|
|||
if (!ft) {
|
||||
ft = mlx5_create_auto_grouped_flow_table(ns, priority,
|
||||
num_entries,
|
||||
num_groups);
|
||||
num_groups,
|
||||
0);
|
||||
|
||||
if (!IS_ERR(ft)) {
|
||||
prio->refcount = 0;
|
||||
|
|
|
@ -356,7 +356,7 @@ static int nes_netdev_stop(struct net_device *netdev)
|
|||
/**
|
||||
* nes_nic_send
|
||||
*/
|
||||
static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
|
||||
static bool nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
struct nes_vnic *nesvnic = netdev_priv(netdev);
|
||||
struct nes_device *nesdev = nesvnic->nesdev;
|
||||
|
@ -413,7 +413,7 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
|
|||
netdev->name, skb_shinfo(skb)->nr_frags + 2, skb_headlen(skb));
|
||||
kfree_skb(skb);
|
||||
nesvnic->tx_sw_dropped++;
|
||||
return NETDEV_TX_LOCKED;
|
||||
return false;
|
||||
}
|
||||
set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
|
||||
bus_address = pci_map_single(nesdev->pcidev, skb->data + NES_FIRST_FRAG_SIZE,
|
||||
|
@ -454,8 +454,7 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
|
|||
set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX, wqe_misc);
|
||||
nesnic->sq_head++;
|
||||
nesnic->sq_head &= nesnic->sq_size - 1;
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -479,7 +478,6 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|||
u32 tso_wqe_length;
|
||||
u32 curr_tcp_seq;
|
||||
u32 wqe_count=1;
|
||||
u32 send_rc;
|
||||
struct iphdr *iph;
|
||||
__le16 *wqe_fragment_length;
|
||||
u32 nr_frags;
|
||||
|
@ -670,13 +668,11 @@ tso_sq_no_longer_full:
|
|||
skb_linearize(skb);
|
||||
skb_set_transport_header(skb, hoffset);
|
||||
skb_set_network_header(skb, nhoffset);
|
||||
send_rc = nes_nic_send(skb, netdev);
|
||||
if (send_rc != NETDEV_TX_OK)
|
||||
if (!nes_nic_send(skb, netdev))
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
} else {
|
||||
send_rc = nes_nic_send(skb, netdev);
|
||||
if (send_rc != NETDEV_TX_OK)
|
||||
if (!nes_nic_send(skb, netdev))
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
@ -686,7 +682,7 @@ tso_sq_no_longer_full:
|
|||
nes_write32(nesdev->regs+NES_WQE_ALLOC,
|
||||
(wqe_count << 24) | (1 << 23) | nesvnic->nic.qp_id);
|
||||
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
|
@ -766,7 +766,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
|
|||
ipoib_dma_unmap_tx(priv, tx_req);
|
||||
dev_kfree_skb_any(skb);
|
||||
} else {
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
++tx->tx_head;
|
||||
|
||||
if (++priv->tx_outstanding == ipoib_sendq_size) {
|
||||
|
|
|
@ -637,7 +637,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
|
|||
if (netif_queue_stopped(dev))
|
||||
netif_wake_queue(dev);
|
||||
} else {
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
|
||||
address->last_send = priv->tx_head;
|
||||
++priv->tx_head;
|
||||
|
|
|
@ -1036,7 +1036,7 @@ static void ipoib_timeout(struct net_device *dev)
|
|||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
|
||||
ipoib_warn(priv, "transmit timeout: latency %d msecs\n",
|
||||
jiffies_to_msecs(jiffies - dev->trans_start));
|
||||
jiffies_to_msecs(jiffies - dev_trans_start(dev)));
|
||||
ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n",
|
||||
netif_queue_stopped(dev),
|
||||
priv->tx_head, priv->tx_tail);
|
||||
|
|
|
@ -1147,8 +1147,6 @@ static byte test_c_ind_mask_bit(PLCI *plci, word b)
|
|||
|
||||
static void dump_c_ind_mask(PLCI *plci)
|
||||
{
|
||||
static char hex_digit_table[0x10] =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
word i, j, k;
|
||||
dword d;
|
||||
char *p;
|
||||
|
@ -1165,7 +1163,7 @@ static void dump_c_ind_mask(PLCI *plci)
|
|||
d = plci->c_ind_mask_table[i + j];
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
*(--p) = hex_digit_table[d & 0xf];
|
||||
*(--p) = hex_asc_lo(d);
|
||||
d >>= 4;
|
||||
}
|
||||
}
|
||||
|
@ -10507,7 +10505,6 @@ static void mixer_set_bchannel_id(PLCI *plci, byte *chi)
|
|||
|
||||
static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
|
||||
{
|
||||
static char hex_digit_table[0x10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
word n, i, j;
|
||||
char *p;
|
||||
char hex_line[2 * MIXER_MAX_DUMP_CHANNELS + MIXER_MAX_DUMP_CHANNELS / 8 + 4];
|
||||
|
@ -10690,13 +10687,13 @@ static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
|
|||
n = li_total_channels;
|
||||
if (n > MIXER_MAX_DUMP_CHANNELS)
|
||||
n = MIXER_MAX_DUMP_CHANNELS;
|
||||
|
||||
p = hex_line;
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
if ((j & 0x7) == 0)
|
||||
*(p++) = ' ';
|
||||
*(p++) = hex_digit_table[li_config_table[j].curchnl >> 4];
|
||||
*(p++) = hex_digit_table[li_config_table[j].curchnl & 0xf];
|
||||
p = hex_byte_pack(p, li_config_table[j].curchnl);
|
||||
}
|
||||
*p = '\0';
|
||||
dbug(1, dprintf("[%06lx] CURRENT %s",
|
||||
|
@ -10706,8 +10703,7 @@ static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
|
|||
{
|
||||
if ((j & 0x7) == 0)
|
||||
*(p++) = ' ';
|
||||
*(p++) = hex_digit_table[li_config_table[j].channel >> 4];
|
||||
*(p++) = hex_digit_table[li_config_table[j].channel & 0xf];
|
||||
p = hex_byte_pack(p, li_config_table[j].channel);
|
||||
}
|
||||
*p = '\0';
|
||||
dbug(1, dprintf("[%06lx] CHANNEL %s",
|
||||
|
@ -10717,8 +10713,7 @@ static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
|
|||
{
|
||||
if ((j & 0x7) == 0)
|
||||
*(p++) = ' ';
|
||||
*(p++) = hex_digit_table[li_config_table[j].chflags >> 4];
|
||||
*(p++) = hex_digit_table[li_config_table[j].chflags & 0xf];
|
||||
p = hex_byte_pack(p, li_config_table[j].chflags);
|
||||
}
|
||||
*p = '\0';
|
||||
dbug(1, dprintf("[%06lx] CHFLAG %s",
|
||||
|
@ -10730,8 +10725,7 @@ static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
|
|||
{
|
||||
if ((j & 0x7) == 0)
|
||||
*(p++) = ' ';
|
||||
*(p++) = hex_digit_table[li_config_table[i].flag_table[j] >> 4];
|
||||
*(p++) = hex_digit_table[li_config_table[i].flag_table[j] & 0xf];
|
||||
p = hex_byte_pack(p, li_config_table[i].flag_table[j]);
|
||||
}
|
||||
*p = '\0';
|
||||
dbug(1, dprintf("[%06lx] FLAG[%02x]%s",
|
||||
|
@ -10744,8 +10738,7 @@ static void mixer_calculate_coefs(DIVA_CAPI_ADAPTER *a)
|
|||
{
|
||||
if ((j & 0x7) == 0)
|
||||
*(p++) = ' ';
|
||||
*(p++) = hex_digit_table[li_config_table[i].coef_table[j] >> 4];
|
||||
*(p++) = hex_digit_table[li_config_table[i].coef_table[j] & 0xf];
|
||||
p = hex_byte_pack(p, li_config_table[i].coef_table[j]);
|
||||
}
|
||||
*p = '\0';
|
||||
dbug(1, dprintf("[%06lx] COEF[%02x]%s",
|
||||
|
|
|
@ -127,7 +127,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
|
|||
if (lp->in_idx >= MAX_SKB_BUFFERS)
|
||||
lp->in_idx = 0; /* wrap around */
|
||||
lp->sk_count++; /* adjust counter */
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
|
||||
/* If we just used up the very last entry in the
|
||||
* TX ring on this device, tell the queueing
|
||||
|
|
|
@ -1153,7 +1153,7 @@ static void isdn_net_tx_timeout(struct net_device *ndev)
|
|||
* ever called --KG
|
||||
*/
|
||||
}
|
||||
ndev->trans_start = jiffies;
|
||||
netif_trans_update(ndev);
|
||||
netif_wake_queue(ndev);
|
||||
}
|
||||
|
||||
|
@ -1291,7 +1291,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
} else {
|
||||
/* Device is connected to an ISDN channel */
|
||||
ndev->trans_start = jiffies;
|
||||
netif_trans_update(ndev);
|
||||
if (!lp->dialstate) {
|
||||
/* ISDN connection is established, try sending */
|
||||
int ret;
|
||||
|
|
|
@ -278,7 +278,7 @@ static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
|
|||
case X25_IFACE_DATA:
|
||||
if (*state == WAN_CONNECTED) {
|
||||
skb_pull(skb, 1);
|
||||
cprot->net_dev->trans_start = jiffies;
|
||||
netif_trans_update(cprot->net_dev);
|
||||
ret = (cprot->dops->data_req(cprot, skb));
|
||||
/* prepare for future retransmissions */
|
||||
if (ret) skb_push(skb, 1);
|
||||
|
|
|
@ -791,7 +791,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
|
|||
pSimple->Address.High = 0;
|
||||
|
||||
mpt_put_msg_frame (LanCtx, mpt_dev, mf);
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
|
||||
dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
|
||||
IOC_AND_NETDEV_NAMES_s_s(dev),
|
||||
|
|
|
@ -192,6 +192,23 @@ config GENEVE
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called geneve.
|
||||
|
||||
config GTP
|
||||
tristate "GPRS Tunneling Protocol datapath (GTP-U)"
|
||||
depends on INET && NET_UDP_TUNNEL
|
||||
select NET_IP_TUNNEL
|
||||
---help---
|
||||
This allows one to create gtp virtual interfaces that provide
|
||||
the GPRS Tunneling Protocol datapath (GTP-U). This tunneling protocol
|
||||
is used to prevent subscribers from accessing mobile carrier core
|
||||
network infrastructure. This driver requires a userspace software that
|
||||
implements the signaling protocol (GTP-C) to update its PDP context
|
||||
base, such as OpenGGSN <http://git.osmocom.org/openggsn/). This
|
||||
tunneling protocol is implemented according to the GSM TS 09.60 and
|
||||
3GPP TS 29.060 standards.
|
||||
|
||||
To compile this drivers as a module, choose M here: the module
|
||||
wil be called gtp.
|
||||
|
||||
config MACSEC
|
||||
tristate "IEEE 802.1AE MAC-level encryption (MACsec)"
|
||||
select CRYPTO
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_VETH) += veth.o
|
|||
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
|
||||
obj-$(CONFIG_VXLAN) += vxlan.o
|
||||
obj-$(CONFIG_GENEVE) += geneve.o
|
||||
obj-$(CONFIG_GTP) += gtp.o
|
||||
obj-$(CONFIG_NLMON) += nlmon.o
|
||||
obj-$(CONFIG_NET_VRF) += vrf.o
|
||||
|
||||
|
|
|
@ -861,7 +861,7 @@ static void cops_timeout(struct net_device *dev)
|
|||
}
|
||||
printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
|
||||
cops_jumpstart(dev); /* Restart the card. */
|
||||
dev->trans_start = jiffies; /* prevent tx timeout */
|
||||
netif_trans_update(dev); /* prevent tx timeout */
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -433,7 +433,7 @@ static void __init com90xx_probe(void)
|
|||
kfree(iomem);
|
||||
}
|
||||
|
||||
static int check_mirror(unsigned long addr, size_t size)
|
||||
static int __init check_mirror(unsigned long addr, size_t size)
|
||||
{
|
||||
void __iomem *p;
|
||||
int res = -1;
|
||||
|
|
|
@ -696,11 +696,17 @@ int can_change_mtu(struct net_device *dev, int new_mtu)
|
|||
/* allow change of MTU according to the CANFD ability of the device */
|
||||
switch (new_mtu) {
|
||||
case CAN_MTU:
|
||||
/* 'CANFD-only' controllers can not switch to CAN_MTU */
|
||||
if (priv->ctrlmode_static & CAN_CTRLMODE_FD)
|
||||
return -EINVAL;
|
||||
|
||||
priv->ctrlmode &= ~CAN_CTRLMODE_FD;
|
||||
break;
|
||||
|
||||
case CANFD_MTU:
|
||||
if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
|
||||
/* check for potential CANFD ability */
|
||||
if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) &&
|
||||
!(priv->ctrlmode_static & CAN_CTRLMODE_FD))
|
||||
return -EINVAL;
|
||||
|
||||
priv->ctrlmode |= CAN_CTRLMODE_FD;
|
||||
|
@ -782,6 +788,35 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
|
|||
= { .len = sizeof(struct can_bittiming_const) },
|
||||
};
|
||||
|
||||
static int can_validate(struct nlattr *tb[], struct nlattr *data[])
|
||||
{
|
||||
bool is_can_fd = false;
|
||||
|
||||
/* Make sure that valid CAN FD configurations always consist of
|
||||
* - nominal/arbitration bittiming
|
||||
* - data bittiming
|
||||
* - control mode with CAN_CTRLMODE_FD set
|
||||
*/
|
||||
|
||||
if (data[IFLA_CAN_CTRLMODE]) {
|
||||
struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
||||
|
||||
is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
|
||||
}
|
||||
|
||||
if (is_can_fd) {
|
||||
if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_DATA_BITTIMING]) {
|
||||
if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int can_changelink(struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[])
|
||||
{
|
||||
|
@ -813,19 +848,31 @@ static int can_changelink(struct net_device *dev,
|
|||
|
||||
if (data[IFLA_CAN_CTRLMODE]) {
|
||||
struct can_ctrlmode *cm;
|
||||
u32 ctrlstatic;
|
||||
u32 maskedflags;
|
||||
|
||||
/* Do not allow changing controller mode while running */
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
||||
ctrlstatic = priv->ctrlmode_static;
|
||||
maskedflags = cm->flags & cm->mask;
|
||||
|
||||
/* check whether changed bits are allowed to be modified */
|
||||
if (cm->mask & ~priv->ctrlmode_supported)
|
||||
/* check whether provided bits are allowed to be passed */
|
||||
if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* do not check for static fd-non-iso if 'fd' is disabled */
|
||||
if (!(maskedflags & CAN_CTRLMODE_FD))
|
||||
ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
|
||||
|
||||
/* make sure static options are provided by configuration */
|
||||
if ((maskedflags & ctrlstatic) != ctrlstatic)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* clear bits to be modified and copy the flag values */
|
||||
priv->ctrlmode &= ~cm->mask;
|
||||
priv->ctrlmode |= (cm->flags & cm->mask);
|
||||
priv->ctrlmode |= maskedflags;
|
||||
|
||||
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
||||
if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
||||
|
@ -966,6 +1013,7 @@ static struct rtnl_link_ops can_link_ops __read_mostly = {
|
|||
.maxtype = IFLA_CAN_MAX,
|
||||
.policy = can_policy,
|
||||
.setup = can_setup,
|
||||
.validate = can_validate,
|
||||
.newlink = can_newlink,
|
||||
.changelink = can_changelink,
|
||||
.get_size = can_get_size,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define IFI_CANFD_STCMD_LOOPBACK BIT(18)
|
||||
#define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24)
|
||||
#define IFI_CANFD_STCMD_ENABLE_ISO BIT(25)
|
||||
#define IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING BIT(26)
|
||||
#define IFI_CANFD_STCMD_NORMAL_MODE ((u32)BIT(31))
|
||||
|
||||
#define IFI_CANFD_RXSTCMD 0x4
|
||||
|
@ -51,7 +52,8 @@
|
|||
#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
|
||||
|
||||
#define IFI_CANFD_INTERRUPT 0xc
|
||||
#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1))
|
||||
#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
|
||||
#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10)
|
||||
#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
|
||||
#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
|
||||
#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
|
||||
|
@ -71,12 +73,12 @@
|
|||
#define IFI_CANFD_TIME_TIMEB_OFF 0
|
||||
#define IFI_CANFD_TIME_TIMEA_OFF 8
|
||||
#define IFI_CANFD_TIME_PRESCALE_OFF 16
|
||||
#define IFI_CANFD_TIME_SJW_OFF_ISO 25
|
||||
#define IFI_CANFD_TIME_SJW_OFF_BOSCH 28
|
||||
#define IFI_CANFD_TIME_SET_SJW_BOSCH BIT(6)
|
||||
#define IFI_CANFD_TIME_SET_TIMEB_BOSCH BIT(7)
|
||||
#define IFI_CANFD_TIME_SET_PRESC_BOSCH BIT(14)
|
||||
#define IFI_CANFD_TIME_SET_TIMEA_BOSCH BIT(15)
|
||||
#define IFI_CANFD_TIME_SJW_OFF_7_9_8_8 25
|
||||
#define IFI_CANFD_TIME_SJW_OFF_4_12_6_6 28
|
||||
#define IFI_CANFD_TIME_SET_SJW_4_12_6_6 BIT(6)
|
||||
#define IFI_CANFD_TIME_SET_TIMEB_4_12_6_6 BIT(7)
|
||||
#define IFI_CANFD_TIME_SET_PRESC_4_12_6_6 BIT(14)
|
||||
#define IFI_CANFD_TIME_SET_TIMEA_4_12_6_6 BIT(15)
|
||||
|
||||
#define IFI_CANFD_TDELAY 0x1c
|
||||
|
||||
|
@ -102,7 +104,26 @@
|
|||
|
||||
#define IFI_CANFD_RES1 0x40
|
||||
|
||||
#define IFI_CANFD_RES2 0x44
|
||||
#define IFI_CANFD_ERROR_CTR 0x44
|
||||
#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC 0x21302899
|
||||
#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST BIT(0)
|
||||
#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST BIT(1)
|
||||
#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST BIT(2)
|
||||
#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST BIT(3)
|
||||
#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST BIT(4)
|
||||
#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST BIT(5)
|
||||
#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST BIT(6)
|
||||
#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL BIT(8)
|
||||
#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL BIT(9)
|
||||
#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL BIT(10)
|
||||
#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL BIT(11)
|
||||
#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL BIT(12)
|
||||
#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL BIT(13)
|
||||
#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL BIT(14)
|
||||
#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET 16
|
||||
#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK 0xff
|
||||
#define IFI_CANFD_ERROR_CTR_ER_RESET BIT(30)
|
||||
#define IFI_CANFD_ERROR_CTR_ER_ENABLE ((u32)BIT(31))
|
||||
|
||||
#define IFI_CANFD_PAR 0x48
|
||||
|
||||
|
@ -196,6 +217,8 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
|
|||
if (enable) {
|
||||
enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
|
||||
IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
||||
enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER;
|
||||
}
|
||||
|
||||
writel(IFI_CANFD_IRQMASK_SET_ERR |
|
||||
|
@ -334,6 +357,68 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr)
|
||||
{
|
||||
struct ifi_canfd_priv *priv = netdev_priv(ndev);
|
||||
struct net_device_stats *stats = &ndev->stats;
|
||||
struct can_frame *cf;
|
||||
struct sk_buff *skb;
|
||||
const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST |
|
||||
IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST |
|
||||
IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST |
|
||||
IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST |
|
||||
IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST |
|
||||
IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST |
|
||||
IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST;
|
||||
|
||||
if (!(errctr & errmask)) /* No error happened. */
|
||||
return 0;
|
||||
|
||||
priv->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
/* Propagate the error condition to the CAN stack. */
|
||||
skb = alloc_can_err_skb(ndev, &cf);
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
/* Read the error counter register and check for new errors. */
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST)
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST)
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
|
||||
if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST)
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
|
||||
/* Reset the error counter, ack the IRQ and re-enable the counter. */
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
writel(IFI_CANFD_INTERRUPT_ERROR_COUNTER,
|
||||
priv->base + IFI_CANFD_INTERRUPT);
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
|
@ -469,6 +554,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
|
|||
|
||||
u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
|
||||
u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
|
||||
u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
|
||||
|
||||
/* Handle bus state changes */
|
||||
if ((stcmd & stcmd_state_mask) ||
|
||||
|
@ -479,6 +565,10 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
|
|||
if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
|
||||
work_done += ifi_canfd_handle_lost_msg(ndev);
|
||||
|
||||
/* Handle lec errors on the bus */
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
||||
work_done += ifi_canfd_handle_lec_err(ndev, errctr);
|
||||
|
||||
/* Handle normal messages on RX */
|
||||
if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
|
||||
work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
|
||||
|
@ -497,11 +587,13 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
|
|||
struct ifi_canfd_priv *priv = netdev_priv(ndev);
|
||||
struct net_device_stats *stats = &ndev->stats;
|
||||
const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
|
||||
IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
|
||||
IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER |
|
||||
IFI_CANFD_INTERRUPT_ERROR_WARNING |
|
||||
IFI_CANFD_INTERRUPT_ERROR_COUNTER;
|
||||
const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
|
||||
IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
|
||||
const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
|
||||
IFI_CANFD_INTERRUPT_ERROR_WARNING);
|
||||
const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ |
|
||||
IFI_CANFD_INTERRUPT_ERROR_WARNING));
|
||||
u32 isr;
|
||||
|
||||
isr = readl(priv->base + IFI_CANFD_INTERRUPT);
|
||||
|
@ -513,44 +605,34 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
|
|||
/* Clear all pending interrupts but ErrWarn */
|
||||
writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
|
||||
|
||||
/* RX IRQ, start NAPI */
|
||||
/* RX IRQ or bus warning, start NAPI */
|
||||
if (isr & rx_irq_mask) {
|
||||
ifi_canfd_irq_enable(ndev, 0);
|
||||
napi_schedule(&priv->napi);
|
||||
}
|
||||
|
||||
/* TX IRQ */
|
||||
if (isr & tx_irq_mask) {
|
||||
if (isr & IFI_CANFD_INTERRUPT_TXFIFO_REMOVE) {
|
||||
stats->tx_bytes += can_get_echo_skb(ndev, 0);
|
||||
stats->tx_packets++;
|
||||
can_led_event(ndev, CAN_LED_EVENT_TX);
|
||||
netif_wake_queue(ndev);
|
||||
}
|
||||
|
||||
if (isr & tx_irq_mask)
|
||||
netif_wake_queue(ndev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct can_bittiming_const ifi_canfd_bittiming_const = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
|
||||
.tseg1_max = 64,
|
||||
.tseg1_max = 256,
|
||||
.tseg2_min = 2, /* Time segment 2 = phase_seg2 */
|
||||
.tseg2_max = 64,
|
||||
.sjw_max = 16,
|
||||
.tseg2_max = 256,
|
||||
.sjw_max = 128,
|
||||
.brp_min = 2,
|
||||
.brp_max = 256,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const ifi_canfd_data_bittiming_const = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
|
||||
.tseg1_max = 64,
|
||||
.tseg2_min = 2, /* Time segment 2 = phase_seg2 */
|
||||
.tseg2_max = 64,
|
||||
.sjw_max = 16,
|
||||
.brp_min = 2,
|
||||
.brp_max = 256,
|
||||
.brp_max = 512,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
|
@ -560,19 +642,6 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev)
|
|||
const struct can_bittiming *bt = &priv->can.bittiming;
|
||||
const struct can_bittiming *dbt = &priv->can.data_bittiming;
|
||||
u16 brp, sjw, tseg1, tseg2;
|
||||
u32 noniso_arg = 0;
|
||||
u32 time_off;
|
||||
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) &&
|
||||
!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) {
|
||||
time_off = IFI_CANFD_TIME_SJW_OFF_ISO;
|
||||
} else {
|
||||
noniso_arg = IFI_CANFD_TIME_SET_TIMEB_BOSCH |
|
||||
IFI_CANFD_TIME_SET_TIMEA_BOSCH |
|
||||
IFI_CANFD_TIME_SET_PRESC_BOSCH |
|
||||
IFI_CANFD_TIME_SET_SJW_BOSCH;
|
||||
time_off = IFI_CANFD_TIME_SJW_OFF_BOSCH;
|
||||
}
|
||||
|
||||
/* Configure bit timing */
|
||||
brp = bt->brp - 2;
|
||||
|
@ -582,8 +651,7 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev)
|
|||
writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
|
||||
(tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
|
||||
(brp << IFI_CANFD_TIME_PRESCALE_OFF) |
|
||||
(sjw << time_off) |
|
||||
noniso_arg,
|
||||
(sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8),
|
||||
priv->base + IFI_CANFD_TIME);
|
||||
|
||||
/* Configure data bit timing */
|
||||
|
@ -594,8 +662,7 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev)
|
|||
writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
|
||||
(tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
|
||||
(brp << IFI_CANFD_TIME_PRESCALE_OFF) |
|
||||
(sjw << time_off) |
|
||||
noniso_arg,
|
||||
(sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8),
|
||||
priv->base + IFI_CANFD_FTIME);
|
||||
}
|
||||
|
||||
|
@ -640,7 +707,8 @@ static void ifi_canfd_start(struct net_device *ndev)
|
|||
|
||||
/* Reset the IP */
|
||||
writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
|
||||
writel(0, priv->base + IFI_CANFD_STCMD);
|
||||
writel(IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING,
|
||||
priv->base + IFI_CANFD_STCMD);
|
||||
|
||||
ifi_canfd_set_bittiming(ndev);
|
||||
ifi_canfd_set_filters(ndev);
|
||||
|
@ -659,7 +727,8 @@ static void ifi_canfd_start(struct net_device *ndev)
|
|||
writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
|
||||
priv->base + IFI_CANFD_INTERRUPT);
|
||||
|
||||
stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE;
|
||||
stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE |
|
||||
IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
|
||||
stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
|
||||
|
@ -667,16 +736,23 @@ static void ifi_canfd_start(struct net_device *ndev)
|
|||
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
|
||||
stcmd |= IFI_CANFD_STCMD_LOOPBACK;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) &&
|
||||
!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
|
||||
stcmd |= IFI_CANFD_STCMD_ENABLE_ISO;
|
||||
|
||||
if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)))
|
||||
if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD))
|
||||
stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD;
|
||||
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
ifi_canfd_irq_enable(ndev, 1);
|
||||
|
||||
/* Unlock, reset and enable the error counter. */
|
||||
writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC,
|
||||
priv->base + IFI_CANFD_ERROR_CTR);
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
|
||||
/* Enable controller */
|
||||
writel(stcmd, priv->base + IFI_CANFD_STCMD);
|
||||
}
|
||||
|
@ -685,6 +761,10 @@ static void ifi_canfd_stop(struct net_device *ndev)
|
|||
{
|
||||
struct ifi_canfd_priv *priv = netdev_priv(ndev);
|
||||
|
||||
/* Reset and disable the error counter. */
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
writel(0, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
|
||||
/* Reset the IP */
|
||||
writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
|
||||
|
||||
|
@ -877,7 +957,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
|
|||
priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK);
|
||||
|
||||
priv->can.bittiming_const = &ifi_canfd_bittiming_const;
|
||||
priv->can.data_bittiming_const = &ifi_canfd_data_bittiming_const;
|
||||
priv->can.data_bittiming_const = &ifi_canfd_bittiming_const;
|
||||
priv->can.do_set_mode = ifi_canfd_set_mode;
|
||||
priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter;
|
||||
|
||||
|
@ -888,7 +968,8 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
|
|||
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_LISTENONLY |
|
||||
CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_FD_NON_ISO;
|
||||
CAN_CTRLMODE_FD_NON_ISO |
|
||||
CAN_CTRLMODE_BERR_REPORTING;
|
||||
|
||||
platform_set_drvdata(pdev, ndev);
|
||||
SET_NETDEV_DEV(ndev, dev);
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
#define MSG_COFFREQ 0x42
|
||||
#define MSG_CONREQ 0x43
|
||||
#define MSG_CCONFREQ 0x47
|
||||
#define MSG_NMTS 0xb0
|
||||
#define MSG_LMTS 0xb4
|
||||
|
||||
/*
|
||||
|
@ -130,6 +131,22 @@
|
|||
|
||||
#define ICAN3_CAN_DLC_MASK 0x0f
|
||||
|
||||
/* Janz ICAN3 NMTS subtypes */
|
||||
#define NMTS_CREATE_NODE_REQ 0x0
|
||||
#define NMTS_SLAVE_STATE_IND 0x8
|
||||
#define NMTS_SLAVE_EVENT_IND 0x9
|
||||
|
||||
/* Janz ICAN3 LMTS subtypes */
|
||||
#define LMTS_BUSON_REQ 0x0
|
||||
#define LMTS_BUSOFF_REQ 0x1
|
||||
#define LMTS_CAN_CONF_REQ 0x2
|
||||
|
||||
/* Janz ICAN3 NMTS Event indications */
|
||||
#define NE_LOCAL_OCCURRED 0x3
|
||||
#define NE_LOCAL_RESOLVED 0x2
|
||||
#define NE_REMOTE_OCCURRED 0xc
|
||||
#define NE_REMOTE_RESOLVED 0x8
|
||||
|
||||
/*
|
||||
* SJA1000 Status and Error Register Definitions
|
||||
*
|
||||
|
@ -800,21 +817,41 @@ static int ican3_set_bus_state(struct ican3_dev *mod, bool on)
|
|||
return ican3_send_msg(mod, &msg);
|
||||
|
||||
} else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) {
|
||||
/* bittiming + can-on/off request */
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.spec = MSG_LMTS;
|
||||
if (on) {
|
||||
msg.len = cpu_to_le16(4);
|
||||
msg.data[0] = 0;
|
||||
msg.data[0] = LMTS_BUSON_REQ;
|
||||
msg.data[1] = 0;
|
||||
msg.data[2] = btr0;
|
||||
msg.data[3] = btr1;
|
||||
} else {
|
||||
msg.len = cpu_to_le16(2);
|
||||
msg.data[0] = 1;
|
||||
msg.data[0] = LMTS_BUSOFF_REQ;
|
||||
msg.data[1] = 0;
|
||||
}
|
||||
res = ican3_send_msg(mod, &msg);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return ican3_send_msg(mod, &msg);
|
||||
if (on) {
|
||||
/* create NMT Slave Node for error processing
|
||||
* class 2 (with error capability, see CiA/DS203-1)
|
||||
* id 1
|
||||
* name locnod1 (must be exactly 7 bytes)
|
||||
*/
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.spec = MSG_NMTS;
|
||||
msg.len = cpu_to_le16(11);
|
||||
msg.data[0] = NMTS_CREATE_NODE_REQ;
|
||||
msg.data[1] = 0;
|
||||
msg.data[2] = 2; /* node class */
|
||||
msg.data[3] = 1; /* node id */
|
||||
strcpy(msg.data + 4, "locnod1"); /* node name */
|
||||
return ican3_send_msg(mod, &msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
@ -849,12 +886,23 @@ static int ican3_set_buserror(struct ican3_dev *mod, u8 quota)
|
|||
{
|
||||
struct ican3_msg msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.spec = MSG_CCONFREQ;
|
||||
msg.len = cpu_to_le16(2);
|
||||
msg.data[0] = 0x00;
|
||||
msg.data[1] = quota;
|
||||
|
||||
if (mod->fwtype == ICAN3_FWTYPE_ICANOS) {
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.spec = MSG_CCONFREQ;
|
||||
msg.len = cpu_to_le16(2);
|
||||
msg.data[0] = 0x00;
|
||||
msg.data[1] = quota;
|
||||
} else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) {
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.spec = MSG_LMTS;
|
||||
msg.len = cpu_to_le16(4);
|
||||
msg.data[0] = LMTS_CAN_CONF_REQ;
|
||||
msg.data[1] = 0x00;
|
||||
msg.data[2] = 0x00;
|
||||
msg.data[3] = quota;
|
||||
} else {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
return ican3_send_msg(mod, &msg);
|
||||
}
|
||||
|
||||
|
@ -1150,6 +1198,41 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
|
|||
}
|
||||
}
|
||||
|
||||
/* Handle NMTS Slave Event Indication Messages from the firmware */
|
||||
static void ican3_handle_nmtsind(struct ican3_dev *mod, struct ican3_msg *msg)
|
||||
{
|
||||
u16 subspec;
|
||||
|
||||
subspec = msg->data[0] + msg->data[1] * 0x100;
|
||||
if (subspec == NMTS_SLAVE_EVENT_IND) {
|
||||
switch (msg->data[2]) {
|
||||
case NE_LOCAL_OCCURRED:
|
||||
case NE_LOCAL_RESOLVED:
|
||||
/* now follows the same message as Raw ICANOS CEVTIND
|
||||
* shift the data at the same place and call this method
|
||||
*/
|
||||
le16_add_cpu(&msg->len, -3);
|
||||
memmove(msg->data, msg->data + 3, le16_to_cpu(msg->len));
|
||||
ican3_handle_cevtind(mod, msg);
|
||||
break;
|
||||
case NE_REMOTE_OCCURRED:
|
||||
case NE_REMOTE_RESOLVED:
|
||||
/* should not occurre, ignore */
|
||||
break;
|
||||
default:
|
||||
netdev_warn(mod->ndev, "unknown NMTS event indication %x\n",
|
||||
msg->data[2]);
|
||||
break;
|
||||
}
|
||||
} else if (subspec == NMTS_SLAVE_STATE_IND) {
|
||||
/* ignore state indications */
|
||||
} else {
|
||||
netdev_warn(mod->ndev, "unhandled NMTS indication %x\n",
|
||||
subspec);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ican3_handle_unknown_message(struct ican3_dev *mod,
|
||||
struct ican3_msg *msg)
|
||||
{
|
||||
|
@ -1179,6 +1262,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
|
|||
case MSG_INQUIRY:
|
||||
ican3_handle_inquiry(mod, msg);
|
||||
break;
|
||||
case MSG_NMTS:
|
||||
ican3_handle_nmtsind(mod, msg);
|
||||
break;
|
||||
default:
|
||||
ican3_handle_unknown_message(mod, msg);
|
||||
break;
|
||||
|
|
|
@ -955,7 +955,7 @@ static struct net_device *alloc_m_can_dev(void)
|
|||
priv->can.do_get_berr_counter = m_can_get_berr_counter;
|
||||
|
||||
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */
|
||||
priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
|
||||
can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
|
||||
|
||||
/* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */
|
||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
|
|
|
@ -276,7 +276,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
out_8(®s->cantflg, 1 << buf_id);
|
||||
|
||||
if (!test_bit(F_TX_PROGRESS, &priv->flags))
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
|
||||
list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head);
|
||||
|
||||
|
@ -469,7 +469,7 @@ static irqreturn_t mscan_isr(int irq, void *dev_id)
|
|||
clear_bit(F_TX_PROGRESS, &priv->flags);
|
||||
priv->cur_pri = 0;
|
||||
} else {
|
||||
dev->trans_start = jiffies;
|
||||
netif_trans_update(dev);
|
||||
}
|
||||
|
||||
if (!test_bit(F_TX_WAIT_ALL, &priv->flags))
|
||||
|
|
|
@ -39,6 +39,7 @@ MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
|
|||
MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
|
||||
"Adlink PCI-7841/cPCI-7841 SE, "
|
||||
"Marathon CAN-bus-PCI, "
|
||||
"Marathon CAN-bus-PCIe, "
|
||||
"TEWS TECHNOLOGIES TPMC810, "
|
||||
"esd CAN-PCI/CPCI/PCI104/200, "
|
||||
"esd CAN-PCI/PMC/266, "
|
||||
|
@ -133,6 +134,7 @@ struct plx_pci_card {
|
|||
#define IXXAT_PCI_SUB_SYS_ID 0x2540
|
||||
|
||||
#define MARATHON_PCI_DEVICE_ID 0x2715
|
||||
#define MARATHON_PCIE_DEVICE_ID 0x3432
|
||||
|
||||
#define TEWS_PCI_VENDOR_ID 0x1498
|
||||
#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A
|
||||
|
@ -141,8 +143,9 @@ struct plx_pci_card {
|
|||
#define CTI_PCI_DEVICE_ID_CRG001 0x0900
|
||||
|
||||
static void plx_pci_reset_common(struct pci_dev *pdev);
|
||||
static void plx_pci_reset_marathon(struct pci_dev *pdev);
|
||||
static void plx9056_pci_reset_common(struct pci_dev *pdev);
|
||||
static void plx_pci_reset_marathon_pci(struct pci_dev *pdev);
|
||||
static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev);
|
||||
|
||||
struct plx_pci_channel_map {
|
||||
u32 bar;
|
||||
|
@ -215,14 +218,22 @@ static struct plx_pci_card_info plx_pci_card_info_ixxat = {
|
|||
/* based on PLX9050 */
|
||||
};
|
||||
|
||||
static struct plx_pci_card_info plx_pci_card_info_marathon = {
|
||||
static struct plx_pci_card_info plx_pci_card_info_marathon_pci = {
|
||||
"Marathon CAN-bus-PCI", 2,
|
||||
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
|
||||
{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
|
||||
&plx_pci_reset_marathon
|
||||
&plx_pci_reset_marathon_pci
|
||||
/* based on PLX9052 */
|
||||
};
|
||||
|
||||
static struct plx_pci_card_info plx_pci_card_info_marathon_pcie = {
|
||||
"Marathon CAN-bus-PCIe", 2,
|
||||
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
|
||||
{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {3, 0x80, 0x00} },
|
||||
&plx_pci_reset_marathon_pcie
|
||||
/* based on PEX8311 */
|
||||
};
|
||||
|
||||
static struct plx_pci_card_info plx_pci_card_info_tews = {
|
||||
"TEWS TECHNOLOGIES TPMC810", 2,
|
||||
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
|
||||
|
@ -316,7 +327,14 @@ static const struct pci_device_id plx_pci_tbl[] = {
|
|||
PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
(kernel_ulong_t)&plx_pci_card_info_marathon
|
||||
(kernel_ulong_t)&plx_pci_card_info_marathon_pci
|
||||
},
|
||||
{
|
||||
/* Marathon CAN-bus-PCIe card */
|
||||
PCI_VENDOR_ID_PLX, MARATHON_PCIE_DEVICE_ID,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
(kernel_ulong_t)&plx_pci_card_info_marathon_pcie
|
||||
},
|
||||
{
|
||||
/* TEWS TECHNOLOGIES TPMC810 card */
|
||||
|
@ -437,8 +455,8 @@ static void plx9056_pci_reset_common(struct pci_dev *pdev)
|
|||
iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL);
|
||||
};
|
||||
|
||||
/* Special reset function for Marathon card */
|
||||
static void plx_pci_reset_marathon(struct pci_dev *pdev)
|
||||
/* Special reset function for Marathon CAN-bus-PCI card */
|
||||
static void plx_pci_reset_marathon_pci(struct pci_dev *pdev)
|
||||
{
|
||||
void __iomem *reset_addr;
|
||||
int i;
|
||||
|
@ -460,6 +478,34 @@ static void plx_pci_reset_marathon(struct pci_dev *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
/* Special reset function for Marathon CAN-bus-PCIe card */
|
||||
static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev)
|
||||
{
|
||||
void __iomem *addr;
|
||||
void __iomem *reset_addr;
|
||||
int i;
|
||||
|
||||
plx9056_pci_reset_common(pdev);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct plx_pci_channel_map *chan_map =
|
||||
&plx_pci_card_info_marathon_pcie.chan_map_tbl[i];
|
||||
addr = pci_iomap(pdev, chan_map->bar, chan_map->size);
|
||||
if (!addr) {
|
||||
dev_err(&pdev->dev, "Failed to remap reset "
|
||||
"space %d (BAR%d)\n", i, chan_map->bar);
|
||||
} else {
|
||||
/* reset the SJA1000 chip */
|
||||
#define MARATHON_PCIE_RESET_OFFSET 32
|
||||
reset_addr = addr + chan_map->offset +
|
||||
MARATHON_PCIE_RESET_OFFSET;
|
||||
iowrite8(0x1, reset_addr);
|
||||
udelay(100);
|
||||
pci_iounmap(pdev, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void plx_pci_del_card(struct pci_dev *pdev)
|
||||
{
|
||||
struct plx_pci_card *card = pci_get_drvdata(pdev);
|
||||
|
@ -486,7 +532,8 @@ static void plx_pci_del_card(struct pci_dev *pdev)
|
|||
* Disable interrupts from PCI-card and disable local
|
||||
* interrupts
|
||||
*/
|
||||
if (pdev->device != PCI_DEVICE_ID_PLX_9056)
|
||||
if (pdev->device != PCI_DEVICE_ID_PLX_9056 &&
|
||||
pdev->device != MARATHON_PCIE_DEVICE_ID)
|
||||
iowrite32(0x0, card->conf_addr + PLX_INTCSR);
|
||||
else
|
||||
iowrite32(0x0, card->conf_addr + PLX9056_INTCSR);
|
||||
|
@ -619,7 +666,8 @@ static int plx_pci_add_card(struct pci_dev *pdev,
|
|||
* Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
|
||||
* Local_2 interrupts from the SJA1000 chips
|
||||
*/
|
||||
if (pdev->device != PCI_DEVICE_ID_PLX_9056) {
|
||||
if (pdev->device != PCI_DEVICE_ID_PLX_9056 &&
|
||||
pdev->device != MARATHON_PCIE_DEVICE_ID) {
|
||||
val = ioread32(card->conf_addr + PLX_INTCSR);
|
||||
if (pdev->subsystem_vendor == PCI_VENDOR_ID_ESDGMBH)
|
||||
val |= PLX_LINT1_EN | PLX_PCI_INT_EN;
|
||||
|
|
|
@ -438,6 +438,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
|
||||
/* set error type */
|
||||
switch (ecc & ECC_MASK) {
|
||||
case ECC_BIT:
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT;
|
||||
|
@ -449,9 +450,12 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
|||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
break;
|
||||
default:
|
||||
cf->data[3] = ecc & ECC_SEG;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set error location */
|
||||
cf->data[3] = ecc & ECC_SEG;
|
||||
|
||||
/* Error occurred during transmission? */
|
||||
if ((ecc & ECC_DIR) == 0)
|
||||
cf->data[2] |= CAN_ERR_PROT_TX;
|
||||
|
|
|
@ -961,7 +961,8 @@ static int mcp251x_open(struct net_device *net)
|
|||
goto open_unlock;
|
||||
}
|
||||
|
||||
priv->wq = create_freezable_workqueue("mcp251x_wq");
|
||||
priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
|
||||
0);
|
||||
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
|
||||
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
|
||||
|
||||
|
|
|
@ -521,7 +521,7 @@ static void ems_usb_write_bulk_callback(struct urb *urb)
|
|||
if (urb->status)
|
||||
netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
|
||||
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
|
||||
/* transmission complete interrupt */
|
||||
netdev->stats.tx_packets++;
|
||||
|
@ -835,7 +835,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
|||
stats->tx_dropped++;
|
||||
}
|
||||
} else {
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
|
||||
/* Slow down tx path */
|
||||
if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS ||
|
||||
|
|
|
@ -480,7 +480,7 @@ static void esd_usb2_write_bulk_callback(struct urb *urb)
|
|||
if (urb->status)
|
||||
netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
|
||||
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
}
|
||||
|
||||
static ssize_t show_firmware(struct device *d,
|
||||
|
@ -820,7 +820,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
|||
goto releasebuf;
|
||||
}
|
||||
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
|
||||
/*
|
||||
* Release our reference to this URB, the USB core will eventually free
|
||||
|
|
|
@ -950,7 +950,8 @@ static void gs_usb_disconnect(struct usb_interface *intf)
|
|||
}
|
||||
|
||||
static const struct usb_device_id gs_usb_table[] = {
|
||||
{USB_DEVICE(USB_GSUSB_1_VENDOR_ID, USB_GSUSB_1_PRODUCT_ID)},
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_GSUSB_1_VENDOR_ID,
|
||||
USB_GSUSB_1_PRODUCT_ID, 0) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ static void peak_usb_write_bulk_callback(struct urb *urb)
|
|||
netdev->stats.tx_bytes += context->data_len;
|
||||
|
||||
/* prevent tx timeout */
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -373,7 +373,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
|
|||
stats->tx_dropped++;
|
||||
}
|
||||
} else {
|
||||
netdev->trans_start = jiffies;
|
||||
netif_trans_update(netdev);
|
||||
|
||||
/* slow down tx path */
|
||||
if (atomic_read(&dev->active_tx_urbs) >= PCAN_USB_MAX_TX_URBS)
|
||||
|
|
|
@ -1106,7 +1106,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
myNextTxDesc->skb = skb;
|
||||
|
||||
dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
|
||||
netif_trans_update(dev); /* NETIF_F_LLTX driver :( */
|
||||
|
||||
e100_hardware_send_packet(np, buf, skb->len);
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
menu "Distributed Switch Architecture drivers"
|
||||
depends on HAVE_NET_DSA
|
||||
|
||||
config NET_DSA_MV88E6XXX
|
||||
tristate
|
||||
default n
|
||||
|
||||
config NET_DSA_MV88E6060
|
||||
tristate "Marvell 88E6060 ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
|
@ -13,46 +9,13 @@ config NET_DSA_MV88E6060
|
|||
This enables support for the Marvell 88E6060 ethernet switch
|
||||
chip.
|
||||
|
||||
config NET_DSA_MV88E6XXX_NEED_PPU
|
||||
bool
|
||||
default n
|
||||
|
||||
config NET_DSA_MV88E6131
|
||||
tristate "Marvell 88E6085/6095/6095F/6131 ethernet switch chip support"
|
||||
config NET_DSA_MV88E6XXX
|
||||
tristate "Marvell 88E6xxx Ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_MV88E6XXX
|
||||
select NET_DSA_MV88E6XXX_NEED_PPU
|
||||
select NET_DSA_TAG_DSA
|
||||
---help---
|
||||
This enables support for the Marvell 88E6085/6095/6095F/6131
|
||||
ethernet switch chips.
|
||||
|
||||
config NET_DSA_MV88E6123
|
||||
tristate "Marvell 88E6123/6161/6165 ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_MV88E6XXX
|
||||
select NET_DSA_TAG_EDSA
|
||||
---help---
|
||||
This enables support for the Marvell 88E6123/6161/6165
|
||||
ethernet switch chips.
|
||||
|
||||
config NET_DSA_MV88E6171
|
||||
tristate "Marvell 88E6171/6175/6350/6351 ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_MV88E6XXX
|
||||
select NET_DSA_TAG_EDSA
|
||||
---help---
|
||||
This enables support for the Marvell 88E6171/6175/6350/6351
|
||||
ethernet switches chips.
|
||||
|
||||
config NET_DSA_MV88E6352
|
||||
tristate "Marvell 88E6172/6176/6320/6321/6352 ethernet switch chip support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_MV88E6XXX
|
||||
select NET_DSA_TAG_EDSA
|
||||
---help---
|
||||
This enables support for the Marvell 88E6172, 88E6176, 88E6320,
|
||||
88E6321 and 88E6352 ethernet switch chips.
|
||||
This enables support for most of the Marvell 88E6xxx models of
|
||||
Ethernet switch chips, except 88E6060.
|
||||
|
||||
config NET_DSA_BCM_SF2
|
||||
tristate "Broadcom Starfighter 2 Ethernet switch support"
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
|
||||
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx_drv.o
|
||||
mv88e6xxx_drv-y += mv88e6xxx.o
|
||||
ifdef CONFIG_NET_DSA_MV88E6123
|
||||
mv88e6xxx_drv-y += mv88e6123.o
|
||||
endif
|
||||
ifdef CONFIG_NET_DSA_MV88E6131
|
||||
mv88e6xxx_drv-y += mv88e6131.o
|
||||
endif
|
||||
ifdef CONFIG_NET_DSA_MV88E6352
|
||||
mv88e6xxx_drv-y += mv88e6352.o
|
||||
endif
|
||||
ifdef CONFIG_NET_DSA_MV88E6171
|
||||
mv88e6xxx_drv-y += mv88e6171.o
|
||||
endif
|
||||
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
|
||||
obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
|
||||
|
|
|
@ -135,8 +135,17 @@ static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
|
|||
return BCM_SF2_STATS_SIZE;
|
||||
}
|
||||
|
||||
static char *bcm_sf2_sw_probe(struct device *host_dev, int sw_addr)
|
||||
static const char *bcm_sf2_sw_drv_probe(struct device *dsa_dev,
|
||||
struct device *host_dev, int sw_addr,
|
||||
void **_priv)
|
||||
{
|
||||
struct bcm_sf2_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(dsa_dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return NULL;
|
||||
*_priv = priv;
|
||||
|
||||
return "Broadcom Starfighter 2";
|
||||
}
|
||||
|
||||
|
@ -151,7 +160,7 @@ static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port)
|
|||
* the same VLAN.
|
||||
*/
|
||||
for (i = 0; i < priv->hw_params.num_ports; i++) {
|
||||
if (!((1 << i) & ds->phys_port_mask))
|
||||
if (!((1 << i) & ds->enabled_port_mask))
|
||||
continue;
|
||||
|
||||
reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
|
||||
|
@ -545,12 +554,11 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
|
|||
priv->port_sts[port].bridge_dev = NULL;
|
||||
}
|
||||
|
||||
static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
|
||||
u8 state)
|
||||
static void bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
|
||||
u8 state)
|
||||
{
|
||||
struct bcm_sf2_priv *priv = ds_to_priv(ds);
|
||||
u8 hw_state, cur_hw_state;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
reg = core_readl(priv, CORE_G_PCTL_PORT(port));
|
||||
|
@ -574,7 +582,7 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
|
|||
break;
|
||||
default:
|
||||
pr_err("%s: invalid STP state: %d\n", __func__, state);
|
||||
return -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fast-age ARL entries if we are moving a port from Learning or
|
||||
|
@ -584,10 +592,9 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
|
|||
if (cur_hw_state != hw_state) {
|
||||
if (cur_hw_state >= G_MISTP_LEARN_STATE &&
|
||||
hw_state <= G_MISTP_LISTEN_STATE) {
|
||||
ret = bcm_sf2_sw_fast_age_port(ds, port);
|
||||
if (ret) {
|
||||
if (bcm_sf2_sw_fast_age_port(ds, port)) {
|
||||
pr_err("%s: fast-ageing failed\n", __func__);
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -596,8 +603,6 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
|
|||
reg &= ~(G_MISTP_STATE_MASK << G_MISTP_STATE_SHIFT);
|
||||
reg |= hw_state;
|
||||
core_writel(priv, reg, CORE_G_PCTL_PORT(port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Address Resolution Logic routines */
|
||||
|
@ -728,13 +733,14 @@ static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_fdb *fdb,
|
||||
struct switchdev_trans *trans)
|
||||
static void bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_fdb *fdb,
|
||||
struct switchdev_trans *trans)
|
||||
{
|
||||
struct bcm_sf2_priv *priv = ds_to_priv(ds);
|
||||
|
||||
return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, true);
|
||||
if (bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, true))
|
||||
pr_err("%s: failed to add MAC address\n", __func__);
|
||||
}
|
||||
|
||||
static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, int port,
|
||||
|
@ -943,8 +949,8 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
|
|||
/* All the interesting properties are at the parent device_node
|
||||
* level
|
||||
*/
|
||||
dn = ds->pd->of_node->parent;
|
||||
bcm_sf2_identify_ports(priv, ds->pd->of_node);
|
||||
dn = ds->cd->of_node->parent;
|
||||
bcm_sf2_identify_ports(priv, ds->cd->of_node);
|
||||
|
||||
priv->irq0 = irq_of_parse_and_map(dn, 0);
|
||||
priv->irq1 = irq_of_parse_and_map(dn, 1);
|
||||
|
@ -1003,7 +1009,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
|
|||
/* Enable all valid ports and disable those unused */
|
||||
for (port = 0; port < priv->hw_params.num_ports; port++) {
|
||||
/* IMP port receives special treatment */
|
||||
if ((1 << port) & ds->phys_port_mask)
|
||||
if ((1 << port) & ds->enabled_port_mask)
|
||||
bcm_sf2_port_setup(ds, port, NULL);
|
||||
else if (dsa_is_cpu_port(ds, port))
|
||||
bcm_sf2_imp_setup(ds, port);
|
||||
|
@ -1016,11 +1022,12 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
|
|||
* 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such
|
||||
* that we can use the regular SWITCH_MDIO master controller instead.
|
||||
*
|
||||
* By default, DSA initializes ds->phys_mii_mask to ds->phys_port_mask
|
||||
* to have a 1:1 mapping between Port address and PHY address in order
|
||||
* to utilize the slave_mii_bus instance to read from Port PHYs. This is
|
||||
* not what we want here, so we initialize phys_mii_mask 0 to always
|
||||
* utilize the "master" MDIO bus backed by the "mdio-unimac" driver.
|
||||
* By default, DSA initializes ds->phys_mii_mask to
|
||||
* ds->enabled_port_mask to have a 1:1 mapping between Port address
|
||||
* and PHY address in order to utilize the slave_mii_bus instance to
|
||||
* read from Port PHYs. This is not what we want here, so we
|
||||
* initialize phys_mii_mask 0 to always utilize the "master" MDIO
|
||||
* bus backed by the "mdio-unimac" driver.
|
||||
*/
|
||||
if (of_machine_is_compatible("brcm,bcm7445d0"))
|
||||
ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
|
||||
|
@ -1278,7 +1285,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
|
|||
* bcm_sf2_sw_setup
|
||||
*/
|
||||
for (port = 0; port < DSA_MAX_PORTS; port++) {
|
||||
if ((1 << port) & ds->phys_port_mask ||
|
||||
if ((1 << port) & ds->enabled_port_mask ||
|
||||
dsa_is_cpu_port(ds, port))
|
||||
bcm_sf2_port_disable(ds, port, NULL);
|
||||
}
|
||||
|
@ -1302,7 +1309,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
|
|||
bcm_sf2_gphy_enable_set(ds, true);
|
||||
|
||||
for (port = 0; port < DSA_MAX_PORTS; port++) {
|
||||
if ((1 << port) & ds->phys_port_mask)
|
||||
if ((1 << port) & ds->enabled_port_mask)
|
||||
bcm_sf2_port_setup(ds, port, NULL);
|
||||
else if (dsa_is_cpu_port(ds, port))
|
||||
bcm_sf2_imp_setup(ds, port);
|
||||
|
@ -1365,8 +1372,7 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port,
|
|||
|
||||
static struct dsa_switch_driver bcm_sf2_switch_driver = {
|
||||
.tag_protocol = DSA_TAG_PROTO_BRCM,
|
||||
.priv_size = sizeof(struct bcm_sf2_priv),
|
||||
.probe = bcm_sf2_sw_probe,
|
||||
.probe = bcm_sf2_sw_drv_probe,
|
||||
.setup = bcm_sf2_sw_setup,
|
||||
.set_addr = bcm_sf2_sw_set_addr,
|
||||
.get_phy_flags = bcm_sf2_sw_get_phy_flags,
|
||||
|
@ -1387,7 +1393,7 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
|
|||
.set_eee = bcm_sf2_sw_set_eee,
|
||||
.port_bridge_join = bcm_sf2_sw_br_join,
|
||||
.port_bridge_leave = bcm_sf2_sw_br_leave,
|
||||
.port_stp_update = bcm_sf2_sw_br_set_stp_state,
|
||||
.port_stp_state_set = bcm_sf2_sw_br_set_stp_state,
|
||||
.port_fdb_prepare = bcm_sf2_sw_fdb_prepare,
|
||||
.port_fdb_add = bcm_sf2_sw_fdb_add,
|
||||
.port_fdb_del = bcm_sf2_sw_fdb_del,
|
||||
|
|
|
@ -19,12 +19,9 @@
|
|||
|
||||
static int reg_read(struct dsa_switch *ds, int addr, int reg)
|
||||
{
|
||||
struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
|
||||
struct mv88e6060_priv *priv = ds_to_priv(ds);
|
||||
|
||||
if (bus == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return mdiobus_read_nested(bus, ds->pd->sw_addr + addr, reg);
|
||||
return mdiobus_read_nested(priv->bus, priv->sw_addr + addr, reg);
|
||||
}
|
||||
|
||||
#define REG_READ(addr, reg) \
|
||||
|
@ -40,12 +37,9 @@ static int reg_read(struct dsa_switch *ds, int addr, int reg)
|
|||
|
||||
static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
|
||||
{
|
||||
struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
|
||||
struct mv88e6060_priv *priv = ds_to_priv(ds);
|
||||
|
||||
if (bus == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return mdiobus_write_nested(bus, ds->pd->sw_addr + addr, reg, val);
|
||||
return mdiobus_write_nested(priv->bus, priv->sw_addr + addr, reg, val);
|
||||
}
|
||||
|
||||
#define REG_WRITE(addr, reg, val) \
|
||||
|
@ -57,14 +51,10 @@ static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
|
|||
return __ret; \
|
||||
})
|
||||
|
||||
static char *mv88e6060_probe(struct device *host_dev, int sw_addr)
|
||||
static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr)
|
||||
{
|
||||
struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
|
||||
int ret;
|
||||
|
||||
if (bus == NULL)
|
||||
return NULL;
|
||||
|
||||
ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID);
|
||||
if (ret >= 0) {
|
||||
if (ret == PORT_SWITCH_ID_6060)
|
||||
|
@ -79,6 +69,27 @@ static char *mv88e6060_probe(struct device *host_dev, int sw_addr)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static const char *mv88e6060_drv_probe(struct device *dsa_dev,
|
||||
struct device *host_dev, int sw_addr,
|
||||
void **_priv)
|
||||
{
|
||||
struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
|
||||
struct mv88e6060_priv *priv;
|
||||
const char *name;
|
||||
|
||||
name = mv88e6060_get_name(bus, sw_addr);
|
||||
if (name) {
|
||||
priv = devm_kzalloc(dsa_dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return NULL;
|
||||
*_priv = priv;
|
||||
priv->bus = bus;
|
||||
priv->sw_addr = sw_addr;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int mv88e6060_switch_reset(struct dsa_switch *ds)
|
||||
{
|
||||
int i;
|
||||
|
@ -159,7 +170,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
|
|||
REG_WRITE(addr, PORT_VLAN_MAP,
|
||||
((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
|
||||
(dsa_is_cpu_port(ds, p) ?
|
||||
ds->phys_port_mask :
|
||||
ds->enabled_port_mask :
|
||||
BIT(ds->dst->cpu_port)));
|
||||
|
||||
/* Port Association Vector: when learning source addresses
|
||||
|
@ -174,8 +185,8 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
|
|||
|
||||
static int mv88e6060_setup(struct dsa_switch *ds)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = mv88e6060_switch_reset(ds);
|
||||
if (ret < 0)
|
||||
|
@ -238,7 +249,7 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
|
|||
|
||||
static struct dsa_switch_driver mv88e6060_switch_driver = {
|
||||
.tag_protocol = DSA_TAG_PROTO_TRAILER,
|
||||
.probe = mv88e6060_probe,
|
||||
.probe = mv88e6060_drv_probe,
|
||||
.setup = mv88e6060_setup,
|
||||
.set_addr = mv88e6060_set_addr,
|
||||
.phy_read = mv88e6060_phy_read,
|
||||
|
|
|
@ -108,4 +108,15 @@
|
|||
#define GLOBAL_ATU_MAC_23 0x0e
|
||||
#define GLOBAL_ATU_MAC_45 0x0f
|
||||
|
||||
struct mv88e6060_priv {
|
||||
/* MDIO bus and address on bus to use. When in single chip
|
||||
* mode, address is 0, and the switch uses multiple addresses
|
||||
* on the bus. When in multi-chip mode, the switch uses a
|
||||
* single address which contains two registers used for
|
||||
* indirect access to more registers.
|
||||
*/
|
||||
struct mii_bus *bus;
|
||||
int sw_addr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support
|
||||
* Copyright (c) 2008-2009 Marvell Semiconductor
|
||||
*
|
||||
* 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 <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
#include <net/dsa.h>
|
||||
#include "mv88e6xxx.h"
|
||||
|
||||
static const struct mv88e6xxx_switch_id mv88e6123_table[] = {
|
||||
{ PORT_SWITCH_ID_6123, "Marvell 88E6123" },
|
||||
{ PORT_SWITCH_ID_6123_A1, "Marvell 88E6123 (A1)" },
|
||||
{ PORT_SWITCH_ID_6123_A2, "Marvell 88E6123 (A2)" },
|
||||
{ PORT_SWITCH_ID_6161, "Marvell 88E6161" },
|
||||
{ PORT_SWITCH_ID_6161_A1, "Marvell 88E6161 (A1)" },
|
||||
{ PORT_SWITCH_ID_6161_A2, "Marvell 88E6161 (A2)" },
|
||||
{ PORT_SWITCH_ID_6165, "Marvell 88E6165" },
|
||||
{ PORT_SWITCH_ID_6165_A1, "Marvell 88E6165 (A1)" },
|
||||
{ PORT_SWITCH_ID_6165_A2, "Marvell 88e6165 (A2)" },
|
||||
};
|
||||
|
||||
static char *mv88e6123_probe(struct device *host_dev, int sw_addr)
|
||||
{
|
||||
return mv88e6xxx_lookup_name(host_dev, sw_addr, mv88e6123_table,
|
||||
ARRAY_SIZE(mv88e6123_table));
|
||||
}
|
||||
|
||||
static int mv88e6123_setup_global(struct dsa_switch *ds)
|
||||
{
|
||||
u32 upstream_port = dsa_upstream_port(ds);
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
ret = mv88e6xxx_setup_global(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable the PHY polling unit (since there won't be any
|
||||
* external PHYs to poll), don't discard packets with
|
||||
* excessive collisions, and mask all interrupt sources.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, 0x0000);
|
||||
|
||||
/* Configure the upstream port, and configure the upstream
|
||||
* port as the port to which ingress and egress monitor frames
|
||||
* are to be sent.
|
||||
*/
|
||||
reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
|
||||
upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg);
|
||||
|
||||
/* Disable remote management for now, and set the switch's
|
||||
* DSA device number.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, ds->index & 0x1f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6123_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
int ret;
|
||||
|
||||
ret = mv88e6xxx_setup_common(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (ps->id) {
|
||||
case PORT_SWITCH_ID_6123:
|
||||
ps->num_ports = 3;
|
||||
break;
|
||||
case PORT_SWITCH_ID_6161:
|
||||
case PORT_SWITCH_ID_6165:
|
||||
ps->num_ports = 6;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = mv88e6xxx_switch_reset(ds, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mv88e6123_setup_global(ds);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return mv88e6xxx_setup_ports(ds);
|
||||
}
|
||||
|
||||
struct dsa_switch_driver mv88e6123_switch_driver = {
|
||||
.tag_protocol = DSA_TAG_PROTO_EDSA,
|
||||
.priv_size = sizeof(struct mv88e6xxx_priv_state),
|
||||
.probe = mv88e6123_probe,
|
||||
.setup = mv88e6123_setup,
|
||||
.set_addr = mv88e6xxx_set_addr_indirect,
|
||||
.phy_read = mv88e6xxx_phy_read,
|
||||
.phy_write = mv88e6xxx_phy_write,
|
||||
.get_strings = mv88e6xxx_get_strings,
|
||||
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||
.adjust_link = mv88e6xxx_adjust_link,
|
||||
#ifdef CONFIG_NET_DSA_HWMON
|
||||
.get_temp = mv88e6xxx_get_temp,
|
||||
#endif
|
||||
.get_regs_len = mv88e6xxx_get_regs_len,
|
||||
.get_regs = mv88e6xxx_get_regs,
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:mv88e6123");
|
||||
MODULE_ALIAS("platform:mv88e6161");
|
||||
MODULE_ALIAS("platform:mv88e6165");
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue