1
0
Fork 0

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

Pull networking updates from David Miller:

 1) Seccomp BPF filters can now be JIT'd, from Alexei Starovoitov.

 2) Multiqueue support in xen-netback and xen-netfront, from Andrew J
    Benniston.

 3) Allow tweaking of aggregation settings in cdc_ncm driver, from Bjørn
    Mork.

 4) BPF now has a "random" opcode, from Chema Gonzalez.

 5) Add more BPF documentation and improve test framework, from Daniel
    Borkmann.

 6) Support TCP fastopen over ipv6, from Daniel Lee.

 7) Add software TSO helper functions and use them to support software
    TSO in mvneta and mv643xx_eth drivers.  From Ezequiel Garcia.

 8) Support software TSO in fec driver too, from Nimrod Andy.

 9) Add Broadcom SYSTEMPORT driver, from Florian Fainelli.

10) Handle broadcasts more gracefully over macvlan when there are large
    numbers of interfaces configured, from Herbert Xu.

11) Allow more control over fwmark used for non-socket based responses,
    from Lorenzo Colitti.

12) Do TCP congestion window limiting based upon measurements, from Neal
    Cardwell.

13) Support busy polling in SCTP, from Neal Horman.

14) Allow RSS key to be configured via ethtool, from Venkata Duvvuru.

15) Bridge promisc mode handling improvements from Vlad Yasevich.

16) Don't use inetpeer entries to implement ID generation any more, it
    performs poorly, from Eric Dumazet.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1522 commits)
  rtnetlink: fix userspace API breakage for iproute2 < v3.9.0
  tcp: fixing TLP's FIN recovery
  net: fec: Add software TSO support
  net: fec: Add Scatter/gather support
  net: fec: Increase buffer descriptor entry number
  net: fec: Factorize feature setting
  net: fec: Enable IP header hardware checksum
  net: fec: Factorize the .xmit transmit function
  bridge: fix compile error when compiling without IPv6 support
  bridge: fix smatch warning / potential null pointer dereference
  via-rhine: fix full-duplex with autoneg disable
  bnx2x: Enlarge the dorq threshold for VFs
  bnx2x: Check for UNDI in uncommon branch
  bnx2x: Fix 1G-baseT link
  bnx2x: Fix link for KR with swapped polarity lane
  sctp: Fix sk_ack_backlog wrap-around problem
  net/core: Add VF link state control policy
  net/fsl: xgmac_mdio is dependent on OF_MDIO
  net/fsl: Make xgmac_mdio read error message useful
  net_sched: drr: warn when qdisc is not work conserving
  ...
hifive-unleashed-5.1
Linus Torvalds 2014-06-12 14:27:40 -07:00
commit f9da455b93
1265 changed files with 61688 additions and 23103 deletions

View File

@ -169,6 +169,14 @@ Description:
"unknown", "notpresent", "down", "lowerlayerdown", "testing",
"dormant", "up".
What: /sys/class/net/<iface>/phys_port_id
Date: July 2013
KernelVersion: 3.12
Contact: netdev@vger.kernel.org
Description:
Indicates the interface unique physical port identifier within
the NIC, as a string.
What: /sys/class/net/<iface>/speed
Date: October 2009
KernelVersion: 2.6.33

View File

@ -0,0 +1,149 @@
What: /sys/class/net/<iface>/cdc_ncm/min_tx_pkt
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
The driver will pad NCM Transfer Blocks (NTBs) longer
than this to tx_max, allowing the device to receive
tx_max sized frames with no terminating short
packet. NTBs shorter than this limit are transmitted
as-is, without any padding, and are terminated with a
short USB packet.
Padding to tx_max allows the driver to transmit NTBs
back-to-back without any interleaving short USB
packets. This reduces the number of short packet
interrupts in the device, and represents a tradeoff
between USB bus bandwidth and device DMA optimization.
Set to 0 to pad all frames. Set greater than tx_max to
disable all padding.
What: /sys/class/net/<iface>/cdc_ncm/rx_max
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
The maximum NTB size for RX. Cannot exceed the
maximum value supported by the device. Must allow at
least one max sized datagram plus headers.
The actual limits are device dependent. See
dwNtbInMaxSize.
Note: Some devices will silently ignore changes to
this value, resulting in oversized NTBs and
corresponding framing errors.
What: /sys/class/net/<iface>/cdc_ncm/tx_max
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
The maximum NTB size for TX. Cannot exceed the
maximum value supported by the device. Must allow at
least one max sized datagram plus headers.
The actual limits are device dependent. See
dwNtbOutMaxSize.
What: /sys/class/net/<iface>/cdc_ncm/tx_timer_usecs
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
Datagram aggregation timeout in µs. The driver will
wait up to 3 times this timeout for more datagrams to
aggregate before transmitting an NTB frame.
Valid range: 5 to 4000000
Set to 0 to disable aggregation.
The following read-only attributes all represent fields of the
structure defined in section 6.2.1 "GetNtbParameters" of "Universal
Serial Bus Communications Class Subclass Specifications for Network
Control Model Devices" (CDC NCM), Revision 1.0 (Errata 1), November
24, 2010 from USB Implementers Forum, Inc. The descriptions are
quoted from table 6-3 of CDC NCM: "NTB Parameter Structure".
What: /sys/class/net/<iface>/cdc_ncm/bmNtbFormatsSupported
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
Bit 0: 16-bit NTB supported (set to 1)
Bit 1: 32-bit NTB supported
Bits 2 15: reserved (reset to zero; must be ignored by host)
What: /sys/class/net/<iface>/cdc_ncm/dwNtbInMaxSize
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
IN NTB Maximum Size in bytes
What: /sys/class/net/<iface>/cdc_ncm/wNdpInDivisor
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
Divisor used for IN NTB Datagram payload alignment
What: /sys/class/net/<iface>/cdc_ncm/wNdpInPayloadRemainder
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
Remainder used to align input datagram payload within
the NTB: (Payload Offset) mod (wNdpInDivisor) =
wNdpInPayloadRemainder
What: /sys/class/net/<iface>/cdc_ncm/wNdpInAlignment
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
NDP alignment modulus for NTBs on the IN pipe. Shall
be a power of 2, and shall be at least 4.
What: /sys/class/net/<iface>/cdc_ncm/dwNtbOutMaxSize
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
OUT NTB Maximum Size
What: /sys/class/net/<iface>/cdc_ncm/wNdpOutDivisor
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
OUT NTB Datagram alignment modulus
What: /sys/class/net/<iface>/cdc_ncm/wNdpOutPayloadRemainder
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
Remainder used to align output datagram payload
offsets within the NTB: Padding, shall be transmitted
as zero by function, and ignored by host. (Payload
Offset) mod (wNdpOutDivisor) = wNdpOutPayloadRemainder
What: /sys/class/net/<iface>/cdc_ncm/wNdpOutAlignment
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
NDP alignment modulus for use in NTBs on the OUT
pipe. Shall be a power of 2, and shall be at least 4.
What: /sys/class/net/<iface>/cdc_ncm/wNtbOutMaxDatagrams
Date: May 2014
KernelVersion: 3.16
Contact: Bjørn Mork <bjorn@mork.no>
Description:
Maximum number of datagrams that the host may pack
into a single OUT NTB. Zero means that the device
imposes no limit.

View File

@ -0,0 +1,79 @@
What: /sys/class/<iface>/queues/rx-<queue>/rps_cpus
Date: March 2010
KernelVersion: 2.6.35
Contact: netdev@vger.kernel.org
Description:
Mask of the CPU(s) currently enabled to participate into the
Receive Packet Steering packet processing flow for this
network device queue. Possible values depend on the number
of available CPU(s) in the system.
What: /sys/class/<iface>/queues/rx-<queue>/rps_flow_cnt
Date: April 2010
KernelVersion: 2.6.35
Contact: netdev@vger.kernel.org
Description:
Number of Receive Packet Steering flows being currently
processed by this particular network device receive queue.
What: /sys/class/<iface>/queues/tx-<queue>/tx_timeout
Date: November 2011
KernelVersion: 3.3
Contact: netdev@vger.kernel.org
Description:
Indicates the number of transmit timeout events seen by this
network interface transmit queue.
What: /sys/class/<iface>/queues/tx-<queue>/xps_cpus
Date: November 2010
KernelVersion: 2.6.38
Contact: netdev@vger.kernel.org
Description:
Mask of the CPU(s) currently enabled to participate into the
Transmit Packet Steering packet processing flow for this
network device transmit queue. Possible vaules depend on the
number of available CPU(s) in the system.
What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time
Date: November 2011
KernelVersion: 3.3
Contact: netdev@vger.kernel.org
Description:
Indicates the hold time in milliseconds to measure the slack
of this particular network device transmit queue.
Default value is 1000.
What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/inflight
Date: November 2011
KernelVersion: 3.3
Contact: netdev@vger.kernel.org
Description:
Indicates the number of bytes (objects) in flight on this
network device transmit queue.
What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit
Date: November 2011
KernelVersion: 3.3
Contact: netdev@vger.kernel.org
Description:
Indicates the current limit of bytes allowed to be queued
on this network device transmit queue. This value is clamped
to be within the bounds defined by limit_max and limit_min.
What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max
Date: November 2011
KernelVersion: 3.3
Contact: netdev@vger.kernel.org
Description:
Indicates the absolute maximum limit of bytes allowed to be
queued on this network device transmit queue. See
include/linux/dynamic_queue_limits.h for the default value.
What: /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min
Date: November 2011
KernelVersion: 3.3
Contact: netdev@vger.kernel.org
Description:
Indicates the absolute minimum limit of bytes allowed to be
queued on this network device transmit queue. Default value is
0.

View File

@ -0,0 +1,201 @@
What: /sys/class/<iface>/statistics/collisions
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of collisions seen by this network device.
This value might not be relevant with all MAC layers.
What: /sys/class/<iface>/statistics/multicast
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of multicast packets received by this
network device.
What: /sys/class/<iface>/statistics/rx_bytes
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of bytes received by this network device.
See the network driver for the exact meaning of when this
value is incremented.
What: /sys/class/<iface>/statistics/rx_compressed
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of compressed packets received by this
network device. This value might only be relevant for interfaces
that support packet compression (e.g: PPP).
What: /sys/class/<iface>/statistics/rx_crc_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets received with a CRC (FCS) error
by this network device. Note that the specific meaning might
depend on the MAC layer used by the interface.
What: /sys/class/<iface>/statistics/rx_dropped
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets received by the network device
but dropped, that are not forwarded to the upper layers for
packet processing. See the network driver for the exact
meaning of this value.
What: /sys/class/<iface>/statistics/rx_fifo_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of receive FIFO errors seen by this
network device. See the network driver for the exact
meaning of this value.
What: /sys/class/<iface>/statistics/rx_frame_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of received frames with error, such as
alignment errors. Note that the specific meaning depends on
on the MAC layer protocol used. See the network driver for
the exact meaning of this value.
What: /sys/class/<iface>/statistics/rx_length_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of received error packet with a length
error, oversized or undersized. See the network driver for the
exact meaning of this value.
What: /sys/class/<iface>/statistics/rx_missed_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of received packets that have been missed
due to lack of capacity in the receive side. See the network
driver for the exact meaning of this value.
What: /sys/class/<iface>/statistics/rx_over_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of received packets that are oversized
compared to what the network device is configured to accept
(e.g: larger than MTU). See the network driver for the exact
meaning of this value.
What: /sys/class/<iface>/statistics/rx_packets
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the total number of good packets received by this
network device.
What: /sys/class/<iface>/statistics/tx_aborted_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets that have been aborted
during transmission by a network device (e.g: because of
a medium collision). See the network driver for the exact
meaning of this value.
What: /sys/class/<iface>/statistics/tx_bytes
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of bytes transmitted by a network
device. See the network driver for the exact meaning of this
value, in particular whether this accounts for all successfully
transmitted packets or all packets that have been queued for
transmission.
What: /sys/class/<iface>/statistics/tx_carrier_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets that could not be transmitted
because of carrier errors (e.g: physical link down). See the
network driver for the exact meaning of this value.
What: /sys/class/<iface>/statistics/tx_compressed
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of transmitted compressed packets. Note
this might only be relevant for devices that support
compression (e.g: PPP).
What: /sys/class/<iface>/statistics/tx_dropped
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets dropped during transmission.
See the driver for the exact reasons as to why the packets were
dropped.
What: /sys/class/<iface>/statistics/tx_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets in error during transmission by
a network device. See the driver for the exact reasons as to
why the packets were dropped.
What: /sys/class/<iface>/statistics/tx_fifo_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets having caused a transmit
FIFO error. See the driver for the exact reasons as to why the
packets were dropped.
What: /sys/class/<iface>/statistics/tx_heartbeat_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets transmitted that have been
reported as heartbeat errors. See the driver for the exact
reasons as to why the packets were dropped.
What: /sys/class/<iface>/statistics/tx_packets
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets transmitted by a network
device. See the driver for whether this reports the number of all
attempted or successful transmissions.
What: /sys/class/<iface>/statistics/tx_window_errors
Date: April 2005
KernelVersion: 2.6.12
Contact: netdev@vger.kernel.org
Description:
Indicates the number of packets not successfully transmitted
due to a window collision. The specific meaning depends on the
MAC layer used. On Ethernet this is usually used to report
late collisions errors.

View File

@ -100,6 +100,7 @@
!Finclude/net/cfg80211.h wdev_priv
!Finclude/net/cfg80211.h ieee80211_iface_limit
!Finclude/net/cfg80211.h ieee80211_iface_combination
!Finclude/net/cfg80211.h cfg80211_check_combinations
</chapter>
<chapter>
<title>Actions and configuration</title>

View File

@ -0,0 +1,17 @@
* AMD 10GbE PHY driver (amd-xgbe-phy)
Required properties:
- compatible: Should be "amd,xgbe-phy-seattle-v1a" and
"ethernet-phy-ieee802.3-c45"
- reg: Address and length of the register sets for the device
- SerDes Rx/Tx registers
- SerDes integration registers (1/2)
- SerDes integration registers (2/2)
Example:
xgbe_phy@e1240800 {
compatible = "amd,xgbe-phy-seattle-v1a", "ethernet-phy-ieee802.3-c45";
reg = <0 0xe1240800 0 0x00400>,
<0 0xe1250000 0 0x00060>,
<0 0xe1250080 0 0x00004>;
};

View File

@ -0,0 +1,34 @@
* AMD 10GbE driver (amd-xgbe)
Required properties:
- compatible: Should be "amd,xgbe-seattle-v1a"
- reg: Address and length of the register sets for the device
- MAC registers
- PCS registers
- interrupt-parent: Should be the phandle for the interrupt controller
that services interrupts for this device
- interrupts: Should contain the amd-xgbe interrupt
- clocks: Should be the DMA clock for the amd-xgbe device (used for
calculating the correct Rx interrupt watchdog timer value on a DMA
channel for coalescing)
- clock-names: Should be the name of the DMA clock, "dma_clk"
- phy-handle: See ethernet.txt file in the same directory
- phy-mode: See ethernet.txt file in the same directory
Optional properties:
- mac-address: mac address to be assigned to the device. Can be overridden
by UEFI.
Example:
xgbe@e0700000 {
compatible = "amd,xgbe-seattle-v1a";
reg = <0 0xe0700000 0 0x80000>,
<0 0xe0780000 0 0x80000>;
interrupt-parent = <&gic>;
interrupts = <0 325 4>;
clocks = <&xgbe_clk>;
clock-names = "dma_clk";
phy-handle = <&phy>;
phy-mode = "xgmii";
mac-address = [ 02 a1 a2 a3 a4 a5 ];
};

View File

@ -24,7 +24,7 @@ Optional properties:
- fixed-link: When the GENET interface is connected to a MoCA hardware block or
when operating in a RGMII to RGMII type of connection, or when the MDIO bus is
voluntarily disabled, this property should be used to describe the "fixed link".
See Documentation/devicetree/bindings/net/fsl-tsec-phy.txt for information on
See Documentation/devicetree/bindings/net/fixed-link.txt for information on
the property specifics
Required child nodes:

View File

@ -0,0 +1,29 @@
* Broadcom BCM7xxx Ethernet Systemport Controller (SYSTEMPORT)
Required properties:
- compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport"
- reg: address and length of the register set for the device.
- interrupts: interrupts for the device, first cell must be for the the rx
interrupts, and the second cell should be for the transmit queues
- local-mac-address: Ethernet MAC address (48 bits) of this adapter
- phy-mode: Should be a string describing the PHY interface to the
Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt
- fixed-link: see Documentation/devicetree/bindings/net/fixed-link.txt for
the property specific details
Optional properties:
- systemport,num-tier2-arb: number of tier 2 arbiters, an integer
- systemport,num-tier1-arb: number of tier 1 arbiters, an integer
- systemport,num-txq: number of HW transmit queues, an integer
- systemport,num-rxq: number of HW receive queues, an integer
Example:
ethernet@f04a0000 {
compatible = "brcm,systemport-v1.00";
reg = <0xf04a0000 0x4650>;
local-mac-address = [ 00 11 22 33 44 55 ];
fixed-link = <0 1 1000 0 0>;
phy-mode = "gmii";
interrupts = <0x0 0x16 0x0>,
<0x0 0x17 0x0>;
};

View File

@ -0,0 +1,44 @@
Xilinx Axi CAN/Zynq CANPS controller Device Tree Bindings
---------------------------------------------------------
Required properties:
- compatible : Should be "xlnx,zynq-can-1.0" for Zynq CAN
controllers and "xlnx,axi-can-1.00.a" for Axi CAN
controllers.
- reg : Physical base address and size of the Axi CAN/Zynq
CANPS registers map.
- interrupts : Property with a value describing the interrupt
number.
- interrupt-parent : Must be core interrupt controller
- clock-names : List of input clock names - "can_clk", "pclk"
(For CANPS), "can_clk" , "s_axi_aclk"(For AXI CAN)
(See clock bindings for details).
- clocks : Clock phandles (see clock bindings for details).
- tx-fifo-depth : Can Tx fifo depth.
- rx-fifo-depth : Can Rx fifo depth.
Example:
For Zynq CANPS Dts file:
zynq_can_0: can@e0008000 {
compatible = "xlnx,zynq-can-1.0";
clocks = <&clkc 19>, <&clkc 36>;
clock-names = "can_clk", "pclk";
reg = <0xe0008000 0x1000>;
interrupts = <0 28 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
For Axi CAN Dts file:
axi_can_0: axi-can@40000000 {
compatible = "xlnx,axi-can-1.00.a";
clocks = <&clkc 0>, <&clkc 1>;
clock-names = "can_clk","s_axi_aclk" ;
reg = <0x40000000 0x10000>;
interrupt-parent = <&intc>;
interrupts = <0 59 1>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};

View File

@ -2,7 +2,9 @@ TI CPSW Phy mode Selection Device Tree Bindings
-----------------------------------------------
Required properties:
- compatible : Should be "ti,am3352-cpsw-phy-sel"
- compatible : Should be "ti,am3352-cpsw-phy-sel" for am335x platform and
"ti,dra7xx-cpsw-phy-sel" for dra7xx platform
"ti,am43xx-cpsw-phy-sel" for am43xx platform
- reg : physical base address and size of the cpsw
registers map
- reg-names : names of the register map given in "reg" node

View File

@ -0,0 +1,42 @@
Fixed link Device Tree binding
------------------------------
Some Ethernet MACs have a "fixed link", and are not connected to a
normal MDIO-managed PHY device. For those situations, a Device Tree
binding allows to describe a "fixed link".
Such a fixed link situation is described by creating a 'fixed-link'
sub-node of the Ethernet MAC device node, with the following
properties:
* 'speed' (integer, mandatory), to indicate the link speed. Accepted
values are 10, 100 and 1000
* 'full-duplex' (boolean, optional), to indicate that full duplex is
used. When absent, half duplex is assumed.
* 'pause' (boolean, optional), to indicate that pause should be
enabled.
* 'asym-pause' (boolean, optional), to indicate that asym_pause should
be enabled.
Old, deprecated 'fixed-link' binding:
* A 'fixed-link' property in the Ethernet MAC node, with 5 cells, of the
form <a b c d e> with the following accepted values:
- a: emulated PHY ID, choose any but but unique to the all specified
fixed-links, from 0 to 31
- b: duplex configuration: 0 for half duplex, 1 for full duplex
- c: link speed in Mbits/sec, accepted values are: 10, 100 and 1000
- d: pause configuration: 0 for no pause, 1 for pause
- e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for
asymmetric pause
Example:
ethernet@0 {
...
fixed-link {
speed = <1000>;
full-duplex;
};
...
};

View File

@ -42,10 +42,7 @@ Properties:
interrupt. For TSEC and eTSEC devices, the first interrupt is
transmit, the second is receive, and the third is error.
- phy-handle : See ethernet.txt file in the same directory.
- fixed-link : <a b c d e> where a is emulated phy id - choose any,
but unique to the all specified fixed-links, b is duplex - 0 half,
1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
- fixed-link : See fixed-link.txt in the same directory.
- phy-connection-type : See ethernet.txt file in the same directory.
This property is only really needed if the connection is of type
"rgmii-id", as all other connection types are detected by hardware.

View File

@ -0,0 +1,36 @@
Hisilicon hix5hd2 gmac controller
Required properties:
- compatible: should be "hisilicon,hix5hd2-gmac".
- reg: specifies base physical address(s) and size of the device registers.
The first region is the MAC register base and size.
The second region is external interface control register.
- interrupts: should contain the MAC interrupt.
- #address-cells: must be <1>.
- #size-cells: must be <0>.
- phy-mode: see ethernet.txt [1].
- phy-handle: see ethernet.txt [1].
- mac-address: see ethernet.txt [1].
- clocks: clock phandle and specifier pair.
- PHY subnode: inherits from phy binding [2]
[1] Documentation/devicetree/bindings/net/ethernet.txt
[2] Documentation/devicetree/bindings/net/phy.txt
Example:
gmac0: ethernet@f9840000 {
compatible = "hisilicon,hix5hd2-gmac";
reg = <0xf9840000 0x1000>,<0xf984300c 0x4>;
interrupts = <0 71 4>;
#address-cells = <1>;
#size-cells = <0>;
phy-mode = "mii";
phy-handle = <&phy2>;
mac-address = [00 00 00 00 00 00];
clocks = <&clock HIX5HD2_MAC0_CLK>;
phy2: ethernet-phy@2 {
reg = <2>;
};
};

View File

@ -0,0 +1,23 @@
* AT86RF230 IEEE 802.15.4 *
Required properties:
- compatible: should be "atmel,at86rf230", "atmel,at86rf231",
"atmel,at86rf233" or "atmel,at86rf212"
- spi-max-frequency: maximal bus speed, should be set to 7500000 depends
sync or async operation mode
- reg: the chipselect index
- interrupts: the interrupt generated by the device
Optional properties:
- reset-gpio: GPIO spec for the rstn pin
- sleep-gpio: GPIO spec for the slp_tr pin
Example:
at86rf231@0 {
compatible = "atmel,at86rf231";
spi-max-frequency = <7500000>;
reg = <0>;
interrupts = <19 1>;
interrupt-parent = <&gpio3>;
};

View File

@ -1,9 +1,18 @@
Micrel KS8851 Ethernet mac
Micrel KS8851 Ethernet mac (MLL)
Required properties:
- compatible = "micrel,ks8851-ml" of parallel interface
- compatible = "micrel,ks8851-mll" of parallel interface
- reg : 2 physical address and size of registers for data and command
- interrupts : interrupt connection
Micrel KS8851 Ethernet mac (SPI)
Required properties:
- compatible = "micrel,ks8851" or the deprecated "ks8851"
- reg : chip select number
- interrupts : interrupt connection
Optional properties:
- vdd-supply: supply for Ethernet mac
- vdd-supply: analog 3.3V supply for Ethernet mac
- vdd-io-supply: digital 1.8V IO supply for Ethernet mac
- reset-gpios: reset_n input pin

View File

@ -1,49 +0,0 @@
Micrel KSZ9021 Gigabit Ethernet PHY
Some boards require special tuning values, particularly when it comes to
clock delays. You can specify clock delay values by adding
micrel-specific properties to an Ethernet OF device node.
All skew control options are specified in picoseconds. The minimum
value is 0, and the maximum value is 3000.
Optional properties:
- rxc-skew-ps : Skew control of RXC pad
- rxdv-skew-ps : Skew control of RX CTL pad
- txc-skew-ps : Skew control of TXC pad
- txen-skew-ps : Skew control of TX_CTL pad
- rxd0-skew-ps : Skew control of RX data 0 pad
- rxd1-skew-ps : Skew control of RX data 1 pad
- rxd2-skew-ps : Skew control of RX data 2 pad
- rxd3-skew-ps : Skew control of RX data 3 pad
- txd0-skew-ps : Skew control of TX data 0 pad
- txd1-skew-ps : Skew control of TX data 1 pad
- txd2-skew-ps : Skew control of TX data 2 pad
- txd3-skew-ps : Skew control of TX data 3 pad
Examples:
/* Attach to an Ethernet device with autodetected PHY */
&enet {
rxc-skew-ps = <3000>;
rxdv-skew-ps = <0>;
txc-skew-ps = <3000>;
txen-skew-ps = <0>;
status = "okay";
};
/* Attach to an explicitly-specified PHY */
mdio {
phy0: ethernet-phy@0 {
rxc-skew-ps = <3000>;
rxdv-skew-ps = <0>;
txc-skew-ps = <3000>;
txen-skew-ps = <0>;
reg = <0>;
};
};
ethernet@70000 {
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};

View File

@ -0,0 +1,83 @@
Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY
Some boards require special tuning values, particularly when it comes to
clock delays. You can specify clock delay values by adding
micrel-specific properties to an Ethernet OF device node.
Note that these settings are applied after any phy-specific fixup from
phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c),
and therefore may overwrite them.
KSZ9021:
All skew control options are specified in picoseconds. The minimum
value is 0, the maximum value is 3000, and it is incremented by 200ps
steps.
Optional properties:
- rxc-skew-ps : Skew control of RXC pad
- rxdv-skew-ps : Skew control of RX CTL pad
- txc-skew-ps : Skew control of TXC pad
- txen-skew-ps : Skew control of TX CTL pad
- rxd0-skew-ps : Skew control of RX data 0 pad
- rxd1-skew-ps : Skew control of RX data 1 pad
- rxd2-skew-ps : Skew control of RX data 2 pad
- rxd3-skew-ps : Skew control of RX data 3 pad
- txd0-skew-ps : Skew control of TX data 0 pad
- txd1-skew-ps : Skew control of TX data 1 pad
- txd2-skew-ps : Skew control of TX data 2 pad
- txd3-skew-ps : Skew control of TX data 3 pad
KSZ9031:
All skew control options are specified in picoseconds. The minimum
value is 0, and the maximum is property-dependent. The increment
step is 60ps.
Optional properties:
Maximum value of 1860:
- rxc-skew-ps : Skew control of RX clock pad
- txc-skew-ps : Skew control of TX clock pad
Maximum value of 900:
- rxdv-skew-ps : Skew control of RX CTL pad
- txen-skew-ps : Skew control of TX CTL pad
- rxd0-skew-ps : Skew control of RX data 0 pad
- rxd1-skew-ps : Skew control of RX data 1 pad
- rxd2-skew-ps : Skew control of RX data 2 pad
- rxd3-skew-ps : Skew control of RX data 3 pad
- txd0-skew-ps : Skew control of TX data 0 pad
- txd1-skew-ps : Skew control of TX data 1 pad
- txd2-skew-ps : Skew control of TX data 2 pad
- txd3-skew-ps : Skew control of TX data 3 pad
Examples:
/* Attach to an Ethernet device with autodetected PHY */
&enet {
rxc-skew-ps = <3000>;
rxdv-skew-ps = <0>;
txc-skew-ps = <3000>;
txen-skew-ps = <0>;
status = "okay";
};
/* Attach to an explicitly-specified PHY */
mdio {
phy0: ethernet-phy@0 {
rxc-skew-ps = <3000>;
rxdv-skew-ps = <0>;
txc-skew-ps = <3000>;
txen-skew-ps = <0>;
reg = <0>;
};
};
ethernet@70000 {
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};

View File

@ -0,0 +1,35 @@
* NXP Semiconductors PN544 NFC Controller
Required properties:
- compatible: Should be "nxp,pn544-i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected
- enable-gpios: Output GPIO pin used for enabling/disabling the PN544
- firmware-gpios: Output GPIO pin used to enter firmware download mode
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
Example (for ARM-based BeagleBone with PN544 on I2C2):
&i2c2 {
status = "okay";
pn544: pn544@28 {
compatible = "nxp,pn544-i2c";
reg = <0x28>;
clock-frequency = <400000>;
interrupt-parent = <&gpio1>;
interrupts = <17 GPIO_ACTIVE_HIGH>;
enable-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
firmware-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,33 @@
* STMicroelectronics SAS. ST21NFCA NFC Controller
Required properties:
- compatible: Should be "st,st21nfca_i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected
- enable-gpios: Output GPIO pin used for enabling/disabling the ST21NFCA
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
&i2c2 {
status = "okay";
st21nfca: st21nfca@1 {
compatible = "st,st21nfca_i2c";
reg = <0x01>;
clock-frequency = <400000>;
interrupt-parent = <&gpio5>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -12,6 +12,7 @@ Required properties:
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
- autosuspend-delay: Specify autosuspend delay in milliseconds.
Example (for ARM-based BeagleBone with TRF7970A on SPI1):
@ -29,6 +30,7 @@ Example (for ARM-based BeagleBone with TRF7970A on SPI1):
ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>,
<&gpio2 5 GPIO_ACTIVE_LOW>;
vin-supply = <&ldo3_reg>;
autosuspend-delay = <30000>;
status = "okay";
};
};

View File

@ -0,0 +1,17 @@
* VIA Rhine 10/100 Network Controller
Required properties:
- compatible : Should be "via,vt8500-rhine" for integrated
Rhine controllers found in VIA VT8500, WonderMedia WM8950
and similar. These are listed as 1106:3106 rev. 0x84 on the
virtual PCI bus under vendor-provided kernels
- reg : Address and length of the io space
- interrupts : Should contain the controller interrupt line
Examples:
ethernet@d8004000 {
compatible = "via,vt8500-rhine";
reg = <0xd8004000 0x100>;
interrupts = <10>;
};

View File

@ -318,3 +318,8 @@ GPIO
devm_gpiod_get_optional()
devm_gpiod_get_index_optional()
devm_gpiod_put()
MDIO
devm_mdiobus_alloc()
devm_mdiobus_alloc_size()
devm_mdiobus_free()

View File

@ -585,13 +585,19 @@ mode
balance-tlb or 5
Adaptive transmit load balancing: channel bonding that
does not require any special switch support. The
outgoing traffic is distributed according to the
current load (computed relative to the speed) on each
slave. Incoming traffic is received by the current
slave. If the receiving slave fails, another slave
takes over the MAC address of the failed receiving
slave.
does not require any special switch support.
In tlb_dynamic_lb=1 mode; the outgoing traffic is
distributed according to the current load (computed
relative to the speed) on each slave.
In tlb_dynamic_lb=0 mode; the load balancing based on
current load is disabled and the load is distributed
only using the hash distribution.
Incoming traffic is received by the current slave.
If the receiving slave fails, another slave takes over
the MAC address of the failed receiving slave.
Prerequisite:
@ -736,6 +742,28 @@ primary_reselect
This option was added for bonding version 3.6.0.
tlb_dynamic_lb
Specifies if dynamic shuffling of flows is enabled in tlb
mode. The value has no effect on any other modes.
The default behavior of tlb mode is to shuffle active flows across
slaves based on the load in that interval. This gives nice lb
characteristics but can cause packet reordering. If re-ordering is
a concern use this variable to disable flow shuffling and rely on
load balancing provided solely by the hash distribution.
xmit-hash-policy can be used to select the appropriate hashing for
the setup.
The sysfs entry can be used to change the setting per bond device
and the initial value is derived from the module parameter. The
sysfs entry is allowed to be changed only if the bond device is
down.
The default value is "1" that enables flow shuffling while value "0"
disables it. This option was added in bonding driver 3.7.1
updelay
Specifies the time, in milliseconds, to wait before enabling a
@ -769,7 +797,7 @@ use_carrier
xmit_hash_policy
Selects the transmit hash policy to use for slave selection in
balance-xor and 802.3ad modes. Possible values are:
balance-xor, 802.3ad, and tlb modes. Possible values are:
layer2

View File

@ -469,6 +469,41 @@ solution for a couple of reasons:
having this 'send only' use-case we may remove the receive list in the
Kernel to save a little (really a very little!) CPU usage.
4.1.1.1 CAN filter usage optimisation
The CAN filters are processed in per-device filter lists at CAN frame
reception time. To reduce the number of checks that need to be performed
while walking through the filter lists the CAN core provides an optimized
filter handling when the filter subscription focusses on a single CAN ID.
For the possible 2048 SFF CAN identifiers the identifier is used as an index
to access the corresponding subscription list without any further checks.
For the 2^29 possible EFF CAN identifiers a 10 bit XOR folding is used as
hash function to retrieve the EFF table index.
To benefit from the optimized filters for single CAN identifiers the
CAN_SFF_MASK or CAN_EFF_MASK have to be set into can_filter.mask together
with set CAN_EFF_FLAG and CAN_RTR_FLAG bits. A set CAN_EFF_FLAG bit in the
can_filter.mask makes clear that it matters whether a SFF or EFF CAN ID is
subscribed. E.g. in the example from above
rfilter[0].can_id = 0x123;
rfilter[0].can_mask = CAN_SFF_MASK;
both SFF frames with CAN ID 0x123 and EFF frames with 0xXXXXX123 can pass.
To filter for only 0x123 (SFF) and 0x12345678 (EFF) CAN identifiers the
filter has to be defined in this way to benefit from the optimized filters:
struct can_filter rfilter[2];
rfilter[0].can_id = 0x123;
rfilter[0].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK);
rfilter[1].can_id = 0x12345678 | CAN_EFF_FLAG;
rfilter[1].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_EFF_MASK);
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
4.1.2 RAW socket option CAN_RAW_ERR_FILTER
As described in chapter 3.4 the CAN interface driver can generate so

View File

@ -0,0 +1,339 @@
cdc_mbim - Driver for CDC MBIM Mobile Broadband modems
========================================================
The cdc_mbim driver supports USB devices conforming to the "Universal
Serial Bus Communications Class Subclass Specification for Mobile
Broadband Interface Model" [1], which is a further development of
"Universal Serial Bus Communications Class Subclass Specifications for
Network Control Model Devices" [2] optimized for Mobile Broadband
devices, aka "3G/LTE modems".
Command Line Parameters
=======================
The cdc_mbim driver has no parameters of its own. But the probing
behaviour for NCM 1.0 backwards compatible MBIM functions (an
"NCM/MBIM function" as defined in section 3.2 of [1]) is affected
by a cdc_ncm driver parameter:
prefer_mbim
-----------
Type: Boolean
Valid Range: N/Y (0-1)
Default Value: Y (MBIM is preferred)
This parameter sets the system policy for NCM/MBIM functions. Such
functions will be handled by either the cdc_ncm driver or the cdc_mbim
driver depending on the prefer_mbim setting. Setting prefer_mbim=N
makes the cdc_mbim driver ignore these functions and lets the cdc_ncm
driver handle them instead.
The parameter is writable, and can be changed at any time. A manual
unbind/bind is required to make the change effective for NCM/MBIM
functions bound to the "wrong" driver
Basic usage
===========
MBIM functions are inactive when unmanaged. The cdc_mbim driver only
provides an userspace interface to the MBIM control channel, and will
not participate in the management of the function. This implies that a
userspace MBIM management application always is required to enable a
MBIM function.
Such userspace applications includes, but are not limited to:
- mbimcli (included with the libmbim [3] library), and
- ModemManager [4]
Establishing a MBIM IP session reequires at least these actions by the
management application:
- open the control channel
- configure network connection settings
- connect to network
- configure IP interface
Management application development
----------------------------------
The driver <-> userspace interfaces are described below. The MBIM
control channel protocol is described in [1].
MBIM control channel userspace ABI
==================================
/dev/cdc-wdmX character device
------------------------------
The driver creates a two-way pipe to the MBIM function control channel
using the cdc-wdm driver as a subdriver. The userspace end of the
control channel pipe is a /dev/cdc-wdmX character device.
The cdc_mbim driver does not process or police messages on the control
channel. The channel is fully delegated to the userspace management
application. It is therefore up to this application to ensure that it
complies with all the control channel requirements in [1].
The cdc-wdmX device is created as a child of the MBIM control
interface USB device. The character device associated with a specific
MBIM function can be looked up using sysfs. For example:
bjorn@nemi:~$ ls /sys/bus/usb/drivers/cdc_mbim/2-4:2.12/usbmisc
cdc-wdm0
bjorn@nemi:~$ grep . /sys/bus/usb/drivers/cdc_mbim/2-4:2.12/usbmisc/cdc-wdm0/dev
180:0
USB configuration descriptors
-----------------------------
The wMaxControlMessage field of the CDC MBIM functional descriptor
limits the maximum control message size. The managament application is
responsible for negotiating a control message size complying with the
requirements in section 9.3.1 of [1], taking this descriptor field
into consideration.
The userspace application can access the CDC MBIM functional
descriptor of a MBIM function using either of the two USB
configuration descriptor kernel interfaces described in [6] or [7].
See also the ioctl documentation below.
Fragmentation
-------------
The userspace application is responsible for all control message
fragmentation and defragmentaion, as described in section 9.5 of [1].
/dev/cdc-wdmX write()
---------------------
The MBIM control messages from the management application *must not*
exceed the negotiated control message size.
/dev/cdc-wdmX read()
--------------------
The management application *must* accept control messages of up the
negotiated control message size.
/dev/cdc-wdmX ioctl()
--------------------
IOCTL_WDM_MAX_COMMAND: Get Maximum Command Size
This ioctl returns the wMaxControlMessage field of the CDC MBIM
functional descriptor for MBIM devices. This is intended as a
convenience, eliminating the need to parse the USB descriptors from
userspace.
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/usb/cdc-wdm.h>
int main()
{
__u16 max;
int fd = open("/dev/cdc-wdm0", O_RDWR);
if (!ioctl(fd, IOCTL_WDM_MAX_COMMAND, &max))
printf("wMaxControlMessage is %d\n", max);
}
Custom device services
----------------------
The MBIM specification allows vendors to freely define additional
services. This is fully supported by the cdc_mbim driver.
Support for new MBIM services, including vendor specified services, is
implemented entirely in userspace, like the rest of the MBIM control
protocol
New services should be registered in the MBIM Registry [5].
MBIM data channel userspace ABI
===============================
wwanY network device
--------------------
The cdc_mbim driver represents the MBIM data channel as a single
network device of the "wwan" type. This network device is initially
mapped to MBIM IP session 0.
Multiplexed IP sessions (IPS)
-----------------------------
MBIM allows multiplexing up to 256 IP sessions over a single USB data
channel. The cdc_mbim driver models such IP sessions as 802.1q VLAN
subdevices of the master wwanY device, mapping MBIM IP session Z to
VLAN ID Z for all values of Z greater than 0.
The device maximum Z is given in the MBIM_DEVICE_CAPS_INFO structure
described in section 10.5.1 of [1].
The userspace management application is responsible for adding new
VLAN links prior to establishing MBIM IP sessions where the SessionId
is greater than 0. These links can be added by using the normal VLAN
kernel interfaces, either ioctl or netlink.
For example, adding a link for a MBIM IP session with SessionId 3:
ip link add link wwan0 name wwan0.3 type vlan id 3
The driver will automatically map the "wwan0.3" network device to MBIM
IP session 3.
Device Service Streams (DSS)
----------------------------
MBIM also allows up to 256 non-IP data streams to be multiplexed over
the same shared USB data channel. The cdc_mbim driver models these
sessions as another set of 802.1q VLAN subdevices of the master wwanY
device, mapping MBIM DSS session A to VLAN ID (256 + A) for all values
of A.
The device maximum A is given in the MBIM_DEVICE_SERVICES_INFO
structure described in section 10.5.29 of [1].
The DSS VLAN subdevices are used as a practical interface between the
shared MBIM data channel and a MBIM DSS aware userspace application.
It is not intended to be presented as-is to an end user. The
assumption is that an userspace application initiating a DSS session
also takes care of the necessary framing of the DSS data, presenting
the stream to the end user in an appropriate way for the stream type.
The network device ABI requires a dummy ethernet header for every DSS
data frame being transported. The contents of this header is
arbitrary, with the following exceptions:
- TX frames using an IP protocol (0x0800 or 0x86dd) will be dropped
- RX frames will have the protocol field set to ETH_P_802_3 (but will
not be properly formatted 802.3 frames)
- RX frames will have the destination address set to the hardware
address of the master device
The DSS supporting userspace management application is responsible for
adding the dummy ethernet header on TX and stripping it on RX.
This is a simple example using tools commonly available, exporting
DssSessionId 5 as a pty character device pointed to by a /dev/nmea
symlink:
ip link add link wwan0 name wwan0.dss5 type vlan id 261
ip link set dev wwan0.dss5 up
socat INTERFACE:wwan0.dss5,type=2 PTY:,echo=0,link=/dev/nmea
This is only an example, most suitable for testing out a DSS
service. Userspace applications supporting specific MBIM DSS services
are expected to use the tools and programming interfaces required by
that service.
Note that adding VLAN links for DSS sessions is entirely optional. A
management application may instead choose to bind a packet socket
directly to the master network device, using the received VLAN tags to
map frames to the correct DSS session and adding 18 byte VLAN ethernet
headers with the appropriate tag on TX. In this case using a socket
filter is recommended, matching only the DSS VLAN subset. This avoid
unnecessary copying of unrelated IP session data to userspace. For
example:
static struct sock_filter dssfilter[] = {
/* use special negative offsets to get VLAN tag */
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 1, 0, 6), /* true */
/* verify DSS VLAN range */
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 0, 4), /* 256 is first DSS VLAN */
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 512, 3, 0), /* 511 is last DSS VLAN */
/* verify ethertype */
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 2 * ETH_ALEN),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ETH_P_802_3, 0, 1),
BPF_STMT(BPF_RET|BPF_K, (u_int)-1), /* accept */
BPF_STMT(BPF_RET|BPF_K, 0), /* ignore */
};
Tagged IP session 0 VLAN
------------------------
As described above, MBIM IP session 0 is treated as special by the
driver. It is initially mapped to untagged frames on the wwanY
network device.
This mapping implies a few restrictions on multiplexed IPS and DSS
sessions, which may not always be practical:
- no IPS or DSS session can use a frame size greater than the MTU on
IP session 0
- no IPS or DSS session can be in the up state unless the network
device representing IP session 0 also is up
These problems can be avoided by optionally making the driver map IP
session 0 to a VLAN subdevice, similar to all other IP sessions. This
behaviour is triggered by adding a VLAN link for the magic VLAN ID
4094. The driver will then immediately start mapping MBIM IP session
0 to this VLAN, and will drop untagged frames on the master wwanY
device.
Tip: It might be less confusing to the end user to name this VLAN
subdevice after the MBIM SessionID instead of the VLAN ID. For
example:
ip link add link wwan0 name wwan0.0 type vlan id 4094
VLAN mapping
------------
Summarizing the cdc_mbim driver mapping described above, we have this
relationship between VLAN tags on the wwanY network device and MBIM
sessions on the shared USB data channel:
VLAN ID MBIM type MBIM SessionID Notes
---------------------------------------------------------
untagged IPS 0 a)
1 - 255 IPS 1 - 255 <VLANID>
256 - 511 DSS 0 - 255 <VLANID - 256>
512 - 4093 b)
4094 IPS 0 c)
a) if no VLAN ID 4094 link exists, else dropped
b) unsupported VLAN range, unconditionally dropped
c) if a VLAN ID 4094 link exists, else dropped
References
==========
[1] USB Implementers Forum, Inc. - "Universal Serial Bus
Communications Class Subclass Specification for Mobile Broadband
Interface Model", Revision 1.0 (Errata 1), May 1, 2013
- http://www.usb.org/developers/docs/devclass_docs/
[2] USB Implementers Forum, Inc. - "Universal Serial Bus
Communications Class Subclass Specifications for Network Control
Model Devices", Revision 1.0 (Errata 1), November 24, 2010
- http://www.usb.org/developers/docs/devclass_docs/
[3] libmbim - "a glib-based library for talking to WWAN modems and
devices which speak the Mobile Interface Broadband Model (MBIM)
protocol"
- http://www.freedesktop.org/wiki/Software/libmbim/
[4] ModemManager - "a DBus-activated daemon which controls mobile
broadband (2G/3G/4G) devices and connections"
- http://www.freedesktop.org/wiki/Software/ModemManager/
[5] "MBIM (Mobile Broadband Interface Model) Registry"
- http://compliance.usb.org/mbim/
[6] "/proc/bus/usb filesystem output"
- Documentation/usb/proc_usb_info.txt
[7] "/sys/bus/usb/devices/.../descriptors"
- Documentation/ABI/stable/sysfs-bus-usb

View File

@ -281,6 +281,7 @@ Possible BPF extensions are shown in the following table:
cpu raw_smp_processor_id()
vlan_tci vlan_tx_tag_get(skb)
vlan_pr vlan_tx_tag_present(skb)
rand prandom_u32()
These extensions can also be prefixed with '#'.
Examples for low-level BPF:
@ -308,6 +309,18 @@ Examples for low-level BPF:
ret #-1
drop: ret #0
** icmp random packet sampling, 1 in 4
ldh [12]
jne #0x800, drop
ldb [23]
jneq #1, drop
# get a random uint32 number
ld rand
mod #4
jneq #1, drop
ret #-1
drop: ret #0
** SECCOMP filter example:
ld [4] /* offsetof(struct seccomp_data, arch) */
@ -548,42 +561,43 @@ toolchain for developing and testing the kernel's JIT compiler.
BPF kernel internals
--------------------
Internally, for the kernel interpreter, a different BPF instruction set
Internally, for the kernel interpreter, a different instruction set
format with similar underlying principles from BPF described in previous
paragraphs is being used. However, the instruction set format is modelled
closer to the underlying architecture to mimic native instruction sets, so
that a better performance can be achieved (more details later).
that a better performance can be achieved (more details later). This new
ISA is called 'eBPF' or 'internal BPF' interchangeably. (Note: eBPF which
originates from [e]xtended BPF is not the same as BPF extensions! While
eBPF is an ISA, BPF extensions date back to classic BPF's 'overloading'
of BPF_LD | BPF_{B,H,W} | BPF_ABS instruction.)
It is designed to be JITed with one to one mapping, which can also open up
the possibility for GCC/LLVM compilers to generate optimized BPF code through
a BPF backend that performs almost as fast as natively compiled code.
the possibility for GCC/LLVM compilers to generate optimized eBPF code through
an eBPF backend that performs almost as fast as natively compiled code.
The new instruction set was originally designed with the possible goal in
mind to write programs in "restricted C" and compile into BPF with a optional
mind to write programs in "restricted C" and compile into eBPF with a optional
GCC/LLVM backend, so that it can just-in-time map to modern 64-bit CPUs with
minimal performance overhead over two steps, that is, C -> BPF -> native code.
minimal performance overhead over two steps, that is, C -> eBPF -> native code.
Currently, the new format is being used for running user BPF programs, which
includes seccomp BPF, classic socket filters, cls_bpf traffic classifier,
team driver's classifier for its load-balancing mode, netfilter's xt_bpf
extension, PTP dissector/classifier, and much more. They are all internally
converted by the kernel into the new instruction set representation and run
in the extended interpreter. For in-kernel handlers, this all works
transparently by using sk_unattached_filter_create() for setting up the
filter, resp. sk_unattached_filter_destroy() for destroying it. The macro
SK_RUN_FILTER(filter, ctx) transparently invokes the right BPF function to
run the filter. 'filter' is a pointer to struct sk_filter that we got from
sk_unattached_filter_create(), and 'ctx' the given context (e.g. skb pointer).
All constraints and restrictions from sk_chk_filter() apply before a
conversion to the new layout is being done behind the scenes!
in the eBPF interpreter. For in-kernel handlers, this all works transparently
by using sk_unattached_filter_create() for setting up the filter, resp.
sk_unattached_filter_destroy() for destroying it. The macro
SK_RUN_FILTER(filter, ctx) transparently invokes eBPF interpreter or JITed
code to run the filter. 'filter' is a pointer to struct sk_filter that we
got from sk_unattached_filter_create(), and 'ctx' the given context (e.g.
skb pointer). All constraints and restrictions from sk_chk_filter() apply
before a conversion to the new layout is being done behind the scenes!
Currently, for JITing, the user BPF format is being used and current BPF JIT
compilers reused whenever possible. In other words, we do not (yet!) perform
a JIT compilation in the new layout, however, future work will successively
migrate traditional JIT compilers into the new instruction format as well, so
that they will profit from the very same benefits. Thus, when speaking about
JIT in the following, a JIT compiler (TBD) for the new instruction format is
meant in this context.
Currently, the classic BPF format is being used for JITing on most of the
architectures. Only x86-64 performs 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.
Some core changes of the new internal format:
@ -592,35 +606,35 @@ Some core changes of the new internal format:
The old format had two registers A and X, and a hidden frame pointer. The
new layout extends this to be 10 internal registers and a read-only frame
pointer. Since 64-bit CPUs are passing arguments to functions via registers
the number of args from BPF program to in-kernel function is restricted
the number of args from eBPF program to in-kernel function is restricted
to 5 and one register is used to accept return value from an in-kernel
function. Natively, x86_64 passes first 6 arguments in registers, aarch64/
sparcv9/mips64 have 7 - 8 registers for arguments; x86_64 has 6 callee saved
registers, and aarch64/sparcv9/mips64 have 11 or more callee saved registers.
Therefore, BPF calling convention is defined as:
Therefore, eBPF calling convention is defined as:
* R0 - return value from in-kernel function
* R1 - R5 - arguments from BPF program to in-kernel function
* R0 - return value from in-kernel function, and exit value for eBPF program
* R1 - R5 - arguments from eBPF program to in-kernel function
* R6 - R9 - callee saved registers that in-kernel function will preserve
* R10 - read-only frame pointer to access stack
Thus, all BPF registers map one to one to HW registers on x86_64, aarch64,
etc, and BPF calling convention maps directly to ABIs used by the kernel on
Thus, all eBPF registers map one to one to HW registers on x86_64, aarch64,
etc, and eBPF calling convention maps directly to ABIs used by the kernel on
64-bit architectures.
On 32-bit architectures JIT may map programs that use only 32-bit arithmetic
and may let more complex programs to be interpreted.
R0 - R5 are scratch registers and BPF program needs spill/fill them if
necessary across calls. Note that there is only one BPF program (== one BPF
main routine) and it cannot call other BPF functions, it can only call
predefined in-kernel functions, though.
R0 - R5 are scratch registers and eBPF program needs spill/fill them if
necessary across calls. Note that there is only one eBPF program (== one
eBPF main routine) and it cannot call other eBPF functions, it can only
call predefined in-kernel functions, though.
- Register width increases from 32-bit to 64-bit:
Still, the semantics of the original 32-bit ALU operations are preserved
via 32-bit subregisters. All BPF registers are 64-bit with 32-bit lower
via 32-bit subregisters. All eBPF registers are 64-bit with 32-bit lower
subregisters that zero-extend into 64-bit if they are being written to.
That behavior maps directly to x86_64 and arm64 subregister definition, but
makes other JITs more difficult.
@ -631,8 +645,8 @@ Some core changes of the new internal format:
Operation is 64-bit, because on 64-bit architectures, pointers are also
64-bit wide, and we want to pass 64-bit values in/out of kernel functions,
so 32-bit BPF registers would otherwise require to define register-pair
ABI, thus, there won't be able to use a direct BPF register to HW register
so 32-bit eBPF registers would otherwise require to define register-pair
ABI, thus, there won't be able to use a direct eBPF register to HW register
mapping and JIT would need to do combine/split/move operations for every
register in and out of the function, which is complex, bug prone and slow.
Another reason is the use of atomic 64-bit counters.
@ -646,14 +660,145 @@ Some core changes of the new internal format:
- Introduces bpf_call insn and register passing convention for zero overhead
calls from/to other kernel functions:
After a kernel function call, R1 - R5 are reset to unreadable and R0 has a
return type of the function. Since R6 - R9 are callee saved, their state is
preserved across the call.
Before an in-kernel function call, the internal BPF program needs to
place function arguments into R1 to R5 registers to satisfy calling
convention, then the interpreter will take them from registers and pass
to in-kernel function. If R1 - R5 registers are mapped to CPU registers
that are used for argument passing on given architecture, the JIT compiler
doesn't need to emit extra moves. Function arguments will be in the correct
registers and BPF_CALL instruction will be JITed as single 'call' HW
instruction. This calling convention was picked to cover common call
situations without performance penalty.
Also in the new design, BPF is limited to 4096 insns, which means that any
After an in-kernel function call, R1 - R5 are reset to unreadable and R0 has
a return value of the function. Since R6 - R9 are callee saved, their state
is preserved across the call.
For example, consider three C functions:
u64 f1() { return (*_f2)(1); }
u64 f2(u64 a) { return f3(a + 1, a); }
u64 f3(u64 a, u64 b) { return a - b; }
GCC can compile f1, f3 into x86_64:
f1:
movl $1, %edi
movq _f2(%rip), %rax
jmp *%rax
f3:
movq %rdi, %rax
subq %rsi, %rax
ret
Function f2 in eBPF may look like:
f2:
bpf_mov R2, R1
bpf_add R1, 1
bpf_call f3
bpf_exit
If f2 is JITed and the pointer stored to '_f2'. The calls f1 -> f2 -> f3 and
returns will be seamless. Without JIT, __sk_run_filter() interpreter needs to
be used to call into f2.
For practical reasons all eBPF programs have only one argument 'ctx' which is
already placed into R1 (e.g. on __sk_run_filter() startup) and the programs
can call kernel functions with up to 5 arguments. Calls with 6 or more arguments
are currently not supported, but these restrictions can be lifted if necessary
in the future.
On 64-bit architectures all register map to HW registers one to one. For
example, x86_64 JIT compiler can map them as ...
R0 - rax
R1 - rdi
R2 - rsi
R3 - rdx
R4 - rcx
R5 - r8
R6 - rbx
R7 - r13
R8 - r14
R9 - r15
R10 - rbp
... since x86_64 ABI mandates rdi, rsi, rdx, rcx, r8, r9 for argument passing
and rbx, r12 - r15 are callee saved.
Then the following internal BPF pseudo-program:
bpf_mov R6, R1 /* save ctx */
bpf_mov R2, 2
bpf_mov R3, 3
bpf_mov R4, 4
bpf_mov R5, 5
bpf_call foo
bpf_mov R7, R0 /* save foo() return value */
bpf_mov R1, R6 /* restore ctx for next call */
bpf_mov R2, 6
bpf_mov R3, 7
bpf_mov R4, 8
bpf_mov R5, 9
bpf_call bar
bpf_add R0, R7
bpf_exit
After JIT to x86_64 may look like:
push %rbp
mov %rsp,%rbp
sub $0x228,%rsp
mov %rbx,-0x228(%rbp)
mov %r13,-0x220(%rbp)
mov %rdi,%rbx
mov $0x2,%esi
mov $0x3,%edx
mov $0x4,%ecx
mov $0x5,%r8d
callq foo
mov %rax,%r13
mov %rbx,%rdi
mov $0x2,%esi
mov $0x3,%edx
mov $0x4,%ecx
mov $0x5,%r8d
callq bar
add %r13,%rax
mov -0x228(%rbp),%rbx
mov -0x220(%rbp),%r13
leaveq
retq
Which is in this example equivalent in C to:
u64 bpf_filter(u64 ctx)
{
return foo(ctx, 2, 3, 4, 5) + bar(ctx, 6, 7, 8, 9);
}
In-kernel functions foo() and bar() with prototype: u64 (*)(u64 arg1, u64
arg2, u64 arg3, u64 arg4, u64 arg5); will receive arguments in proper
registers and place their return value into '%rax' which is R0 in eBPF.
Prologue and epilogue are emitted by JIT and are implicit in the
interpreter. R0-R5 are scratch registers, so eBPF program needs to preserve
them across the calls as defined by calling convention.
For example the following program is invalid:
bpf_mov R1, 1
bpf_call foo
bpf_mov R0, R1
bpf_exit
After the call the registers R1-R5 contain junk values and cannot be read.
In the future an eBPF verifier can be used to validate internal BPF programs.
Also in the new design, eBPF is limited to 4096 insns, which means that any
program will terminate quickly and will only call a fixed number of kernel
functions. Original BPF and the new format are two operand instructions,
which helps to do one-to-one mapping between BPF insn and x86 insn during JIT.
which helps to do one-to-one mapping between eBPF insn and x86 insn during JIT.
The input context pointer for invoking the interpreter function is generic,
its content is defined by a specific use case. For seccomp register R1 points
@ -661,7 +806,26 @@ to seccomp_data, for converted BPF filters R1 points to a skb.
A program, that is translated internally consists of the following elements:
op:16, jt:8, jf:8, k:32 ==> op:8, a_reg:4, x_reg:4, off:16, imm:32
op:16, jt:8, jf:8, k:32 ==> op:8, dst_reg:4, src_reg:4, off:16, imm:32
So far 87 internal BPF instructions were implemented. 8-bit 'op' opcode field
has room for new instructions. Some of them may use 16/24/32 byte encoding. New
instructions must be multiple of 8 bytes to preserve backward compatibility.
Internal BPF is a general purpose RISC instruction set. Not every register and
every instruction are used during translation from original BPF to new format.
For example, socket filters are not using 'exclusive add' instruction, but
tracing filters may do to maintain counters of events, for example. Register R9
is not used by socket filters either, but more complex filters may be running
out of registers and would have to resort to spill/fill to stack.
Internal BPF can used as generic assembler for last step performance
optimizations, socket filters and seccomp are using it as assembler. Tracing
filters may use it as assembler to generate code from kernel. In kernel usage
may not be bounded by security considerations, since generated internal BPF code
may be optimizing internal code path and not being exposed to the user space.
Safety of internal BPF can come from a verifier (TBD). In such use cases as
described, it may be used as safe instruction set.
Just like the original BPF, the new format runs within a controlled environment,
is deterministic and the kernel can easily prove that. The safety of the program
@ -670,6 +834,181 @@ loops and other CFG validation; second step starts from the first insn and
descends all possible paths. It simulates execution of every insn and observes
the state change of registers and stack.
eBPF opcode encoding
--------------------
eBPF is reusing most of the opcode encoding from classic to simplify conversion
of classic BPF to eBPF. For arithmetic and jump instructions the 8-bit 'code'
field is divided into three parts:
+----------------+--------+--------------------+
| 4 bits | 1 bit | 3 bits |
| operation code | source | instruction class |
+----------------+--------+--------------------+
(MSB) (LSB)
Three LSB bits store instruction class which is one of:
Classic BPF classes: eBPF classes:
BPF_LD 0x00 BPF_LD 0x00
BPF_LDX 0x01 BPF_LDX 0x01
BPF_ST 0x02 BPF_ST 0x02
BPF_STX 0x03 BPF_STX 0x03
BPF_ALU 0x04 BPF_ALU 0x04
BPF_JMP 0x05 BPF_JMP 0x05
BPF_RET 0x06 [ class 6 unused, for future if needed ]
BPF_MISC 0x07 BPF_ALU64 0x07
When BPF_CLASS(code) == BPF_ALU or BPF_JMP, 4th bit encodes source operand ...
BPF_K 0x00
BPF_X 0x08
* in classic BPF, this means:
BPF_SRC(code) == BPF_X - use register X as source operand
BPF_SRC(code) == BPF_K - use 32-bit immediate as source operand
* in eBPF, this means:
BPF_SRC(code) == BPF_X - use 'src_reg' register as source operand
BPF_SRC(code) == BPF_K - use 32-bit immediate as source operand
... and four MSB bits store operation code.
If BPF_CLASS(code) == BPF_ALU or BPF_ALU64 [ in eBPF ], BPF_OP(code) is one of:
BPF_ADD 0x00
BPF_SUB 0x10
BPF_MUL 0x20
BPF_DIV 0x30
BPF_OR 0x40
BPF_AND 0x50
BPF_LSH 0x60
BPF_RSH 0x70
BPF_NEG 0x80
BPF_MOD 0x90
BPF_XOR 0xa0
BPF_MOV 0xb0 /* eBPF only: mov reg to reg */
BPF_ARSH 0xc0 /* eBPF only: sign extending shift right */
BPF_END 0xd0 /* eBPF only: endianness conversion */
If BPF_CLASS(code) == BPF_JMP, BPF_OP(code) is one of:
BPF_JA 0x00
BPF_JEQ 0x10
BPF_JGT 0x20
BPF_JGE 0x30
BPF_JSET 0x40
BPF_JNE 0x50 /* eBPF only: jump != */
BPF_JSGT 0x60 /* eBPF only: signed '>' */
BPF_JSGE 0x70 /* eBPF only: signed '>=' */
BPF_CALL 0x80 /* eBPF only: function call */
BPF_EXIT 0x90 /* eBPF only: function return */
So BPF_ADD | BPF_X | BPF_ALU means 32-bit addition in both classic BPF
and eBPF. There are only two registers in classic BPF, so it means A += X.
In eBPF it means dst_reg = (u32) dst_reg + (u32) src_reg; similarly,
BPF_XOR | BPF_K | BPF_ALU means A ^= imm32 in classic BPF and analogous
src_reg = (u32) src_reg ^ (u32) imm32 in eBPF.
Classic BPF is using BPF_MISC class to represent A = X and X = A moves.
eBPF is using BPF_MOV | BPF_X | BPF_ALU code instead. Since there are no
BPF_MISC operations in eBPF, the class 7 is used as BPF_ALU64 to mean
exactly the same operations as BPF_ALU, but with 64-bit wide operands
instead. So BPF_ADD | BPF_X | BPF_ALU64 means 64-bit addition, i.e.:
dst_reg = dst_reg + src_reg
Classic BPF wastes the whole BPF_RET class to represent a single 'ret'
operation. Classic BPF_RET | BPF_K means copy imm32 into return register
and perform function exit. eBPF is modeled to match CPU, so BPF_JMP | BPF_EXIT
in eBPF means function exit only. The eBPF program needs to store return
value into register R0 before doing a BPF_EXIT. Class 6 in eBPF is currently
unused and reserved for future use.
For load and store instructions the 8-bit 'code' field is divided as:
+--------+--------+-------------------+
| 3 bits | 2 bits | 3 bits |
| mode | size | instruction class |
+--------+--------+-------------------+
(MSB) (LSB)
Size modifier is one of ...
BPF_W 0x00 /* word */
BPF_H 0x08 /* half word */
BPF_B 0x10 /* byte */
BPF_DW 0x18 /* eBPF only, double word */
... which encodes size of load/store operation:
B - 1 byte
H - 2 byte
W - 4 byte
DW - 8 byte (eBPF only)
Mode modifier is one of:
BPF_IMM 0x00 /* classic BPF only, reserved in eBPF */
BPF_ABS 0x20
BPF_IND 0x40
BPF_MEM 0x60
BPF_LEN 0x80 /* classic BPF only, reserved in eBPF */
BPF_MSH 0xa0 /* classic BPF only, reserved in eBPF */
BPF_XADD 0xc0 /* eBPF only, exclusive add */
eBPF has two non-generic instructions: (BPF_ABS | <size> | BPF_LD) and
(BPF_IND | <size> | BPF_LD) which are used to access packet data.
They had to be carried over from classic to have strong performance of
socket filters running in eBPF interpreter. These instructions can only
be used when interpreter context is a pointer to 'struct sk_buff' and
have seven implicit operands. Register R6 is an implicit input that must
contain pointer to sk_buff. Register R0 is an implicit output which contains
the data fetched from the packet. Registers R1-R5 are scratch registers
and must not be used to store the data across BPF_ABS | BPF_LD or
BPF_IND | BPF_LD instructions.
These instructions have implicit program exit condition as well. When
eBPF program is trying to access the data beyond the packet boundary,
the interpreter will abort the execution of the program. JIT compilers
therefore must preserve this property. src_reg and imm32 fields are
explicit inputs to these instructions.
For example:
BPF_IND | BPF_W | BPF_LD means:
R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + src_reg + imm32))
and R1 - R5 were scratched.
Unlike classic BPF instruction set, eBPF has generic load/store operations:
BPF_MEM | <size> | BPF_STX: *(size *) (dst_reg + off) = src_reg
BPF_MEM | <size> | BPF_ST: *(size *) (dst_reg + off) = imm32
BPF_MEM | <size> | BPF_LDX: dst_reg = *(size *) (src_reg + off)
BPF_XADD | BPF_W | BPF_STX: lock xadd *(u32 *)(dst_reg + off16) += src_reg
BPF_XADD | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW. Note that 1 and
2 byte atomic increments are not supported.
Testing
-------
Next to the BPF toolchain, the kernel also ships a test module that contains
various test cases for classic and internal BPF that can be executed against
the BPF interpreter and JIT compiler. It can be found in lib/test_bpf.c and
enabled via Kconfig:
CONFIG_TEST_BPF=m
After the module has been built and installed, the test suite can be executed
via insmod or modprobe against 'test_bpf' module. Results of the test cases
including timings in nsec can be found in the kernel log (dmesg).
Misc
----

View File

@ -604,6 +604,13 @@ L: amd64-microcode@amd64.org
S: Maintained
F: arch/x86/kernel/microcode_amd.c
AMD XGBE DRIVER
M: Tom Lendacky <thomas.lendacky@amd.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/amd/xgbe/
F: drivers/net/phy/amd-xgbe-phy.c
AMS (Apple Motion Sensor) DRIVER
M: Michael Hanselmann <linux-kernel@hansmi.ch>
S: Supported
@ -1894,7 +1901,7 @@ F: drivers/net/ethernet/broadcom/bnx2.*
F: drivers/net/ethernet/broadcom/bnx2_*
BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
M: Ariel Elior <ariele@broadcom.com>
M: Ariel Elior <ariel.elior@qlogic.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/bnx2x/
@ -1974,6 +1981,12 @@ S: Maintained
F: drivers/bcma/
F: include/linux/bcma/
BROADCOM SYSTEMPORT ETHERNET DRIVER
M: Florian Fainelli <f.fainelli@gmail.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/bcmsysport.*
BROCADE BFA FC SCSI DRIVER
M: Anil Gurumurthy <anil.gurumurthy@qlogic.com>
M: Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
@ -2230,9 +2243,8 @@ F: drivers/platform/chrome/
CISCO VIC ETHERNET NIC DRIVER
M: Christian Benvenuti <benve@cisco.com>
M: Sujith Sankar <ssujith@cisco.com>
M: Govindarajulu Varadarajan <govindarajulu90@gmail.com>
M: Govindarajulu Varadarajan <_govind@gmx.com>
M: Neel Patel <neepatel@cisco.com>
M: Nishank Trivedi <nistrive@cisco.com>
S: Supported
F: drivers/net/ethernet/cisco/enic/
@ -6168,6 +6180,7 @@ F: include/uapi/linux/netdevice.h
F: tools/net/
F: tools/testing/selftests/net/
F: lib/random32.c
F: lib/test_bpf.c
NETWORKING [IPv4/IPv6]
M: "David S. Miller" <davem@davemloft.net>

View File

@ -662,6 +662,8 @@
mac: ethernet@4a100000 {
compatible = "ti,cpsw";
ti,hwmods = "cpgmac0";
clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;
clock-names = "fck", "cpts";
cpdma_channels = <8>;
ale_entries = <1024>;
bd_ram_size = <0x2000>;

View File

@ -490,6 +490,8 @@
#address-cells = <1>;
#size-cells = <1>;
ti,hwmods = "cpgmac0";
clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;
clock-names = "fck", "cpts";
status = "disabled";
cpdma_channels = <8>;
ale_entries = <1024>;

View File

@ -57,6 +57,10 @@
ethernet@30000 {
status = "okay";
phy-mode = "sgmii";
fixed-link {
speed = <1000>;
full-duplex;
};
};
pcie-controller {

View File

@ -165,5 +165,11 @@
reg = <0xd8100000 0x10000>;
interrupts = <48>;
};
ethernet@d8004000 {
compatible = "via,vt8500-rhine";
reg = <0xd8004000 0x100>;
interrupts = <10>;
};
};
};

View File

@ -218,5 +218,11 @@
reg = <0xd8100000 0x10000>;
interrupts = <48>;
};
ethernet@d8004000 {
compatible = "via,vt8500-rhine";
reg = <0xd8004000 0x100>;
interrupts = <10>;
};
};
};

View File

@ -298,5 +298,11 @@
bus-width = <4>;
sdon-inverted;
};
ethernet@d8004000 {
compatible = "via,vt8500-rhine";
reg = <0xd8004000 0x100>;
interrupts = <10>;
};
};
};

View File

@ -23,9 +23,7 @@
#include "board.h"
static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
.name = "wifi_rfkill",
.reset_gpio = 25, /* PD1 */
.shutdown_gpio = 85, /* PK5 */
.name = "wifi_rfkill",
.type = RFKILL_TYPE_WLAN,
};

View File

@ -136,7 +136,7 @@ static u16 saved_regs(struct jit_ctx *ctx)
u16 ret = 0;
if ((ctx->skf->len > 1) ||
(ctx->skf->insns[0].code == BPF_S_RET_A))
(ctx->skf->insns[0].code == (BPF_RET | BPF_A)))
ret |= 1 << r_A;
#ifdef CONFIG_FRAME_POINTER
@ -164,18 +164,10 @@ static inline int mem_words_used(struct jit_ctx *ctx)
static inline bool is_load_to_a(u16 inst)
{
switch (inst) {
case BPF_S_LD_W_LEN:
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
case BPF_S_ANC_CPU:
case BPF_S_ANC_IFINDEX:
case BPF_S_ANC_MARK:
case BPF_S_ANC_PROTOCOL:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_ANC_QUEUE:
case BPF_LD | BPF_W | BPF_LEN:
case BPF_LD | BPF_W | BPF_ABS:
case BPF_LD | BPF_H | BPF_ABS:
case BPF_LD | BPF_B | BPF_ABS:
return true;
default:
return false;
@ -215,7 +207,7 @@ static void build_prologue(struct jit_ctx *ctx)
emit(ARM_MOV_I(r_X, 0), ctx);
/* do not leak kernel data to userspace */
if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst)))
if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
emit(ARM_MOV_I(r_A, 0), ctx);
/* stack space for the BPF_MEM words */
@ -480,36 +472,39 @@ static int build_body(struct jit_ctx *ctx)
u32 k;
for (i = 0; i < prog->len; i++) {
u16 code;
inst = &(prog->insns[i]);
/* K as an immediate value operand */
k = inst->k;
code = bpf_anc_helper(inst);
/* compute offsets only in the fake pass */
if (ctx->target == NULL)
ctx->offsets[i] = ctx->idx * 4;
switch (inst->code) {
case BPF_S_LD_IMM:
switch (code) {
case BPF_LD | BPF_IMM:
emit_mov_i(r_A, k, ctx);
break;
case BPF_S_LD_W_LEN:
case BPF_LD | BPF_W | BPF_LEN:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
emit(ARM_LDR_I(r_A, r_skb,
offsetof(struct sk_buff, len)), ctx);
break;
case BPF_S_LD_MEM:
case BPF_LD | BPF_MEM:
/* A = scratch[k] */
ctx->seen |= SEEN_MEM_WORD(k);
emit(ARM_LDR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_LD_W_ABS:
case BPF_LD | BPF_W | BPF_ABS:
load_order = 2;
goto load;
case BPF_S_LD_H_ABS:
case BPF_LD | BPF_H | BPF_ABS:
load_order = 1;
goto load;
case BPF_S_LD_B_ABS:
case BPF_LD | BPF_B | BPF_ABS:
load_order = 0;
load:
/* the interpreter will deal with the negative K */
@ -552,31 +547,31 @@ load_common:
emit_err_ret(ARM_COND_NE, ctx);
emit(ARM_MOV_R(r_A, ARM_R0), ctx);
break;
case BPF_S_LD_W_IND:
case BPF_LD | BPF_W | BPF_IND:
load_order = 2;
goto load_ind;
case BPF_S_LD_H_IND:
case BPF_LD | BPF_H | BPF_IND:
load_order = 1;
goto load_ind;
case BPF_S_LD_B_IND:
case BPF_LD | BPF_B | BPF_IND:
load_order = 0;
load_ind:
OP_IMM3(ARM_ADD, r_off, r_X, k, ctx);
goto load_common;
case BPF_S_LDX_IMM:
case BPF_LDX | BPF_IMM:
ctx->seen |= SEEN_X;
emit_mov_i(r_X, k, ctx);
break;
case BPF_S_LDX_W_LEN:
case BPF_LDX | BPF_W | BPF_LEN:
ctx->seen |= SEEN_X | SEEN_SKB;
emit(ARM_LDR_I(r_X, r_skb,
offsetof(struct sk_buff, len)), ctx);
break;
case BPF_S_LDX_MEM:
case BPF_LDX | BPF_MEM:
ctx->seen |= SEEN_X | SEEN_MEM_WORD(k);
emit(ARM_LDR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_LDX_B_MSH:
case BPF_LDX | BPF_B | BPF_MSH:
/* x = ((*(frame + k)) & 0xf) << 2; */
ctx->seen |= SEEN_X | SEEN_DATA | SEEN_CALL;
/* the interpreter should deal with the negative K */
@ -606,113 +601,113 @@ load_ind:
emit(ARM_AND_I(r_X, ARM_R0, 0x00f), ctx);
emit(ARM_LSL_I(r_X, r_X, 2), ctx);
break;
case BPF_S_ST:
case BPF_ST:
ctx->seen |= SEEN_MEM_WORD(k);
emit(ARM_STR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_STX:
case BPF_STX:
update_on_xread(ctx);
ctx->seen |= SEEN_MEM_WORD(k);
emit(ARM_STR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_ALU_ADD_K:
case BPF_ALU | BPF_ADD | BPF_K:
/* A += K */
OP_IMM3(ARM_ADD, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_ADD_X:
case BPF_ALU | BPF_ADD | BPF_X:
update_on_xread(ctx);
emit(ARM_ADD_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_SUB_K:
case BPF_ALU | BPF_SUB | BPF_K:
/* A -= K */
OP_IMM3(ARM_SUB, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_SUB_X:
case BPF_ALU | BPF_SUB | BPF_X:
update_on_xread(ctx);
emit(ARM_SUB_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_MUL_K:
case BPF_ALU | BPF_MUL | BPF_K:
/* A *= K */
emit_mov_i(r_scratch, k, ctx);
emit(ARM_MUL(r_A, r_A, r_scratch), ctx);
break;
case BPF_S_ALU_MUL_X:
case BPF_ALU | BPF_MUL | BPF_X:
update_on_xread(ctx);
emit(ARM_MUL(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_DIV_K:
case BPF_ALU | BPF_DIV | BPF_K:
if (k == 1)
break;
emit_mov_i(r_scratch, k, ctx);
emit_udiv(r_A, r_A, r_scratch, ctx);
break;
case BPF_S_ALU_DIV_X:
case BPF_ALU | BPF_DIV | BPF_X:
update_on_xread(ctx);
emit(ARM_CMP_I(r_X, 0), ctx);
emit_err_ret(ARM_COND_EQ, ctx);
emit_udiv(r_A, r_A, r_X, ctx);
break;
case BPF_S_ALU_OR_K:
case BPF_ALU | BPF_OR | BPF_K:
/* A |= K */
OP_IMM3(ARM_ORR, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_OR_X:
case BPF_ALU | BPF_OR | BPF_X:
update_on_xread(ctx);
emit(ARM_ORR_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_XOR_K:
case BPF_ALU | BPF_XOR | BPF_K:
/* A ^= K; */
OP_IMM3(ARM_EOR, r_A, r_A, k, ctx);
break;
case BPF_S_ANC_ALU_XOR_X:
case BPF_S_ALU_XOR_X:
case BPF_ANC | SKF_AD_ALU_XOR_X:
case BPF_ALU | BPF_XOR | BPF_X:
/* A ^= X */
update_on_xread(ctx);
emit(ARM_EOR_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_AND_K:
case BPF_ALU | BPF_AND | BPF_K:
/* A &= K */
OP_IMM3(ARM_AND, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_AND_X:
case BPF_ALU | BPF_AND | BPF_X:
update_on_xread(ctx);
emit(ARM_AND_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_LSH_K:
case BPF_ALU | BPF_LSH | BPF_K:
if (unlikely(k > 31))
return -1;
emit(ARM_LSL_I(r_A, r_A, k), ctx);
break;
case BPF_S_ALU_LSH_X:
case BPF_ALU | BPF_LSH | BPF_X:
update_on_xread(ctx);
emit(ARM_LSL_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_RSH_K:
case BPF_ALU | BPF_RSH | BPF_K:
if (unlikely(k > 31))
return -1;
emit(ARM_LSR_I(r_A, r_A, k), ctx);
break;
case BPF_S_ALU_RSH_X:
case BPF_ALU | BPF_RSH | BPF_X:
update_on_xread(ctx);
emit(ARM_LSR_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_NEG:
case BPF_ALU | BPF_NEG:
/* A = -A */
emit(ARM_RSB_I(r_A, r_A, 0), ctx);
break;
case BPF_S_JMP_JA:
case BPF_JMP | BPF_JA:
/* pc += K */
emit(ARM_B(b_imm(i + k + 1, ctx)), ctx);
break;
case BPF_S_JMP_JEQ_K:
case BPF_JMP | BPF_JEQ | BPF_K:
/* pc += (A == K) ? pc->jt : pc->jf */
condt = ARM_COND_EQ;
goto cmp_imm;
case BPF_S_JMP_JGT_K:
case BPF_JMP | BPF_JGT | BPF_K:
/* pc += (A > K) ? pc->jt : pc->jf */
condt = ARM_COND_HI;
goto cmp_imm;
case BPF_S_JMP_JGE_K:
case BPF_JMP | BPF_JGE | BPF_K:
/* pc += (A >= K) ? pc->jt : pc->jf */
condt = ARM_COND_HS;
cmp_imm:
@ -731,22 +726,22 @@ cond_jump:
_emit(condt ^ 1, ARM_B(b_imm(i + inst->jf + 1,
ctx)), ctx);
break;
case BPF_S_JMP_JEQ_X:
case BPF_JMP | BPF_JEQ | BPF_X:
/* pc += (A == X) ? pc->jt : pc->jf */
condt = ARM_COND_EQ;
goto cmp_x;
case BPF_S_JMP_JGT_X:
case BPF_JMP | BPF_JGT | BPF_X:
/* pc += (A > X) ? pc->jt : pc->jf */
condt = ARM_COND_HI;
goto cmp_x;
case BPF_S_JMP_JGE_X:
case BPF_JMP | BPF_JGE | BPF_X:
/* pc += (A >= X) ? pc->jt : pc->jf */
condt = ARM_COND_CS;
cmp_x:
update_on_xread(ctx);
emit(ARM_CMP_R(r_A, r_X), ctx);
goto cond_jump;
case BPF_S_JMP_JSET_K:
case BPF_JMP | BPF_JSET | BPF_K:
/* pc += (A & K) ? pc->jt : pc->jf */
condt = ARM_COND_NE;
/* not set iff all zeroes iff Z==1 iff EQ */
@ -759,16 +754,16 @@ cmp_x:
emit(ARM_TST_I(r_A, imm12), ctx);
}
goto cond_jump;
case BPF_S_JMP_JSET_X:
case BPF_JMP | BPF_JSET | BPF_X:
/* pc += (A & X) ? pc->jt : pc->jf */
update_on_xread(ctx);
condt = ARM_COND_NE;
emit(ARM_TST_R(r_A, r_X), ctx);
goto cond_jump;
case BPF_S_RET_A:
case BPF_RET | BPF_A:
emit(ARM_MOV_R(ARM_R0, r_A), ctx);
goto b_epilogue;
case BPF_S_RET_K:
case BPF_RET | BPF_K:
if ((k == 0) && (ctx->ret0_fp_idx < 0))
ctx->ret0_fp_idx = i;
emit_mov_i(ARM_R0, k, ctx);
@ -776,17 +771,17 @@ b_epilogue:
if (i != ctx->skf->len - 1)
emit(ARM_B(b_imm(prog->len, ctx)), ctx);
break;
case BPF_S_MISC_TAX:
case BPF_MISC | BPF_TAX:
/* X = A */
ctx->seen |= SEEN_X;
emit(ARM_MOV_R(r_X, r_A), ctx);
break;
case BPF_S_MISC_TXA:
case BPF_MISC | BPF_TXA:
/* A = X */
update_on_xread(ctx);
emit(ARM_MOV_R(r_A, r_X), ctx);
break;
case BPF_S_ANC_PROTOCOL:
case BPF_ANC | SKF_AD_PROTOCOL:
/* A = ntohs(skb->protocol) */
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
@ -795,7 +790,7 @@ b_epilogue:
emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
emit_swap16(r_A, r_scratch, ctx);
break;
case BPF_S_ANC_CPU:
case BPF_ANC | SKF_AD_CPU:
/* r_scratch = current_thread_info() */
OP_IMM3(ARM_BIC, r_scratch, ARM_SP, THREAD_SIZE - 1, ctx);
/* A = current_thread_info()->cpu */
@ -803,7 +798,7 @@ b_epilogue:
off = offsetof(struct thread_info, cpu);
emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
break;
case BPF_S_ANC_IFINDEX:
case BPF_ANC | SKF_AD_IFINDEX:
/* A = skb->dev->ifindex */
ctx->seen |= SEEN_SKB;
off = offsetof(struct sk_buff, dev);
@ -817,30 +812,30 @@ b_epilogue:
off = offsetof(struct net_device, ifindex);
emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
break;
case BPF_S_ANC_MARK:
case BPF_ANC | SKF_AD_MARK:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
off = offsetof(struct sk_buff, mark);
emit(ARM_LDR_I(r_A, r_skb, off), ctx);
break;
case BPF_S_ANC_RXHASH:
case BPF_ANC | SKF_AD_RXHASH:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
off = offsetof(struct sk_buff, hash);
emit(ARM_LDR_I(r_A, r_skb, off), ctx);
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_ANC | SKF_AD_VLAN_TAG:
case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
off = offsetof(struct sk_buff, vlan_tci);
emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
if (inst->code == BPF_S_ANC_VLAN_TAG)
if (code == (BPF_ANC | SKF_AD_VLAN_TAG))
OP_IMM3(ARM_AND, r_A, r_A, VLAN_VID_MASK, ctx);
else
OP_IMM3(ARM_AND, r_A, r_A, VLAN_TAG_PRESENT, ctx);
break;
case BPF_S_ANC_QUEUE:
case BPF_ANC | SKF_AD_QUEUE:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
queue_mapping) != 2);

View File

@ -168,6 +168,7 @@ static void nvram_read_alpha2(const char *prefix, const char *name,
static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
const char *prefix, bool fallback)
{
nvram_read_u16(prefix, NULL, "devid", &sprom->dev_id, 0, fallback);
nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff, fallback);
nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff, fallback);
nvram_read_u8(prefix, NULL, "ledbh2", &sprom->gpio2, 0xff, fallback);

View File

@ -78,7 +78,7 @@ sk_load_byte_positive_offset:
blr
/*
* BPF_S_LDX_B_MSH: ldxb 4*([offset]&0xf)
* BPF_LDX | BPF_B | BPF_MSH: ldxb 4*([offset]&0xf)
* r_addr is the offset value
*/
.globl sk_load_byte_msh

View File

@ -79,19 +79,11 @@ static void bpf_jit_build_prologue(struct sk_filter *fp, u32 *image,
}
switch (filter[0].code) {
case BPF_S_RET_K:
case BPF_S_LD_W_LEN:
case BPF_S_ANC_PROTOCOL:
case BPF_S_ANC_IFINDEX:
case BPF_S_ANC_MARK:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_ANC_CPU:
case BPF_S_ANC_QUEUE:
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
case BPF_RET | BPF_K:
case BPF_LD | BPF_W | BPF_LEN:
case BPF_LD | BPF_W | BPF_ABS:
case BPF_LD | BPF_H | BPF_ABS:
case BPF_LD | BPF_B | BPF_ABS:
/* first instruction sets A register (or is RET 'constant') */
break;
default:
@ -144,6 +136,7 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
for (i = 0; i < flen; i++) {
unsigned int K = filter[i].k;
u16 code = bpf_anc_helper(&filter[i]);
/*
* addrs[] maps a BPF bytecode address into a real offset from
@ -151,35 +144,35 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
*/
addrs[i] = ctx->idx * 4;
switch (filter[i].code) {
switch (code) {
/*** ALU ops ***/
case BPF_S_ALU_ADD_X: /* A += X; */
case BPF_ALU | BPF_ADD | BPF_X: /* A += X; */
ctx->seen |= SEEN_XREG;
PPC_ADD(r_A, r_A, r_X);
break;
case BPF_S_ALU_ADD_K: /* A += K; */
case BPF_ALU | BPF_ADD | BPF_K: /* A += K; */
if (!K)
break;
PPC_ADDI(r_A, r_A, IMM_L(K));
if (K >= 32768)
PPC_ADDIS(r_A, r_A, IMM_HA(K));
break;
case BPF_S_ALU_SUB_X: /* A -= X; */
case BPF_ALU | BPF_SUB | BPF_X: /* A -= X; */
ctx->seen |= SEEN_XREG;
PPC_SUB(r_A, r_A, r_X);
break;
case BPF_S_ALU_SUB_K: /* A -= K */
case BPF_ALU | BPF_SUB | BPF_K: /* A -= K */
if (!K)
break;
PPC_ADDI(r_A, r_A, IMM_L(-K));
if (K >= 32768)
PPC_ADDIS(r_A, r_A, IMM_HA(-K));
break;
case BPF_S_ALU_MUL_X: /* A *= X; */
case BPF_ALU | BPF_MUL | BPF_X: /* A *= X; */
ctx->seen |= SEEN_XREG;
PPC_MUL(r_A, r_A, r_X);
break;
case BPF_S_ALU_MUL_K: /* A *= K */
case BPF_ALU | BPF_MUL | BPF_K: /* A *= K */
if (K < 32768)
PPC_MULI(r_A, r_A, K);
else {
@ -187,7 +180,7 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_MUL(r_A, r_A, r_scratch1);
}
break;
case BPF_S_ALU_MOD_X: /* A %= X; */
case BPF_ALU | BPF_MOD | BPF_X: /* A %= X; */
ctx->seen |= SEEN_XREG;
PPC_CMPWI(r_X, 0);
if (ctx->pc_ret0 != -1) {
@ -201,13 +194,13 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_MUL(r_scratch1, r_X, r_scratch1);
PPC_SUB(r_A, r_A, r_scratch1);
break;
case BPF_S_ALU_MOD_K: /* A %= K; */
case BPF_ALU | BPF_MOD | BPF_K: /* A %= K; */
PPC_LI32(r_scratch2, K);
PPC_DIVWU(r_scratch1, r_A, r_scratch2);
PPC_MUL(r_scratch1, r_scratch2, r_scratch1);
PPC_SUB(r_A, r_A, r_scratch1);
break;
case BPF_S_ALU_DIV_X: /* A /= X; */
case BPF_ALU | BPF_DIV | BPF_X: /* A /= X; */
ctx->seen |= SEEN_XREG;
PPC_CMPWI(r_X, 0);
if (ctx->pc_ret0 != -1) {
@ -223,17 +216,17 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
}
PPC_DIVWU(r_A, r_A, r_X);
break;
case BPF_S_ALU_DIV_K: /* A /= K */
case BPF_ALU | BPF_DIV | BPF_K: /* A /= K */
if (K == 1)
break;
PPC_LI32(r_scratch1, K);
PPC_DIVWU(r_A, r_A, r_scratch1);
break;
case BPF_S_ALU_AND_X:
case BPF_ALU | BPF_AND | BPF_X:
ctx->seen |= SEEN_XREG;
PPC_AND(r_A, r_A, r_X);
break;
case BPF_S_ALU_AND_K:
case BPF_ALU | BPF_AND | BPF_K:
if (!IMM_H(K))
PPC_ANDI(r_A, r_A, K);
else {
@ -241,51 +234,51 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_AND(r_A, r_A, r_scratch1);
}
break;
case BPF_S_ALU_OR_X:
case BPF_ALU | BPF_OR | BPF_X:
ctx->seen |= SEEN_XREG;
PPC_OR(r_A, r_A, r_X);
break;
case BPF_S_ALU_OR_K:
case BPF_ALU | BPF_OR | BPF_K:
if (IMM_L(K))
PPC_ORI(r_A, r_A, IMM_L(K));
if (K >= 65536)
PPC_ORIS(r_A, r_A, IMM_H(K));
break;
case BPF_S_ANC_ALU_XOR_X:
case BPF_S_ALU_XOR_X: /* A ^= X */
case BPF_ANC | SKF_AD_ALU_XOR_X:
case BPF_ALU | BPF_XOR | BPF_X: /* A ^= X */
ctx->seen |= SEEN_XREG;
PPC_XOR(r_A, r_A, r_X);
break;
case BPF_S_ALU_XOR_K: /* A ^= K */
case BPF_ALU | BPF_XOR | BPF_K: /* A ^= K */
if (IMM_L(K))
PPC_XORI(r_A, r_A, IMM_L(K));
if (K >= 65536)
PPC_XORIS(r_A, r_A, IMM_H(K));
break;
case BPF_S_ALU_LSH_X: /* A <<= X; */
case BPF_ALU | BPF_LSH | BPF_X: /* A <<= X; */
ctx->seen |= SEEN_XREG;
PPC_SLW(r_A, r_A, r_X);
break;
case BPF_S_ALU_LSH_K:
case BPF_ALU | BPF_LSH | BPF_K:
if (K == 0)
break;
else
PPC_SLWI(r_A, r_A, K);
break;
case BPF_S_ALU_RSH_X: /* A >>= X; */
case BPF_ALU | BPF_RSH | BPF_X: /* A >>= X; */
ctx->seen |= SEEN_XREG;
PPC_SRW(r_A, r_A, r_X);
break;
case BPF_S_ALU_RSH_K: /* A >>= K; */
case BPF_ALU | BPF_RSH | BPF_K: /* A >>= K; */
if (K == 0)
break;
else
PPC_SRWI(r_A, r_A, K);
break;
case BPF_S_ALU_NEG:
case BPF_ALU | BPF_NEG:
PPC_NEG(r_A, r_A);
break;
case BPF_S_RET_K:
case BPF_RET | BPF_K:
PPC_LI32(r_ret, K);
if (!K) {
if (ctx->pc_ret0 == -1)
@ -312,7 +305,7 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_BLR();
}
break;
case BPF_S_RET_A:
case BPF_RET | BPF_A:
PPC_MR(r_ret, r_A);
if (i != flen - 1) {
if (ctx->seen)
@ -321,53 +314,53 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_BLR();
}
break;
case BPF_S_MISC_TAX: /* X = A */
case BPF_MISC | BPF_TAX: /* X = A */
PPC_MR(r_X, r_A);
break;
case BPF_S_MISC_TXA: /* A = X */
case BPF_MISC | BPF_TXA: /* A = X */
ctx->seen |= SEEN_XREG;
PPC_MR(r_A, r_X);
break;
/*** Constant loads/M[] access ***/
case BPF_S_LD_IMM: /* A = K */
case BPF_LD | BPF_IMM: /* A = K */
PPC_LI32(r_A, K);
break;
case BPF_S_LDX_IMM: /* X = K */
case BPF_LDX | BPF_IMM: /* X = K */
PPC_LI32(r_X, K);
break;
case BPF_S_LD_MEM: /* A = mem[K] */
case BPF_LD | BPF_MEM: /* A = mem[K] */
PPC_MR(r_A, r_M + (K & 0xf));
ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
break;
case BPF_S_LDX_MEM: /* X = mem[K] */
case BPF_LDX | BPF_MEM: /* X = mem[K] */
PPC_MR(r_X, r_M + (K & 0xf));
ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
break;
case BPF_S_ST: /* mem[K] = A */
case BPF_ST: /* mem[K] = A */
PPC_MR(r_M + (K & 0xf), r_A);
ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
break;
case BPF_S_STX: /* mem[K] = X */
case BPF_STX: /* mem[K] = X */
PPC_MR(r_M + (K & 0xf), r_X);
ctx->seen |= SEEN_XREG | SEEN_MEM | (1<<(K & 0xf));
break;
case BPF_S_LD_W_LEN: /* A = skb->len; */
case BPF_LD | BPF_W | BPF_LEN: /* A = skb->len; */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len));
break;
case BPF_S_LDX_W_LEN: /* X = skb->len; */
case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */
PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len));
break;
/*** Ancillary info loads ***/
case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
case BPF_ANC | SKF_AD_PROTOCOL: /* A = ntohs(skb->protocol); */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
protocol) != 2);
PPC_NTOHS_OFFS(r_A, r_skb, offsetof(struct sk_buff,
protocol));
break;
case BPF_S_ANC_IFINDEX:
case BPF_ANC | SKF_AD_IFINDEX:
PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
dev));
PPC_CMPDI(r_scratch1, 0);
@ -384,33 +377,33 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_LWZ_OFFS(r_A, r_scratch1,
offsetof(struct net_device, ifindex));
break;
case BPF_S_ANC_MARK:
case BPF_ANC | SKF_AD_MARK:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
mark));
break;
case BPF_S_ANC_RXHASH:
case BPF_ANC | SKF_AD_RXHASH:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
hash));
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_ANC | SKF_AD_VLAN_TAG:
case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
vlan_tci));
if (filter[i].code == BPF_S_ANC_VLAN_TAG)
if (code == (BPF_ANC | SKF_AD_VLAN_TAG))
PPC_ANDI(r_A, r_A, VLAN_VID_MASK);
else
PPC_ANDI(r_A, r_A, VLAN_TAG_PRESENT);
break;
case BPF_S_ANC_QUEUE:
case BPF_ANC | SKF_AD_QUEUE:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
queue_mapping) != 2);
PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
queue_mapping));
break;
case BPF_S_ANC_CPU:
case BPF_ANC | SKF_AD_CPU:
#ifdef CONFIG_SMP
/*
* PACA ptr is r13:
@ -426,13 +419,13 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
break;
/*** Absolute loads from packet header/data ***/
case BPF_S_LD_W_ABS:
case BPF_LD | BPF_W | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, sk_load_word);
goto common_load;
case BPF_S_LD_H_ABS:
case BPF_LD | BPF_H | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, sk_load_half);
goto common_load;
case BPF_S_LD_B_ABS:
case BPF_LD | BPF_B | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, sk_load_byte);
common_load:
/* Load from [K]. */
@ -449,13 +442,13 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
break;
/*** Indirect loads from packet header/data ***/
case BPF_S_LD_W_IND:
case BPF_LD | BPF_W | BPF_IND:
func = sk_load_word;
goto common_load_ind;
case BPF_S_LD_H_IND:
case BPF_LD | BPF_H | BPF_IND:
func = sk_load_half;
goto common_load_ind;
case BPF_S_LD_B_IND:
case BPF_LD | BPF_B | BPF_IND:
func = sk_load_byte;
common_load_ind:
/*
@ -473,31 +466,31 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_BCC(COND_LT, exit_addr);
break;
case BPF_S_LDX_B_MSH:
case BPF_LDX | BPF_B | BPF_MSH:
func = CHOOSE_LOAD_FUNC(K, sk_load_byte_msh);
goto common_load;
break;
/*** Jump and branches ***/
case BPF_S_JMP_JA:
case BPF_JMP | BPF_JA:
if (K != 0)
PPC_JMP(addrs[i + 1 + K]);
break;
case BPF_S_JMP_JGT_K:
case BPF_S_JMP_JGT_X:
case BPF_JMP | BPF_JGT | BPF_K:
case BPF_JMP | BPF_JGT | BPF_X:
true_cond = COND_GT;
goto cond_branch;
case BPF_S_JMP_JGE_K:
case BPF_S_JMP_JGE_X:
case BPF_JMP | BPF_JGE | BPF_K:
case BPF_JMP | BPF_JGE | BPF_X:
true_cond = COND_GE;
goto cond_branch;
case BPF_S_JMP_JEQ_K:
case BPF_S_JMP_JEQ_X:
case BPF_JMP | BPF_JEQ | BPF_K:
case BPF_JMP | BPF_JEQ | BPF_X:
true_cond = COND_EQ;
goto cond_branch;
case BPF_S_JMP_JSET_K:
case BPF_S_JMP_JSET_X:
case BPF_JMP | BPF_JSET | BPF_K:
case BPF_JMP | BPF_JSET | BPF_X:
true_cond = COND_NE;
/* Fall through */
cond_branch:
@ -508,20 +501,20 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
break;
}
switch (filter[i].code) {
case BPF_S_JMP_JGT_X:
case BPF_S_JMP_JGE_X:
case BPF_S_JMP_JEQ_X:
switch (code) {
case BPF_JMP | BPF_JGT | BPF_X:
case BPF_JMP | BPF_JGE | BPF_X:
case BPF_JMP | BPF_JEQ | BPF_X:
ctx->seen |= SEEN_XREG;
PPC_CMPLW(r_A, r_X);
break;
case BPF_S_JMP_JSET_X:
case BPF_JMP | BPF_JSET | BPF_X:
ctx->seen |= SEEN_XREG;
PPC_AND_DOT(r_scratch1, r_A, r_X);
break;
case BPF_S_JMP_JEQ_K:
case BPF_S_JMP_JGT_K:
case BPF_S_JMP_JGE_K:
case BPF_JMP | BPF_JEQ | BPF_K:
case BPF_JMP | BPF_JGT | BPF_K:
case BPF_JMP | BPF_JGE | BPF_K:
if (K < 32768)
PPC_CMPLWI(r_A, K);
else {
@ -529,7 +522,7 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_CMPLW(r_A, r_scratch1);
}
break;
case BPF_S_JMP_JSET_K:
case BPF_JMP | BPF_JSET | BPF_K:
if (K < 32768)
/* PPC_ANDI is /only/ dot-form */
PPC_ANDI(r_scratch1, r_A, K);

View File

@ -25,7 +25,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/spi/spi.h>
#include <linux/fsl_devices.h>
#include <linux/fs_enet_pd.h>
@ -178,37 +177,6 @@ u32 get_baudrate(void)
EXPORT_SYMBOL(get_baudrate);
#endif /* CONFIG_CPM2 */
#ifdef CONFIG_FIXED_PHY
static int __init of_add_fixed_phys(void)
{
int ret;
struct device_node *np;
u32 *fixed_link;
struct fixed_phy_status status = {};
for_each_node_by_name(np, "ethernet") {
fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
if (!fixed_link)
continue;
status.link = 1;
status.duplex = fixed_link[1];
status.speed = fixed_link[2];
status.pause = fixed_link[3];
status.asym_pause = fixed_link[4];
ret = fixed_phy_add(PHY_POLL, fixed_link[0], &status);
if (ret) {
of_node_put(np);
return ret;
}
}
return 0;
}
arch_initcall(of_add_fixed_phys);
#endif /* CONFIG_FIXED_PHY */
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
static __be32 __iomem *rstcr;

View File

@ -269,27 +269,17 @@ static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
EMIT4(0xa7c80000);
/* Clear A if the first register does not set it. */
switch (filter[0].code) {
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
case BPF_S_LD_W_LEN:
case BPF_S_LD_W_IND:
case BPF_S_LD_H_IND:
case BPF_S_LD_B_IND:
case BPF_S_LD_IMM:
case BPF_S_LD_MEM:
case BPF_S_MISC_TXA:
case BPF_S_ANC_PROTOCOL:
case BPF_S_ANC_PKTTYPE:
case BPF_S_ANC_IFINDEX:
case BPF_S_ANC_MARK:
case BPF_S_ANC_QUEUE:
case BPF_S_ANC_HATYPE:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_CPU:
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_RET_K:
case BPF_LD | BPF_W | BPF_ABS:
case BPF_LD | BPF_H | BPF_ABS:
case BPF_LD | BPF_B | BPF_ABS:
case BPF_LD | BPF_W | BPF_LEN:
case BPF_LD | BPF_W | BPF_IND:
case BPF_LD | BPF_H | BPF_IND:
case BPF_LD | BPF_B | BPF_IND:
case BPF_LD | BPF_IMM:
case BPF_LD | BPF_MEM:
case BPF_MISC | BPF_TXA:
case BPF_RET | BPF_K:
/* first instruction sets A register */
break;
default: /* A = 0 */
@ -304,15 +294,18 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
unsigned int K;
int offset;
unsigned int mask;
u16 code;
K = filter->k;
switch (filter->code) {
case BPF_S_ALU_ADD_X: /* A += X */
code = bpf_anc_helper(filter);
switch (code) {
case BPF_ALU | BPF_ADD | BPF_X: /* A += X */
jit->seen |= SEEN_XREG;
/* ar %r5,%r12 */
EMIT2(0x1a5c);
break;
case BPF_S_ALU_ADD_K: /* A += K */
case BPF_ALU | BPF_ADD | BPF_K: /* A += K */
if (!K)
break;
if (K <= 16383)
@ -325,12 +318,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* a %r5,<d(K)>(%r13) */
EMIT4_DISP(0x5a50d000, EMIT_CONST(K));
break;
case BPF_S_ALU_SUB_X: /* A -= X */
case BPF_ALU | BPF_SUB | BPF_X: /* A -= X */
jit->seen |= SEEN_XREG;
/* sr %r5,%r12 */
EMIT2(0x1b5c);
break;
case BPF_S_ALU_SUB_K: /* A -= K */
case BPF_ALU | BPF_SUB | BPF_K: /* A -= K */
if (!K)
break;
if (K <= 16384)
@ -343,12 +336,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* s %r5,<d(K)>(%r13) */
EMIT4_DISP(0x5b50d000, EMIT_CONST(K));
break;
case BPF_S_ALU_MUL_X: /* A *= X */
case BPF_ALU | BPF_MUL | BPF_X: /* A *= X */
jit->seen |= SEEN_XREG;
/* msr %r5,%r12 */
EMIT4(0xb252005c);
break;
case BPF_S_ALU_MUL_K: /* A *= K */
case BPF_ALU | BPF_MUL | BPF_K: /* A *= K */
if (K <= 16383)
/* mhi %r5,K */
EMIT4_IMM(0xa75c0000, K);
@ -359,7 +352,7 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* ms %r5,<d(K)>(%r13) */
EMIT4_DISP(0x7150d000, EMIT_CONST(K));
break;
case BPF_S_ALU_DIV_X: /* A /= X */
case BPF_ALU | BPF_DIV | BPF_X: /* A /= X */
jit->seen |= SEEN_XREG | SEEN_RET0;
/* ltr %r12,%r12 */
EMIT2(0x12cc);
@ -370,7 +363,7 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* dlr %r4,%r12 */
EMIT4(0xb997004c);
break;
case BPF_S_ALU_DIV_K: /* A /= K */
case BPF_ALU | BPF_DIV | BPF_K: /* A /= K */
if (K == 1)
break;
/* lhi %r4,0 */
@ -378,7 +371,7 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* dl %r4,<d(K)>(%r13) */
EMIT6_DISP(0xe340d000, 0x0097, EMIT_CONST(K));
break;
case BPF_S_ALU_MOD_X: /* A %= X */
case BPF_ALU | BPF_MOD | BPF_X: /* A %= X */
jit->seen |= SEEN_XREG | SEEN_RET0;
/* ltr %r12,%r12 */
EMIT2(0x12cc);
@ -391,7 +384,7 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* lr %r5,%r4 */
EMIT2(0x1854);
break;
case BPF_S_ALU_MOD_K: /* A %= K */
case BPF_ALU | BPF_MOD | BPF_K: /* A %= K */
if (K == 1) {
/* lhi %r5,0 */
EMIT4(0xa7580000);
@ -404,12 +397,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* lr %r5,%r4 */
EMIT2(0x1854);
break;
case BPF_S_ALU_AND_X: /* A &= X */
case BPF_ALU | BPF_AND | BPF_X: /* A &= X */
jit->seen |= SEEN_XREG;
/* nr %r5,%r12 */
EMIT2(0x145c);
break;
case BPF_S_ALU_AND_K: /* A &= K */
case BPF_ALU | BPF_AND | BPF_K: /* A &= K */
if (test_facility(21))
/* nilf %r5,<K> */
EMIT6_IMM(0xc05b0000, K);
@ -417,12 +410,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* n %r5,<d(K)>(%r13) */
EMIT4_DISP(0x5450d000, EMIT_CONST(K));
break;
case BPF_S_ALU_OR_X: /* A |= X */
case BPF_ALU | BPF_OR | BPF_X: /* A |= X */
jit->seen |= SEEN_XREG;
/* or %r5,%r12 */
EMIT2(0x165c);
break;
case BPF_S_ALU_OR_K: /* A |= K */
case BPF_ALU | BPF_OR | BPF_K: /* A |= K */
if (test_facility(21))
/* oilf %r5,<K> */
EMIT6_IMM(0xc05d0000, K);
@ -430,55 +423,55 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
/* o %r5,<d(K)>(%r13) */
EMIT4_DISP(0x5650d000, EMIT_CONST(K));
break;
case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */
case BPF_S_ALU_XOR_X:
case BPF_ANC | SKF_AD_ALU_XOR_X: /* A ^= X; */
case BPF_ALU | BPF_XOR | BPF_X:
jit->seen |= SEEN_XREG;
/* xr %r5,%r12 */
EMIT2(0x175c);
break;
case BPF_S_ALU_XOR_K: /* A ^= K */
case BPF_ALU | BPF_XOR | BPF_K: /* A ^= K */
if (!K)
break;
/* x %r5,<d(K)>(%r13) */
EMIT4_DISP(0x5750d000, EMIT_CONST(K));
break;
case BPF_S_ALU_LSH_X: /* A <<= X; */
case BPF_ALU | BPF_LSH | BPF_X: /* A <<= X; */
jit->seen |= SEEN_XREG;
/* sll %r5,0(%r12) */
EMIT4(0x8950c000);
break;
case BPF_S_ALU_LSH_K: /* A <<= K */
case BPF_ALU | BPF_LSH | BPF_K: /* A <<= K */
if (K == 0)
break;
/* sll %r5,K */
EMIT4_DISP(0x89500000, K);
break;
case BPF_S_ALU_RSH_X: /* A >>= X; */
case BPF_ALU | BPF_RSH | BPF_X: /* A >>= X; */
jit->seen |= SEEN_XREG;
/* srl %r5,0(%r12) */
EMIT4(0x8850c000);
break;
case BPF_S_ALU_RSH_K: /* A >>= K; */
case BPF_ALU | BPF_RSH | BPF_K: /* A >>= K; */
if (K == 0)
break;
/* srl %r5,K */
EMIT4_DISP(0x88500000, K);
break;
case BPF_S_ALU_NEG: /* A = -A */
case BPF_ALU | BPF_NEG: /* A = -A */
/* lnr %r5,%r5 */
EMIT2(0x1155);
break;
case BPF_S_JMP_JA: /* ip += K */
case BPF_JMP | BPF_JA: /* ip += K */
offset = addrs[i + K] + jit->start - jit->prg;
EMIT4_PCREL(0xa7f40000, offset);
break;
case BPF_S_JMP_JGT_K: /* ip += (A > K) ? jt : jf */
case BPF_JMP | BPF_JGT | BPF_K: /* ip += (A > K) ? jt : jf */
mask = 0x200000; /* jh */
goto kbranch;
case BPF_S_JMP_JGE_K: /* ip += (A >= K) ? jt : jf */
case BPF_JMP | BPF_JGE | BPF_K: /* ip += (A >= K) ? jt : jf */
mask = 0xa00000; /* jhe */
goto kbranch;
case BPF_S_JMP_JEQ_K: /* ip += (A == K) ? jt : jf */
case BPF_JMP | BPF_JEQ | BPF_K: /* ip += (A == K) ? jt : jf */
mask = 0x800000; /* je */
kbranch: /* Emit compare if the branch targets are different */
if (filter->jt != filter->jf) {
@ -511,7 +504,7 @@ branch: if (filter->jt == filter->jf) {
EMIT4_PCREL(0xa7040000 | (mask ^ 0xf00000), offset);
}
break;
case BPF_S_JMP_JSET_K: /* ip += (A & K) ? jt : jf */
case BPF_JMP | BPF_JSET | BPF_K: /* ip += (A & K) ? jt : jf */
mask = 0x700000; /* jnz */
/* Emit test if the branch targets are different */
if (filter->jt != filter->jf) {
@ -525,13 +518,13 @@ branch: if (filter->jt == filter->jf) {
EMIT4_IMM(0xa7510000, K);
}
goto branch;
case BPF_S_JMP_JGT_X: /* ip += (A > X) ? jt : jf */
case BPF_JMP | BPF_JGT | BPF_X: /* ip += (A > X) ? jt : jf */
mask = 0x200000; /* jh */
goto xbranch;
case BPF_S_JMP_JGE_X: /* ip += (A >= X) ? jt : jf */
case BPF_JMP | BPF_JGE | BPF_X: /* ip += (A >= X) ? jt : jf */
mask = 0xa00000; /* jhe */
goto xbranch;
case BPF_S_JMP_JEQ_X: /* ip += (A == X) ? jt : jf */
case BPF_JMP | BPF_JEQ | BPF_X: /* ip += (A == X) ? jt : jf */
mask = 0x800000; /* je */
xbranch: /* Emit compare if the branch targets are different */
if (filter->jt != filter->jf) {
@ -540,7 +533,7 @@ xbranch: /* Emit compare if the branch targets are different */
EMIT2(0x195c);
}
goto branch;
case BPF_S_JMP_JSET_X: /* ip += (A & X) ? jt : jf */
case BPF_JMP | BPF_JSET | BPF_X: /* ip += (A & X) ? jt : jf */
mask = 0x700000; /* jnz */
/* Emit test if the branch targets are different */
if (filter->jt != filter->jf) {
@ -551,15 +544,15 @@ xbranch: /* Emit compare if the branch targets are different */
EMIT2(0x144c);
}
goto branch;
case BPF_S_LD_W_ABS: /* A = *(u32 *) (skb->data+K) */
case BPF_LD | BPF_W | BPF_ABS: /* A = *(u32 *) (skb->data+K) */
jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_WORD;
offset = jit->off_load_word;
goto load_abs;
case BPF_S_LD_H_ABS: /* A = *(u16 *) (skb->data+K) */
case BPF_LD | BPF_H | BPF_ABS: /* A = *(u16 *) (skb->data+K) */
jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_HALF;
offset = jit->off_load_half;
goto load_abs;
case BPF_S_LD_B_ABS: /* A = *(u8 *) (skb->data+K) */
case BPF_LD | BPF_B | BPF_ABS: /* A = *(u8 *) (skb->data+K) */
jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_BYTE;
offset = jit->off_load_byte;
load_abs: if ((int) K < 0)
@ -573,19 +566,19 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* jnz <ret0> */
EMIT4_PCREL(0xa7740000, (jit->ret0_ip - jit->prg));
break;
case BPF_S_LD_W_IND: /* A = *(u32 *) (skb->data+K+X) */
case BPF_LD | BPF_W | BPF_IND: /* A = *(u32 *) (skb->data+K+X) */
jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IWORD;
offset = jit->off_load_iword;
goto call_fn;
case BPF_S_LD_H_IND: /* A = *(u16 *) (skb->data+K+X) */
case BPF_LD | BPF_H | BPF_IND: /* A = *(u16 *) (skb->data+K+X) */
jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IHALF;
offset = jit->off_load_ihalf;
goto call_fn;
case BPF_S_LD_B_IND: /* A = *(u8 *) (skb->data+K+X) */
case BPF_LD | BPF_B | BPF_IND: /* A = *(u8 *) (skb->data+K+X) */
jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IBYTE;
offset = jit->off_load_ibyte;
goto call_fn;
case BPF_S_LDX_B_MSH:
case BPF_LDX | BPF_B | BPF_MSH:
/* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */
jit->seen |= SEEN_RET0;
if ((int) K < 0) {
@ -596,17 +589,17 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
jit->seen |= SEEN_DATAREF | SEEN_LOAD_BMSH;
offset = jit->off_load_bmsh;
goto call_fn;
case BPF_S_LD_W_LEN: /* A = skb->len; */
case BPF_LD | BPF_W | BPF_LEN: /* A = skb->len; */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
/* l %r5,<d(len)>(%r2) */
EMIT4_DISP(0x58502000, offsetof(struct sk_buff, len));
break;
case BPF_S_LDX_W_LEN: /* X = skb->len; */
case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */
jit->seen |= SEEN_XREG;
/* l %r12,<d(len)>(%r2) */
EMIT4_DISP(0x58c02000, offsetof(struct sk_buff, len));
break;
case BPF_S_LD_IMM: /* A = K */
case BPF_LD | BPF_IMM: /* A = K */
if (K <= 16383)
/* lhi %r5,K */
EMIT4_IMM(0xa7580000, K);
@ -617,7 +610,7 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* l %r5,<d(K)>(%r13) */
EMIT4_DISP(0x5850d000, EMIT_CONST(K));
break;
case BPF_S_LDX_IMM: /* X = K */
case BPF_LDX | BPF_IMM: /* X = K */
jit->seen |= SEEN_XREG;
if (K <= 16383)
/* lhi %r12,<K> */
@ -629,29 +622,29 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* l %r12,<d(K)>(%r13) */
EMIT4_DISP(0x58c0d000, EMIT_CONST(K));
break;
case BPF_S_LD_MEM: /* A = mem[K] */
case BPF_LD | BPF_MEM: /* A = mem[K] */
jit->seen |= SEEN_MEM;
/* l %r5,<K>(%r15) */
EMIT4_DISP(0x5850f000,
(jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
break;
case BPF_S_LDX_MEM: /* X = mem[K] */
case BPF_LDX | BPF_MEM: /* X = mem[K] */
jit->seen |= SEEN_XREG | SEEN_MEM;
/* l %r12,<K>(%r15) */
EMIT4_DISP(0x58c0f000,
(jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
break;
case BPF_S_MISC_TAX: /* X = A */
case BPF_MISC | BPF_TAX: /* X = A */
jit->seen |= SEEN_XREG;
/* lr %r12,%r5 */
EMIT2(0x18c5);
break;
case BPF_S_MISC_TXA: /* A = X */
case BPF_MISC | BPF_TXA: /* A = X */
jit->seen |= SEEN_XREG;
/* lr %r5,%r12 */
EMIT2(0x185c);
break;
case BPF_S_RET_K:
case BPF_RET | BPF_K:
if (K == 0) {
jit->seen |= SEEN_RET0;
if (last)
@ -671,33 +664,33 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
}
break;
case BPF_S_RET_A:
case BPF_RET | BPF_A:
/* llgfr %r2,%r5 */
EMIT4(0xb9160025);
/* j <exit> */
EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
break;
case BPF_S_ST: /* mem[K] = A */
case BPF_ST: /* mem[K] = A */
jit->seen |= SEEN_MEM;
/* st %r5,<K>(%r15) */
EMIT4_DISP(0x5050f000,
(jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
break;
case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
case BPF_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
jit->seen |= SEEN_XREG | SEEN_MEM;
/* st %r12,<K>(%r15) */
EMIT4_DISP(0x50c0f000,
(jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
break;
case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
case BPF_ANC | SKF_AD_PROTOCOL: /* A = ntohs(skb->protocol); */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
/* lhi %r5,0 */
EMIT4(0xa7580000);
/* icm %r5,3,<d(protocol)>(%r2) */
EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, protocol));
break;
case BPF_S_ANC_IFINDEX: /* if (!skb->dev) return 0;
* A = skb->dev->ifindex */
case BPF_ANC | SKF_AD_IFINDEX: /* if (!skb->dev) return 0;
* A = skb->dev->ifindex */
BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
jit->seen |= SEEN_RET0;
/* lg %r1,<d(dev)>(%r2) */
@ -709,20 +702,20 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* l %r5,<d(ifindex)>(%r1) */
EMIT4_DISP(0x58501000, offsetof(struct net_device, ifindex));
break;
case BPF_S_ANC_MARK: /* A = skb->mark */
case BPF_ANC | SKF_AD_MARK: /* A = skb->mark */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
/* l %r5,<d(mark)>(%r2) */
EMIT4_DISP(0x58502000, offsetof(struct sk_buff, mark));
break;
case BPF_S_ANC_QUEUE: /* A = skb->queue_mapping */
case BPF_ANC | SKF_AD_QUEUE: /* A = skb->queue_mapping */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
/* lhi %r5,0 */
EMIT4(0xa7580000);
/* icm %r5,3,<d(queue_mapping)>(%r2) */
EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, queue_mapping));
break;
case BPF_S_ANC_HATYPE: /* if (!skb->dev) return 0;
* A = skb->dev->type */
case BPF_ANC | SKF_AD_HATYPE: /* if (!skb->dev) return 0;
* A = skb->dev->type */
BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
jit->seen |= SEEN_RET0;
/* lg %r1,<d(dev)>(%r2) */
@ -736,20 +729,20 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* icm %r5,3,<d(type)>(%r1) */
EMIT4_DISP(0xbf531000, offsetof(struct net_device, type));
break;
case BPF_S_ANC_RXHASH: /* A = skb->hash */
case BPF_ANC | SKF_AD_RXHASH: /* A = skb->hash */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
/* l %r5,<d(hash)>(%r2) */
EMIT4_DISP(0x58502000, offsetof(struct sk_buff, hash));
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_ANC | SKF_AD_VLAN_TAG:
case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000);
/* lhi %r5,0 */
EMIT4(0xa7580000);
/* icm %r5,3,<d(vlan_tci)>(%r2) */
EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, vlan_tci));
if (filter->code == BPF_S_ANC_VLAN_TAG) {
if (code == (BPF_ANC | SKF_AD_VLAN_TAG)) {
/* nill %r5,0xefff */
EMIT4_IMM(0xa5570000, ~VLAN_TAG_PRESENT);
} else {
@ -759,7 +752,7 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
EMIT4_DISP(0x88500000, 12);
}
break;
case BPF_S_ANC_PKTTYPE:
case BPF_ANC | SKF_AD_PKTTYPE:
if (pkt_type_offset < 0)
goto out;
/* lhi %r5,0 */
@ -769,7 +762,7 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* srl %r5,5 */
EMIT4_DISP(0x88500000, 5);
break;
case BPF_S_ANC_CPU: /* A = smp_processor_id() */
case BPF_ANC | SKF_AD_CPU: /* A = smp_processor_id() */
#ifdef CONFIG_SMP
/* l %r5,<d(cpu_nr)> */
EMIT4_DISP(0x58500000, offsetof(struct _lowcore, cpu_nr));

View File

@ -238,4 +238,16 @@ static inline __sum16 ip_compute_csum(const void *buff, int len)
return csum_fold(csum_partial(buff, len, 0));
}
#define HAVE_ARCH_CSUM_ADD
static inline __wsum csum_add(__wsum csum, __wsum addend)
{
__asm__ __volatile__(
"addcc %0, %1, %0\n"
"addx %0, %%g0, %0"
: "=r" (csum)
: "r" (addend), "0" (csum));
return csum;
}
#endif /* !(__SPARC_CHECKSUM_H) */

View File

@ -164,4 +164,16 @@ static inline __sum16 ip_compute_csum(const void *buff, int len)
return csum_fold(csum_partial(buff, len, 0));
}
#define HAVE_ARCH_CSUM_ADD
static inline __wsum csum_add(__wsum csum, __wsum addend)
{
__asm__ __volatile__(
"addcc %0, %1, %0\n"
"addx %0, %%g0, %0"
: "=r" (csum)
: "r" (addend), "0" (csum));
return csum;
}
#endif /* !(__SPARC64_CHECKSUM_H) */

View File

@ -83,9 +83,9 @@ static void bpf_flush_icache(void *start_, void *end_)
#define BNE (F2(0, 2) | CONDNE)
#ifdef CONFIG_SPARC64
#define BNE_PTR (F2(0, 1) | CONDNE | (2 << 20))
#define BE_PTR (F2(0, 1) | CONDE | (2 << 20))
#else
#define BNE_PTR BNE
#define BE_PTR BE
#endif
#define SETHI(K, REG) \
@ -415,20 +415,11 @@ void bpf_jit_compile(struct sk_filter *fp)
emit_reg_move(O7, r_saved_O7);
switch (filter[0].code) {
case BPF_S_RET_K:
case BPF_S_LD_W_LEN:
case BPF_S_ANC_PROTOCOL:
case BPF_S_ANC_PKTTYPE:
case BPF_S_ANC_IFINDEX:
case BPF_S_ANC_MARK:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_ANC_CPU:
case BPF_S_ANC_QUEUE:
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
case BPF_RET | BPF_K:
case BPF_LD | BPF_W | BPF_LEN:
case BPF_LD | BPF_W | BPF_ABS:
case BPF_LD | BPF_H | BPF_ABS:
case BPF_LD | BPF_B | BPF_ABS:
/* The first instruction sets the A register (or is
* a "RET 'constant'")
*/
@ -445,59 +436,60 @@ void bpf_jit_compile(struct sk_filter *fp)
unsigned int t_offset;
unsigned int f_offset;
u32 t_op, f_op;
u16 code = bpf_anc_helper(&filter[i]);
int ilen;
switch (filter[i].code) {
case BPF_S_ALU_ADD_X: /* A += X; */
switch (code) {
case BPF_ALU | BPF_ADD | BPF_X: /* A += X; */
emit_alu_X(ADD);
break;
case BPF_S_ALU_ADD_K: /* A += K; */
case BPF_ALU | BPF_ADD | BPF_K: /* A += K; */
emit_alu_K(ADD, K);
break;
case BPF_S_ALU_SUB_X: /* A -= X; */
case BPF_ALU | BPF_SUB | BPF_X: /* A -= X; */
emit_alu_X(SUB);
break;
case BPF_S_ALU_SUB_K: /* A -= K */
case BPF_ALU | BPF_SUB | BPF_K: /* A -= K */
emit_alu_K(SUB, K);
break;
case BPF_S_ALU_AND_X: /* A &= X */
case BPF_ALU | BPF_AND | BPF_X: /* A &= X */
emit_alu_X(AND);
break;
case BPF_S_ALU_AND_K: /* A &= K */
case BPF_ALU | BPF_AND | BPF_K: /* A &= K */
emit_alu_K(AND, K);
break;
case BPF_S_ALU_OR_X: /* A |= X */
case BPF_ALU | BPF_OR | BPF_X: /* A |= X */
emit_alu_X(OR);
break;
case BPF_S_ALU_OR_K: /* A |= K */
case BPF_ALU | BPF_OR | BPF_K: /* A |= K */
emit_alu_K(OR, K);
break;
case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */
case BPF_S_ALU_XOR_X:
case BPF_ANC | SKF_AD_ALU_XOR_X: /* A ^= X; */
case BPF_ALU | BPF_XOR | BPF_X:
emit_alu_X(XOR);
break;
case BPF_S_ALU_XOR_K: /* A ^= K */
case BPF_ALU | BPF_XOR | BPF_K: /* A ^= K */
emit_alu_K(XOR, K);
break;
case BPF_S_ALU_LSH_X: /* A <<= X */
case BPF_ALU | BPF_LSH | BPF_X: /* A <<= X */
emit_alu_X(SLL);
break;
case BPF_S_ALU_LSH_K: /* A <<= K */
case BPF_ALU | BPF_LSH | BPF_K: /* A <<= K */
emit_alu_K(SLL, K);
break;
case BPF_S_ALU_RSH_X: /* A >>= X */
case BPF_ALU | BPF_RSH | BPF_X: /* A >>= X */
emit_alu_X(SRL);
break;
case BPF_S_ALU_RSH_K: /* A >>= K */
case BPF_ALU | BPF_RSH | BPF_K: /* A >>= K */
emit_alu_K(SRL, K);
break;
case BPF_S_ALU_MUL_X: /* A *= X; */
case BPF_ALU | BPF_MUL | BPF_X: /* A *= X; */
emit_alu_X(MUL);
break;
case BPF_S_ALU_MUL_K: /* A *= K */
case BPF_ALU | BPF_MUL | BPF_K: /* A *= K */
emit_alu_K(MUL, K);
break;
case BPF_S_ALU_DIV_K: /* A /= K with K != 0*/
case BPF_ALU | BPF_DIV | BPF_K: /* A /= K with K != 0*/
if (K == 1)
break;
emit_write_y(G0);
@ -512,7 +504,7 @@ void bpf_jit_compile(struct sk_filter *fp)
#endif
emit_alu_K(DIV, K);
break;
case BPF_S_ALU_DIV_X: /* A /= X; */
case BPF_ALU | BPF_DIV | BPF_X: /* A /= X; */
emit_cmpi(r_X, 0);
if (pc_ret0 > 0) {
t_offset = addrs[pc_ret0 - 1];
@ -544,10 +536,10 @@ void bpf_jit_compile(struct sk_filter *fp)
#endif
emit_alu_X(DIV);
break;
case BPF_S_ALU_NEG:
case BPF_ALU | BPF_NEG:
emit_neg();
break;
case BPF_S_RET_K:
case BPF_RET | BPF_K:
if (!K) {
if (pc_ret0 == -1)
pc_ret0 = i;
@ -556,7 +548,7 @@ void bpf_jit_compile(struct sk_filter *fp)
emit_loadimm(K, r_A);
}
/* Fallthrough */
case BPF_S_RET_A:
case BPF_RET | BPF_A:
if (seen_or_pass0) {
if (i != flen - 1) {
emit_jump(cleanup_addr);
@ -573,18 +565,18 @@ void bpf_jit_compile(struct sk_filter *fp)
emit_jmpl(r_saved_O7, 8, G0);
emit_reg_move(r_A, O0); /* delay slot */
break;
case BPF_S_MISC_TAX:
case BPF_MISC | BPF_TAX:
seen |= SEEN_XREG;
emit_reg_move(r_A, r_X);
break;
case BPF_S_MISC_TXA:
case BPF_MISC | BPF_TXA:
seen |= SEEN_XREG;
emit_reg_move(r_X, r_A);
break;
case BPF_S_ANC_CPU:
case BPF_ANC | SKF_AD_CPU:
emit_load_cpu(r_A);
break;
case BPF_S_ANC_PROTOCOL:
case BPF_ANC | SKF_AD_PROTOCOL:
emit_skb_load16(protocol, r_A);
break;
#if 0
@ -592,38 +584,38 @@ void bpf_jit_compile(struct sk_filter *fp)
* a bit field even though we very much
* know what we are doing here.
*/
case BPF_S_ANC_PKTTYPE:
case BPF_ANC | SKF_AD_PKTTYPE:
__emit_skb_load8(pkt_type, r_A);
emit_alu_K(SRL, 5);
break;
#endif
case BPF_S_ANC_IFINDEX:
case BPF_ANC | SKF_AD_IFINDEX:
emit_skb_loadptr(dev, r_A);
emit_cmpi(r_A, 0);
emit_branch(BNE_PTR, cleanup_addr + 4);
emit_branch(BE_PTR, cleanup_addr + 4);
emit_nop();
emit_load32(r_A, struct net_device, ifindex, r_A);
break;
case BPF_S_ANC_MARK:
case BPF_ANC | SKF_AD_MARK:
emit_skb_load32(mark, r_A);
break;
case BPF_S_ANC_QUEUE:
case BPF_ANC | SKF_AD_QUEUE:
emit_skb_load16(queue_mapping, r_A);
break;
case BPF_S_ANC_HATYPE:
case BPF_ANC | SKF_AD_HATYPE:
emit_skb_loadptr(dev, r_A);
emit_cmpi(r_A, 0);
emit_branch(BNE_PTR, cleanup_addr + 4);
emit_branch(BE_PTR, cleanup_addr + 4);
emit_nop();
emit_load16(r_A, struct net_device, type, r_A);
break;
case BPF_S_ANC_RXHASH:
case BPF_ANC | SKF_AD_RXHASH:
emit_skb_load32(hash, r_A);
break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_ANC | SKF_AD_VLAN_TAG:
case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
emit_skb_load16(vlan_tci, r_A);
if (filter[i].code == BPF_S_ANC_VLAN_TAG) {
if (code == (BPF_ANC | SKF_AD_VLAN_TAG)) {
emit_andi(r_A, VLAN_VID_MASK, r_A);
} else {
emit_loadimm(VLAN_TAG_PRESENT, r_TMP);
@ -631,44 +623,44 @@ void bpf_jit_compile(struct sk_filter *fp)
}
break;
case BPF_S_LD_IMM:
case BPF_LD | BPF_IMM:
emit_loadimm(K, r_A);
break;
case BPF_S_LDX_IMM:
case BPF_LDX | BPF_IMM:
emit_loadimm(K, r_X);
break;
case BPF_S_LD_MEM:
case BPF_LD | BPF_MEM:
emit_ldmem(K * 4, r_A);
break;
case BPF_S_LDX_MEM:
case BPF_LDX | BPF_MEM:
emit_ldmem(K * 4, r_X);
break;
case BPF_S_ST:
case BPF_ST:
emit_stmem(K * 4, r_A);
break;
case BPF_S_STX:
case BPF_STX:
emit_stmem(K * 4, r_X);
break;
#define CHOOSE_LOAD_FUNC(K, func) \
((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
case BPF_S_LD_W_ABS:
case BPF_LD | BPF_W | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_word);
common_load: seen |= SEEN_DATAREF;
emit_loadimm(K, r_OFF);
emit_call(func);
break;
case BPF_S_LD_H_ABS:
case BPF_LD | BPF_H | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_half);
goto common_load;
case BPF_S_LD_B_ABS:
case BPF_LD | BPF_B | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_byte);
goto common_load;
case BPF_S_LDX_B_MSH:
case BPF_LDX | BPF_B | BPF_MSH:
func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_byte_msh);
goto common_load;
case BPF_S_LD_W_IND:
case BPF_LD | BPF_W | BPF_IND:
func = bpf_jit_load_word;
common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG;
if (K) {
@ -683,13 +675,13 @@ common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG;
}
emit_call(func);
break;
case BPF_S_LD_H_IND:
case BPF_LD | BPF_H | BPF_IND:
func = bpf_jit_load_half;
goto common_load_ind;
case BPF_S_LD_B_IND:
case BPF_LD | BPF_B | BPF_IND:
func = bpf_jit_load_byte;
goto common_load_ind;
case BPF_S_JMP_JA:
case BPF_JMP | BPF_JA:
emit_jump(addrs[i + K]);
emit_nop();
break;
@ -700,14 +692,14 @@ common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG;
f_op = FOP; \
goto cond_branch
COND_SEL(BPF_S_JMP_JGT_K, BGU, BLEU);
COND_SEL(BPF_S_JMP_JGE_K, BGEU, BLU);
COND_SEL(BPF_S_JMP_JEQ_K, BE, BNE);
COND_SEL(BPF_S_JMP_JSET_K, BNE, BE);
COND_SEL(BPF_S_JMP_JGT_X, BGU, BLEU);
COND_SEL(BPF_S_JMP_JGE_X, BGEU, BLU);
COND_SEL(BPF_S_JMP_JEQ_X, BE, BNE);
COND_SEL(BPF_S_JMP_JSET_X, BNE, BE);
COND_SEL(BPF_JMP | BPF_JGT | BPF_K, BGU, BLEU);
COND_SEL(BPF_JMP | BPF_JGE | BPF_K, BGEU, BLU);
COND_SEL(BPF_JMP | BPF_JEQ | BPF_K, BE, BNE);
COND_SEL(BPF_JMP | BPF_JSET | BPF_K, BNE, BE);
COND_SEL(BPF_JMP | BPF_JGT | BPF_X, BGU, BLEU);
COND_SEL(BPF_JMP | BPF_JGE | BPF_X, BGEU, BLU);
COND_SEL(BPF_JMP | BPF_JEQ | BPF_X, BE, BNE);
COND_SEL(BPF_JMP | BPF_JSET | BPF_X, BNE, BE);
cond_branch: f_offset = addrs[i + filter[i].jf];
t_offset = addrs[i + filter[i].jt];
@ -719,20 +711,20 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
break;
}
switch (filter[i].code) {
case BPF_S_JMP_JGT_X:
case BPF_S_JMP_JGE_X:
case BPF_S_JMP_JEQ_X:
switch (code) {
case BPF_JMP | BPF_JGT | BPF_X:
case BPF_JMP | BPF_JGE | BPF_X:
case BPF_JMP | BPF_JEQ | BPF_X:
seen |= SEEN_XREG;
emit_cmp(r_A, r_X);
break;
case BPF_S_JMP_JSET_X:
case BPF_JMP | BPF_JSET | BPF_X:
seen |= SEEN_XREG;
emit_btst(r_A, r_X);
break;
case BPF_S_JMP_JEQ_K:
case BPF_S_JMP_JGT_K:
case BPF_S_JMP_JGE_K:
case BPF_JMP | BPF_JEQ | BPF_K:
case BPF_JMP | BPF_JGT | BPF_K:
case BPF_JMP | BPF_JGE | BPF_K:
if (is_simm13(K)) {
emit_cmpi(r_A, K);
} else {
@ -740,7 +732,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
emit_cmp(r_A, r_TMP);
}
break;
case BPF_S_JMP_JSET_K:
case BPF_JMP | BPF_JSET | BPF_K:
if (is_simm13(K)) {
emit_btsti(r_A, K);
} else {

View File

@ -184,8 +184,15 @@ static inline unsigned add32_with_carry(unsigned a, unsigned b)
asm("addl %2,%0\n\t"
"adcl $0,%0"
: "=r" (a)
: "0" (a), "r" (b));
: "0" (a), "rm" (b));
return a;
}
#define HAVE_ARCH_CSUM_ADD
static inline __wsum csum_add(__wsum csum, __wsum addend)
{
return (__force __wsum)add32_with_carry((__force unsigned)csum,
(__force unsigned)addend);
}
#endif /* _ASM_X86_CHECKSUM_64_H */

View File

@ -12,13 +12,16 @@
/*
* Calling convention :
* rdi : skb pointer
* rbx : skb pointer (callee saved)
* esi : offset of byte(s) to fetch in skb (can be scratched)
* r8 : copy of skb->data
* r10 : copy of skb->data
* r9d : hlen = skb->len - skb->data_len
*/
#define SKBDATA %r8
#define SKBDATA %r10
#define SKF_MAX_NEG_OFF $(-0x200000) /* SKF_LL_OFF from filter.h */
#define MAX_BPF_STACK (512 /* from filter.h */ + \
32 /* space for rbx,r13,r14,r15 */ + \
8 /* space for skb_copy_bits */)
sk_load_word:
.globl sk_load_word
@ -68,53 +71,31 @@ sk_load_byte_positive_offset:
movzbl (SKBDATA,%rsi),%eax
ret
/**
* sk_load_byte_msh - BPF_S_LDX_B_MSH helper
*
* Implements BPF_S_LDX_B_MSH : ldxb 4*([offset]&0xf)
* Must preserve A accumulator (%eax)
* Inputs : %esi is the offset value
*/
sk_load_byte_msh:
.globl sk_load_byte_msh
test %esi,%esi
js bpf_slow_path_byte_msh_neg
sk_load_byte_msh_positive_offset:
.globl sk_load_byte_msh_positive_offset
cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte_msh */
jle bpf_slow_path_byte_msh
movzbl (SKBDATA,%rsi),%ebx
and $15,%bl
shl $2,%bl
ret
/* rsi contains offset and can be scratched */
#define bpf_slow_path_common(LEN) \
push %rdi; /* save skb */ \
mov %rbx, %rdi; /* arg1 == skb */ \
push %r9; \
push SKBDATA; \
/* rsi already has offset */ \
mov $LEN,%ecx; /* len */ \
lea -12(%rbp),%rdx; \
lea - MAX_BPF_STACK + 32(%rbp),%rdx; \
call skb_copy_bits; \
test %eax,%eax; \
pop SKBDATA; \
pop %r9; \
pop %rdi
pop %r9;
bpf_slow_path_word:
bpf_slow_path_common(4)
js bpf_error
mov -12(%rbp),%eax
mov - MAX_BPF_STACK + 32(%rbp),%eax
bswap %eax
ret
bpf_slow_path_half:
bpf_slow_path_common(2)
js bpf_error
mov -12(%rbp),%ax
mov - MAX_BPF_STACK + 32(%rbp),%ax
rol $8,%ax
movzwl %ax,%eax
ret
@ -122,21 +103,11 @@ bpf_slow_path_half:
bpf_slow_path_byte:
bpf_slow_path_common(1)
js bpf_error
movzbl -12(%rbp),%eax
ret
bpf_slow_path_byte_msh:
xchg %eax,%ebx /* dont lose A , X is about to be scratched */
bpf_slow_path_common(1)
js bpf_error
movzbl -12(%rbp),%eax
and $15,%al
shl $2,%al
xchg %eax,%ebx
movzbl - MAX_BPF_STACK + 32(%rbp),%eax
ret
#define sk_negative_common(SIZE) \
push %rdi; /* save skb */ \
mov %rbx, %rdi; /* arg1 == skb */ \
push %r9; \
push SKBDATA; \
/* rsi already has offset */ \
@ -145,10 +116,8 @@ bpf_slow_path_byte_msh:
test %rax,%rax; \
pop SKBDATA; \
pop %r9; \
pop %rdi; \
jz bpf_error
bpf_slow_path_word_neg:
cmp SKF_MAX_NEG_OFF, %esi /* test range */
jl bpf_error /* offset lower -> error */
@ -179,22 +148,12 @@ sk_load_byte_negative_offset:
movzbl (%rax), %eax
ret
bpf_slow_path_byte_msh_neg:
cmp SKF_MAX_NEG_OFF, %esi
jl bpf_error
sk_load_byte_msh_negative_offset:
.globl sk_load_byte_msh_negative_offset
xchg %eax,%ebx /* dont lose A , X is about to be scratched */
sk_negative_common(1)
movzbl (%rax),%eax
and $15,%al
shl $2,%al
xchg %eax,%ebx
ret
bpf_error:
# force a return 0 from jit handler
xor %eax,%eax
mov -8(%rbp),%rbx
xor %eax,%eax
mov - MAX_BPF_STACK(%rbp),%rbx
mov - MAX_BPF_STACK + 8(%rbp),%r13
mov - MAX_BPF_STACK + 16(%rbp),%r14
mov - MAX_BPF_STACK + 24(%rbp),%r15
leaveq
ret

File diff suppressed because it is too large Load Diff

View File

@ -2780,7 +2780,7 @@ static struct pci_driver fore200e_pca_driver = {
static int __init fore200e_module_init(void)
{
int err;
int err = 0;
printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");

View File

@ -2551,12 +2551,12 @@ done:
timeout = 5 * 1000;
while (atomic_read(&vc->scq->used) > 0) {
timeout = msleep_interruptible(timeout);
if (!timeout)
if (!timeout) {
pr_warn("%s: SCQ drain timeout: %u used\n",
card->name, atomic_read(&vc->scq->used));
break;
}
}
if (!timeout)
printk("%s: SCQ drain timeout: %u used\n",
card->name, atomic_read(&vc->scq->used));
writel(TCMDQ_HALT | vc->index, SAR_REG_TCMDQ);
clear_scd(card, vc->scq, vc->class);

View File

@ -193,9 +193,10 @@ static int ath3k_load_firmware(struct usb_device *udev,
sent += 20;
count -= 20;
pipe = usb_sndbulkpipe(udev, 0x02);
while (count) {
size = min_t(uint, count, BULK_SIZE);
pipe = usb_sndbulkpipe(udev, 0x02);
memcpy(send_buf, firmware->data + sent, size);
err = usb_bulk_msg(udev, pipe, send_buf, size,

View File

@ -59,6 +59,8 @@ struct btmrvl_device {
};
struct btmrvl_adapter {
void *hw_regs_buf;
u8 *hw_regs;
u32 int_count;
struct sk_buff_head tx_queue;
u8 psmode;
@ -140,7 +142,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv);
bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd);
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv);

View File

@ -24,6 +24,7 @@
#include <net/bluetooth/hci_core.h>
#include "btmrvl_drv.h"
#include "btmrvl_sdio.h"
#define VERSION "1.0"
@ -201,7 +202,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
return 0;
}
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
{
int ret;
@ -337,10 +338,25 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
static void btmrvl_init_adapter(struct btmrvl_private *priv)
{
int buf_size;
skb_queue_head_init(&priv->adapter->tx_queue);
priv->adapter->ps_state = PS_AWAKE;
buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN);
priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL);
if (!priv->adapter->hw_regs_buf) {
priv->adapter->hw_regs = NULL;
BT_ERR("Unable to allocate buffer for hw_regs.");
} else {
priv->adapter->hw_regs =
(u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf,
BTSDIO_DMA_ALIGN);
BT_DBG("hw_regs_buf=%p hw_regs=%p",
priv->adapter->hw_regs_buf, priv->adapter->hw_regs);
}
init_waitqueue_head(&priv->adapter->cmd_wait_q);
}
@ -348,6 +364,7 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv)
{
skb_queue_purge(&priv->adapter->tx_queue);
kfree(priv->adapter->hw_regs_buf);
kfree(priv->adapter);
priv->adapter = NULL;

View File

@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
.io_port_0 = 0x00,
.io_port_1 = 0x01,
.io_port_2 = 0x02,
.int_read_to_clear = false,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
.cfg = 0x00,
@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
.io_port_0 = 0x78,
.io_port_1 = 0x79,
.io_port_2 = 0x7a,
.int_read_to_clear = false,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
.io_port_0 = 0xd8,
.io_port_1 = 0xd9,
.io_port_2 = 0xda,
.int_read_to_clear = true,
.host_int_rsr = 0x01,
.card_misc_cfg = 0xcc,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
@ -667,6 +672,53 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
return 0;
}
static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
{
struct btmrvl_adapter *adapter = card->priv->adapter;
int ret;
ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE);
if (ret) {
BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret);
return ret;
}
*ireg = adapter->hw_regs[card->reg->host_intstatus];
BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg);
return 0;
}
static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
{
int ret;
*ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_readb: read int status failed: %d", ret);
return ret;
}
if (*ireg) {
/*
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
* Clear the interrupt status register and re-enable the
* interrupt.
*/
BT_DBG("int_status = 0x%x", *ireg);
sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS |
UP_LD_HOST_INT_STATUS),
card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_writeb: clear int status failed: %d", ret);
return ret;
}
}
return 0;
}
static void btmrvl_sdio_interrupt(struct sdio_func *func)
{
struct btmrvl_private *priv;
@ -684,28 +736,13 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
priv = card->priv;
ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_readb: read int status register failed");
if (card->reg->int_read_to_clear)
ret = btmrvl_sdio_read_to_clear(card, &ireg);
else
ret = btmrvl_sdio_write_to_clear(card, &ireg);
if (ret)
return;
}
if (ireg != 0) {
/*
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
* Clear the interrupt status register and re-enable the
* interrupt.
*/
BT_DBG("ireg = 0x%x", ireg);
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
UP_LD_HOST_INT_STATUS),
card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_writeb: clear int status register failed");
return;
}
}
spin_lock_irqsave(&priv->driver_lock, flags);
sdio_ireg |= ireg;
@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
if (card->reg->int_read_to_clear) {
reg = sdio_readb(func, card->reg->host_int_rsr, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
reg = sdio_readb(func, card->reg->card_misc_cfg, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
}
sdio_set_drvdata(func, card);
sdio_release_host(func);

View File

@ -78,6 +78,9 @@ struct btmrvl_sdio_card_reg {
u8 io_port_0;
u8 io_port_1;
u8 io_port_2;
bool int_read_to_clear;
u8 host_int_rsr;
u8 card_misc_cfg;
};
struct btmrvl_sdio_card {

View File

@ -49,6 +49,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_WRONG_SCO_MTU 0x40
#define BTUSB_ATH3012 0x80
#define BTUSB_INTEL 0x100
#define BTUSB_BCM_PATCHRAM 0x200
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
/* Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
/* Belkin F8065bf - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
@ -1381,6 +1383,154 @@ exit_mfg_deactivate:
return 0;
}
static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct usb_device *udev = data->udev;
char fw_name[64];
const struct firmware *fw;
const u8 *fw_ptr;
size_t fw_size;
const struct hci_command_hdr *cmd;
const u8 *cmd_param;
u16 opcode;
struct sk_buff *skb;
struct hci_rp_read_local_version *ver;
long ret;
snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd",
udev->product ? udev->product : "BCM",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
ret = request_firmware(&fw, fw_name, &hdev->dev);
if (ret < 0) {
BT_INFO("%s: BCM: patch %s not found", hdev->name,
fw_name);
return 0;
}
/* Reset */
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
goto done;
}
kfree_skb(skb);
/* Read Local Version Info */
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
hdev->name, ret);
goto done;
}
if (skb->len != sizeof(*ver)) {
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
hdev->name);
kfree_skb(skb);
ret = -EIO;
goto done;
}
ver = (struct hci_rp_read_local_version *) skb->data;
BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
ver->lmp_ver, ver->lmp_subver);
kfree_skb(skb);
/* Start Download */
skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: BCM: Download Minidrv command failed (%ld)",
hdev->name, ret);
goto reset_fw;
}
kfree_skb(skb);
/* 50 msec delay after Download Minidrv completes */
msleep(50);
fw_ptr = fw->data;
fw_size = fw->size;
while (fw_size >= sizeof(*cmd)) {
cmd = (struct hci_command_hdr *) fw_ptr;
fw_ptr += sizeof(*cmd);
fw_size -= sizeof(*cmd);
if (fw_size < cmd->plen) {
BT_ERR("%s: BCM: patch %s is corrupted",
hdev->name, fw_name);
ret = -EINVAL;
goto reset_fw;
}
cmd_param = fw_ptr;
fw_ptr += cmd->plen;
fw_size -= cmd->plen;
opcode = le16_to_cpu(cmd->opcode);
skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: BCM: patch command %04x failed (%ld)",
hdev->name, opcode, ret);
goto reset_fw;
}
kfree_skb(skb);
}
/* 250 msec delay after Launch Ram completes */
msleep(250);
reset_fw:
/* Reset */
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
goto done;
}
kfree_skb(skb);
/* Read Local Version Info */
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
hdev->name, ret);
goto done;
}
if (skb->len != sizeof(*ver)) {
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
hdev->name);
kfree_skb(skb);
ret = -EIO;
goto done;
}
ver = (struct hci_rp_read_local_version *) skb->data;
BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
ver->lmp_ver, ver->lmp_subver);
kfree_skb(skb);
done:
release_firmware(fw);
return ret;
}
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_BCM92035)
hdev->setup = btusb_setup_bcm92035;
if (id->driver_info & BTUSB_BCM_PATCHRAM)
hdev->setup = btusb_setup_bcm_patchram;
if (id->driver_info & BTUSB_INTEL)
hdev->setup = btusb_setup_intel;

View File

@ -55,13 +55,6 @@ struct h4_struct {
struct sk_buff_head txq;
};
/* H4 receiver States */
#define H4_W4_PACKET_TYPE 0
#define H4_W4_EVENT_HDR 1
#define H4_W4_ACL_HDR 2
#define H4_W4_SCO_HDR 3
#define H4_W4_DATA 4
/* Initialize protocol */
static int h4_open(struct hci_uart *hu)
{

View File

@ -116,9 +116,25 @@ static struct ti_dt_clk am43xx_clks[] = {
int __init am43xx_dt_clk_init(void)
{
struct clk *clk1, *clk2;
ti_dt_clocks_register(am43xx_clks);
omap2_clk_disable_autoidle_all();
/*
* cpsw_cpts_rft_clk has got the choice of 3 clocksources
* dpll_core_m4_ck, dpll_core_m5_ck and dpll_disp_m2_ck.
* By default dpll_core_m4_ck is selected, witn this as clock
* source the CPTS doesnot work properly. It gives clockcheck errors
* while running PTP.
* clockcheck: clock jumped backward or running slower than expected!
* By selecting dpll_core_m5_ck as the clocksource fixes this issue.
* In AM335x dpll_core_m5_ck is the default clocksource.
*/
clk1 = clk_get_sys(NULL, "cpsw_cpts_rft_clk");
clk2 = clk_get_sys(NULL, "dpll_core_m5_ck");
clk_set_parent(clk1, clk2);
return 0;
}

View File

@ -404,7 +404,7 @@ static u32 next_vp;
* performance critical channels (IDE, SCSI and Network) will be uniformly
* distributed across all available CPUs.
*/
static void init_vp_index(struct vmbus_channel *channel, uuid_le *type_guid)
static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid)
{
u32 cur_cpu;
int i;

View File

@ -649,9 +649,9 @@ extern struct vmbus_connection vmbus_connection;
/* General vmbus interface */
struct hv_device *vmbus_device_create(uuid_le *type,
uuid_le *instance,
struct vmbus_channel *channel);
struct hv_device *vmbus_device_create(const uuid_le *type,
const uuid_le *instance,
struct vmbus_channel *channel);
int vmbus_device_register(struct hv_device *child_device_obj);
void vmbus_device_unregister(struct hv_device *device_obj);

View File

@ -435,7 +435,7 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
return ret;
}
static uuid_le null_guid;
static const uuid_le null_guid;
static inline bool is_null_guid(const __u8 *guid)
{
@ -450,7 +450,7 @@ static inline bool is_null_guid(const __u8 *guid)
*/
static const struct hv_vmbus_device_id *hv_vmbus_get_id(
const struct hv_vmbus_device_id *id,
__u8 *guid)
const __u8 *guid)
{
for (; !is_null_guid(id->guid); id++)
if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
@ -779,9 +779,9 @@ EXPORT_SYMBOL_GPL(vmbus_driver_unregister);
* vmbus_device_create - Creates and registers a new child device
* on the vmbus.
*/
struct hv_device *vmbus_device_create(uuid_le *type,
uuid_le *instance,
struct vmbus_channel *channel)
struct hv_device *vmbus_device_create(const uuid_le *type,
const uuid_le *instance,
struct vmbus_channel *channel)
{
struct hv_device *child_device_obj;

View File

@ -234,12 +234,16 @@ static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
static void set_emss(struct c4iw_ep *ep, u16 opt)
{
ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] - 40;
ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] -
sizeof(struct iphdr) - sizeof(struct tcphdr);
ep->mss = ep->emss;
if (GET_TCPOPT_TSTAMP(opt))
ep->emss -= 12;
if (ep->emss < 128)
ep->emss = 128;
if (ep->emss & 7)
PDBG("Warning: misaligned mtu idx %u mss %u emss=%u\n",
GET_TCPOPT_MSS(opt), ep->mss, ep->emss);
PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, GET_TCPOPT_MSS(opt),
ep->mss, ep->emss);
}
@ -473,7 +477,7 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT;
flowc->mnemval[5].val = cpu_to_be32(ep->rcv_seq);
flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF;
flowc->mnemval[6].val = cpu_to_be32(snd_win);
flowc->mnemval[6].val = cpu_to_be32(ep->snd_win);
flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS;
flowc->mnemval[7].val = cpu_to_be32(ep->emss);
/* Pad WR to 16 byte boundary */
@ -565,6 +569,17 @@ static void c4iw_record_pm_msg(struct c4iw_ep *ep,
sizeof(ep->com.mapped_remote_addr));
}
static void best_mtu(const unsigned short *mtus, unsigned short mtu,
unsigned int *idx, int use_ts)
{
unsigned short hdr_size = sizeof(struct iphdr) +
sizeof(struct tcphdr) +
(use_ts ? 12 : 0);
unsigned short data_size = mtu - hdr_size;
cxgb4_best_aligned_mtu(mtus, hdr_size, data_size, 8, idx);
}
static int send_connect(struct c4iw_ep *ep)
{
struct cpl_act_open_req *req;
@ -591,6 +606,7 @@ static int send_connect(struct c4iw_ep *ep)
&ep->com.mapped_local_addr;
struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
&ep->com.mapped_remote_addr;
int win;
wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
roundup(sizev4, 16) :
@ -606,8 +622,18 @@ static int send_connect(struct c4iw_ep *ep)
}
set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
enable_tcp_timestamps);
wscale = compute_wscale(rcv_win);
/*
* Specify the largest window that will fit in opt0. The
* remainder will be specified in the rx_data_ack.
*/
win = ep->rcv_win >> 10;
if (win > RCV_BUFSIZ_MASK)
win = RCV_BUFSIZ_MASK;
opt0 = (nocong ? NO_CONG(1) : 0) |
KEEP_ALIVE(1) |
DELACK(1) |
@ -618,7 +644,7 @@ static int send_connect(struct c4iw_ep *ep)
SMAC_SEL(ep->smac_idx) |
DSCP(ep->tos) |
ULP_MODE(ULP_MODE_TCPDDP) |
RCV_BUFSIZ(rcv_win>>10);
RCV_BUFSIZ(win);
opt2 = RX_CHANNEL(0) |
CCTRL_ECN(enable_ecn) |
RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
@ -674,6 +700,13 @@ static int send_connect(struct c4iw_ep *ep)
req6->opt2 = cpu_to_be32(opt2);
}
} else {
u32 isn = (prandom_u32() & ~7UL) - 1;
opt2 |= T5_OPT_2_VALID;
opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
if (peer2peer)
isn += 4;
if (ep->com.remote_addr.ss_family == AF_INET) {
t5_req = (struct cpl_t5_act_open_req *)
skb_put(skb, wrlen);
@ -690,6 +723,9 @@ static int send_connect(struct c4iw_ep *ep)
cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0],
ep->l2t)));
t5_req->rsvd = cpu_to_be32(isn);
PDBG("%s snd_isn %u\n", __func__,
be32_to_cpu(t5_req->rsvd));
t5_req->opt2 = cpu_to_be32(opt2);
} else {
t5_req6 = (struct cpl_t5_act_open_req6 *)
@ -713,6 +749,9 @@ static int send_connect(struct c4iw_ep *ep)
cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0],
ep->l2t));
t5_req6->rsvd = cpu_to_be32(isn);
PDBG("%s snd_isn %u\n", __func__,
be32_to_cpu(t5_req6->rsvd));
t5_req6->opt2 = cpu_to_be32(opt2);
}
}
@ -1186,6 +1225,14 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)
return 0;
}
/*
* If we couldn't specify the entire rcv window at connection setup
* due to the limit in the number of bits in the RCV_BUFSIZ field,
* then add the overage in to the credits returned.
*/
if (ep->rcv_win > RCV_BUFSIZ_MASK * 1024)
credits += ep->rcv_win - RCV_BUFSIZ_MASK * 1024;
req = (struct cpl_rx_data_ack *) skb_put(skb, wrlen);
memset(req, 0, wrlen);
INIT_TP_WR(req, ep->hwtid);
@ -1659,6 +1706,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
unsigned int mtu_idx;
int wscale;
struct sockaddr_in *sin;
int win;
skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));
@ -1681,8 +1729,18 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
htons(F_FW_OFLD_CONNECTION_WR_CPLRXDATAACK);
req->tcb.tx_max = (__force __be32) jiffies;
req->tcb.rcv_adv = htons(1);
cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
enable_tcp_timestamps);
wscale = compute_wscale(rcv_win);
/*
* Specify the largest window that will fit in opt0. The
* remainder will be specified in the rx_data_ack.
*/
win = ep->rcv_win >> 10;
if (win > RCV_BUFSIZ_MASK)
win = RCV_BUFSIZ_MASK;
req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) |
(nocong ? NO_CONG(1) : 0) |
KEEP_ALIVE(1) |
@ -1694,7 +1752,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
SMAC_SEL(ep->smac_idx) |
DSCP(ep->tos) |
ULP_MODE(ULP_MODE_TCPDDP) |
RCV_BUFSIZ(rcv_win >> 10));
RCV_BUFSIZ(win));
req->tcb.opt2 = (__force __be32) (PACE(1) |
TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
RX_CHANNEL(0) |
@ -1731,6 +1789,13 @@ static int is_neg_adv(unsigned int status)
status == CPL_ERR_KEEPALV_NEG_ADVICE;
}
static void set_tcp_window(struct c4iw_ep *ep, struct port_info *pi)
{
ep->snd_win = snd_win;
ep->rcv_win = rcv_win;
PDBG("%s snd_win %d rcv_win %d\n", __func__, ep->snd_win, ep->rcv_win);
}
#define ACT_OPEN_RETRY_COUNT 2
static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
@ -1779,6 +1844,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
ep->ctrlq_idx = cxgb4_port_idx(pdev);
ep->rss_qid = cdev->rdev.lldi.rxq_ids[
cxgb4_port_idx(pdev) * step];
set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));
dev_put(pdev);
} else {
pdev = get_real_dev(n->dev);
@ -1797,6 +1863,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
cdev->rdev.lldi.nchan;
ep->rss_qid = cdev->rdev.lldi.rxq_ids[
cxgb4_port_idx(pdev) * step];
set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));
if (clear_mpa_v1) {
ep->retry_with_mpa_v1 = 0;
@ -2027,13 +2094,36 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
u64 opt0;
u32 opt2;
int wscale;
struct cpl_t5_pass_accept_rpl *rpl5 = NULL;
int win;
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
BUG_ON(skb_cloned(skb));
skb_trim(skb, sizeof(*rpl));
skb_get(skb);
cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
rpl = cplhdr(skb);
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
skb_trim(skb, roundup(sizeof(*rpl5), 16));
rpl5 = (void *)rpl;
INIT_TP_WR(rpl5, ep->hwtid);
} else {
skb_trim(skb, sizeof(*rpl));
INIT_TP_WR(rpl, ep->hwtid);
}
OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
ep->hwtid));
best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
enable_tcp_timestamps && req->tcpopt.tstamp);
wscale = compute_wscale(rcv_win);
/*
* Specify the largest window that will fit in opt0. The
* remainder will be specified in the rx_data_ack.
*/
win = ep->rcv_win >> 10;
if (win > RCV_BUFSIZ_MASK)
win = RCV_BUFSIZ_MASK;
opt0 = (nocong ? NO_CONG(1) : 0) |
KEEP_ALIVE(1) |
DELACK(1) |
@ -2044,7 +2134,7 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
SMAC_SEL(ep->smac_idx) |
DSCP(ep->tos >> 2) |
ULP_MODE(ULP_MODE_TCPDDP) |
RCV_BUFSIZ(rcv_win>>10);
RCV_BUFSIZ(win);
opt2 = RX_CHANNEL(0) |
RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
@ -2064,14 +2154,18 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
opt2 |= CCTRL_ECN(1);
}
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
u32 isn = (prandom_u32() & ~7UL) - 1;
opt2 |= T5_OPT_2_VALID;
opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
rpl5 = (void *)rpl;
memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16));
if (peer2peer)
isn += 4;
rpl5->iss = cpu_to_be32(isn);
PDBG("%s iss %u\n", __func__, be32_to_cpu(rpl5->iss));
}
rpl = cplhdr(skb);
INIT_TP_WR(rpl, ep->hwtid);
OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
ep->hwtid));
rpl->opt0 = cpu_to_be64(opt0);
rpl->opt2 = cpu_to_be32(opt2);
set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
@ -2136,6 +2230,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
int err;
u16 peer_mss = ntohs(req->tcpopt.mss);
int iptype;
unsigned short hdrs;
parent_ep = lookup_stid(t, stid);
if (!parent_ep) {
@ -2193,8 +2288,10 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
goto reject;
}
if (peer_mss && child_ep->mtu > (peer_mss + 40))
child_ep->mtu = peer_mss + 40;
hdrs = sizeof(struct iphdr) + sizeof(struct tcphdr) +
((enable_tcp_timestamps && req->tcpopt.tstamp) ? 12 : 0);
if (peer_mss && child_ep->mtu > (peer_mss + hdrs))
child_ep->mtu = peer_mss + hdrs;
state_set(&child_ep->com, CONNECTING);
child_ep->com.dev = dev;

View File

@ -134,7 +134,8 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
V_FW_RI_RES_WR_IQANUS(0) |
V_FW_RI_RES_WR_IQANUD(1) |
F_FW_RI_RES_WR_IQANDST |
V_FW_RI_RES_WR_IQANDSTINDEX(*rdev->lldi.rxq_ids));
V_FW_RI_RES_WR_IQANDSTINDEX(
rdev->lldi.ciq_ids[cq->vector]));
res->u.cq.iqdroprss_to_iqesize = cpu_to_be16(
F_FW_RI_RES_WR_IQDROPRSS |
V_FW_RI_RES_WR_IQPCIECH(2) |
@ -870,6 +871,9 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
rhp = to_c4iw_dev(ibdev);
if (vector >= rhp->rdev.lldi.nciq)
return ERR_PTR(-EINVAL);
chp = kzalloc(sizeof(*chp), GFP_KERNEL);
if (!chp)
return ERR_PTR(-ENOMEM);
@ -915,6 +919,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
}
chp->cq.size = hwentries;
chp->cq.memsize = memsize;
chp->cq.vector = vector;
ret = create_cq(&rhp->rdev, &chp->cq,
ucontext ? &ucontext->uctx : &rhp->rdev.uctx);

View File

@ -810,6 +810,8 @@ struct c4iw_ep {
u8 retry_with_mpa_v1;
u8 tried_with_mpa_v1;
unsigned int retry_count;
int snd_win;
int rcv_win;
};
static inline void print_addr(struct c4iw_ep_common *epc, const char *func,

View File

@ -500,7 +500,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
dev->ibdev.node_type = RDMA_NODE_RNIC;
memcpy(dev->ibdev.node_desc, C4IW_NODE_DESC, sizeof(C4IW_NODE_DESC));
dev->ibdev.phys_port_cnt = dev->rdev.lldi.nports;
dev->ibdev.num_comp_vectors = 1;
dev->ibdev.num_comp_vectors = dev->rdev.lldi.nciq;
dev->ibdev.dma_device = &(dev->rdev.lldi.pdev->dev);
dev->ibdev.query_device = c4iw_query_device;
dev->ibdev.query_port = c4iw_query_port;

View File

@ -542,6 +542,7 @@ struct t4_cq {
size_t memsize;
__be64 bits_type_ts;
u32 cqid;
int vector;
u16 size; /* including status page */
u16 cidx;
u16 sw_pidx;

View File

@ -848,6 +848,7 @@ enum { /* TCP congestion control algorithms */
#define V_CONG_CNTRL(x) ((x) << S_CONG_CNTRL)
#define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL)
#define CONG_CNTRL_VALID (1 << 18)
#define T5_OPT_2_VALID (1 << 31)
#endif /* _T4FW_RI_API_H_ */

View File

@ -105,5 +105,5 @@ static const struct ethtool_ops ipoib_ethtool_ops = {
void ipoib_set_ethtool_ops(struct net_device *dev)
{
SET_ETHTOOL_OPS(dev, &ipoib_ethtool_ops);
dev->ethtool_ops = &ipoib_ethtool_ops;
}

View File

@ -1,11 +1,3 @@
config ISDN_DRV_AVMB1_VERBOSE_REASON
bool "Verbose reason code reporting"
default y
help
If you say Y here, the CAPI drivers will give verbose reasons for
disconnecting. This will increase the size of the kernel by 7 KB. If
unsure, say Y.
config CAPI_TRACE
bool "CAPI trace support"
default y
@ -17,7 +9,7 @@ config CAPI_TRACE
If unsure, say Y.
config ISDN_CAPI_CAPI20
tristate "CAPI2.0 /dev/capi support"
tristate "CAPI2.0 /dev/capi20 support"
help
This option will provide the CAPI 2.0 interface to userspace
applications via /dev/capi20. Applications should use the
@ -42,3 +34,11 @@ config ISDN_CAPI_CAPIDRV
the legacy isdn4linux link layer. If you have a card which is
supported by a CAPI driver, but still want to use old features like
ippp interfaces or ttyI emulation, say Y/M here.
config ISDN_CAPI_CAPIDRV_VERBOSE
bool "Verbose reason code reporting"
depends on ISDN_CAPI_CAPIDRV
help
If you say Y here, the capidrv interface will give verbose reasons
for disconnecting. This will increase the size of the kernel by 7 KB.
If unsure, say N.

View File

@ -1271,7 +1271,7 @@ static int __init capinc_tty_init(void)
return -ENOMEM;
}
drv->driver_name = "capi_nc";
drv->name = "capi";
drv->name = "capi!";
drv->major = 0;
drv->minor_start = 0;
drv->type = TTY_DRIVER_TYPE_SERIAL;
@ -1417,7 +1417,7 @@ static int __init capi_init(void)
return PTR_ERR(capi_class);
}
device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi20");
if (capinc_tty_init() < 0) {
device_destroy(capi_class, MKDEV(capi_major, 0));

View File

@ -763,6 +763,201 @@ static inline int new_bchan(capidrv_contr *card)
}
/* ------------------------------------------------------------------- */
static char *capi_info2str(u16 reason)
{
#ifndef CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE
return "..";
#else
switch (reason) {
/*-- informative values (corresponding message was processed) -----*/
case 0x0001:
return "NCPI not supported by current protocol, NCPI ignored";
case 0x0002:
return "Flags not supported by current protocol, flags ignored";
case 0x0003:
return "Alert already sent by another application";
/*-- error information concerning CAPI_REGISTER -----*/
case 0x1001:
return "Too many applications";
case 0x1002:
return "Logical block size too small, must be at least 128 Bytes";
case 0x1003:
return "Buffer exceeds 64 kByte";
case 0x1004:
return "Message buffer size too small, must be at least 1024 Bytes";
case 0x1005:
return "Max. number of logical connections not supported";
case 0x1006:
return "Reserved";
case 0x1007:
return "The message could not be accepted because of an internal busy condition";
case 0x1008:
return "OS resource error (no memory ?)";
case 0x1009:
return "CAPI not installed";
case 0x100A:
return "Controller does not support external equipment";
case 0x100B:
return "Controller does only support external equipment";
/*-- error information concerning message exchange functions -----*/
case 0x1101:
return "Illegal application number";
case 0x1102:
return "Illegal command or subcommand or message length less than 12 bytes";
case 0x1103:
return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
case 0x1104:
return "Queue is empty";
case 0x1105:
return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
case 0x1106:
return "Unknown notification parameter";
case 0x1107:
return "The Message could not be accepted because of an internal busy condition";
case 0x1108:
return "OS Resource error (no memory ?)";
case 0x1109:
return "CAPI not installed";
case 0x110A:
return "Controller does not support external equipment";
case 0x110B:
return "Controller does only support external equipment";
/*-- error information concerning resource / coding problems -----*/
case 0x2001:
return "Message not supported in current state";
case 0x2002:
return "Illegal Controller / PLCI / NCCI";
case 0x2003:
return "Out of PLCI";
case 0x2004:
return "Out of NCCI";
case 0x2005:
return "Out of LISTEN";
case 0x2006:
return "Out of FAX resources (protocol T.30)";
case 0x2007:
return "Illegal message parameter coding";
/*-- error information concerning requested services -----*/
case 0x3001:
return "B1 protocol not supported";
case 0x3002:
return "B2 protocol not supported";
case 0x3003:
return "B3 protocol not supported";
case 0x3004:
return "B1 protocol parameter not supported";
case 0x3005:
return "B2 protocol parameter not supported";
case 0x3006:
return "B3 protocol parameter not supported";
case 0x3007:
return "B protocol combination not supported";
case 0x3008:
return "NCPI not supported";
case 0x3009:
return "CIP Value unknown";
case 0x300A:
return "Flags not supported (reserved bits)";
case 0x300B:
return "Facility not supported";
case 0x300C:
return "Data length not supported by current protocol";
case 0x300D:
return "Reset procedure not supported by current protocol";
/*-- informations about the clearing of a physical connection -----*/
case 0x3301:
return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
case 0x3302:
return "Protocol error layer 2";
case 0x3303:
return "Protocol error layer 3";
case 0x3304:
return "Another application got that call";
/*-- T.30 specific reasons -----*/
case 0x3311:
return "Connecting not successful (remote station is no FAX G3 machine)";
case 0x3312:
return "Connecting not successful (training error)";
case 0x3313:
return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
case 0x3314:
return "Disconnected during transfer (remote abort)";
case 0x3315:
return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
case 0x3316:
return "Disconnected during transfer (local tx data underrun)";
case 0x3317:
return "Disconnected during transfer (local rx data overflow)";
case 0x3318:
return "Disconnected during transfer (local abort)";
case 0x3319:
return "Illegal parameter coding (e.g. SFF coding error)";
/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
case 0x3481: return "Unallocated (unassigned) number";
case 0x3482: return "No route to specified transit network";
case 0x3483: return "No route to destination";
case 0x3486: return "Channel unacceptable";
case 0x3487:
return "Call awarded and being delivered in an established channel";
case 0x3490: return "Normal call clearing";
case 0x3491: return "User busy";
case 0x3492: return "No user responding";
case 0x3493: return "No answer from user (user alerted)";
case 0x3495: return "Call rejected";
case 0x3496: return "Number changed";
case 0x349A: return "Non-selected user clearing";
case 0x349B: return "Destination out of order";
case 0x349C: return "Invalid number format";
case 0x349D: return "Facility rejected";
case 0x349E: return "Response to STATUS ENQUIRY";
case 0x349F: return "Normal, unspecified";
case 0x34A2: return "No circuit / channel available";
case 0x34A6: return "Network out of order";
case 0x34A9: return "Temporary failure";
case 0x34AA: return "Switching equipment congestion";
case 0x34AB: return "Access information discarded";
case 0x34AC: return "Requested circuit / channel not available";
case 0x34AF: return "Resources unavailable, unspecified";
case 0x34B1: return "Quality of service unavailable";
case 0x34B2: return "Requested facility not subscribed";
case 0x34B9: return "Bearer capability not authorized";
case 0x34BA: return "Bearer capability not presently available";
case 0x34BF: return "Service or option not available, unspecified";
case 0x34C1: return "Bearer capability not implemented";
case 0x34C2: return "Channel type not implemented";
case 0x34C5: return "Requested facility not implemented";
case 0x34C6: return "Only restricted digital information bearer capability is available";
case 0x34CF: return "Service or option not implemented, unspecified";
case 0x34D1: return "Invalid call reference value";
case 0x34D2: return "Identified channel does not exist";
case 0x34D3: return "A suspended call exists, but this call identity does not";
case 0x34D4: return "Call identity in use";
case 0x34D5: return "No call suspended";
case 0x34D6: return "Call having the requested call identity has been cleared";
case 0x34D8: return "Incompatible destination";
case 0x34DB: return "Invalid transit network selection";
case 0x34DF: return "Invalid message, unspecified";
case 0x34E0: return "Mandatory information element is missing";
case 0x34E1: return "Message type non-existent or not implemented";
case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
case 0x34E3: return "Information element non-existent or not implemented";
case 0x34E4: return "Invalid information element contents";
case 0x34E5: return "Message not compatible with call state";
case 0x34E6: return "Recovery on timer expiry";
case 0x34EF: return "Protocol error, unspecified";
case 0x34FF: return "Interworking, unspecified";
default: return "No additional information";
}
#endif
}
static void handle_controller(_cmsg *cmsg)
{

View File

@ -22,205 +22,6 @@
/* from CAPI2.0 DDK AVM Berlin GmbH */
#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
char *capi_info2str(u16 reason)
{
return "..";
}
#else
char *capi_info2str(u16 reason)
{
switch (reason) {
/*-- informative values (corresponding message was processed) -----*/
case 0x0001:
return "NCPI not supported by current protocol, NCPI ignored";
case 0x0002:
return "Flags not supported by current protocol, flags ignored";
case 0x0003:
return "Alert already sent by another application";
/*-- error information concerning CAPI_REGISTER -----*/
case 0x1001:
return "Too many applications";
case 0x1002:
return "Logical block size too small, must be at least 128 Bytes";
case 0x1003:
return "Buffer exceeds 64 kByte";
case 0x1004:
return "Message buffer size too small, must be at least 1024 Bytes";
case 0x1005:
return "Max. number of logical connections not supported";
case 0x1006:
return "Reserved";
case 0x1007:
return "The message could not be accepted because of an internal busy condition";
case 0x1008:
return "OS resource error (no memory ?)";
case 0x1009:
return "CAPI not installed";
case 0x100A:
return "Controller does not support external equipment";
case 0x100B:
return "Controller does only support external equipment";
/*-- error information concerning message exchange functions -----*/
case 0x1101:
return "Illegal application number";
case 0x1102:
return "Illegal command or subcommand or message length less than 12 bytes";
case 0x1103:
return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
case 0x1104:
return "Queue is empty";
case 0x1105:
return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
case 0x1106:
return "Unknown notification parameter";
case 0x1107:
return "The Message could not be accepted because of an internal busy condition";
case 0x1108:
return "OS Resource error (no memory ?)";
case 0x1109:
return "CAPI not installed";
case 0x110A:
return "Controller does not support external equipment";
case 0x110B:
return "Controller does only support external equipment";
/*-- error information concerning resource / coding problems -----*/
case 0x2001:
return "Message not supported in current state";
case 0x2002:
return "Illegal Controller / PLCI / NCCI";
case 0x2003:
return "Out of PLCI";
case 0x2004:
return "Out of NCCI";
case 0x2005:
return "Out of LISTEN";
case 0x2006:
return "Out of FAX resources (protocol T.30)";
case 0x2007:
return "Illegal message parameter coding";
/*-- error information concerning requested services -----*/
case 0x3001:
return "B1 protocol not supported";
case 0x3002:
return "B2 protocol not supported";
case 0x3003:
return "B3 protocol not supported";
case 0x3004:
return "B1 protocol parameter not supported";
case 0x3005:
return "B2 protocol parameter not supported";
case 0x3006:
return "B3 protocol parameter not supported";
case 0x3007:
return "B protocol combination not supported";
case 0x3008:
return "NCPI not supported";
case 0x3009:
return "CIP Value unknown";
case 0x300A:
return "Flags not supported (reserved bits)";
case 0x300B:
return "Facility not supported";
case 0x300C:
return "Data length not supported by current protocol";
case 0x300D:
return "Reset procedure not supported by current protocol";
/*-- informations about the clearing of a physical connection -----*/
case 0x3301:
return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
case 0x3302:
return "Protocol error layer 2";
case 0x3303:
return "Protocol error layer 3";
case 0x3304:
return "Another application got that call";
/*-- T.30 specific reasons -----*/
case 0x3311:
return "Connecting not successful (remote station is no FAX G3 machine)";
case 0x3312:
return "Connecting not successful (training error)";
case 0x3313:
return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
case 0x3314:
return "Disconnected during transfer (remote abort)";
case 0x3315:
return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
case 0x3316:
return "Disconnected during transfer (local tx data underrun)";
case 0x3317:
return "Disconnected during transfer (local rx data overflow)";
case 0x3318:
return "Disconnected during transfer (local abort)";
case 0x3319:
return "Illegal parameter coding (e.g. SFF coding error)";
/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
case 0x3481: return "Unallocated (unassigned) number";
case 0x3482: return "No route to specified transit network";
case 0x3483: return "No route to destination";
case 0x3486: return "Channel unacceptable";
case 0x3487:
return "Call awarded and being delivered in an established channel";
case 0x3490: return "Normal call clearing";
case 0x3491: return "User busy";
case 0x3492: return "No user responding";
case 0x3493: return "No answer from user (user alerted)";
case 0x3495: return "Call rejected";
case 0x3496: return "Number changed";
case 0x349A: return "Non-selected user clearing";
case 0x349B: return "Destination out of order";
case 0x349C: return "Invalid number format";
case 0x349D: return "Facility rejected";
case 0x349E: return "Response to STATUS ENQUIRY";
case 0x349F: return "Normal, unspecified";
case 0x34A2: return "No circuit / channel available";
case 0x34A6: return "Network out of order";
case 0x34A9: return "Temporary failure";
case 0x34AA: return "Switching equipment congestion";
case 0x34AB: return "Access information discarded";
case 0x34AC: return "Requested circuit / channel not available";
case 0x34AF: return "Resources unavailable, unspecified";
case 0x34B1: return "Quality of service unavailable";
case 0x34B2: return "Requested facility not subscribed";
case 0x34B9: return "Bearer capability not authorized";
case 0x34BA: return "Bearer capability not presently available";
case 0x34BF: return "Service or option not available, unspecified";
case 0x34C1: return "Bearer capability not implemented";
case 0x34C2: return "Channel type not implemented";
case 0x34C5: return "Requested facility not implemented";
case 0x34C6: return "Only restricted digital information bearer capability is available";
case 0x34CF: return "Service or option not implemented, unspecified";
case 0x34D1: return "Invalid call reference value";
case 0x34D2: return "Identified channel does not exist";
case 0x34D3: return "A suspended call exists, but this call identity does not";
case 0x34D4: return "Call identity in use";
case 0x34D5: return "No call suspended";
case 0x34D6: return "Call having the requested call identity has been cleared";
case 0x34D8: return "Incompatible destination";
case 0x34DB: return "Invalid transit network selection";
case 0x34DF: return "Invalid message, unspecified";
case 0x34E0: return "Mandatory information element is missing";
case 0x34E1: return "Message type non-existent or not implemented";
case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
case 0x34E3: return "Information element non-existent or not implemented";
case 0x34E4: return "Invalid information element contents";
case 0x34E5: return "Message not compatible with call state";
case 0x34E6: return "Recovery on timer expiry";
case 0x34EF: return "Protocol error, unspecified";
case 0x34FF: return "Interworking, unspecified";
default: return "No additional information";
}
}
#endif
typedef struct {
int typ;
size_t off;
@ -1073,4 +874,3 @@ EXPORT_SYMBOL(capi_cmsg_header);
EXPORT_SYMBOL(capi_cmd2str);
EXPORT_SYMBOL(capi_cmsg2str);
EXPORT_SYMBOL(capi_message2str);
EXPORT_SYMBOL(capi_info2str);

View File

@ -197,25 +197,6 @@ typedef struct _hfc4s8s_hw {
/***************************/
/* inline function defines */
/***************************/
#ifdef HISAX_HFC4S8S_PCIMEM /* inline functions memory mapped */
/* memory write and dummy IO read to avoid PCI byte merge problems */
#define Write_hfc8(a, b, c) {(*((volatile u_char *)(a->membase + b)) = c); inb(a->iobase + 4);}
/* memory write without dummy IO access for fifo data access */
#define fWrite_hfc8(a, b, c) (*((volatile u_char *)(a->membase + b)) = c)
#define Read_hfc8(a, b) (*((volatile u_char *)(a->membase + b)))
#define Write_hfc16(a, b, c) (*((volatile unsigned short *)(a->membase + b)) = c)
#define Read_hfc16(a, b) (*((volatile unsigned short *)(a->membase + b)))
#define Write_hfc32(a, b, c) (*((volatile unsigned long *)(a->membase + b)) = c)
#define Read_hfc32(a, b) (*((volatile unsigned long *)(a->membase + b)))
#define wait_busy(a) {while ((Read_hfc8(a, R_STATUS) & M_BUSY));}
#define PCI_ENA_MEMIO 0x03
#else
/* inline functions io mapped */
static inline void
SetRegAddr(hfc4s8s_hw *a, u_char b)
@ -306,8 +287,6 @@ wait_busy(hfc4s8s_hw *a)
#define PCI_ENA_REGIO 0x01
#endif /* HISAX_HFC4S8S_PCIMEM */
/******************************************************/
/* function to read critical counter registers that */
/* may be updated by the chip during read */
@ -724,26 +703,15 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
return;
} else {
/* read errornous D frame */
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1p->hw, A_FIFO_DATA0);
#endif
while (z1 >= 4) {
#ifdef HISAX_HFC4S8S_PCIMEM
Read_hfc32(l1p->hw, A_FIFO_DATA0);
#else
fRead_hfc32(l1p->hw);
#endif
z1 -= 4;
}
while (z1--)
#ifdef HISAX_HFC4S8S_PCIMEM
Read_hfc8(l1p->hw, A_FIFO_DATA0);
#else
fRead_hfc8(l1p->hw);
#endif
fRead_hfc8(l1p->hw);
Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1);
wait_busy(l1p->hw);
@ -753,27 +721,16 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
cp = skb->data;
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1p->hw, A_FIFO_DATA0);
#endif
while (z1 >= 4) {
#ifdef HISAX_HFC4S8S_PCIMEM
*((unsigned long *) cp) =
Read_hfc32(l1p->hw, A_FIFO_DATA0);
#else
*((unsigned long *) cp) = fRead_hfc32(l1p->hw);
#endif
cp += 4;
z1 -= 4;
}
while (z1--)
#ifdef HISAX_HFC4S8S_PCIMEM
*cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0);
#else
*cp++ = fRead_hfc8(l1p->hw);
#endif
*cp++ = fRead_hfc8(l1p->hw);
Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */
wait_busy(l1p->hw);
@ -859,28 +816,17 @@ rx_b_frame(struct hfc4s8s_btype *bch)
wait_busy(l1->hw);
return;
}
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1->hw, A_FIFO_DATA0);
#endif
while (z1 >= 4) {
#ifdef HISAX_HFC4S8S_PCIMEM
*((unsigned long *) bch->rx_ptr) =
Read_hfc32(l1->hw, A_FIFO_DATA0);
#else
*((unsigned long *) bch->rx_ptr) =
fRead_hfc32(l1->hw);
#endif
bch->rx_ptr += 4;
z1 -= 4;
}
while (z1--)
#ifdef HISAX_HFC4S8S_PCIMEM
*(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0);
#else
*(bch->rx_ptr++) = fRead_hfc8(l1->hw);
#endif
*(bch->rx_ptr++) = fRead_hfc8(l1->hw);
if (hdlc_complete) {
/* increment f counter */
@ -940,29 +886,17 @@ tx_d_frame(struct hfc4s8s_l1 *l1p)
if ((skb = skb_dequeue(&l1p->d_tx_queue))) {
cp = skb->data;
cnt = skb->len;
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1p->hw, A_FIFO_DATA0);
#endif
while (cnt >= 4) {
#ifdef HISAX_HFC4S8S_PCIMEM
fWrite_hfc32(l1p->hw, A_FIFO_DATA0,
*(unsigned long *) cp);
#else
SetRegAddr(l1p->hw, A_FIFO_DATA0);
fWrite_hfc32(l1p->hw, *(unsigned long *) cp);
#endif
cp += 4;
cnt -= 4;
}
#ifdef HISAX_HFC4S8S_PCIMEM
while (cnt--)
fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++);
#else
while (cnt--)
fWrite_hfc8(l1p->hw, *cp++);
#endif
l1p->tx_cnt = skb->truesize;
Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */
@ -1037,26 +971,15 @@ tx_b_frame(struct hfc4s8s_btype *bch)
cp = skb->data + bch->tx_cnt;
bch->tx_cnt += cnt;
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1->hw, A_FIFO_DATA0);
#endif
while (cnt >= 4) {
#ifdef HISAX_HFC4S8S_PCIMEM
fWrite_hfc32(l1->hw, A_FIFO_DATA0,
*(unsigned long *) cp);
#else
fWrite_hfc32(l1->hw, *(unsigned long *) cp);
#endif
cp += 4;
cnt -= 4;
}
while (cnt--)
#ifdef HISAX_HFC4S8S_PCIMEM
fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++);
#else
fWrite_hfc8(l1->hw, *cp++);
#endif
fWrite_hfc8(l1->hw, *cp++);
if (bch->tx_cnt >= skb->len) {
if (bch->mode == L1_MODE_HDLC) {
@ -1281,10 +1204,8 @@ hfc4s8s_interrupt(int intno, void *dev_id)
if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN))
return IRQ_NONE;
#ifndef HISAX_HFC4S8S_PCIMEM
/* read current selected regsister */
old_ioreg = GetRegAddr(hw);
#endif
/* Layer 1 State change */
hw->mr.r_irq_statech |=
@ -1292,9 +1213,7 @@ hfc4s8s_interrupt(int intno, void *dev_id)
if (!
(b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA)))
&& !hw->mr.r_irq_statech) {
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(hw, old_ioreg);
#endif
return IRQ_NONE;
}
@ -1322,9 +1241,7 @@ hfc4s8s_interrupt(int intno, void *dev_id)
/* queue the request to allow other cards to interrupt */
schedule_work(&hw->tqueue);
#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(hw, old_ioreg);
#endif
return IRQ_HANDLED;
} /* hfc4s8s_interrupt */
@ -1471,13 +1388,8 @@ static void
release_pci_ports(hfc4s8s_hw *hw)
{
pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
#ifdef HISAX_HFC4S8S_PCIMEM
if (hw->membase)
iounmap((void *) hw->membase);
#else
if (hw->iobase)
release_region(hw->iobase, 8);
#endif
}
/*****************************************/
@ -1486,11 +1398,7 @@ release_pci_ports(hfc4s8s_hw *hw)
static void
enable_pci_ports(hfc4s8s_hw *hw)
{
#ifdef HISAX_HFC4S8S_PCIMEM
pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
#else
pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO);
#endif
}
/*************************************/
@ -1561,15 +1469,9 @@ setup_instance(hfc4s8s_hw *hw)
hw->irq);
goto out;
}
#ifdef HISAX_HFC4S8S_PCIMEM
printk(KERN_INFO
"HFC-4S/8S: found PCI card at membase 0x%p, irq %d\n",
hw->hw_membase, hw->irq);
#else
printk(KERN_INFO
"HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n",
hw->iobase, hw->irq);
#endif
hfc_hardware_enable(hw, 1, 0);
@ -1614,17 +1516,12 @@ hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->irq = pdev->irq;
hw->iobase = pci_resource_start(pdev, 0);
#ifdef HISAX_HFC4S8S_PCIMEM
hw->hw_membase = (u_char *) pci_resource_start(pdev, 1);
hw->membase = ioremap((ulong) hw->hw_membase, 256);
#else
if (!request_region(hw->iobase, 8, hw->card_name)) {
printk(KERN_INFO
"HFC-4S/8S: failed to request address space at 0x%04x\n",
hw->iobase);
goto out;
}
#endif
pci_set_drvdata(pdev, hw);
err = setup_instance(hw);

View File

@ -634,7 +634,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_IPPP_FILTER
case PPPIOCSPASS:
{
struct sock_fprog fprog;
struct sock_fprog_kern fprog;
struct sock_filter *code;
int err, len = get_filter(argp, &code);
@ -653,7 +653,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
}
case PPPIOCSACTIVE:
{
struct sock_fprog fprog;
struct sock_fprog_kern fprog;
struct sock_filter *code;
int err, len = get_filter(argp, &code);

View File

@ -287,11 +287,9 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask,
p = frame;
/* restart timer */
if ((int)(hc->keep_tl.expires-jiffies) < 5 * HZ) {
del_timer(&hc->keep_tl);
hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE * HZ;
add_timer(&hc->keep_tl);
} else
if (time_before(hc->keep_tl.expires, jiffies + 5 * HZ))
mod_timer(&hc->keep_tl, jiffies + L1OIP_KEEPALIVE * HZ);
else
hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE * HZ;
if (debug & DEBUG_L1OIP_MSG)
@ -621,11 +619,9 @@ multiframe:
goto multiframe;
/* restart timer */
if ((int)(hc->timeout_tl.expires-jiffies) < 5 * HZ || !hc->timeout_on) {
if (time_before(hc->timeout_tl.expires, jiffies + 5 * HZ) || !hc->timeout_on) {
hc->timeout_on = 1;
del_timer(&hc->timeout_tl);
hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT * HZ;
add_timer(&hc->timeout_tl);
mod_timer(&hc->timeout_tl, jiffies + L1OIP_TIMEOUT * HZ);
} else /* only adjust timer */
hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT * HZ;

View File

@ -448,7 +448,6 @@ mmc_spi_command_send(struct mmc_spi_host *host,
{
struct scratch *data = host->data;
u8 *cp = data->status;
u32 arg = cmd->arg;
int status;
struct spi_transfer *t;
@ -465,14 +464,12 @@ mmc_spi_command_send(struct mmc_spi_host *host,
* We init the whole buffer to all-ones, which is what we need
* to write while we're reading (later) response data.
*/
memset(cp++, 0xff, sizeof(data->status));
memset(cp, 0xff, sizeof(data->status));
*cp++ = 0x40 | cmd->opcode;
*cp++ = (u8)(arg >> 24);
*cp++ = (u8)(arg >> 16);
*cp++ = (u8)(arg >> 8);
*cp++ = (u8)arg;
*cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01;
cp[1] = 0x40 | cmd->opcode;
put_unaligned_be32(cmd->arg, cp+2);
cp[6] = crc7_be(0, cp+1, 5) | 0x01;
cp += 7;
/* Then, read up to 13 bytes (while writing all-ones):
* - N(CR) (== 1..8) bytes of all-ones
@ -711,10 +708,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
* so we have to cope with this situation and check the response
* bit-by-bit. Arggh!!!
*/
pattern = scratch->status[0] << 24;
pattern |= scratch->status[1] << 16;
pattern |= scratch->status[2] << 8;
pattern |= scratch->status[3];
pattern = get_unaligned_be32(scratch->status);
/* First 3 bit of pattern are undefined */
pattern |= 0xE0000000;

View File

@ -157,7 +157,7 @@ static inline struct aggregator *__get_first_agg(struct port *port)
rcu_read_lock();
first_slave = bond_first_slave_rcu(bond);
agg = first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
agg = first_slave ? &(SLAVE_AD_INFO(first_slave)->aggregator) : NULL;
rcu_read_unlock();
return agg;
@ -192,7 +192,7 @@ static inline void __enable_port(struct port *port)
{
struct slave *slave = port->slave;
if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
if ((slave->link == BOND_LINK_UP) && bond_slave_is_up(slave))
bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
}
@ -241,7 +241,7 @@ static inline int __check_agg_selection_timer(struct port *port)
*/
static inline void __get_state_machine_lock(struct port *port)
{
spin_lock_bh(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
spin_lock_bh(&(SLAVE_AD_INFO(port->slave)->state_machine_lock));
}
/**
@ -250,7 +250,7 @@ static inline void __get_state_machine_lock(struct port *port)
*/
static inline void __release_state_machine_lock(struct port *port)
{
spin_unlock_bh(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
spin_unlock_bh(&(SLAVE_AD_INFO(port->slave)->state_machine_lock));
}
/**
@ -350,7 +350,7 @@ static u8 __get_duplex(struct port *port)
static inline void __initialize_port_locks(struct slave *slave)
{
/* make sure it isn't called twice */
spin_lock_init(&(SLAVE_AD_INFO(slave).state_machine_lock));
spin_lock_init(&(SLAVE_AD_INFO(slave)->state_machine_lock));
}
/* Conversions */
@ -688,8 +688,8 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator)
struct slave *slave;
bond_for_each_slave_rcu(bond, slave, iter)
if (SLAVE_AD_INFO(slave).aggregator.is_active)
return &(SLAVE_AD_INFO(slave).aggregator);
if (SLAVE_AD_INFO(slave)->aggregator.is_active)
return &(SLAVE_AD_INFO(slave)->aggregator);
return NULL;
}
@ -1293,7 +1293,7 @@ static void ad_port_selection_logic(struct port *port)
}
/* search on all aggregators for a suitable aggregator for this port */
bond_for_each_slave(bond, slave, iter) {
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
aggregator = &(SLAVE_AD_INFO(slave)->aggregator);
/* keep a free aggregator for later use(if needed) */
if (!aggregator->lag_ports) {
@ -1504,7 +1504,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
best = (active && agg_device_up(active)) ? active : NULL;
bond_for_each_slave_rcu(bond, slave, iter) {
agg = &(SLAVE_AD_INFO(slave).aggregator);
agg = &(SLAVE_AD_INFO(slave)->aggregator);
agg->is_active = 0;
@ -1549,7 +1549,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
best->slave ? best->slave->dev->name : "NULL");
bond_for_each_slave_rcu(bond, slave, iter) {
agg = &(SLAVE_AD_INFO(slave).aggregator);
agg = &(SLAVE_AD_INFO(slave)->aggregator);
pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
agg->aggregator_identifier, agg->num_of_ports,
@ -1840,16 +1840,16 @@ void bond_3ad_bind_slave(struct slave *slave)
struct aggregator *aggregator;
/* check that the slave has not been initialized yet. */
if (SLAVE_AD_INFO(slave).port.slave != slave) {
if (SLAVE_AD_INFO(slave)->port.slave != slave) {
/* port initialization */
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
ad_initialize_port(port, bond->params.lacp_fast);
__initialize_port_locks(slave);
port->slave = slave;
port->actor_port_number = SLAVE_AD_INFO(slave).id;
port->actor_port_number = SLAVE_AD_INFO(slave)->id;
/* key is determined according to the link speed, duplex and user key(which
* is yet not supported)
*/
@ -1874,7 +1874,7 @@ void bond_3ad_bind_slave(struct slave *slave)
__disable_port(port);
/* aggregator initialization */
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
aggregator = &(SLAVE_AD_INFO(slave)->aggregator);
ad_initialize_agg(aggregator);
@ -1903,8 +1903,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
struct slave *slave_iter;
struct list_head *iter;
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
port = &(SLAVE_AD_INFO(slave).port);
aggregator = &(SLAVE_AD_INFO(slave)->aggregator);
port = &(SLAVE_AD_INFO(slave)->port);
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
@ -1932,7 +1932,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
(aggregator->lag_ports->next_port_in_aggregator)) {
/* find new aggregator for the related port(s) */
bond_for_each_slave(bond, slave_iter, iter) {
new_aggregator = &(SLAVE_AD_INFO(slave_iter).aggregator);
new_aggregator = &(SLAVE_AD_INFO(slave_iter)->aggregator);
/* if the new aggregator is empty, or it is
* connected to our port only
*/
@ -2010,7 +2010,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
/* find the aggregator that this port is connected to */
bond_for_each_slave(bond, slave_iter, iter) {
temp_aggregator = &(SLAVE_AD_INFO(slave_iter).aggregator);
temp_aggregator = &(SLAVE_AD_INFO(slave_iter)->aggregator);
prev_port = NULL;
/* search the port in the aggregator's related ports */
for (temp_port = temp_aggregator->lag_ports; temp_port;
@ -2076,7 +2076,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
if (BOND_AD_INFO(bond).agg_select_timer &&
!(--BOND_AD_INFO(bond).agg_select_timer)) {
slave = bond_first_slave_rcu(bond);
port = slave ? &(SLAVE_AD_INFO(slave).port) : NULL;
port = slave ? &(SLAVE_AD_INFO(slave)->port) : NULL;
/* select the active aggregator for the bond */
if (port) {
@ -2094,7 +2094,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
/* for each port run the state machines */
bond_for_each_slave_rcu(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
if (!port->slave) {
pr_warn_ratelimited("%s: Warning: Found an uninitialized port\n",
bond->dev->name);
@ -2155,7 +2155,7 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
if (length >= sizeof(struct lacpdu)) {
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
if (!port->slave) {
pr_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n",
@ -2212,7 +2212,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
{
struct port *port;
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
@ -2245,7 +2245,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
{
struct port *port;
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
@ -2279,7 +2279,7 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
{
struct port *port;
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
@ -2347,7 +2347,7 @@ int bond_3ad_set_carrier(struct bonding *bond)
ret = 0;
goto out;
}
active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator));
active = __get_active_agg(&(SLAVE_AD_INFO(first_slave)->aggregator));
if (active) {
/* are enough slaves available to consider link up? */
if (active->num_of_ports < bond->params.min_links) {
@ -2384,7 +2384,7 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
struct port *port;
bond_for_each_slave_rcu(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
if (port->aggregator && port->aggregator->is_active) {
aggregator = port->aggregator;
break;
@ -2440,22 +2440,22 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
goto err_free;
}
slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg);
slave_agg_no = bond_xmit_hash(bond, skb) % slaves_in_agg;
first_ok_slave = NULL;
bond_for_each_slave_rcu(bond, slave, iter) {
agg = SLAVE_AD_INFO(slave).port.aggregator;
agg = SLAVE_AD_INFO(slave)->port.aggregator;
if (!agg || agg->aggregator_identifier != agg_id)
continue;
if (slave_agg_no >= 0) {
if (!first_ok_slave && SLAVE_IS_OK(slave))
if (!first_ok_slave && bond_slave_can_tx(slave))
first_ok_slave = slave;
slave_agg_no--;
continue;
}
if (SLAVE_IS_OK(slave)) {
if (bond_slave_can_tx(slave)) {
bond_dev_queue_xmit(bond, skb, slave->dev);
goto out;
}
@ -2522,7 +2522,7 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
lacp_fast = bond->params.lacp_fast;
bond_for_each_slave(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave).port);
port = &(SLAVE_AD_INFO(slave)->port);
__get_state_machine_lock(port);
if (lacp_fast)
port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;

View File

@ -229,7 +229,7 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
/* Find the slave with the largest gap */
bond_for_each_slave_rcu(bond, slave, iter) {
if (SLAVE_IS_OK(slave)) {
if (bond_slave_can_tx(slave)) {
long long gap = compute_gap(slave);
if (max_gap < gap) {
@ -384,7 +384,7 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
bool found = false;
bond_for_each_slave(bond, slave, iter) {
if (!SLAVE_IS_OK(slave))
if (!bond_slave_can_tx(slave))
continue;
if (!found) {
if (!before || before->speed < slave->speed)
@ -417,7 +417,7 @@ static struct slave *__rlb_next_rx_slave(struct bonding *bond)
bool found = false;
bond_for_each_slave_rcu(bond, slave, iter) {
if (!SLAVE_IS_OK(slave))
if (!bond_slave_can_tx(slave))
continue;
if (!found) {
if (!before || before->speed < slave->speed)
@ -755,7 +755,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
/* Don't modify or load balance ARPs that do not originate locally
* (e.g.,arrive via a bridge).
*/
if (!bond_slave_has_mac_rcu(bond, arp->mac_src))
if (!bond_slave_has_mac_rx(bond, arp->mac_src))
return NULL;
if (arp->op_code == htons(ARPOP_REPLY)) {
@ -1039,11 +1039,14 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
struct bonding *bond = bond_get_bond_by_slave(slave);
struct net_device *upper;
struct list_head *iter;
struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP];
/* send untagged */
alb_send_lp_vid(slave, mac_addr, 0, 0);
/* loop through vlans and send one packet for each */
/* loop through all devices and see if we need to send a packet
* for that device.
*/
rcu_read_lock();
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0) {
@ -1059,6 +1062,16 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
vlan_dev_vlan_id(upper));
}
}
/* If this is a macvlan device, then only send updates
* when strict_match is turned off.
*/
if (netif_is_macvlan(upper) && !strict_match) {
memset(tags, 0, sizeof(tags));
bond_verify_device_path(bond->dev, upper, tags);
alb_send_lp_vid(slave, upper->dev_addr,
tags[0].vlan_proto, tags[0].vlan_id);
}
}
rcu_read_unlock();
}
@ -1068,7 +1081,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
struct net_device *dev = slave->dev;
struct sockaddr s_addr;
if (slave->bond->params.mode == BOND_MODE_TLB) {
if (BOND_MODE(slave->bond) == BOND_MODE_TLB) {
memcpy(dev->dev_addr, addr, dev->addr_len);
return 0;
}
@ -1111,13 +1124,13 @@ static void alb_swap_mac_addr(struct slave *slave1, struct slave *slave2)
static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
struct slave *slave2)
{
int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
int slaves_state_differ = (bond_slave_can_tx(slave1) != bond_slave_can_tx(slave2));
struct slave *disabled_slave = NULL;
ASSERT_RTNL();
/* fasten the change in the switch */
if (SLAVE_IS_OK(slave1)) {
if (bond_slave_can_tx(slave1)) {
alb_send_learning_packets(slave1, slave1->dev->dev_addr, false);
if (bond->alb_info.rlb_enabled) {
/* inform the clients that the mac address
@ -1129,7 +1142,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
disabled_slave = slave1;
}
if (SLAVE_IS_OK(slave2)) {
if (bond_slave_can_tx(slave2)) {
alb_send_learning_packets(slave2, slave2->dev->dev_addr, false);
if (bond->alb_info.rlb_enabled) {
/* inform the clients that the mac address
@ -1358,6 +1371,77 @@ void bond_alb_deinitialize(struct bonding *bond)
rlb_deinitialize(bond);
}
static int bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
struct slave *tx_slave)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct ethhdr *eth_data = eth_hdr(skb);
if (!tx_slave) {
/* unbalanced or unassigned, send through primary */
tx_slave = rcu_dereference(bond->curr_active_slave);
if (bond->params.tlb_dynamic_lb)
bond_info->unbalanced_load += skb->len;
}
if (tx_slave && bond_slave_can_tx(tx_slave)) {
if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
ether_addr_copy(eth_data->h_source,
tx_slave->dev->dev_addr);
}
bond_dev_queue_xmit(bond, skb, tx_slave->dev);
goto out;
}
if (tx_slave && bond->params.tlb_dynamic_lb) {
_lock_tx_hashtbl(bond);
__tlb_clear_slave(bond, tx_slave, 0);
_unlock_tx_hashtbl(bond);
}
/* no suitable interface, frame not sent */
dev_kfree_skb_any(skb);
out:
return NETDEV_TX_OK;
}
int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
struct ethhdr *eth_data;
struct slave *tx_slave = NULL;
u32 hash_index;
skb_reset_mac_header(skb);
eth_data = eth_hdr(skb);
/* Do not TX balance any multicast or broadcast */
if (!is_multicast_ether_addr(eth_data->h_dest)) {
switch (skb->protocol) {
case htons(ETH_P_IP):
case htons(ETH_P_IPX):
/* In case of IPX, it will falback to L2 hash */
case htons(ETH_P_IPV6):
hash_index = bond_xmit_hash(bond, skb);
if (bond->params.tlb_dynamic_lb) {
tx_slave = tlb_choose_channel(bond,
hash_index & 0xFF,
skb->len);
} else {
struct list_head *iter;
int idx = hash_index % bond->slave_cnt;
bond_for_each_slave_rcu(bond, tx_slave, iter)
if (--idx < 0)
break;
}
break;
}
}
return bond_do_alb_xmit(skb, bond, tx_slave);
}
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
@ -1366,7 +1450,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
struct slave *tx_slave = NULL;
static const __be32 ip_bcast = htonl(0xffffffff);
int hash_size = 0;
int do_tx_balance = 1;
bool do_tx_balance = true;
u32 hash_index = 0;
const u8 *hash_start = NULL;
struct ipv6hdr *ip6hdr;
@ -1381,7 +1465,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast) ||
(iph->daddr == ip_bcast) ||
(iph->protocol == IPPROTO_IGMP)) {
do_tx_balance = 0;
do_tx_balance = false;
break;
}
hash_start = (char *)&(iph->daddr);
@ -1393,7 +1477,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
* that here just in case.
*/
if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast)) {
do_tx_balance = 0;
do_tx_balance = false;
break;
}
@ -1401,7 +1485,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
* broadcasts in IPv4.
*/
if (ether_addr_equal_64bits(eth_data->h_dest, mac_v6_allmcast)) {
do_tx_balance = 0;
do_tx_balance = false;
break;
}
@ -1411,7 +1495,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
*/
ip6hdr = ipv6_hdr(skb);
if (ipv6_addr_any(&ip6hdr->saddr)) {
do_tx_balance = 0;
do_tx_balance = false;
break;
}
@ -1421,7 +1505,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
case ETH_P_IPX:
if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
/* something is wrong with this packet */
do_tx_balance = 0;
do_tx_balance = false;
break;
}
@ -1430,7 +1514,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
* this family since it has an "ARP" like
* mechanism
*/
do_tx_balance = 0;
do_tx_balance = false;
break;
}
@ -1438,12 +1522,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
hash_size = ETH_ALEN;
break;
case ETH_P_ARP:
do_tx_balance = 0;
do_tx_balance = false;
if (bond_info->rlb_enabled)
tx_slave = rlb_arp_xmit(skb, bond);
break;
default:
do_tx_balance = 0;
do_tx_balance = false;
break;
}
@ -1452,32 +1536,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
tx_slave = tlb_choose_channel(bond, hash_index, skb->len);
}
if (!tx_slave) {
/* unbalanced or unassigned, send through primary */
tx_slave = rcu_dereference(bond->curr_active_slave);
bond_info->unbalanced_load += skb->len;
}
if (tx_slave && SLAVE_IS_OK(tx_slave)) {
if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
ether_addr_copy(eth_data->h_source,
tx_slave->dev->dev_addr);
}
bond_dev_queue_xmit(bond, skb, tx_slave->dev);
goto out;
}
if (tx_slave) {
_lock_tx_hashtbl(bond);
__tlb_clear_slave(bond, tx_slave, 0);
_unlock_tx_hashtbl(bond);
}
/* no suitable interface, frame not sent */
dev_kfree_skb_any(skb);
out:
return NETDEV_TX_OK;
return bond_do_alb_xmit(skb, bond, tx_slave);
}
void bond_alb_monitor(struct work_struct *work)
@ -1514,8 +1573,10 @@ void bond_alb_monitor(struct work_struct *work)
/* If updating current_active, use all currently
* user mac addreses (!strict_match). Otherwise, only
* use mac of the slave device.
* In RLB mode, we always use strict matches.
*/
strict_match = (slave != bond->curr_active_slave);
strict_match = (slave != bond->curr_active_slave ||
bond_info->rlb_enabled);
alb_send_learning_packets(slave, slave->dev->dev_addr,
strict_match);
}
@ -1719,7 +1780,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
/* in TLB mode, the slave might flip down/up with the old dev_addr,
* and thus filter bond->dev_addr's packets, so force bond's mac
*/
if (bond->params.mode == BOND_MODE_TLB) {
if (BOND_MODE(bond) == BOND_MODE_TLB) {
struct sockaddr sa;
u8 tmp_addr[ETH_ALEN];

View File

@ -175,6 +175,7 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave);
void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
void bond_alb_monitor(struct work_struct *);
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);

View File

@ -23,7 +23,7 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
struct rlb_client_info *client_info;
u32 hash_index;
if (bond->params.mode != BOND_MODE_ALB)
if (BOND_MODE(bond) != BOND_MODE_ALB)
return 0;
seq_printf(m, "SourceIP DestinationIP "

View File

@ -343,7 +343,7 @@ static int bond_set_carrier(struct bonding *bond)
if (!bond_has_slaves(bond))
goto down;
if (bond->params.mode == BOND_MODE_8023AD)
if (BOND_MODE(bond) == BOND_MODE_8023AD)
return bond_3ad_set_carrier(bond);
bond_for_each_slave(bond, slave, iter) {
@ -497,7 +497,7 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
struct list_head *iter;
int err = 0;
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
/* write lock already acquired */
if (bond->curr_active_slave) {
err = dev_set_promiscuity(bond->curr_active_slave->dev,
@ -523,7 +523,7 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
struct list_head *iter;
int err = 0;
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
/* write lock already acquired */
if (bond->curr_active_slave) {
err = dev_set_allmulti(bond->curr_active_slave->dev,
@ -574,7 +574,7 @@ static void bond_hw_addr_flush(struct net_device *bond_dev,
dev_uc_unsync(slave_dev, bond_dev);
dev_mc_unsync(slave_dev, bond_dev);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
/* del lacpdu mc addr from mc list */
u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
@ -585,8 +585,8 @@ static void bond_hw_addr_flush(struct net_device *bond_dev,
/*--------------------------- Active slave change ---------------------------*/
/* Update the hardware address list and promisc/allmulti for the new and
* old active slaves (if any). Modes that are !USES_PRIMARY keep all
* slaves up date at all times; only the USES_PRIMARY modes need to call
* old active slaves (if any). Modes that are not using primary keep all
* slaves up date at all times; only the modes that use primary need to call
* this function to swap these settings during a failover.
*/
static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
@ -747,7 +747,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
bond_for_each_slave(bond, slave, iter) {
if (slave->link == BOND_LINK_UP)
return slave;
if (slave->link == BOND_LINK_BACK && IS_UP(slave->dev) &&
if (slave->link == BOND_LINK_BACK && bond_slave_is_up(slave) &&
slave->delay < mintime) {
mintime = slave->delay;
bestslave = slave;
@ -801,7 +801,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
new_active->last_link_up = jiffies;
if (new_active->link == BOND_LINK_BACK) {
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
pr_info("%s: making interface %s the new active one %d ms earlier\n",
bond->dev->name, new_active->dev->name,
(bond->params.updelay - new_active->delay) * bond->params.miimon);
@ -810,20 +810,20 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
new_active->delay = 0;
new_active->link = BOND_LINK_UP;
if (bond->params.mode == BOND_MODE_8023AD)
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
if (bond_is_lb(bond))
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
} else {
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
pr_info("%s: making interface %s the new active one\n",
bond->dev->name, new_active->dev->name);
}
}
}
if (USES_PRIMARY(bond->params.mode))
if (bond_uses_primary(bond))
bond_hw_addr_swap(bond, new_active, old_active);
if (bond_is_lb(bond)) {
@ -838,7 +838,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
rcu_assign_pointer(bond->curr_active_slave, new_active);
}
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) {
if (old_active)
bond_set_slave_inactive_flags(old_active,
BOND_SLAVE_NOTIFY_NOW);
@ -876,8 +876,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
* resend only if bond is brought up with the affected
* bonding modes and the retransmission is enabled */
if (netif_running(bond->dev) && (bond->params.resend_igmp > 0) &&
((USES_PRIMARY(bond->params.mode) && new_active) ||
bond->params.mode == BOND_MODE_ROUNDROBIN)) {
((bond_uses_primary(bond) && new_active) ||
BOND_MODE(bond) == BOND_MODE_ROUNDROBIN)) {
bond->igmp_retrans = bond->params.resend_igmp;
queue_delayed_work(bond->wq, &bond->mcast_work, 1);
}
@ -958,7 +958,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
struct slave *slave;
bond_for_each_slave(bond, slave, iter)
if (IS_UP(slave->dev))
if (bond_slave_is_up(slave))
slave_disable_netpoll(slave);
}
@ -1038,6 +1038,7 @@ static void bond_compute_features(struct bonding *bond)
if (!bond_has_slaves(bond))
goto done;
vlan_features &= NETIF_F_ALL_FOR_ALL;
bond_for_each_slave(bond, slave, iter) {
vlan_features = netdev_increment_features(vlan_features,
@ -1084,7 +1085,7 @@ static bool bond_should_deliver_exact_match(struct sk_buff *skb,
struct bonding *bond)
{
if (bond_is_slave_inactive(slave)) {
if (bond->params.mode == BOND_MODE_ALB &&
if (BOND_MODE(bond) == BOND_MODE_ALB &&
skb->pkt_type != PACKET_BROADCAST &&
skb->pkt_type != PACKET_MULTICAST)
return false;
@ -1126,7 +1127,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
skb->dev = bond->dev;
if (bond->params.mode == BOND_MODE_ALB &&
if (BOND_MODE(bond) == BOND_MODE_ALB &&
bond->dev->priv_flags & IFF_BRIDGE_PORT &&
skb->pkt_type == PACKET_HOST) {
@ -1163,6 +1164,35 @@ static void bond_upper_dev_unlink(struct net_device *bond_dev,
rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE, GFP_KERNEL);
}
static struct slave *bond_alloc_slave(struct bonding *bond)
{
struct slave *slave = NULL;
slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!slave)
return NULL;
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
SLAVE_AD_INFO(slave) = kzalloc(sizeof(struct ad_slave_info),
GFP_KERNEL);
if (!SLAVE_AD_INFO(slave)) {
kfree(slave);
return NULL;
}
}
return slave;
}
static void bond_free_slave(struct slave *slave)
{
struct bonding *bond = bond_get_bond_by_slave(slave);
if (BOND_MODE(bond) == BOND_MODE_8023AD)
kfree(SLAVE_AD_INFO(slave));
kfree(slave);
}
/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
@ -1269,7 +1299,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
if (!bond_has_slaves(bond)) {
pr_warn("%s: Warning: The first slave device specified does not support setting the MAC address\n",
bond_dev->name);
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) {
bond->params.fail_over_mac = BOND_FOM_ACTIVE;
pr_warn("%s: Setting fail_over_mac to active for active-backup mode\n",
bond_dev->name);
@ -1290,11 +1320,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond->dev->addr_assign_type == NET_ADDR_RANDOM)
bond_set_dev_addr(bond->dev, slave_dev);
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
new_slave = bond_alloc_slave(bond);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
new_slave->bond = bond;
new_slave->dev = slave_dev;
/*
* Set the new_slave's queue_id to be zero. Queue ID mapping
* is set via sysfs or module option if desired.
@ -1317,7 +1350,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
ether_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr);
if (!bond->params.fail_over_mac ||
bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
/*
* Set slave to master's mac address. The application already
* set the master's mac address to that of the first slave
@ -1338,8 +1371,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_restore_mac;
}
new_slave->bond = bond;
new_slave->dev = slave_dev;
slave_dev->priv_flags |= IFF_BONDING;
if (bond_is_lb(bond)) {
@ -1351,10 +1382,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_close;
}
/* If the mode USES_PRIMARY, then the following is handled by
/* If the mode uses primary, then the following is handled by
* bond_change_active_slave().
*/
if (!USES_PRIMARY(bond->params.mode)) {
if (!bond_uses_primary(bond)) {
/* set promiscuity level to new slave */
if (bond_dev->flags & IFF_PROMISC) {
res = dev_set_promiscuity(slave_dev, 1);
@ -1377,7 +1408,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
netif_addr_unlock_bh(bond_dev);
}
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
/* add lacpdu mc addr to mc list */
u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
@ -1450,7 +1481,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
new_slave->link == BOND_LINK_DOWN ? "DOWN" :
(new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
if (bond_uses_primary(bond) && bond->params.primary[0]) {
/* if there is a primary slave, remember it */
if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
bond->primary_slave = new_slave;
@ -1458,7 +1489,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
switch (bond->params.mode) {
switch (BOND_MODE(bond)) {
case BOND_MODE_ACTIVEBACKUP:
bond_set_slave_inactive_flags(new_slave,
BOND_SLAVE_NOTIFY_NOW);
@ -1471,14 +1502,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
/* if this is the first slave */
if (!prev_slave) {
SLAVE_AD_INFO(new_slave).id = 1;
SLAVE_AD_INFO(new_slave)->id = 1;
/* Initialize AD with the number of times that the AD timer is called in 1 second
* can be called only after the mac address of the bond is set
*/
bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL);
} else {
SLAVE_AD_INFO(new_slave).id =
SLAVE_AD_INFO(prev_slave).id + 1;
SLAVE_AD_INFO(new_slave)->id =
SLAVE_AD_INFO(prev_slave)->id + 1;
}
bond_3ad_bind_slave(new_slave);
@ -1539,7 +1570,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_compute_features(bond);
bond_set_carrier(bond);
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
@ -1563,7 +1594,7 @@ err_unregister:
netdev_rx_handler_unregister(slave_dev);
err_detach:
if (!USES_PRIMARY(bond->params.mode))
if (!bond_uses_primary(bond))
bond_hw_addr_flush(bond_dev, slave_dev);
vlan_vids_del_by_dev(slave_dev, bond_dev);
@ -1585,7 +1616,7 @@ err_close:
err_restore_mac:
if (!bond->params.fail_over_mac ||
bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
/* XXX TODO - fom follow mode needs to change master's
* MAC if this slave's MAC is in use by the bond, or at
* least print a warning.
@ -1599,7 +1630,7 @@ err_restore_mtu:
dev_set_mtu(slave_dev, new_slave->original_mtu);
err_free:
kfree(new_slave);
bond_free_slave(new_slave);
err_undo_flags:
/* Enslave of first slave has failed and we need to fix master's mac */
@ -1661,7 +1692,7 @@ static int __bond_release_one(struct net_device *bond_dev,
write_lock_bh(&bond->lock);
/* Inform AD package of unbinding of slave. */
if (bond->params.mode == BOND_MODE_8023AD)
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_unbind_slave(slave);
write_unlock_bh(&bond->lock);
@ -1676,7 +1707,7 @@ static int __bond_release_one(struct net_device *bond_dev,
bond->current_arp_slave = NULL;
if (!all && (!bond->params.fail_over_mac ||
bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) {
if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) &&
bond_has_slaves(bond))
pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n",
@ -1748,10 +1779,10 @@ static int __bond_release_one(struct net_device *bond_dev,
/* must do this from outside any spinlocks */
vlan_vids_del_by_dev(slave_dev, bond_dev);
/* If the mode USES_PRIMARY, then this cases was handled above by
/* If the mode uses primary, then this cases was handled above by
* bond_change_active_slave(..., NULL)
*/
if (!USES_PRIMARY(bond->params.mode)) {
if (!bond_uses_primary(bond)) {
/* unset promiscuity level from slave
* NOTE: The NETDEV_CHANGEADDR call above may change the value
* of the IFF_PROMISC flag in the bond_dev, but we need the
@ -1775,7 +1806,7 @@ static int __bond_release_one(struct net_device *bond_dev,
dev_close(slave_dev);
if (bond->params.fail_over_mac != BOND_FOM_ACTIVE ||
bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
/* restore original ("permanent") mac address */
ether_addr_copy(addr.sa_data, slave->perm_hwaddr);
addr.sa_family = slave_dev->type;
@ -1786,7 +1817,7 @@ static int __bond_release_one(struct net_device *bond_dev,
slave_dev->priv_flags &= ~IFF_BONDING;
kfree(slave);
bond_free_slave(slave);
return 0; /* deletion OK */
}
@ -1821,7 +1852,7 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
{
struct bonding *bond = netdev_priv(bond_dev);
info->bond_mode = bond->params.mode;
info->bond_mode = BOND_MODE(bond);
info->miimon = bond->params.miimon;
info->num_slaves = bond->slave_cnt;
@ -1877,7 +1908,7 @@ static int bond_miimon_inspect(struct bonding *bond)
if (slave->delay) {
pr_info("%s: link status down for %sinterface %s, disabling it in %d ms\n",
bond->dev->name,
(bond->params.mode ==
(BOND_MODE(bond) ==
BOND_MODE_ACTIVEBACKUP) ?
(bond_is_active_slave(slave) ?
"active " : "backup ") : "",
@ -1968,10 +1999,10 @@ static void bond_miimon_commit(struct bonding *bond)
slave->link = BOND_LINK_UP;
slave->last_link_up = jiffies;
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
/* prevent it from being the active one */
bond_set_backup_slave(slave);
} else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
} else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
/* make it immediately active */
bond_set_active_slave(slave);
} else if (slave != bond->primary_slave) {
@ -1985,7 +2016,7 @@ static void bond_miimon_commit(struct bonding *bond)
slave->duplex ? "full" : "half");
/* notify ad that the link status has changed */
if (bond->params.mode == BOND_MODE_8023AD)
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_handle_link_change(slave, BOND_LINK_UP);
if (bond_is_lb(bond))
@ -2004,15 +2035,15 @@ static void bond_miimon_commit(struct bonding *bond)
slave->link = BOND_LINK_DOWN;
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
bond->params.mode == BOND_MODE_8023AD)
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_8023AD)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
pr_info("%s: link status definitely down for interface %s, disabling it\n",
bond->dev->name, slave->dev->name);
if (bond->params.mode == BOND_MODE_8023AD)
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_handle_link_change(slave,
BOND_LINK_DOWN);
@ -2175,9 +2206,9 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
* When the path is validated, collect any vlan information in the
* path.
*/
static bool bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
struct bond_vlan_tag *tags)
bool bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
struct bond_vlan_tag *tags)
{
struct net_device *upper;
struct list_head *iter;
@ -2287,8 +2318,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
if (!slave_do_arp_validate(bond, slave)) {
if ((slave_do_arp_validate_only(bond, slave) && is_arp) ||
!slave_do_arp_validate_only(bond, slave))
if ((slave_do_arp_validate_only(bond) && is_arp) ||
!slave_do_arp_validate_only(bond))
slave->last_rx = jiffies;
return RX_HANDLER_ANOTHER;
} else if (!is_arp) {
@ -2456,7 +2487,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
* do - all replies will be rx'ed on same link causing slaves
* to be unstable during low/no traffic periods
*/
if (IS_UP(slave->dev))
if (bond_slave_is_up(slave))
bond_arp_send_all(bond, slave);
}
@ -2678,10 +2709,10 @@ static bool bond_ab_arp_probe(struct bonding *bond)
bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
bond_for_each_slave_rcu(bond, slave, iter) {
if (!found && !before && IS_UP(slave->dev))
if (!found && !before && bond_slave_is_up(slave))
before = slave;
if (found && !new_slave && IS_UP(slave->dev))
if (found && !new_slave && bond_slave_is_up(slave))
new_slave = slave;
/* if the link state is up at this point, we
* mark it down - this can happen if we have
@ -2690,7 +2721,7 @@ static bool bond_ab_arp_probe(struct bonding *bond)
* one the current slave so it is still marked
* up when it is actually down
*/
if (!IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) {
slave->link = BOND_LINK_DOWN;
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
@ -2853,7 +2884,7 @@ static int bond_slave_netdev_event(unsigned long event,
bond_update_speed_duplex(slave);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
if (old_speed != slave->speed)
bond_3ad_adapter_speed_changed(slave);
if (old_duplex != slave->duplex)
@ -2881,7 +2912,7 @@ static int bond_slave_netdev_event(unsigned long event,
break;
case NETDEV_CHANGENAME:
/* we don't care if we don't have primary set */
if (!USES_PRIMARY(bond->params.mode) ||
if (!bond_uses_primary(bond) ||
!bond->params.primary[0])
break;
@ -3011,20 +3042,18 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
* bond_xmit_hash - generate a hash value based on the xmit policy
* @bond: bonding device
* @skb: buffer to use for headers
* @count: modulo value
*
* This function will extract the necessary headers from the skb buffer and use
* them to generate a hash based on the xmit_policy set in the bonding device
* which will be reduced modulo count before returning.
*/
int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count)
u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
{
struct flow_keys flow;
u32 hash;
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 ||
!bond_flow_dissect(bond, skb, &flow))
return bond_eth_hash(skb) % count;
return bond_eth_hash(skb);
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 ||
bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23)
@ -3035,7 +3064,7 @@ int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count)
hash ^= (hash >> 16);
hash ^= (hash >> 8);
return hash % count;
return hash;
}
/*-------------------------- Device entry points ----------------------------*/
@ -3046,7 +3075,7 @@ static void bond_work_init_all(struct bonding *bond)
bond_resend_igmp_join_requests_delayed);
INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
INIT_DELAYED_WORK(&bond->arp_work, bond_activebackup_arp_mon);
else
INIT_DELAYED_WORK(&bond->arp_work, bond_loadbalance_arp_mon);
@ -3073,7 +3102,7 @@ static int bond_open(struct net_device *bond_dev)
if (bond_has_slaves(bond)) {
read_lock(&bond->curr_slave_lock);
bond_for_each_slave(bond, slave, iter) {
if (USES_PRIMARY(bond->params.mode)
if (bond_uses_primary(bond)
&& (slave != bond->curr_active_slave)) {
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
@ -3092,9 +3121,10 @@ static int bond_open(struct net_device *bond_dev)
/* bond_alb_initialize must be called before the timer
* is started.
*/
if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB)))
if (bond_alb_initialize(bond, (BOND_MODE(bond) == BOND_MODE_ALB)))
return -ENOMEM;
queue_delayed_work(bond->wq, &bond->alb_work, 0);
if (bond->params.tlb_dynamic_lb)
queue_delayed_work(bond->wq, &bond->alb_work, 0);
}
if (bond->params.miimon) /* link check interval, in milliseconds. */
@ -3105,7 +3135,7 @@ static int bond_open(struct net_device *bond_dev)
bond->recv_probe = bond_arp_rcv;
}
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
bond->recv_probe = bond_3ad_lacpdu_recv;
@ -3310,7 +3340,7 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
rcu_read_lock();
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
slave = rcu_dereference(bond->curr_active_slave);
if (slave) {
dev_uc_sync(slave->dev, bond_dev);
@ -3464,7 +3494,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
struct list_head *iter;
int res = 0;
if (bond->params.mode == BOND_MODE_ALB)
if (BOND_MODE(bond) == BOND_MODE_ALB)
return bond_alb_set_mac_address(bond_dev, addr);
@ -3475,7 +3505,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
* Returning an error causes ifenslave to fail.
*/
if (bond->params.fail_over_mac &&
bond->params.mode == BOND_MODE_ACTIVEBACKUP)
BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
return 0;
if (!is_valid_ether_addr(sa->sa_data))
@ -3555,7 +3585,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl
/* Here we start from the slave with slave_id */
bond_for_each_slave_rcu(bond, slave, iter) {
if (--i < 0) {
if (slave_can_tx(slave)) {
if (bond_slave_can_tx(slave)) {
bond_dev_queue_xmit(bond, skb, slave->dev);
return;
}
@ -3567,7 +3597,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl
bond_for_each_slave_rcu(bond, slave, iter) {
if (--i < 0)
break;
if (slave_can_tx(slave)) {
if (bond_slave_can_tx(slave)) {
bond_dev_queue_xmit(bond, skb, slave->dev);
return;
}
@ -3624,7 +3654,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
*/
if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
slave = rcu_dereference(bond->curr_active_slave);
if (slave && slave_can_tx(slave))
if (slave && bond_slave_can_tx(slave))
bond_dev_queue_xmit(bond, skb, slave->dev);
else
bond_xmit_slave_id(bond, skb, 0);
@ -3662,7 +3692,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
bond_xmit_slave_id(bond, skb, bond_xmit_hash(bond, skb, bond->slave_cnt));
bond_xmit_slave_id(bond, skb, bond_xmit_hash(bond, skb) % bond->slave_cnt);
return NETDEV_TX_OK;
}
@ -3677,7 +3707,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
bond_for_each_slave_rcu(bond, slave, iter) {
if (bond_is_last_slave(bond, slave))
break;
if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
if (bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (!skb2) {
@ -3689,7 +3719,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
bond_dev_queue_xmit(bond, skb2, slave->dev);
}
}
if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
if (slave && bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)
bond_dev_queue_xmit(bond, skb, slave->dev);
else
dev_kfree_skb_any(skb);
@ -3714,7 +3744,7 @@ static inline int bond_slave_override(struct bonding *bond,
/* Find out if any slaves have the same mapping as this skb. */
bond_for_each_slave_rcu(bond, slave, iter) {
if (slave->queue_id == skb->queue_mapping) {
if (slave_can_tx(slave)) {
if (bond_slave_can_tx(slave)) {
bond_dev_queue_xmit(bond, skb, slave->dev);
return 0;
}
@ -3755,12 +3785,11 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
{
struct bonding *bond = netdev_priv(dev);
if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
if (!bond_slave_override(bond, skb))
return NETDEV_TX_OK;
}
if (bond_should_override_tx_queue(bond) &&
!bond_slave_override(bond, skb))
return NETDEV_TX_OK;
switch (bond->params.mode) {
switch (BOND_MODE(bond)) {
case BOND_MODE_ROUNDROBIN:
return bond_xmit_roundrobin(skb, dev);
case BOND_MODE_ACTIVEBACKUP:
@ -3772,12 +3801,13 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
case BOND_MODE_8023AD:
return bond_3ad_xmit_xor(skb, dev);
case BOND_MODE_ALB:
case BOND_MODE_TLB:
return bond_alb_xmit(skb, dev);
case BOND_MODE_TLB:
return bond_tlb_xmit(skb, dev);
default:
/* Should never happen, mode already checked */
pr_err("%s: Error: Unknown bonding mode %d\n",
dev->name, bond->params.mode);
dev->name, BOND_MODE(bond));
WARN_ON_ONCE(1);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@ -3817,14 +3847,14 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
ecmd->duplex = DUPLEX_UNKNOWN;
ecmd->port = PORT_OTHER;
/* Since SLAVE_IS_OK returns false for all inactive or down slaves, we
/* Since bond_slave_can_tx returns false for all inactive or down slaves, we
* do not need to check mode. Though link speed might not represent
* the true receive or transmit bandwidth (not all modes are symmetric)
* this is an accurate maximum.
*/
read_lock(&bond->lock);
bond_for_each_slave(bond, slave, iter) {
if (SLAVE_IS_OK(slave)) {
if (bond_slave_can_tx(slave)) {
if (slave->speed != SPEED_UNKNOWN)
speed += slave->speed;
if (ecmd->duplex == DUPLEX_UNKNOWN &&
@ -3915,7 +3945,7 @@ void bond_setup(struct net_device *bond_dev)
/* Initialize the device options */
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
bond_dev->priv_flags |= IFF_BONDING;
bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT;
bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
/* At first, we block adding VLANs. That's the only way to
@ -3994,7 +4024,8 @@ static int bond_check_params(struct bond_params *params)
if (xmit_hash_policy) {
if ((bond_mode != BOND_MODE_XOR) &&
(bond_mode != BOND_MODE_8023AD)) {
(bond_mode != BOND_MODE_8023AD) &&
(bond_mode != BOND_MODE_TLB)) {
pr_info("xmit_hash_policy param is irrelevant in mode %s\n",
bond_mode_name(bond_mode));
} else {
@ -4079,7 +4110,7 @@ static int bond_check_params(struct bond_params *params)
}
/* reset values for 802.3ad/TLB/ALB */
if (BOND_NO_USES_ARP(bond_mode)) {
if (!bond_mode_uses_arp(bond_mode)) {
if (!miimon) {
pr_warn("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n");
pr_warn("Forcing miimon to 100msec\n");
@ -4161,7 +4192,7 @@ static int bond_check_params(struct bond_params *params)
catch mistakes */
__be32 ip;
if (!in4_pton(arp_ip_target[i], -1, (u8 *)&ip, -1, NULL) ||
IS_IP_TARGET_UNUSABLE_ADDRESS(ip)) {
!bond_is_ip_target_ok(ip)) {
pr_warn("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
arp_ip_target[i]);
arp_interval = 0;
@ -4234,7 +4265,7 @@ static int bond_check_params(struct bond_params *params)
pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details\n");
}
if (primary && !USES_PRIMARY(bond_mode)) {
if (primary && !bond_mode_uses_primary(bond_mode)) {
/* currently, using a primary only makes sense
* in active backup, TLB or ALB modes
*/
@ -4300,6 +4331,7 @@ static int bond_check_params(struct bond_params *params)
params->min_links = min_links;
params->lp_interval = lp_interval;
params->packets_per_slave = packets_per_slave;
params->tlb_dynamic_lb = 1; /* Default value */
if (packets_per_slave > 0) {
params->reciprocal_packets_per_slave =
reciprocal_value(packets_per_slave);

View File

@ -56,10 +56,10 @@ static int bond_fill_slave_info(struct sk_buff *skb,
if (nla_put_u16(skb, IFLA_BOND_SLAVE_QUEUE_ID, slave->queue_id))
goto nla_put_failure;
if (slave->bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
const struct aggregator *agg;
agg = SLAVE_AD_INFO(slave).port.aggregator;
agg = SLAVE_AD_INFO(slave)->port.aggregator;
if (agg)
if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
agg->aggregator_identifier))
@ -407,7 +407,7 @@ static int bond_fill_info(struct sk_buff *skb,
unsigned int packets_per_slave;
int i, targets_added;
if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode))
if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond)))
goto nla_put_failure;
if (slave_dev &&
@ -505,7 +505,7 @@ static int bond_fill_info(struct sk_buff *skb,
bond->params.ad_select))
goto nla_put_failure;
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info info;
if (!bond_3ad_get_active_agg_info(bond, &info)) {

View File

@ -70,6 +70,8 @@ static int bond_option_mode_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_slaves_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval);
static const struct bond_opt_value bond_mode_tbl[] = {
@ -180,6 +182,12 @@ static const struct bond_opt_value bond_lp_interval_tbl[] = {
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
{ "off", 0, 0},
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static const struct bond_option bond_opts[] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
@ -200,7 +208,7 @@ static const struct bond_option bond_opts[] = {
[BOND_OPT_XMIT_HASH] = {
.id = BOND_OPT_XMIT_HASH,
.name = "xmit_hash_policy",
.desc = "balance-xor and 802.3ad hashing method",
.desc = "balance-xor, 802.3ad, and tlb hashing method",
.values = bond_xmit_hashtype_tbl,
.set = bond_option_xmit_hash_policy_set
},
@ -365,9 +373,33 @@ static const struct bond_option bond_opts[] = {
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_slaves_set
},
[BOND_OPT_TLB_DYNAMIC_LB] = {
.id = BOND_OPT_TLB_DYNAMIC_LB,
.name = "tlb_dynamic_lb",
.desc = "Enable dynamic flow shuffling",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_TLB)),
.values = bond_tlb_dynamic_lb_tbl,
.flags = BOND_OPTFLAG_IFDOWN,
.set = bond_option_tlb_dynamic_lb_set,
},
{ }
};
/* Searches for an option by name */
const struct bond_option *bond_opt_get_by_name(const char *name)
{
const struct bond_option *opt;
int option;
for (option = 0; option < BOND_OPT_LAST; option++) {
opt = bond_opt_get(option);
if (opt && !strcmp(opt->name, name))
return opt;
}
return NULL;
}
/* Searches for a value in opt's values[] table */
const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
{
@ -641,7 +673,7 @@ const struct bond_option *bond_opt_get(unsigned int option)
int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval)
{
if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) {
if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) {
pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n",
bond->dev->name, newval->string);
/* disable arp monitoring */
@ -662,7 +694,7 @@ int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newv
static struct net_device *__bond_option_active_slave_get(struct bonding *bond,
struct slave *slave)
{
return USES_PRIMARY(bond->params.mode) && slave ? slave->dev : NULL;
return bond_uses_primary(bond) && slave ? slave->dev : NULL;
}
struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond)
@ -727,7 +759,7 @@ static int bond_option_active_slave_set(struct bonding *bond,
bond->dev->name, new_active->dev->name);
} else {
if (old_active && (new_active->link == BOND_LINK_UP) &&
IS_UP(new_active->dev)) {
bond_slave_is_up(new_active)) {
pr_info("%s: Setting %s as active slave\n",
bond->dev->name, new_active->dev->name);
bond_change_active_slave(bond, new_active);
@ -746,6 +778,10 @@ static int bond_option_active_slave_set(struct bonding *bond,
return ret;
}
/* There are two tricky bits here. First, if MII monitoring is activated, then
* we must disable ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
static int bond_option_miimon_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
@ -784,6 +820,10 @@ static int bond_option_miimon_set(struct bonding *bond,
return 0;
}
/* Set up and down delays. These must be multiples of the
* MII monitoring value, and are stored internally as the multiplier.
* Thus, we must translate to MS for the real world.
*/
static int bond_option_updelay_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
@ -842,6 +882,10 @@ static int bond_option_use_carrier_set(struct bonding *bond,
return 0;
}
/* There are two tricky bits here. First, if ARP monitoring is activated, then
* we must disable MII monitoring. Second, if the ARP timer isn't running,
* we must start it.
*/
static int bond_option_arp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
@ -899,7 +943,7 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
__be32 *targets = bond->params.arp_targets;
int ind;
if (IS_IP_TARGET_UNUSABLE_ADDRESS(target)) {
if (!bond_is_ip_target_ok(target)) {
pr_err("%s: invalid ARP target %pI4 specified for addition\n",
bond->dev->name, &target);
return -EINVAL;
@ -944,7 +988,7 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
unsigned long *targets_rx;
int ind, i;
if (IS_IP_TARGET_UNUSABLE_ADDRESS(target)) {
if (!bond_is_ip_target_ok(target)) {
pr_err("%s: invalid ARP target %pI4 specified for removal\n",
bond->dev->name, &target);
return -EINVAL;
@ -1338,3 +1382,13 @@ err_no_cmd:
ret = -EPERM;
goto out;
}
static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
pr_info("%s: Setting dynamic-lb to %s (%llu)\n",
bond->dev->name, newval->string, newval->value);
bond->params.tlb_dynamic_lb = newval->value;
return 0;
}

View File

@ -62,6 +62,7 @@ enum {
BOND_OPT_RESEND_IGMP,
BOND_OPT_LP_INTERVAL,
BOND_OPT_SLAVES,
BOND_OPT_TLB_DYNAMIC_LB,
BOND_OPT_LAST
};
@ -104,6 +105,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
struct bond_opt_value *val);
const struct bond_option *bond_opt_get(unsigned int option);
const struct bond_option *bond_opt_get_by_name(const char *name);
const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
/* This helper is used to initialize a bond_opt_value structure for parameter

View File

@ -72,9 +72,9 @@ static void bond_info_show_master(struct seq_file *seq)
curr = rcu_dereference(bond->curr_active_slave);
seq_printf(seq, "Bonding Mode: %s",
bond_mode_name(bond->params.mode));
bond_mode_name(BOND_MODE(bond)));
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
bond->params.fail_over_mac) {
optval = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
bond->params.fail_over_mac);
@ -83,15 +83,15 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "\n");
if (bond->params.mode == BOND_MODE_XOR ||
bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_XOR ||
BOND_MODE(bond) == BOND_MODE_8023AD) {
optval = bond_opt_get_val(BOND_OPT_XMIT_HASH,
bond->params.xmit_policy);
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
optval->string, bond->params.xmit_policy);
}
if (USES_PRIMARY(bond->params.mode)) {
if (bond_uses_primary(bond)) {
seq_printf(seq, "Primary Slave: %s",
(bond->primary_slave) ?
bond->primary_slave->dev->name : "None");
@ -134,7 +134,7 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "\n");
}
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
seq_puts(seq, "\n802.3ad info\n");
@ -188,9 +188,9 @@ static void bond_info_show_slave(struct seq_file *seq,
seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
const struct aggregator *agg
= SLAVE_AD_INFO(slave).port.aggregator;
= SLAVE_AD_INFO(slave)->port.aggregator;
if (agg)
seq_printf(seq, "Aggregator ID: %d\n",

View File

@ -45,8 +45,7 @@
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd))))
/*
* "show" function for the bond_masters attribute.
/* "show" function for the bond_masters attribute.
* The class parameter is ignored.
*/
static ssize_t bonding_show_bonds(struct class *cls,
@ -88,14 +87,12 @@ static struct net_device *bond_get_by_name(struct bond_net *bn, const char *ifna
return NULL;
}
/*
* "store" function for the bond_masters attribute. This is what
/* "store" function for the bond_masters attribute. This is what
* creates and deletes entire bonds.
*
* The class parameter is ignored.
*
*/
static ssize_t bonding_store_bonds(struct class *cls,
struct class_attribute *attr,
const char *buffer, size_t count)
@ -158,9 +155,26 @@ static const struct class_attribute class_attr_bonding_masters = {
.store = bonding_store_bonds,
};
/*
* Show the slaves in the current bond.
*/
/* Generic "store" method for bonding sysfs option setting */
static ssize_t bonding_sysfs_store_option(struct device *d,
struct device_attribute *attr,
const char *buffer, size_t count)
{
struct bonding *bond = to_bond(d);
const struct bond_option *opt;
int ret;
opt = bond_opt_get_by_name(attr->attr.name);
if (WARN_ON(!opt))
return -ENOENT;
ret = bond_opt_tryset_rtnl(bond, opt->id, (char *)buffer);
if (!ret)
ret = count;
return ret;
}
/* Show the slaves in the current bond. */
static ssize_t bonding_show_slaves(struct device *d,
struct device_attribute *attr, char *buf)
{
@ -190,62 +204,24 @@ static ssize_t bonding_show_slaves(struct device *d,
return res;
}
/*
* Set the slaves in the current bond.
* This is supposed to be only thin wrapper for bond_enslave and bond_release.
* All hard work should be done there.
*/
static ssize_t bonding_store_slaves(struct device *d,
struct device_attribute *attr,
const char *buffer, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_SLAVES, (char *)buffer);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves,
bonding_store_slaves);
bonding_sysfs_store_option);
/*
* Show and set the bonding mode. The bond interface must be down to
* change the mode.
*/
/* Show the bonding mode. */
static ssize_t bonding_show_mode(struct device *d,
struct device_attribute *attr, char *buf)
{
struct bonding *bond = to_bond(d);
const struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
val = bond_opt_get_val(BOND_OPT_MODE, BOND_MODE(bond));
return sprintf(buf, "%s %d\n", val->string, bond->params.mode);
}
static ssize_t bonding_store_mode(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MODE, (char *)buf);
if (!ret)
ret = count;
return ret;
return sprintf(buf, "%s %d\n", val->string, BOND_MODE(bond));
}
static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
bonding_show_mode, bonding_store_mode);
bonding_show_mode, bonding_sysfs_store_option);
/*
* Show and set the bonding transmit hash method.
*/
/* Show the bonding transmit hash method. */
static ssize_t bonding_show_xmit_hash(struct device *d,
struct device_attribute *attr,
char *buf)
@ -257,26 +233,10 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
return sprintf(buf, "%s %d\n", val->string, bond->params.xmit_policy);
}
static ssize_t bonding_store_xmit_hash(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_XMIT_HASH, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR,
bonding_show_xmit_hash, bonding_store_xmit_hash);
bonding_show_xmit_hash, bonding_sysfs_store_option);
/*
* Show and set arp_validate.
*/
/* Show arp_validate. */
static ssize_t bonding_show_arp_validate(struct device *d,
struct device_attribute *attr,
char *buf)
@ -289,26 +249,10 @@ static ssize_t bonding_show_arp_validate(struct device *d,
return sprintf(buf, "%s %d\n", val->string, bond->params.arp_validate);
}
static ssize_t bonding_store_arp_validate(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_VALIDATE, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate,
bonding_store_arp_validate);
/*
* Show and set arp_all_targets.
*/
bonding_sysfs_store_option);
/* Show arp_all_targets. */
static ssize_t bonding_show_arp_all_targets(struct device *d,
struct device_attribute *attr,
char *buf)
@ -321,28 +265,10 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
return sprintf(buf, "%s %d\n",
val->string, bond->params.arp_all_targets);
}
static ssize_t bonding_store_arp_all_targets(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_ALL_TARGETS, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(arp_all_targets, S_IRUGO | S_IWUSR,
bonding_show_arp_all_targets, bonding_store_arp_all_targets);
bonding_show_arp_all_targets, bonding_sysfs_store_option);
/*
* Show and store fail_over_mac. User only allowed to change the
* value when there are no slaves.
*/
/* Show fail_over_mac. */
static ssize_t bonding_show_fail_over_mac(struct device *d,
struct device_attribute *attr,
char *buf)
@ -355,30 +281,10 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
return sprintf(buf, "%s %d\n", val->string, bond->params.fail_over_mac);
}
static ssize_t bonding_store_fail_over_mac(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_FAIL_OVER_MAC, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR,
bonding_show_fail_over_mac, bonding_store_fail_over_mac);
bonding_show_fail_over_mac, bonding_sysfs_store_option);
/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
* MII monitoring. Second, if the ARP timer isn't running, we must
* start it.
*/
/* Show the arp timer interval. */
static ssize_t bonding_show_arp_interval(struct device *d,
struct device_attribute *attr,
char *buf)
@ -387,26 +293,10 @@ static ssize_t bonding_show_arp_interval(struct device *d,
return sprintf(buf, "%d\n", bond->params.arp_interval);
}
static ssize_t bonding_store_arp_interval(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_INTERVAL, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR,
bonding_show_arp_interval, bonding_store_arp_interval);
bonding_show_arp_interval, bonding_sysfs_store_option);
/*
* Show and set the arp targets.
*/
/* Show the arp targets. */
static ssize_t bonding_show_arp_targets(struct device *d,
struct device_attribute *attr,
char *buf)
@ -424,27 +314,10 @@ static ssize_t bonding_show_arp_targets(struct device *d,
return res;
}
static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR,
bonding_show_arp_targets, bonding_sysfs_store_option);
static ssize_t bonding_store_arp_targets(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_TARGETS, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
/*
* Show and set the up and down delays. These must be multiples of the
* MII monitoring value, and are stored internally as the multiplier.
* Thus, we must translate to MS for the real world.
*/
/* Show the up and down delays. */
static ssize_t bonding_show_downdelay(struct device *d,
struct device_attribute *attr,
char *buf)
@ -453,22 +326,8 @@ static ssize_t bonding_show_downdelay(struct device *d,
return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon);
}
static ssize_t bonding_store_downdelay(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_DOWNDELAY, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
bonding_show_downdelay, bonding_store_downdelay);
bonding_show_downdelay, bonding_sysfs_store_option);
static ssize_t bonding_show_updelay(struct device *d,
struct device_attribute *attr,
@ -479,27 +338,10 @@ static ssize_t bonding_show_updelay(struct device *d,
return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon);
}
static ssize_t bonding_store_updelay(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_UPDELAY, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR,
bonding_show_updelay, bonding_store_updelay);
bonding_show_updelay, bonding_sysfs_store_option);
/*
* Show and set the LACP interval. Interface must be down, and the mode
* must be set to 802.3ad mode.
*/
/* Show the LACP interval. */
static ssize_t bonding_show_lacp(struct device *d,
struct device_attribute *attr,
char *buf)
@ -511,22 +353,8 @@ static ssize_t bonding_show_lacp(struct device *d,
return sprintf(buf, "%s %d\n", val->string, bond->params.lacp_fast);
}
static ssize_t bonding_store_lacp(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LACP_RATE, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR,
bonding_show_lacp, bonding_store_lacp);
bonding_show_lacp, bonding_sysfs_store_option);
static ssize_t bonding_show_min_links(struct device *d,
struct device_attribute *attr,
@ -536,22 +364,8 @@ static ssize_t bonding_show_min_links(struct device *d,
return sprintf(buf, "%u\n", bond->params.min_links);
}
static ssize_t bonding_store_min_links(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MINLINKS, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR,
bonding_show_min_links, bonding_store_min_links);
bonding_show_min_links, bonding_sysfs_store_option);
static ssize_t bonding_show_ad_select(struct device *d,
struct device_attribute *attr,
@ -564,27 +378,10 @@ static ssize_t bonding_show_ad_select(struct device *d,
return sprintf(buf, "%s %d\n", val->string, bond->params.ad_select);
}
static ssize_t bonding_store_ad_select(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_AD_SELECT, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR,
bonding_show_ad_select, bonding_store_ad_select);
bonding_show_ad_select, bonding_sysfs_store_option);
/*
* Show and set the number of peer notifications to send after a failover event.
*/
/* Show and set the number of peer notifications to send after a failover event. */
static ssize_t bonding_show_num_peer_notif(struct device *d,
struct device_attribute *attr,
char *buf)
@ -611,12 +408,7 @@ static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR,
bonding_show_num_peer_notif, bonding_store_num_peer_notif);
/*
* Show and set the MII monitor interval. There are two tricky bits
* here. First, if MII monitoring is activated, then we must disable
* ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
/* Show the MII monitor interval. */
static ssize_t bonding_show_miimon(struct device *d,
struct device_attribute *attr,
char *buf)
@ -625,30 +417,10 @@ static ssize_t bonding_show_miimon(struct device *d,
return sprintf(buf, "%d\n", bond->params.miimon);
}
static ssize_t bonding_store_miimon(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MIIMON, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR,
bonding_show_miimon, bonding_store_miimon);
bonding_show_miimon, bonding_sysfs_store_option);
/*
* Show and set the primary slave. The store function is much
* simpler than bonding_store_slaves function because it only needs to
* handle one interface name.
* The bond must be a mode that supports a primary for this be
* set.
*/
/* Show the primary slave. */
static ssize_t bonding_show_primary(struct device *d,
struct device_attribute *attr,
char *buf)
@ -661,26 +433,10 @@ static ssize_t bonding_show_primary(struct device *d,
return count;
}
static ssize_t bonding_store_primary(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR,
bonding_show_primary, bonding_store_primary);
bonding_show_primary, bonding_sysfs_store_option);
/*
* Show and set the primary_reselect flag.
*/
/* Show the primary_reselect flag. */
static ssize_t bonding_show_primary_reselect(struct device *d,
struct device_attribute *attr,
char *buf)
@ -694,28 +450,10 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
return sprintf(buf, "%s %d\n",
val->string, bond->params.primary_reselect);
}
static ssize_t bonding_store_primary_reselect(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY_RESELECT,
(char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR,
bonding_show_primary_reselect,
bonding_store_primary_reselect);
bonding_show_primary_reselect, bonding_sysfs_store_option);
/*
* Show and set the use_carrier flag.
*/
/* Show the use_carrier flag. */
static ssize_t bonding_show_carrier(struct device *d,
struct device_attribute *attr,
char *buf)
@ -724,27 +462,11 @@ static ssize_t bonding_show_carrier(struct device *d,
return sprintf(buf, "%d\n", bond->params.use_carrier);
}
static ssize_t bonding_store_carrier(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_USE_CARRIER, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR,
bonding_show_carrier, bonding_store_carrier);
bonding_show_carrier, bonding_sysfs_store_option);
/*
* Show and set currently active_slave.
*/
/* Show currently active_slave. */
static ssize_t bonding_show_active_slave(struct device *d,
struct device_attribute *attr,
char *buf)
@ -761,27 +483,10 @@ static ssize_t bonding_show_active_slave(struct device *d,
return count;
}
static ssize_t bonding_store_active_slave(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ACTIVE_SLAVE, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR,
bonding_show_active_slave, bonding_store_active_slave);
bonding_show_active_slave, bonding_sysfs_store_option);
/*
* Show link status of the bond interface.
*/
/* Show link status of the bond interface. */
static ssize_t bonding_show_mii_status(struct device *d,
struct device_attribute *attr,
char *buf)
@ -792,9 +497,7 @@ static ssize_t bonding_show_mii_status(struct device *d,
}
static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
/*
* Show current 802.3ad aggregator ID.
*/
/* Show current 802.3ad aggregator ID. */
static ssize_t bonding_show_ad_aggregator(struct device *d,
struct device_attribute *attr,
char *buf)
@ -802,7 +505,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
@ -814,9 +517,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d,
static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
/*
* Show number of active 802.3ad ports.
*/
/* Show number of active 802.3ad ports. */
static ssize_t bonding_show_ad_num_ports(struct device *d,
struct device_attribute *attr,
char *buf)
@ -824,7 +525,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
@ -836,9 +537,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d,
static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
/*
* Show current 802.3ad actor key.
*/
/* Show current 802.3ad actor key. */
static ssize_t bonding_show_ad_actor_key(struct device *d,
struct device_attribute *attr,
char *buf)
@ -846,7 +545,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
@ -858,9 +557,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d,
static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
/*
* Show current 802.3ad partner key.
*/
/* Show current 802.3ad partner key. */
static ssize_t bonding_show_ad_partner_key(struct device *d,
struct device_attribute *attr,
char *buf)
@ -868,7 +565,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
@ -880,9 +577,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d,
static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
/*
* Show current 802.3ad partner mac.
*/
/* Show current 802.3ad partner mac. */
static ssize_t bonding_show_ad_partner_mac(struct device *d,
struct device_attribute *attr,
char *buf)
@ -890,7 +585,7 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
int count = 0;
struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
if (!bond_3ad_get_active_agg_info(bond, &ad_info))
count = sprintf(buf, "%pM\n", ad_info.partner_system);
@ -900,9 +595,7 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
}
static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
/*
* Show the queue_ids of the slaves in the current bond.
*/
/* Show the queue_ids of the slaves in the current bond. */
static ssize_t bonding_show_queue_id(struct device *d,
struct device_attribute *attr,
char *buf)
@ -933,31 +626,11 @@ static ssize_t bonding_show_queue_id(struct device *d,
return res;
}
/*
* Set the queue_ids of the slaves in the current bond. The bond
* interface must be enslaved for this to work.
*/
static ssize_t bonding_store_queue_id(struct device *d,
struct device_attribute *attr,
const char *buffer, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_QUEUE_ID, (char *)buffer);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
bonding_store_queue_id);
bonding_sysfs_store_option);
/*
* Show and set the all_slaves_active flag.
*/
/* Show the all_slaves_active flag. */
static ssize_t bonding_show_slaves_active(struct device *d,
struct device_attribute *attr,
char *buf)
@ -966,27 +639,10 @@ static ssize_t bonding_show_slaves_active(struct device *d,
return sprintf(buf, "%d\n", bond->params.all_slaves_active);
}
static ssize_t bonding_store_slaves_active(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ALL_SLAVES_ACTIVE,
(char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
bonding_show_slaves_active, bonding_store_slaves_active);
bonding_show_slaves_active, bonding_sysfs_store_option);
/*
* Show and set the number of IGMP membership reports to send on link failure
*/
/* Show the number of IGMP membership reports to send on link failure */
static ssize_t bonding_show_resend_igmp(struct device *d,
struct device_attribute *attr,
char *buf)
@ -995,23 +651,8 @@ static ssize_t bonding_show_resend_igmp(struct device *d,
return sprintf(buf, "%d\n", bond->params.resend_igmp);
}
static ssize_t bonding_store_resend_igmp(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_RESEND_IGMP, (char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
bonding_show_resend_igmp, bonding_store_resend_igmp);
bonding_show_resend_igmp, bonding_sysfs_store_option);
static ssize_t bonding_show_lp_interval(struct device *d,
@ -1019,25 +660,21 @@ static ssize_t bonding_show_lp_interval(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.lp_interval);
}
static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR,
bonding_show_lp_interval, bonding_sysfs_store_option);
static ssize_t bonding_store_lp_interval(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t bonding_show_tlb_dynamic_lb(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LP_INTERVAL, (char *)buf);
if (!ret)
ret = count;
return ret;
return sprintf(buf, "%d\n", bond->params.tlb_dynamic_lb);
}
static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR,
bonding_show_lp_interval, bonding_store_lp_interval);
static DEVICE_ATTR(tlb_dynamic_lb, S_IRUGO | S_IWUSR,
bonding_show_tlb_dynamic_lb, bonding_sysfs_store_option);
static ssize_t bonding_show_packets_per_slave(struct device *d,
struct device_attribute *attr,
@ -1045,27 +682,11 @@ static ssize_t bonding_show_packets_per_slave(struct device *d,
{
struct bonding *bond = to_bond(d);
unsigned int packets_per_slave = bond->params.packets_per_slave;
return sprintf(buf, "%u\n", packets_per_slave);
}
static ssize_t bonding_store_packets_per_slave(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PACKETS_PER_SLAVE,
(char *)buf);
if (!ret)
ret = count;
return ret;
}
static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR,
bonding_show_packets_per_slave,
bonding_store_packets_per_slave);
bonding_show_packets_per_slave, bonding_sysfs_store_option);
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
@ -1099,6 +720,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_min_links.attr,
&dev_attr_lp_interval.attr,
&dev_attr_packets_per_slave.attr,
&dev_attr_tlb_dynamic_lb.attr,
NULL,
};
@ -1107,8 +729,7 @@ static struct attribute_group bonding_group = {
.attrs = per_bond_attrs,
};
/*
* Initialize sysfs. This sets up the bonding_masters file in
/* Initialize sysfs. This sets up the bonding_masters file in
* /sys/class/net.
*/
int bond_create_sysfs(struct bond_net *bn)
@ -1120,8 +741,7 @@ int bond_create_sysfs(struct bond_net *bn)
ret = netdev_class_create_file_ns(&bn->class_attr_bonding_masters,
bn->net);
/*
* Permit multiple loads of the module by ignoring failures to
/* Permit multiple loads of the module by ignoring failures to
* create the bonding_masters sysfs file. Bonding devices
* created by second or subsequent loads of the module will
* not be listed in, or controllable by, bonding_masters, but
@ -1144,16 +764,13 @@ int bond_create_sysfs(struct bond_net *bn)
}
/*
* Remove /sys/class/net/bonding_masters.
*/
/* Remove /sys/class/net/bonding_masters. */
void bond_destroy_sysfs(struct bond_net *bn)
{
netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, bn->net);
}
/*
* Initialize sysfs for each bond. This sets up and registers
/* Initialize sysfs for each bond. This sets up and registers
* the 'bondctl' directory for each individual bond under /sys/class/net.
*/
void bond_prepare_sysfs_group(struct bonding *bond)

View File

@ -69,8 +69,8 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)
{
const struct aggregator *agg;
if (slave->bond->params.mode == BOND_MODE_8023AD) {
agg = SLAVE_AD_INFO(slave).port.aggregator;
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
agg = SLAVE_AD_INFO(slave)->port.aggregator;
if (agg)
return sprintf(buf, "%d\n",
agg->aggregator_identifier);

View File

@ -41,42 +41,6 @@
#define BOND_DEFAULT_MIIMON 100
#define IS_UP(dev) \
((((dev)->flags & IFF_UP) == IFF_UP) && \
netif_running(dev) && \
netif_carrier_ok(dev))
/*
* Checks whether slave is ready for transmit.
*/
#define SLAVE_IS_OK(slave) \
(((slave)->dev->flags & IFF_UP) && \
netif_running((slave)->dev) && \
((slave)->link == BOND_LINK_UP) && \
bond_is_active_slave(slave))
#define USES_PRIMARY(mode) \
(((mode) == BOND_MODE_ACTIVEBACKUP) || \
((mode) == BOND_MODE_TLB) || \
((mode) == BOND_MODE_ALB))
#define BOND_NO_USES_ARP(mode) \
(((mode) == BOND_MODE_8023AD) || \
((mode) == BOND_MODE_TLB) || \
((mode) == BOND_MODE_ALB))
#define TX_QUEUE_OVERRIDE(mode) \
(((mode) == BOND_MODE_ACTIVEBACKUP) || \
((mode) == BOND_MODE_ROUNDROBIN))
#define BOND_MODE_IS_LB(mode) \
(((mode) == BOND_MODE_TLB) || \
((mode) == BOND_MODE_ALB))
#define IS_IP_TARGET_UNUSABLE_ADDRESS(a) \
((htonl(INADDR_BROADCAST) == a) || \
ipv4_is_zeronet(a))
/*
* Less bad way to call ioctl from within the kernel; this needs to be
* done some other way to get the call out of interrupt context.
@ -90,6 +54,8 @@
set_fs(fs); \
res; })
#define BOND_MODE(bond) ((bond)->params.mode)
/* slave list primitives */
#define bond_slave_list(bond) (&(bond)->dev->adj_list.lower)
@ -175,6 +141,7 @@ struct bond_params {
int resend_igmp;
int lp_interval;
int packets_per_slave;
int tlb_dynamic_lb;
struct reciprocal_value reciprocal_packets_per_slave;
};
@ -183,8 +150,6 @@ struct bond_parm_tbl {
int mode;
};
#define BOND_MAX_MODENAME_LEN 20
struct slave {
struct net_device *dev; /* first - useful for panic debug */
struct bonding *bond; /* our master */
@ -205,7 +170,7 @@ struct slave {
u32 speed;
u16 queue_id;
u8 perm_hwaddr[ETH_ALEN];
struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
struct ad_slave_info *ad_info;
struct tlb_slave_info tlb_info;
#ifdef CONFIG_NET_POLL_CONTROLLER
struct netpoll *np;
@ -285,14 +250,41 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
{
if (!slave || !slave->bond)
return NULL;
return slave->bond;
}
static inline bool bond_should_override_tx_queue(struct bonding *bond)
{
return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_ROUNDROBIN;
}
static inline bool bond_is_lb(const struct bonding *bond)
{
return BOND_MODE_IS_LB(bond->params.mode);
return BOND_MODE(bond) == BOND_MODE_TLB ||
BOND_MODE(bond) == BOND_MODE_ALB;
}
static inline bool bond_mode_uses_arp(int mode)
{
return mode != BOND_MODE_8023AD && mode != BOND_MODE_TLB &&
mode != BOND_MODE_ALB;
}
static inline bool bond_mode_uses_primary(int mode)
{
return mode == BOND_MODE_ACTIVEBACKUP || mode == BOND_MODE_TLB ||
mode == BOND_MODE_ALB;
}
static inline bool bond_uses_primary(struct bonding *bond)
{
return bond_mode_uses_primary(BOND_MODE(bond));
}
static inline bool bond_slave_is_up(struct slave *slave)
{
return netif_running(slave->dev) && netif_carrier_ok(slave->dev);
}
static inline void bond_set_active_slave(struct slave *slave)
@ -365,6 +357,12 @@ static inline bool bond_is_active_slave(struct slave *slave)
return !bond_slave_state(slave);
}
static inline bool bond_slave_can_tx(struct slave *slave)
{
return bond_slave_is_up(slave) && slave->link == BOND_LINK_UP &&
bond_is_active_slave(slave);
}
#define BOND_PRI_RESELECT_ALWAYS 0
#define BOND_PRI_RESELECT_BETTER 1
#define BOND_PRI_RESELECT_FAILURE 2
@ -396,12 +394,16 @@ static inline int slave_do_arp_validate(struct bonding *bond,
return bond->params.arp_validate & (1 << bond_slave_state(slave));
}
static inline int slave_do_arp_validate_only(struct bonding *bond,
struct slave *slave)
static inline int slave_do_arp_validate_only(struct bonding *bond)
{
return bond->params.arp_validate & BOND_ARP_FILTER;
}
static inline int bond_is_ip_target_ok(__be32 addr)
{
return !ipv4_is_lbcast(addr) && !ipv4_is_zeronet(addr);
}
/* Get the oldest arp which we've received on this slave for bond's
* arp_targets.
*/
@ -479,16 +481,14 @@ static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be3
return addr;
}
static inline bool slave_can_tx(struct slave *slave)
{
if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP &&
bond_is_active_slave(slave))
return true;
else
return false;
}
struct bond_net;
struct bond_net {
struct net *net; /* Associated network namespace */
struct list_head dev_list;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_dir;
#endif
struct class_attribute class_attr_bonding_masters;
};
int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
void bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
@ -500,7 +500,7 @@ int bond_sysfs_slave_add(struct slave *slave);
void bond_sysfs_slave_del(struct slave *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count);
u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
void bond_create_debugfs(void);
@ -516,15 +516,9 @@ void bond_netlink_fini(void);
struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
struct net_device *bond_option_active_slave_get(struct bonding *bond);
const char *bond_slave_link_status(s8 link);
struct bond_net {
struct net * net; /* Associated network namespace */
struct list_head dev_list;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry * proc_dir;
#endif
struct class_attribute class_attr_bonding_masters;
};
bool bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
struct bond_vlan_tag *tags);
#ifdef CONFIG_PROC_FS
void bond_create_proc_entry(struct bonding *bond);
@ -576,6 +570,27 @@ static inline struct slave *bond_slave_has_mac_rcu(struct bonding *bond,
return NULL;
}
/* Caller must hold rcu_read_lock() for read */
static inline bool bond_slave_has_mac_rx(struct bonding *bond, const u8 *mac)
{
struct list_head *iter;
struct slave *tmp;
struct netdev_hw_addr *ha;
bond_for_each_slave_rcu(bond, tmp, iter)
if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
return true;
if (netdev_uc_empty(bond->dev))
return false;
netdev_for_each_uc_addr(ha, bond->dev)
if (ether_addr_equal_64bits(mac, ha->addr))
return true;
return false;
}
/* Check if the ip is present in arp ip list, or first free slot if ip == 0
* Returns -1 if not found, index if found
*/

View File

@ -65,7 +65,7 @@ config CAN_LEDS
config CAN_AT91
tristate "Atmel AT91 onchip CAN controller"
depends on ARM
depends on ARCH_AT91 || COMPILE_TEST
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors.
@ -77,12 +77,6 @@ config CAN_TI_HECC
Driver for TI HECC (High End CAN Controller) module found on many
TI devices. The device specifications are available from www.ti.com
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on SPI && HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
config CAN_BFIN
depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
tristate "Analog Devices Blackfin on-chip CAN"
@ -110,7 +104,7 @@ config CAN_FLEXCAN
config PCH_CAN
tristate "Intel EG20T PCH CAN controller"
depends on PCI
depends on PCI && (X86_32 || COMPILE_TEST)
---help---
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
is an IOH for x86 embedded processor (Intel Atom E6xx series).
@ -125,6 +119,24 @@ config CAN_GRCAN
endian syntheses of the cores would need some modifications on
the hardware level to work.
config CAN_RCAR
tristate "Renesas R-Car CAN controller"
depends on ARM
---help---
Say Y here if you want to use CAN controller found on Renesas R-Car
SoCs.
To compile this driver as a module, choose M here: the module will
be called rcar_can.
config CAN_XILINXCAN
tristate "Xilinx CAN"
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
depends on COMMON_CLK && HAS_IOMEM
---help---
Xilinx CAN driver. This driver supports both soft AXI CAN IP and
Zynq CANPS IP.
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
@ -133,6 +145,8 @@ source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/cc770/Kconfig"
source "drivers/net/can/spi/Kconfig"
source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"

View File

@ -10,6 +10,7 @@ can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += spi/
obj-y += usb/
obj-y += softing/
@ -19,11 +20,12 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_PCH_CAN) += pch_can.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
obj-$(CONFIG_CAN_RCAR) += rcar_can.o
obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG

View File

@ -252,8 +252,7 @@ static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj
struct c_can_priv *priv = netdev_priv(dev);
int cnt, reg = C_CAN_IFACE(COMREQ_REG, iface);
priv->write_reg(priv, reg + 1, cmd);
priv->write_reg(priv, reg, obj);
priv->write_reg32(priv, reg, (cmd << 16) | obj);
for (cnt = MIN_TIMEOUT_VALUE; cnt; cnt--) {
if (!(priv->read_reg(priv, reg) & IF_COMR_BUSY))
@ -328,8 +327,7 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
change_bit(idx, &priv->tx_dir);
}
priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), arb);
priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), arb >> 16);
priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), arb);
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
@ -391,8 +389,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
frame->can_dlc = get_can_dlc(ctrl & 0x0F);
arb = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface));
arb |= priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface)) << 16;
arb = priv->read_reg32(priv, C_CAN_IFACE(ARB1_REG, iface));
if (arb & IF_ARB_MSGXTD)
frame->can_id = (arb & CAN_EFF_MASK) | CAN_EFF_FLAG;
@ -424,12 +421,10 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
struct c_can_priv *priv = netdev_priv(dev);
mask |= BIT(29);
priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), mask);
priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), mask >> 16);
priv->write_reg32(priv, C_CAN_IFACE(MASK1_REG, iface), mask);
id |= IF_ARB_MSGVAL;
priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), id);
priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), id >> 16);
priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), id);
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP);

View File

@ -78,6 +78,7 @@ enum reg {
C_CAN_INTPND2_REG,
C_CAN_MSGVAL1_REG,
C_CAN_MSGVAL2_REG,
C_CAN_FUNCTION_REG,
};
static const u16 reg_map_c_can[] = {
@ -129,6 +130,7 @@ static const u16 reg_map_d_can[] = {
[C_CAN_BRPEXT_REG] = 0x0E,
[C_CAN_INT_REG] = 0x10,
[C_CAN_TEST_REG] = 0x14,
[C_CAN_FUNCTION_REG] = 0x18,
[C_CAN_TXRQST1_REG] = 0x88,
[C_CAN_TXRQST2_REG] = 0x8A,
[C_CAN_NEWDAT1_REG] = 0x9C,
@ -176,8 +178,10 @@ struct c_can_priv {
atomic_t tx_active;
unsigned long tx_dir;
int last_status;
u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
u16 (*read_reg) (const struct c_can_priv *priv, enum reg index);
void (*write_reg) (const struct c_can_priv *priv, enum reg index, u16 val);
u32 (*read_reg32) (const struct c_can_priv *priv, enum reg index);
void (*write_reg32) (const struct c_can_priv *priv, enum reg index, u32 val);
void __iomem *base;
const u16 *regs;
void *priv; /* for board-specific data */

View File

@ -19,9 +19,13 @@
#include "c_can.h"
#define PCI_DEVICE_ID_PCH_CAN 0x8818
#define PCH_PCI_SOFT_RESET 0x01fc
enum c_can_pci_reg_align {
C_CAN_REG_ALIGN_16,
C_CAN_REG_ALIGN_32,
C_CAN_REG_32,
};
struct c_can_pci_data {
@ -31,6 +35,10 @@ struct c_can_pci_data {
enum c_can_pci_reg_align reg_align;
/* Set the frequency */
unsigned int freq;
/* PCI bar number */
int bar;
/* Callback for reset */
void (*init)(const struct c_can_priv *priv, bool enable);
};
/*
@ -39,30 +47,70 @@ struct c_can_pci_data {
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface.
*/
static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + priv->regs[index]);
}
static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + priv->regs[index]);
}
static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + 2 * priv->regs[index]);
}
static u16 c_can_pci_read_reg_32bit(const struct c_can_priv *priv,
enum reg index)
{
return (u16)ioread32(priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_write_reg_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
iowrite32((u32)val, priv->base + 2 * priv->regs[index]);
}
static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index)
{
u32 val;
val = priv->read_reg(priv, index);
val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
return val;
}
static void c_can_pci_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
{
priv->write_reg(priv, index + 1, val >> 16);
priv->write_reg(priv, index, val);
}
static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable)
{
if (enable) {
u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET;
/* write to sw reset register */
iowrite32(1, addr);
iowrite32(0, addr);
}
}
static int c_can_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@ -90,7 +138,8 @@ static int c_can_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev);
}
addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
addr = pci_iomap(pdev, c_can_pci_data->bar,
pci_resource_len(pdev, c_can_pci_data->bar));
if (!addr) {
dev_err(&pdev->dev,
"device has no PCI memory resources, "
@ -147,10 +196,18 @@ static int c_can_pci_probe(struct pci_dev *pdev,
priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
break;
case C_CAN_REG_32:
priv->read_reg = c_can_pci_read_reg_32bit;
priv->write_reg = c_can_pci_write_reg_32bit;
break;
default:
ret = -EINVAL;
goto out_free_c_can;
}
priv->read_reg32 = c_can_pci_read_reg32;
priv->write_reg32 = c_can_pci_write_reg32;
priv->raminit = c_can_pci_data->init;
ret = register_c_can_dev(dev);
if (ret) {
@ -198,6 +255,15 @@ static struct c_can_pci_data c_can_sta2x11= {
.type = BOSCH_C_CAN,
.reg_align = C_CAN_REG_ALIGN_32,
.freq = 52000000, /* 52 Mhz */
.bar = 0,
};
static struct c_can_pci_data c_can_pch = {
.type = BOSCH_C_CAN,
.reg_align = C_CAN_REG_32,
.freq = 50000000, /* 50 MHz */
.init = c_can_pci_reset_pch,
.bar = 1,
};
#define C_CAN_ID(_vend, _dev, _driverdata) { \
@ -207,6 +273,8 @@ static struct c_can_pci_data c_can_sta2x11= {
static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
c_can_sta2x11),
C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,
c_can_pch),
{},
};
static struct pci_driver c_can_pci_driver = {

View File

@ -40,6 +40,7 @@
#define CAN_RAMINIT_START_MASK(i) (0x001 << (i))
#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i))
#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i))
#define DCAN_RAM_INIT_BIT (1 << 3)
static DEFINE_SPINLOCK(raminit_lock);
/*
* 16-bit c_can registers can be arranged differently in the memory
@ -47,31 +48,31 @@ static DEFINE_SPINLOCK(raminit_lock);
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface.
*/
static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
static u16 c_can_plat_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + priv->regs[index]);
}
static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
static void c_can_plat_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + priv->regs[index]);
}
static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
static u16 c_can_plat_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + 2 * priv->regs[index]);
}
static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + 2 * priv->regs[index]);
}
static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask,
static void c_can_hw_raminit_wait_ti(const struct c_can_priv *priv, u32 mask,
u32 val)
{
/* We look only at the bits of our instance. */
@ -80,7 +81,7 @@ static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask,
udelay(1);
}
static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable)
{
u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance);
u32 ctrl;
@ -96,18 +97,68 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
writel(ctrl, priv->raminit_ctrlreg);
ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance);
c_can_hw_raminit_wait(priv, ctrl, mask);
c_can_hw_raminit_wait_ti(priv, ctrl, mask);
if (enable) {
/* Set start bit and wait for the done bit. */
ctrl |= CAN_RAMINIT_START_MASK(priv->instance);
writel(ctrl, priv->raminit_ctrlreg);
ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
c_can_hw_raminit_wait(priv, ctrl, mask);
c_can_hw_raminit_wait_ti(priv, ctrl, mask);
}
spin_unlock(&raminit_lock);
}
static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
{
u32 val;
val = priv->read_reg(priv, index);
val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
return val;
}
static void c_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
{
priv->write_reg(priv, index + 1, val >> 16);
priv->write_reg(priv, index, val);
}
static u32 d_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
{
return readl(priv->base + priv->regs[index]);
}
static void d_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
{
writel(val, priv->base + priv->regs[index]);
}
static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask)
{
while (priv->read_reg32(priv, C_CAN_FUNCTION_REG) & mask)
udelay(1);
}
static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
{
u32 ctrl;
ctrl = priv->read_reg32(priv, C_CAN_FUNCTION_REG);
ctrl &= ~DCAN_RAM_INIT_BIT;
priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl);
c_can_hw_raminit_wait(priv, ctrl);
if (enable) {
ctrl |= DCAN_RAM_INIT_BIT;
priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl);
c_can_hw_raminit_wait(priv, ctrl);
}
}
static struct platform_device_id c_can_id_table[] = {
[BOSCH_C_CAN_PLATFORM] = {
.name = KBUILD_MODNAME,
@ -201,11 +252,15 @@ static int c_can_plat_probe(struct platform_device *pdev)
case IORESOURCE_MEM_32BIT:
priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
priv->read_reg32 = c_can_plat_read_reg32;
priv->write_reg32 = c_can_plat_write_reg32;
break;
case IORESOURCE_MEM_16BIT:
default:
priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
priv->read_reg32 = c_can_plat_read_reg32;
priv->write_reg32 = c_can_plat_write_reg32;
break;
}
break;
@ -214,6 +269,8 @@ static int c_can_plat_probe(struct platform_device *pdev)
priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
priv->read_reg32 = d_can_plat_read_reg32;
priv->write_reg32 = d_can_plat_write_reg32;
if (pdev->dev.of_node)
priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
@ -221,11 +278,20 @@ static int c_can_plat_probe(struct platform_device *pdev)
priv->instance = pdev->id;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
/* Not all D_CAN modules have a separate register for the D_CAN
* RAM initialization. Use default RAM init bit in D_CAN module
* if not specified in DT.
*/
if (!res) {
priv->raminit = c_can_hw_raminit;
break;
}
priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0)
dev_info(&pdev->dev, "control memory is not used for raminit\n");
else
priv->raminit = c_can_hw_raminit;
priv->raminit = c_can_hw_raminit_ti;
break;
default:
ret = -EINVAL;

View File

@ -1,5 +1,5 @@
config CAN_MSCAN
depends on PPC || M68K
depends on PPC
tristate "Support for Freescale MSCAN based chips"
---help---
The Motorola Scalable Controller Area Network (MSCAN) definition

View File

@ -0,0 +1,876 @@
/* Renesas R-Car CAN device driver
*
* Copyright (C) 2013 Cogent Embedded, Inc. <source@cogentembedded.com>
* Copyright (C) 2013 Renesas Solutions Corp.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/can/led.h>
#include <linux/can/dev.h>
#include <linux/clk.h>
#include <linux/can/platform/rcar_can.h>
#define RCAR_CAN_DRV_NAME "rcar_can"
/* Mailbox configuration:
* mailbox 60 - 63 - Rx FIFO mailboxes
* mailbox 56 - 59 - Tx FIFO mailboxes
* non-FIFO mailboxes are not used
*/
#define RCAR_CAN_N_MBX 64 /* Number of mailboxes in non-FIFO mode */
#define RCAR_CAN_RX_FIFO_MBX 60 /* Mailbox - window to Rx FIFO */
#define RCAR_CAN_TX_FIFO_MBX 56 /* Mailbox - window to Tx FIFO */
#define RCAR_CAN_FIFO_DEPTH 4
/* Mailbox registers structure */
struct rcar_can_mbox_regs {
u32 id; /* IDE and RTR bits, SID and EID */
u8 stub; /* Not used */
u8 dlc; /* Data Length Code - bits [0..3] */
u8 data[8]; /* Data Bytes */
u8 tsh; /* Time Stamp Higher Byte */
u8 tsl; /* Time Stamp Lower Byte */
};
struct rcar_can_regs {
struct rcar_can_mbox_regs mb[RCAR_CAN_N_MBX]; /* Mailbox registers */
u32 mkr_2_9[8]; /* Mask Registers 2-9 */
u32 fidcr[2]; /* FIFO Received ID Compare Register */
u32 mkivlr1; /* Mask Invalid Register 1 */
u32 mier1; /* Mailbox Interrupt Enable Register 1 */
u32 mkr_0_1[2]; /* Mask Registers 0-1 */
u32 mkivlr0; /* Mask Invalid Register 0*/
u32 mier0; /* Mailbox Interrupt Enable Register 0 */
u8 pad_440[0x3c0];
u8 mctl[64]; /* Message Control Registers */
u16 ctlr; /* Control Register */
u16 str; /* Status register */
u8 bcr[3]; /* Bit Configuration Register */
u8 clkr; /* Clock Select Register */
u8 rfcr; /* Receive FIFO Control Register */
u8 rfpcr; /* Receive FIFO Pointer Control Register */
u8 tfcr; /* Transmit FIFO Control Register */
u8 tfpcr; /* Transmit FIFO Pointer Control Register */
u8 eier; /* Error Interrupt Enable Register */
u8 eifr; /* Error Interrupt Factor Judge Register */
u8 recr; /* Receive Error Count Register */
u8 tecr; /* Transmit Error Count Register */
u8 ecsr; /* Error Code Store Register */
u8 cssr; /* Channel Search Support Register */
u8 mssr; /* Mailbox Search Status Register */
u8 msmr; /* Mailbox Search Mode Register */
u16 tsr; /* Time Stamp Register */
u8 afsr; /* Acceptance Filter Support Register */
u8 pad_857;
u8 tcr; /* Test Control Register */
u8 pad_859[7];
u8 ier; /* Interrupt Enable Register */
u8 isr; /* Interrupt Status Register */
u8 pad_862;
u8 mbsmr; /* Mailbox Search Mask Register */
};
struct rcar_can_priv {
struct can_priv can; /* Must be the first member! */
struct net_device *ndev;
struct napi_struct napi;
struct rcar_can_regs __iomem *regs;
struct clk *clk;
u8 tx_dlc[RCAR_CAN_FIFO_DEPTH];
u32 tx_head;
u32 tx_tail;
u8 clock_select;
u8 ier;
};
static const struct can_bittiming_const rcar_can_bittiming_const = {
.name = RCAR_CAN_DRV_NAME,
.tseg1_min = 4,
.tseg1_max = 16,
.tseg2_min = 2,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 1024,
.brp_inc = 1,
};
/* Control Register bits */
#define RCAR_CAN_CTLR_BOM (3 << 11) /* Bus-Off Recovery Mode Bits */
#define RCAR_CAN_CTLR_BOM_ENT (1 << 11) /* Entry to halt mode */
/* at bus-off entry */
#define RCAR_CAN_CTLR_SLPM (1 << 10)
#define RCAR_CAN_CTLR_CANM (3 << 8) /* Operating Mode Select Bit */
#define RCAR_CAN_CTLR_CANM_HALT (1 << 9)
#define RCAR_CAN_CTLR_CANM_RESET (1 << 8)
#define RCAR_CAN_CTLR_CANM_FORCE_RESET (3 << 8)
#define RCAR_CAN_CTLR_MLM (1 << 3) /* Message Lost Mode Select */
#define RCAR_CAN_CTLR_IDFM (3 << 1) /* ID Format Mode Select Bits */
#define RCAR_CAN_CTLR_IDFM_MIXED (1 << 2) /* Mixed ID mode */
#define RCAR_CAN_CTLR_MBM (1 << 0) /* Mailbox Mode select */
/* Status Register bits */
#define RCAR_CAN_STR_RSTST (1 << 8) /* Reset Status Bit */
/* FIFO Received ID Compare Registers 0 and 1 bits */
#define RCAR_CAN_FIDCR_IDE (1 << 31) /* ID Extension Bit */
#define RCAR_CAN_FIDCR_RTR (1 << 30) /* Remote Transmission Request Bit */
/* Receive FIFO Control Register bits */
#define RCAR_CAN_RFCR_RFEST (1 << 7) /* Receive FIFO Empty Status Flag */
#define RCAR_CAN_RFCR_RFE (1 << 0) /* Receive FIFO Enable */
/* Transmit FIFO Control Register bits */
#define RCAR_CAN_TFCR_TFUST (7 << 1) /* Transmit FIFO Unsent Message */
/* Number Status Bits */
#define RCAR_CAN_TFCR_TFUST_SHIFT 1 /* Offset of Transmit FIFO Unsent */
/* Message Number Status Bits */
#define RCAR_CAN_TFCR_TFE (1 << 0) /* Transmit FIFO Enable */
#define RCAR_CAN_N_RX_MKREGS1 2 /* Number of mask registers */
/* for Rx mailboxes 0-31 */
#define RCAR_CAN_N_RX_MKREGS2 8
/* Bit Configuration Register settings */
#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20)
#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8)
#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4)
#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07)
/* Mailbox and Mask Registers bits */
#define RCAR_CAN_IDE (1 << 31)
#define RCAR_CAN_RTR (1 << 30)
#define RCAR_CAN_SID_SHIFT 18
/* Mailbox Interrupt Enable Register 1 bits */
#define RCAR_CAN_MIER1_RXFIE (1 << 28) /* Receive FIFO Interrupt Enable */
#define RCAR_CAN_MIER1_TXFIE (1 << 24) /* Transmit FIFO Interrupt Enable */
/* Interrupt Enable Register bits */
#define RCAR_CAN_IER_ERSIE (1 << 5) /* Error (ERS) Interrupt Enable Bit */
#define RCAR_CAN_IER_RXFIE (1 << 4) /* Reception FIFO Interrupt */
/* Enable Bit */
#define RCAR_CAN_IER_TXFIE (1 << 3) /* Transmission FIFO Interrupt */
/* Enable Bit */
/* Interrupt Status Register bits */
#define RCAR_CAN_ISR_ERSF (1 << 5) /* Error (ERS) Interrupt Status Bit */
#define RCAR_CAN_ISR_RXFF (1 << 4) /* Reception FIFO Interrupt */
/* Status Bit */
#define RCAR_CAN_ISR_TXFF (1 << 3) /* Transmission FIFO Interrupt */
/* Status Bit */
/* Error Interrupt Enable Register bits */
#define RCAR_CAN_EIER_BLIE (1 << 7) /* Bus Lock Interrupt Enable */
#define RCAR_CAN_EIER_OLIE (1 << 6) /* Overload Frame Transmit */
/* Interrupt Enable */
#define RCAR_CAN_EIER_ORIE (1 << 5) /* Receive Overrun Interrupt Enable */
#define RCAR_CAN_EIER_BORIE (1 << 4) /* Bus-Off Recovery Interrupt Enable */
#define RCAR_CAN_EIER_BOEIE (1 << 3) /* Bus-Off Entry Interrupt Enable */
#define RCAR_CAN_EIER_EPIE (1 << 2) /* Error Passive Interrupt Enable */
#define RCAR_CAN_EIER_EWIE (1 << 1) /* Error Warning Interrupt Enable */
#define RCAR_CAN_EIER_BEIE (1 << 0) /* Bus Error Interrupt Enable */
/* Error Interrupt Factor Judge Register bits */
#define RCAR_CAN_EIFR_BLIF (1 << 7) /* Bus Lock Detect Flag */
#define RCAR_CAN_EIFR_OLIF (1 << 6) /* Overload Frame Transmission */
/* Detect Flag */
#define RCAR_CAN_EIFR_ORIF (1 << 5) /* Receive Overrun Detect Flag */
#define RCAR_CAN_EIFR_BORIF (1 << 4) /* Bus-Off Recovery Detect Flag */
#define RCAR_CAN_EIFR_BOEIF (1 << 3) /* Bus-Off Entry Detect Flag */
#define RCAR_CAN_EIFR_EPIF (1 << 2) /* Error Passive Detect Flag */
#define RCAR_CAN_EIFR_EWIF (1 << 1) /* Error Warning Detect Flag */
#define RCAR_CAN_EIFR_BEIF (1 << 0) /* Bus Error Detect Flag */
/* Error Code Store Register bits */
#define RCAR_CAN_ECSR_EDPM (1 << 7) /* Error Display Mode Select Bit */
#define RCAR_CAN_ECSR_ADEF (1 << 6) /* ACK Delimiter Error Flag */
#define RCAR_CAN_ECSR_BE0F (1 << 5) /* Bit Error (dominant) Flag */
#define RCAR_CAN_ECSR_BE1F (1 << 4) /* Bit Error (recessive) Flag */
#define RCAR_CAN_ECSR_CEF (1 << 3) /* CRC Error Flag */
#define RCAR_CAN_ECSR_AEF (1 << 2) /* ACK Error Flag */
#define RCAR_CAN_ECSR_FEF (1 << 1) /* Form Error Flag */
#define RCAR_CAN_ECSR_SEF (1 << 0) /* Stuff Error Flag */
#define RCAR_CAN_NAPI_WEIGHT 4
#define MAX_STR_READS 0x100
static void tx_failure_cleanup(struct net_device *ndev)
{
int i;
for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++)
can_free_echo_skb(ndev, i);
}
static void rcar_can_error(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u8 eifr, txerr = 0, rxerr = 0;
/* Propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(ndev, &cf);
eifr = readb(&priv->regs->eifr);
if (eifr & (RCAR_CAN_EIFR_EWIF | RCAR_CAN_EIFR_EPIF)) {
txerr = readb(&priv->regs->tecr);
rxerr = readb(&priv->regs->recr);
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
}
if (eifr & RCAR_CAN_EIFR_BEIF) {
int rx_errors = 0, tx_errors = 0;
u8 ecsr;
netdev_dbg(priv->ndev, "Bus error interrupt:\n");
if (skb) {
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_UNSPEC;
}
ecsr = readb(&priv->regs->ecsr);
if (ecsr & RCAR_CAN_ECSR_ADEF) {
netdev_dbg(priv->ndev, "ACK Delimiter Error\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr);
if (skb)
cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL;
}
if (ecsr & RCAR_CAN_ECSR_BE0F) {
netdev_dbg(priv->ndev, "Bit Error (dominant)\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_BE0F, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_BIT0;
}
if (ecsr & RCAR_CAN_ECSR_BE1F) {
netdev_dbg(priv->ndev, "Bit Error (recessive)\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_BE1F, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_BIT1;
}
if (ecsr & RCAR_CAN_ECSR_CEF) {
netdev_dbg(priv->ndev, "CRC Error\n");
rx_errors++;
writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr);
if (skb)
cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
}
if (ecsr & RCAR_CAN_ECSR_AEF) {
netdev_dbg(priv->ndev, "ACK Error\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr);
if (skb) {
cf->can_id |= CAN_ERR_ACK;
cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
}
}
if (ecsr & RCAR_CAN_ECSR_FEF) {
netdev_dbg(priv->ndev, "Form Error\n");
rx_errors++;
writeb(~RCAR_CAN_ECSR_FEF, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_FORM;
}
if (ecsr & RCAR_CAN_ECSR_SEF) {
netdev_dbg(priv->ndev, "Stuff Error\n");
rx_errors++;
writeb(~RCAR_CAN_ECSR_SEF, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_STUFF;
}
priv->can.can_stats.bus_error++;
ndev->stats.rx_errors += rx_errors;
ndev->stats.tx_errors += tx_errors;
writeb(~RCAR_CAN_EIFR_BEIF, &priv->regs->eifr);
}
if (eifr & RCAR_CAN_EIFR_EWIF) {
netdev_dbg(priv->ndev, "Error warning interrupt\n");
priv->can.state = CAN_STATE_ERROR_WARNING;
priv->can.can_stats.error_warning++;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_EWIF, &priv->regs->eifr);
if (skb)
cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
}
if (eifr & RCAR_CAN_EIFR_EPIF) {
netdev_dbg(priv->ndev, "Error passive interrupt\n");
priv->can.state = CAN_STATE_ERROR_PASSIVE;
priv->can.can_stats.error_passive++;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_EPIF, &priv->regs->eifr);
if (skb)
cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
}
if (eifr & RCAR_CAN_EIFR_BOEIF) {
netdev_dbg(priv->ndev, "Bus-off entry interrupt\n");
tx_failure_cleanup(ndev);
priv->ier = RCAR_CAN_IER_ERSIE;
writeb(priv->ier, &priv->regs->ier);
priv->can.state = CAN_STATE_BUS_OFF;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr);
can_bus_off(ndev);
if (skb)
cf->can_id |= CAN_ERR_BUSOFF;
}
if (eifr & RCAR_CAN_EIFR_ORIF) {
netdev_dbg(priv->ndev, "Receive overrun error interrupt\n");
ndev->stats.rx_over_errors++;
ndev->stats.rx_errors++;
writeb(~RCAR_CAN_EIFR_ORIF, &priv->regs->eifr);
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
}
}
if (eifr & RCAR_CAN_EIFR_OLIF) {
netdev_dbg(priv->ndev,
"Overload Frame Transmission error interrupt\n");
ndev->stats.rx_over_errors++;
ndev->stats.rx_errors++;
writeb(~RCAR_CAN_EIFR_OLIF, &priv->regs->eifr);
if (skb) {
cf->can_id |= CAN_ERR_PROT;
cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
}
}
if (skb) {
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
}
}
static void rcar_can_tx_done(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
u8 isr;
while (1) {
u8 unsent = readb(&priv->regs->tfcr);
unsent = (unsent & RCAR_CAN_TFCR_TFUST) >>
RCAR_CAN_TFCR_TFUST_SHIFT;
if (priv->tx_head - priv->tx_tail <= unsent)
break;
stats->tx_packets++;
stats->tx_bytes += priv->tx_dlc[priv->tx_tail %
RCAR_CAN_FIFO_DEPTH];
priv->tx_dlc[priv->tx_tail % RCAR_CAN_FIFO_DEPTH] = 0;
can_get_echo_skb(ndev, priv->tx_tail % RCAR_CAN_FIFO_DEPTH);
priv->tx_tail++;
netif_wake_queue(ndev);
}
/* Clear interrupt */
isr = readb(&priv->regs->isr);
writeb(isr & ~RCAR_CAN_ISR_TXFF, &priv->regs->isr);
can_led_event(ndev, CAN_LED_EVENT_TX);
}
static irqreturn_t rcar_can_interrupt(int irq, void *dev_id)
{
struct net_device *ndev = dev_id;
struct rcar_can_priv *priv = netdev_priv(ndev);
u8 isr;
isr = readb(&priv->regs->isr);
if (!(isr & priv->ier))
return IRQ_NONE;
if (isr & RCAR_CAN_ISR_ERSF)
rcar_can_error(ndev);
if (isr & RCAR_CAN_ISR_TXFF)
rcar_can_tx_done(ndev);
if (isr & RCAR_CAN_ISR_RXFF) {
if (napi_schedule_prep(&priv->napi)) {
/* Disable Rx FIFO interrupts */
priv->ier &= ~RCAR_CAN_IER_RXFIE;
writeb(priv->ier, &priv->regs->ier);
__napi_schedule(&priv->napi);
}
}
return IRQ_HANDLED;
}
static void rcar_can_set_bittiming(struct net_device *dev)
{
struct rcar_can_priv *priv = netdev_priv(dev);
struct can_bittiming *bt = &priv->can.bittiming;
u32 bcr;
bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
RCAR_CAN_BCR_BPR(bt->brp - 1) | RCAR_CAN_BCR_SJW(bt->sjw - 1) |
RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1);
/* Don't overwrite CLKR with 32-bit BCR access; CLKR has 8-bit access.
* All the registers are big-endian but they get byte-swapped on 32-bit
* read/write (but not on 8-bit, contrary to the manuals)...
*/
writel((bcr << 8) | priv->clock_select, &priv->regs->bcr);
}
static void rcar_can_start(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
int i;
/* Set controller to known mode:
* - FIFO mailbox mode
* - accept all messages
* - overrun mode
* CAN is in sleep mode after MCU hardware or software reset.
*/
ctlr = readw(&priv->regs->ctlr);
ctlr &= ~RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
/* Go to reset mode */
ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET;
writew(ctlr, &priv->regs->ctlr);
for (i = 0; i < MAX_STR_READS; i++) {
if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)
break;
}
rcar_can_set_bittiming(ndev);
ctlr |= RCAR_CAN_CTLR_IDFM_MIXED; /* Select mixed ID mode */
ctlr |= RCAR_CAN_CTLR_BOM_ENT; /* Entry to halt mode automatically */
/* at bus-off */
ctlr |= RCAR_CAN_CTLR_MBM; /* Select FIFO mailbox mode */
ctlr |= RCAR_CAN_CTLR_MLM; /* Overrun mode */
writew(ctlr, &priv->regs->ctlr);
/* Accept all SID and EID */
writel(0, &priv->regs->mkr_2_9[6]);
writel(0, &priv->regs->mkr_2_9[7]);
/* In FIFO mailbox mode, write "0" to bits 24 to 31 */
writel(0, &priv->regs->mkivlr1);
/* Accept all frames */
writel(0, &priv->regs->fidcr[0]);
writel(RCAR_CAN_FIDCR_IDE | RCAR_CAN_FIDCR_RTR, &priv->regs->fidcr[1]);
/* Enable and configure FIFO mailbox interrupts */
writel(RCAR_CAN_MIER1_RXFIE | RCAR_CAN_MIER1_TXFIE, &priv->regs->mier1);
priv->ier = RCAR_CAN_IER_ERSIE | RCAR_CAN_IER_RXFIE |
RCAR_CAN_IER_TXFIE;
writeb(priv->ier, &priv->regs->ier);
/* Accumulate error codes */
writeb(RCAR_CAN_ECSR_EDPM, &priv->regs->ecsr);
/* Enable error interrupts */
writeb(RCAR_CAN_EIER_EWIE | RCAR_CAN_EIER_EPIE | RCAR_CAN_EIER_BOEIE |
(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING ?
RCAR_CAN_EIER_BEIE : 0) | RCAR_CAN_EIER_ORIE |
RCAR_CAN_EIER_OLIE, &priv->regs->eier);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* Go to operation mode */
writew(ctlr & ~RCAR_CAN_CTLR_CANM, &priv->regs->ctlr);
for (i = 0; i < MAX_STR_READS; i++) {
if (!(readw(&priv->regs->str) & RCAR_CAN_STR_RSTST))
break;
}
/* Enable Rx and Tx FIFO */
writeb(RCAR_CAN_RFCR_RFE, &priv->regs->rfcr);
writeb(RCAR_CAN_TFCR_TFE, &priv->regs->tfcr);
}
static int rcar_can_open(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
int err;
err = clk_prepare_enable(priv->clk);
if (err) {
netdev_err(ndev, "clk_prepare_enable() failed, error %d\n",
err);
goto out;
}
err = open_candev(ndev);
if (err) {
netdev_err(ndev, "open_candev() failed, error %d\n", err);
goto out_clock;
}
napi_enable(&priv->napi);
err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
if (err) {
netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq);
goto out_close;
}
can_led_event(ndev, CAN_LED_EVENT_OPEN);
rcar_can_start(ndev);
netif_start_queue(ndev);
return 0;
out_close:
napi_disable(&priv->napi);
close_candev(ndev);
out_clock:
clk_disable_unprepare(priv->clk);
out:
return err;
}
static void rcar_can_stop(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
int i;
/* Go to (force) reset mode */
ctlr = readw(&priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET;
writew(ctlr, &priv->regs->ctlr);
for (i = 0; i < MAX_STR_READS; i++) {
if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)
break;
}
writel(0, &priv->regs->mier0);
writel(0, &priv->regs->mier1);
writeb(0, &priv->regs->ier);
writeb(0, &priv->regs->eier);
/* Go to sleep mode */
ctlr |= RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_STOPPED;
}
static int rcar_can_close(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev);
rcar_can_stop(ndev);
free_irq(ndev->irq, ndev);
napi_disable(&priv->napi);
clk_disable_unprepare(priv->clk);
close_candev(ndev);
can_led_event(ndev, CAN_LED_EVENT_STOP);
return 0;
}
static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
struct can_frame *cf = (struct can_frame *)skb->data;
u32 data, i;
if (can_dropped_invalid_skb(ndev, skb))
return NETDEV_TX_OK;
if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE;
else /* Standard frame format */
data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT;
if (cf->can_id & CAN_RTR_FLAG) { /* Remote transmission request */
data |= RCAR_CAN_RTR;
} else {
for (i = 0; i < cf->can_dlc; i++)
writeb(cf->data[i],
&priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].data[i]);
}
writel(data, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].id);
writeb(cf->can_dlc, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc);
priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->can_dlc;
can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH);
priv->tx_head++;
/* Start Tx: write 0xff to the TFPCR register to increment
* the CPU-side pointer for the transmit FIFO to the next
* mailbox location
*/
writeb(0xff, &priv->regs->tfpcr);
/* Stop the queue if we've filled all FIFO entries */
if (priv->tx_head - priv->tx_tail >= RCAR_CAN_FIFO_DEPTH)
netif_stop_queue(ndev);
return NETDEV_TX_OK;
}
static const struct net_device_ops rcar_can_netdev_ops = {
.ndo_open = rcar_can_open,
.ndo_stop = rcar_can_close,
.ndo_start_xmit = rcar_can_start_xmit,
};
static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
{
struct net_device_stats *stats = &priv->ndev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u32 data;
u8 dlc;
skb = alloc_can_skb(priv->ndev, &cf);
if (!skb) {
stats->rx_dropped++;
return;
}
data = readl(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].id);
if (data & RCAR_CAN_IDE)
cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK;
dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc);
cf->can_dlc = get_can_dlc(dlc);
if (data & RCAR_CAN_RTR) {
cf->can_id |= CAN_RTR_FLAG;
} else {
for (dlc = 0; dlc < cf->can_dlc; dlc++)
cf->data[dlc] =
readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].data[dlc]);
}
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
stats->rx_bytes += cf->can_dlc;
stats->rx_packets++;
netif_receive_skb(skb);
}
static int rcar_can_rx_poll(struct napi_struct *napi, int quota)
{
struct rcar_can_priv *priv = container_of(napi,
struct rcar_can_priv, napi);
int num_pkts;
for (num_pkts = 0; num_pkts < quota; num_pkts++) {
u8 rfcr, isr;
isr = readb(&priv->regs->isr);
/* Clear interrupt bit */
if (isr & RCAR_CAN_ISR_RXFF)
writeb(isr & ~RCAR_CAN_ISR_RXFF, &priv->regs->isr);
rfcr = readb(&priv->regs->rfcr);
if (rfcr & RCAR_CAN_RFCR_RFEST)
break;
rcar_can_rx_pkt(priv);
/* Write 0xff to the RFPCR register to increment
* the CPU-side pointer for the receive FIFO
* to the next mailbox location
*/
writeb(0xff, &priv->regs->rfpcr);
}
/* All packets processed */
if (num_pkts < quota) {
napi_complete(napi);
priv->ier |= RCAR_CAN_IER_RXFIE;
writeb(priv->ier, &priv->regs->ier);
}
return num_pkts;
}
static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
{
switch (mode) {
case CAN_MODE_START:
rcar_can_start(ndev);
netif_wake_queue(ndev);
return 0;
default:
return -EOPNOTSUPP;
}
}
static int rcar_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct rcar_can_priv *priv = netdev_priv(dev);
int err;
err = clk_prepare_enable(priv->clk);
if (err)
return err;
bec->txerr = readb(&priv->regs->tecr);
bec->rxerr = readb(&priv->regs->recr);
clk_disable_unprepare(priv->clk);
return 0;
}
static int rcar_can_probe(struct platform_device *pdev)
{
struct rcar_can_platform_data *pdata;
struct rcar_can_priv *priv;
struct net_device *ndev;
struct resource *mem;
void __iomem *addr;
int err = -ENODEV;
int irq;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform data provided!\n");
goto fail;
}
irq = platform_get_irq(pdev, 0);
if (!irq) {
dev_err(&pdev->dev, "No IRQ resource\n");
goto fail;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) {
err = PTR_ERR(addr);
goto fail;
}
ndev = alloc_candev(sizeof(struct rcar_can_priv), RCAR_CAN_FIFO_DEPTH);
if (!ndev) {
dev_err(&pdev->dev, "alloc_candev() failed\n");
err = -ENOMEM;
goto fail;
}
priv = netdev_priv(ndev);
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
err = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", err);
goto fail_clk;
}
ndev->netdev_ops = &rcar_can_netdev_ops;
ndev->irq = irq;
ndev->flags |= IFF_ECHO;
priv->ndev = ndev;
priv->regs = addr;
priv->clock_select = pdata->clock_select;
priv->can.clock.freq = clk_get_rate(priv->clk);
priv->can.bittiming_const = &rcar_can_bittiming_const;
priv->can.do_set_mode = rcar_can_do_set_mode;
priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll,
RCAR_CAN_NAPI_WEIGHT);
err = register_candev(ndev);
if (err) {
dev_err(&pdev->dev, "register_candev() failed, error %d\n",
err);
goto fail_candev;
}
devm_can_led_init(ndev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->regs, ndev->irq);
return 0;
fail_candev:
netif_napi_del(&priv->napi);
fail_clk:
free_candev(ndev);
fail:
return err;
}
static int rcar_can_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct rcar_can_priv *priv = netdev_priv(ndev);
unregister_candev(ndev);
netif_napi_del(&priv->napi);
free_candev(ndev);
return 0;
}
static int __maybe_unused rcar_can_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
if (netif_running(ndev)) {
netif_stop_queue(ndev);
netif_device_detach(ndev);
}
ctlr = readw(&priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_CANM_HALT;
writew(ctlr, &priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_SLEEPING;
clk_disable(priv->clk);
return 0;
}
static int __maybe_unused rcar_can_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
int err;
err = clk_enable(priv->clk);
if (err) {
netdev_err(ndev, "clk_enable() failed, error %d\n", err);
return err;
}
ctlr = readw(&priv->regs->ctlr);
ctlr &= ~RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
ctlr &= ~RCAR_CAN_CTLR_CANM;
writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) {
netif_device_attach(ndev);
netif_start_queue(ndev);
}
return 0;
}
static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume);
static struct platform_driver rcar_can_driver = {
.driver = {
.name = RCAR_CAN_DRV_NAME,
.owner = THIS_MODULE,
.pm = &rcar_can_pm_ops,
},
.probe = rcar_can_probe,
.remove = rcar_can_remove,
};
module_platform_driver(rcar_can_driver);
MODULE_AUTHOR("Cogent Embedded, Inc.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CAN driver for Renesas R-Car SoC");
MODULE_ALIAS("platform:" RCAR_CAN_DRV_NAME);

View File

@ -556,15 +556,6 @@ failed:
/*
* netdev sysfs
*/
static ssize_t show_channel(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "%i\n", priv->index);
}
static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -609,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr,
return count;
}
static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
static const struct attribute *const netdev_sysfs_attrs[] = {
&dev_attr_channel.attr,
&dev_attr_chip.attr,
&dev_attr_output.attr,
NULL,
@ -679,17 +668,20 @@ static int softing_netdev_register(struct net_device *netdev)
{
int ret;
netdev->sysfs_groups[0] = &netdev_sysfs_group;
ret = register_candev(netdev);
if (ret) {
dev_alert(&netdev->dev, "register failed\n");
return ret;
}
if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0)
netdev_alert(netdev, "sysfs group failed\n");
return 0;
}
static void softing_netdev_cleanup(struct net_device *netdev)
{
sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group);
unregister_candev(netdev);
free_candev(netdev);
}
@ -721,8 +713,6 @@ DEV_ATTR_RO(firmware_version, id.fw_version);
DEV_ATTR_RO_STR(hardware, pdat->name);
DEV_ATTR_RO(hardware_version, id.hw_version);
DEV_ATTR_RO(license, id.license);
DEV_ATTR_RO(frequency, id.freq);
DEV_ATTR_RO(txpending, tx.pending);
static struct attribute *softing_pdev_attrs[] = {
&dev_attr_serial.attr,
@ -731,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = {
&dev_attr_hardware.attr,
&dev_attr_hardware_version.attr,
&dev_attr_license.attr,
&dev_attr_frequency.attr,
&dev_attr_txpending.attr,
NULL,
};

View File

@ -0,0 +1,10 @@
menu "CAN SPI interfaces"
depends on SPI
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
endmenu

View File

@ -0,0 +1,8 @@
#
# Makefile for the Linux Controller Area Network SPI drivers.
#
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG

View File

@ -214,6 +214,8 @@
#define TX_ECHO_SKB_MAX 1
#define MCP251X_OST_DELAY_MS (5)
#define DEVICE_NAME "mcp251x"
static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
@ -624,50 +626,45 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
static int mcp251x_hw_reset(struct spi_device *spi)
{
struct mcp251x_priv *priv = spi_get_drvdata(spi);
u8 reg;
int ret;
unsigned long timeout;
/* Wait for oscillator startup timer after power up */
mdelay(MCP251X_OST_DELAY_MS);
priv->spi_tx_buf[0] = INSTRUCTION_RESET;
ret = spi_write(spi, priv->spi_tx_buf, 1);
if (ret) {
dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
return -EIO;
}
ret = mcp251x_spi_trans(spi, 1);
if (ret)
return ret;
/* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
reg = mcp251x_read_reg(spi, CANSTAT);
if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
return -ENODEV;
/* Wait for reset to finish */
timeout = jiffies + HZ;
mdelay(10);
while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)
!= CANCTRL_REQOP_CONF) {
schedule();
if (time_after(jiffies, timeout)) {
dev_err(&spi->dev, "MCP251x didn't"
" enter in conf mode after reset\n");
return -EBUSY;
}
}
return 0;
}
static int mcp251x_hw_probe(struct spi_device *spi)
{
int st1, st2;
u8 ctrl;
int ret;
mcp251x_hw_reset(spi);
ret = mcp251x_hw_reset(spi);
if (ret)
return ret;
/*
* Please note that these are "magic values" based on after
* reset defaults taken from data sheet which allows us to see
* if we really have a chip on the bus (we avoid common all
* zeroes or all ones situations)
*/
st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
ctrl = mcp251x_read_reg(spi, CANCTRL);
dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
dev_dbg(&spi->dev, "CANCTRL 0x%02x\n", ctrl);
/* Check for power up default values */
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
/* Check for power up default value */
if ((ctrl & 0x17) != 0x07)
return -ENODEV;
return 0;
}
static int mcp251x_power_enable(struct regulator *reg, int enable)
@ -776,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) {
mdelay(10);
mcp251x_hw_reset(spi);
mcp251x_setup(net, priv, spi);
if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
@ -955,7 +951,7 @@ static int mcp251x_open(struct net_device *net)
priv->tx_len = 0;
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
flags, DEVICE_NAME, priv);
flags | IRQF_ONESHOT, DEVICE_NAME, priv);
if (ret) {
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
mcp251x_power_enable(priv->transceiver, 0);
@ -1032,8 +1028,8 @@ static int mcp251x_can_probe(struct spi_device *spi)
struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
struct net_device *net;
struct mcp251x_priv *priv;
int freq, ret = -ENODEV;
struct clk *clk;
int freq, ret;
clk = devm_clk_get(&spi->dev, NULL);
if (IS_ERR(clk)) {
@ -1076,6 +1072,18 @@ static int mcp251x_can_probe(struct spi_device *spi)
priv->net = net;
priv->clk = clk;
spi_set_drvdata(spi, priv);
/* Configure the SPI bus */
spi->bits_per_word = 8;
if (mcp251x_is_2510(spi))
spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
else
spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
ret = spi_setup(spi);
if (ret)
goto out_clk;
priv->power = devm_regulator_get(&spi->dev, "vdd");
priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
@ -1088,8 +1096,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
if (ret)
goto out_clk;
spi_set_drvdata(spi, priv);
priv->spi = spi;
mutex_init(&priv->mcp_lock);
@ -1134,20 +1140,11 @@ static int mcp251x_can_probe(struct spi_device *spi)
SET_NETDEV_DEV(net, &spi->dev);
/* Configure the SPI bus */
spi->mode = spi->mode ? : SPI_MODE_0;
if (mcp251x_is_2510(spi))
spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
else
spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
spi->bits_per_word = 8;
spi_setup(spi);
/* Here is OK to not lock the MCP, no one knows about it yet */
if (!mcp251x_hw_probe(spi)) {
ret = -ENODEV;
ret = mcp251x_hw_probe(spi);
if (ret)
goto error_probe;
}
mcp251x_hw_sleep(spi);
ret = register_candev(net);
@ -1156,7 +1153,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
devm_can_led_init(net);
return ret;
return 0;
error_probe:
if (mcp251x_enable_dma)

View File

@ -13,13 +13,21 @@ config CAN_ESD_USB2
This driver supports the CAN-USB/2 interface
from esd electronic system design gmbh (http://www.esd.eu).
config CAN_GS_USB
tristate "Geschwister Schneider UG interfaces"
---help---
This driver supports the Geschwister Schneider USB/CAN devices.
If unsure choose N,
choose Y for built in support,
M to compile as module (module will be named: gs_usb).
config CAN_KVASER_USB
tristate "Kvaser CAN/USB interface"
---help---
This driver adds support for Kvaser CAN/USB devices like Kvaser
Leaf Light.
The driver gives support for the following devices:
The driver provides support for the following devices:
- Kvaser Leaf Light
- Kvaser Leaf Professional HS
- Kvaser Leaf SemiPro HS
@ -36,6 +44,8 @@ config CAN_KVASER_USB
- Kvaser Leaf Light "China"
- Kvaser BlackBird SemiPro
- Kvaser USBcan R
- Kvaser Leaf Light v2
- Kvaser Mini PCI Express HS
If unsure, say N.

Some files were not shown because too many files have changed in this diff Show More