mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 09:00:52 +07:00
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 ...
This commit is contained in:
commit
f9da455b93
@ -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
|
||||
|
149
Documentation/ABI/testing/sysfs-class-net-cdc_ncm
Normal file
149
Documentation/ABI/testing/sysfs-class-net-cdc_ncm
Normal 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.
|
79
Documentation/ABI/testing/sysfs-class-net-queues
Normal file
79
Documentation/ABI/testing/sysfs-class-net-queues
Normal 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.
|
201
Documentation/ABI/testing/sysfs-class-net-statistics
Normal file
201
Documentation/ABI/testing/sysfs-class-net-statistics
Normal 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.
|
@ -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>
|
||||
|
17
Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
Normal file
17
Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
Normal 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>;
|
||||
};
|
34
Documentation/devicetree/bindings/net/amd-xgbe.txt
Normal file
34
Documentation/devicetree/bindings/net/amd-xgbe.txt
Normal 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 ];
|
||||
};
|
@ -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:
|
||||
|
@ -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>;
|
||||
};
|
44
Documentation/devicetree/bindings/net/can/xilinx_can.txt
Normal file
44
Documentation/devicetree/bindings/net/can/xilinx_can.txt
Normal 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>;
|
||||
};
|
@ -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
|
||||
|
42
Documentation/devicetree/bindings/net/fixed-link.txt
Normal file
42
Documentation/devicetree/bindings/net/fixed-link.txt
Normal 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;
|
||||
};
|
||||
...
|
||||
};
|
@ -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.
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
@ -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";
|
||||
};
|
83
Documentation/devicetree/bindings/net/micrel-ksz90x1.txt
Normal file
83
Documentation/devicetree/bindings/net/micrel-ksz90x1.txt
Normal 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";
|
||||
};
|
35
Documentation/devicetree/bindings/net/nfc/pn544.txt
Normal file
35
Documentation/devicetree/bindings/net/nfc/pn544.txt
Normal 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>;
|
||||
};
|
||||
};
|
33
Documentation/devicetree/bindings/net/nfc/st21nfca.txt
Normal file
33
Documentation/devicetree/bindings/net/nfc/st21nfca.txt
Normal 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>;
|
||||
};
|
||||
};
|
@ -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";
|
||||
};
|
||||
};
|
||||
|
17
Documentation/devicetree/bindings/net/via-rhine.txt
Normal file
17
Documentation/devicetree/bindings/net/via-rhine.txt
Normal 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>;
|
||||
};
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
339
Documentation/networking/cdc_mbim.txt
Normal file
339
Documentation/networking/cdc_mbim.txt
Normal 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
|
@ -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
|
||||
----
|
||||
|
||||
|
19
MAINTAINERS
19
MAINTAINERS
@ -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>
|
||||
|
@ -662,6 +662,8 @@ ehrpwm2: ehrpwm@48304200 {
|
||||
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>;
|
||||
|
@ -490,6 +490,8 @@ GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH
|
||||
#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>;
|
||||
|
@ -57,6 +57,10 @@ sata@a0000 {
|
||||
ethernet@30000 {
|
||||
status = "okay";
|
||||
phy-mode = "sgmii";
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
pcie-controller {
|
||||
|
@ -165,5 +165,11 @@ rtc@d8100000 {
|
||||
reg = <0xd8100000 0x10000>;
|
||||
interrupts = <48>;
|
||||
};
|
||||
|
||||
ethernet@d8004000 {
|
||||
compatible = "via,vt8500-rhine";
|
||||
reg = <0xd8004000 0x100>;
|
||||
interrupts = <10>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -218,5 +218,11 @@ rtc@d8100000 {
|
||||
reg = <0xd8100000 0x10000>;
|
||||
interrupts = <48>;
|
||||
};
|
||||
|
||||
ethernet@d8004000 {
|
||||
compatible = "via,vt8500-rhine";
|
||||
reg = <0xd8004000 0x100>;
|
||||
interrupts = <10>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -298,5 +298,11 @@ sdhc@d800a000 {
|
||||
bus-width = <4>;
|
||||
sdon-inverted;
|
||||
};
|
||||
|
||||
ethernet@d8004000 {
|
||||
compatible = "via,vt8500-rhine";
|
||||
reg = <0xd8004000 0x100>;
|
||||
interrupts = <10>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
_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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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 @@ static int build_body(struct jit_ctx *ctx)
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 @@ branch: if (filter->jt == filter->jf) {
|
||||
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 @@ branch: if (filter->jt == filter->jf) {
|
||||
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 @@ load_abs: if ((int) K < 0)
|
||||
/* 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 @@ load_abs: if ((int) K < 0)
|
||||
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 @@ load_abs: if ((int) K < 0)
|
||||
/* 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 @@ load_abs: if ((int) K < 0)
|
||||
/* 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 @@ load_abs: if ((int) K < 0)
|
||||
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 @@ load_abs: if ((int) K < 0)
|
||||
/* 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 @@ load_abs: if ((int) K < 0)
|
||||
/* 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 @@ load_abs: if ((int) K < 0)
|
||||
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 @@ load_abs: if ((int) K < 0)
|
||||
/* 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));
|
||||
|
@ -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) */
|
||||
|
@ -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) */
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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
@ -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");
|
||||
|
||||
|
@ -2551,12 +2551,12 @@ idt77252_close(struct atm_vcc *vcc)
|
||||
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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 @@ static int btusb_setup_intel(struct hci_dev *hdev)
|
||||
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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len)
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 "
|
||||
|
@ -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 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
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 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
|
||||
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 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
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);
|
||||
|
@ -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)) {
|
||||
|
@ -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 @@ static int bond_option_slaves_set(struct bonding *bond,
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
876
drivers/net/can/rcar_can.c
Normal file
876
drivers/net/can/rcar_can.c
Normal 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);
|
@ -556,15 +556,6 @@ static int softing_card_boot(struct softing *card)
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
|
||||
|
10
drivers/net/can/spi/Kconfig
Normal file
10
drivers/net/can/spi/Kconfig
Normal 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
|
8
drivers/net/can/spi/Makefile
Normal file
8
drivers/net/can/spi/Makefile
Normal 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
|
@ -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)
|
@ -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
Loading…
Reference in New Issue
Block a user