Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Millar: "Here are some highlights from the 2065 networking commits that happened this development cycle: 1) XDP support for IXGBE (John Fastabend) and thunderx (Sunil Kowuri) 2) Add a generic XDP driver, so that anyone can test XDP even if they lack a networking device whose driver has explicit XDP support (me). 3) Sparc64 now has an eBPF JIT too (me) 4) Add a BPF program testing framework via BPF_PROG_TEST_RUN (Alexei Starovoitov) 5) Make netfitler network namespace teardown less expensive (Florian Westphal) 6) Add symmetric hashing support to nft_hash (Laura Garcia Liebana) 7) Implement NAPI and GRO in netvsc driver (Stephen Hemminger) 8) Support TC flower offload statistics in mlxsw (Arkadi Sharshevsky) 9) Multiqueue support in stmmac driver (Joao Pinto) 10) Remove TCP timewait recycling, it never really could possibly work well in the real world and timestamp randomization really zaps any hint of usability this feature had (Soheil Hassas Yeganeh) 11) Support level3 vs level4 ECMP route hashing in ipv4 (Nikolay Aleksandrov) 12) Add socket busy poll support to epoll (Sridhar Samudrala) 13) Netlink extended ACK support (Johannes Berg, Pablo Neira Ayuso, and several others) 14) IPSEC hw offload infrastructure (Steffen Klassert)" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (2065 commits) tipc: refactor function tipc_sk_recv_stream() tipc: refactor function tipc_sk_recvmsg() net: thunderx: Optimize page recycling for XDP net: thunderx: Support for XDP header adjustment net: thunderx: Add support for XDP_TX net: thunderx: Add support for XDP_DROP net: thunderx: Add basic XDP support net: thunderx: Cleanup receive buffer allocation net: thunderx: Optimize CQE_TX handling net: thunderx: Optimize RBDR descriptor handling net: thunderx: Support for page recycling ipx: call ipxitf_put() in ioctl error path net: sched: add helpers to handle extended actions qed*: Fix issues in the ptp filter config implementation. qede: Fix concurrency issue in PTP Tx path processing. stmmac: Add support for SIMATIC IOT2000 platform net: hns: fix ethtool_get_strings overflow in hns driver tcp: fix wraparound issue in tcp_lp bpf, arm64: fix jit branch offset related to ldimm64 bpf, arm64: implement jiting of BPF_XADD ...
This commit is contained in:
commit
8d65b08deb
|
@ -21,3 +21,30 @@ Description:
|
|||
is responsible for coordination of driver and firmware
|
||||
link framing mode, changing this setting to 'Y' if the
|
||||
firmware is configured for 'raw-ip' mode.
|
||||
|
||||
What: /sys/class/net/<iface>/qmi/add_mux
|
||||
Date: March 2017
|
||||
KernelVersion: 4.11
|
||||
Contact: Bjørn Mork <bjorn@mork.no>
|
||||
Description:
|
||||
Unsigned integer.
|
||||
|
||||
Write a number ranging from 1 to 127 to add a qmap mux
|
||||
based network device, supported by recent Qualcomm based
|
||||
modems.
|
||||
|
||||
The network device will be called qmimux.
|
||||
|
||||
Userspace is in charge of managing the qmux network device
|
||||
activation and data stream setup on the modem side by
|
||||
using the proper QMI protocol requests.
|
||||
|
||||
What: /sys/class/net/<iface>/qmi/del_mux
|
||||
Date: March 2017
|
||||
KernelVersion: 4.11
|
||||
Contact: Bjørn Mork <bjorn@mork.no>
|
||||
Description:
|
||||
Unsigned integer.
|
||||
|
||||
Write a number ranging from 1 to 127 to delete a previously
|
||||
created qmap mux based network device.
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
Required properties:
|
||||
- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
|
||||
"brcm,genet-v3", "brcm,genet-v4".
|
||||
"brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5".
|
||||
- reg: address and length of the register set for the device
|
||||
- interrupts: must be two cells, the first cell is the general purpose
|
||||
interrupt line, while the second cell is the interrupt for the ring
|
||||
RX and TX queues operating in ring mode
|
||||
- interrupts and/or interrupts-extended: must be two cells, the first cell
|
||||
is the general purpose interrupt line, while the second cell is the
|
||||
interrupt for the ring RX and TX queues operating in ring mode. An
|
||||
optional third interrupt cell for Wake-on-LAN can be specified.
|
||||
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
for information on the property specifics.
|
||||
- phy-mode: see ethernet.txt file in the same directory
|
||||
- #address-cells: should be 1
|
||||
- #size-cells: should be 1
|
||||
|
@ -29,15 +32,15 @@ Optional properties:
|
|||
|
||||
Required child nodes:
|
||||
|
||||
- mdio bus node: this node should always be present regarless of the PHY
|
||||
- mdio bus node: this node should always be present regardless of the PHY
|
||||
configuration of the GENET instance
|
||||
|
||||
MDIO bus node required properties:
|
||||
|
||||
- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
|
||||
parent node compatible property (e.g: brcm,genet-v4 pairs with
|
||||
brcm,genet-mdio-v4)
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5", the version
|
||||
has to match the parent node compatible property (e.g: brcm,genet-v4 pairs
|
||||
with brcm,genet-mdio-v4)
|
||||
- reg: address and length relative to the parent node base register address
|
||||
- #address-cells: address cell for MDIO bus addressing, should be 1
|
||||
- #size-cells: size of the cells for MDIO bus addressing, should be 0
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
Required properties:
|
||||
- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
|
||||
- reg: address and length of the regsiter set for the device, first one is the
|
||||
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5" or
|
||||
"brcm,unimac-mdio"
|
||||
- reg: address and length of the register set for the device, first one is the
|
||||
base register, and the second one is optional and for indirect accesses to
|
||||
larger than 16-bits MDIO transactions
|
||||
- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"
|
||||
|
|
24
Documentation/devicetree/bindings/net/can/holt_hi311x.txt
Normal file
24
Documentation/devicetree/bindings/net/can/holt_hi311x.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
* Holt HI-311X stand-alone CAN controller device tree bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
- "holt,hi3110" for HI-3110
|
||||
- reg: SPI chip select.
|
||||
- clocks: The clock feeding the CAN controller.
|
||||
- interrupt-parent: The parent interrupt controller.
|
||||
- interrupts: Should contain IRQ line for the CAN controller.
|
||||
|
||||
Optional properties:
|
||||
- vdd-supply: Regulator that powers the CAN controller.
|
||||
- xceiver-supply: Regulator that powers the CAN transceiver.
|
||||
|
||||
Example:
|
||||
can0: can@1 {
|
||||
compatible = "holt,hi3110";
|
||||
reg = <1>;
|
||||
clocks = <&clk32m>;
|
||||
interrupt-parent = <&gpio4>;
|
||||
interrupts = <13 IRQ_TYPE_EDGE_RISING>;
|
||||
vdd-supply = <®5v0>;
|
||||
xceiver-supply = <®5v0>;
|
||||
};
|
32
Documentation/devicetree/bindings/net/can/ti_hecc.txt
Normal file
32
Documentation/devicetree/bindings/net/can/ti_hecc.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
Texas Instruments High End CAN Controller (HECC)
|
||||
================================================
|
||||
|
||||
This file provides information, what the device node
|
||||
for the hecc interface contains.
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,am3517-hecc"
|
||||
- reg: addresses and lengths of the register spaces for 'hecc', 'hecc-ram'
|
||||
and 'mbx'
|
||||
- reg-names :"hecc", "hecc-ram", "mbx"
|
||||
- interrupts: interrupt mapping for the hecc interrupts sources
|
||||
- clocks: clock phandles (see clock bindings for details)
|
||||
|
||||
Optional properties:
|
||||
- ti,use-hecc1int: if provided configures HECC to produce all interrupts
|
||||
on HECC1INT interrupt line. By default HECC0INT interrupt
|
||||
line will be used.
|
||||
- xceiver-supply: regulator that powers the CAN transceiver
|
||||
|
||||
Example:
|
||||
|
||||
For am3517evm board:
|
||||
hecc: can@5c050000 {
|
||||
compatible = "ti,am3517-hecc";
|
||||
reg = <0x5c050000 0x80>,
|
||||
<0x5c053000 0x180>,
|
||||
<0x5c052000 0x200>;
|
||||
reg-names = "hecc", "hecc-ram", "mbx";
|
||||
interrupts = <24>;
|
||||
clocks = <&hecc_ck>;
|
||||
};
|
105
Documentation/devicetree/bindings/net/dsa/lan9303.txt
Normal file
105
Documentation/devicetree/bindings/net/dsa/lan9303.txt
Normal file
|
@ -0,0 +1,105 @@
|
|||
SMSC/MicroChip LAN9303 three port ethernet switch
|
||||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be
|
||||
- "smsc,lan9303-i2c" for I2C managed mode
|
||||
or
|
||||
- "smsc,lan9303-mdio" for mdio managed mode
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios: GPIO to be used to reset the whole device
|
||||
- reset-duration: reset duration in milliseconds, defaults to 200 ms
|
||||
|
||||
Subnodes:
|
||||
|
||||
The integrated switch subnode should be specified according to the binding
|
||||
described in dsa/dsa.txt. The CPU port of this switch is always port 0.
|
||||
|
||||
Note: always use 'reg = <0/1/2>;' for the three DSA ports, even if the device is
|
||||
configured to use 1/2/3 instead. This hardware configuration will be
|
||||
auto-detected and mapped accordingly.
|
||||
|
||||
Example:
|
||||
|
||||
I2C managed mode:
|
||||
|
||||
master: masterdevice@X {
|
||||
status = "okay";
|
||||
|
||||
fixed-link { /* RMII fixed link to LAN9303 */
|
||||
speed = <100>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
switch: switch@a {
|
||||
compatible = "smsc,lan9303-i2c";
|
||||
reg = <0xa>;
|
||||
status = "okay";
|
||||
reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
|
||||
reset-duration = <200>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 { /* RMII fixed link to master */
|
||||
reg = <0>;
|
||||
label = "cpu";
|
||||
ethernet = <&master>;
|
||||
};
|
||||
|
||||
port@1 { /* external port 1 */
|
||||
reg = <1>;
|
||||
label = "lan1;
|
||||
};
|
||||
|
||||
port@2 { /* external port 2 */
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
MDIO managed mode:
|
||||
|
||||
master: masterdevice@X {
|
||||
status = "okay";
|
||||
phy-handle = <&switch>;
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
switch: switch-phy@0 {
|
||||
compatible = "smsc,lan9303-mdio";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
|
||||
reset-duration = <100>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "cpu";
|
||||
ethernet = <&master>;
|
||||
};
|
||||
|
||||
port@1 { /* external port 1 */
|
||||
reg = <1>;
|
||||
label = "lan1;
|
||||
};
|
||||
|
||||
port@2 { /* external port 2 */
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
92
Documentation/devicetree/bindings/net/dsa/mt7530.txt
Normal file
92
Documentation/devicetree/bindings/net/dsa/mt7530.txt
Normal file
|
@ -0,0 +1,92 @@
|
|||
Mediatek MT7530 Ethernet switch
|
||||
================================
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be compatible = "mediatek,mt7530";
|
||||
- #address-cells: Must be 1.
|
||||
- #size-cells: Must be 0.
|
||||
- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
|
||||
on multi-chip module belong to MT7623A has or the remotely standalone
|
||||
chip as the function MT7623N reference board provided for.
|
||||
- core-supply: Phandle to the regulator node necessary for the core power.
|
||||
- io-supply: Phandle to the regulator node necessary for the I/O power.
|
||||
See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
|
||||
for details for the regulator setup on these boards.
|
||||
|
||||
If the property mediatek,mcm isn't defined, following property is required
|
||||
|
||||
- reset-gpios: Should be a gpio specifier for a reset line.
|
||||
|
||||
Else, following properties are required
|
||||
|
||||
- resets : Phandle pointing to the system reset controller with
|
||||
line index for the ethsys.
|
||||
- reset-names : Should be set to "mcm".
|
||||
|
||||
Required properties for the child nodes within ports container:
|
||||
|
||||
- reg: Port address described must be 6 for CPU port and from 0 to 5 for
|
||||
user ports.
|
||||
- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
|
||||
"cpu".
|
||||
|
||||
See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
|
||||
required, optional properties and how the integrated switch subnodes must
|
||||
be specified.
|
||||
|
||||
Example:
|
||||
|
||||
&mdio0 {
|
||||
switch@0 {
|
||||
compatible = "mediatek,mt7530";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
core-supply = <&mt6323_vpa_reg>;
|
||||
io-supply = <&mt6323_vemc3v3_reg>;
|
||||
reset-gpios = <&pio 33 0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan0";
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan1";
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan3";
|
||||
};
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "wan";
|
||||
};
|
||||
|
||||
port@6 {
|
||||
reg = <6>;
|
||||
label = "cpu";
|
||||
ethernet = <&gmac0>;
|
||||
phy-mode = "trgmii";
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
35
Documentation/devicetree/bindings/net/ftgmac100.txt
Normal file
35
Documentation/devicetree/bindings/net/ftgmac100.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
* Faraday Technology FTGMAC100 gigabit ethernet controller
|
||||
|
||||
Required properties:
|
||||
- compatible: "faraday,ftgmac100"
|
||||
|
||||
Must also contain one of these if used as part of an Aspeed AST2400
|
||||
or 2500 family SoC as they have some subtle tweaks to the
|
||||
implementation:
|
||||
|
||||
- "aspeed,ast2400-mac"
|
||||
- "aspeed,ast2500-mac"
|
||||
|
||||
- reg: Address and length of the register set for the device
|
||||
- interrupts: Should contain ethernet controller interrupt
|
||||
|
||||
Optional properties:
|
||||
- phy-mode: See ethernet.txt file in the same directory. If the property is
|
||||
absent, "rgmii" is assumed. Supported values are "rgmii*" and "rmii" for
|
||||
aspeed parts. Other (unknown) parts will accept any value.
|
||||
- use-ncsi: Use the NC-SI stack instead of an MDIO PHY. Currently assumes
|
||||
rmii (100bT) but kept as a separate property in case NC-SI grows support
|
||||
for a gigabit link.
|
||||
- no-hw-checksum: Used to disable HW checksum support. Here for backward
|
||||
compatibility as the driver now should have correct defaults based on
|
||||
the SoC.
|
||||
|
||||
Example:
|
||||
|
||||
mac0: ethernet@1e660000 {
|
||||
compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
|
||||
reg = <0x1e660000 0x180>;
|
||||
interrupts = <2>;
|
||||
status = "okay";
|
||||
use-ncsi;
|
||||
};
|
28
Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
Normal file
28
Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
* CA8210 IEEE 802.15.4 *
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "cascoda,ca8210"
|
||||
- reg: Controlling chip select
|
||||
- spi-max-frequency: Maximum clock speed, should be *less than*
|
||||
4000000
|
||||
- spi-cpol: Requires inverted clock polarity
|
||||
- reset-gpio: GPIO attached to reset
|
||||
- irq-gpio: GPIO attached to IRQ
|
||||
Optional properties:
|
||||
- extclock-enable: Include for the ca8210 to route its 16MHz clock
|
||||
to an output
|
||||
- extclock-freq: Frequency in Hz of the external clock
|
||||
- extclock-gpio: GPIO of the ca8210 to output the clock on
|
||||
|
||||
Example:
|
||||
ca8210@0 {
|
||||
compatible = "cascoda,ca8210";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <3000000>;
|
||||
spi-cpol;
|
||||
reset-gpio = <&gpio1 1 GPIO_ACTIVE_HIGH>;
|
||||
irq-gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
|
||||
extclock-enable;
|
||||
extclock-freq = 16000000;
|
||||
extclock-gpio = 2;
|
||||
};
|
|
@ -7,17 +7,20 @@ interface.
|
|||
|
||||
Required properties:
|
||||
- compatible: "marvell,orion-mdio"
|
||||
- reg: address and length of the SMI register
|
||||
- reg: address and length of the MDIO registers. When an interrupt is
|
||||
not present, the length is the size of the SMI register (4 bytes)
|
||||
otherwise it must be 0x84 bytes to cover the interrupt control
|
||||
registers.
|
||||
|
||||
Optional properties:
|
||||
- interrupts: interrupt line number for the SMI error/done interrupt
|
||||
- clocks: Phandle to the clock control device and gate bit
|
||||
- clocks: phandle for up to three required clocks for the MDIO instance
|
||||
|
||||
The child nodes of the MDIO driver are the individual PHY devices
|
||||
connected to this MDIO bus. They must have a "reg" property given the
|
||||
PHY address on the MDIO bus.
|
||||
|
||||
Example at the SoC level:
|
||||
Example at the SoC level without an interrupt property:
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
|
@ -26,6 +29,16 @@ mdio {
|
|||
reg = <0xd0072004 0x4>;
|
||||
};
|
||||
|
||||
Example with an interrupt property:
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "marvell,orion-mdio";
|
||||
reg = <0xd0072004 0x84>;
|
||||
interrupts = <30>;
|
||||
};
|
||||
|
||||
And at the board level:
|
||||
|
||||
mdio {
|
||||
|
|
|
@ -1,17 +1,28 @@
|
|||
* Marvell Armada 375 Ethernet Controller (PPv2)
|
||||
* Marvell Armada 375 Ethernet Controller (PPv2.1)
|
||||
Marvell Armada 7K/8K Ethernet Controller (PPv2.2)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be "marvell,armada-375-pp2"
|
||||
- compatible: should be one of:
|
||||
"marvell,armada-375-pp2"
|
||||
"marvell,armada-7k-pp2"
|
||||
- reg: addresses and length of the register sets for the device.
|
||||
Must contain the following register sets:
|
||||
For "marvell,armada-375-pp2", must contain the following register
|
||||
sets:
|
||||
- common controller registers
|
||||
- LMS registers
|
||||
In addition, at least one port register set is required.
|
||||
- clocks: a pointer to the reference clocks for this device, consequently:
|
||||
- main controller clock
|
||||
- GOP clock
|
||||
- clock-names: names of used clocks, must be "pp_clk" and "gop_clk".
|
||||
- one register area per Ethernet port
|
||||
For "marvell,armada-7k-pp2", must contain the following register
|
||||
sets:
|
||||
- packet processor registers
|
||||
- networking interfaces registers
|
||||
|
||||
- clocks: pointers to the reference clocks for this device, consequently:
|
||||
- main controller clock (for both armada-375-pp2 and armada-7k-pp2)
|
||||
- GOP clock (for both armada-375-pp2 and armada-7k-pp2)
|
||||
- MG clock (only for armada-7k-pp2)
|
||||
- clock-names: names of used clocks, must be "pp_clk", "gop_clk" and
|
||||
"mg_clk" (the latter only for armada-7k-pp2).
|
||||
|
||||
The ethernet ports are represented by subnodes. At least one port is
|
||||
required.
|
||||
|
@ -19,8 +30,10 @@ required.
|
|||
Required properties (port):
|
||||
|
||||
- interrupts: interrupt for the port
|
||||
- port-id: should be '0' or '1' for ethernet ports, and '2' for the
|
||||
loopback port
|
||||
- port-id: ID of the port from the MAC point of view
|
||||
- gop-port-id: only for marvell,armada-7k-pp2, ID of the port from the
|
||||
GOP (Group Of Ports) point of view. This ID is used to index the
|
||||
per-port registers in the second register area.
|
||||
- phy-mode: See ethernet.txt file in the same directory
|
||||
|
||||
Optional properties (port):
|
||||
|
@ -29,7 +42,7 @@ Optional properties (port):
|
|||
- phy: a phandle to a phy node defining the PHY address (as the reg
|
||||
property, a single integer).
|
||||
|
||||
Example:
|
||||
Example for marvell,armada-375-pp2:
|
||||
|
||||
ethernet@f0000 {
|
||||
compatible = "marvell,armada-375-pp2";
|
||||
|
@ -57,3 +70,30 @@ ethernet@f0000 {
|
|||
phy-mode = "gmii";
|
||||
};
|
||||
};
|
||||
|
||||
Example for marvell,armada-7k-pp2:
|
||||
|
||||
cpm_ethernet: ethernet@0 {
|
||||
compatible = "marvell,armada-7k-pp22";
|
||||
reg = <0x0 0x100000>, <0x129000 0xb000>;
|
||||
clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>, <&cpm_syscon0 1 5>;
|
||||
clock-names = "pp_clk", "gop_clk", "gp_clk";
|
||||
|
||||
eth0: eth0 {
|
||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
port-id = <0>;
|
||||
gop-port-id = <0>;
|
||||
};
|
||||
|
||||
eth1: eth1 {
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
port-id = <1>;
|
||||
gop-port-id = <2>;
|
||||
};
|
||||
|
||||
eth2: eth2 {
|
||||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
|
||||
port-id = <2>;
|
||||
gop-port-id = <3>;
|
||||
};
|
||||
};
|
||||
|
|
37
Documentation/devicetree/bindings/net/mdio.txt
Normal file
37
Documentation/devicetree/bindings/net/mdio.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
Common MDIO bus properties.
|
||||
|
||||
These are generic properties that can apply to any MDIO bus.
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: One GPIO that control the RESET lines of all PHYs on that MDIO
|
||||
bus.
|
||||
- reset-delay-us: RESET pulse width in microseconds.
|
||||
|
||||
A list of child nodes, one per device on the bus is expected. These
|
||||
should follow the generic phy.txt, or a device specific binding document.
|
||||
|
||||
The 'reset-delay-us' indicates the RESET signal pulse width in microseconds and
|
||||
applies to all PHY devices. It must therefore be appropriately determined based
|
||||
on all PHY requirements (maximum value of all per-PHY RESET pulse widths).
|
||||
|
||||
Example :
|
||||
This example shows these optional properties, plus other properties
|
||||
required for the TI Davinci MDIO driver.
|
||||
|
||||
davinci_mdio: ethernet@0x5c030000 {
|
||||
compatible = "ti,davinci_mdio";
|
||||
reg = <0x5c030000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
|
||||
reset-delay-us = <2>;
|
||||
|
||||
ethphy0: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
ethphy1: ethernet-phy@3 {
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
|
@ -5,8 +5,8 @@ Required properties:
|
|||
- spi-max-frequency: Maximum SPI frequency (<= 2000000).
|
||||
- interrupt-parent: phandle of parent interrupt handler.
|
||||
- interrupts: A single interrupt specifier.
|
||||
- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the
|
||||
TRF7970A.
|
||||
- ti,enable-gpios: One or two GPIO entries used for 'EN' and 'EN2' pins on the
|
||||
TRF7970A. EN2 is optional.
|
||||
- vin-supply: Regulator for supply voltage to VIN pin
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
|
@ -21,6 +21,8 @@ Optional SoC Specific Properties:
|
|||
- t5t-rmb-extra-byte-quirk: Specify that the trf7970a has the erratum
|
||||
where an extra byte is returned by Read Multiple Block commands issued
|
||||
to Type 5 tags.
|
||||
- vdd-io-supply: Regulator specifying voltage for vdd-io
|
||||
- clock-frequency: Set to specify that the input frequency to the trf7970a is 13560000Hz or 27120000Hz
|
||||
|
||||
Example (for ARM-based BeagleBone with TRF7970A on SPI1):
|
||||
|
||||
|
@ -39,10 +41,12 @@ Example (for ARM-based BeagleBone with TRF7970A on SPI1):
|
|||
<&gpio2 5 GPIO_ACTIVE_LOW>;
|
||||
vin-supply = <&ldo3_reg>;
|
||||
vin-voltage-override = <5000000>;
|
||||
vdd-io-supply = <&ldo2_reg>;
|
||||
autosuspend-delay = <30000>;
|
||||
irq-status-read-quirk;
|
||||
en2-rf-quirk;
|
||||
t5t-rmb-extra-byte-quirk;
|
||||
clock-frequency = <27120000>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
|
51
Documentation/devicetree/bindings/net/nokia-bluetooth.txt
Normal file
51
Documentation/devicetree/bindings/net/nokia-bluetooth.txt
Normal file
|
@ -0,0 +1,51 @@
|
|||
Nokia Bluetooth Chips
|
||||
---------------------
|
||||
|
||||
Nokia phones often come with UART connected bluetooth chips from different
|
||||
vendors and modified device API. Those devices speak a protocol named H4+
|
||||
(also known as h4p) by Nokia, which is similar to the H4 protocol from the
|
||||
Bluetooth standard. In addition to the H4 protocol it specifies two more
|
||||
UART status lines for wakeup of UART transceivers to improve power management
|
||||
and a few new packet types used to negotiate uart speed.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should contain "nokia,h4p-bluetooth" as well as one of the following:
|
||||
* "brcm,bcm2048-nokia"
|
||||
* "ti,wl1271-bluetooth-nokia"
|
||||
- reset-gpios: GPIO specifier, used to reset the BT module (active low)
|
||||
- bluetooth-wakeup-gpios: GPIO specifier, used to wakeup the BT module (active high)
|
||||
- host-wakeup-gpios: GPIO specifier, used to wakeup the host processor (active high)
|
||||
- clock-names: should be "sysclk"
|
||||
- clocks: should contain a clock specifier for every name in clock-names
|
||||
|
||||
Optional properties:
|
||||
|
||||
- None
|
||||
|
||||
Example:
|
||||
|
||||
/ {
|
||||
/* controlled (enabled/disabled) directly by BT module */
|
||||
bluetooth_clk: vctcxo {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <38400000>;
|
||||
};
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart2_pins>;
|
||||
|
||||
bluetooth {
|
||||
compatible = "ti,wl1271-bluetooth-nokia", "nokia,h4p-bluetooth";
|
||||
|
||||
reset-gpios = <&gpio1 26 GPIO_ACTIVE_LOW>; /* gpio26 */
|
||||
host-wakeup-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */
|
||||
bluetooth-wakeup-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>; /* gpio37 */
|
||||
|
||||
clocks = <&bluetooth_clk>;
|
||||
clock-names = "sysclk";
|
||||
};
|
||||
};
|
|
@ -7,9 +7,12 @@ Required properties:
|
|||
- interrupt-parent: Should be the phandle for the interrupt controller
|
||||
that services interrupts for this device
|
||||
- interrupts: Should contain the STMMAC interrupts
|
||||
- interrupt-names: Should contain the interrupt names "macirq"
|
||||
"eth_wake_irq" if this interrupt is supported in the "interrupts"
|
||||
property
|
||||
- interrupt-names: Should contain a list of interrupt names corresponding to
|
||||
the interrupts in the interrupts property, if available.
|
||||
Valid interrupt names are:
|
||||
- "macirq" (combined signal for various interrupt events)
|
||||
- "eth_wake_irq" (the interrupt to manage the remote wake-up packet detection)
|
||||
- "eth_lpi" (the interrupt that occurs when Tx or Rx enters/exits LPI state)
|
||||
- phy-mode: See ethernet.txt file in the same directory.
|
||||
- snps,reset-gpio gpio number for phy reset.
|
||||
- snps,reset-active-low boolean flag to indicate if phy reset is active low.
|
||||
|
@ -28,9 +31,9 @@ Optional properties:
|
|||
clocks may be specified in derived bindings.
|
||||
- clock-names: One name for each entry in the clocks property, the
|
||||
first one should be "stmmaceth" and the second one should be "pclk".
|
||||
- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
|
||||
available this clock is used for programming the Timestamp Addend Register.
|
||||
If not passed then the system clock will be used and this is fine on some
|
||||
- ptp_ref: this is the PTP reference clock; in case of the PTP is available
|
||||
this clock is used for programming the Timestamp Addend Register. If not
|
||||
passed then the system clock will be used and this is fine on some
|
||||
platforms.
|
||||
- tx-fifo-depth: See ethernet.txt file in the same directory
|
||||
- rx-fifo-depth: See ethernet.txt file in the same directory
|
||||
|
@ -72,7 +75,45 @@ Optional properties:
|
|||
- snps,mb: mixed-burst
|
||||
- snps,rb: rebuild INCRx Burst
|
||||
- mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
|
||||
|
||||
- Multiple RX Queues parameters: below the list of all the parameters to
|
||||
configure the multiple RX queues:
|
||||
- snps,rx-queues-to-use: number of RX queues to be used in the driver
|
||||
- Choose one of these RX scheduling algorithms:
|
||||
- snps,rx-sched-sp: Strict priority
|
||||
- snps,rx-sched-wsp: Weighted Strict priority
|
||||
- For each RX queue
|
||||
- Choose one of these modes:
|
||||
- snps,dcb-algorithm: Queue to be enabled as DCB
|
||||
- snps,avb-algorithm: Queue to be enabled as AVB
|
||||
- snps,map-to-dma-channel: Channel to map
|
||||
- Specifiy specific packet routing:
|
||||
- snps,route-avcp: AV Untagged Control packets
|
||||
- snps,route-ptp: PTP Packets
|
||||
- snps,route-dcbcp: DCB Control Packets
|
||||
- snps,route-up: Untagged Packets
|
||||
- snps,route-multi-broad: Multicast & Broadcast Packets
|
||||
- snps,priority: RX queue priority (Range: 0x0 to 0xF)
|
||||
- Multiple TX Queues parameters: below the list of all the parameters to
|
||||
configure the multiple TX queues:
|
||||
- snps,tx-queues-to-use: number of TX queues to be used in the driver
|
||||
- Choose one of these TX scheduling algorithms:
|
||||
- snps,tx-sched-wrr: Weighted Round Robin
|
||||
- snps,tx-sched-wfq: Weighted Fair Queuing
|
||||
- snps,tx-sched-dwrr: Deficit Weighted Round Robin
|
||||
- snps,tx-sched-sp: Strict priority
|
||||
- For each TX queue
|
||||
- snps,weight: TX queue weight (if using a DCB weight algorithm)
|
||||
- Choose one of these modes:
|
||||
- snps,dcb-algorithm: TX queue will be working in DCB
|
||||
- snps,avb-algorithm: TX queue will be working in AVB
|
||||
[Attention] Queue 0 is reserved for legacy traffic
|
||||
and so no AVB is available in this queue.
|
||||
- Configure Credit Base Shaper (if AVB Mode selected):
|
||||
- snps,send_slope: enable Low Power Interface
|
||||
- snps,idle_slope: unlock on WoL
|
||||
- snps,high_credit: max write outstanding req. limit
|
||||
- snps,low_credit: max read outstanding req. limit
|
||||
- snps,priority: TX queue priority (Range: 0x0 to 0xF)
|
||||
Examples:
|
||||
|
||||
stmmac_axi_setup: stmmac-axi-config {
|
||||
|
@ -81,12 +122,41 @@ Examples:
|
|||
snps,blen = <256 128 64 32 0 0 0>;
|
||||
};
|
||||
|
||||
mtl_rx_setup: rx-queues-config {
|
||||
snps,rx-queues-to-use = <1>;
|
||||
snps,rx-sched-sp;
|
||||
queue0 {
|
||||
snps,dcb-algorithm;
|
||||
snps,map-to-dma-channel = <0x0>;
|
||||
snps,priority = <0x0>;
|
||||
};
|
||||
};
|
||||
|
||||
mtl_tx_setup: tx-queues-config {
|
||||
snps,tx-queues-to-use = <2>;
|
||||
snps,tx-sched-wrr;
|
||||
queue0 {
|
||||
snps,weight = <0x10>;
|
||||
snps,dcb-algorithm;
|
||||
snps,priority = <0x0>;
|
||||
};
|
||||
|
||||
queue1 {
|
||||
snps,avb-algorithm;
|
||||
snps,send_slope = <0x1000>;
|
||||
snps,idle_slope = <0x1000>;
|
||||
snps,high_credit = <0x3E800>;
|
||||
snps,low_credit = <0xFFC18000>;
|
||||
snps,priority = <0x1>;
|
||||
};
|
||||
};
|
||||
|
||||
gmac0: ethernet@e0800000 {
|
||||
compatible = "st,spear600-gmac";
|
||||
reg = <0xe0800000 0x8000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <24 23>;
|
||||
interrupt-names = "macirq", "eth_wake_irq";
|
||||
interrupts = <24 23 22>;
|
||||
interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
|
||||
mac-address = [000000000000]; /* Filled in by U-Boot */
|
||||
max-frame-size = <3800>;
|
||||
phy-mode = "gmii";
|
||||
|
@ -104,4 +174,6 @@ Examples:
|
|||
phy1: ethernet-phy@0 {
|
||||
};
|
||||
};
|
||||
snps,mtl-rx-config = <&mtl_rx_setup>;
|
||||
snps,mtl-tx-config = <&mtl_tx_setup>;
|
||||
};
|
||||
|
|
35
Documentation/devicetree/bindings/net/ti,wilink-st.txt
Normal file
35
Documentation/devicetree/bindings/net/ti,wilink-st.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices
|
||||
|
||||
TI WiLink devices have a UART interface for providing Bluetooth, FM radio,
|
||||
and GPS over what's called "shared transport". The shared transport is
|
||||
standard BT HCI protocol with additional channels for the other functions.
|
||||
|
||||
These devices also have a separate WiFi interface as described in
|
||||
wireless/ti,wlcore.txt.
|
||||
|
||||
This bindings follows the UART slave device binding in
|
||||
../serial/slave-device.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"ti,wl1271-st"
|
||||
"ti,wl1273-st"
|
||||
"ti,wl1831-st"
|
||||
"ti,wl1835-st"
|
||||
"ti,wl1837-st"
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios : GPIO signal controlling enabling of BT. Active high.
|
||||
- vio-supply : Vio input supply (1.8V)
|
||||
- vbat-supply : Vbat input supply (2.9-4.8V)
|
||||
|
||||
Example:
|
||||
|
||||
&serial0 {
|
||||
compatible = "ns16550a";
|
||||
...
|
||||
bluetooth {
|
||||
compatible = "ti,wl1835-st";
|
||||
enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
|
@ -51,6 +51,7 @@ brcm Broadcom Corporation
|
|||
buffalo Buffalo, Inc.
|
||||
calxeda Calxeda
|
||||
capella Capella Microsystems, Inc
|
||||
cascoda Cascoda, Ltd.
|
||||
cavium Cavium, Inc.
|
||||
cdns Cadence Design Systems Inc.
|
||||
ceva Ceva, Inc.
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
cfg80211 subsystem
|
||||
==================
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:doc: Introduction
|
||||
|
||||
Device registration
|
||||
===================
|
||||
|
||||
|
@ -179,6 +182,12 @@ Actions and configuration
|
|||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_ibss_joined
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_connect_resp_params
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_connect_done
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_connect_result
|
||||
|
||||
|
|
|
@ -595,10 +595,9 @@ got from bpf_prog_create(), and 'ctx' the given context (e.g.
|
|||
skb pointer). All constraints and restrictions from bpf_check_classic() apply
|
||||
before a conversion to the new layout is being done behind the scenes!
|
||||
|
||||
Currently, the classic BPF format is being used for JITing on most of the
|
||||
architectures. x86-64, aarch64 and s390x perform JIT compilation from eBPF
|
||||
instruction set, however, future work will migrate other JIT compilers as well,
|
||||
so that they will profit from the very same benefits.
|
||||
Currently, the classic BPF format is being used for JITing on most 32-bit
|
||||
architectures, whereas x86-64, aarch64, s390x, powerpc64, sparc64 perform JIT
|
||||
compilation from eBPF instruction set.
|
||||
|
||||
Some core changes of the new internal format:
|
||||
|
||||
|
|
|
@ -63,6 +63,78 @@ Additional Configurations
|
|||
The latest release of ethtool can be found from
|
||||
https://www.kernel.org/pub/software/network/ethtool
|
||||
|
||||
|
||||
Flow Director n-ntuple traffic filters (FDir)
|
||||
---------------------------------------------
|
||||
The driver utilizes the ethtool interface for configuring ntuple filters,
|
||||
via "ethtool -N <device> <filter>".
|
||||
|
||||
The sctp4, ip4, udp4, and tcp4 flow types are supported with the standard
|
||||
fields including src-ip, dst-ip, src-port and dst-port. The driver only
|
||||
supports fully enabling or fully masking the fields, so use of the mask
|
||||
fields for partial matches is not supported.
|
||||
|
||||
Additionally, the driver supports using the action to specify filters for a
|
||||
Virtual Function. You can specify the action as a 64bit value, where the
|
||||
lower 32 bits represents the queue number, while the next 8 bits represent
|
||||
which VF. Note that 0 is the PF, so the VF identifier is offset by 1. For
|
||||
example:
|
||||
|
||||
... action 0x800000002 ...
|
||||
|
||||
Would indicate to direct traffic for Virtual Function 7 (8 minus 1) on queue
|
||||
2 of that VF.
|
||||
|
||||
The driver also supports using the user-defined field to specify 2 bytes of
|
||||
arbitrary data to match within the packet payload in addition to the regular
|
||||
fields. The data is specified in the lower 32bits of the user-def field in
|
||||
the following way:
|
||||
|
||||
+----------------------------+---------------------------+
|
||||
| 31 28 24 20 16 | 15 12 8 4 0|
|
||||
+----------------------------+---------------------------+
|
||||
| offset into packet payload | 2 bytes of flexible data |
|
||||
+----------------------------+---------------------------+
|
||||
|
||||
As an example,
|
||||
|
||||
... user-def 0x4FFFF ....
|
||||
|
||||
means to match the value 0xFFFF 4 bytes into the packet payload. Note that
|
||||
the offset is based on the beginning of the payload, and not the beginning
|
||||
of the packet. Thus
|
||||
|
||||
flow-type tcp4 ... user-def 0x8BEAF ....
|
||||
|
||||
would match TCP/IPv4 packets which have the value 0xBEAF 8bytes into the
|
||||
TCP/IPv4 payload.
|
||||
|
||||
For ICMP, the hardware parses the ICMP header as 4 bytes of header and 4
|
||||
bytes of payload, so if you want to match an ICMP frames payload you may need
|
||||
to add 4 to the offset in order to match the data.
|
||||
|
||||
Furthermore, the offset can only be up to a value of 64, as the hardware
|
||||
will only read up to 64 bytes of data from the payload. It must also be even
|
||||
as the flexible data is 2 bytes long and must be aligned to byte 0 of the
|
||||
packet payload.
|
||||
|
||||
When programming filters, the hardware is limited to using a single input
|
||||
set for each flow type. This means that it is an error to program two
|
||||
different filters with the same type that don't match on the same fields.
|
||||
Thus the second of the following two commands will fail:
|
||||
|
||||
ethtool -N <device> flow-type tcp4 src-ip 192.168.0.7 action 5
|
||||
ethtool -N <device> flow-type tcp4 dst-ip 192.168.15.18 action 1
|
||||
|
||||
This is because the first filter will be accepted and reprogram the input
|
||||
set for TCPv4 filters, but the second filter will be unable to reprogram the
|
||||
input set until all the conflicting TCPv4 filters are first removed.
|
||||
|
||||
Note that the user-defined flexible offset is also considered part of the
|
||||
input set and cannot be programmed separately for multiple filters of the
|
||||
same type. However, the flexible data is not part of the input set and
|
||||
multiple filters may use the same offset but match against different data.
|
||||
|
||||
Data Center Bridging (DCB)
|
||||
--------------------------
|
||||
DCB configuration is not currently supported.
|
||||
|
|
|
@ -73,6 +73,14 @@ fib_multipath_use_neigh - BOOLEAN
|
|||
0 - disabled
|
||||
1 - enabled
|
||||
|
||||
fib_multipath_hash_policy - INTEGER
|
||||
Controls which hash policy to use for multipath routes. Only valid
|
||||
for kernels built with CONFIG_IP_ROUTE_MULTIPATH enabled.
|
||||
Default: 0 (Layer 3)
|
||||
Possible values:
|
||||
0 - Layer 3
|
||||
1 - Layer 4
|
||||
|
||||
route/max_size - INTEGER
|
||||
Maximum number of routes allowed in the kernel. Increase
|
||||
this when using large numbers of interfaces and/or routes.
|
||||
|
@ -594,6 +602,14 @@ tcp_fastopen - INTEGER
|
|||
Note that that additional client or server features are only
|
||||
effective if the basic support (0x1 and 0x2) are enabled respectively.
|
||||
|
||||
tcp_fastopen_blackhole_timeout_sec - INTEGER
|
||||
Initial time period in second to disable Fastopen on active TCP sockets
|
||||
when a TFO firewall blackhole issue happens.
|
||||
This time period will grow exponentially when more blackhole issues
|
||||
get detected right after Fastopen is re-enabled and will reset to
|
||||
initial value when the blackhole issue goes away.
|
||||
By default, it is set to 1hr.
|
||||
|
||||
tcp_syn_retries - INTEGER
|
||||
Number of times initial SYNs for an active TCP connection attempt
|
||||
will be retransmitted. Should not be higher than 127. Default value
|
||||
|
@ -640,11 +656,6 @@ tcp_tso_win_divisor - INTEGER
|
|||
building larger TSO frames.
|
||||
Default: 3
|
||||
|
||||
tcp_tw_recycle - BOOLEAN
|
||||
Enable fast recycling TIME-WAIT sockets. Default value is 0.
|
||||
It should not be changed without advice/request of technical
|
||||
experts.
|
||||
|
||||
tcp_tw_reuse - BOOLEAN
|
||||
Allow to reuse TIME-WAIT sockets for new connections when it is
|
||||
safe from protocol viewpoint. Default value is 0.
|
||||
|
@ -853,12 +864,21 @@ ip_dynaddr - BOOLEAN
|
|||
ip_early_demux - BOOLEAN
|
||||
Optimize input packet processing down to one demux for
|
||||
certain kinds of local sockets. Currently we only do this
|
||||
for established TCP sockets.
|
||||
for established TCP and connected UDP sockets.
|
||||
|
||||
It may add an additional cost for pure routing workloads that
|
||||
reduces overall throughput, in such case you should disable it.
|
||||
Default: 1
|
||||
|
||||
tcp_early_demux - BOOLEAN
|
||||
Enable early demux for established TCP sockets.
|
||||
Default: 1
|
||||
|
||||
udp_early_demux - BOOLEAN
|
||||
Enable early demux for connected UDP sockets. Disable this if
|
||||
your system could experience more unconnected load.
|
||||
Default: 1
|
||||
|
||||
icmp_echo_ignore_all - BOOLEAN
|
||||
If set non-zero, then the kernel will ignore all ICMP ECHO
|
||||
requests sent to it.
|
||||
|
@ -1458,11 +1478,20 @@ accept_ra_pinfo - BOOLEAN
|
|||
Functional default: enabled if accept_ra is enabled.
|
||||
disabled if accept_ra is disabled.
|
||||
|
||||
accept_ra_rt_info_min_plen - INTEGER
|
||||
Minimum prefix length of Route Information in RA.
|
||||
|
||||
Route Information w/ prefix smaller than this variable shall
|
||||
be ignored.
|
||||
|
||||
Functional default: 0 if accept_ra_rtr_pref is enabled.
|
||||
-1 if accept_ra_rtr_pref is disabled.
|
||||
|
||||
accept_ra_rt_info_max_plen - INTEGER
|
||||
Maximum prefix length of Route Information in RA.
|
||||
|
||||
Route Information w/ prefix larger than or equal to this
|
||||
variable shall be ignored.
|
||||
Route Information w/ prefix larger than this variable shall
|
||||
be ignored.
|
||||
|
||||
Functional default: 0 if accept_ra_rtr_pref is enabled.
|
||||
-1 if accept_ra_rtr_pref is disabled.
|
||||
|
|
|
@ -175,6 +175,14 @@ nat_icmp_send - BOOLEAN
|
|||
for VS/NAT when the load balancer receives packets from real
|
||||
servers but the connection entries don't exist.
|
||||
|
||||
pmtu_disc - BOOLEAN
|
||||
0 - disabled
|
||||
not 0 - enabled (default)
|
||||
|
||||
By default, reject with FRAG_NEEDED all DF packets that exceed
|
||||
the PMTU, irrespective of the forwarding method. For TUN method
|
||||
the flag can be disabled to fragment such packets.
|
||||
|
||||
secure_tcp - INTEGER
|
||||
0 - disabled (default)
|
||||
|
||||
|
@ -185,15 +193,59 @@ secure_tcp - INTEGER
|
|||
The value definition is the same as that of drop_entry and
|
||||
drop_packet.
|
||||
|
||||
sync_threshold - INTEGER
|
||||
default 3
|
||||
sync_threshold - vector of 2 INTEGERs: sync_threshold, sync_period
|
||||
default 3 50
|
||||
|
||||
It sets synchronization threshold, which is the minimum number
|
||||
of incoming packets that a connection needs to receive before
|
||||
the connection will be synchronized. A connection will be
|
||||
synchronized, every time the number of its incoming packets
|
||||
modulus 50 equals the threshold. The range of the threshold is
|
||||
from 0 to 49.
|
||||
It sets synchronization threshold, which is the minimum number
|
||||
of incoming packets that a connection needs to receive before
|
||||
the connection will be synchronized. A connection will be
|
||||
synchronized, every time the number of its incoming packets
|
||||
modulus sync_period equals the threshold. The range of the
|
||||
threshold is from 0 to sync_period.
|
||||
|
||||
When sync_period and sync_refresh_period are 0, send sync only
|
||||
for state changes or only once when pkts matches sync_threshold
|
||||
|
||||
sync_refresh_period - UNSIGNED INTEGER
|
||||
default 0
|
||||
|
||||
In seconds, difference in reported connection timer that triggers
|
||||
new sync message. It can be used to avoid sync messages for the
|
||||
specified period (or half of the connection timeout if it is lower)
|
||||
if connection state is not changed since last sync.
|
||||
|
||||
This is useful for normal connections with high traffic to reduce
|
||||
sync rate. Additionally, retry sync_retries times with period of
|
||||
sync_refresh_period/8.
|
||||
|
||||
sync_retries - INTEGER
|
||||
default 0
|
||||
|
||||
Defines sync retries with period of sync_refresh_period/8. Useful
|
||||
to protect against loss of sync messages. The range of the
|
||||
sync_retries is from 0 to 3.
|
||||
|
||||
sync_qlen_max - UNSIGNED LONG
|
||||
|
||||
Hard limit for queued sync messages that are not sent yet. It
|
||||
defaults to 1/32 of the memory pages but actually represents
|
||||
number of messages. It will protect us from allocating large
|
||||
parts of memory when the sending rate is lower than the queuing
|
||||
rate.
|
||||
|
||||
sync_sock_size - INTEGER
|
||||
default 0
|
||||
|
||||
Configuration of SNDBUF (master) or RCVBUF (slave) socket limit.
|
||||
Default value is 0 (preserve system defaults).
|
||||
|
||||
sync_ports - INTEGER
|
||||
default 1
|
||||
|
||||
The number of threads that master and backup servers can use for
|
||||
sync traffic. Every thread will use single UDP port, thread 0 will
|
||||
use the default port 8848 while last thread will use port
|
||||
8848+sync_ports-1.
|
||||
|
||||
snat_reroute - BOOLEAN
|
||||
0 - disabled
|
||||
|
|
|
@ -19,6 +19,25 @@ platform_labels - INTEGER
|
|||
Possible values: 0 - 1048575
|
||||
Default: 0
|
||||
|
||||
ip_ttl_propagate - BOOL
|
||||
Control whether TTL is propagated from the IPv4/IPv6 header to
|
||||
the MPLS header on imposing labels and propagated from the
|
||||
MPLS header to the IPv4/IPv6 header on popping the last label.
|
||||
|
||||
If disabled, the MPLS transport network will appear as a
|
||||
single hop to transit traffic.
|
||||
|
||||
0 - disabled / RFC 3443 [Short] Pipe Model
|
||||
1 - enabled / RFC 3443 Uniform Model (default)
|
||||
|
||||
default_ttl - BOOL
|
||||
Default TTL value to use for MPLS packets where it cannot be
|
||||
propagated from an IP header, either because one isn't present
|
||||
or ip_ttl_propagate has been disabled.
|
||||
|
||||
Possible values: 1 - 255
|
||||
Default: 255
|
||||
|
||||
conf/<interface>/input - BOOL
|
||||
Control whether packets can be input on this interface.
|
||||
|
||||
|
|
|
@ -13,43 +13,43 @@ an example setup using a data-center-class switch ASIC chip. Other setups
|
|||
with SR-IOV or soft switches, such as OVS, are possible.
|
||||
|
||||
|
||||
User-space tools
|
||||
|
||||
user space |
|
||||
+-------------------------------------------------------------------+
|
||||
kernel | Netlink
|
||||
|
|
||||
+--------------+-------------------------------+
|
||||
| Network stack |
|
||||
| (Linux) |
|
||||
| |
|
||||
+----------------------------------------------+
|
||||
|
||||
User-space tools
|
||||
|
||||
user space |
|
||||
+-------------------------------------------------------------------+
|
||||
kernel | Netlink
|
||||
|
|
||||
+--------------+-------------------------------+
|
||||
| Network stack |
|
||||
| (Linux) |
|
||||
| |
|
||||
+----------------------------------------------+
|
||||
|
||||
sw1p2 sw1p4 sw1p6
|
||||
sw1p1 + sw1p3 + sw1p5 + eth1
|
||||
+ | + | + | +
|
||||
| | | | | | |
|
||||
+--+----+----+----+-+--+----+---+ +-----+-----+
|
||||
| Switch driver | | mgmt |
|
||||
| (this document) | | driver |
|
||||
| | | |
|
||||
+--------------+----------------+ +-----------+
|
||||
|
|
||||
kernel | HW bus (eg PCI)
|
||||
+-------------------------------------------------------------------+
|
||||
hardware |
|
||||
+--------------+---+------------+
|
||||
| Switch device (sw1) |
|
||||
| +----+ +--------+
|
||||
| | v offloaded data path | mgmt port
|
||||
| | | |
|
||||
+--|----|----+----+----+----+---+
|
||||
| | | | | |
|
||||
+ + + + + +
|
||||
sw1p1 + sw1p3 + sw1p5 + eth1
|
||||
+ | + | + | +
|
||||
| | | | | | |
|
||||
+--+----+----+----+-+--+----+---+ +-----+-----+
|
||||
| Switch driver | | mgmt |
|
||||
| (this document) | | driver |
|
||||
| | | |
|
||||
+--------------+----------------+ +-----------+
|
||||
|
|
||||
kernel | HW bus (eg PCI)
|
||||
+-------------------------------------------------------------------+
|
||||
hardware |
|
||||
+--------------+---+------------+
|
||||
| Switch device (sw1) |
|
||||
| +----+ +--------+
|
||||
| | v offloaded data path | mgmt port
|
||||
| | | |
|
||||
+--|----|----+----+----+----+---+
|
||||
| | | | | |
|
||||
+ + + + + +
|
||||
p1 p2 p3 p4 p5 p6
|
||||
|
||||
front-panel ports
|
||||
|
||||
|
||||
front-panel ports
|
||||
|
||||
|
||||
Fig 1.
|
||||
|
||||
|
|
|
@ -188,7 +188,16 @@ netdev_budget
|
|||
|
||||
Maximum number of packets taken from all interfaces in one polling cycle (NAPI
|
||||
poll). In one polling cycle interfaces which are registered to polling are
|
||||
probed in a round-robin manner.
|
||||
probed in a round-robin manner. Also, a polling cycle may not exceed
|
||||
netdev_budget_usecs microseconds, even if netdev_budget has not been
|
||||
exhausted.
|
||||
|
||||
netdev_budget_usecs
|
||||
---------------------
|
||||
|
||||
Maximum number of microseconds in one NAPI polling cycle. Polling
|
||||
will exit when either netdev_budget_usecs have elapsed during the
|
||||
poll cycle or the number of packets processed reaches netdev_budget.
|
||||
|
||||
netdev_max_backlog
|
||||
------------------
|
||||
|
|
42
MAINTAINERS
42
MAINTAINERS
|
@ -896,12 +896,19 @@ F: arch/arm64/boot/dts/apm/
|
|||
APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
|
||||
M: Iyappan Subramanian <isubramanian@apm.com>
|
||||
M: Keyur Chudgar <kchudgar@apm.com>
|
||||
M: Quan Nguyen <qnguyen@apm.com>
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/apm/xgene/
|
||||
F: drivers/net/phy/mdio-xgene.c
|
||||
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
|
||||
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
|
||||
|
||||
APPLIED MICRO (APM) X-GENE SOC ETHERNET (V2) DRIVER
|
||||
M: Iyappan Subramanian <isubramanian@apm.com>
|
||||
M: Keyur Chudgar <kchudgar@apm.com>
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/apm/xgene-v2/
|
||||
|
||||
APPLIED MICRO (APM) X-GENE SOC PMU
|
||||
M: Tai Nguyen <ttnguyen@apm.com>
|
||||
S: Supported
|
||||
|
@ -2944,6 +2951,15 @@ W: http://www.linux-c6x.org/wiki/index.php/Main_Page
|
|||
S: Maintained
|
||||
F: arch/c6x/
|
||||
|
||||
CA8210 IEEE-802.15.4 RADIO DRIVER
|
||||
M: Harry Morris <h.morris@cascoda.com>
|
||||
M: linuxdev@cascoda.com
|
||||
L: linux-wpan@vger.kernel.org
|
||||
W: https://github.com/Cascoda/ca8210-linux.git
|
||||
S: Maintained
|
||||
F: drivers/net/ieee802154/ca8210.c
|
||||
F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
|
||||
|
||||
CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
|
||||
M: David Howells <dhowells@redhat.com>
|
||||
L: linux-cachefs@redhat.com (moderated for non-subscribers)
|
||||
|
@ -7884,7 +7900,7 @@ S: Maintained
|
|||
F: drivers/net/ethernet/marvell/mvneta.*
|
||||
|
||||
MARVELL MWIFIEX WIRELESS DRIVER
|
||||
M: Amitkumar Karwar <akarwar@marvell.com>
|
||||
M: Amitkumar Karwar <amitkarwar@gmail.com>
|
||||
M: Nishant Sarmukadam <nishants@marvell.com>
|
||||
M: Ganapathi Bhat <gbhat@marvell.com>
|
||||
M: Xinming Hu <huxm@marvell.com>
|
||||
|
@ -8829,12 +8845,12 @@ F: net/core/flow.c
|
|||
F: net/xfrm/
|
||||
F: net/key/
|
||||
F: net/ipv4/xfrm*
|
||||
F: net/ipv4/esp4.c
|
||||
F: net/ipv4/esp4*
|
||||
F: net/ipv4/ah4.c
|
||||
F: net/ipv4/ipcomp.c
|
||||
F: net/ipv4/ip_vti.c
|
||||
F: net/ipv6/xfrm*
|
||||
F: net/ipv6/esp6.c
|
||||
F: net/ipv6/esp6*
|
||||
F: net/ipv6/ah6.c
|
||||
F: net/ipv6/ipcomp6.c
|
||||
F: net/ipv6/ip6_vti.c
|
||||
|
@ -8888,8 +8904,6 @@ S: Supported
|
|||
F: drivers/net/ethernet/qlogic/netxen/
|
||||
|
||||
NFC SUBSYSTEM
|
||||
M: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
|
||||
M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
|
||||
M: Samuel Ortiz <sameo@linux.intel.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: linux-nfc@lists.01.org (subscribers-only)
|
||||
|
@ -11125,6 +11139,12 @@ F: include/linux/dma/dw.h
|
|||
F: include/linux/platform_data/dma-dw.h
|
||||
F: drivers/dma/dw/
|
||||
|
||||
SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
|
||||
M: Jie Deng <jiedeng@synopsys.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/synopsys/
|
||||
|
||||
SYNOPSYS DESIGNWARE I2C DRIVER
|
||||
M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
|
@ -12229,12 +12249,19 @@ F: Documentation/accounting/taskstats*
|
|||
F: include/linux/taskstats*
|
||||
F: kernel/taskstats.c
|
||||
|
||||
TC CLASSIFIER
|
||||
TC subsystem
|
||||
M: Jamal Hadi Salim <jhs@mojatatu.com>
|
||||
M: Cong Wang <xiyou.wangcong@gmail.com>
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: include/net/pkt_cls.h
|
||||
F: include/net/pkt_sched.h
|
||||
F: include/net/tc_act/
|
||||
F: include/uapi/linux/pkt_cls.h
|
||||
F: include/uapi/linux/pkt_sched.h
|
||||
F: include/uapi/linux/tc_act/
|
||||
F: include/uapi/linux/tc_ematch/
|
||||
F: net/sched/
|
||||
|
||||
TCP LOW PRIORITY MODULE
|
||||
|
@ -13330,8 +13357,11 @@ L: netdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: include/linux/virtio_vsock.h
|
||||
F: include/uapi/linux/virtio_vsock.h
|
||||
F: include/uapi/linux/vsockmon.h
|
||||
F: net/vmw_vsock/af_vsock_tap.c
|
||||
F: net/vmw_vsock/virtio_transport_common.c
|
||||
F: net/vmw_vsock/virtio_transport.c
|
||||
F: drivers/net/vsockmon.c
|
||||
F: drivers/vhost/vsock.c
|
||||
F: drivers/vhost/vsock.h
|
||||
|
||||
|
|
|
@ -99,4 +99,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
|
|
@ -42,18 +42,16 @@
|
|||
};
|
||||
|
||||
mac0: ethernet@1e660000 {
|
||||
compatible = "faraday,ftgmac100";
|
||||
compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
|
||||
reg = <0x1e660000 0x180>;
|
||||
interrupts = <2>;
|
||||
no-hw-checksum;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mac1: ethernet@1e680000 {
|
||||
compatible = "faraday,ftgmac100";
|
||||
compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
|
||||
reg = <0x1e680000 0x180>;
|
||||
interrupts = <3>;
|
||||
no-hw-checksum;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -33,18 +33,16 @@
|
|||
};
|
||||
|
||||
mac0: ethernet@1e660000 {
|
||||
compatible = "faraday,ftgmac100";
|
||||
compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
|
||||
reg = <0x1e660000 0x180>;
|
||||
interrupts = <2>;
|
||||
no-hw-checksum;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mac1: ethernet@1e680000 {
|
||||
compatible = "faraday,ftgmac100";
|
||||
compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
|
||||
reg = <0x1e680000 0x180>;
|
||||
interrupts = <3>;
|
||||
no-hw-checksum;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -98,6 +98,11 @@
|
|||
assigned-clocks = <&sys_ctrl HI6220_UART1_SRC>;
|
||||
assigned-clock-rates = <150000000>;
|
||||
status = "ok";
|
||||
|
||||
bluetooth {
|
||||
compatible = "ti,wl1835-st";
|
||||
enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
uart2: uart@f7112000 {
|
||||
|
|
|
@ -80,6 +80,7 @@ enum aarch64_insn_register_type {
|
|||
AARCH64_INSN_REGTYPE_RM,
|
||||
AARCH64_INSN_REGTYPE_RD,
|
||||
AARCH64_INSN_REGTYPE_RA,
|
||||
AARCH64_INSN_REGTYPE_RS,
|
||||
};
|
||||
|
||||
enum aarch64_insn_register {
|
||||
|
@ -188,6 +189,8 @@ enum aarch64_insn_ldst_type {
|
|||
AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
|
||||
AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
|
||||
AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
|
||||
AARCH64_INSN_LDST_LOAD_EX,
|
||||
AARCH64_INSN_LDST_STORE_EX,
|
||||
};
|
||||
|
||||
enum aarch64_insn_adsb_type {
|
||||
|
@ -240,6 +243,23 @@ enum aarch64_insn_logic_type {
|
|||
AARCH64_INSN_LOGIC_BIC_SETFLAGS
|
||||
};
|
||||
|
||||
enum aarch64_insn_prfm_type {
|
||||
AARCH64_INSN_PRFM_TYPE_PLD,
|
||||
AARCH64_INSN_PRFM_TYPE_PLI,
|
||||
AARCH64_INSN_PRFM_TYPE_PST,
|
||||
};
|
||||
|
||||
enum aarch64_insn_prfm_target {
|
||||
AARCH64_INSN_PRFM_TARGET_L1,
|
||||
AARCH64_INSN_PRFM_TARGET_L2,
|
||||
AARCH64_INSN_PRFM_TARGET_L3,
|
||||
};
|
||||
|
||||
enum aarch64_insn_prfm_policy {
|
||||
AARCH64_INSN_PRFM_POLICY_KEEP,
|
||||
AARCH64_INSN_PRFM_POLICY_STRM,
|
||||
};
|
||||
|
||||
#define __AARCH64_INSN_FUNCS(abbr, mask, val) \
|
||||
static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
|
||||
{ return (code & (mask)) == (val); } \
|
||||
|
@ -248,6 +268,7 @@ static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
|
|||
|
||||
__AARCH64_INSN_FUNCS(adr, 0x9F000000, 0x10000000)
|
||||
__AARCH64_INSN_FUNCS(adrp, 0x9F000000, 0x90000000)
|
||||
__AARCH64_INSN_FUNCS(prfm, 0x3FC00000, 0x39800000)
|
||||
__AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000)
|
||||
__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
|
||||
__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
|
||||
|
@ -357,6 +378,11 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
|
|||
int offset,
|
||||
enum aarch64_insn_variant variant,
|
||||
enum aarch64_insn_ldst_type type);
|
||||
u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg,
|
||||
enum aarch64_insn_register base,
|
||||
enum aarch64_insn_register state,
|
||||
enum aarch64_insn_size_type size,
|
||||
enum aarch64_insn_ldst_type type);
|
||||
u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
|
||||
enum aarch64_insn_register src,
|
||||
int imm, enum aarch64_insn_variant variant,
|
||||
|
@ -397,6 +423,10 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
|
|||
int shift,
|
||||
enum aarch64_insn_variant variant,
|
||||
enum aarch64_insn_logic_type type);
|
||||
u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
|
||||
enum aarch64_insn_prfm_type type,
|
||||
enum aarch64_insn_prfm_target target,
|
||||
enum aarch64_insn_prfm_policy policy);
|
||||
s32 aarch64_get_branch_offset(u32 insn);
|
||||
u32 aarch64_set_branch_offset(u32 insn, s32 offset);
|
||||
|
||||
|
|
|
@ -474,6 +474,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
|
|||
shift = 10;
|
||||
break;
|
||||
case AARCH64_INSN_REGTYPE_RM:
|
||||
case AARCH64_INSN_REGTYPE_RS:
|
||||
shift = 16;
|
||||
break;
|
||||
default:
|
||||
|
@ -757,6 +758,111 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
|
|||
offset >> shift);
|
||||
}
|
||||
|
||||
u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg,
|
||||
enum aarch64_insn_register base,
|
||||
enum aarch64_insn_register state,
|
||||
enum aarch64_insn_size_type size,
|
||||
enum aarch64_insn_ldst_type type)
|
||||
{
|
||||
u32 insn;
|
||||
|
||||
switch (type) {
|
||||
case AARCH64_INSN_LDST_LOAD_EX:
|
||||
insn = aarch64_insn_get_load_ex_value();
|
||||
break;
|
||||
case AARCH64_INSN_LDST_STORE_EX:
|
||||
insn = aarch64_insn_get_store_ex_value();
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unknown load/store exclusive encoding %d\n", __func__, type);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
insn = aarch64_insn_encode_ldst_size(size, insn);
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn,
|
||||
reg);
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
|
||||
base);
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn,
|
||||
AARCH64_INSN_REG_ZR);
|
||||
|
||||
return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RS, insn,
|
||||
state);
|
||||
}
|
||||
|
||||
static u32 aarch64_insn_encode_prfm_imm(enum aarch64_insn_prfm_type type,
|
||||
enum aarch64_insn_prfm_target target,
|
||||
enum aarch64_insn_prfm_policy policy,
|
||||
u32 insn)
|
||||
{
|
||||
u32 imm_type = 0, imm_target = 0, imm_policy = 0;
|
||||
|
||||
switch (type) {
|
||||
case AARCH64_INSN_PRFM_TYPE_PLD:
|
||||
break;
|
||||
case AARCH64_INSN_PRFM_TYPE_PLI:
|
||||
imm_type = BIT(0);
|
||||
break;
|
||||
case AARCH64_INSN_PRFM_TYPE_PST:
|
||||
imm_type = BIT(1);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unknown prfm type encoding %d\n", __func__, type);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
switch (target) {
|
||||
case AARCH64_INSN_PRFM_TARGET_L1:
|
||||
break;
|
||||
case AARCH64_INSN_PRFM_TARGET_L2:
|
||||
imm_target = BIT(0);
|
||||
break;
|
||||
case AARCH64_INSN_PRFM_TARGET_L3:
|
||||
imm_target = BIT(1);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unknown prfm target encoding %d\n", __func__, target);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
switch (policy) {
|
||||
case AARCH64_INSN_PRFM_POLICY_KEEP:
|
||||
break;
|
||||
case AARCH64_INSN_PRFM_POLICY_STRM:
|
||||
imm_policy = BIT(0);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unknown prfm policy encoding %d\n", __func__, policy);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
/* In this case, imm5 is encoded into Rt field. */
|
||||
insn &= ~GENMASK(4, 0);
|
||||
insn |= imm_policy | (imm_target << 1) | (imm_type << 3);
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
|
||||
enum aarch64_insn_prfm_type type,
|
||||
enum aarch64_insn_prfm_target target,
|
||||
enum aarch64_insn_prfm_policy policy)
|
||||
{
|
||||
u32 insn = aarch64_insn_get_prfm_value();
|
||||
|
||||
insn = aarch64_insn_encode_ldst_size(AARCH64_INSN_SIZE_64, insn);
|
||||
|
||||
insn = aarch64_insn_encode_prfm_imm(type, target, policy, insn);
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
|
||||
base);
|
||||
|
||||
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, 0);
|
||||
}
|
||||
|
||||
u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
|
||||
enum aarch64_insn_register src,
|
||||
int imm, enum aarch64_insn_variant variant,
|
||||
|
|
|
@ -83,6 +83,25 @@
|
|||
/* Rt = Rn[0]; Rt2 = Rn[8]; Rn += 16; */
|
||||
#define A64_POP(Rt, Rt2, Rn) A64_LS_PAIR(Rt, Rt2, Rn, 16, LOAD, POST_INDEX)
|
||||
|
||||
/* Load/store exclusive */
|
||||
#define A64_SIZE(sf) \
|
||||
((sf) ? AARCH64_INSN_SIZE_64 : AARCH64_INSN_SIZE_32)
|
||||
#define A64_LSX(sf, Rt, Rn, Rs, type) \
|
||||
aarch64_insn_gen_load_store_ex(Rt, Rn, Rs, A64_SIZE(sf), \
|
||||
AARCH64_INSN_LDST_##type)
|
||||
/* Rt = [Rn]; (atomic) */
|
||||
#define A64_LDXR(sf, Rt, Rn) \
|
||||
A64_LSX(sf, Rt, Rn, A64_ZR, LOAD_EX)
|
||||
/* [Rn] = Rt; (atomic) Rs = [state] */
|
||||
#define A64_STXR(sf, Rt, Rn, Rs) \
|
||||
A64_LSX(sf, Rt, Rn, Rs, STORE_EX)
|
||||
|
||||
/* Prefetch */
|
||||
#define A64_PRFM(Rn, type, target, policy) \
|
||||
aarch64_insn_gen_prefetch(Rn, AARCH64_INSN_PRFM_TYPE_##type, \
|
||||
AARCH64_INSN_PRFM_TARGET_##target, \
|
||||
AARCH64_INSN_PRFM_POLICY_##policy)
|
||||
|
||||
/* Add/subtract (immediate) */
|
||||
#define A64_ADDSUB_IMM(sf, Rd, Rn, imm12, type) \
|
||||
aarch64_insn_gen_add_sub_imm(Rd, Rn, imm12, \
|
||||
|
|
|
@ -321,6 +321,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
const s32 imm = insn->imm;
|
||||
const int i = insn - ctx->prog->insnsi;
|
||||
const bool is64 = BPF_CLASS(code) == BPF_ALU64;
|
||||
const bool isdw = BPF_SIZE(code) == BPF_DW;
|
||||
u8 jmp_cond;
|
||||
s32 jmp_offset;
|
||||
|
||||
|
@ -604,15 +605,6 @@ emit_cond_jmp:
|
|||
const struct bpf_insn insn1 = insn[1];
|
||||
u64 imm64;
|
||||
|
||||
if (insn1.code != 0 || insn1.src_reg != 0 ||
|
||||
insn1.dst_reg != 0 || insn1.off != 0) {
|
||||
/* Note: verifier in BPF core must catch invalid
|
||||
* instructions.
|
||||
*/
|
||||
pr_err_once("Invalid BPF_LD_IMM64 instruction\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
imm64 = (u64)insn1.imm << 32 | (u32)imm;
|
||||
emit_a64_mov_i64(dst, imm64, ctx);
|
||||
|
||||
|
@ -690,7 +682,16 @@ emit_cond_jmp:
|
|||
case BPF_STX | BPF_XADD | BPF_W:
|
||||
/* STX XADD: lock *(u64 *)(dst + off) += src */
|
||||
case BPF_STX | BPF_XADD | BPF_DW:
|
||||
goto notyet;
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_ADD(1, tmp, tmp, dst), ctx);
|
||||
emit(A64_PRFM(tmp, PST, L1, STRM), ctx);
|
||||
emit(A64_LDXR(isdw, tmp2, tmp), ctx);
|
||||
emit(A64_ADD(isdw, tmp2, tmp2, src), ctx);
|
||||
emit(A64_STXR(isdw, tmp2, tmp, tmp2), ctx);
|
||||
jmp_offset = -3;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(0, tmp2, jmp_offset), ctx);
|
||||
break;
|
||||
|
||||
/* R0 = ntohx(*(size *)(((struct sk_buff *)R6)->data + imm)) */
|
||||
case BPF_LD | BPF_ABS | BPF_W:
|
||||
|
@ -757,10 +758,6 @@ emit_cond_jmp:
|
|||
}
|
||||
break;
|
||||
}
|
||||
notyet:
|
||||
pr_info_once("*** NOT YET: opcode %02x ***\n", code);
|
||||
return -EFAULT;
|
||||
|
||||
default:
|
||||
pr_err_once("unknown opcode %02x\n", code);
|
||||
return -EINVAL;
|
||||
|
@ -779,14 +776,14 @@ static int build_body(struct jit_ctx *ctx)
|
|||
int ret;
|
||||
|
||||
ret = build_insn(insn, ctx);
|
||||
|
||||
if (ctx->image == NULL)
|
||||
ctx->offset[i] = ctx->idx;
|
||||
|
||||
if (ret > 0) {
|
||||
i++;
|
||||
if (ctx->image == NULL)
|
||||
ctx->offset[i] = ctx->idx;
|
||||
continue;
|
||||
}
|
||||
if (ctx->image == NULL)
|
||||
ctx->offset[i] = ctx->idx;
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -92,5 +92,11 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
|
||||
|
|
|
@ -101,4 +101,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_IA64_SOCKET_H */
|
||||
|
|
|
@ -92,4 +92,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_M32R_SOCKET_H */
|
||||
|
|
|
@ -110,4 +110,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
|
|
@ -92,4 +92,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
|
|
|
@ -91,4 +91,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 0x402F
|
||||
|
||||
#define SO_MEMINFO 0x4030
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 0x4031
|
||||
|
||||
#define SO_COOKIE 0x4032
|
||||
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
|
|
@ -99,4 +99,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_POWERPC_SOCKET_H */
|
||||
|
|
|
@ -98,4 +98,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
|
|
|
@ -31,7 +31,8 @@ config SPARC
|
|||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select GENERIC_PCI_IOMAP
|
||||
select HAVE_NMI_WATCHDOG if SPARC64
|
||||
select HAVE_CBPF_JIT
|
||||
select HAVE_CBPF_JIT if SPARC32
|
||||
select HAVE_EBPF_JIT if SPARC64
|
||||
select HAVE_DEBUG_BUGVERBOSE
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_CLOCKEVENTS
|
||||
|
|
|
@ -88,6 +88,12 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 0x0038
|
||||
|
||||
#define SO_MEMINFO 0x0039
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 0x003a
|
||||
|
||||
#define SO_COOKIE 0x003b
|
||||
|
||||
/* Security levels - as per NRL IPv6 - don't actually do anything */
|
||||
#define SO_SECURITY_AUTHENTICATION 0x5001
|
||||
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#
|
||||
# Arch-specific network modules
|
||||
#
|
||||
obj-$(CONFIG_BPF_JIT) += bpf_jit_asm.o bpf_jit_comp.o
|
||||
obj-$(CONFIG_BPF_JIT) += bpf_jit_asm_$(BITS).o bpf_jit_comp_$(BITS).o
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#define r_TMP2 G2
|
||||
#define r_OFF G3
|
||||
|
||||
/* assembly code in arch/sparc/net/bpf_jit_asm.S */
|
||||
/* assembly code in arch/sparc/net/bpf_jit_asm_32.S */
|
||||
extern u32 bpf_jit_load_word[];
|
||||
extern u32 bpf_jit_load_half[];
|
||||
extern u32 bpf_jit_load_byte[];
|
66
arch/sparc/net/bpf_jit_64.h
Normal file
66
arch/sparc/net/bpf_jit_64.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#ifndef _BPF_JIT_H
|
||||
#define _BPF_JIT_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#define G0 0x00
|
||||
#define G1 0x01
|
||||
#define G2 0x02
|
||||
#define G3 0x03
|
||||
#define G6 0x06
|
||||
#define G7 0x07
|
||||
#define O0 0x08
|
||||
#define O1 0x09
|
||||
#define O2 0x0a
|
||||
#define O3 0x0b
|
||||
#define O4 0x0c
|
||||
#define O5 0x0d
|
||||
#define SP 0x0e
|
||||
#define O7 0x0f
|
||||
#define L0 0x10
|
||||
#define L1 0x11
|
||||
#define L2 0x12
|
||||
#define L3 0x13
|
||||
#define L4 0x14
|
||||
#define L5 0x15
|
||||
#define L6 0x16
|
||||
#define L7 0x17
|
||||
#define I0 0x18
|
||||
#define I1 0x19
|
||||
#define I2 0x1a
|
||||
#define I3 0x1b
|
||||
#define I4 0x1c
|
||||
#define I5 0x1d
|
||||
#define FP 0x1e
|
||||
#define I7 0x1f
|
||||
|
||||
#define r_SKB L0
|
||||
#define r_HEADLEN L4
|
||||
#define r_SKB_DATA L5
|
||||
#define r_TMP G1
|
||||
#define r_TMP2 G3
|
||||
|
||||
/* assembly code in arch/sparc/net/bpf_jit_asm_64.S */
|
||||
extern u32 bpf_jit_load_word[];
|
||||
extern u32 bpf_jit_load_half[];
|
||||
extern u32 bpf_jit_load_byte[];
|
||||
extern u32 bpf_jit_load_byte_msh[];
|
||||
extern u32 bpf_jit_load_word_positive_offset[];
|
||||
extern u32 bpf_jit_load_half_positive_offset[];
|
||||
extern u32 bpf_jit_load_byte_positive_offset[];
|
||||
extern u32 bpf_jit_load_byte_msh_positive_offset[];
|
||||
extern u32 bpf_jit_load_word_negative_offset[];
|
||||
extern u32 bpf_jit_load_half_negative_offset[];
|
||||
extern u32 bpf_jit_load_byte_negative_offset[];
|
||||
extern u32 bpf_jit_load_byte_msh_negative_offset[];
|
||||
|
||||
#else
|
||||
#define r_RESULT %o0
|
||||
#define r_SKB %o0
|
||||
#define r_OFF %o1
|
||||
#define r_HEADLEN %l4
|
||||
#define r_SKB_DATA %l5
|
||||
#define r_TMP %g1
|
||||
#define r_TMP2 %g3
|
||||
#endif
|
||||
|
||||
#endif /* _BPF_JIT_H */
|
|
@ -1,18 +1,11 @@
|
|||
#include <asm/ptrace.h>
|
||||
|
||||
#include "bpf_jit.h"
|
||||
#include "bpf_jit_32.h"
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
#define SAVE_SZ 176
|
||||
#define SCRATCH_OFF STACK_BIAS + 128
|
||||
#define BE_PTR(label) be,pn %xcc, label
|
||||
#define SIGN_EXTEND(reg) sra reg, 0, reg
|
||||
#else
|
||||
#define SAVE_SZ 96
|
||||
#define SCRATCH_OFF 72
|
||||
#define BE_PTR(label) be label
|
||||
#define SIGN_EXTEND(reg)
|
||||
#endif
|
||||
|
||||
#define SKF_MAX_NEG_OFF (-0x200000) /* SKF_LL_OFF from filter.h */
|
||||
|
161
arch/sparc/net/bpf_jit_asm_64.S
Normal file
161
arch/sparc/net/bpf_jit_asm_64.S
Normal file
|
@ -0,0 +1,161 @@
|
|||
#include <asm/ptrace.h>
|
||||
|
||||
#include "bpf_jit_64.h"
|
||||
|
||||
#define SAVE_SZ 176
|
||||
#define SCRATCH_OFF STACK_BIAS + 128
|
||||
#define BE_PTR(label) be,pn %xcc, label
|
||||
#define SIGN_EXTEND(reg) sra reg, 0, reg
|
||||
|
||||
#define SKF_MAX_NEG_OFF (-0x200000) /* SKF_LL_OFF from filter.h */
|
||||
|
||||
.text
|
||||
.globl bpf_jit_load_word
|
||||
bpf_jit_load_word:
|
||||
cmp r_OFF, 0
|
||||
bl bpf_slow_path_word_neg
|
||||
nop
|
||||
.globl bpf_jit_load_word_positive_offset
|
||||
bpf_jit_load_word_positive_offset:
|
||||
sub r_HEADLEN, r_OFF, r_TMP
|
||||
cmp r_TMP, 3
|
||||
ble bpf_slow_path_word
|
||||
add r_SKB_DATA, r_OFF, r_TMP
|
||||
andcc r_TMP, 3, %g0
|
||||
bne load_word_unaligned
|
||||
nop
|
||||
retl
|
||||
ld [r_TMP], r_RESULT
|
||||
load_word_unaligned:
|
||||
ldub [r_TMP + 0x0], r_OFF
|
||||
ldub [r_TMP + 0x1], r_TMP2
|
||||
sll r_OFF, 8, r_OFF
|
||||
or r_OFF, r_TMP2, r_OFF
|
||||
ldub [r_TMP + 0x2], r_TMP2
|
||||
sll r_OFF, 8, r_OFF
|
||||
or r_OFF, r_TMP2, r_OFF
|
||||
ldub [r_TMP + 0x3], r_TMP2
|
||||
sll r_OFF, 8, r_OFF
|
||||
retl
|
||||
or r_OFF, r_TMP2, r_RESULT
|
||||
|
||||
.globl bpf_jit_load_half
|
||||
bpf_jit_load_half:
|
||||
cmp r_OFF, 0
|
||||
bl bpf_slow_path_half_neg
|
||||
nop
|
||||
.globl bpf_jit_load_half_positive_offset
|
||||
bpf_jit_load_half_positive_offset:
|
||||
sub r_HEADLEN, r_OFF, r_TMP
|
||||
cmp r_TMP, 1
|
||||
ble bpf_slow_path_half
|
||||
add r_SKB_DATA, r_OFF, r_TMP
|
||||
andcc r_TMP, 1, %g0
|
||||
bne load_half_unaligned
|
||||
nop
|
||||
retl
|
||||
lduh [r_TMP], r_RESULT
|
||||
load_half_unaligned:
|
||||
ldub [r_TMP + 0x0], r_OFF
|
||||
ldub [r_TMP + 0x1], r_TMP2
|
||||
sll r_OFF, 8, r_OFF
|
||||
retl
|
||||
or r_OFF, r_TMP2, r_RESULT
|
||||
|
||||
.globl bpf_jit_load_byte
|
||||
bpf_jit_load_byte:
|
||||
cmp r_OFF, 0
|
||||
bl bpf_slow_path_byte_neg
|
||||
nop
|
||||
.globl bpf_jit_load_byte_positive_offset
|
||||
bpf_jit_load_byte_positive_offset:
|
||||
cmp r_OFF, r_HEADLEN
|
||||
bge bpf_slow_path_byte
|
||||
nop
|
||||
retl
|
||||
ldub [r_SKB_DATA + r_OFF], r_RESULT
|
||||
|
||||
#define bpf_slow_path_common(LEN) \
|
||||
save %sp, -SAVE_SZ, %sp; \
|
||||
mov %i0, %o0; \
|
||||
mov %i1, %o1; \
|
||||
add %fp, SCRATCH_OFF, %o2; \
|
||||
call skb_copy_bits; \
|
||||
mov (LEN), %o3; \
|
||||
cmp %o0, 0; \
|
||||
restore;
|
||||
|
||||
bpf_slow_path_word:
|
||||
bpf_slow_path_common(4)
|
||||
bl bpf_error
|
||||
ld [%sp + SCRATCH_OFF], r_RESULT
|
||||
retl
|
||||
nop
|
||||
bpf_slow_path_half:
|
||||
bpf_slow_path_common(2)
|
||||
bl bpf_error
|
||||
lduh [%sp + SCRATCH_OFF], r_RESULT
|
||||
retl
|
||||
nop
|
||||
bpf_slow_path_byte:
|
||||
bpf_slow_path_common(1)
|
||||
bl bpf_error
|
||||
ldub [%sp + SCRATCH_OFF], r_RESULT
|
||||
retl
|
||||
nop
|
||||
|
||||
#define bpf_negative_common(LEN) \
|
||||
save %sp, -SAVE_SZ, %sp; \
|
||||
mov %i0, %o0; \
|
||||
mov %i1, %o1; \
|
||||
SIGN_EXTEND(%o1); \
|
||||
call bpf_internal_load_pointer_neg_helper; \
|
||||
mov (LEN), %o2; \
|
||||
mov %o0, r_TMP; \
|
||||
cmp %o0, 0; \
|
||||
BE_PTR(bpf_error); \
|
||||
restore;
|
||||
|
||||
bpf_slow_path_word_neg:
|
||||
sethi %hi(SKF_MAX_NEG_OFF), r_TMP
|
||||
cmp r_OFF, r_TMP
|
||||
bl bpf_error
|
||||
nop
|
||||
.globl bpf_jit_load_word_negative_offset
|
||||
bpf_jit_load_word_negative_offset:
|
||||
bpf_negative_common(4)
|
||||
andcc r_TMP, 3, %g0
|
||||
bne load_word_unaligned
|
||||
nop
|
||||
retl
|
||||
ld [r_TMP], r_RESULT
|
||||
|
||||
bpf_slow_path_half_neg:
|
||||
sethi %hi(SKF_MAX_NEG_OFF), r_TMP
|
||||
cmp r_OFF, r_TMP
|
||||
bl bpf_error
|
||||
nop
|
||||
.globl bpf_jit_load_half_negative_offset
|
||||
bpf_jit_load_half_negative_offset:
|
||||
bpf_negative_common(2)
|
||||
andcc r_TMP, 1, %g0
|
||||
bne load_half_unaligned
|
||||
nop
|
||||
retl
|
||||
lduh [r_TMP], r_RESULT
|
||||
|
||||
bpf_slow_path_byte_neg:
|
||||
sethi %hi(SKF_MAX_NEG_OFF), r_TMP
|
||||
cmp r_OFF, r_TMP
|
||||
bl bpf_error
|
||||
nop
|
||||
.globl bpf_jit_load_byte_negative_offset
|
||||
bpf_jit_load_byte_negative_offset:
|
||||
bpf_negative_common(1)
|
||||
retl
|
||||
ldub [r_TMP], r_RESULT
|
||||
|
||||
bpf_error:
|
||||
/* Make the JIT program itself return zero. */
|
||||
ret
|
||||
restore %g0, %g0, %o0
|
|
@ -8,7 +8,7 @@
|
|||
#include <asm/cacheflush.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "bpf_jit.h"
|
||||
#include "bpf_jit_32.h"
|
||||
|
||||
int bpf_jit_enable __read_mostly;
|
||||
|
||||
|
@ -17,24 +17,6 @@ static inline bool is_simm13(unsigned int value)
|
|||
return value + 0x1000 < 0x2000;
|
||||
}
|
||||
|
||||
static void bpf_flush_icache(void *start_, void *end_)
|
||||
{
|
||||
#ifdef CONFIG_SPARC64
|
||||
/* Cheetah's I-cache is fully coherent. */
|
||||
if (tlb_type == spitfire) {
|
||||
unsigned long start = (unsigned long) start_;
|
||||
unsigned long end = (unsigned long) end_;
|
||||
|
||||
start &= ~7UL;
|
||||
end = (end + 7UL) & ~7UL;
|
||||
while (start < end) {
|
||||
flushi(start);
|
||||
start += 32;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SEEN_DATAREF 1 /* might call external helpers */
|
||||
#define SEEN_XREG 2 /* ebx is used */
|
||||
#define SEEN_MEM 4 /* use mem[] for temporary storage */
|
||||
|
@ -82,11 +64,7 @@ static void bpf_flush_icache(void *start_, void *end_)
|
|||
#define BE (F2(0, 2) | CONDE)
|
||||
#define BNE (F2(0, 2) | CONDNE)
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
#define BE_PTR (F2(0, 1) | CONDE | (2 << 20))
|
||||
#else
|
||||
#define BE_PTR BE
|
||||
#endif
|
||||
|
||||
#define SETHI(K, REG) \
|
||||
(F2(0, 0x4) | RD(REG) | (((K) >> 10) & 0x3fffff))
|
||||
|
@ -116,13 +94,8 @@ static void bpf_flush_icache(void *start_, void *end_)
|
|||
#define LD64 F3(3, 0x0b)
|
||||
#define ST32 F3(3, 0x04)
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
#define LDPTR LD64
|
||||
#define BASE_STACKFRAME 176
|
||||
#else
|
||||
#define LDPTR LD32
|
||||
#define BASE_STACKFRAME 96
|
||||
#endif
|
||||
|
||||
#define LD32I (LD32 | IMMED)
|
||||
#define LD8I (LD8 | IMMED)
|
||||
|
@ -234,11 +207,7 @@ do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \
|
|||
__emit_load8(BASE, STRUCT, FIELD, DEST); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
#define BIAS (STACK_BIAS - 4)
|
||||
#else
|
||||
#define BIAS (-4)
|
||||
#endif
|
||||
|
||||
#define emit_ldmem(OFF, DEST) \
|
||||
do { *prog++ = LD32I | RS1(SP) | S13(BIAS - (OFF)) | RD(DEST); \
|
||||
|
@ -249,13 +218,8 @@ do { *prog++ = ST32I | RS1(SP) | S13(BIAS - (OFF)) | RD(SRC); \
|
|||
} while (0)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#ifdef CONFIG_SPARC64
|
||||
#define emit_load_cpu(REG) \
|
||||
emit_load16(G6, struct thread_info, cpu, REG)
|
||||
#else
|
||||
#define emit_load_cpu(REG) \
|
||||
emit_load32(G6, struct thread_info, cpu, REG)
|
||||
#endif
|
||||
#else
|
||||
#define emit_load_cpu(REG) emit_clear(REG)
|
||||
#endif
|
||||
|
@ -486,7 +450,6 @@ void bpf_jit_compile(struct bpf_prog *fp)
|
|||
if (K == 1)
|
||||
break;
|
||||
emit_write_y(G0);
|
||||
#ifdef CONFIG_SPARC32
|
||||
/* The Sparc v8 architecture requires
|
||||
* three instructions between a %y
|
||||
* register write and the first use.
|
||||
|
@ -494,31 +457,21 @@ void bpf_jit_compile(struct bpf_prog *fp)
|
|||
emit_nop();
|
||||
emit_nop();
|
||||
emit_nop();
|
||||
#endif
|
||||
emit_alu_K(DIV, K);
|
||||
break;
|
||||
case BPF_ALU | BPF_DIV | BPF_X: /* A /= X; */
|
||||
emit_cmpi(r_X, 0);
|
||||
if (pc_ret0 > 0) {
|
||||
t_offset = addrs[pc_ret0 - 1];
|
||||
#ifdef CONFIG_SPARC32
|
||||
emit_branch(BE, t_offset + 20);
|
||||
#else
|
||||
emit_branch(BE, t_offset + 8);
|
||||
#endif
|
||||
emit_nop(); /* delay slot */
|
||||
} else {
|
||||
emit_branch_off(BNE, 16);
|
||||
emit_nop();
|
||||
#ifdef CONFIG_SPARC32
|
||||
emit_jump(cleanup_addr + 20);
|
||||
#else
|
||||
emit_jump(cleanup_addr + 8);
|
||||
#endif
|
||||
emit_clear(r_A);
|
||||
}
|
||||
emit_write_y(G0);
|
||||
#ifdef CONFIG_SPARC32
|
||||
/* The Sparc v8 architecture requires
|
||||
* three instructions between a %y
|
||||
* register write and the first use.
|
||||
|
@ -526,7 +479,6 @@ void bpf_jit_compile(struct bpf_prog *fp)
|
|||
emit_nop();
|
||||
emit_nop();
|
||||
emit_nop();
|
||||
#endif
|
||||
emit_alu_X(DIV);
|
||||
break;
|
||||
case BPF_ALU | BPF_NEG:
|
||||
|
@ -797,7 +749,6 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
|
|||
bpf_jit_dump(flen, proglen, pass + 1, image);
|
||||
|
||||
if (image) {
|
||||
bpf_flush_icache(image, image + proglen);
|
||||
fp->bpf_func = (void *)image;
|
||||
fp->jited = 1;
|
||||
}
|
1566
arch/sparc/net/bpf_jit_comp_64.c
Normal file
1566
arch/sparc/net/bpf_jit_comp_64.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -490,13 +490,6 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
|||
break;
|
||||
|
||||
case BPF_LD | BPF_IMM | BPF_DW:
|
||||
if (insn[1].code != 0 || insn[1].src_reg != 0 ||
|
||||
insn[1].dst_reg != 0 || insn[1].off != 0) {
|
||||
/* verifier must catch invalid insns */
|
||||
pr_err("invalid BPF_LD_IMM64 insn\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* optimization: if imm64 is zero, use 'xor <dst>,<dst>'
|
||||
* to save 7 bytes.
|
||||
*/
|
||||
|
|
|
@ -103,4 +103,10 @@
|
|||
|
||||
#define SCM_TIMESTAMPING_OPT_STATS 54
|
||||
|
||||
#define SO_MEMINFO 55
|
||||
|
||||
#define SO_INCOMING_NAPI_ID 56
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _XTENSA_SOCKET_H */
|
||||
|
|
|
@ -483,7 +483,8 @@ static const struct crypto_link {
|
|||
[CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
|
||||
};
|
||||
|
||||
static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *attrs[CRYPTOCFGA_MAX+1];
|
||||
const struct crypto_link *link;
|
||||
|
@ -522,7 +523,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
}
|
||||
|
||||
err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
|
||||
crypto_policy);
|
||||
crypto_policy, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -2267,9 +2267,8 @@ static int amb_probe(struct pci_dev *pci_dev,
|
|||
dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
|
||||
dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
|
||||
|
||||
init_timer(&dev->housekeeping);
|
||||
dev->housekeeping.function = do_housekeeping;
|
||||
dev->housekeeping.data = (unsigned long) dev;
|
||||
setup_timer(&dev->housekeeping, do_housekeeping,
|
||||
(unsigned long)dev);
|
||||
mod_timer(&dev->housekeeping, jiffies);
|
||||
|
||||
// enable host interrupts
|
||||
|
|
|
@ -185,8 +185,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
|
|||
chip->owner = THIS_MODULE;
|
||||
chip->parent = bcma_bus_get_host_dev(bus);
|
||||
#if IS_BUILTIN(CONFIG_OF)
|
||||
if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
#endif
|
||||
switch (bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
|
|
|
@ -201,9 +201,6 @@ static void bcma_of_fill_device(struct device *parent,
|
|||
{
|
||||
struct device_node *node;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF_IRQ))
|
||||
return;
|
||||
|
||||
node = bcma_of_find_child_device(parent, core);
|
||||
if (node)
|
||||
core->dev.of_node = node;
|
||||
|
@ -242,19 +239,18 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
|
|||
core->dev.release = bcma_release_core_dev;
|
||||
core->dev.bus = &bcma_bus_type;
|
||||
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
|
||||
core->dev.parent = bcma_bus_get_host_dev(bus);
|
||||
if (core->dev.parent)
|
||||
bcma_of_fill_device(core->dev.parent, core);
|
||||
|
||||
switch (bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
core->dev.parent = &bus->host_pci->dev;
|
||||
core->dma_dev = &bus->host_pci->dev;
|
||||
core->irq = bus->host_pci->irq;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_SOC:
|
||||
if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
|
||||
core->dma_dev = &bus->host_pdev->dev;
|
||||
core->dev.parent = &bus->host_pdev->dev;
|
||||
if (core->dev.parent)
|
||||
bcma_of_fill_device(core->dev.parent, core);
|
||||
} else {
|
||||
core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
core->dma_dev = &core->dev;
|
||||
|
|
|
@ -34,7 +34,7 @@ int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
|||
|
||||
err = drbd_nla_check_mandatory(maxtype, nla);
|
||||
if (!err)
|
||||
err = nla_parse_nested(tb, maxtype, nla, policy);
|
||||
err = nla_parse_nested(tb, maxtype, nla, policy, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1662,7 +1662,7 @@ again:
|
|||
goto out;
|
||||
}
|
||||
ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
|
||||
nbd_sock_policy);
|
||||
nbd_sock_policy, info->extack);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "nbd: error processing sock list\n");
|
||||
ret = -EINVAL;
|
||||
|
@ -1818,7 +1818,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
|
|||
goto out;
|
||||
}
|
||||
ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
|
||||
nbd_sock_policy);
|
||||
nbd_sock_policy, info->extack);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "nbd: error processing sock list\n");
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -76,6 +76,12 @@ config BT_HCIUART
|
|||
Say Y here to compile support for Bluetooth UART devices into the
|
||||
kernel or say M to compile it as module (hci_uart).
|
||||
|
||||
config BT_HCIUART_SERDEV
|
||||
bool
|
||||
depends on SERIAL_DEV_BUS && BT_HCIUART
|
||||
depends on SERIAL_DEV_BUS=y || SERIAL_DEV_BUS=BT_HCIUART
|
||||
default y
|
||||
|
||||
config BT_HCIUART_H4
|
||||
bool "UART (H4) protocol support"
|
||||
depends on BT_HCIUART
|
||||
|
@ -86,6 +92,18 @@ config BT_HCIUART_H4
|
|||
|
||||
Say Y here to compile support for HCI UART (H4) protocol.
|
||||
|
||||
config BT_HCIUART_NOKIA
|
||||
tristate "UART Nokia H4+ protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
depends on PM
|
||||
help
|
||||
Nokia H4+ is serial protocol for communication between Bluetooth
|
||||
device and host. This protocol is required for Bluetooth devices
|
||||
with UART interface in Nokia devices.
|
||||
|
||||
Say Y here to compile support for Nokia's H4+ protocol.
|
||||
|
||||
config BT_HCIUART_BCSP
|
||||
bool "BCSP protocol support"
|
||||
depends on BT_HCIUART
|
||||
|
@ -344,7 +362,7 @@ config BT_WILINK
|
|||
|
||||
config BT_QCOMSMD
|
||||
tristate "Qualcomm SMD based HCI support"
|
||||
depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n)
|
||||
depends on RPMSG || (COMPILE_TEST && RPMSG=n)
|
||||
depends on QCOM_WCNSS_CTRL || (COMPILE_TEST && QCOM_WCNSS_CTRL=n)
|
||||
select BT_QCA
|
||||
help
|
||||
|
|
|
@ -25,10 +25,13 @@ obj-$(CONFIG_BT_BCM) += btbcm.o
|
|||
obj-$(CONFIG_BT_RTL) += btrtl.o
|
||||
obj-$(CONFIG_BT_QCA) += btqca.o
|
||||
|
||||
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
|
||||
|
||||
btmrvl-y := btmrvl_main.o
|
||||
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
|
||||
|
||||
hci_uart-y := hci_ldisc.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_SERDEV) += hci_serdev.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
|
||||
|
|
|
@ -695,9 +695,8 @@ static int bluecard_open(struct bluecard_info *info)
|
|||
|
||||
spin_lock_init(&(info->lock));
|
||||
|
||||
init_timer(&(info->timer));
|
||||
info->timer.function = &bluecard_activity_led_timeout;
|
||||
info->timer.data = (u_long)info;
|
||||
setup_timer(&(info->timer), &bluecard_activity_led_timeout,
|
||||
(u_long)info);
|
||||
|
||||
skb_queue_head_init(&(info->txq));
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
|
@ -60,13 +61,15 @@ static const struct of_device_id btmrvl_sdio_of_match_table[] = {
|
|||
|
||||
static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
|
||||
{
|
||||
struct btmrvl_plt_wake_cfg *cfg = priv;
|
||||
struct btmrvl_sdio_card *card = priv;
|
||||
struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
|
||||
|
||||
if (cfg->irq_bt >= 0) {
|
||||
pr_info("%s: wake by bt", __func__);
|
||||
cfg->wake_by_bt = true;
|
||||
disable_irq_nosync(irq);
|
||||
}
|
||||
pr_info("%s: wake by bt", __func__);
|
||||
cfg->wake_by_bt = true;
|
||||
disable_irq_nosync(irq);
|
||||
|
||||
pm_wakeup_event(&card->func->dev, 0);
|
||||
pm_system_wakeup();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -101,7 +104,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
|
|||
} else {
|
||||
ret = devm_request_irq(dev, cfg->irq_bt,
|
||||
btmrvl_wake_irq_bt,
|
||||
0, "bt_wake", cfg);
|
||||
0, "bt_wake", card);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to request irq_bt %d (%d)\n",
|
||||
|
@ -1574,7 +1577,7 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
|
|||
MODULE_SHUTDOWN_REQ);
|
||||
btmrvl_sdio_disable_host_int(card);
|
||||
}
|
||||
BT_DBG("unregester dev");
|
||||
BT_DBG("unregister dev");
|
||||
card->priv->surprise_removed = true;
|
||||
btmrvl_sdio_unregister_dev(card);
|
||||
btmrvl_remove_card(card->priv);
|
||||
|
@ -1625,6 +1628,13 @@ static int btmrvl_sdio_suspend(struct device *dev)
|
|||
if (priv->adapter->hs_state != HS_ACTIVATED) {
|
||||
if (btmrvl_enable_hs(priv)) {
|
||||
BT_ERR("HS not activated, suspend failed!");
|
||||
/* 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);
|
||||
disable_irq(card->plt_wake_cfg->irq_bt);
|
||||
}
|
||||
|
||||
priv->adapter->is_suspending = false;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -1637,10 +1647,10 @@ static int btmrvl_sdio_suspend(struct device *dev)
|
|||
if (priv->adapter->hs_state == HS_ACTIVATED) {
|
||||
BT_DBG("suspend with MMC_PM_KEEP_POWER");
|
||||
return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
} else {
|
||||
BT_DBG("suspend without MMC_PM_KEEP_POWER");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_DBG("suspend without MMC_PM_KEEP_POWER");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btmrvl_sdio_resume(struct device *dev)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/smd.h>
|
||||
#include <linux/rpmsg.h>
|
||||
#include <linux/soc/qcom/wcnss_ctrl.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
|
@ -26,8 +26,8 @@
|
|||
struct btqcomsmd {
|
||||
struct hci_dev *hdev;
|
||||
|
||||
struct qcom_smd_channel *acl_channel;
|
||||
struct qcom_smd_channel *cmd_channel;
|
||||
struct rpmsg_endpoint *acl_channel;
|
||||
struct rpmsg_endpoint *cmd_channel;
|
||||
};
|
||||
|
||||
static int btqcomsmd_recv(struct hci_dev *hdev, unsigned int type,
|
||||
|
@ -48,19 +48,19 @@ static int btqcomsmd_recv(struct hci_dev *hdev, unsigned int type,
|
|||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
static int btqcomsmd_acl_callback(struct qcom_smd_channel *channel,
|
||||
const void *data, size_t count)
|
||||
static int btqcomsmd_acl_callback(struct rpmsg_device *rpdev, void *data,
|
||||
int count, void *priv, u32 addr)
|
||||
{
|
||||
struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
|
||||
struct btqcomsmd *btq = priv;
|
||||
|
||||
btq->hdev->stat.byte_rx += count;
|
||||
return btqcomsmd_recv(btq->hdev, HCI_ACLDATA_PKT, data, count);
|
||||
}
|
||||
|
||||
static int btqcomsmd_cmd_callback(struct qcom_smd_channel *channel,
|
||||
const void *data, size_t count)
|
||||
static int btqcomsmd_cmd_callback(struct rpmsg_device *rpdev, void *data,
|
||||
int count, void *priv, u32 addr)
|
||||
{
|
||||
struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
|
||||
struct btqcomsmd *btq = priv;
|
||||
|
||||
return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count);
|
||||
}
|
||||
|
@ -72,12 +72,12 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
switch (hci_skb_pkt_type(skb)) {
|
||||
case HCI_ACLDATA_PKT:
|
||||
ret = qcom_smd_send(btq->acl_channel, skb->data, skb->len);
|
||||
ret = rpmsg_send(btq->acl_channel, skb->data, skb->len);
|
||||
hdev->stat.acl_tx++;
|
||||
hdev->stat.byte_tx += skb->len;
|
||||
break;
|
||||
case HCI_COMMAND_PKT:
|
||||
ret = qcom_smd_send(btq->cmd_channel, skb->data, skb->len);
|
||||
ret = rpmsg_send(btq->cmd_channel, skb->data, skb->len);
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
default:
|
||||
|
@ -114,18 +114,15 @@ static int btqcomsmd_probe(struct platform_device *pdev)
|
|||
wcnss = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
btq->acl_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_ACL",
|
||||
btqcomsmd_acl_callback);
|
||||
btqcomsmd_acl_callback, btq);
|
||||
if (IS_ERR(btq->acl_channel))
|
||||
return PTR_ERR(btq->acl_channel);
|
||||
|
||||
btq->cmd_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_CMD",
|
||||
btqcomsmd_cmd_callback);
|
||||
btqcomsmd_cmd_callback, btq);
|
||||
if (IS_ERR(btq->cmd_channel))
|
||||
return PTR_ERR(btq->cmd_channel);
|
||||
|
||||
qcom_smd_set_drvdata(btq->acl_channel, btq);
|
||||
qcom_smd_set_drvdata(btq->cmd_channel, btq);
|
||||
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev)
|
||||
return -ENOMEM;
|
||||
|
@ -158,6 +155,9 @@ static int btqcomsmd_remove(struct platform_device *pdev)
|
|||
hci_unregister_dev(btq->hdev);
|
||||
hci_free_dev(btq->hdev);
|
||||
|
||||
rpmsg_destroy_ept(btq->cmd_channel);
|
||||
rpmsg_destroy_ept(btq->acl_channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -275,11 +275,8 @@ static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff)
|
|||
|
||||
BT_INFO("%s: rtl: loading %s", hdev->name, name);
|
||||
ret = request_firmware(&fw, name, &hdev->dev);
|
||||
if (ret < 0) {
|
||||
BT_ERR("%s: Failed to load %s", hdev->name, name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fw->size;
|
||||
*buff = kmemdup(fw->data, ret, GFP_KERNEL);
|
||||
|
||||
|
@ -331,6 +328,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
|
|||
u8 *cfg_buff = NULL;
|
||||
u8 *tbuff;
|
||||
char *cfg_name = NULL;
|
||||
bool config_needed = false;
|
||||
|
||||
switch (lmp_subver) {
|
||||
case RTL_ROM_LMP_8723B:
|
||||
|
@ -344,6 +342,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
|
|||
break;
|
||||
case RTL_ROM_LMP_8822B:
|
||||
cfg_name = "rtl_bt/rtl8822b_config.bin";
|
||||
config_needed = true;
|
||||
break;
|
||||
default:
|
||||
BT_ERR("%s: rtl: no config according to lmp_subver %04x",
|
||||
|
@ -353,8 +352,12 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
|
|||
|
||||
if (cfg_name) {
|
||||
cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff);
|
||||
if (cfg_sz < 0)
|
||||
if (cfg_sz < 0) {
|
||||
cfg_sz = 0;
|
||||
if (config_needed)
|
||||
BT_ERR("Necessary config file %s not found\n",
|
||||
cfg_name);
|
||||
}
|
||||
} else
|
||||
cfg_sz = 0;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -262,6 +263,7 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME },
|
||||
{ USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME },
|
||||
|
@ -328,6 +330,7 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
|
||||
|
||||
/* Intel Bluetooth devices */
|
||||
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW },
|
||||
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
|
||||
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
|
||||
|
@ -2024,13 +2027,18 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* At the moment the iBT 3.0 hardware variants 0x0b (LnP/SfP)
|
||||
* and 0x0c (WsP) are supported by this firmware loading method.
|
||||
/* Check for supported iBT hardware variants of 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 && ver.hw_variant != 0x0c) {
|
||||
switch (ver.hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
case 0x12: /* ThP */
|
||||
break;
|
||||
default:
|
||||
BT_ERR("%s: Unsupported Intel hardware variant (%u)",
|
||||
hdev->name, ver.hw_variant);
|
||||
return -EINVAL;
|
||||
|
@ -2792,6 +2800,7 @@ static irqreturn_t btusb_oob_wake_handler(int irq, void *priv)
|
|||
struct btusb_data *data = priv;
|
||||
|
||||
pm_wakeup_event(&data->udev->dev, 0);
|
||||
pm_system_wakeup();
|
||||
|
||||
/* Disable only if not already disabled (keep it balanced) */
|
||||
if (test_and_clear_bit(BTUSB_OOB_WAKE_ENABLED, &data->flags)) {
|
||||
|
|
|
@ -146,13 +146,13 @@ static bool bcm_device_exists(struct bcm_device *device)
|
|||
static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
|
||||
{
|
||||
if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled)
|
||||
clk_enable(dev->clk);
|
||||
clk_prepare_enable(dev->clk);
|
||||
|
||||
gpiod_set_value(dev->shutdown, powered);
|
||||
gpiod_set_value(dev->device_wakeup, powered);
|
||||
|
||||
if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled)
|
||||
clk_disable(dev->clk);
|
||||
clk_disable_unprepare(dev->clk);
|
||||
|
||||
dev->clk_enabled = powered;
|
||||
|
||||
|
@ -287,6 +287,9 @@ static int bcm_open(struct hci_uart *hu)
|
|||
|
||||
hu->priv = bcm;
|
||||
|
||||
if (!hu->tty->dev)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&bcm_device_lock);
|
||||
list_for_each(p, &bcm_device_list) {
|
||||
struct bcm_device *dev = list_entry(p, struct bcm_device, list);
|
||||
|
@ -307,7 +310,7 @@ static int bcm_open(struct hci_uart *hu)
|
|||
}
|
||||
|
||||
mutex_unlock(&bcm_device_lock);
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -697,28 +700,14 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
|
|||
/* Always tell the ACPI core to skip this resource */
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int bcm_acpi_probe(struct bcm_device *dev)
|
||||
static int bcm_platform_probe(struct bcm_device *dev)
|
||||
{
|
||||
struct platform_device *pdev = dev->pdev;
|
||||
LIST_HEAD(resources);
|
||||
const struct dmi_system_id *dmi_id;
|
||||
const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios;
|
||||
const struct acpi_device_id *id;
|
||||
int ret;
|
||||
|
||||
dev->name = dev_name(&pdev->dev);
|
||||
|
||||
/* Retrieve GPIO data */
|
||||
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
|
||||
if (id)
|
||||
gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data;
|
||||
|
||||
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
||||
gpio_mapping);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
|
||||
dev->device_wakeup = devm_gpiod_get_optional(&pdev->dev,
|
||||
|
@ -755,6 +744,33 @@ static int bcm_acpi_probe(struct bcm_device *dev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static int bcm_acpi_probe(struct bcm_device *dev)
|
||||
{
|
||||
struct platform_device *pdev = dev->pdev;
|
||||
LIST_HEAD(resources);
|
||||
const struct dmi_system_id *dmi_id;
|
||||
const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios;
|
||||
const struct acpi_device_id *id;
|
||||
int ret;
|
||||
|
||||
/* Retrieve GPIO data */
|
||||
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
|
||||
if (id)
|
||||
gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data;
|
||||
|
||||
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
||||
gpio_mapping);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bcm_platform_probe(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Retrieve UART ACPI info */
|
||||
ret = acpi_dev_get_resources(ACPI_COMPANION(&dev->pdev->dev),
|
||||
&resources, bcm_resource, dev);
|
||||
|
@ -789,7 +805,10 @@ static int bcm_probe(struct platform_device *pdev)
|
|||
|
||||
dev->pdev = pdev;
|
||||
|
||||
ret = bcm_acpi_probe(dev);
|
||||
if (has_acpi_companion(&pdev->dev))
|
||||
ret = bcm_acpi_probe(dev);
|
||||
else
|
||||
ret = bcm_platform_probe(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -171,9 +171,20 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
|
|||
const unsigned char *buffer, int count,
|
||||
const struct h4_recv_pkt *pkts, int pkts_count)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
u8 alignment = hu->alignment;
|
||||
|
||||
while (count) {
|
||||
int i, len;
|
||||
|
||||
/* remove padding bytes from buffer */
|
||||
for (; hu->padding && count > 0; hu->padding--) {
|
||||
count--;
|
||||
buffer++;
|
||||
}
|
||||
if (!count)
|
||||
break;
|
||||
|
||||
if (!skb) {
|
||||
for (i = 0; i < pkts_count; i++) {
|
||||
if (buffer[0] != (&pkts[i])->type)
|
||||
|
@ -253,11 +264,17 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
if (!dlen) {
|
||||
hu->padding = (skb->len - 1) % alignment;
|
||||
hu->padding = (alignment - hu->padding) % alignment;
|
||||
|
||||
/* No more data, complete frame */
|
||||
(&pkts[i])->recv(hdev, skb);
|
||||
skb = NULL;
|
||||
}
|
||||
} else {
|
||||
hu->padding = (skb->len - 1) % alignment;
|
||||
hu->padding = (alignment - hu->padding) % alignment;
|
||||
|
||||
/* Complete frame */
|
||||
(&pkts[i])->recv(hdev, skb);
|
||||
skb = NULL;
|
||||
|
|
|
@ -307,6 +307,9 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
|
|||
struct list_head *p;
|
||||
int err = -ENODEV;
|
||||
|
||||
if (!hu->tty->dev)
|
||||
return err;
|
||||
|
||||
mutex_lock(&intel_device_list_lock);
|
||||
|
||||
list_for_each(p, &intel_device_list) {
|
||||
|
@ -379,6 +382,9 @@ static void intel_busy_work(struct work_struct *work)
|
|||
struct intel_data *intel = container_of(work, struct intel_data,
|
||||
busy_work);
|
||||
|
||||
if (!intel->hu->tty->dev)
|
||||
return;
|
||||
|
||||
/* Link is busy, delay the suspend */
|
||||
mutex_lock(&intel_device_list_lock);
|
||||
list_for_each(p, &intel_device_list) {
|
||||
|
@ -601,12 +607,18 @@ static int intel_setup(struct hci_uart *hu)
|
|||
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.
|
||||
*/
|
||||
if (ver.hw_variant != 0x0b) {
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (ver.hw_variant) {
|
||||
case 0x0b: /* LnP */
|
||||
case 0x0c: /* WsP */
|
||||
case 0x12: /* ThP */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||
ver.hw_variant);
|
||||
return -EINVAL;
|
||||
|
@ -699,11 +711,14 @@ static int intel_setup(struct hci_uart *hu)
|
|||
/* With this Intel bootloader only the hardware variant and device
|
||||
* revision information are used to select the right firmware.
|
||||
*
|
||||
* Currently this bootloader support is limited to hardware variant
|
||||
* iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
|
||||
* The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
|
||||
*
|
||||
* Currently the supported hardware variants are:
|
||||
* 11 (0x0b) for iBT 3.0 (LnP/SfP)
|
||||
*/
|
||||
snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
|
||||
le16_to_cpu(params->dev_revid));
|
||||
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
|
||||
le16_to_cpu(ver.hw_variant),
|
||||
le16_to_cpu(params->dev_revid));
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
|
@ -716,8 +731,9 @@ static int intel_setup(struct hci_uart *hu)
|
|||
bt_dev_info(hdev, "Found device firmware: %s", fwname);
|
||||
|
||||
/* Save the DDC file name for later */
|
||||
snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
|
||||
le16_to_cpu(params->dev_revid));
|
||||
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
|
||||
le16_to_cpu(ver.hw_variant),
|
||||
le16_to_cpu(params->dev_revid));
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
|
@ -889,6 +905,8 @@ done:
|
|||
list_for_each(p, &intel_device_list) {
|
||||
struct intel_device *dev = list_entry(p, struct intel_device,
|
||||
list);
|
||||
if (!hu->tty->dev)
|
||||
break;
|
||||
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
|
||||
if (device_may_wakeup(&dev->pdev->dev)) {
|
||||
set_bit(STATE_LPM_ENABLED, &intel->flags);
|
||||
|
@ -1056,6 +1074,9 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
|
||||
BT_DBG("hu %p skb %p", hu, skb);
|
||||
|
||||
if (!hu->tty->dev)
|
||||
goto out_enqueue;
|
||||
|
||||
/* Be sure our controller is resumed and potential LPM transaction
|
||||
* completed before enqueuing any packet.
|
||||
*/
|
||||
|
@ -1072,7 +1093,7 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
mutex_unlock(&intel_device_list_lock);
|
||||
|
||||
out_enqueue:
|
||||
skb_queue_tail(&intel->txq, skb);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -113,16 +113,21 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
|
|||
{
|
||||
struct sk_buff *skb = hu->tx_skb;
|
||||
|
||||
if (!skb)
|
||||
skb = hu->proto->dequeue(hu);
|
||||
else
|
||||
if (!skb) {
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
skb = hu->proto->dequeue(hu);
|
||||
} else {
|
||||
hu->tx_skb = NULL;
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
int hci_uart_tx_wakeup(struct hci_uart *hu)
|
||||
{
|
||||
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
return 0;
|
||||
|
||||
if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
|
||||
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
|
||||
return 0;
|
||||
|
@ -134,6 +139,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup);
|
||||
|
||||
static void hci_uart_write_work(struct work_struct *work)
|
||||
{
|
||||
|
@ -176,6 +182,7 @@ static void hci_uart_init_work(struct work_struct *work)
|
|||
{
|
||||
struct hci_uart *hu = container_of(work, struct hci_uart, init_ready);
|
||||
int err;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
||||
return;
|
||||
|
@ -183,9 +190,12 @@ static void hci_uart_init_work(struct work_struct *work)
|
|||
err = hci_register_dev(hu->hdev);
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
hci_free_dev(hu->hdev);
|
||||
hdev = hu->hdev;
|
||||
hu->hdev = NULL;
|
||||
hci_free_dev(hdev);
|
||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
hu->proto->close(hu);
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(HCI_UART_REGISTERED, &hu->flags);
|
||||
|
@ -251,6 +261,9 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
|
||||
skb->len);
|
||||
|
||||
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
return -EUNATCH;
|
||||
|
||||
hu->proto->enqueue(hu, skb);
|
||||
|
||||
hci_uart_tx_wakeup(hu);
|
||||
|
@ -318,25 +331,6 @@ void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
|
|||
hu->oper_speed = oper_speed;
|
||||
}
|
||||
|
||||
void hci_uart_init_tty(struct hci_uart *hu)
|
||||
{
|
||||
struct tty_struct *tty = hu->tty;
|
||||
struct ktermios ktermios;
|
||||
|
||||
/* Bring the UART into a known 8 bits no parity hw fc state */
|
||||
ktermios = tty->termios;
|
||||
ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
|
||||
INLCR | IGNCR | ICRNL | IXON);
|
||||
ktermios.c_oflag &= ~OPOST;
|
||||
ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
ktermios.c_cflag &= ~(CSIZE | PARENB);
|
||||
ktermios.c_cflag |= CS8;
|
||||
ktermios.c_cflag |= CRTSCTS;
|
||||
|
||||
/* tty_set_termios() return not checked as it is always 0 */
|
||||
tty_set_termios(tty, &ktermios);
|
||||
}
|
||||
|
||||
void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed)
|
||||
{
|
||||
struct tty_struct *tty = hu->tty;
|
||||
|
@ -459,6 +453,10 @@ static int hci_uart_tty_open(struct tty_struct *tty)
|
|||
hu->tty = tty;
|
||||
tty->receive_room = 65536;
|
||||
|
||||
/* disable alignment support by default */
|
||||
hu->alignment = 1;
|
||||
hu->padding = 0;
|
||||
|
||||
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||
|
||||
|
@ -616,6 +614,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
|||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
hu->hdev = NULL;
|
||||
hci_free_dev(hdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -34,20 +34,24 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ti_wilink_st.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
|
||||
|
@ -76,6 +80,12 @@ struct hcill_cmd {
|
|||
u8 cmd;
|
||||
} __packed;
|
||||
|
||||
struct ll_device {
|
||||
struct hci_uart hu;
|
||||
struct serdev_device *serdev;
|
||||
struct gpio_desc *enable_gpio;
|
||||
};
|
||||
|
||||
struct ll_struct {
|
||||
unsigned long rx_state;
|
||||
unsigned long rx_count;
|
||||
|
@ -136,6 +146,9 @@ static int ll_open(struct hci_uart *hu)
|
|||
|
||||
hu->priv = ll;
|
||||
|
||||
if (hu->serdev)
|
||||
serdev_device_open(hu->serdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -164,6 +177,13 @@ static int ll_close(struct hci_uart *hu)
|
|||
|
||||
kfree_skb(ll->rx_skb);
|
||||
|
||||
if (hu->serdev) {
|
||||
struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev);
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
|
||||
|
||||
serdev_device_close(hu->serdev);
|
||||
}
|
||||
|
||||
hu->priv = NULL;
|
||||
|
||||
kfree(ll);
|
||||
|
@ -505,9 +525,244 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu)
|
|||
return skb_dequeue(&ll->txq);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SERIAL_DEV_BUS)
|
||||
static int read_local_version(struct hci_dev *hdev)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned short version = 0;
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_local_version *ver;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Reading TI version information failed (%ld)",
|
||||
PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
if (skb->len != sizeof(*ver)) {
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ver = (struct hci_rp_read_local_version *)skb->data;
|
||||
if (le16_to_cpu(ver->manufacturer) != 13) {
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
version = le16_to_cpu(ver->lmp_subver);
|
||||
|
||||
out:
|
||||
if (err) bt_dev_err(hdev, "Failed to read TI version info: %d", err);
|
||||
kfree_skb(skb);
|
||||
return err ? err : version;
|
||||
}
|
||||
|
||||
/**
|
||||
* download_firmware -
|
||||
* internal function which parses through the .bts firmware
|
||||
* script file intreprets SEND, DELAY actions only as of now
|
||||
*/
|
||||
static int download_firmware(struct ll_device *lldev)
|
||||
{
|
||||
unsigned short chip, min_ver, maj_ver;
|
||||
int version, err, len;
|
||||
unsigned char *ptr, *action_ptr;
|
||||
unsigned char bts_scr_name[40]; /* 40 char long bts scr name? */
|
||||
const struct firmware *fw;
|
||||
struct sk_buff *skb;
|
||||
struct hci_command *cmd;
|
||||
|
||||
version = read_local_version(lldev->hu.hdev);
|
||||
if (version < 0)
|
||||
return version;
|
||||
|
||||
chip = (version & 0x7C00) >> 10;
|
||||
min_ver = (version & 0x007F);
|
||||
maj_ver = (version & 0x0380) >> 7;
|
||||
if (version & 0x8000)
|
||||
maj_ver |= 0x0008;
|
||||
|
||||
snprintf(bts_scr_name, sizeof(bts_scr_name),
|
||||
"ti-connectivity/TIInit_%d.%d.%d.bts",
|
||||
chip, maj_ver, min_ver);
|
||||
|
||||
err = request_firmware(&fw, bts_scr_name, &lldev->serdev->dev);
|
||||
if (err || !fw->data || !fw->size) {
|
||||
bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
|
||||
err, bts_scr_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
ptr = (void *)fw->data;
|
||||
len = fw->size;
|
||||
/* bts_header to remove out magic number and
|
||||
* version
|
||||
*/
|
||||
ptr += sizeof(struct bts_header);
|
||||
len -= sizeof(struct bts_header);
|
||||
|
||||
while (len > 0 && ptr) {
|
||||
bt_dev_dbg(lldev->hu.hdev, " action size %d, type %d ",
|
||||
((struct bts_action *)ptr)->size,
|
||||
((struct bts_action *)ptr)->type);
|
||||
|
||||
action_ptr = &(((struct bts_action *)ptr)->data[0]);
|
||||
|
||||
switch (((struct bts_action *)ptr)->type) {
|
||||
case ACTION_SEND_COMMAND: /* action send */
|
||||
bt_dev_dbg(lldev->hu.hdev, "S");
|
||||
cmd = (struct hci_command *)action_ptr;
|
||||
if (cmd->opcode == 0xff36) {
|
||||
/* ignore remote change
|
||||
* baud rate HCI VS command */
|
||||
bt_dev_warn(lldev->hu.hdev, "change remote baud rate command in firmware");
|
||||
break;
|
||||
}
|
||||
if (cmd->prefix != 1)
|
||||
bt_dev_dbg(lldev->hu.hdev, "command type %d\n", cmd->prefix);
|
||||
|
||||
skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(lldev->hu.hdev, "send command failed\n");
|
||||
goto out_rel_fw;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
case ACTION_WAIT_EVENT: /* wait */
|
||||
/* no need to wait as command was synchronous */
|
||||
bt_dev_dbg(lldev->hu.hdev, "W");
|
||||
break;
|
||||
case ACTION_DELAY: /* sleep */
|
||||
bt_dev_info(lldev->hu.hdev, "sleep command in scr");
|
||||
mdelay(((struct bts_action_delay *)action_ptr)->msec);
|
||||
break;
|
||||
}
|
||||
len -= (sizeof(struct bts_action) +
|
||||
((struct bts_action *)ptr)->size);
|
||||
ptr += sizeof(struct bts_action) +
|
||||
((struct bts_action *)ptr)->size;
|
||||
}
|
||||
|
||||
out_rel_fw:
|
||||
/* fw download complete */
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ll_setup(struct hci_uart *hu)
|
||||
{
|
||||
int err, retry = 3;
|
||||
struct ll_device *lldev;
|
||||
struct serdev_device *serdev = hu->serdev;
|
||||
u32 speed;
|
||||
|
||||
if (!serdev)
|
||||
return 0;
|
||||
|
||||
lldev = serdev_device_get_drvdata(serdev);
|
||||
|
||||
serdev_device_set_flow_control(serdev, true);
|
||||
|
||||
do {
|
||||
/* Configure BT_EN to HIGH state */
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
|
||||
msleep(5);
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 1);
|
||||
msleep(100);
|
||||
|
||||
err = download_firmware(lldev);
|
||||
if (!err)
|
||||
break;
|
||||
|
||||
/* Toggle BT_EN and retry */
|
||||
bt_dev_err(hu->hdev, "download firmware failed, retrying...");
|
||||
} while (retry--);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Operational speed if any */
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
else if (hu->proto->oper_speed)
|
||||
speed = hu->proto->oper_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
if (speed) {
|
||||
struct sk_buff *skb = __hci_cmd_sync(hu->hdev, 0xff36, sizeof(speed), &speed, HCI_INIT_TIMEOUT);
|
||||
if (!IS_ERR(skb)) {
|
||||
kfree_skb(skb);
|
||||
serdev_device_set_baudrate(serdev, speed);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hci_uart_proto llp;
|
||||
|
||||
static int hci_ti_probe(struct serdev_device *serdev)
|
||||
{
|
||||
struct hci_uart *hu;
|
||||
struct ll_device *lldev;
|
||||
u32 max_speed = 3000000;
|
||||
|
||||
lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL);
|
||||
if (!lldev)
|
||||
return -ENOMEM;
|
||||
hu = &lldev->hu;
|
||||
|
||||
serdev_device_set_drvdata(serdev, lldev);
|
||||
lldev->serdev = hu->serdev = serdev;
|
||||
|
||||
lldev->enable_gpio = devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lldev->enable_gpio))
|
||||
return PTR_ERR(lldev->enable_gpio);
|
||||
|
||||
of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed);
|
||||
hci_uart_set_speeds(hu, 115200, max_speed);
|
||||
|
||||
return hci_uart_register_device(hu, &llp);
|
||||
}
|
||||
|
||||
static void hci_ti_remove(struct serdev_device *serdev)
|
||||
{
|
||||
struct ll_device *lldev = serdev_device_get_drvdata(serdev);
|
||||
struct hci_uart *hu = &lldev->hu;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
hu->proto->close(hu);
|
||||
}
|
||||
|
||||
static const struct of_device_id hci_ti_of_match[] = {
|
||||
{ .compatible = "ti,wl1831-st" },
|
||||
{ .compatible = "ti,wl1835-st" },
|
||||
{ .compatible = "ti,wl1837-st" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hci_ti_of_match);
|
||||
|
||||
static struct serdev_device_driver hci_ti_drv = {
|
||||
.driver = {
|
||||
.name = "hci-ti",
|
||||
.of_match_table = of_match_ptr(hci_ti_of_match),
|
||||
},
|
||||
.probe = hci_ti_probe,
|
||||
.remove = hci_ti_remove,
|
||||
};
|
||||
#else
|
||||
#define ll_setup NULL
|
||||
#endif
|
||||
|
||||
static const struct hci_uart_proto llp = {
|
||||
.id = HCI_UART_LL,
|
||||
.name = "LL",
|
||||
.setup = ll_setup,
|
||||
.open = ll_open,
|
||||
.close = ll_close,
|
||||
.recv = ll_recv,
|
||||
|
@ -518,10 +773,14 @@ static const struct hci_uart_proto llp = {
|
|||
|
||||
int __init ll_init(void)
|
||||
{
|
||||
serdev_device_driver_register(&hci_ti_drv);
|
||||
|
||||
return hci_uart_register_proto(&llp);
|
||||
}
|
||||
|
||||
int __exit ll_deinit(void)
|
||||
{
|
||||
serdev_device_driver_unregister(&hci_ti_drv);
|
||||
|
||||
return hci_uart_unregister_proto(&llp);
|
||||
}
|
||||
|
|
827
drivers/bluetooth/hci_nokia.c
Normal file
827
drivers/bluetooth/hci_nokia.c
Normal file
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
* Bluetooth HCI UART H4 driver with Nokia Extensions AKA Nokia H4+
|
||||
*
|
||||
* Copyright (C) 2015 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2015-2017 Sebastian Reichel <sre@kernel.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned/le_struct.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
#include "btbcm.h"
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
#define NOKIA_ID_BCM2048 0x04
|
||||
#define NOKIA_ID_TI1271 0x31
|
||||
|
||||
#define FIRMWARE_BCM2048 "nokia/bcmfw.bin"
|
||||
#define FIRMWARE_TI1271 "nokia/ti1273.bin"
|
||||
|
||||
#define HCI_NOKIA_NEG_PKT 0x06
|
||||
#define HCI_NOKIA_ALIVE_PKT 0x07
|
||||
#define HCI_NOKIA_RADIO_PKT 0x08
|
||||
|
||||
#define HCI_NOKIA_NEG_HDR_SIZE 1
|
||||
#define HCI_NOKIA_MAX_NEG_SIZE 255
|
||||
#define HCI_NOKIA_ALIVE_HDR_SIZE 1
|
||||
#define HCI_NOKIA_MAX_ALIVE_SIZE 255
|
||||
#define HCI_NOKIA_RADIO_HDR_SIZE 2
|
||||
#define HCI_NOKIA_MAX_RADIO_SIZE 255
|
||||
|
||||
#define NOKIA_PROTO_PKT 0x44
|
||||
#define NOKIA_PROTO_BYTE 0x4c
|
||||
|
||||
#define NOKIA_NEG_REQ 0x00
|
||||
#define NOKIA_NEG_ACK 0x20
|
||||
#define NOKIA_NEG_NAK 0x40
|
||||
|
||||
#define H4_TYPE_SIZE 1
|
||||
|
||||
#define NOKIA_RECV_ALIVE \
|
||||
.type = HCI_NOKIA_ALIVE_PKT, \
|
||||
.hlen = HCI_NOKIA_ALIVE_HDR_SIZE, \
|
||||
.loff = 0, \
|
||||
.lsize = 1, \
|
||||
.maxlen = HCI_NOKIA_MAX_ALIVE_SIZE \
|
||||
|
||||
#define NOKIA_RECV_NEG \
|
||||
.type = HCI_NOKIA_NEG_PKT, \
|
||||
.hlen = HCI_NOKIA_NEG_HDR_SIZE, \
|
||||
.loff = 0, \
|
||||
.lsize = 1, \
|
||||
.maxlen = HCI_NOKIA_MAX_NEG_SIZE \
|
||||
|
||||
#define NOKIA_RECV_RADIO \
|
||||
.type = HCI_NOKIA_RADIO_PKT, \
|
||||
.hlen = HCI_NOKIA_RADIO_HDR_SIZE, \
|
||||
.loff = 1, \
|
||||
.lsize = 1, \
|
||||
.maxlen = HCI_NOKIA_MAX_RADIO_SIZE \
|
||||
|
||||
struct hci_nokia_neg_hdr {
|
||||
u8 dlen;
|
||||
} __packed;
|
||||
|
||||
struct hci_nokia_neg_cmd {
|
||||
u8 ack;
|
||||
u16 baud;
|
||||
u16 unused1;
|
||||
u8 proto;
|
||||
u16 sys_clk;
|
||||
u16 unused2;
|
||||
} __packed;
|
||||
|
||||
#define NOKIA_ALIVE_REQ 0x55
|
||||
#define NOKIA_ALIVE_RESP 0xcc
|
||||
|
||||
struct hci_nokia_alive_hdr {
|
||||
u8 dlen;
|
||||
} __packed;
|
||||
|
||||
struct hci_nokia_alive_pkt {
|
||||
u8 mid;
|
||||
u8 unused;
|
||||
} __packed;
|
||||
|
||||
struct hci_nokia_neg_evt {
|
||||
u8 ack;
|
||||
u16 baud;
|
||||
u16 unused1;
|
||||
u8 proto;
|
||||
u16 sys_clk;
|
||||
u16 unused2;
|
||||
u8 man_id;
|
||||
u8 ver_id;
|
||||
} __packed;
|
||||
|
||||
#define MAX_BAUD_RATE 3692300
|
||||
#define SETUP_BAUD_RATE 921600
|
||||
#define INIT_BAUD_RATE 120000
|
||||
|
||||
struct hci_nokia_radio_hdr {
|
||||
u8 evt;
|
||||
u8 dlen;
|
||||
} __packed;
|
||||
|
||||
struct nokia_bt_dev {
|
||||
struct hci_uart hu;
|
||||
struct serdev_device *serdev;
|
||||
|
||||
struct gpio_desc *reset;
|
||||
struct gpio_desc *wakeup_host;
|
||||
struct gpio_desc *wakeup_bt;
|
||||
unsigned long sysclk_speed;
|
||||
|
||||
int wake_irq;
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff_head txq;
|
||||
bdaddr_t bdaddr;
|
||||
|
||||
int init_error;
|
||||
struct completion init_completion;
|
||||
|
||||
u8 man_id;
|
||||
u8 ver_id;
|
||||
|
||||
bool initialized;
|
||||
bool tx_enabled;
|
||||
bool rx_enabled;
|
||||
};
|
||||
|
||||
static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb);
|
||||
|
||||
static void nokia_flow_control(struct serdev_device *serdev, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
serdev_device_set_rts(serdev, true);
|
||||
serdev_device_set_flow_control(serdev, true);
|
||||
} else {
|
||||
serdev_device_set_flow_control(serdev, false);
|
||||
serdev_device_set_rts(serdev, false);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t wakeup_handler(int irq, void *data)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = data;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
int wake_state = gpiod_get_value(btdev->wakeup_host);
|
||||
|
||||
if (btdev->rx_enabled == wake_state)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (wake_state)
|
||||
pm_runtime_get(dev);
|
||||
else
|
||||
pm_runtime_put(dev);
|
||||
|
||||
btdev->rx_enabled = wake_state;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int nokia_reset(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
int err;
|
||||
|
||||
/* reset routine */
|
||||
gpiod_set_value_cansleep(btdev->reset, 1);
|
||||
gpiod_set_value_cansleep(btdev->wakeup_bt, 1);
|
||||
|
||||
msleep(100);
|
||||
|
||||
/* safety check */
|
||||
err = gpiod_get_value_cansleep(btdev->wakeup_host);
|
||||
if (err == 1) {
|
||||
dev_err(dev, "reset: host wakeup not low!");
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
/* flush queue */
|
||||
serdev_device_write_flush(btdev->serdev);
|
||||
|
||||
/* init uart */
|
||||
nokia_flow_control(btdev->serdev, false);
|
||||
serdev_device_set_baudrate(btdev->serdev, INIT_BAUD_RATE);
|
||||
|
||||
gpiod_set_value_cansleep(btdev->reset, 0);
|
||||
|
||||
/* wait for cts */
|
||||
err = serdev_device_wait_for_cts(btdev->serdev, true, 200);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "CTS not received: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
nokia_flow_control(btdev->serdev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_send_alive_packet(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
struct hci_nokia_alive_hdr *hdr;
|
||||
struct hci_nokia_alive_pkt *pkt;
|
||||
struct sk_buff *skb;
|
||||
int len;
|
||||
|
||||
init_completion(&btdev->init_completion);
|
||||
|
||||
len = H4_TYPE_SIZE + sizeof(*hdr) + sizeof(*pkt);
|
||||
skb = bt_skb_alloc(len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hci_skb_pkt_type(skb) = HCI_NOKIA_ALIVE_PKT;
|
||||
memset(skb->data, 0x00, len);
|
||||
|
||||
hdr = (struct hci_nokia_alive_hdr *)skb_put(skb, sizeof(*hdr));
|
||||
hdr->dlen = sizeof(*pkt);
|
||||
pkt = (struct hci_nokia_alive_pkt *)skb_put(skb, sizeof(*pkt));
|
||||
pkt->mid = NOKIA_ALIVE_REQ;
|
||||
|
||||
nokia_enqueue(hu, skb);
|
||||
hci_uart_tx_wakeup(hu);
|
||||
|
||||
dev_dbg(dev, "Alive sent");
|
||||
|
||||
if (!wait_for_completion_interruptible_timeout(&btdev->init_completion,
|
||||
msecs_to_jiffies(1000))) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (btdev->init_error < 0)
|
||||
return btdev->init_error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_send_negotiation(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
struct hci_nokia_neg_cmd *neg_cmd;
|
||||
struct hci_nokia_neg_hdr *neg_hdr;
|
||||
struct sk_buff *skb;
|
||||
int len, err;
|
||||
u16 baud = DIV_ROUND_CLOSEST(btdev->sysclk_speed * 10, SETUP_BAUD_RATE);
|
||||
int sysclk = btdev->sysclk_speed / 1000;
|
||||
|
||||
len = H4_TYPE_SIZE + sizeof(*neg_hdr) + sizeof(*neg_cmd);
|
||||
skb = bt_skb_alloc(len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hci_skb_pkt_type(skb) = HCI_NOKIA_NEG_PKT;
|
||||
|
||||
neg_hdr = (struct hci_nokia_neg_hdr *)skb_put(skb, sizeof(*neg_hdr));
|
||||
neg_hdr->dlen = sizeof(*neg_cmd);
|
||||
|
||||
neg_cmd = (struct hci_nokia_neg_cmd *)skb_put(skb, sizeof(*neg_cmd));
|
||||
neg_cmd->ack = NOKIA_NEG_REQ;
|
||||
neg_cmd->baud = cpu_to_le16(baud);
|
||||
neg_cmd->unused1 = 0x0000;
|
||||
neg_cmd->proto = NOKIA_PROTO_BYTE;
|
||||
neg_cmd->sys_clk = cpu_to_le16(sysclk);
|
||||
neg_cmd->unused2 = 0x0000;
|
||||
|
||||
btdev->init_error = 0;
|
||||
init_completion(&btdev->init_completion);
|
||||
|
||||
nokia_enqueue(hu, skb);
|
||||
hci_uart_tx_wakeup(hu);
|
||||
|
||||
dev_dbg(dev, "Negotiation sent");
|
||||
|
||||
if (!wait_for_completion_interruptible_timeout(&btdev->init_completion,
|
||||
msecs_to_jiffies(10000))) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (btdev->init_error < 0)
|
||||
return btdev->init_error;
|
||||
|
||||
/* Change to previously negotiated speed. Flow Control
|
||||
* is disabled until bluetooth adapter is ready to avoid
|
||||
* broken bytes being received.
|
||||
*/
|
||||
nokia_flow_control(btdev->serdev, false);
|
||||
serdev_device_set_baudrate(btdev->serdev, SETUP_BAUD_RATE);
|
||||
err = serdev_device_wait_for_cts(btdev->serdev, true, 200);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "CTS not received: %d", err);
|
||||
return err;
|
||||
}
|
||||
nokia_flow_control(btdev->serdev, true);
|
||||
|
||||
dev_dbg(dev, "Negotiation successful");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_setup_fw(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
const char *fwname;
|
||||
const struct firmware *fw;
|
||||
const u8 *fw_ptr;
|
||||
size_t fw_size;
|
||||
int err;
|
||||
|
||||
dev_dbg(dev, "setup firmware");
|
||||
|
||||
if (btdev->man_id == NOKIA_ID_BCM2048) {
|
||||
fwname = FIRMWARE_BCM2048;
|
||||
} else if (btdev->man_id == NOKIA_ID_TI1271) {
|
||||
fwname = FIRMWARE_TI1271;
|
||||
} else {
|
||||
dev_err(dev, "Unsupported bluetooth device!");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = request_firmware(&fw, fwname, dev);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "%s: Failed to load Nokia firmware file (%d)",
|
||||
hu->hdev->name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data;
|
||||
fw_size = fw->size;
|
||||
|
||||
while (fw_size >= 4) {
|
||||
u16 pkt_size = get_unaligned_le16(fw_ptr);
|
||||
u8 pkt_type = fw_ptr[2];
|
||||
const struct hci_command_hdr *cmd;
|
||||
u16 opcode;
|
||||
struct sk_buff *skb;
|
||||
|
||||
switch (pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
cmd = (struct hci_command_hdr *)(fw_ptr + 3);
|
||||
opcode = le16_to_cpu(cmd->opcode);
|
||||
|
||||
skb = __hci_cmd_sync(hu->hdev, opcode, cmd->plen,
|
||||
fw_ptr + 3 + HCI_COMMAND_HDR_SIZE,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
dev_err(dev, "%s: FW command %04x failed (%d)",
|
||||
hu->hdev->name, opcode, err);
|
||||
goto done;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
case HCI_NOKIA_RADIO_PKT:
|
||||
case HCI_NOKIA_NEG_PKT:
|
||||
case HCI_NOKIA_ALIVE_PKT:
|
||||
break;
|
||||
}
|
||||
|
||||
fw_ptr += pkt_size + 2;
|
||||
fw_size -= pkt_size + 2;
|
||||
}
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nokia_setup(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
int err;
|
||||
|
||||
btdev->initialized = false;
|
||||
|
||||
nokia_flow_control(btdev->serdev, false);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
if (btdev->tx_enabled) {
|
||||
gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
|
||||
pm_runtime_put(&btdev->serdev->dev);
|
||||
btdev->tx_enabled = false;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "protocol setup");
|
||||
|
||||
/* 0. reset connection */
|
||||
err = nokia_reset(hu);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Reset failed: %d", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 1. negotiate speed etc */
|
||||
err = nokia_send_negotiation(hu);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Negotiation failed: %d", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 2. verify correct setup using alive packet */
|
||||
err = nokia_send_alive_packet(hu);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Alive check failed: %d", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 3. send firmware */
|
||||
err = nokia_setup_fw(hu);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Could not setup FW: %d", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nokia_flow_control(btdev->serdev, false);
|
||||
serdev_device_set_baudrate(btdev->serdev, MAX_BAUD_RATE);
|
||||
nokia_flow_control(btdev->serdev, true);
|
||||
|
||||
if (btdev->man_id == NOKIA_ID_BCM2048) {
|
||||
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
|
||||
dev_dbg(dev, "bcm2048 has invalid bluetooth address!");
|
||||
}
|
||||
|
||||
dev_dbg(dev, "protocol setup done!");
|
||||
|
||||
gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
|
||||
pm_runtime_put(dev);
|
||||
btdev->tx_enabled = false;
|
||||
btdev->initialized = true;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nokia_open(struct hci_uart *hu)
|
||||
{
|
||||
struct device *dev = &hu->serdev->dev;
|
||||
|
||||
dev_dbg(dev, "protocol open");
|
||||
|
||||
serdev_device_open(hu->serdev);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_flush(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
|
||||
dev_dbg(&btdev->serdev->dev, "flush device");
|
||||
|
||||
skb_queue_purge(&btdev->txq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_close(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
|
||||
dev_dbg(dev, "close device");
|
||||
|
||||
btdev->initialized = false;
|
||||
|
||||
skb_queue_purge(&btdev->txq);
|
||||
|
||||
kfree_skb(btdev->rx_skb);
|
||||
|
||||
/* disable module */
|
||||
gpiod_set_value(btdev->reset, 1);
|
||||
gpiod_set_value(btdev->wakeup_bt, 0);
|
||||
|
||||
pm_runtime_disable(&btdev->serdev->dev);
|
||||
serdev_device_close(btdev->serdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enqueue frame for transmittion (padding, crc, etc) */
|
||||
static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
int err;
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
|
||||
/* Packets must be word aligned */
|
||||
if (skb->len % 2) {
|
||||
err = skb_pad(skb, 1);
|
||||
if (err)
|
||||
return err;
|
||||
*skb_put(skb, 1) = 0x00;
|
||||
}
|
||||
|
||||
skb_queue_tail(&btdev->txq, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_recv_negotiation_packet(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
struct hci_nokia_neg_hdr *hdr;
|
||||
struct hci_nokia_neg_evt *evt;
|
||||
int ret = 0;
|
||||
|
||||
hdr = (struct hci_nokia_neg_hdr *)skb->data;
|
||||
if (hdr->dlen != sizeof(*evt)) {
|
||||
btdev->init_error = -EIO;
|
||||
ret = -EIO;
|
||||
goto finish_neg;
|
||||
}
|
||||
|
||||
evt = (struct hci_nokia_neg_evt *)skb_pull(skb, sizeof(*hdr));
|
||||
|
||||
if (evt->ack != NOKIA_NEG_ACK) {
|
||||
dev_err(dev, "Negotiation received: wrong reply");
|
||||
btdev->init_error = -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto finish_neg;
|
||||
}
|
||||
|
||||
btdev->man_id = evt->man_id;
|
||||
btdev->ver_id = evt->ver_id;
|
||||
|
||||
dev_dbg(dev, "Negotiation received: baud=%u:clk=%u:manu=%u:vers=%u",
|
||||
evt->baud, evt->sys_clk, evt->man_id, evt->ver_id);
|
||||
|
||||
finish_neg:
|
||||
complete(&btdev->init_completion);
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nokia_recv_alive_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
struct hci_nokia_alive_hdr *hdr;
|
||||
struct hci_nokia_alive_pkt *pkt;
|
||||
int ret = 0;
|
||||
|
||||
hdr = (struct hci_nokia_alive_hdr *)skb->data;
|
||||
if (hdr->dlen != sizeof(*pkt)) {
|
||||
dev_err(dev, "Corrupted alive message");
|
||||
btdev->init_error = -EIO;
|
||||
ret = -EIO;
|
||||
goto finish_alive;
|
||||
}
|
||||
|
||||
pkt = (struct hci_nokia_alive_pkt *)skb_pull(skb, sizeof(*hdr));
|
||||
|
||||
if (pkt->mid != NOKIA_ALIVE_RESP) {
|
||||
dev_err(dev, "Alive received: invalid response: 0x%02x!",
|
||||
pkt->mid);
|
||||
btdev->init_error = -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto finish_alive;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Alive received");
|
||||
|
||||
finish_alive:
|
||||
complete(&btdev->init_completion);
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nokia_recv_radio(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
/* Packets received on the dedicated radio channel are
|
||||
* HCI events and so feed them back into the core.
|
||||
*/
|
||||
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
/* Recv data */
|
||||
static const struct h4_recv_pkt nokia_recv_pkts[] = {
|
||||
{ H4_RECV_ACL, .recv = hci_recv_frame },
|
||||
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
||||
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
||||
{ NOKIA_RECV_ALIVE, .recv = nokia_recv_alive_packet },
|
||||
{ NOKIA_RECV_NEG, .recv = nokia_recv_negotiation_packet },
|
||||
{ NOKIA_RECV_RADIO, .recv = nokia_recv_radio },
|
||||
};
|
||||
|
||||
static int nokia_recv(struct hci_uart *hu, const void *data, int count)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
int err;
|
||||
|
||||
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||
return -EUNATCH;
|
||||
|
||||
btdev->rx_skb = h4_recv_buf(hu->hdev, btdev->rx_skb, data, count,
|
||||
nokia_recv_pkts, ARRAY_SIZE(nokia_recv_pkts));
|
||||
if (IS_ERR(btdev->rx_skb)) {
|
||||
err = PTR_ERR(btdev->rx_skb);
|
||||
dev_err(dev, "Frame reassembly failed (%d)", err);
|
||||
btdev->rx_skb = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sk_buff *nokia_dequeue(struct hci_uart *hu)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = hu->priv;
|
||||
struct device *dev = &btdev->serdev->dev;
|
||||
struct sk_buff *result = skb_dequeue(&btdev->txq);
|
||||
|
||||
if (!btdev->initialized)
|
||||
return result;
|
||||
|
||||
if (btdev->tx_enabled == !!result)
|
||||
return result;
|
||||
|
||||
if (result) {
|
||||
pm_runtime_get_sync(dev);
|
||||
gpiod_set_value_cansleep(btdev->wakeup_bt, 1);
|
||||
} else {
|
||||
serdev_device_wait_until_sent(btdev->serdev, 0);
|
||||
gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
|
||||
pm_runtime_put(dev);
|
||||
}
|
||||
|
||||
btdev->tx_enabled = !!result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct hci_uart_proto nokia_proto = {
|
||||
.id = HCI_UART_NOKIA,
|
||||
.name = "Nokia",
|
||||
.open = nokia_open,
|
||||
.close = nokia_close,
|
||||
.recv = nokia_recv,
|
||||
.enqueue = nokia_enqueue,
|
||||
.dequeue = nokia_dequeue,
|
||||
.flush = nokia_flush,
|
||||
.setup = nokia_setup,
|
||||
.manufacturer = 1,
|
||||
};
|
||||
|
||||
static int nokia_bluetooth_serdev_probe(struct serdev_device *serdev)
|
||||
{
|
||||
struct device *dev = &serdev->dev;
|
||||
struct nokia_bt_dev *btdev;
|
||||
struct clk *sysclk;
|
||||
int err = 0;
|
||||
|
||||
btdev = devm_kzalloc(dev, sizeof(*btdev), GFP_KERNEL);
|
||||
if (!btdev)
|
||||
return -ENOMEM;
|
||||
|
||||
btdev->hu.serdev = btdev->serdev = serdev;
|
||||
serdev_device_set_drvdata(serdev, btdev);
|
||||
|
||||
btdev->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(btdev->reset)) {
|
||||
err = PTR_ERR(btdev->reset);
|
||||
dev_err(dev, "could not get reset gpio: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
btdev->wakeup_host = devm_gpiod_get(dev, "host-wakeup", GPIOD_IN);
|
||||
if (IS_ERR(btdev->wakeup_host)) {
|
||||
err = PTR_ERR(btdev->wakeup_host);
|
||||
dev_err(dev, "could not get host wakeup gpio: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
btdev->wake_irq = gpiod_to_irq(btdev->wakeup_host);
|
||||
|
||||
err = devm_request_threaded_irq(dev, btdev->wake_irq, NULL,
|
||||
wakeup_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"wakeup", btdev);
|
||||
if (err) {
|
||||
dev_err(dev, "could request wakeup irq: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
btdev->wakeup_bt = devm_gpiod_get(dev, "bluetooth-wakeup",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(btdev->wakeup_bt)) {
|
||||
err = PTR_ERR(btdev->wakeup_bt);
|
||||
dev_err(dev, "could not get BT wakeup gpio: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
sysclk = devm_clk_get(dev, "sysclk");
|
||||
if (IS_ERR(sysclk)) {
|
||||
err = PTR_ERR(sysclk);
|
||||
dev_err(dev, "could not get sysclk: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
clk_prepare_enable(sysclk);
|
||||
btdev->sysclk_speed = clk_get_rate(sysclk);
|
||||
clk_disable_unprepare(sysclk);
|
||||
|
||||
skb_queue_head_init(&btdev->txq);
|
||||
|
||||
btdev->hu.priv = btdev;
|
||||
btdev->hu.alignment = 2; /* Nokia H4+ is word aligned */
|
||||
|
||||
err = hci_uart_register_device(&btdev->hu, &nokia_proto);
|
||||
if (err) {
|
||||
dev_err(dev, "could not register bluetooth uart: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nokia_bluetooth_serdev_remove(struct serdev_device *serdev)
|
||||
{
|
||||
struct nokia_bt_dev *btdev = serdev_device_get_drvdata(serdev);
|
||||
struct hci_uart *hu = &btdev->hu;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
hu->proto->close(hu);
|
||||
|
||||
pm_runtime_disable(&btdev->serdev->dev);
|
||||
}
|
||||
|
||||
static int nokia_bluetooth_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct serdev_device *serdev = to_serdev_device(dev);
|
||||
|
||||
nokia_flow_control(serdev, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nokia_bluetooth_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct serdev_device *serdev = to_serdev_device(dev);
|
||||
|
||||
nokia_flow_control(serdev, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops nokia_bluetooth_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(nokia_bluetooth_runtime_suspend,
|
||||
nokia_bluetooth_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id nokia_bluetooth_of_match[] = {
|
||||
{ .compatible = "nokia,h4p-bluetooth", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, nokia_bluetooth_of_match);
|
||||
#endif
|
||||
|
||||
static struct serdev_device_driver nokia_bluetooth_serdev_driver = {
|
||||
.probe = nokia_bluetooth_serdev_probe,
|
||||
.remove = nokia_bluetooth_serdev_remove,
|
||||
.driver = {
|
||||
.name = "nokia-bluetooth",
|
||||
.pm = &nokia_bluetooth_pm_ops,
|
||||
.of_match_table = of_match_ptr(nokia_bluetooth_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_serdev_device_driver(nokia_bluetooth_serdev_driver);
|
||||
|
||||
MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth HCI UART Nokia H4+ driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
356
drivers/bluetooth/hci_serdev.c
Normal file
356
drivers/bluetooth/hci_serdev.c
Normal file
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* Bluetooth HCI serdev driver lib
|
||||
*
|
||||
* Copyright (C) 2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
|
||||
*
|
||||
* Based on hci_ldisc.c:
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
|
||||
struct serdev_device_ops hci_serdev_client_ops;
|
||||
|
||||
static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
|
||||
{
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
||||
/* Update HCI stat counters */
|
||||
switch (pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
|
||||
case HCI_ACLDATA_PKT:
|
||||
hdev->stat.acl_tx++;
|
||||
break;
|
||||
|
||||
case HCI_SCODATA_PKT:
|
||||
hdev->stat.sco_tx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
|
||||
{
|
||||
struct sk_buff *skb = hu->tx_skb;
|
||||
|
||||
if (!skb)
|
||||
skb = hu->proto->dequeue(hu);
|
||||
else
|
||||
hu->tx_skb = NULL;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void hci_uart_write_work(struct work_struct *work)
|
||||
{
|
||||
struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
|
||||
struct serdev_device *serdev = hu->serdev;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* REVISIT:
|
||||
* should we cope with bad skbs or ->write() returning an error value?
|
||||
*/
|
||||
do {
|
||||
clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
|
||||
|
||||
while ((skb = hci_uart_dequeue(hu))) {
|
||||
int len;
|
||||
|
||||
len = serdev_device_write_buf(serdev,
|
||||
skb->data, skb->len);
|
||||
hdev->stat.byte_tx += len;
|
||||
|
||||
skb_pull(skb, len);
|
||||
if (skb->len) {
|
||||
hu->tx_skb = skb;
|
||||
break;
|
||||
}
|
||||
|
||||
hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
|
||||
kfree_skb(skb);
|
||||
}
|
||||
} while(test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
|
||||
|
||||
clear_bit(HCI_UART_SENDING, &hu->tx_state);
|
||||
}
|
||||
|
||||
/* ------- Interface to HCI layer ------ */
|
||||
|
||||
/* Initialize device */
|
||||
static int hci_uart_open(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s %p", hdev->name, hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset device */
|
||||
static int hci_uart_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("hdev %p serdev %p", hdev, hu->serdev);
|
||||
|
||||
if (hu->tx_skb) {
|
||||
kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
|
||||
}
|
||||
|
||||
/* Flush any pending characters in the driver and discipline. */
|
||||
serdev_device_write_flush(hu->serdev);
|
||||
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
hu->proto->flush(hu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close device */
|
||||
static int hci_uart_close(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("hdev %p", hdev);
|
||||
|
||||
hci_uart_flush(hdev);
|
||||
hdev->flush = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send frames from HCI layer */
|
||||
static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
|
||||
skb->len);
|
||||
|
||||
hu->proto->enqueue(hu, skb);
|
||||
|
||||
hci_uart_tx_wakeup(hu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_uart_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct hci_rp_read_local_version *ver;
|
||||
struct sk_buff *skb;
|
||||
unsigned int speed;
|
||||
int err;
|
||||
|
||||
/* Init speed if any */
|
||||
if (hu->init_speed)
|
||||
speed = hu->init_speed;
|
||||
else if (hu->proto->init_speed)
|
||||
speed = hu->proto->init_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
if (speed)
|
||||
serdev_device_set_baudrate(hu->serdev, speed);
|
||||
|
||||
/* Operational speed if any */
|
||||
if (hu->oper_speed)
|
||||
speed = hu->oper_speed;
|
||||
else if (hu->proto->oper_speed)
|
||||
speed = hu->proto->oper_speed;
|
||||
else
|
||||
speed = 0;
|
||||
|
||||
if (hu->proto->set_baudrate && speed) {
|
||||
err = hu->proto->set_baudrate(hu, speed);
|
||||
if (err)
|
||||
BT_ERR("%s: failed to set baudrate", hdev->name);
|
||||
else
|
||||
serdev_device_set_baudrate(hu->serdev, speed);
|
||||
}
|
||||
|
||||
if (hu->proto->setup)
|
||||
return hu->proto->setup(hu);
|
||||
|
||||
if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags))
|
||||
return 0;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
BT_ERR("%s: Reading local version information failed (%ld)",
|
||||
hdev->name, PTR_ERR(skb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*ver)) {
|
||||
BT_ERR("%s: Event length mismatch for version information",
|
||||
hdev->name);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** hci_uart_write_wakeup - transmit buffer wakeup
|
||||
* @serdev: serial device
|
||||
*
|
||||
* This function is called by the serdev framework when it accepts
|
||||
* more data being sent.
|
||||
*/
|
||||
static void hci_uart_write_wakeup(struct serdev_device *serdev)
|
||||
{
|
||||
struct hci_uart *hu = serdev_device_get_drvdata(serdev);
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (!hu || serdev != hu->serdev) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
|
||||
/** hci_uart_receive_buf - receive buffer wakeup
|
||||
* @serdev: serial device
|
||||
* @data: pointer to received data
|
||||
* @count: count of received data in bytes
|
||||
*
|
||||
* This function is called by the serdev framework when it received data
|
||||
* in the RX buffer.
|
||||
*
|
||||
* Return: number of processed bytes
|
||||
*/
|
||||
static int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data,
|
||||
size_t count)
|
||||
{
|
||||
struct hci_uart *hu = serdev_device_get_drvdata(serdev);
|
||||
|
||||
if (!hu || serdev != hu->serdev) {
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
return 0;
|
||||
|
||||
/* It does not need a lock here as it is already protected by a mutex in
|
||||
* tty caller
|
||||
*/
|
||||
hu->proto->recv(hu, data, count);
|
||||
|
||||
if (hu->hdev)
|
||||
hu->hdev->stat.byte_rx += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
struct serdev_device_ops hci_serdev_client_ops = {
|
||||
.receive_buf = hci_uart_receive_buf,
|
||||
.write_wakeup = hci_uart_write_wakeup,
|
||||
};
|
||||
|
||||
int hci_uart_register_device(struct hci_uart *hu,
|
||||
const struct hci_uart_proto *p)
|
||||
{
|
||||
int err;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops);
|
||||
|
||||
err = p->open(hu);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hu->proto = p;
|
||||
set_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
|
||||
/* Initialize and register HCI device */
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
BT_ERR("Can't allocate HCI device");
|
||||
err = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
hu->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_UART;
|
||||
hci_set_drvdata(hdev, hu);
|
||||
|
||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||
|
||||
/* Only when vendor specific setup callback is provided, consider
|
||||
* the manufacturer information valid. This avoids filling in the
|
||||
* value for Ericsson when nothing is specified.
|
||||
*/
|
||||
if (hu->proto->setup)
|
||||
hdev->manufacturer = hu->proto->manufacturer;
|
||||
|
||||
hdev->open = hci_uart_open;
|
||||
hdev->close = hci_uart_close;
|
||||
hdev->flush = hci_uart_flush;
|
||||
hdev->send = hci_uart_send_frame;
|
||||
hdev->setup = hci_uart_setup;
|
||||
SET_HCIDEV_DEV(hdev, &hu->serdev->dev);
|
||||
|
||||
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
|
||||
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
|
||||
|
||||
if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
|
||||
set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
|
||||
|
||||
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
|
||||
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
|
||||
hdev->dev_type = HCI_AMP;
|
||||
else
|
||||
hdev->dev_type = HCI_PRIMARY;
|
||||
|
||||
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
|
||||
return 0;
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
err = -ENODEV;
|
||||
goto err_register;
|
||||
}
|
||||
|
||||
set_bit(HCI_UART_REGISTERED, &hu->flags);
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
hci_free_dev(hdev);
|
||||
err_alloc:
|
||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
p->close(hu);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hci_uart_register_device);
|
|
@ -58,6 +58,7 @@
|
|||
#define HCI_UART_VND_DETECT 5
|
||||
|
||||
struct hci_uart;
|
||||
struct serdev_device;
|
||||
|
||||
struct hci_uart_proto {
|
||||
unsigned int id;
|
||||
|
@ -77,6 +78,7 @@ struct hci_uart_proto {
|
|||
|
||||
struct hci_uart {
|
||||
struct tty_struct *tty;
|
||||
struct serdev_device *serdev;
|
||||
struct hci_dev *hdev;
|
||||
unsigned long flags;
|
||||
unsigned long hdev_flags;
|
||||
|
@ -92,6 +94,9 @@ struct hci_uart {
|
|||
|
||||
unsigned int init_speed;
|
||||
unsigned int oper_speed;
|
||||
|
||||
u8 alignment;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
/* HCI_UART proto flag bits */
|
||||
|
@ -105,9 +110,10 @@ struct hci_uart {
|
|||
|
||||
int hci_uart_register_proto(const struct hci_uart_proto *p);
|
||||
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
|
||||
int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p);
|
||||
|
||||
int hci_uart_tx_wakeup(struct hci_uart *hu);
|
||||
int hci_uart_init_ready(struct hci_uart *hu);
|
||||
void hci_uart_init_tty(struct hci_uart *hu);
|
||||
void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
|
||||
void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
|
||||
void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "hyperv_vmbus.h"
|
||||
|
||||
#define VMBUS_PKT_TRAILER 8
|
||||
|
||||
/*
|
||||
* When we write to the ring buffer, check if the host needs to
|
||||
* be signaled. Here is the details of this protocol:
|
||||
|
@ -336,6 +338,12 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_cached_read_index(struct hv_ring_buffer_info *rbi)
|
||||
{
|
||||
rbi->cached_read_index = rbi->ring_buffer->read_index;
|
||||
}
|
||||
|
||||
int hv_ringbuffer_read(struct vmbus_channel *channel,
|
||||
void *buffer, u32 buflen, u32 *buffer_actual_len,
|
||||
u64 *requestid, bool raw)
|
||||
|
@ -366,7 +374,8 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
|
|||
return ret;
|
||||
}
|
||||
|
||||
init_cached_read_index(channel);
|
||||
init_cached_read_index(inring_info);
|
||||
|
||||
next_read_location = hv_get_next_read_location(inring_info);
|
||||
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
|
||||
sizeof(desc),
|
||||
|
@ -410,3 +419,86 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine number of bytes available in ring buffer after
|
||||
* the current iterator (priv_read_index) location.
|
||||
*
|
||||
* This is similar to hv_get_bytes_to_read but with private
|
||||
* read index instead.
|
||||
*/
|
||||
static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
|
||||
{
|
||||
u32 priv_read_loc = rbi->priv_read_index;
|
||||
u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
|
||||
|
||||
if (write_loc >= priv_read_loc)
|
||||
return write_loc - priv_read_loc;
|
||||
else
|
||||
return (rbi->ring_datasize - priv_read_loc) + write_loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get first vmbus packet from ring buffer after read_index
|
||||
*
|
||||
* If ring buffer is empty, returns NULL and no other action needed.
|
||||
*/
|
||||
struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
|
||||
/* set state for later hv_signal_on_read() */
|
||||
init_cached_read_index(rbi);
|
||||
|
||||
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
|
||||
return NULL;
|
||||
|
||||
return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
|
||||
|
||||
/*
|
||||
* Get next vmbus packet from ring buffer.
|
||||
*
|
||||
* Advances the current location (priv_read_index) and checks for more
|
||||
* data. If the end of the ring buffer is reached, then return NULL.
|
||||
*/
|
||||
struct vmpacket_descriptor *
|
||||
__hv_pkt_iter_next(struct vmbus_channel *channel,
|
||||
const struct vmpacket_descriptor *desc)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
u32 packetlen = desc->len8 << 3;
|
||||
u32 dsize = rbi->ring_datasize;
|
||||
|
||||
/* bump offset to next potential packet */
|
||||
rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
|
||||
if (rbi->priv_read_index >= dsize)
|
||||
rbi->priv_read_index -= dsize;
|
||||
|
||||
/* more data? */
|
||||
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
|
||||
return NULL;
|
||||
else
|
||||
return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
|
||||
|
||||
/*
|
||||
* Update host ring buffer after iterating over packets.
|
||||
*/
|
||||
void hv_pkt_iter_close(struct vmbus_channel *channel)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
|
||||
/*
|
||||
* Make sure all reads are done before we update the read index since
|
||||
* the writer may start writing to the read area once the read index
|
||||
* is updated.
|
||||
*/
|
||||
virt_rmb();
|
||||
rbi->ring_buffer->read_index = rbi->priv_read_index;
|
||||
|
||||
hv_signal_on_read(channel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_pkt_iter_close);
|
||||
|
|
|
@ -88,7 +88,7 @@ static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh)
|
|||
return false;
|
||||
|
||||
ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
|
||||
nlmsg_len(nlh), ib_nl_addr_policy);
|
||||
nlmsg_len(nlh), ib_nl_addr_policy, NULL);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -472,12 +472,14 @@ int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
|
|||
int ret;
|
||||
const char *err_str = "";
|
||||
|
||||
ret = nlmsg_validate(cb->nlh, nlh_len, policy_max-1, nlmsg_policy);
|
||||
ret = nlmsg_validate(cb->nlh, nlh_len, policy_max - 1, nlmsg_policy,
|
||||
NULL);
|
||||
if (ret) {
|
||||
err_str = "Invalid attribute";
|
||||
goto parse_nlmsg_error;
|
||||
}
|
||||
ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max-1, nlmsg_policy);
|
||||
ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max - 1,
|
||||
nlmsg_policy, NULL);
|
||||
if (ret) {
|
||||
err_str = "Unable to parse the nlmsg";
|
||||
goto parse_nlmsg_error;
|
||||
|
|
|
@ -146,7 +146,8 @@ nla_put_failure:
|
|||
}
|
||||
EXPORT_SYMBOL(ibnl_put_attr);
|
||||
|
||||
static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ibnl_client *client;
|
||||
int type = nlh->nlmsg_type;
|
||||
|
@ -209,7 +210,7 @@ static void ibnl_rcv_reply_skb(struct sk_buff *skb)
|
|||
if (nlh->nlmsg_flags & NLM_F_REQUEST)
|
||||
return;
|
||||
|
||||
ibnl_rcv_msg(skb, nlh);
|
||||
ibnl_rcv_msg(skb, nlh, NULL);
|
||||
|
||||
msglen = NLMSG_ALIGN(nlh->nlmsg_len);
|
||||
if (msglen > skb->len)
|
||||
|
|
|
@ -808,7 +808,7 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
|
|||
return -EPERM;
|
||||
|
||||
ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
|
||||
nlmsg_len(nlh), ib_nl_policy);
|
||||
nlmsg_len(nlh), ib_nl_policy, NULL);
|
||||
attr = (const struct nlattr *)tb[LS_NLA_TYPE_TIMEOUT];
|
||||
if (ret || !attr)
|
||||
goto settimeout_out;
|
||||
|
@ -860,7 +860,7 @@ static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh)
|
|||
return 0;
|
||||
|
||||
ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
|
||||
nlmsg_len(nlh), ib_nl_policy);
|
||||
nlmsg_len(nlh), ib_nl_policy, NULL);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -729,16 +729,6 @@ static inline struct mlx5_ib_mw *to_mmw(struct ib_mw *ibmw)
|
|||
return container_of(ibmw, struct mlx5_ib_mw, ibmw);
|
||||
}
|
||||
|
||||
struct mlx5_ib_ah {
|
||||
struct ib_ah ibah;
|
||||
struct mlx5_av av;
|
||||
};
|
||||
|
||||
static inline struct mlx5_ib_ah *to_mah(struct ib_ah *ibah)
|
||||
{
|
||||
return container_of(ibah, struct mlx5_ib_ah, ibah);
|
||||
}
|
||||
|
||||
int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
|
||||
struct mlx5_db *db);
|
||||
void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db);
|
||||
|
|
|
@ -897,6 +897,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev,
|
|||
if (init_attr->create_flags & ~(IB_QP_CREATE_SIGNATURE_EN |
|
||||
IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
|
||||
IB_QP_CREATE_IPOIB_UD_LSO |
|
||||
IB_QP_CREATE_NETIF_QP |
|
||||
mlx5_ib_create_qp_sqpn_qp1()))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -587,9 +587,8 @@ void qedr_affiliated_event(void *context, u8 e_code, void *fw_handle)
|
|||
#define EVENT_TYPE_CQ 1
|
||||
#define EVENT_TYPE_QP 2
|
||||
struct qedr_dev *dev = (struct qedr_dev *)context;
|
||||
union event_ring_data *data = fw_handle;
|
||||
u64 roce_handle64 = ((u64)data->roce_handle.hi << 32) +
|
||||
data->roce_handle.lo;
|
||||
struct regpair *async_handle = (struct regpair *)fw_handle;
|
||||
u64 roce_handle64 = ((u64) async_handle->hi << 32) + async_handle->lo;
|
||||
u8 event_type = EVENT_TYPE_NOT_DEFINED;
|
||||
struct ib_event event;
|
||||
struct ib_cq *ibcq;
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
#include <linux/qed/qed_chain.h>
|
||||
#include <linux/qed/qed_roce_if.h>
|
||||
#include <linux/qed/qede_roce.h>
|
||||
#include "qedr_hsi.h"
|
||||
#include <linux/qed/roce_common.h>
|
||||
#include "qedr_hsi_rdma.h"
|
||||
|
||||
#define QEDR_MODULE_VERSION "8.10.10.0"
|
||||
#define QEDR_NODE_DESC "QLogic 579xx RoCE HCA"
|
||||
|
|
|
@ -43,14 +43,11 @@
|
|||
#include <rdma/ib_addr.h>
|
||||
#include <rdma/ib_cache.h>
|
||||
|
||||
#include "qedr_hsi.h"
|
||||
#include <linux/qed/qed_if.h>
|
||||
#include <linux/qed/qed_roce_if.h>
|
||||
#include "qedr.h"
|
||||
#include "qedr_hsi.h"
|
||||
#include "verbs.h"
|
||||
#include <rdma/qedr-abi.h>
|
||||
#include "qedr_hsi.h"
|
||||
#include "qedr_cm.h"
|
||||
|
||||
void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info)
|
||||
|
|
|
@ -43,7 +43,8 @@
|
|||
#include <rdma/ib_addr.h>
|
||||
#include <rdma/ib_cache.h>
|
||||
|
||||
#include "qedr_hsi.h"
|
||||
#include <linux/qed/common_hsi.h>
|
||||
#include "qedr_hsi_rdma.h"
|
||||
#include <linux/qed/qed_if.h>
|
||||
#include "qedr.h"
|
||||
#include "verbs.h"
|
||||
|
|
|
@ -157,10 +157,8 @@ int cf_command(int drvid, int mode,
|
|||
/* allocate mem for information struct */
|
||||
if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
|
||||
return (-ENOMEM); /* no memory */
|
||||
init_timer(&cs->timer);
|
||||
setup_timer(&cs->timer, deflect_timer_expire, (ulong)cs);
|
||||
cs->info[0] = '\0';
|
||||
cs->timer.function = deflect_timer_expire;
|
||||
cs->timer.data = (ulong) cs; /* pointer to own structure */
|
||||
cs->ics.driver = drvid;
|
||||
cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
|
||||
cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
|
||||
|
@ -452,10 +450,9 @@ static int isdn_divert_icall(isdn_ctrl *ic)
|
|||
return (0); /* no external deflection needed */
|
||||
if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
|
||||
return (0); /* no memory */
|
||||
init_timer(&cs->timer);
|
||||
setup_timer(&cs->timer, deflect_timer_expire,
|
||||
(ulong)cs);
|
||||
cs->info[0] = '\0';
|
||||
cs->timer.function = deflect_timer_expire;
|
||||
cs->timer.data = (ulong) cs; /* pointer to own structure */
|
||||
|
||||
cs->ics = *ic; /* copy incoming data */
|
||||
if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0");
|
||||
|
|
|
@ -300,9 +300,8 @@ static int um_idi_open_adapter(struct file *file, int adapter_nr)
|
|||
p_os = (diva_um_idi_os_context_t *) diva_um_id_get_os_context(e);
|
||||
init_waitqueue_head(&p_os->read_wait);
|
||||
init_waitqueue_head(&p_os->close_wait);
|
||||
init_timer(&p_os->diva_timer_id);
|
||||
p_os->diva_timer_id.function = (void *) diva_um_timer_function;
|
||||
p_os->diva_timer_id.data = (unsigned long) p_os;
|
||||
setup_timer(&p_os->diva_timer_id, (void *)diva_um_timer_function,
|
||||
(unsigned long)p_os);
|
||||
p_os->aborted = 0;
|
||||
p_os->adapter_nr = adapter_nr;
|
||||
return (1);
|
||||
|
|
|
@ -13,7 +13,7 @@ config MISDN_HFCPCI
|
|||
|
||||
config MISDN_HFCMULTI
|
||||
tristate "Support for HFC multiport cards (HFC-4S/8S/E1)"
|
||||
depends on PCI || 8xx
|
||||
depends on PCI || CPM1
|
||||
depends on MISDN
|
||||
help
|
||||
Enable support for cards with Cologne Chip AG's HFC multiport
|
||||
|
@ -27,8 +27,8 @@ config MISDN_HFCMULTI_8xx
|
|||
bool "Support for XHFC embedded board in HFC multiport driver"
|
||||
depends on MISDN
|
||||
depends on MISDN_HFCMULTI
|
||||
depends on 8xx
|
||||
default 8xx
|
||||
depends on CPM1
|
||||
default CPM1
|
||||
help
|
||||
Enable support for the XHFC embedded solution from Speech Design.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <asm/8xx_immap.h>
|
||||
#include <asm/cpm1.h>
|
||||
|
||||
/* Change this to the value used by your board */
|
||||
#ifndef IMAP_ADDR
|
||||
|
|
|
@ -3878,9 +3878,8 @@ hfcmulti_initmode(struct dchannel *dch)
|
|||
if (hc->dnum[pt]) {
|
||||
mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol,
|
||||
-1, 0, -1, 0);
|
||||
dch->timer.function = (void *) hfcmulti_dbusy_timer;
|
||||
dch->timer.data = (long) dch;
|
||||
init_timer(&dch->timer);
|
||||
setup_timer(&dch->timer, (void *)hfcmulti_dbusy_timer,
|
||||
(long)dch);
|
||||
}
|
||||
for (i = 1; i <= 31; i++) {
|
||||
if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
|
||||
|
@ -3986,9 +3985,8 @@ hfcmulti_initmode(struct dchannel *dch)
|
|||
hc->chan[i].slot_rx = -1;
|
||||
hc->chan[i].conf = -1;
|
||||
mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0);
|
||||
dch->timer.function = (void *) hfcmulti_dbusy_timer;
|
||||
dch->timer.data = (long) dch;
|
||||
init_timer(&dch->timer);
|
||||
setup_timer(&dch->timer, (void *)hfcmulti_dbusy_timer,
|
||||
(long)dch);
|
||||
hc->chan[i - 2].slot_tx = -1;
|
||||
hc->chan[i - 2].slot_rx = -1;
|
||||
hc->chan[i - 2].conf = -1;
|
||||
|
|
|
@ -1717,9 +1717,8 @@ static void
|
|||
inithfcpci(struct hfc_pci *hc)
|
||||
{
|
||||
printk(KERN_DEBUG "inithfcpci: entered\n");
|
||||
hc->dch.timer.function = (void *) hfcpci_dbusy_timer;
|
||||
hc->dch.timer.data = (long) &hc->dch;
|
||||
init_timer(&hc->dch.timer);
|
||||
setup_timer(&hc->dch.timer, (void *)hfcpci_dbusy_timer,
|
||||
(long)&hc->dch);
|
||||
hc->chanlimit = 2;
|
||||
mode_hfcpci(&hc->bch[0], 1, -1);
|
||||
mode_hfcpci(&hc->bch[1], 2, -1);
|
||||
|
@ -2044,9 +2043,7 @@ setup_hw(struct hfc_pci *hc)
|
|||
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
|
||||
/* At this point the needed PCI config is done */
|
||||
/* fifos are still not enabled */
|
||||
hc->hw.timer.function = (void *) hfcpci_Timer;
|
||||
hc->hw.timer.data = (long) hc;
|
||||
init_timer(&hc->hw.timer);
|
||||
setup_timer(&hc->hw.timer, (void *)hfcpci_Timer, (long)hc);
|
||||
/* default PCM master */
|
||||
test_and_set_bit(HFC_CFG_MASTER, &hc->cfg);
|
||||
return 0;
|
||||
|
|
|
@ -796,9 +796,8 @@ isac_init(struct isac_hw *isac)
|
|||
}
|
||||
isac->mon_tx = NULL;
|
||||
isac->mon_rx = NULL;
|
||||
isac->dch.timer.function = (void *) dbusy_timer_handler;
|
||||
isac->dch.timer.data = (long)isac;
|
||||
init_timer(&isac->dch.timer);
|
||||
setup_timer(&isac->dch.timer, (void *)dbusy_timer_handler,
|
||||
(long)isac);
|
||||
isac->mocr = 0xaa;
|
||||
if (isac->type & IPAC_TYPE_ISACX) {
|
||||
/* Disable all IRQ */
|
||||
|
|
|
@ -1635,13 +1635,11 @@ init_isar(struct isar_hw *isar)
|
|||
}
|
||||
if (isar->version != 1)
|
||||
return -EINVAL;
|
||||
isar->ch[0].ftimer.function = &ftimer_handler;
|
||||
isar->ch[0].ftimer.data = (long)&isar->ch[0];
|
||||
init_timer(&isar->ch[0].ftimer);
|
||||
setup_timer(&isar->ch[0].ftimer, &ftimer_handler,
|
||||
(long)&isar->ch[0]);
|
||||
test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
|
||||
isar->ch[1].ftimer.function = &ftimer_handler;
|
||||
isar->ch[1].ftimer.data = (long)&isar->ch[1];
|
||||
init_timer(&isar->ch[1].ftimer);
|
||||
setup_timer(&isar->ch[1].ftimer, &ftimer_handler,
|
||||
(long)&isar->ch[1]);
|
||||
test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -852,9 +852,8 @@ static void initW6692(struct w6692_hw *card)
|
|||
{
|
||||
u8 val;
|
||||
|
||||
card->dch.timer.function = (void *)dbusy_timer_handler;
|
||||
card->dch.timer.data = (u_long)&card->dch;
|
||||
init_timer(&card->dch.timer);
|
||||
setup_timer(&card->dch.timer, (void *)dbusy_timer_handler,
|
||||
(u_long)&card->dch);
|
||||
w6692_mode(&card->bc[0], ISDN_P_NONE);
|
||||
w6692_mode(&card->bc[1], ISDN_P_NONE);
|
||||
WriteW6692(card, W_D_CTL, 0x00);
|
||||
|
|
|
@ -789,7 +789,5 @@ void Amd7930_init(struct IsdnCardState *cs)
|
|||
void setup_Amd7930(struct IsdnCardState *cs)
|
||||
{
|
||||
INIT_WORK(&cs->tqueue, Amd7930_bh);
|
||||
cs->dbusytimer.function = (void *) dbusy_timer_handler;
|
||||
cs->dbusytimer.data = (long) cs;
|
||||
init_timer(&cs->dbusytimer);
|
||||
setup_timer(&cs->dbusytimer, (void *)dbusy_timer_handler, (long)cs);
|
||||
}
|
||||
|
|
|
@ -125,9 +125,7 @@ clear_arcofi(struct IsdnCardState *cs) {
|
|||
|
||||
void
|
||||
init_arcofi(struct IsdnCardState *cs) {
|
||||
cs->dc.isac.arcofitimer.function = (void *) arcofi_timer;
|
||||
cs->dc.isac.arcofitimer.data = (long) cs;
|
||||
init_timer(&cs->dc.isac.arcofitimer);
|
||||
setup_timer(&cs->dc.isac.arcofitimer, (void *)arcofi_timer, (long)cs);
|
||||
init_waitqueue_head(&cs->dc.isac.arcofi_wait);
|
||||
test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
|
||||
}
|
||||
|
|
|
@ -976,9 +976,8 @@ static int setup_diva_common(struct IsdnCardState *cs)
|
|||
printk(KERN_INFO "Diva: IPACX Design Id: %x\n",
|
||||
MemReadISAC_IPACX(cs, IPACX_ID) & 0x3F);
|
||||
} else { /* DIVA 2.0 */
|
||||
cs->hw.diva.tl.function = (void *) diva_led_handler;
|
||||
cs->hw.diva.tl.data = (long) cs;
|
||||
init_timer(&cs->hw.diva.tl);
|
||||
setup_timer(&cs->hw.diva.tl, (void *)diva_led_handler,
|
||||
(long)cs);
|
||||
cs->readisac = &ReadISAC;
|
||||
cs->writeisac = &WriteISAC;
|
||||
cs->readisacfifo = &ReadISACfifo;
|
||||
|
|
|
@ -1147,9 +1147,7 @@ static int setup_elsa_common(struct IsdnCard *card)
|
|||
init_arcofi(cs);
|
||||
#endif
|
||||
setup_isac(cs);
|
||||
cs->hw.elsa.tl.function = (void *) elsa_led_handler;
|
||||
cs->hw.elsa.tl.data = (long) cs;
|
||||
init_timer(&cs->hw.elsa.tl);
|
||||
setup_timer(&cs->hw.elsa.tl, (void *)elsa_led_handler, (long)cs);
|
||||
/* Teste Timer */
|
||||
if (cs->hw.elsa.timer) {
|
||||
byteout(cs->hw.elsa.trig, 0xff);
|
||||
|
|
|
@ -98,13 +98,11 @@ void
|
|||
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
|
||||
{
|
||||
ft->fi = fi;
|
||||
ft->tl.function = (void *) FsmExpireTimer;
|
||||
ft->tl.data = (long) ft;
|
||||
#if FSM_TIMER_DEBUG
|
||||
if (ft->fi->debug)
|
||||
ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
|
||||
#endif
|
||||
init_timer(&ft->tl);
|
||||
setup_timer(&ft->tl, (void *)FsmExpireTimer, (long)ft);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue