forked from Minki/linux
Networking changes for 5.13.
Core: - bpf: - allow bpf programs calling kernel functions (initially to reuse TCP congestion control implementations) - enable task local storage for tracing programs - remove the need to store per-task state in hash maps, and allow tracing programs access to task local storage previously added for BPF_LSM - add bpf_for_each_map_elem() helper, allowing programs to walk all map elements in a more robust and easier to verify fashion - sockmap: support UDP and cross-protocol BPF_SK_SKB_VERDICT redirection - lpm: add support for batched ops in LPM trie - add BTF_KIND_FLOAT support - mostly to allow use of BTF on s390 which has floats in its headers files - improve BPF syscall documentation and extend the use of kdoc parsing scripts we already employ for bpf-helpers - libbpf, bpftool: support static linking of BPF ELF files - improve support for encapsulation of L2 packets - xdp: restructure redirect actions to avoid a runtime lookup, improving performance by 4-8% in microbenchmarks - xsk: build skb by page (aka generic zerocopy xmit) - improve performance of software AF_XDP path by 33% for devices which don't need headers in the linear skb part (e.g. virtio) - nexthop: resilient next-hop groups - improve path stability on next-hops group changes (incl. offload for mlxsw) - ipv6: segment routing: add support for IPv4 decapsulation - icmp: add support for RFC 8335 extended PROBE messages - inet: use bigger hash table for IP ID generation - tcp: deal better with delayed TX completions - make sure we don't give up on fast TCP retransmissions only because driver is slow in reporting that it completed transmitting the original - tcp: reorder tcp_congestion_ops for better cache locality - mptcp: - add sockopt support for common TCP options - add support for common TCP msg flags - include multiple address ids in RM_ADDR - add reset option support for resetting one subflow - udp: GRO L4 improvements - improve 'forward' / 'frag_list' co-existence with UDP tunnel GRO, allowing the first to take place correctly even for encapsulated UDP traffic - micro-optimize dev_gro_receive() and flow dissection, avoid retpoline overhead on VLAN and TEB GRO - use less memory for sysctls, add a new sysctl type, to allow using u8 instead of "int" and "long" and shrink networking sysctls - veth: allow GRO without XDP - this allows aggregating UDP packets before handing them off to routing, bridge, OvS, etc. - allow specifing ifindex when device is moved to another namespace - netfilter: - nft_socket: add support for cgroupsv2 - nftables: add catch-all set element - special element used to define a default action in case normal lookup missed - use net_generic infra in many modules to avoid allocating per-ns memory unnecessarily - xps: improve the xps handling to avoid potential out-of-bound accesses and use-after-free when XPS change race with other re-configuration under traffic - add a config knob to turn off per-cpu netdev refcnt to catch underflows in testing Device APIs: - add WWAN subsystem to organize the WWAN interfaces better and hopefully start driving towards more unified and vendor- -independent APIs - ethtool: - add interface for reading IEEE MIB stats (incl. mlx5 and bnxt support) - allow network drivers to dump arbitrary SFP EEPROM data, current offset+length API was a poor fit for modern SFP which define EEPROM in terms of pages (incl. mlx5 support) - act_police, flow_offload: add support for packet-per-second policing (incl. offload for nfp) - psample: add additional metadata attributes like transit delay for packets sampled from switch HW (and corresponding egress and policy-based sampling in the mlxsw driver) - dsa: improve support for sandwiched LAGs with bridge and DSA - netfilter: - flowtable: use direct xmit in topologies with IP forwarding, bridging, vlans etc. - nftables: counter hardware offload support - Bluetooth: - improvements for firmware download w/ Intel devices - add support for reading AOSP vendor capabilities - add support for virtio transport driver - mac80211: - allow concurrent monitor iface and ethernet rx decap - set priority and queue mapping for injected frames - phy: add support for Clause-45 PHY Loopback - pci/iov: add sysfs MSI-X vector assignment interface to distribute MSI-X resources to VFs (incl. mlx5 support) New hardware/drivers: - dsa: mv88e6xxx: add support for Marvell mv88e6393x - 11-port Ethernet switch with 8x 1-Gigabit Ethernet and 3x 10-Gigabit interfaces. - dsa: support for legacy Broadcom tags used on BCM5325, BCM5365 and BCM63xx switches - Microchip KSZ8863 and KSZ8873; 3x 10/100Mbps Ethernet switches - ath11k: support for QCN9074 a 802.11ax device - Bluetooth: Broadcom BCM4330 and BMC4334 - phy: Marvell 88X2222 transceiver support - mdio: add BCM6368 MDIO mux bus controller - r8152: support RTL8153 and RTL8156 (USB Ethernet) chips - mana: driver for Microsoft Azure Network Adapter (MANA) - Actions Semi Owl Ethernet MAC - can: driver for ETAS ES58X CAN/USB interfaces Pure driver changes: - add XDP support to: enetc, igc, stmmac - add AF_XDP support to: stmmac - virtio: - page_to_skb() use build_skb when there's sufficient tailroom (21% improvement for 1000B UDP frames) - support XDP even without dedicated Tx queues - share the Tx queues with the stack when necessary - mlx5: - flow rules: add support for mirroring with conntrack, matching on ICMP, GTP, flex filters and more - support packet sampling with flow offloads - persist uplink representor netdev across eswitch mode changes - allow coexistence of CQE compression and HW time-stamping - add ethtool extended link error state reporting - ice, iavf: support flow filters, UDP Segmentation Offload - dpaa2-switch: - move the driver out of staging - add spanning tree (STP) support - add rx copybreak support - add tc flower hardware offload on ingress traffic - ionic: - implement Rx page reuse - support HW PTP time-stamping - octeon: support TC hardware offloads - flower matching on ingress and egress ratelimitting. - stmmac: - add RX frame steering based on VLAN priority in tc flower - support frame preemption (FPE) - intel: add cross time-stamping freq difference adjustment - ocelot: - support forwarding of MRP frames in HW - support multiple bridges - support PTP Sync one-step timestamping - dsa: mv88e6xxx, dpaa2-switch: offload bridge port flags like learning, flooding etc. - ipa: add IPA v4.5, v4.9 and v4.11 support (Qualcomm SDX55, SM8350, SC7280 SoCs) - mt7601u: enable TDLS support - mt76: - add support for 802.3 rx frames (mt7915/mt7615) - mt7915 flash pre-calibration support - mt7921/mt7663 runtime power management fixes Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmCKFPIACgkQMUZtbf5S Irtw0g/+NA8bWdHNgG4H5rya0pv2z3IieLRmSdDfKRQQXcJpklawc5MKVVaTee/Q 5/QqgPdCsu1LAU6JXBKsKmyDDaMlQKdWuKbOqDSiAQKoMesZStTEHf9d851ZzgxA Cdb6O7BD3lBl/IN+oxNG+KcmD1LKquTPKGySq2mQtEdLO12ekAsranzmj4voKffd q9tBShpXQ7Dq77DLYfiQXVCvsizNcbbJFuxX0o9Lpb9+61ZyYAbogZSa9ypiZZwR I/9azRBtJg7UV1aD/cLuAfy66Qh7t63+rCxVazs5Os8jVO26P/jQdisnnOe/x+p9 wYEmKm3GSu0V4SAPxkWW+ooKusflCeqDoMIuooKt6kbP6BRj540veGw3Ww/m5YFr 7pLQkTSP/tSjuGQIdBE1LOP5LBO8DZeC8Kiop9V0fzAW9hFSZbEq25WW0bPj8QQO zA4Z7yWlslvxcfY2BdJX3wD8klaINkl/8fDWZFFsBdfFX2VeLtm7Xfduw34BJpvU rYT3oWr6PhtkPAKR32SUcemSfeWgIVU41eSshzRz3kez1NngBUuLlSGGSEaKbes5 pZVt6pYFFVByyf6MTHFEoQvafZfEw04JILZpo4R5V8iTHzom0kD3Py064sBiXEw2 B6t+OW4qgcxGblpFkK2lD4kR2s1TPUs0ckVO6sAy1x8q60KKKjY= =vcbA -----END PGP SIGNATURE----- Merge tag 'net-next-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - bpf: - allow bpf programs calling kernel functions (initially to reuse TCP congestion control implementations) - enable task local storage for tracing programs - remove the need to store per-task state in hash maps, and allow tracing programs access to task local storage previously added for BPF_LSM - add bpf_for_each_map_elem() helper, allowing programs to walk all map elements in a more robust and easier to verify fashion - sockmap: support UDP and cross-protocol BPF_SK_SKB_VERDICT redirection - lpm: add support for batched ops in LPM trie - add BTF_KIND_FLOAT support - mostly to allow use of BTF on s390 which has floats in its headers files - improve BPF syscall documentation and extend the use of kdoc parsing scripts we already employ for bpf-helpers - libbpf, bpftool: support static linking of BPF ELF files - improve support for encapsulation of L2 packets - xdp: restructure redirect actions to avoid a runtime lookup, improving performance by 4-8% in microbenchmarks - xsk: build skb by page (aka generic zerocopy xmit) - improve performance of software AF_XDP path by 33% for devices which don't need headers in the linear skb part (e.g. virtio) - nexthop: resilient next-hop groups - improve path stability on next-hops group changes (incl. offload for mlxsw) - ipv6: segment routing: add support for IPv4 decapsulation - icmp: add support for RFC 8335 extended PROBE messages - inet: use bigger hash table for IP ID generation - tcp: deal better with delayed TX completions - make sure we don't give up on fast TCP retransmissions only because driver is slow in reporting that it completed transmitting the original - tcp: reorder tcp_congestion_ops for better cache locality - mptcp: - add sockopt support for common TCP options - add support for common TCP msg flags - include multiple address ids in RM_ADDR - add reset option support for resetting one subflow - udp: GRO L4 improvements - improve 'forward' / 'frag_list' co-existence with UDP tunnel GRO, allowing the first to take place correctly even for encapsulated UDP traffic - micro-optimize dev_gro_receive() and flow dissection, avoid retpoline overhead on VLAN and TEB GRO - use less memory for sysctls, add a new sysctl type, to allow using u8 instead of "int" and "long" and shrink networking sysctls - veth: allow GRO without XDP - this allows aggregating UDP packets before handing them off to routing, bridge, OvS, etc. - allow specifing ifindex when device is moved to another namespace - netfilter: - nft_socket: add support for cgroupsv2 - nftables: add catch-all set element - special element used to define a default action in case normal lookup missed - use net_generic infra in many modules to avoid allocating per-ns memory unnecessarily - xps: improve the xps handling to avoid potential out-of-bound accesses and use-after-free when XPS change race with other re-configuration under traffic - add a config knob to turn off per-cpu netdev refcnt to catch underflows in testing Device APIs: - add WWAN subsystem to organize the WWAN interfaces better and hopefully start driving towards more unified and vendor- independent APIs - ethtool: - add interface for reading IEEE MIB stats (incl. mlx5 and bnxt support) - allow network drivers to dump arbitrary SFP EEPROM data, current offset+length API was a poor fit for modern SFP which define EEPROM in terms of pages (incl. mlx5 support) - act_police, flow_offload: add support for packet-per-second policing (incl. offload for nfp) - psample: add additional metadata attributes like transit delay for packets sampled from switch HW (and corresponding egress and policy-based sampling in the mlxsw driver) - dsa: improve support for sandwiched LAGs with bridge and DSA - netfilter: - flowtable: use direct xmit in topologies with IP forwarding, bridging, vlans etc. - nftables: counter hardware offload support - Bluetooth: - improvements for firmware download w/ Intel devices - add support for reading AOSP vendor capabilities - add support for virtio transport driver - mac80211: - allow concurrent monitor iface and ethernet rx decap - set priority and queue mapping for injected frames - phy: add support for Clause-45 PHY Loopback - pci/iov: add sysfs MSI-X vector assignment interface to distribute MSI-X resources to VFs (incl. mlx5 support) New hardware/drivers: - dsa: mv88e6xxx: add support for Marvell mv88e6393x - 11-port Ethernet switch with 8x 1-Gigabit Ethernet and 3x 10-Gigabit interfaces. - dsa: support for legacy Broadcom tags used on BCM5325, BCM5365 and BCM63xx switches - Microchip KSZ8863 and KSZ8873; 3x 10/100Mbps Ethernet switches - ath11k: support for QCN9074 a 802.11ax device - Bluetooth: Broadcom BCM4330 and BMC4334 - phy: Marvell 88X2222 transceiver support - mdio: add BCM6368 MDIO mux bus controller - r8152: support RTL8153 and RTL8156 (USB Ethernet) chips - mana: driver for Microsoft Azure Network Adapter (MANA) - Actions Semi Owl Ethernet MAC - can: driver for ETAS ES58X CAN/USB interfaces Pure driver changes: - add XDP support to: enetc, igc, stmmac - add AF_XDP support to: stmmac - virtio: - page_to_skb() use build_skb when there's sufficient tailroom (21% improvement for 1000B UDP frames) - support XDP even without dedicated Tx queues - share the Tx queues with the stack when necessary - mlx5: - flow rules: add support for mirroring with conntrack, matching on ICMP, GTP, flex filters and more - support packet sampling with flow offloads - persist uplink representor netdev across eswitch mode changes - allow coexistence of CQE compression and HW time-stamping - add ethtool extended link error state reporting - ice, iavf: support flow filters, UDP Segmentation Offload - dpaa2-switch: - move the driver out of staging - add spanning tree (STP) support - add rx copybreak support - add tc flower hardware offload on ingress traffic - ionic: - implement Rx page reuse - support HW PTP time-stamping - octeon: support TC hardware offloads - flower matching on ingress and egress ratelimitting. - stmmac: - add RX frame steering based on VLAN priority in tc flower - support frame preemption (FPE) - intel: add cross time-stamping freq difference adjustment - ocelot: - support forwarding of MRP frames in HW - support multiple bridges - support PTP Sync one-step timestamping - dsa: mv88e6xxx, dpaa2-switch: offload bridge port flags like learning, flooding etc. - ipa: add IPA v4.5, v4.9 and v4.11 support (Qualcomm SDX55, SM8350, SC7280 SoCs) - mt7601u: enable TDLS support - mt76: - add support for 802.3 rx frames (mt7915/mt7615) - mt7915 flash pre-calibration support - mt7921/mt7663 runtime power management fixes" * tag 'net-next-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2451 commits) net: selftest: fix build issue if INET is disabled net: netrom: nr_in: Remove redundant assignment to ns net: tun: Remove redundant assignment to ret net: phy: marvell: add downshift support for M88E1240 net: dsa: ksz: Make reg_mib_cnt a u8 as it never exceeds 255 net/sched: act_ct: Remove redundant ct get and check icmp: standardize naming of RFC 8335 PROBE constants bpf, selftests: Update array map tests for per-cpu batched ops bpf: Add batched ops support for percpu array bpf: Implement formatted output helpers with bstr_printf seq_file: Add a seq_bprintf function sfc: adjust efx->xdp_tx_queue_count with the real number of initialized queues net:nfc:digital: Fix a double free in digital_tg_recv_dep_req net: fix a concurrency bug in l2tp_tunnel_register() net/smc: Remove redundant assignment to rc mpls: Remove redundant assignment to err llc2: Remove redundant assignment to rc net/tls: Remove redundant initialization of record rds: Remove redundant assignment to nr_sig dt-bindings: net: mdio-gpio: add compatible for microchip,mdio-smi0 ...
This commit is contained in:
commit
9d31d23389
@ -378,3 +378,32 @@ Description:
|
||||
The value comes from the PCI kernel device state and can be one
|
||||
of: "unknown", "error", "D0", D1", "D2", "D3hot", "D3cold".
|
||||
The file is read only.
|
||||
|
||||
What: /sys/bus/pci/devices/.../sriov_vf_total_msix
|
||||
Date: January 2021
|
||||
Contact: Leon Romanovsky <leonro@nvidia.com>
|
||||
Description:
|
||||
This file is associated with a SR-IOV physical function (PF).
|
||||
It contains the total number of MSI-X vectors available for
|
||||
assignment to all virtual functions (VFs) associated with PF.
|
||||
The value will be zero if the device doesn't support this
|
||||
functionality. For supported devices, the value will be
|
||||
constant and won't be changed after MSI-X vectors assignment.
|
||||
|
||||
What: /sys/bus/pci/devices/.../sriov_vf_msix_count
|
||||
Date: January 2021
|
||||
Contact: Leon Romanovsky <leonro@nvidia.com>
|
||||
Description:
|
||||
This file is associated with a SR-IOV virtual function (VF).
|
||||
It allows configuration of the number of MSI-X vectors for
|
||||
the VF. This allows devices that have a global pool of MSI-X
|
||||
vectors to optimally divide them between VFs based on VF usage.
|
||||
|
||||
The values accepted are:
|
||||
* > 0 - this number will be reported as the Table Size in the
|
||||
VF's MSI-X capability
|
||||
* < 0 - not valid
|
||||
* = 0 - will reset to the device default value
|
||||
|
||||
The file is writable if the PF is bound to a driver that
|
||||
implements ->sriov_set_msix_vec_count().
|
||||
|
@ -51,3 +51,15 @@ Description:
|
||||
Boolean value indicating whether the PHY device is used in
|
||||
standalone mode, without a net_device associated, by PHYLINK.
|
||||
Attribute created only when this is the case.
|
||||
|
||||
What: /sys/class/mdio_bus/<bus>/<device>/phy_dev_flags
|
||||
Date: March 2021
|
||||
KernelVersion: 5.13
|
||||
Contact: netdev@vger.kernel.org
|
||||
Description:
|
||||
32-bit hexadecimal number representing a bit mask of the
|
||||
configuration bits passed from the consumer of the PHY
|
||||
(Ethernet MAC, switch, etc.) to the PHY driver. The flags are
|
||||
only used internally by the kernel and their placement are
|
||||
not meant to be stable across kernel versions. This is intended
|
||||
for facilitating the debugging of PHY drivers.
|
||||
|
@ -311,6 +311,17 @@ permit to distribute the load on several cpus.
|
||||
If set to 1 (default), timestamps are sampled as soon as possible, before
|
||||
queueing.
|
||||
|
||||
netdev_unregister_timeout_secs
|
||||
------------------------------
|
||||
|
||||
Unregister network device timeout in seconds.
|
||||
This option controls the timeout (in seconds) used to issue a warning while
|
||||
waiting for a network device refcount to drop to 0 during device
|
||||
unregistration. A lower value may be useful during bisection to detect
|
||||
a leaked reference faster. A larger value may be useful to prevent false
|
||||
warnings on slow/loaded systems.
|
||||
Default value is 10, minimum 1, maximum 3600.
|
||||
|
||||
optmem_max
|
||||
----------
|
||||
|
||||
|
@ -258,3 +258,18 @@ Q: Can BPF functionality such as new program or map types, new
|
||||
helpers, etc be added out of kernel module code?
|
||||
|
||||
A: NO.
|
||||
|
||||
Q: Directly calling kernel function is an ABI?
|
||||
----------------------------------------------
|
||||
Q: Some kernel functions (e.g. tcp_slow_start) can be called
|
||||
by BPF programs. Do these kernel functions become an ABI?
|
||||
|
||||
A: NO.
|
||||
|
||||
The kernel function protos will change and the bpf programs will be
|
||||
rejected by the verifier. Also, for example, some of the bpf-callable
|
||||
kernel functions have already been used by other kernel tcp
|
||||
cc (congestion-control) implementations. If any of these kernel
|
||||
functions has changed, both the in-tree and out-of-tree kernel tcp cc
|
||||
implementations have to be changed. The same goes for the bpf
|
||||
programs and they have to be adjusted accordingly.
|
||||
|
@ -29,7 +29,7 @@ list:
|
||||
This may also include issues related to XDP, BPF tracing, etc.
|
||||
|
||||
Given netdev has a high volume of traffic, please also add the BPF
|
||||
maintainers to Cc (from kernel MAINTAINERS_ file):
|
||||
maintainers to Cc (from kernel ``MAINTAINERS`` file):
|
||||
|
||||
* Alexei Starovoitov <ast@kernel.org>
|
||||
* Daniel Borkmann <daniel@iogearbox.net>
|
||||
@ -234,11 +234,11 @@ be subject to change.
|
||||
|
||||
Q: samples/bpf preference vs selftests?
|
||||
---------------------------------------
|
||||
Q: When should I add code to `samples/bpf/`_ and when to BPF kernel
|
||||
selftests_ ?
|
||||
Q: When should I add code to ``samples/bpf/`` and when to BPF kernel
|
||||
selftests_?
|
||||
|
||||
A: In general, we prefer additions to BPF kernel selftests_ rather than
|
||||
`samples/bpf/`_. The rationale is very simple: kernel selftests are
|
||||
``samples/bpf/``. The rationale is very simple: kernel selftests are
|
||||
regularly run by various bots to test for kernel regressions.
|
||||
|
||||
The more test cases we add to BPF selftests, the better the coverage
|
||||
@ -246,9 +246,9 @@ and the less likely it is that those could accidentally break. It is
|
||||
not that BPF kernel selftests cannot demo how a specific feature can
|
||||
be used.
|
||||
|
||||
That said, `samples/bpf/`_ may be a good place for people to get started,
|
||||
That said, ``samples/bpf/`` may be a good place for people to get started,
|
||||
so it might be advisable that simple demos of features could go into
|
||||
`samples/bpf/`_, but advanced functional and corner-case testing rather
|
||||
``samples/bpf/``, but advanced functional and corner-case testing rather
|
||||
into kernel selftests.
|
||||
|
||||
If your sample looks like a test case, then go for BPF kernel selftests
|
||||
@ -449,6 +449,19 @@ from source at
|
||||
|
||||
https://github.com/acmel/dwarves
|
||||
|
||||
pahole starts to use libbpf definitions and APIs since v1.13 after the
|
||||
commit 21507cd3e97b ("pahole: add libbpf as submodule under lib/bpf").
|
||||
It works well with the git repository because the libbpf submodule will
|
||||
use "git submodule update --init --recursive" to update.
|
||||
|
||||
Unfortunately, the default github release source code does not contain
|
||||
libbpf submodule source code and this will cause build issues, the tarball
|
||||
from https://git.kernel.org/pub/scm/devel/pahole/pahole.git/ is same with
|
||||
github, you can get the source tarball with corresponding libbpf submodule
|
||||
codes from
|
||||
|
||||
https://fedorapeople.org/~acme/dwarves
|
||||
|
||||
Some distros have pahole version 1.16 packaged already, e.g.
|
||||
Fedora, Gentoo.
|
||||
|
||||
@ -645,10 +658,9 @@ when:
|
||||
|
||||
.. Links
|
||||
.. _Documentation/process/: https://www.kernel.org/doc/html/latest/process/
|
||||
.. _MAINTAINERS: ../../MAINTAINERS
|
||||
.. _netdev-FAQ: ../networking/netdev-FAQ.rst
|
||||
.. _samples/bpf/: ../../samples/bpf/
|
||||
.. _selftests: ../../tools/testing/selftests/bpf/
|
||||
.. _selftests:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/testing/selftests/bpf/
|
||||
.. _Documentation/dev-tools/kselftest.rst:
|
||||
https://www.kernel.org/doc/html/latest/dev-tools/kselftest.html
|
||||
.. _Documentation/bpf/btf.rst: btf.rst
|
||||
|
@ -84,6 +84,7 @@ sequentially and type id is assigned to each recognized type starting from id
|
||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||
#define BTF_KIND_VAR 14 /* Variable */
|
||||
#define BTF_KIND_DATASEC 15 /* Section */
|
||||
#define BTF_KIND_FLOAT 16 /* Floating point */
|
||||
|
||||
Note that the type section encodes debug info, not just pure types.
|
||||
``BTF_KIND_FUNC`` is not a type, and it represents a defined subprogram.
|
||||
@ -95,8 +96,8 @@ Each type contains the following common data::
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-30: unused
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
*/
|
||||
@ -452,6 +453,18 @@ map definition.
|
||||
* ``offset``: the in-section offset of the variable
|
||||
* ``size``: the size of the variable in bytes
|
||||
|
||||
2.2.16 BTF_KIND_FLOAT
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``struct btf_type`` encoding requirement:
|
||||
* ``name_off``: any valid offset
|
||||
* ``info.kind_flag``: 0
|
||||
* ``info.kind``: BTF_KIND_FLOAT
|
||||
* ``info.vlen``: 0
|
||||
* ``size``: the size of the float type in bytes: 2, 4, 8, 12 or 16.
|
||||
|
||||
No additional type data follow ``btf_type``.
|
||||
|
||||
3. BTF Kernel API
|
||||
*****************
|
||||
|
||||
|
@ -12,9 +12,6 @@ BPF instruction-set.
|
||||
The Cilium project also maintains a `BPF and XDP Reference Guide`_
|
||||
that goes into great technical depth about the BPF Architecture.
|
||||
|
||||
The primary info for the bpf syscall is available in the `man-pages`_
|
||||
for `bpf(2)`_.
|
||||
|
||||
BPF Type Format (BTF)
|
||||
=====================
|
||||
|
||||
@ -35,6 +32,12 @@ Two sets of Questions and Answers (Q&A) are maintained.
|
||||
bpf_design_QA
|
||||
bpf_devel_QA
|
||||
|
||||
Syscall API
|
||||
===========
|
||||
|
||||
The primary info for the bpf syscall is available in the `man-pages`_
|
||||
for `bpf(2)`_. For more information about the userspace API, see
|
||||
Documentation/userspace-api/ebpf/index.rst.
|
||||
|
||||
Helper functions
|
||||
================
|
||||
|
92
Documentation/devicetree/bindings/net/actions,owl-emac.yaml
Normal file
92
Documentation/devicetree/bindings/net/actions,owl-emac.yaml
Normal file
@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/actions,owl-emac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Actions Semi Owl SoCs Ethernet MAC Controller
|
||||
|
||||
maintainers:
|
||||
- Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
|
||||
description: |
|
||||
This Ethernet MAC is used on the Owl family of SoCs from Actions Semi.
|
||||
It provides the RMII and SMII interfaces and is compliant with the
|
||||
IEEE 802.3 CSMA/CD standard, supporting both half-duplex and full-duplex
|
||||
operation modes at 10/100 Mb/s data transfer rates.
|
||||
|
||||
allOf:
|
||||
- $ref: "ethernet-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: actions,owl-emac
|
||||
- items:
|
||||
- enum:
|
||||
- actions,s500-emac
|
||||
- const: actions,owl-emac
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
additionalItems: false
|
||||
items:
|
||||
- const: eth
|
||||
- const: rmii
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
actions,ethcfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the device containing custom config.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- phy-mode
|
||||
- phy-handle
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/actions,s500-cmu.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/reset/actions,s500-reset.h>
|
||||
|
||||
ethernet@b0310000 {
|
||||
compatible = "actions,s500-emac", "actions,owl-emac";
|
||||
reg = <0xb0310000 0x10000>;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cmu 59 /*CLK_ETHERNET*/>, <&cmu CLK_RMII_REF>;
|
||||
clock-names = "eth", "rmii";
|
||||
resets = <&cmu RESET_ETHERNET>;
|
||||
phy-mode = "rmii";
|
||||
phy-handle = <ð_phy>;
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
eth_phy: ethernet-phy@3 {
|
||||
reg = <0x3>;
|
||||
interrupt-parent = <&sirq>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
@ -22,10 +22,18 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: RX interrupt
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: RX interrupt
|
||||
- description: TX interrupt
|
||||
|
||||
interrupt-names:
|
||||
const: rx
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
required:
|
||||
- reg
|
||||
@ -43,6 +51,7 @@ examples:
|
||||
compatible = "brcm,bcm4908-enet";
|
||||
reg = <0x80002000 0x1000>;
|
||||
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "rx";
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "rx", "tx";
|
||||
};
|
||||
|
@ -0,0 +1,76 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/brcm,bcm6368-mdio-mux.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom BCM6368 MDIO bus multiplexer
|
||||
|
||||
maintainers:
|
||||
- Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
|
||||
description:
|
||||
This MDIO bus multiplexer defines buses that could be internal as well as
|
||||
external to SoCs. When child bus is selected, one needs to select these two
|
||||
properties as well to generate desired MDIO transaction on appropriate bus.
|
||||
|
||||
allOf:
|
||||
- $ref: "mdio.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm6368-mdio-mux
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
patternProperties:
|
||||
'^mdio@[0-1]$':
|
||||
type: object
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mdio0: mdio@10e000b0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "brcm,bcm6368-mdio-mux";
|
||||
reg = <0x10e000b0 0x6>;
|
||||
|
||||
mdio_int: mdio@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
mdio_ext: mdio@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
@ -1,56 +0,0 @@
|
||||
Broadcom Bluetooth Chips
|
||||
---------------------
|
||||
|
||||
This documents the binding structure and common properties for serial
|
||||
attached Broadcom devices.
|
||||
|
||||
Serial attached Broadcom devices shall be a child node of the host UART
|
||||
device the slave device is attached to.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should contain one of the following:
|
||||
* "brcm,bcm20702a1"
|
||||
* "brcm,bcm4329-bt"
|
||||
* "brcm,bcm4330-bt"
|
||||
* "brcm,bcm43438-bt"
|
||||
* "brcm,bcm4345c5"
|
||||
* "brcm,bcm43540-bt"
|
||||
* "brcm,bcm4335a0"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- max-speed: see Documentation/devicetree/bindings/serial/serial.yaml
|
||||
- shutdown-gpios: GPIO specifier, used to enable the BT module
|
||||
- device-wakeup-gpios: GPIO specifier, used to wakeup the controller
|
||||
- host-wakeup-gpios: GPIO specifier, used to wakeup the host processor.
|
||||
deprecated, replaced by interrupts and
|
||||
"host-wakeup" interrupt-names
|
||||
- clocks: 1 or 2 clocks as defined in clock-names below, in that order
|
||||
- clock-names: names for clock inputs, matching the clocks given
|
||||
- "extclk": deprecated, replaced by "txco"
|
||||
- "txco": external reference clock (not a standalone crystal)
|
||||
- "lpo": external low power 32.768 kHz clock
|
||||
- vbat-supply: phandle to regulator supply for VBAT
|
||||
- vddio-supply: phandle to regulator supply for VDDIO
|
||||
- brcm,bt-pcm-int-params: configure PCM parameters via a 5-byte array
|
||||
- sco-routing: 0 = PCM, 1 = Transport, 2 = Codec, 3 = I2S
|
||||
- pcm-interface-rate: 128KBps, 256KBps, 512KBps, 1024KBps, 2048KBps
|
||||
- pcm-frame-type: short, long
|
||||
- pcm-sync-mode: slave, master
|
||||
- pcm-clock-mode: slave, master
|
||||
- interrupts: must be one, used to wakeup the host processor
|
||||
- interrupt-names: must be "host-wakeup"
|
||||
|
||||
Example:
|
||||
|
||||
&uart2 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart2_pins>;
|
||||
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
max-speed = <921600>;
|
||||
brcm,bt-pcm-int-params = [01 02 00 01 01];
|
||||
};
|
||||
};
|
118
Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
Normal file
118
Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
Normal file
@ -0,0 +1,118 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/broadcom-bluetooth.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom Bluetooth Chips
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
description:
|
||||
This binding describes Broadcom UART-attached bluetooth chips.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,bcm20702a1
|
||||
- brcm,bcm4329-bt
|
||||
- brcm,bcm4330-bt
|
||||
- brcm,bcm4334-bt
|
||||
- brcm,bcm43438-bt
|
||||
- brcm,bcm4345c5
|
||||
- brcm,bcm43540-bt
|
||||
- brcm,bcm4335a0
|
||||
|
||||
shutdown-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO specifier for the line BT_REG_ON used to
|
||||
power on the BT module
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO specifier for the line BT_RST_N used to
|
||||
reset the BT module. This should be marked as
|
||||
GPIO_ACTIVE_LOW.
|
||||
|
||||
device-wakeup-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO specifier for the line BT_WAKE used to
|
||||
wakeup the controller. This is using the BT_GPIO_0
|
||||
pin on the chip when in use.
|
||||
|
||||
host-wakeup-gpios:
|
||||
maxItems: 1
|
||||
deprecated: true
|
||||
description: GPIO specifier for the line HOST_WAKE used
|
||||
to wakeup the host processor. This is using he BT_GPIO_1
|
||||
pin on the chip when in use. This is deprecated and replaced
|
||||
by interrupts and "host-wakeup" interrupt-names
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
description: 1 or 2 clocks as defined in clock-names below,
|
||||
in that order
|
||||
|
||||
clock-names:
|
||||
description: Names of the 1 to 2 supplied clocks
|
||||
items:
|
||||
- const: txco
|
||||
- const: lpo
|
||||
- const: extclk
|
||||
|
||||
vbat-supply:
|
||||
description: phandle to regulator supply for VBAT
|
||||
|
||||
vddio-supply:
|
||||
description: phandle to regulator supply for VDDIO
|
||||
|
||||
brcm,bt-pcm-int-params:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
minItems: 5
|
||||
maxItems: 5
|
||||
description: |-
|
||||
configure PCM parameters via a 5-byte array:
|
||||
sco-routing: 0 = PCM, 1 = Transport, 2 = Codec, 3 = I2S
|
||||
pcm-interface-rate: 128KBps, 256KBps, 512KBps, 1024KBps, 2048KBps
|
||||
pcm-frame-type: short, long
|
||||
pcm-sync-mode: slave, master
|
||||
pcm-clock-mode: slave, master
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Handle to the line HOST_WAKE used to wake
|
||||
up the host processor. This uses the BT_GPIO_1 pin on
|
||||
the chip when in use.
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: host-wakeup
|
||||
|
||||
max-speed: true
|
||||
current-speed: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
uart {
|
||||
uart-has-rtscts;
|
||||
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm4330-bt";
|
||||
max-speed = <921600>;
|
||||
brcm,bt-pcm-int-params = [01 02 00 01 01];
|
||||
shutdown-gpios = <&gpio 30 GPIO_ACTIVE_HIGH>;
|
||||
device-wakeup-gpios = <&gpio 7 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio 9 GPIO_ACTIVE_LOW>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
@ -19,7 +19,8 @@ Required properties:
|
||||
"renesas,can-r8a7793" if CAN controller is a part of R8A7793 SoC.
|
||||
"renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC.
|
||||
"renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC.
|
||||
"renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC.
|
||||
"renesas,can-r8a7796" if CAN controller is a part of R8A77960 SoC.
|
||||
"renesas,can-r8a77961" if CAN controller is a part of R8A77961 SoC.
|
||||
"renesas,can-r8a77965" if CAN controller is a part of R8A77965 SoC.
|
||||
"renesas,can-r8a77990" if CAN controller is a part of R8A77990 SoC.
|
||||
"renesas,can-r8a77995" if CAN controller is a part of R8A77995 SoC.
|
||||
@ -40,7 +41,7 @@ Required properties:
|
||||
- pinctrl-names: must be "default".
|
||||
|
||||
Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795,
|
||||
R8A7796, R8A77965, R8A77990, and R8A77995:
|
||||
R8A77960, R8A77961, R8A77965, R8A77990, and R8A77995:
|
||||
For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can
|
||||
be used by both CAN and CAN FD controller at the same time. It needs to be
|
||||
scaled to maximum frequency if any of these controllers use it. This is done
|
||||
|
@ -70,6 +70,15 @@ patternProperties:
|
||||
device is what the switch port is connected to
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
dsa-tag-protocol:
|
||||
description:
|
||||
Instead of the default, the switch will use this tag protocol if
|
||||
possible. Useful when a device supports multiple protcols and
|
||||
the default is incompatible with the Ethernet device.
|
||||
enum:
|
||||
- dsa
|
||||
- edsa
|
||||
|
||||
phy-handle: true
|
||||
|
||||
phy-mode: true
|
||||
|
@ -5,6 +5,10 @@ Required properties for GSWIP core:
|
||||
|
||||
- compatible : "lantiq,xrx200-gswip" for the embedded GSWIP in the
|
||||
xRX200 SoC
|
||||
"lantiq,xrx300-gswip" for the embedded GSWIP in the
|
||||
xRX300 SoC
|
||||
"lantiq,xrx330-gswip" for the embedded GSWIP in the
|
||||
xRX330 SoC
|
||||
- reg : memory range of the GSWIP core registers
|
||||
: memory range of the GSWIP MDIO registers
|
||||
: memory range of the GSWIP MII registers
|
||||
|
@ -21,6 +21,8 @@ properties:
|
||||
- microchip,ksz8765
|
||||
- microchip,ksz8794
|
||||
- microchip,ksz8795
|
||||
- microchip,ksz8863
|
||||
- microchip,ksz8873
|
||||
- microchip,ksz9477
|
||||
- microchip,ksz9897
|
||||
- microchip,ksz9896
|
||||
|
@ -102,3 +102,18 @@ Example:
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
* Integrated Endpoint Register Block bindings
|
||||
|
||||
Optionally, the fsl_enetc driver can probe on the Integrated Endpoint Register
|
||||
Block, which preconfigures the FIFO limits for the ENETC ports. This is a node
|
||||
with the following properties:
|
||||
|
||||
- reg : Specifies the address in the SoC memory space.
|
||||
- compatible : Must be "fsl,ls1028a-enetc-ierb".
|
||||
|
||||
Example:
|
||||
ierb@1f0800000 {
|
||||
compatible = "fsl,ls1028a-enetc-ierb";
|
||||
reg = <0x01 0xf0800000 0x0 0x10000>;
|
||||
};
|
||||
|
73
Documentation/devicetree/bindings/net/idt,3243x-emac.yaml
Normal file
73
Documentation/devicetree/bindings/net/idt,3243x-emac.yaml
Normal file
@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/idt,3243x-emac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: IDT 79rc3243x Ethernet controller
|
||||
|
||||
description: Ethernet controller integrated into IDT 79RC3243x family SoCs
|
||||
|
||||
maintainers:
|
||||
- Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||
|
||||
allOf:
|
||||
- $ref: ethernet-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: idt,3243x-emac
|
||||
|
||||
reg:
|
||||
maxItems: 3
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: emac
|
||||
- const: dma_rx
|
||||
- const: dma_tx
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: RX interrupt
|
||||
- description: TX interrupt
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: mdioclk
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
ethernet@60000 {
|
||||
compatible = "idt,3243x-emac";
|
||||
|
||||
reg = <0x60000 0x10000>,
|
||||
<0x40000 0x14>,
|
||||
<0x40014 0x14>;
|
||||
reg-names = "emac", "dma_rx", "dma_tx";
|
||||
|
||||
interrupt-parent = <&rcpic3>;
|
||||
interrupts = <0>, <1>;
|
||||
interrupt-names = "rx", "tx";
|
||||
|
||||
clocks = <&iclk>;
|
||||
clock-names = "mdioclk";
|
||||
};
|
102
Documentation/devicetree/bindings/net/intel,ixp4xx-ethernet.yaml
Normal file
102
Documentation/devicetree/bindings/net/intel,ixp4xx-ethernet.yaml
Normal file
@ -0,0 +1,102 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2018 Linaro Ltd.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/net/intel,ixp4xx-ethernet.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Intel IXP4xx ethernet
|
||||
|
||||
allOf:
|
||||
- $ref: "ethernet-controller.yaml#"
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
description: |
|
||||
The Intel IXP4xx ethernet makes use of the IXP4xx NPE (Network
|
||||
Processing Engine) and the IXP4xx Queue Manager to process
|
||||
the ethernet frames. It can optionally contain an MDIO bus to
|
||||
talk to PHYs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: intel,ixp4xx-ethernet
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: Ethernet MMIO address range
|
||||
|
||||
queue-rx:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle-array'
|
||||
maxItems: 1
|
||||
description: phandle to the RX queue on the NPE
|
||||
|
||||
queue-txready:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle-array'
|
||||
maxItems: 1
|
||||
description: phandle to the TX READY queue on the NPE
|
||||
|
||||
phy-mode: true
|
||||
|
||||
phy-handle: true
|
||||
|
||||
intel,npe-handle:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle-array'
|
||||
maxItems: 1
|
||||
description: phandle to the NPE this ethernet instance is using
|
||||
and the instance to use in the second cell
|
||||
|
||||
mdio:
|
||||
type: object
|
||||
$ref: "mdio.yaml#"
|
||||
description: optional node for embedded MDIO controller
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- queue-rx
|
||||
- queue-txready
|
||||
- intel,npe-handle
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
npe: npe@c8006000 {
|
||||
compatible = "intel,ixp4xx-network-processing-engine";
|
||||
reg = <0xc8006000 0x1000>, <0xc8007000 0x1000>, <0xc8008000 0x1000>;
|
||||
};
|
||||
|
||||
ethernet@c8009000 {
|
||||
compatible = "intel,ixp4xx-ethernet";
|
||||
reg = <0xc8009000 0x1000>;
|
||||
status = "disabled";
|
||||
queue-rx = <&qmgr 4>;
|
||||
queue-txready = <&qmgr 21>;
|
||||
intel,npe-handle = <&npe 1>;
|
||||
phy-mode = "rgmii";
|
||||
phy-handle = <&phy1>;
|
||||
};
|
||||
|
||||
ethernet@c800c000 {
|
||||
compatible = "intel,ixp4xx-ethernet";
|
||||
reg = <0xc800c000 0x1000>;
|
||||
status = "disabled";
|
||||
queue-rx = <&qmgr 3>;
|
||||
queue-txready = <&qmgr 20>;
|
||||
intel,npe-handle = <&npe 2>;
|
||||
phy-mode = "rgmii";
|
||||
phy-handle = <&phy2>;
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
phy1: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
phy2: ethernet-phy@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
};
|
@ -2,6 +2,7 @@ MDIO on GPIOs
|
||||
|
||||
Currently defined compatibles:
|
||||
- virtual,gpio-mdio
|
||||
- microchip,mdio-smi0
|
||||
|
||||
MDC and MDIO lines connected to GPIO controllers are listed in the
|
||||
gpios property as described in section VIII.1 in the following order:
|
||||
|
@ -43,7 +43,12 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: "qcom,sdm845-ipa"
|
||||
enum:
|
||||
- qcom,sc7180-ipa
|
||||
- qcom,sc7280-ipa
|
||||
- qcom,sdm845-ipa
|
||||
- qcom,sdx55-ipa
|
||||
- qcom,sm8350-ipa
|
||||
|
||||
reg:
|
||||
items:
|
||||
@ -120,6 +125,14 @@ properties:
|
||||
the firmware passed to Trust Zone for authentication. Required
|
||||
when Trust Zone (not the modem) performs early initialization.
|
||||
|
||||
firmware-name:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
If present, name (or relative path) of the file within the
|
||||
firmware search path containing the firmware image used when
|
||||
initializing IPA hardware. Optional, and only used when
|
||||
Trust Zone performs early initialization.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- iommus
|
||||
@ -129,12 +142,23 @@ required:
|
||||
- interconnects
|
||||
- qcom,smem-states
|
||||
|
||||
# Either modem-init is present, or memory-region must be present.
|
||||
oneOf:
|
||||
- required:
|
||||
- modem-init
|
||||
- required:
|
||||
- memory-region
|
||||
|
||||
# If memory-region is present, firmware-name may optionally be present.
|
||||
# But if modem-init is present, firmware-name must not be present.
|
||||
if:
|
||||
required:
|
||||
- modem-init
|
||||
then:
|
||||
not:
|
||||
required:
|
||||
- firmware-name
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -50,7 +50,16 @@ properties:
|
||||
interrupt-names: true
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: AVB functional clock
|
||||
- description: Optional TXC reference clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: fck
|
||||
- const: refclk
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
@ -1,76 +0,0 @@
|
||||
Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC)
|
||||
|
||||
The device node has following properties.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "rockchip,<name>-gamc"
|
||||
"rockchip,px30-gmac": found on PX30 SoCs
|
||||
"rockchip,rk3128-gmac": found on RK312x SoCs
|
||||
"rockchip,rk3228-gmac": found on RK322x SoCs
|
||||
"rockchip,rk3288-gmac": found on RK3288 SoCs
|
||||
"rockchip,rk3328-gmac": found on RK3328 SoCs
|
||||
"rockchip,rk3366-gmac": found on RK3366 SoCs
|
||||
"rockchip,rk3368-gmac": found on RK3368 SoCs
|
||||
"rockchip,rk3399-gmac": found on RK3399 SoCs
|
||||
"rockchip,rv1108-gmac": found on RV1108 SoCs
|
||||
- reg: addresses and length of the register sets for the device.
|
||||
- interrupts: Should contain the GMAC interrupts.
|
||||
- interrupt-names: Should contain the interrupt names "macirq".
|
||||
- rockchip,grf: phandle to the syscon grf used to control speed and mode.
|
||||
- clocks: <&cru SCLK_MAC>: clock selector for main clock, from PLL or PHY.
|
||||
<&cru SCLK_MAC_PLL>: PLL clock for SCLK_MAC
|
||||
<&cru SCLK_MAC_RX>: clock gate for RX
|
||||
<&cru SCLK_MAC_TX>: clock gate for TX
|
||||
<&cru SCLK_MACREF>: clock gate for RMII referce clock
|
||||
<&cru SCLK_MACREF_OUT> clock gate for RMII reference clock output
|
||||
<&cru ACLK_GMAC>: AXI clock gate for GMAC
|
||||
<&cru PCLK_GMAC>: APB clock gate for GMAC
|
||||
- clock-names: One name for each entry in the clocks property.
|
||||
- phy-mode: See ethernet.txt file in the same directory.
|
||||
- pinctrl-names: Names corresponding to the numbered pinctrl states.
|
||||
- pinctrl-0: pin-control mode. can be <&rgmii_pins> or <&rmii_pins>.
|
||||
- clock_in_out: For RGMII, it must be "input", means main clock(125MHz)
|
||||
is not sourced from SoC's PLL, but input from PHY; For RMII, "input" means
|
||||
PHY provides the reference clock(50MHz), "output" means GMAC provides the
|
||||
reference clock.
|
||||
- snps,reset-gpio gpio number for phy reset.
|
||||
- snps,reset-active-low boolean flag to indicate if phy reset is active low.
|
||||
- assigned-clocks: main clock, should be <&cru SCLK_MAC>;
|
||||
- assigned-clock-parents = parent of main clock.
|
||||
can be <&ext_gmac> or <&cru SCLK_MAC_PLL>.
|
||||
|
||||
Optional properties:
|
||||
- tx_delay: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default.
|
||||
- rx_delay: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default.
|
||||
- phy-supply: phandle to a regulator if the PHY needs one
|
||||
|
||||
Example:
|
||||
|
||||
gmac: ethernet@ff290000 {
|
||||
compatible = "rockchip,rk3288-gmac";
|
||||
reg = <0xff290000 0x10000>;
|
||||
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq";
|
||||
rockchip,grf = <&grf>;
|
||||
clocks = <&cru SCLK_MAC>,
|
||||
<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
|
||||
<&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
|
||||
<&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
|
||||
clock-names = "stmmaceth",
|
||||
"mac_clk_rx", "mac_clk_tx",
|
||||
"clk_mac_ref", "clk_mac_refout",
|
||||
"aclk_mac", "pclk_mac";
|
||||
phy-mode = "rgmii";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&rgmii_pins /*&rmii_pins*/>;
|
||||
|
||||
clock_in_out = "input";
|
||||
snps,reset-gpio = <&gpio4 7 0>;
|
||||
snps,reset-active-low;
|
||||
|
||||
assigned-clocks = <&cru SCLK_MAC>;
|
||||
assigned-clock-parents = <&ext_gmac>;
|
||||
tx_delay = <0x30>;
|
||||
rx_delay = <0x10>;
|
||||
|
||||
};
|
120
Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
Normal file
120
Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
Normal file
@ -0,0 +1,120 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/net/rockchip-dwmac.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Rockchip 10/100/1000 Ethernet driver(GMAC)
|
||||
|
||||
maintainers:
|
||||
- David Wu <david.wu@rock-chips.com>
|
||||
|
||||
# We need a select here so we don't match all nodes with 'snps,dwmac'
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- rockchip,px30-gmac
|
||||
- rockchip,rk3128-gmac
|
||||
- rockchip,rk3228-gmac
|
||||
- rockchip,rk3288-gmac
|
||||
- rockchip,rk3328-gmac
|
||||
- rockchip,rk3366-gmac
|
||||
- rockchip,rk3368-gmac
|
||||
- rockchip,rk3399-gmac
|
||||
- rockchip,rv1108-gmac
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: "snps,dwmac.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- rockchip,px30-gmac
|
||||
- rockchip,rk3128-gmac
|
||||
- rockchip,rk3228-gmac
|
||||
- rockchip,rk3288-gmac
|
||||
- rockchip,rk3328-gmac
|
||||
- rockchip,rk3366-gmac
|
||||
- rockchip,rk3368-gmac
|
||||
- rockchip,rk3399-gmac
|
||||
- rockchip,rv1108-gmac
|
||||
|
||||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 8
|
||||
|
||||
clock-names:
|
||||
contains:
|
||||
enum:
|
||||
- stmmaceth
|
||||
- mac_clk_tx
|
||||
- mac_clk_rx
|
||||
- aclk_mac
|
||||
- pclk_mac
|
||||
- clk_mac_ref
|
||||
- clk_mac_refout
|
||||
- clk_mac_speed
|
||||
|
||||
clock_in_out:
|
||||
description:
|
||||
For RGMII, it must be "input", means main clock(125MHz)
|
||||
is not sourced from SoC's PLL, but input from PHY.
|
||||
For RMII, "input" means PHY provides the reference clock(50MHz),
|
||||
"output" means GMAC provides the reference clock.
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [input, output]
|
||||
|
||||
rockchip,grf:
|
||||
description: The phandle of the syscon node for the general register file.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
tx_delay:
|
||||
description: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
rx_delay:
|
||||
description: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
phy-supply:
|
||||
description: PHY regulator
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/rk3288-cru.h>
|
||||
|
||||
gmac: ethernet@ff290000 {
|
||||
compatible = "rockchip,rk3288-gmac";
|
||||
reg = <0xff290000 0x10000>;
|
||||
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&cru SCLK_MAC>,
|
||||
<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
|
||||
<&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
|
||||
<&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
|
||||
clock-names = "stmmaceth",
|
||||
"mac_clk_rx", "mac_clk_tx",
|
||||
"clk_mac_ref", "clk_mac_refout",
|
||||
"aclk_mac", "pclk_mac";
|
||||
assigned-clocks = <&cru SCLK_MAC>;
|
||||
assigned-clock-parents = <&ext_gmac>;
|
||||
|
||||
rockchip,grf = <&grf>;
|
||||
phy-mode = "rgmii";
|
||||
clock_in_out = "input";
|
||||
tx_delay = <0x30>;
|
||||
rx_delay = <0x10>;
|
||||
};
|
@ -56,6 +56,15 @@ properties:
|
||||
- amlogic,meson8m2-dwmac
|
||||
- amlogic,meson-gxbb-dwmac
|
||||
- amlogic,meson-axg-dwmac
|
||||
- rockchip,px30-gmac
|
||||
- rockchip,rk3128-gmac
|
||||
- rockchip,rk3228-gmac
|
||||
- rockchip,rk3288-gmac
|
||||
- rockchip,rk3328-gmac
|
||||
- rockchip,rk3366-gmac
|
||||
- rockchip,rk3368-gmac
|
||||
- rockchip,rk3399-gmac
|
||||
- rockchip,rv1108-gmac
|
||||
- snps,dwmac
|
||||
- snps,dwmac-3.50a
|
||||
- snps,dwmac-3.610
|
||||
@ -89,7 +98,7 @@ properties:
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
maxItems: 8
|
||||
additionalItems: true
|
||||
items:
|
||||
- description: GMAC main clock
|
||||
@ -101,7 +110,7 @@ properties:
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
maxItems: 8
|
||||
additionalItems: true
|
||||
contains:
|
||||
enum:
|
||||
|
@ -1,24 +0,0 @@
|
||||
Common IEEE 802.11 properties
|
||||
|
||||
This provides documentation of common properties that are valid for all wireless
|
||||
devices.
|
||||
|
||||
Optional properties:
|
||||
- ieee80211-freq-limit : list of supported frequency ranges in KHz. This can be
|
||||
used for devices that in a given config support less channels than
|
||||
normally. It may happen chipset supports a wide wireless band but it is
|
||||
limited to some part of it due to used antennas or power amplifier.
|
||||
An example case for this can be tri-band wireless router with two
|
||||
identical chipsets used for two different 5 GHz subbands. Using them
|
||||
incorrectly could not work or decrease performance noticeably.
|
||||
|
||||
Example:
|
||||
|
||||
pcie@0,0 {
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
wifi@0,0 {
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
ieee80211-freq-limit = <2402000 2482000>,
|
||||
<5170000 5250000>;
|
||||
};
|
||||
};
|
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/wireless/ieee80211.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common IEEE 802.11 Binding
|
||||
|
||||
maintainers:
|
||||
- Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
|
||||
description: |
|
||||
This provides documentation of common properties that are valid for
|
||||
all wireless devices
|
||||
|
||||
properties:
|
||||
ieee80211-freq-limit:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
description:
|
||||
List of supported frequency ranges in KHz. This can be used for devices
|
||||
that in a given config support less channels than normally. It may happen
|
||||
chipset supports a wide wireless band but it is limited to some part of
|
||||
it due to used antennas or power amplifier. An example case for this
|
||||
can be tri-band wireless router with two identical chipsets used for two
|
||||
different 5 GHz subbands. Using them incorrectly could not work or
|
||||
decrease performance noticeably
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
- |
|
||||
pcie0 {
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
wifi@0,0 {
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
ieee80211-freq-limit = <2402000 2482000>,
|
||||
<5170000 5250000>;
|
||||
};
|
||||
};
|
@ -1,78 +0,0 @@
|
||||
* MediaTek mt76xx devices
|
||||
|
||||
This node provides properties for configuring the MediaTek mt76xx wireless
|
||||
device. The node is expected to be specified as a child node of the PCI
|
||||
controller to which the wireless chip is connected.
|
||||
|
||||
Alternatively, it can specify the wireless part of the MT7628/MT7688 or
|
||||
MT7622 SoC. For SoC, use the following compatible strings:
|
||||
|
||||
compatible:
|
||||
- "mediatek,mt7628-wmac" for MT7628/MT7688
|
||||
- "mediatek,mt7622-wmac" for MT7622
|
||||
|
||||
properties:
|
||||
- reg: Address and length of the register set for the device.
|
||||
- interrupts: Main device interrupt
|
||||
|
||||
MT7622 specific properties:
|
||||
- power-domains: phandle to the power domain that the WMAC is part of
|
||||
- mediatek,infracfg: phandle to the infrastructure bus fabric syscon node
|
||||
|
||||
Optional properties:
|
||||
|
||||
- ieee80211-freq-limit: See ieee80211.txt
|
||||
- mediatek,mtd-eeprom: Specify a MTD partition + offset containing EEPROM data
|
||||
- big-endian: if the radio eeprom partition is written in big-endian, specify
|
||||
this property
|
||||
- mediatek,eeprom-merge-otp: Merge EEPROM data with OTP data. Can be used on
|
||||
boards where the flash calibration data is generic and specific calibration
|
||||
data should be pulled from the OTP ROM
|
||||
|
||||
The MAC address can as well be set with corresponding optional properties
|
||||
defined in net/ethernet.txt.
|
||||
|
||||
Optional nodes:
|
||||
- led: Properties for a connected LED
|
||||
Optional properties:
|
||||
- led-sources: See Documentation/devicetree/bindings/leds/common.txt
|
||||
|
||||
&pcie {
|
||||
pcie0 {
|
||||
wifi@0,0 {
|
||||
compatible = "mediatek,mt76";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
ieee80211-freq-limit = <5000000 6000000>;
|
||||
mediatek,mtd-eeprom = <&factory 0x8000>;
|
||||
big-endian;
|
||||
|
||||
led {
|
||||
led-sources = <2>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
MT7628 example:
|
||||
|
||||
wmac: wmac@10300000 {
|
||||
compatible = "mediatek,mt7628-wmac";
|
||||
reg = <0x10300000 0x100000>;
|
||||
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <6>;
|
||||
|
||||
mediatek,mtd-eeprom = <&factory 0x0000>;
|
||||
};
|
||||
|
||||
MT7622 example:
|
||||
|
||||
wmac: wmac@18000000 {
|
||||
compatible = "mediatek,mt7622-wmac";
|
||||
reg = <0 0x18000000 0 0x100000>;
|
||||
interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
mediatek,infracfg = <&infracfg>;
|
||||
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
|
||||
};
|
@ -0,0 +1,228 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/wireless/mediatek,mt76.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek mt76 wireless devices Generic Binding
|
||||
|
||||
maintainers:
|
||||
- Felix Fietkau <nbd@nbd.name>
|
||||
- Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
- Ryder Lee <ryder.lee@mediatek.com>
|
||||
|
||||
description: |
|
||||
This node provides properties for configuring the MediaTek mt76xx
|
||||
wireless device. The node is expected to be specified as a child
|
||||
node of the PCI controller to which the wireless chip is connected.
|
||||
Alternatively, it can specify the wireless part of the MT7628/MT7688
|
||||
or MT7622 SoC.
|
||||
|
||||
allOf:
|
||||
- $ref: ieee80211.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt76
|
||||
- mediatek,mt7628-wmac
|
||||
- mediatek,mt7622-wmac
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
mediatek,infracfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the infrastructure bus fabric syscon node.
|
||||
This property is MT7622 specific
|
||||
|
||||
ieee80211-freq-limit: true
|
||||
|
||||
mediatek,mtd-eeprom:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description:
|
||||
Phandle to a MTD partition + offset containing EEPROM data
|
||||
|
||||
big-endian:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Specify if the radio eeprom partition is written in big-endian
|
||||
|
||||
mediatek,eeprom-merge-otp:
|
||||
type: boolean
|
||||
description:
|
||||
Merge EEPROM data with OTP data. Can be used on boards where the flash
|
||||
calibration data is generic and specific calibration data should be
|
||||
pulled from the OTP ROM
|
||||
|
||||
led:
|
||||
type: object
|
||||
$ref: /schemas/leds/common.yaml#
|
||||
additionalProperties: false
|
||||
properties:
|
||||
led-sources:
|
||||
maxItems: 1
|
||||
|
||||
power-limits:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
patternProperties:
|
||||
"^r[0-9]+":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
regdomain:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
Regdomain refers to a legal regulatory region. Different
|
||||
countries define different levels of allowable transmitter
|
||||
power, time that a channel can be occupied, and different
|
||||
available channels
|
||||
enum:
|
||||
- FCC
|
||||
- ETSI
|
||||
- JP
|
||||
|
||||
patternProperties:
|
||||
"^txpower-[256]g$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
patternProperties:
|
||||
"^b[0-9]+$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
description:
|
||||
Pairs of first and last channel number of the selected
|
||||
band
|
||||
|
||||
rates-cck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
description:
|
||||
4 half-dBm per-rate power limit values
|
||||
|
||||
rates-ofdm:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
minItems: 8
|
||||
maxItems: 8
|
||||
description:
|
||||
8 half-dBm per-rate power limit values
|
||||
|
||||
rates-mcs:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-matrix
|
||||
description:
|
||||
Sets of per-rate power limit values for 802.11n/802.11ac
|
||||
rates for multiple channel bandwidth settings.
|
||||
Each set starts with the number of channel bandwidth
|
||||
settings for which the rate set applies, followed by
|
||||
either 8 or 10 power limit values. The order of the
|
||||
channel bandwidth settings is 20, 40, 80 and 160 MHz.
|
||||
maxItems: 4
|
||||
items:
|
||||
minItems: 9
|
||||
maxItems: 11
|
||||
|
||||
rates-ru:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-matrix
|
||||
description:
|
||||
Sets of per-rate power limit values for 802.11ax rates
|
||||
for multiple channel bandwidth or resource unit settings.
|
||||
Each set starts with the number of channel bandwidth or
|
||||
resource unit settings for which the rate set applies,
|
||||
followed by 12 power limit values. The order of the
|
||||
channel resource unit settings is RU26, RU52, RU106,
|
||||
RU242/SU20, RU484/SU40, RU996/SU80 and RU2x996/SU160.
|
||||
items:
|
||||
minItems: 13
|
||||
maxItems: 13
|
||||
|
||||
txs-delta:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
Half-dBm power delta for different numbers of antennas
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
pcie0 {
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
wifi@0,0 {
|
||||
compatible = "mediatek,mt76";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
ieee80211-freq-limit = <5000000 6000000>;
|
||||
mediatek,mtd-eeprom = <&factory 0x8000>;
|
||||
big-endian;
|
||||
|
||||
led {
|
||||
led-sources = <2>;
|
||||
};
|
||||
|
||||
power-limits {
|
||||
r0 {
|
||||
regdomain = "FCC";
|
||||
txpower-5g {
|
||||
b0 {
|
||||
channels = <36 48>;
|
||||
rates-ofdm = /bits/ 8 <23 23 23 23 23 23 23 23>;
|
||||
rates-mcs = /bits/ 8 <1 23 23 23 23 23 23 23 23 23 23>,
|
||||
<3 22 22 22 22 22 22 22 22 22 22>;
|
||||
rates-ru = /bits/ 8 <3 22 22 22 22 22 22 22 22 22 22 22 22>,
|
||||
<4 20 20 20 20 20 20 20 20 20 20 20 20>;
|
||||
};
|
||||
b1 {
|
||||
channels = <100 181>;
|
||||
rates-ofdm = /bits/ 8 <14 14 14 14 14 14 14 14>;
|
||||
rates-mcs = /bits/ 8 <4 14 14 14 14 14 14 14 14 14 14>;
|
||||
txs-delta = <12 9 6>;
|
||||
rates-ru = /bits/ 8 <7 14 14 14 14 14 14 14 14 14 14 14 14>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
wifi@10300000 {
|
||||
compatible = "mediatek,mt7628-wmac";
|
||||
reg = <0x10300000 0x100000>;
|
||||
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <6>;
|
||||
|
||||
mediatek,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
wifi@18000000 {
|
||||
compatible = "mediatek,mt7622-wmac";
|
||||
reg = <0x10300000 0x100000>;
|
||||
interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
mediatek,infracfg = <&infracfg>;
|
||||
|
||||
power-domains = <&scpsys 3>;
|
||||
};
|
@ -42,11 +42,23 @@ Optional properties:
|
||||
support both 1000BaseX and SGMII modes. If set, the phy-mode
|
||||
should be set to match the mode selected on core reset (i.e.
|
||||
by the basex_or_sgmii core input line).
|
||||
- clocks : AXI bus clock for the device. Refer to common clock bindings.
|
||||
Used to calculate MDIO clock divisor. If not specified, it is
|
||||
auto-detected from the CPU clock (but only on platforms where
|
||||
this is possible). New device trees should specify this - the
|
||||
auto detection is only for backward compatibility.
|
||||
- clock-names: Tuple listing input clock names. Possible clocks:
|
||||
s_axi_lite_clk: Clock for AXI register slave interface
|
||||
axis_clk: AXI4-Stream clock for TXD RXD TXC and RXS interfaces
|
||||
ref_clk: Ethernet reference clock, used by signal delay
|
||||
primitives and transceivers
|
||||
mgt_clk: MGT reference clock (used by optional internal
|
||||
PCS/PMA PHY)
|
||||
|
||||
Note that if s_axi_lite_clk is not specified by name, the
|
||||
first clock of any name is used for this. If that is also not
|
||||
specified, the clock rate is auto-detected from the CPU clock
|
||||
(but only on platforms where this is possible). New device
|
||||
trees should specify all applicable clocks by name - the
|
||||
fallbacks to an unnamed clock or to CPU clock are only for
|
||||
backward compatibility.
|
||||
- clocks: Phandles to input clocks matching clock-names. Refer to common
|
||||
clock bindings.
|
||||
- axistream-connected: Reference to another node which contains the resources
|
||||
for the AXI DMA controller used by this device.
|
||||
If this is specified, the DMA-related resources from that
|
||||
@ -62,7 +74,8 @@ Example:
|
||||
device_type = "network";
|
||||
interrupt-parent = <µblaze_0_axi_intc>;
|
||||
interrupts = <2 0 1>;
|
||||
clocks = <&axi_clk>;
|
||||
clock-names = "s_axi_lite_clk", "axis_clk", "ref_clk", "mgt_clk";
|
||||
clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>;
|
||||
phy-mode = "mii";
|
||||
reg = <0x40c00000 0x40000 0x50c00000 0x40000>;
|
||||
xlnx,rxcsum = <0x2>;
|
||||
|
@ -91,7 +91,7 @@ examples:
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm4330-bt";
|
||||
reset-gpios = <&gpf 8 GPIO_ACTIVE_HIGH>;
|
||||
vcc-supply = <&wlan0_power>;
|
||||
vbat-supply = <&wlan0_power>;
|
||||
device-wakeup-gpios = <&gpf 5 GPIO_ACTIVE_HIGH>;
|
||||
host-wakeup-gpios = <&gpf 6 GPIO_ACTIVE_HIGH>;
|
||||
shutdown-gpios = <&gpf 4 GPIO_ACTIVE_LOW>;
|
||||
|
@ -608,6 +608,8 @@ demand:
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
|
||||
&recv_own_msgs, sizeof(recv_own_msgs));
|
||||
|
||||
Note that reception of a socket's own CAN frames are subject to the same
|
||||
filtering as other CAN frames (see :ref:`socketcan-rawfilter`).
|
||||
|
||||
.. _socketcan-rawfd:
|
||||
|
||||
|
@ -183,6 +183,40 @@ User command examples:
|
||||
values:
|
||||
cmode driverinit value true
|
||||
|
||||
esw_port_metadata: Eswitch port metadata state
|
||||
----------------------------------------------
|
||||
When applicable, disabling Eswitch metadata can increase packet rate
|
||||
up to 20% depending on the use case and packet sizes.
|
||||
|
||||
Eswitch port metadata state controls whether to internally tag packets with
|
||||
metadata. Metadata tagging must be enabled for multi-port RoCE, failover
|
||||
between representors and stacked devices.
|
||||
By default metadata is enabled on the supported devices in E-switch.
|
||||
Metadata is applicable only for E-switch in switchdev mode and
|
||||
users may disable it when NONE of the below use cases will be in use:
|
||||
1. HCA is in Dual/multi-port RoCE mode.
|
||||
2. VF/SF representor bonding (Usually used for Live migration)
|
||||
3. Stacked devices
|
||||
|
||||
When metadata is disabled, the above use cases will fail to initialize if
|
||||
users try to enable them.
|
||||
|
||||
- Show eswitch port metadata::
|
||||
|
||||
$ devlink dev param show pci/0000:06:00.0 name esw_port_metadata
|
||||
pci/0000:06:00.0:
|
||||
name esw_port_metadata type driver-specific
|
||||
values:
|
||||
cmode runtime value true
|
||||
|
||||
- Disable eswitch port metadata::
|
||||
|
||||
$ devlink dev param set pci/0000:06:00.0 name esw_port_metadata value false cmode runtime
|
||||
|
||||
- Change eswitch mode to switchdev mode where after choosing the metadata value::
|
||||
|
||||
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
|
||||
|
||||
mlx5 subfunction
|
||||
================
|
||||
mlx5 supports subfunction management using devlink port (see :ref:`Documentation/networking/devlink/devlink-port.rst <devlink_port>`) interface.
|
||||
|
@ -87,11 +87,15 @@ Receive Buffer
|
||||
contain one or more packets. The number of receive sections may be changed
|
||||
via ethtool Rx ring parameters.
|
||||
|
||||
There is a similar send buffer which is used to aggregate packets for sending.
|
||||
The send area is broken into chunks of 6144 bytes, each of section may
|
||||
contain one or more packets. The send buffer is an optimization, the driver
|
||||
will use slower method to handle very large packets or if the send buffer
|
||||
area is exhausted.
|
||||
There is a similar send buffer which is used to aggregate packets
|
||||
for sending. The send area is broken into chunks, typically of 6144
|
||||
bytes, each of section may contain one or more packets. Small
|
||||
packets are usually transmitted via copy to the send buffer. However,
|
||||
if the buffer is temporarily exhausted, or the packet to be transmitted is
|
||||
an LSO packet, the driver will provide the host with pointers to the data
|
||||
from the SKB. This attempts to achieve a balance between the overhead of
|
||||
data copy and the impact of remapping VM memory to be accessible by the
|
||||
host.
|
||||
|
||||
XDP support
|
||||
-----------
|
||||
|
@ -60,4 +60,4 @@ To do:
|
||||
|
||||
Both success and failure reports are welcome.
|
||||
|
||||
Maciej W. Rozycki <macro@linux-mips.org>
|
||||
Maciej W. Rozycki <macro@orcam.me.uk>
|
||||
|
@ -24,7 +24,7 @@ attributes of the health reporting and recovery procedures.
|
||||
|
||||
The ``devlink`` health reporter:
|
||||
Device driver creates a "health reporter" per each error/health type.
|
||||
Error/Health type can be a known/generic (eg pci error, fw error, rx/tx error)
|
||||
Error/Health type can be a known/generic (e.g. PCI error, fw error, rx/tx error)
|
||||
or unknown (driver specific).
|
||||
For each registered health reporter a driver can issue error/health reports
|
||||
asynchronously. All health reports handling is done by ``devlink``.
|
||||
@ -48,6 +48,7 @@ Once an error is reported, devlink health will perform the following actions:
|
||||
* Object dump is being taken and saved at the reporter instance (as long as
|
||||
there is no other dump which is already stored)
|
||||
* Auto recovery attempt is being done. Depends on:
|
||||
|
||||
- Auto-recovery configuration
|
||||
- Grace period vs. time passed since last recover
|
||||
|
||||
@ -72,14 +73,18 @@ via ``devlink``, e.g per error type (per health reporter):
|
||||
* - ``DEVLINK_CMD_HEALTH_REPORTER_SET``
|
||||
- Allows reporter-related configuration setting.
|
||||
* - ``DEVLINK_CMD_HEALTH_REPORTER_RECOVER``
|
||||
- Triggers a reporter's recovery procedure.
|
||||
- Triggers reporter's recovery procedure.
|
||||
* - ``DEVLINK_CMD_HEALTH_REPORTER_TEST``
|
||||
- Triggers a fake health event on the reporter. The effects of the test
|
||||
event in terms of recovery flow should follow closely that of a real
|
||||
event.
|
||||
* - ``DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE``
|
||||
- Retrieves diagnostics data from a reporter on a device.
|
||||
- Retrieves current device state related to the reporter.
|
||||
* - ``DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET``
|
||||
- Retrieves the last stored dump. Devlink health
|
||||
saves a single dump. If an dump is not already stored by the devlink
|
||||
saves a single dump. If an dump is not already stored by devlink
|
||||
for this reporter, devlink generates a new dump.
|
||||
dump output is defined by the reporter.
|
||||
Dump output is defined by the reporter.
|
||||
* - ``DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR``
|
||||
- Clears the last saved dump file for the specified reporter.
|
||||
|
||||
@ -93,7 +98,7 @@ The following diagram provides a general overview of ``devlink-health``::
|
||||
+--------------------------+
|
||||
|request for ops
|
||||
|(diagnose,
|
||||
mlx5_core devlink |recover,
|
||||
driver devlink |recover,
|
||||
|dump)
|
||||
+--------+ +--------------------------+
|
||||
| | | reporter| |
|
||||
|
@ -34,8 +34,15 @@ interface. The CPU port is the switch port connected to an Ethernet MAC chip.
|
||||
The corresponding linux Ethernet interface is called the master interface.
|
||||
All other corresponding linux interfaces are called slave interfaces.
|
||||
|
||||
The slave interfaces depend on the master interface. They can only brought up,
|
||||
when the master interface is up.
|
||||
The slave interfaces depend on the master interface being up in order for them
|
||||
to send or receive traffic. Prior to kernel v5.12, the state of the master
|
||||
interface had to be managed explicitly by the user. Starting with kernel v5.12,
|
||||
the behavior is as follows:
|
||||
|
||||
- when a DSA slave interface is brought up, the master interface is
|
||||
automatically brought up.
|
||||
- when the master interface is brought down, all DSA slave interfaces are
|
||||
automatically brought down.
|
||||
|
||||
In this documentation the following Ethernet interfaces are used:
|
||||
|
||||
@ -78,79 +85,76 @@ The tagging based configuration is desired and supported by the majority of
|
||||
DSA switches. These switches are capable to tag incoming and outgoing traffic
|
||||
without using a VLAN based configuration.
|
||||
|
||||
single port
|
||||
~~~~~~~~~~~
|
||||
*single port*
|
||||
.. code-block:: sh
|
||||
|
||||
.. code-block:: sh
|
||||
# configure each interface
|
||||
ip addr add 192.0.2.1/30 dev lan1
|
||||
ip addr add 192.0.2.5/30 dev lan2
|
||||
ip addr add 192.0.2.9/30 dev lan3
|
||||
|
||||
# configure each interface
|
||||
ip addr add 192.0.2.1/30 dev lan1
|
||||
ip addr add 192.0.2.5/30 dev lan2
|
||||
ip addr add 192.0.2.9/30 dev lan3
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
ip link set eth0 up
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
ip link set eth0 up
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
*bridge*
|
||||
.. code-block:: sh
|
||||
|
||||
bridge
|
||||
~~~~~~
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
ip link set eth0 up
|
||||
|
||||
.. code-block:: sh
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
ip link set eth0 up
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
# add ports to bridge
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
ip link set dev lan3 master br0
|
||||
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
# configure the bridge
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
|
||||
# add ports to bridge
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
ip link set dev lan3 master br0
|
||||
# bring up the bridge
|
||||
ip link set dev br0 up
|
||||
|
||||
# configure the bridge
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
*gateway*
|
||||
.. code-block:: sh
|
||||
|
||||
# bring up the bridge
|
||||
ip link set dev br0 up
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
ip link set eth0 up
|
||||
|
||||
gateway
|
||||
~~~~~~~
|
||||
# bring up the slave interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
|
||||
.. code-block:: sh
|
||||
# configure the upstream port
|
||||
ip addr add 192.0.2.1/30 dev wan
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
ip link set eth0 up
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
|
||||
# bring up the slave interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
# add ports to bridge
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
|
||||
# configure the upstream port
|
||||
ip addr add 192.0.2.1/30 dev wan
|
||||
# configure the bridge
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
|
||||
# add ports to bridge
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
|
||||
# configure the bridge
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
|
||||
# bring up the bridge
|
||||
ip link set dev br0 up
|
||||
# bring up the bridge
|
||||
ip link set dev br0 up
|
||||
|
||||
.. _dsa-vlan-configuration:
|
||||
|
||||
@ -161,132 +165,130 @@ A minority of switches are not capable to use a taging protocol
|
||||
(DSA_TAG_PROTO_NONE). These switches can be configured by a VLAN based
|
||||
configuration.
|
||||
|
||||
single port
|
||||
~~~~~~~~~~~
|
||||
The configuration can only be set up via VLAN tagging and bridge setup.
|
||||
*single port*
|
||||
The configuration can only be set up via VLAN tagging and bridge setup.
|
||||
|
||||
.. code-block:: sh
|
||||
.. code-block:: sh
|
||||
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
ip link add link eth0 name eth0.3 type vlan id 3
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
ip link add link eth0 name eth0.3 type vlan id 3
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
ip link set eth0.3 up
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
ip link set eth0.3 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
|
||||
# activate VLAN filtering
|
||||
ip link set dev br0 type bridge vlan_filtering 1
|
||||
# activate VLAN filtering
|
||||
ip link set dev br0 type bridge vlan_filtering 1
|
||||
|
||||
# add ports to bridges
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
ip link set dev lan3 master br0
|
||||
# add ports to bridges
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
ip link set dev lan3 master br0
|
||||
|
||||
# tag traffic on ports
|
||||
bridge vlan add dev lan1 vid 1 pvid untagged
|
||||
bridge vlan add dev lan2 vid 2 pvid untagged
|
||||
bridge vlan add dev lan3 vid 3 pvid untagged
|
||||
# tag traffic on ports
|
||||
bridge vlan add dev lan1 vid 1 pvid untagged
|
||||
bridge vlan add dev lan2 vid 2 pvid untagged
|
||||
bridge vlan add dev lan3 vid 3 pvid untagged
|
||||
|
||||
# configure the VLANs
|
||||
ip addr add 192.0.2.1/30 dev eth0.1
|
||||
ip addr add 192.0.2.5/30 dev eth0.2
|
||||
ip addr add 192.0.2.9/30 dev eth0.3
|
||||
# configure the VLANs
|
||||
ip addr add 192.0.2.1/30 dev eth0.1
|
||||
ip addr add 192.0.2.5/30 dev eth0.2
|
||||
ip addr add 192.0.2.9/30 dev eth0.3
|
||||
|
||||
# bring up the bridge devices
|
||||
ip link set br0 up
|
||||
# bring up the bridge devices
|
||||
ip link set br0 up
|
||||
|
||||
|
||||
bridge
|
||||
~~~~~~
|
||||
*bridge*
|
||||
.. code-block:: sh
|
||||
|
||||
.. code-block:: sh
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
# activate VLAN filtering
|
||||
ip link set dev br0 type bridge vlan_filtering 1
|
||||
|
||||
# activate VLAN filtering
|
||||
ip link set dev br0 type bridge vlan_filtering 1
|
||||
# add ports to bridge
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
ip link set dev lan3 master br0
|
||||
ip link set eth0.1 master br0
|
||||
|
||||
# add ports to bridge
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
ip link set dev lan3 master br0
|
||||
ip link set eth0.1 master br0
|
||||
# tag traffic on ports
|
||||
bridge vlan add dev lan1 vid 1 pvid untagged
|
||||
bridge vlan add dev lan2 vid 1 pvid untagged
|
||||
bridge vlan add dev lan3 vid 1 pvid untagged
|
||||
|
||||
# tag traffic on ports
|
||||
bridge vlan add dev lan1 vid 1 pvid untagged
|
||||
bridge vlan add dev lan2 vid 1 pvid untagged
|
||||
bridge vlan add dev lan3 vid 1 pvid untagged
|
||||
# configure the bridge
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
|
||||
# configure the bridge
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
# bring up the bridge
|
||||
ip link set dev br0 up
|
||||
|
||||
# bring up the bridge
|
||||
ip link set dev br0 up
|
||||
*gateway*
|
||||
.. code-block:: sh
|
||||
|
||||
gateway
|
||||
~~~~~~~
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
|
||||
.. code-block:: sh
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
# bring up the slave interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
|
||||
# bring up the slave interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
# activate VLAN filtering
|
||||
ip link set dev br0 type bridge vlan_filtering 1
|
||||
|
||||
# create bridge
|
||||
ip link add name br0 type bridge
|
||||
# add ports to bridges
|
||||
ip link set dev wan master br0
|
||||
ip link set eth0.1 master br0
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
|
||||
# activate VLAN filtering
|
||||
ip link set dev br0 type bridge vlan_filtering 1
|
||||
# tag traffic on ports
|
||||
bridge vlan add dev lan1 vid 1 pvid untagged
|
||||
bridge vlan add dev lan2 vid 1 pvid untagged
|
||||
bridge vlan add dev wan vid 2 pvid untagged
|
||||
|
||||
# add ports to bridges
|
||||
ip link set dev wan master br0
|
||||
ip link set eth0.1 master br0
|
||||
ip link set dev lan1 master br0
|
||||
ip link set dev lan2 master br0
|
||||
# configure the VLANs
|
||||
ip addr add 192.0.2.1/30 dev eth0.2
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
|
||||
# tag traffic on ports
|
||||
bridge vlan add dev lan1 vid 1 pvid untagged
|
||||
bridge vlan add dev lan2 vid 1 pvid untagged
|
||||
bridge vlan add dev wan vid 2 pvid untagged
|
||||
|
||||
# configure the VLANs
|
||||
ip addr add 192.0.2.1/30 dev eth0.2
|
||||
ip addr add 192.0.2.129/25 dev br0
|
||||
|
||||
# bring up the bridge devices
|
||||
ip link set br0 up
|
||||
# bring up the bridge devices
|
||||
ip link set br0 up
|
||||
|
@ -65,14 +65,8 @@ Note that DSA does not currently create network interfaces for the "cpu" and
|
||||
Switch tagging protocols
|
||||
------------------------
|
||||
|
||||
DSA currently supports 5 different tagging protocols, and a tag-less mode as
|
||||
well. The different protocols are implemented in:
|
||||
|
||||
- ``net/dsa/tag_trailer.c``: Marvell's 4 trailer tag mode (legacy)
|
||||
- ``net/dsa/tag_dsa.c``: Marvell's original DSA tag
|
||||
- ``net/dsa/tag_edsa.c``: Marvell's enhanced DSA tag
|
||||
- ``net/dsa/tag_brcm.c``: Broadcom's 4 bytes tag
|
||||
- ``net/dsa/tag_qca.c``: Qualcomm's 2 bytes tag
|
||||
DSA supports many vendor-specific tagging protocols, one software-defined
|
||||
tagging protocol, and a tag-less mode as well (``DSA_TAG_PROTO_NONE``).
|
||||
|
||||
The exact format of the tag protocol is vendor specific, but in general, they
|
||||
all contain something which:
|
||||
@ -80,6 +74,144 @@ all contain something which:
|
||||
- identifies which port the Ethernet frame came from/should be sent to
|
||||
- provides a reason why this frame was forwarded to the management interface
|
||||
|
||||
All tagging protocols are in ``net/dsa/tag_*.c`` files and implement the
|
||||
methods of the ``struct dsa_device_ops`` structure, which are detailed below.
|
||||
|
||||
Tagging protocols generally fall in one of three categories:
|
||||
|
||||
1. The switch-specific frame header is located before the Ethernet header,
|
||||
shifting to the right (from the perspective of the DSA master's frame
|
||||
parser) the MAC DA, MAC SA, EtherType and the entire L2 payload.
|
||||
2. The switch-specific frame header is located before the EtherType, keeping
|
||||
the MAC DA and MAC SA in place from the DSA master's perspective, but
|
||||
shifting the 'real' EtherType and L2 payload to the right.
|
||||
3. The switch-specific frame header is located at the tail of the packet,
|
||||
keeping all frame headers in place and not altering the view of the packet
|
||||
that the DSA master's frame parser has.
|
||||
|
||||
A tagging protocol may tag all packets with switch tags of the same length, or
|
||||
the tag length might vary (for example packets with PTP timestamps might
|
||||
require an extended switch tag, or there might be one tag length on TX and a
|
||||
different one on RX). Either way, the tagging protocol driver must populate the
|
||||
``struct dsa_device_ops::overhead`` with the length in octets of the longest
|
||||
switch frame header. The DSA framework will automatically adjust the MTU of the
|
||||
master interface to accomodate for this extra size in order for DSA user ports
|
||||
to support the standard MTU (L2 payload length) of 1500 octets. The ``overhead``
|
||||
is also used to request from the network stack, on a best-effort basis, the
|
||||
allocation of packets with a ``needed_headroom`` or ``needed_tailroom``
|
||||
sufficient such that the act of pushing the switch tag on transmission of a
|
||||
packet does not cause it to reallocate due to lack of memory.
|
||||
|
||||
Even though applications are not expected to parse DSA-specific frame headers,
|
||||
the format on the wire of the tagging protocol represents an Application Binary
|
||||
Interface exposed by the kernel towards user space, for decoders such as
|
||||
``libpcap``. The tagging protocol driver must populate the ``proto`` member of
|
||||
``struct dsa_device_ops`` with a value that uniquely describes the
|
||||
characteristics of the interaction required between the switch hardware and the
|
||||
data path driver: the offset of each bit field within the frame header and any
|
||||
stateful processing required to deal with the frames (as may be required for
|
||||
PTP timestamping).
|
||||
|
||||
From the perspective of the network stack, all switches within the same DSA
|
||||
switch tree use the same tagging protocol. In case of a packet transiting a
|
||||
fabric with more than one switch, the switch-specific frame header is inserted
|
||||
by the first switch in the fabric that the packet was received on. This header
|
||||
typically contains information regarding its type (whether it is a control
|
||||
frame that must be trapped to the CPU, or a data frame to be forwarded).
|
||||
Control frames should be decapsulated only by the software data path, whereas
|
||||
data frames might also be autonomously forwarded towards other user ports of
|
||||
other switches from the same fabric, and in this case, the outermost switch
|
||||
ports must decapsulate the packet.
|
||||
|
||||
Note that in certain cases, it might be the case that the tagging format used
|
||||
by a leaf switch (not connected directly to the CPU) to not be the same as what
|
||||
the network stack sees. This can be seen with Marvell switch trees, where the
|
||||
CPU port can be configured to use either the DSA or the Ethertype DSA (EDSA)
|
||||
format, but the DSA links are configured to use the shorter (without Ethertype)
|
||||
DSA frame header, in order to reduce the autonomous packet forwarding overhead.
|
||||
It still remains the case that, if the DSA switch tree is configured for the
|
||||
EDSA tagging protocol, the operating system sees EDSA-tagged packets from the
|
||||
leaf switches that tagged them with the shorter DSA header. This can be done
|
||||
because the Marvell switch connected directly to the CPU is configured to
|
||||
perform tag translation between DSA and EDSA (which is simply the operation of
|
||||
adding or removing the ``ETH_P_EDSA`` EtherType and some padding octets).
|
||||
|
||||
It is possible to construct cascaded setups of DSA switches even if their
|
||||
tagging protocols are not compatible with one another. In this case, there are
|
||||
no DSA links in this fabric, and each switch constitutes a disjoint DSA switch
|
||||
tree. The DSA links are viewed as simply a pair of a DSA master (the out-facing
|
||||
port of the upstream DSA switch) and a CPU port (the in-facing port of the
|
||||
downstream DSA switch).
|
||||
|
||||
The tagging protocol of the attached DSA switch tree can be viewed through the
|
||||
``dsa/tagging`` sysfs attribute of the DSA master::
|
||||
|
||||
cat /sys/class/net/eth0/dsa/tagging
|
||||
|
||||
If the hardware and driver are capable, the tagging protocol of the DSA switch
|
||||
tree can be changed at runtime. This is done by writing the new tagging
|
||||
protocol name to the same sysfs device attribute as above (the DSA master and
|
||||
all attached switch ports must be down while doing this).
|
||||
|
||||
It is desirable that all tagging protocols are testable with the ``dsa_loop``
|
||||
mockup driver, which can be attached to any network interface. The goal is that
|
||||
any network interface should be capable of transmitting the same packet in the
|
||||
same way, and the tagger should decode the same received packet in the same way
|
||||
regardless of the driver used for the switch control path, and the driver used
|
||||
for the DSA master.
|
||||
|
||||
The transmission of a packet goes through the tagger's ``xmit`` function.
|
||||
The passed ``struct sk_buff *skb`` has ``skb->data`` pointing at
|
||||
``skb_mac_header(skb)``, i.e. at the destination MAC address, and the passed
|
||||
``struct net_device *dev`` represents the virtual DSA user network interface
|
||||
whose hardware counterpart the packet must be steered to (i.e. ``swp0``).
|
||||
The job of this method is to prepare the skb in a way that the switch will
|
||||
understand what egress port the packet is for (and not deliver it towards other
|
||||
ports). Typically this is fulfilled by pushing a frame header. Checking for
|
||||
insufficient size in the skb headroom or tailroom is unnecessary provided that
|
||||
the ``overhead`` and ``tail_tag`` properties were filled out properly, because
|
||||
DSA ensures there is enough space before calling this method.
|
||||
|
||||
The reception of a packet goes through the tagger's ``rcv`` function. The
|
||||
passed ``struct sk_buff *skb`` has ``skb->data`` pointing at
|
||||
``skb_mac_header(skb) + ETH_ALEN`` octets, i.e. to where the first octet after
|
||||
the EtherType would have been, were this frame not tagged. The role of this
|
||||
method is to consume the frame header, adjust ``skb->data`` to really point at
|
||||
the first octet after the EtherType, and to change ``skb->dev`` to point to the
|
||||
virtual DSA user network interface corresponding to the physical front-facing
|
||||
switch port that the packet was received on.
|
||||
|
||||
Since tagging protocols in category 1 and 2 break software (and most often also
|
||||
hardware) packet dissection on the DSA master, features such as RPS (Receive
|
||||
Packet Steering) on the DSA master would be broken. The DSA framework deals
|
||||
with this by hooking into the flow dissector and shifting the offset at which
|
||||
the IP header is to be found in the tagged frame as seen by the DSA master.
|
||||
This behavior is automatic based on the ``overhead`` value of the tagging
|
||||
protocol. If not all packets are of equal size, the tagger can implement the
|
||||
``flow_dissect`` method of the ``struct dsa_device_ops`` and override this
|
||||
default behavior by specifying the correct offset incurred by each individual
|
||||
RX packet. Tail taggers do not cause issues to the flow dissector.
|
||||
|
||||
Due to various reasons (most common being category 1 taggers being associated
|
||||
with DSA-unaware masters, mangling what the master perceives as MAC DA), the
|
||||
tagging protocol may require the DSA master to operate in promiscuous mode, to
|
||||
receive all frames regardless of the value of the MAC DA. This can be done by
|
||||
setting the ``promisc_on_master`` property of the ``struct dsa_device_ops``.
|
||||
Note that this assumes a DSA-unaware master driver, which is the norm.
|
||||
|
||||
Hardware manufacturers are strongly discouraged to do this, but some tagging
|
||||
protocols might not provide source port information on RX for all packets, but
|
||||
e.g. only for control traffic (link-local PDUs). In this case, by implementing
|
||||
the ``filter`` method of ``struct dsa_device_ops``, the tagger might select
|
||||
which packets are to be redirected on RX towards the virtual DSA user network
|
||||
interfaces, and which are to be left in the DSA master's RX data path.
|
||||
|
||||
It might also happen (although silicon vendors are strongly discouraged to
|
||||
produce hardware like this) that a tagging protocol splits the switch-specific
|
||||
information into a header portion and a tail portion, therefore not falling
|
||||
cleanly into any of the above 3 categories. DSA does not support this
|
||||
configuration.
|
||||
|
||||
Master network devices
|
||||
----------------------
|
||||
|
||||
@ -172,23 +304,34 @@ Graphical representation
|
||||
Summarized, this is basically how DSA looks like from a network device
|
||||
perspective::
|
||||
|
||||
|
||||
|---------------------------
|
||||
| CPU network device (eth0)|
|
||||
----------------------------
|
||||
| <tag added by switch |
|
||||
| |
|
||||
| |
|
||||
| tag added by CPU> |
|
||||
|--------------------------------------------|
|
||||
| Switch driver |
|
||||
|--------------------------------------------|
|
||||
|| || ||
|
||||
|-------| |-------| |-------|
|
||||
| sw0p0 | | sw0p1 | | sw0p2 |
|
||||
|-------| |-------| |-------|
|
||||
|
||||
|
||||
Unaware application
|
||||
opens and binds socket
|
||||
| ^
|
||||
| |
|
||||
+-----------v--|--------------------+
|
||||
|+------+ +------+ +------+ +------+|
|
||||
|| swp0 | | swp1 | | swp2 | | swp3 ||
|
||||
|+------+-+------+-+------+-+------+|
|
||||
| DSA switch driver |
|
||||
+-----------------------------------+
|
||||
| ^
|
||||
Tag added by | | Tag consumed by
|
||||
switch driver | | switch driver
|
||||
v |
|
||||
+-----------------------------------+
|
||||
| Unmodified host interface driver | Software
|
||||
--------+-----------------------------------+------------
|
||||
| Host interface (eth0) | Hardware
|
||||
+-----------------------------------+
|
||||
| ^
|
||||
Tag consumed by | | Tag added by
|
||||
switch hardware | | switch hardware
|
||||
v |
|
||||
+-----------------------------------+
|
||||
| Switch |
|
||||
|+------+ +------+ +------+ +------+|
|
||||
|| swp0 | | swp1 | | swp2 | | swp3 ||
|
||||
++------+-+------+-+------+-+------++
|
||||
|
||||
Slave MDIO bus
|
||||
--------------
|
||||
@ -239,14 +382,6 @@ DSA data structures are defined in ``include/net/dsa.h`` as well as
|
||||
Design limitations
|
||||
==================
|
||||
|
||||
Limits on the number of devices and ports
|
||||
-----------------------------------------
|
||||
|
||||
DSA currently limits the number of maximum switches within a tree to 4
|
||||
(``DSA_MAX_SWITCHES``), and the number of ports per switch to 12 (``DSA_MAX_PORTS``).
|
||||
These limits could be extended to support larger configurations would this need
|
||||
arise.
|
||||
|
||||
Lack of CPU/DSA network devices
|
||||
-------------------------------
|
||||
|
||||
@ -281,6 +416,7 @@ DSA currently leverages the following subsystems:
|
||||
- MDIO/PHY library: ``drivers/net/phy/phy.c``, ``mdio_bus.c``
|
||||
- Switchdev:``net/switchdev/*``
|
||||
- Device Tree for various of_* functions
|
||||
- Devlink: ``net/core/devlink.c``
|
||||
|
||||
MDIO/PHY library
|
||||
----------------
|
||||
@ -317,14 +453,39 @@ SWITCHDEV
|
||||
|
||||
DSA directly utilizes SWITCHDEV when interfacing with the bridge layer, and
|
||||
more specifically with its VLAN filtering portion when configuring VLANs on top
|
||||
of per-port slave network devices. Since DSA primarily deals with
|
||||
MDIO-connected switches, although not exclusively, SWITCHDEV's
|
||||
prepare/abort/commit phases are often simplified into a prepare phase which
|
||||
checks whether the operation is supported by the DSA switch driver, and a commit
|
||||
phase which applies the changes.
|
||||
of per-port slave network devices. As of today, the only SWITCHDEV objects
|
||||
supported by DSA are the FDB and VLAN objects.
|
||||
|
||||
As of today, the only SWITCHDEV objects supported by DSA are the FDB and VLAN
|
||||
objects.
|
||||
Devlink
|
||||
-------
|
||||
|
||||
DSA registers one devlink device per physical switch in the fabric.
|
||||
For each devlink device, every physical port (i.e. user ports, CPU ports, DSA
|
||||
links or unused ports) is exposed as a devlink port.
|
||||
|
||||
DSA drivers can make use of the following devlink features:
|
||||
|
||||
- Regions: debugging feature which allows user space to dump driver-defined
|
||||
areas of hardware information in a low-level, binary format. Both global
|
||||
regions as well as per-port regions are supported. It is possible to export
|
||||
devlink regions even for pieces of data that are already exposed in some way
|
||||
to the standard iproute2 user space programs (ip-link, bridge), like address
|
||||
tables and VLAN tables. For example, this might be useful if the tables
|
||||
contain additional hardware-specific details which are not visible through
|
||||
the iproute2 abstraction, or it might be useful to inspect these tables on
|
||||
the non-user ports too, which are invisible to iproute2 because no network
|
||||
interface is registered for them.
|
||||
- Params: a feature which enables user to configure certain low-level tunable
|
||||
knobs pertaining to the device. Drivers may implement applicable generic
|
||||
devlink params, or may add new device-specific devlink params.
|
||||
- Resources: a monitoring feature which enables users to see the degree of
|
||||
utilization of certain hardware tables in the device, such as FDB, VLAN, etc.
|
||||
- Shared buffers: a QoS feature for adjusting and partitioning memory and frame
|
||||
reservations per port and per traffic class, in the ingress and egress
|
||||
directions, such that low-priority bulk traffic does not impede the
|
||||
processing of high-priority critical traffic.
|
||||
|
||||
For more details, consult ``Documentation/networking/devlink/``.
|
||||
|
||||
Device Tree
|
||||
-----------
|
||||
@ -490,6 +651,17 @@ Bridge layer
|
||||
computing a STP state change based on current and asked parameters and perform
|
||||
the relevant ageing based on the intersection results
|
||||
|
||||
- ``port_bridge_flags``: bridge layer function invoked when a port must
|
||||
configure its settings for e.g. flooding of unknown traffic or source address
|
||||
learning. The switch driver is responsible for initial setup of the
|
||||
standalone ports with address learning disabled and egress flooding of all
|
||||
types of traffic, then the DSA core notifies of any change to the bridge port
|
||||
flags when the port joins and leaves a bridge. DSA does not currently manage
|
||||
the bridge port flags for the CPU port. The assumption is that address
|
||||
learning should be statically enabled (if supported by the hardware) on the
|
||||
CPU port, and flooding towards the CPU port should also be enabled, due to a
|
||||
lack of an explicit address filtering mechanism in the DSA core.
|
||||
|
||||
Bridge VLAN filtering
|
||||
---------------------
|
||||
|
||||
@ -503,14 +675,10 @@ Bridge VLAN filtering
|
||||
accept any 802.1Q frames irrespective of their VLAN ID, and untagged frames are
|
||||
allowed.
|
||||
|
||||
- ``port_vlan_prepare``: bridge layer function invoked when the bridge prepares the
|
||||
configuration of a VLAN on the given port. If the operation is not supported
|
||||
by the hardware, this function should return ``-EOPNOTSUPP`` to inform the bridge
|
||||
code to fallback to a software implementation. No hardware setup must be done
|
||||
in this function. See port_vlan_add for this and details.
|
||||
|
||||
- ``port_vlan_add``: bridge layer function invoked when a VLAN is configured
|
||||
(tagged or untagged) for the given switch port
|
||||
(tagged or untagged) for the given switch port. If the operation is not
|
||||
supported by the hardware, this function should return ``-EOPNOTSUPP`` to
|
||||
inform the bridge code to fallback to a software implementation.
|
||||
|
||||
- ``port_vlan_del``: bridge layer function invoked when a VLAN is removed from the
|
||||
given switch port
|
||||
@ -538,14 +706,10 @@ Bridge VLAN filtering
|
||||
function that the driver has to call for each MAC address known to be behind
|
||||
the given port. A switchdev object is used to carry the VID and FDB info.
|
||||
|
||||
- ``port_mdb_prepare``: bridge layer function invoked when the bridge prepares the
|
||||
installation of a multicast database entry. If the operation is not supported,
|
||||
this function should return ``-EOPNOTSUPP`` to inform the bridge code to fallback
|
||||
to a software implementation. No hardware setup must be done in this function.
|
||||
See ``port_fdb_add`` for this and details.
|
||||
|
||||
- ``port_mdb_add``: bridge layer function invoked when the bridge wants to install
|
||||
a multicast database entry, the switch hardware should be programmed with the
|
||||
a multicast database entry. If the operation is not supported, this function
|
||||
should return ``-EOPNOTSUPP`` to inform the bridge code to fallback to a
|
||||
software implementation. The switch hardware should be programmed with the
|
||||
specified address in the specified VLAN ID in the forwarding database
|
||||
associated with this VLAN ID.
|
||||
|
||||
@ -561,6 +725,101 @@ Bridge VLAN filtering
|
||||
function that the driver has to call for each MAC address known to be behind
|
||||
the given port. A switchdev object is used to carry the VID and MDB info.
|
||||
|
||||
Link aggregation
|
||||
----------------
|
||||
|
||||
Link aggregation is implemented in the Linux networking stack by the bonding
|
||||
and team drivers, which are modeled as virtual, stackable network interfaces.
|
||||
DSA is capable of offloading a link aggregation group (LAG) to hardware that
|
||||
supports the feature, and supports bridging between physical ports and LAGs,
|
||||
as well as between LAGs. A bonding/team interface which holds multiple physical
|
||||
ports constitutes a logical port, although DSA has no explicit concept of a
|
||||
logical port at the moment. Due to this, events where a LAG joins/leaves a
|
||||
bridge are treated as if all individual physical ports that are members of that
|
||||
LAG join/leave the bridge. Switchdev port attributes (VLAN filtering, STP
|
||||
state, etc) and objects (VLANs, MDB entries) offloaded to a LAG as bridge port
|
||||
are treated similarly: DSA offloads the same switchdev object / port attribute
|
||||
on all members of the LAG. Static bridge FDB entries on a LAG are not yet
|
||||
supported, since the DSA driver API does not have the concept of a logical port
|
||||
ID.
|
||||
|
||||
- ``port_lag_join``: function invoked when a given switch port is added to a
|
||||
LAG. The driver may return ``-EOPNOTSUPP``, and in this case, DSA will fall
|
||||
back to a software implementation where all traffic from this port is sent to
|
||||
the CPU.
|
||||
- ``port_lag_leave``: function invoked when a given switch port leaves a LAG
|
||||
and returns to operation as a standalone port.
|
||||
- ``port_lag_change``: function invoked when the link state of any member of
|
||||
the LAG changes, and the hashing function needs rebalancing to only make use
|
||||
of the subset of physical LAG member ports that are up.
|
||||
|
||||
Drivers that benefit from having an ID associated with each offloaded LAG
|
||||
can optionally populate ``ds->num_lag_ids`` from the ``dsa_switch_ops::setup``
|
||||
method. The LAG ID associated with a bonding/team interface can then be
|
||||
retrieved by a DSA switch driver using the ``dsa_lag_id`` function.
|
||||
|
||||
IEC 62439-2 (MRP)
|
||||
-----------------
|
||||
|
||||
The Media Redundancy Protocol is a topology management protocol optimized for
|
||||
fast fault recovery time for ring networks, which has some components
|
||||
implemented as a function of the bridge driver. MRP uses management PDUs
|
||||
(Test, Topology, LinkDown/Up, Option) sent at a multicast destination MAC
|
||||
address range of 01:15:4e:00:00:0x and with an EtherType of 0x88e3.
|
||||
Depending on the node's role in the ring (MRM: Media Redundancy Manager,
|
||||
MRC: Media Redundancy Client, MRA: Media Redundancy Automanager), certain MRP
|
||||
PDUs might need to be terminated locally and others might need to be forwarded.
|
||||
An MRM might also benefit from offloading to hardware the creation and
|
||||
transmission of certain MRP PDUs (Test).
|
||||
|
||||
Normally an MRP instance can be created on top of any network interface,
|
||||
however in the case of a device with an offloaded data path such as DSA, it is
|
||||
necessary for the hardware, even if it is not MRP-aware, to be able to extract
|
||||
the MRP PDUs from the fabric before the driver can proceed with the software
|
||||
implementation. DSA today has no driver which is MRP-aware, therefore it only
|
||||
listens for the bare minimum switchdev objects required for the software assist
|
||||
to work properly. The operations are detailed below.
|
||||
|
||||
- ``port_mrp_add`` and ``port_mrp_del``: notifies driver when an MRP instance
|
||||
with a certain ring ID, priority, primary port and secondary port is
|
||||
created/deleted.
|
||||
- ``port_mrp_add_ring_role`` and ``port_mrp_del_ring_role``: function invoked
|
||||
when an MRP instance changes ring roles between MRM or MRC. This affects
|
||||
which MRP PDUs should be trapped to software and which should be autonomously
|
||||
forwarded.
|
||||
|
||||
IEC 62439-3 (HSR/PRP)
|
||||
---------------------
|
||||
|
||||
The Parallel Redundancy Protocol (PRP) is a network redundancy protocol which
|
||||
works by duplicating and sequence numbering packets through two independent L2
|
||||
networks (which are unaware of the PRP tail tags carried in the packets), and
|
||||
eliminating the duplicates at the receiver. The High-availability Seamless
|
||||
Redundancy (HSR) protocol is similar in concept, except all nodes that carry
|
||||
the redundant traffic are aware of the fact that it is HSR-tagged (because HSR
|
||||
uses a header with an EtherType of 0x892f) and are physically connected in a
|
||||
ring topology. Both HSR and PRP use supervision frames for monitoring the
|
||||
health of the network and for discovery of other nodes.
|
||||
|
||||
In Linux, both HSR and PRP are implemented in the hsr driver, which
|
||||
instantiates a virtual, stackable network interface with two member ports.
|
||||
The driver only implements the basic roles of DANH (Doubly Attached Node
|
||||
implementing HSR) and DANP (Doubly Attached Node implementing PRP); the roles
|
||||
of RedBox and QuadBox are not implemented (therefore, bridging a hsr network
|
||||
interface with a physical switch port does not produce the expected result).
|
||||
|
||||
A driver which is able of offloading certain functions of a DANP or DANH should
|
||||
declare the corresponding netdev features as indicated by the documentation at
|
||||
``Documentation/networking/netdev-features.rst``. Additionally, the following
|
||||
methods must be implemented:
|
||||
|
||||
- ``port_hsr_join``: function invoked when a given switch port is added to a
|
||||
DANP/DANH. The driver may return ``-EOPNOTSUPP`` and in this case, DSA will
|
||||
fall back to a software implementation where all traffic from this port is
|
||||
sent to the CPU.
|
||||
- ``port_hsr_leave``: function invoked when a given switch port leaves a
|
||||
DANP/DANH and returns to normal operation as a standalone port.
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
@ -576,8 +835,5 @@ two subsystems and get the best of both worlds.
|
||||
Other hanging fruits
|
||||
--------------------
|
||||
|
||||
- making the number of ports fully dynamic and not dependent on ``DSA_MAX_PORTS``
|
||||
- allowing more than one CPU/management interface:
|
||||
http://comments.gmane.org/gmane.linux.network/365657
|
||||
- porting more drivers from other vendors:
|
||||
http://comments.gmane.org/gmane.linux.network/365510
|
||||
|
@ -208,41 +208,49 @@ Userspace to kernel:
|
||||
``ETHTOOL_MSG_CABLE_TEST_ACT`` action start cable test
|
||||
``ETHTOOL_MSG_CABLE_TEST_TDR_ACT`` action start raw TDR cable test
|
||||
``ETHTOOL_MSG_TUNNEL_INFO_GET`` get tunnel offload info
|
||||
``ETHTOOL_MSG_FEC_GET`` get FEC settings
|
||||
``ETHTOOL_MSG_FEC_SET`` set FEC settings
|
||||
``ETHTOOL_MSG_MODULE_EEPROM_GET`` read SFP module EEPROM
|
||||
``ETHTOOL_MSG_STATS_GET`` get standard statistics
|
||||
===================================== ================================
|
||||
|
||||
Kernel to userspace:
|
||||
|
||||
===================================== =================================
|
||||
``ETHTOOL_MSG_STRSET_GET_REPLY`` string set contents
|
||||
``ETHTOOL_MSG_LINKINFO_GET_REPLY`` link settings
|
||||
``ETHTOOL_MSG_LINKINFO_NTF`` link settings notification
|
||||
``ETHTOOL_MSG_LINKMODES_GET_REPLY`` link modes info
|
||||
``ETHTOOL_MSG_LINKMODES_NTF`` link modes notification
|
||||
``ETHTOOL_MSG_LINKSTATE_GET_REPLY`` link state info
|
||||
``ETHTOOL_MSG_DEBUG_GET_REPLY`` debugging settings
|
||||
``ETHTOOL_MSG_DEBUG_NTF`` debugging settings notification
|
||||
``ETHTOOL_MSG_WOL_GET_REPLY`` wake-on-lan settings
|
||||
``ETHTOOL_MSG_WOL_NTF`` wake-on-lan settings notification
|
||||
``ETHTOOL_MSG_FEATURES_GET_REPLY`` device features
|
||||
``ETHTOOL_MSG_FEATURES_SET_REPLY`` optional reply to FEATURES_SET
|
||||
``ETHTOOL_MSG_FEATURES_NTF`` netdev features notification
|
||||
``ETHTOOL_MSG_PRIVFLAGS_GET_REPLY`` private flags
|
||||
``ETHTOOL_MSG_PRIVFLAGS_NTF`` private flags
|
||||
``ETHTOOL_MSG_RINGS_GET_REPLY`` ring sizes
|
||||
``ETHTOOL_MSG_RINGS_NTF`` ring sizes
|
||||
``ETHTOOL_MSG_CHANNELS_GET_REPLY`` channel counts
|
||||
``ETHTOOL_MSG_CHANNELS_NTF`` channel counts
|
||||
``ETHTOOL_MSG_COALESCE_GET_REPLY`` coalescing parameters
|
||||
``ETHTOOL_MSG_COALESCE_NTF`` coalescing parameters
|
||||
``ETHTOOL_MSG_PAUSE_GET_REPLY`` pause parameters
|
||||
``ETHTOOL_MSG_PAUSE_NTF`` pause parameters
|
||||
``ETHTOOL_MSG_EEE_GET_REPLY`` EEE settings
|
||||
``ETHTOOL_MSG_EEE_NTF`` EEE settings
|
||||
``ETHTOOL_MSG_TSINFO_GET_REPLY`` timestamping info
|
||||
``ETHTOOL_MSG_CABLE_TEST_NTF`` Cable test results
|
||||
``ETHTOOL_MSG_CABLE_TEST_TDR_NTF`` Cable test TDR results
|
||||
``ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY`` tunnel offload info
|
||||
===================================== =================================
|
||||
======================================== =================================
|
||||
``ETHTOOL_MSG_STRSET_GET_REPLY`` string set contents
|
||||
``ETHTOOL_MSG_LINKINFO_GET_REPLY`` link settings
|
||||
``ETHTOOL_MSG_LINKINFO_NTF`` link settings notification
|
||||
``ETHTOOL_MSG_LINKMODES_GET_REPLY`` link modes info
|
||||
``ETHTOOL_MSG_LINKMODES_NTF`` link modes notification
|
||||
``ETHTOOL_MSG_LINKSTATE_GET_REPLY`` link state info
|
||||
``ETHTOOL_MSG_DEBUG_GET_REPLY`` debugging settings
|
||||
``ETHTOOL_MSG_DEBUG_NTF`` debugging settings notification
|
||||
``ETHTOOL_MSG_WOL_GET_REPLY`` wake-on-lan settings
|
||||
``ETHTOOL_MSG_WOL_NTF`` wake-on-lan settings notification
|
||||
``ETHTOOL_MSG_FEATURES_GET_REPLY`` device features
|
||||
``ETHTOOL_MSG_FEATURES_SET_REPLY`` optional reply to FEATURES_SET
|
||||
``ETHTOOL_MSG_FEATURES_NTF`` netdev features notification
|
||||
``ETHTOOL_MSG_PRIVFLAGS_GET_REPLY`` private flags
|
||||
``ETHTOOL_MSG_PRIVFLAGS_NTF`` private flags
|
||||
``ETHTOOL_MSG_RINGS_GET_REPLY`` ring sizes
|
||||
``ETHTOOL_MSG_RINGS_NTF`` ring sizes
|
||||
``ETHTOOL_MSG_CHANNELS_GET_REPLY`` channel counts
|
||||
``ETHTOOL_MSG_CHANNELS_NTF`` channel counts
|
||||
``ETHTOOL_MSG_COALESCE_GET_REPLY`` coalescing parameters
|
||||
``ETHTOOL_MSG_COALESCE_NTF`` coalescing parameters
|
||||
``ETHTOOL_MSG_PAUSE_GET_REPLY`` pause parameters
|
||||
``ETHTOOL_MSG_PAUSE_NTF`` pause parameters
|
||||
``ETHTOOL_MSG_EEE_GET_REPLY`` EEE settings
|
||||
``ETHTOOL_MSG_EEE_NTF`` EEE settings
|
||||
``ETHTOOL_MSG_TSINFO_GET_REPLY`` timestamping info
|
||||
``ETHTOOL_MSG_CABLE_TEST_NTF`` Cable test results
|
||||
``ETHTOOL_MSG_CABLE_TEST_TDR_NTF`` Cable test TDR results
|
||||
``ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY`` tunnel offload info
|
||||
``ETHTOOL_MSG_FEC_GET_REPLY`` FEC settings
|
||||
``ETHTOOL_MSG_FEC_NTF`` FEC settings
|
||||
``ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY`` read SFP module EEPROM
|
||||
``ETHTOOL_MSG_STATS_GET_REPLY`` standard statistics
|
||||
======================================== =================================
|
||||
|
||||
``GET`` requests are sent by userspace applications to retrieve device
|
||||
information. They usually do not contain any message specific attributes.
|
||||
@ -1280,6 +1288,193 @@ Kernel response contents:
|
||||
For UDP tunnel table empty ``ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES`` indicates that
|
||||
the table contains static entries, hard-coded by the NIC.
|
||||
|
||||
FEC_GET
|
||||
=======
|
||||
|
||||
Gets FEC configuration and state like ``ETHTOOL_GFECPARAM`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_FEC_HEADER`` nested request header
|
||||
===================================== ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_FEC_HEADER`` nested request header
|
||||
``ETHTOOL_A_FEC_MODES`` bitset configured modes
|
||||
``ETHTOOL_A_FEC_AUTO`` bool FEC mode auto selection
|
||||
``ETHTOOL_A_FEC_ACTIVE`` u32 index of active FEC mode
|
||||
``ETHTOOL_A_FEC_STATS`` nested FEC statistics
|
||||
===================================== ====== ==========================
|
||||
|
||||
``ETHTOOL_A_FEC_ACTIVE`` is the bit index of the FEC link mode currently
|
||||
active on the interface. This attribute may not be present if device does
|
||||
not support FEC.
|
||||
|
||||
``ETHTOOL_A_FEC_MODES`` and ``ETHTOOL_A_FEC_AUTO`` are only meaningful when
|
||||
autonegotiation is disabled. If ``ETHTOOL_A_FEC_AUTO`` is non-zero driver will
|
||||
select the FEC mode automatically based on the parameters of the SFP module.
|
||||
This is equivalent to the ``ETHTOOL_FEC_AUTO`` bit of the ioctl interface.
|
||||
``ETHTOOL_A_FEC_MODES`` carry the current FEC configuration using link mode
|
||||
bits (rather than old ``ETHTOOL_FEC_*`` bits).
|
||||
|
||||
``ETHTOOL_A_FEC_STATS`` are reported if ``ETHTOOL_FLAG_STATS`` was set in
|
||||
``ETHTOOL_A_HEADER_FLAGS``.
|
||||
Each attribute carries an array of 64bit statistics. First entry in the array
|
||||
contains the total number of events on the port, while the following entries
|
||||
are counters corresponding to lanes/PCS instances. The number of entries in
|
||||
the array will be:
|
||||
|
||||
+--------------+---------------------------------------------+
|
||||
| `0` | device does not support FEC statistics |
|
||||
+--------------+---------------------------------------------+
|
||||
| `1` | device does not support per-lane break down |
|
||||
+--------------+---------------------------------------------+
|
||||
| `1 + #lanes` | device has full support for FEC stats |
|
||||
+--------------+---------------------------------------------+
|
||||
|
||||
Drivers fill in the statistics in the following structure:
|
||||
|
||||
.. kernel-doc:: include/linux/ethtool.h
|
||||
:identifiers: ethtool_fec_stats
|
||||
|
||||
FEC_SET
|
||||
=======
|
||||
|
||||
Sets FEC parameters like ``ETHTOOL_SFECPARAM`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_FEC_HEADER`` nested request header
|
||||
``ETHTOOL_A_FEC_MODES`` bitset configured modes
|
||||
``ETHTOOL_A_FEC_AUTO`` bool FEC mode auto selection
|
||||
===================================== ====== ==========================
|
||||
|
||||
``FEC_SET`` is only meaningful when autonegotiation is disabled. Otherwise
|
||||
FEC mode is selected as part of autonegotiation.
|
||||
|
||||
``ETHTOOL_A_FEC_MODES`` selects which FEC mode should be used. It's recommended
|
||||
to set only one bit, if multiple bits are set driver may choose between them
|
||||
in an implementation specific way.
|
||||
|
||||
``ETHTOOL_A_FEC_AUTO`` requests the driver to choose FEC mode based on SFP
|
||||
module parameters. This does not mean autonegotiation.
|
||||
|
||||
MODULE_EEPROM
|
||||
=============
|
||||
|
||||
Fetch module EEPROM data dump.
|
||||
This interface is designed to allow dumps of at most 1/2 page at once. This
|
||||
means only dumps of 128 (or less) bytes are allowed, without crossing half page
|
||||
boundary located at offset 128. For pages other than 0 only high 128 bytes are
|
||||
accessible.
|
||||
|
||||
Request contents:
|
||||
|
||||
======================================= ====== ==========================
|
||||
``ETHTOOL_A_MODULE_EEPROM_HEADER`` nested request header
|
||||
``ETHTOOL_A_MODULE_EEPROM_OFFSET`` u32 offset within a page
|
||||
``ETHTOOL_A_MODULE_EEPROM_LENGTH`` u32 amount of bytes to read
|
||||
``ETHTOOL_A_MODULE_EEPROM_PAGE`` u8 page number
|
||||
``ETHTOOL_A_MODULE_EEPROM_BANK`` u8 bank number
|
||||
``ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS`` u8 page I2C address
|
||||
======================================= ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
+---------------------------------------------+--------+---------------------+
|
||||
| ``ETHTOOL_A_MODULE_EEPROM_HEADER`` | nested | reply header |
|
||||
+---------------------------------------------+--------+---------------------+
|
||||
| ``ETHTOOL_A_MODULE_EEPROM_DATA`` | nested | array of bytes from |
|
||||
| | | module EEPROM |
|
||||
+---------------------------------------------+--------+---------------------+
|
||||
|
||||
``ETHTOOL_A_MODULE_EEPROM_DATA`` has an attribute length equal to the amount of
|
||||
bytes driver actually read.
|
||||
|
||||
STATS_GET
|
||||
=========
|
||||
|
||||
Get standard statistics for the interface. Note that this is not
|
||||
a re-implementation of ``ETHTOOL_GSTATS`` which exposed driver-defined
|
||||
stats.
|
||||
|
||||
Request contents:
|
||||
|
||||
======================================= ====== ==========================
|
||||
``ETHTOOL_A_STATS_HEADER`` nested request header
|
||||
``ETHTOOL_A_STATS_GROUPS`` bitset requested groups of stats
|
||||
======================================= ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
+-----------------------------------+--------+--------------------------------+
|
||||
| ``ETHTOOL_A_STATS_HEADER`` | nested | reply header |
|
||||
+-----------------------------------+--------+--------------------------------+
|
||||
| ``ETHTOOL_A_STATS_GRP`` | nested | one or more group of stats |
|
||||
+-+---------------------------------+--------+--------------------------------+
|
||||
| | ``ETHTOOL_A_STATS_GRP_ID`` | u32 | group ID - ``ETHTOOL_STATS_*`` |
|
||||
+-+---------------------------------+--------+--------------------------------+
|
||||
| | ``ETHTOOL_A_STATS_GRP_SS_ID`` | u32 | string set ID for names |
|
||||
+-+---------------------------------+--------+--------------------------------+
|
||||
| | ``ETHTOOL_A_STATS_GRP_STAT`` | nested | nest containing a statistic |
|
||||
+-+---------------------------------+--------+--------------------------------+
|
||||
| | ``ETHTOOL_A_STATS_GRP_HIST_RX`` | nested | histogram statistic (Rx) |
|
||||
+-+---------------------------------+--------+--------------------------------+
|
||||
| | ``ETHTOOL_A_STATS_GRP_HIST_TX`` | nested | histogram statistic (Tx) |
|
||||
+-+---------------------------------+--------+--------------------------------+
|
||||
|
||||
Users specify which groups of statistics they are requesting via
|
||||
the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:
|
||||
|
||||
====================== ======== ===============================================
|
||||
ETHTOOL_STATS_ETH_MAC eth-mac Basic IEEE 802.3 MAC statistics (30.3.1.1.*)
|
||||
ETHTOOL_STATS_ETH_PHY eth-phy Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
|
||||
ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
|
||||
ETHTOOL_STATS_RMON rmon RMON (RFC 2819) statistics
|
||||
====================== ======== ===============================================
|
||||
|
||||
Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
|
||||
``ETHTOOL_A_STATS_GRP_ID`` identifies which group's statistics nest contains.
|
||||
``ETHTOOL_A_STATS_GRP_SS_ID`` identifies the string set ID for the names of
|
||||
the statistics in the group, if available.
|
||||
|
||||
Statistics are added to the ``ETHTOOL_A_STATS_GRP`` nest under
|
||||
``ETHTOOL_A_STATS_GRP_STAT``. ``ETHTOOL_A_STATS_GRP_STAT`` should contain
|
||||
single 8 byte (u64) attribute inside - the type of that attribute is
|
||||
the statistic ID and the value is the value of the statistic.
|
||||
Each group has its own interpretation of statistic IDs.
|
||||
Attribute IDs correspond to strings from the string set identified
|
||||
by ``ETHTOOL_A_STATS_GRP_SS_ID``. Complex statistics (such as RMON histogram
|
||||
entries) are also listed inside ``ETHTOOL_A_STATS_GRP`` and do not have
|
||||
a string defined in the string set.
|
||||
|
||||
RMON "histogram" counters count number of packets within given size range.
|
||||
Because RFC does not specify the ranges beyond the standard 1518 MTU devices
|
||||
differ in definition of buckets. For this reason the definition of packet ranges
|
||||
is left to each driver.
|
||||
|
||||
``ETHTOOL_A_STATS_GRP_HIST_RX`` and ``ETHTOOL_A_STATS_GRP_HIST_TX`` nests
|
||||
contain the following attributes:
|
||||
|
||||
================================= ====== ===================================
|
||||
ETHTOOL_A_STATS_RMON_HIST_BKT_LOW u32 low bound of the packet size bucket
|
||||
ETHTOOL_A_STATS_RMON_HIST_BKT_HI u32 high bound of the bucket
|
||||
ETHTOOL_A_STATS_RMON_HIST_VAL u64 packet counter
|
||||
================================= ====== ===================================
|
||||
|
||||
Low and high bounds are inclusive, for example:
|
||||
|
||||
============================= ==== ====
|
||||
RFC statistic low high
|
||||
============================= ==== ====
|
||||
etherStatsPkts64Octets 0 64
|
||||
etherStatsPkts512to1023Octets 512 1023
|
||||
============================= ==== ====
|
||||
|
||||
Request translation
|
||||
===================
|
||||
|
||||
@ -1357,8 +1552,8 @@ are netlink only.
|
||||
``ETHTOOL_GET_DUMP_FLAG`` n/a
|
||||
``ETHTOOL_GET_DUMP_DATA`` n/a
|
||||
``ETHTOOL_GET_TS_INFO`` ``ETHTOOL_MSG_TSINFO_GET``
|
||||
``ETHTOOL_GMODULEINFO`` n/a
|
||||
``ETHTOOL_GMODULEEEPROM`` n/a
|
||||
``ETHTOOL_GMODULEINFO`` ``ETHTOOL_MSG_MODULE_EEPROM_GET``
|
||||
``ETHTOOL_GMODULEEEPROM`` ``ETHTOOL_MSG_MODULE_EEPROM_GET``
|
||||
``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET``
|
||||
``ETHTOOL_SEEE`` ``ETHTOOL_MSG_EEE_SET``
|
||||
``ETHTOOL_GRSSH`` n/a
|
||||
@ -1373,9 +1568,9 @@ are netlink only.
|
||||
``ETHTOOL_MSG_LINKMODES_SET``
|
||||
``ETHTOOL_PHY_GTUNABLE`` n/a
|
||||
``ETHTOOL_PHY_STUNABLE`` n/a
|
||||
``ETHTOOL_GFECPARAM`` n/a
|
||||
``ETHTOOL_SFECPARAM`` n/a
|
||||
n/a ''ETHTOOL_MSG_CABLE_TEST_ACT''
|
||||
n/a ''ETHTOOL_MSG_CABLE_TEST_TDR_ACT''
|
||||
``ETHTOOL_GFECPARAM`` ``ETHTOOL_MSG_FEC_GET``
|
||||
``ETHTOOL_SFECPARAM`` ``ETHTOOL_MSG_FEC_SET``
|
||||
n/a ``ETHTOOL_MSG_CABLE_TEST_ACT``
|
||||
n/a ``ETHTOOL_MSG_CABLE_TEST_TDR_ACT``
|
||||
n/a ``ETHTOOL_MSG_TUNNEL_INFO_GET``
|
||||
=================================== =====================================
|
||||
|
@ -327,7 +327,7 @@ Examples for low-level BPF:
|
||||
ret #-1
|
||||
drop: ret #0
|
||||
|
||||
**icmp random packet sampling, 1 in 4**:
|
||||
**icmp random packet sampling, 1 in 4**::
|
||||
|
||||
ldh [12]
|
||||
jne #0x800, drop
|
||||
|
@ -76,6 +76,7 @@ Contents:
|
||||
netdevices
|
||||
netfilter-sysctl
|
||||
netif-msg
|
||||
nexthop-group-resilient
|
||||
nf_conntrack-sysctl
|
||||
nf_flowtable
|
||||
openvswitch
|
||||
|
@ -1073,7 +1073,9 @@ ip_local_reserved_ports - list of comma separated ranges
|
||||
|
||||
although this is redundant. However such a setting is useful
|
||||
if later the port range is changed to a value that will
|
||||
include the reserved ports.
|
||||
include the reserved ports. Also keep in mind, that overlapping
|
||||
of these ranges may affect probability of selecting ephemeral
|
||||
ports which are right after block of reserved ports.
|
||||
|
||||
Default: Empty
|
||||
|
||||
@ -1143,6 +1145,12 @@ icmp_echo_ignore_all - BOOLEAN
|
||||
|
||||
Default: 0
|
||||
|
||||
icmp_echo_enable_probe - BOOLEAN
|
||||
If set to one, then the kernel will respond to RFC 8335 PROBE
|
||||
requests sent to it.
|
||||
|
||||
Default: 0
|
||||
|
||||
icmp_echo_ignore_broadcasts - BOOLEAN
|
||||
If set non-zero, then the kernel will ignore all ICMP ECHO and
|
||||
TIMESTAMP requests sent to it via broadcast/multicast.
|
||||
|
293
Documentation/networking/nexthop-group-resilient.rst
Normal file
293
Documentation/networking/nexthop-group-resilient.rst
Normal file
@ -0,0 +1,293 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================
|
||||
Resilient Next-hop Groups
|
||||
=========================
|
||||
|
||||
Resilient groups are a type of next-hop group that is aimed at minimizing
|
||||
disruption in flow routing across changes to the group composition and
|
||||
weights of constituent next hops.
|
||||
|
||||
The idea behind resilient hashing groups is best explained in contrast to
|
||||
the legacy multipath next-hop group, which uses the hash-threshold
|
||||
algorithm, described in RFC 2992.
|
||||
|
||||
To select a next hop, hash-threshold algorithm first assigns a range of
|
||||
hashes to each next hop in the group, and then selects the next hop by
|
||||
comparing the SKB hash with the individual ranges. When a next hop is
|
||||
removed from the group, the ranges are recomputed, which leads to
|
||||
reassignment of parts of hash space from one next hop to another. RFC 2992
|
||||
illustrates it thus::
|
||||
|
||||
+-------+-------+-------+-------+-------+
|
||||
| 1 | 2 | 3 | 4 | 5 |
|
||||
+-------+-+-----+---+---+-----+-+-------+
|
||||
| 1 | 2 | 4 | 5 |
|
||||
+---------+---------+---------+---------+
|
||||
|
||||
Before and after deletion of next hop 3
|
||||
under the hash-threshold algorithm.
|
||||
|
||||
Note how next hop 2 gave up part of the hash space in favor of next hop 1,
|
||||
and 4 in favor of 5. While there will usually be some overlap between the
|
||||
previous and the new distribution, some traffic flows change the next hop
|
||||
that they resolve to.
|
||||
|
||||
If a multipath group is used for load-balancing between multiple servers,
|
||||
this hash space reassignment causes an issue that packets from a single
|
||||
flow suddenly end up arriving at a server that does not expect them. This
|
||||
can result in TCP connections being reset.
|
||||
|
||||
If a multipath group is used for load-balancing among available paths to
|
||||
the same server, the issue is that different latencies and reordering along
|
||||
the way causes the packets to arrive in the wrong order, resulting in
|
||||
degraded application performance.
|
||||
|
||||
To mitigate the above-mentioned flow redirection, resilient next-hop groups
|
||||
insert another layer of indirection between the hash space and its
|
||||
constituent next hops: a hash table. The selection algorithm uses SKB hash
|
||||
to choose a hash table bucket, then reads the next hop that this bucket
|
||||
contains, and forwards traffic there.
|
||||
|
||||
This indirection brings an important feature. In the hash-threshold
|
||||
algorithm, the range of hashes associated with a next hop must be
|
||||
continuous. With a hash table, mapping between the hash table buckets and
|
||||
the individual next hops is arbitrary. Therefore when a next hop is deleted
|
||||
the buckets that held it are simply reassigned to other next hops::
|
||||
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|1|1|1|1|2|2|2|2|3|3|3|3|4|4|4|4|5|5|5|5|
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
v v v v
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|1|1|1|1|2|2|2|2|1|2|4|5|4|4|4|4|5|5|5|5|
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Before and after deletion of next hop 3
|
||||
under the resilient hashing algorithm.
|
||||
|
||||
When weights of next hops in a group are altered, it may be possible to
|
||||
choose a subset of buckets that are currently not used for forwarding
|
||||
traffic, and use those to satisfy the new next-hop distribution demands,
|
||||
keeping the "busy" buckets intact. This way, established flows are ideally
|
||||
kept being forwarded to the same endpoints through the same paths as before
|
||||
the next-hop group change.
|
||||
|
||||
Algorithm
|
||||
---------
|
||||
|
||||
In a nutshell, the algorithm works as follows. Each next hop deserves a
|
||||
certain number of buckets, according to its weight and the number of
|
||||
buckets in the hash table. In accordance with the source code, we will call
|
||||
this number a "wants count" of a next hop. In case of an event that might
|
||||
cause bucket allocation change, the wants counts for individual next hops
|
||||
are updated.
|
||||
|
||||
Next hops that have fewer buckets than their wants count, are called
|
||||
"underweight". Those that have more are "overweight". If there are no
|
||||
overweight (and therefore no underweight) next hops in the group, it is
|
||||
said to be "balanced".
|
||||
|
||||
Each bucket maintains a last-used timer. Every time a packet is forwarded
|
||||
through a bucket, this timer is updated to current jiffies value. One
|
||||
attribute of a resilient group is then the "idle timer", which is the
|
||||
amount of time that a bucket must not be hit by traffic in order for it to
|
||||
be considered "idle". Buckets that are not idle are busy.
|
||||
|
||||
After assigning wants counts to next hops, an "upkeep" algorithm runs. For
|
||||
buckets:
|
||||
|
||||
1) that have no assigned next hop, or
|
||||
2) whose next hop has been removed, or
|
||||
3) that are idle and their next hop is overweight,
|
||||
|
||||
upkeep changes the next hop that the bucket references to one of the
|
||||
underweight next hops. If, after considering all buckets in this manner,
|
||||
there are still underweight next hops, another upkeep run is scheduled to a
|
||||
future time.
|
||||
|
||||
There may not be enough "idle" buckets to satisfy the updated wants counts
|
||||
of all next hops. Another attribute of a resilient group is the "unbalanced
|
||||
timer". This timer can be set to 0, in which case the table will stay out
|
||||
of balance until idle buckets do appear, possibly never. If set to a
|
||||
non-zero value, the value represents the period of time that the table is
|
||||
permitted to stay out of balance.
|
||||
|
||||
With this in mind, we update the above list of conditions with one more
|
||||
item. Thus buckets:
|
||||
|
||||
4) whose next hop is overweight, and the amount of time that the table has
|
||||
been out of balance exceeds the unbalanced timer, if that is non-zero,
|
||||
|
||||
\... are migrated as well.
|
||||
|
||||
Offloading & Driver Feedback
|
||||
----------------------------
|
||||
|
||||
When offloading resilient groups, the algorithm that distributes buckets
|
||||
among next hops is still the one in SW. Drivers are notified of updates to
|
||||
next hop groups in the following three ways:
|
||||
|
||||
- Full group notification with the type
|
||||
``NH_NOTIFIER_INFO_TYPE_RES_TABLE``. This is used just after the group is
|
||||
created and buckets populated for the first time.
|
||||
|
||||
- Single-bucket notifications of the type
|
||||
``NH_NOTIFIER_INFO_TYPE_RES_BUCKET``, which is used for notifications of
|
||||
individual migrations within an already-established group.
|
||||
|
||||
- Pre-replace notification, ``NEXTHOP_EVENT_RES_TABLE_PRE_REPLACE``. This
|
||||
is sent before the group is replaced, and is a way for the driver to veto
|
||||
the group before committing anything to the HW.
|
||||
|
||||
Some single-bucket notifications are forced, as indicated by the "force"
|
||||
flag in the notification. Those are used for the cases where e.g. the next
|
||||
hop associated with the bucket was removed, and the bucket really must be
|
||||
migrated.
|
||||
|
||||
Non-forced notifications can be overridden by the driver by returning an
|
||||
error code. The use case for this is that the driver notifies the HW that a
|
||||
bucket should be migrated, but the HW discovers that the bucket has in fact
|
||||
been hit by traffic.
|
||||
|
||||
A second way for the HW to report that a bucket is busy is through the
|
||||
``nexthop_res_grp_activity_update()`` API. The buckets identified this way
|
||||
as busy are treated as if traffic hit them.
|
||||
|
||||
Offloaded buckets should be flagged as either "offload" or "trap". This is
|
||||
done through the ``nexthop_bucket_set_hw_flags()`` API.
|
||||
|
||||
Netlink UAPI
|
||||
------------
|
||||
|
||||
Resilient Group Replacement
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Resilient groups are configured using the ``RTM_NEWNEXTHOP`` message in the
|
||||
same manner as other multipath groups. The following changes apply to the
|
||||
attributes passed in the netlink message:
|
||||
|
||||
=================== =========================================================
|
||||
``NHA_GROUP_TYPE`` Should be ``NEXTHOP_GRP_TYPE_RES`` for resilient group.
|
||||
``NHA_RES_GROUP`` A nest that contains attributes specific to resilient
|
||||
groups.
|
||||
=================== =========================================================
|
||||
|
||||
``NHA_RES_GROUP`` payload:
|
||||
|
||||
=================================== =========================================
|
||||
``NHA_RES_GROUP_BUCKETS`` Number of buckets in the hash table.
|
||||
``NHA_RES_GROUP_IDLE_TIMER`` Idle timer in units of clock_t.
|
||||
``NHA_RES_GROUP_UNBALANCED_TIMER`` Unbalanced timer in units of clock_t.
|
||||
=================================== =========================================
|
||||
|
||||
Next Hop Get
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Requests to get resilient next-hop groups use the ``RTM_GETNEXTHOP``
|
||||
message in exactly the same way as other next hop get requests. The
|
||||
response attributes match the replacement attributes cited above, except
|
||||
``NHA_RES_GROUP`` payload will include the following attribute:
|
||||
|
||||
=================================== =========================================
|
||||
``NHA_RES_GROUP_UNBALANCED_TIME`` How long has the resilient group been out
|
||||
of balance, in units of clock_t.
|
||||
=================================== =========================================
|
||||
|
||||
Bucket Get
|
||||
^^^^^^^^^^
|
||||
|
||||
The message ``RTM_GETNEXTHOPBUCKET`` without the ``NLM_F_DUMP`` flag is
|
||||
used to request a single bucket. The attributes recognized at get requests
|
||||
are:
|
||||
|
||||
=================== =========================================================
|
||||
``NHA_ID`` ID of the next-hop group that the bucket belongs to.
|
||||
``NHA_RES_BUCKET`` A nest that contains attributes specific to bucket.
|
||||
=================== =========================================================
|
||||
|
||||
``NHA_RES_BUCKET`` payload:
|
||||
|
||||
======================== ====================================================
|
||||
``NHA_RES_BUCKET_INDEX`` Index of bucket in the resilient table.
|
||||
======================== ====================================================
|
||||
|
||||
Bucket Dumps
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The message ``RTM_GETNEXTHOPBUCKET`` with the ``NLM_F_DUMP`` flag is used
|
||||
to request a dump of matching buckets. The attributes recognized at dump
|
||||
requests are:
|
||||
|
||||
=================== =========================================================
|
||||
``NHA_ID`` If specified, limits the dump to just the next-hop group
|
||||
with this ID.
|
||||
``NHA_OIF`` If specified, limits the dump to buckets that contain
|
||||
next hops that use the device with this ifindex.
|
||||
``NHA_MASTER`` If specified, limits the dump to buckets that contain
|
||||
next hops that use a device in the VRF with this ifindex.
|
||||
``NHA_RES_BUCKET`` A nest that contains attributes specific to bucket.
|
||||
=================== =========================================================
|
||||
|
||||
``NHA_RES_BUCKET`` payload:
|
||||
|
||||
======================== ====================================================
|
||||
``NHA_RES_BUCKET_NH_ID`` If specified, limits the dump to just the buckets
|
||||
that contain the next hop with this ID.
|
||||
======================== ====================================================
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To illustrate the usage, consider the following commands::
|
||||
|
||||
# ip nexthop add id 1 via 192.0.2.2 dev eth0
|
||||
# ip nexthop add id 2 via 192.0.2.3 dev eth0
|
||||
# ip nexthop add id 10 group 1/2 type resilient \
|
||||
buckets 8 idle_timer 60 unbalanced_timer 300
|
||||
|
||||
The last command creates a resilient next-hop group. It will have 8 buckets
|
||||
(which is unusually low number, and used here for demonstration purposes
|
||||
only), each bucket will be considered idle when no traffic hits it for at
|
||||
least 60 seconds, and if the table remains out of balance for 300 seconds,
|
||||
it will be forcefully brought into balance.
|
||||
|
||||
Changing next-hop weights leads to change in bucket allocation::
|
||||
|
||||
# ip nexthop replace id 10 group 1,3/2 type resilient
|
||||
|
||||
This can be confirmed by looking at individual buckets::
|
||||
|
||||
# ip nexthop bucket show id 10
|
||||
id 10 index 0 idle_time 5.59 nhid 1
|
||||
id 10 index 1 idle_time 5.59 nhid 1
|
||||
id 10 index 2 idle_time 8.74 nhid 2
|
||||
id 10 index 3 idle_time 8.74 nhid 2
|
||||
id 10 index 4 idle_time 8.74 nhid 1
|
||||
id 10 index 5 idle_time 8.74 nhid 1
|
||||
id 10 index 6 idle_time 8.74 nhid 1
|
||||
id 10 index 7 idle_time 8.74 nhid 1
|
||||
|
||||
Note the two buckets that have a shorter idle time. Those are the ones that
|
||||
were migrated after the next-hop replace command to satisfy the new demand
|
||||
that next hop 1 be given 6 buckets instead of 4.
|
||||
|
||||
Netdevsim
|
||||
---------
|
||||
|
||||
The netdevsim driver implements a mock offload of resilient groups, and
|
||||
exposes debugfs interface that allows marking individual buckets as busy.
|
||||
For example, the following will mark bucket 23 in next-hop group 10 as
|
||||
active::
|
||||
|
||||
# echo 10 23 > /sys/kernel/debug/netdevsim/netdevsim10/fib/nexthop_bucket_activity
|
||||
|
||||
In addition, another debugfs interface can be used to configure that the
|
||||
next attempt to migrate a bucket should fail::
|
||||
|
||||
# echo 1 > /sys/kernel/debug/netdevsim/netdevsim10/fib/fail_nexthop_bucket_replace
|
||||
|
||||
Besides serving as an example, the interfaces that netdevsim exposes are
|
||||
useful in automated testing, and
|
||||
``tools/testing/selftests/drivers/net/netdevsim/nexthop.sh`` makes use of
|
||||
them to test the algorithm.
|
@ -4,35 +4,38 @@
|
||||
Netfilter's flowtable infrastructure
|
||||
====================================
|
||||
|
||||
This documentation describes the software flowtable infrastructure available in
|
||||
Netfilter since Linux kernel 4.16.
|
||||
This documentation describes the Netfilter flowtable infrastructure which allows
|
||||
you to define a fastpath through the flowtable datapath. This infrastructure
|
||||
also provides hardware offload support. The flowtable supports for the layer 3
|
||||
IPv4 and IPv6 and the layer 4 TCP and UDP protocols.
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Initial packets follow the classic forwarding path, once the flow enters the
|
||||
established state according to the conntrack semantics (ie. we have seen traffic
|
||||
in both directions), then you can decide to offload the flow to the flowtable
|
||||
from the forward chain via the 'flow offload' action available in nftables.
|
||||
Once the first packet of the flow successfully goes through the IP forwarding
|
||||
path, from the second packet on, you might decide to offload the flow to the
|
||||
flowtable through your ruleset. The flowtable infrastructure provides a rule
|
||||
action that allows you to specify when to add a flow to the flowtable.
|
||||
|
||||
Packets that find an entry in the flowtable (ie. flowtable hit) are sent to the
|
||||
output netdevice via neigh_xmit(), hence, they bypass the classic forwarding
|
||||
path (the visible effect is that you do not see these packets from any of the
|
||||
netfilter hooks coming after the ingress). In case of flowtable miss, the packet
|
||||
follows the classic forward path.
|
||||
A packet that finds a matching entry in the flowtable (ie. flowtable hit) is
|
||||
transmitted to the output netdevice via neigh_xmit(), hence, packets bypass the
|
||||
classic IP forwarding path (the visible effect is that you do not see these
|
||||
packets from any of the Netfilter hooks coming after ingress). In case that
|
||||
there is no matching entry in the flowtable (ie. flowtable miss), the packet
|
||||
follows the classic IP forwarding path.
|
||||
|
||||
The flowtable uses a resizable hashtable, lookups are based on the following
|
||||
7-tuple selectors: source, destination, layer 3 and layer 4 protocols, source
|
||||
and destination ports and the input interface (useful in case there are several
|
||||
conntrack zones in place).
|
||||
The flowtable uses a resizable hashtable. Lookups are based on the following
|
||||
n-tuple selectors: layer 2 protocol encapsulation (VLAN and PPPoE), layer 3
|
||||
source and destination, layer 4 source and destination ports and the input
|
||||
interface (useful in case there are several conntrack zones in place).
|
||||
|
||||
Flowtables are populated via the 'flow offload' nftables action, so the user can
|
||||
selectively specify what flows are placed into the flow table. Hence, packets
|
||||
follow the classic forwarding path unless the user explicitly instruct packets
|
||||
to use this new alternative forwarding path via nftables policy.
|
||||
The 'flow add' action allows you to populate the flowtable, the user selectively
|
||||
specifies what flows are placed into the flowtable. Hence, packets follow the
|
||||
classic IP forwarding path unless the user explicitly instruct flows to use this
|
||||
new alternative forwarding path via policy.
|
||||
|
||||
This is represented in Fig.1, which describes the classic forwarding path
|
||||
including the Netfilter hooks and the flowtable fastpath bypass.
|
||||
The flowtable datapath is represented in Fig.1, which describes the classic IP
|
||||
forwarding path including the Netfilter hooks and the flowtable fastpath bypass.
|
||||
|
||||
::
|
||||
|
||||
@ -67,11 +70,13 @@ including the Netfilter hooks and the flowtable fastpath bypass.
|
||||
Fig.1 Netfilter hooks and flowtable interactions
|
||||
|
||||
The flowtable entry also stores the NAT configuration, so all packets are
|
||||
mangled according to the NAT policy that matches the initial packets that went
|
||||
through the classic forwarding path. The TTL is decremented before calling
|
||||
neigh_xmit(). Fragmented traffic is passed up to follow the classic forwarding
|
||||
path given that the transport selectors are missing, therefore flowtable lookup
|
||||
is not possible.
|
||||
mangled according to the NAT policy that is specified from the classic IP
|
||||
forwarding path. The TTL is decremented before calling neigh_xmit(). Fragmented
|
||||
traffic is passed up to follow the classic IP forwarding path given that the
|
||||
transport header is missing, in this case, flowtable lookups are not possible.
|
||||
TCP RST and FIN packets are also passed up to the classic IP forwarding path to
|
||||
release the flow gracefully. Packets that exceed the MTU are also passed up to
|
||||
the classic forwarding path to report packet-too-big ICMP errors to the sender.
|
||||
|
||||
Example configuration
|
||||
---------------------
|
||||
@ -85,7 +90,7 @@ flowtable and add one rule to your forward chain::
|
||||
}
|
||||
chain y {
|
||||
type filter hook forward priority 0; policy accept;
|
||||
ip protocol tcp flow offload @f
|
||||
ip protocol tcp flow add @f
|
||||
counter packets 0 bytes 0
|
||||
}
|
||||
}
|
||||
@ -103,6 +108,119 @@ flow is offloaded, you will observe that the counter rule in the example above
|
||||
does not get updated for the packets that are being forwarded through the
|
||||
forwarding bypass.
|
||||
|
||||
You can identify offloaded flows through the [OFFLOAD] tag when listing your
|
||||
connection tracking table.
|
||||
|
||||
::
|
||||
|
||||
# conntrack -L
|
||||
tcp 6 src=10.141.10.2 dst=192.168.10.2 sport=52728 dport=5201 src=192.168.10.2 dst=192.168.10.1 sport=5201 dport=52728 [OFFLOAD] mark=0 use=2
|
||||
|
||||
|
||||
Layer 2 encapsulation
|
||||
---------------------
|
||||
|
||||
Since Linux kernel 5.13, the flowtable infrastructure discovers the real
|
||||
netdevice behind VLAN and PPPoE netdevices. The flowtable software datapath
|
||||
parses the VLAN and PPPoE layer 2 headers to extract the ethertype and the
|
||||
VLAN ID / PPPoE session ID which are used for the flowtable lookups. The
|
||||
flowtable datapath also deals with layer 2 decapsulation.
|
||||
|
||||
You do not need to add the PPPoE and the VLAN devices to your flowtable,
|
||||
instead the real device is sufficient for the flowtable to track your flows.
|
||||
|
||||
Bridge and IP forwarding
|
||||
------------------------
|
||||
|
||||
Since Linux kernel 5.13, you can add bridge ports to the flowtable. The
|
||||
flowtable infrastructure discovers the topology behind the bridge device. This
|
||||
allows the flowtable to define a fastpath bypass between the bridge ports
|
||||
(represented as eth1 and eth2 in the example figure below) and the gateway
|
||||
device (represented as eth0) in your switch/router.
|
||||
|
||||
::
|
||||
|
||||
fastpath bypass
|
||||
.-------------------------.
|
||||
/ \
|
||||
| IP forwarding |
|
||||
| / \ \/
|
||||
| br0 eth0 ..... eth0
|
||||
. / \ *host B*
|
||||
-> eth1 eth2
|
||||
. *switch/router*
|
||||
.
|
||||
.
|
||||
eth0
|
||||
*host A*
|
||||
|
||||
The flowtable infrastructure also supports for bridge VLAN filtering actions
|
||||
such as PVID and untagged. You can also stack a classic VLAN device on top of
|
||||
your bridge port.
|
||||
|
||||
If you would like that your flowtable defines a fastpath between your bridge
|
||||
ports and your IP forwarding path, you have to add your bridge ports (as
|
||||
represented by the real netdevice) to your flowtable definition.
|
||||
|
||||
Counters
|
||||
--------
|
||||
|
||||
The flowtable can synchronize packet and byte counters with the existing
|
||||
connection tracking entry by specifying the counter statement in your flowtable
|
||||
definition, e.g.
|
||||
|
||||
::
|
||||
|
||||
table inet x {
|
||||
flowtable f {
|
||||
hook ingress priority 0; devices = { eth0, eth1 };
|
||||
counter
|
||||
}
|
||||
}
|
||||
|
||||
Counter support is available since Linux kernel 5.7.
|
||||
|
||||
Hardware offload
|
||||
----------------
|
||||
|
||||
If your network device provides hardware offload support, you can turn it on by
|
||||
means of the 'offload' flag in your flowtable definition, e.g.
|
||||
|
||||
::
|
||||
|
||||
table inet x {
|
||||
flowtable f {
|
||||
hook ingress priority 0; devices = { eth0, eth1 };
|
||||
flags offload;
|
||||
}
|
||||
}
|
||||
|
||||
There is a workqueue that adds the flows to the hardware. Note that a few
|
||||
packets might still run over the flowtable software path until the workqueue has
|
||||
a chance to offload the flow to the network device.
|
||||
|
||||
You can identify hardware offloaded flows through the [HW_OFFLOAD] tag when
|
||||
listing your connection tracking table. Please, note that the [OFFLOAD] tag
|
||||
refers to the software offload mode, so there is a distinction between [OFFLOAD]
|
||||
which refers to the software flowtable fastpath and [HW_OFFLOAD] which refers
|
||||
to the hardware offload datapath being used by the flow.
|
||||
|
||||
The flowtable hardware offload infrastructure also supports for the DSA
|
||||
(Distributed Switch Architecture).
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
The flowtable behaves like a cache. The flowtable entries might get stale if
|
||||
either the destination MAC address or the egress netdevice that is used for
|
||||
transmission changes.
|
||||
|
||||
This might be a problem if:
|
||||
|
||||
- You run the flowtable in software mode and you combine bridge and IP
|
||||
forwarding in your setup.
|
||||
- Hardware offload is enabled.
|
||||
|
||||
More reading
|
||||
------------
|
||||
|
||||
|
@ -80,8 +80,8 @@ values of phy_interface_t must be understood from the perspective of the PHY
|
||||
device itself, leading to the following:
|
||||
|
||||
* PHY_INTERFACE_MODE_RGMII: the PHY is not responsible for inserting any
|
||||
internal delay by itself, it assumes that either the Ethernet MAC (if capable
|
||||
or the PCB traces) insert the correct 1.5-2ns delay
|
||||
internal delay by itself, it assumes that either the Ethernet MAC (if capable)
|
||||
or the PCB traces insert the correct 1.5-2ns delay
|
||||
|
||||
* PHY_INTERFACE_MODE_RGMII_TXID: the PHY should insert an internal delay
|
||||
for the transmit data lines (TXD[3:0]) processed by the PHY device
|
||||
|
@ -44,8 +44,27 @@ If `-s` is specified once the detailed errors won't be shown.
|
||||
Protocol-specific statistics
|
||||
----------------------------
|
||||
|
||||
Some of the interfaces used for configuring devices are also able
|
||||
to report related statistics. For example ethtool interface used
|
||||
Protocol-specific statistics are exposed via relevant interfaces,
|
||||
the same interfaces as are used to configure them.
|
||||
|
||||
ethtool
|
||||
~~~~~~~
|
||||
|
||||
Ethtool exposes common low-level statistics.
|
||||
All the standard statistics are expected to be maintained
|
||||
by the device, not the driver (as opposed to driver-defined stats
|
||||
described in the next section which mix software and hardware stats).
|
||||
For devices which contain unmanaged
|
||||
switches (e.g. legacy SR-IOV or multi-host NICs) the events counted
|
||||
may not pertain exclusively to the packets destined to
|
||||
the local host interface. In other words the events may
|
||||
be counted at the network port (MAC/PHY blocks) without separation
|
||||
for different host side (PCIe) devices. Such ambiguity must not
|
||||
be present when internal switch is managed by Linux (so called
|
||||
switchdev mode for NICs).
|
||||
|
||||
Standard ethtool statistics can be accessed via the interfaces used
|
||||
for configuration. For example ethtool interface used
|
||||
to configure pause frames can report corresponding hardware counters::
|
||||
|
||||
$ ethtool --include-statistics -a eth0
|
||||
@ -57,6 +76,27 @@ to configure pause frames can report corresponding hardware counters::
|
||||
tx_pause_frames: 1
|
||||
rx_pause_frames: 1
|
||||
|
||||
General Ethernet statistics not associated with any particular
|
||||
functionality are exposed via ``ethtool -S $ifc`` by specifying
|
||||
the ``--groups`` parameter::
|
||||
|
||||
$ ethtool -S eth0 --groups eth-phy eth-mac eth-ctrl rmon
|
||||
Stats for eth0:
|
||||
eth-phy-SymbolErrorDuringCarrier: 0
|
||||
eth-mac-FramesTransmittedOK: 1
|
||||
eth-mac-FrameTooLongErrors: 1
|
||||
eth-ctrl-MACControlFramesTransmitted: 1
|
||||
eth-ctrl-MACControlFramesReceived: 0
|
||||
eth-ctrl-UnsupportedOpcodesReceived: 1
|
||||
rmon-etherStatsUndersizePkts: 1
|
||||
rmon-etherStatsJabbers: 0
|
||||
rmon-rx-etherStatsPkts64Octets: 1
|
||||
rmon-rx-etherStatsPkts65to127Octets: 0
|
||||
rmon-rx-etherStatsPkts128to255Octets: 0
|
||||
rmon-tx-etherStatsPkts64Octets: 2
|
||||
rmon-tx-etherStatsPkts65to127Octets: 3
|
||||
rmon-tx-etherStatsPkts128to255Octets: 0
|
||||
|
||||
Driver-defined statistics
|
||||
-------------------------
|
||||
|
||||
@ -130,6 +170,7 @@ the `ETHTOOL_FLAG_STATS` flag in `ETHTOOL_A_HEADER_FLAGS`. Currently
|
||||
statistics are supported in the following commands:
|
||||
|
||||
- `ETHTOOL_MSG_PAUSE_GET`
|
||||
- `ETHTOOL_MSG_FEC_GET`
|
||||
|
||||
debugfs
|
||||
-------
|
||||
@ -176,3 +217,4 @@ translated to netlink attributes when dumped. Drivers must not overwrite
|
||||
the statistics they don't report with 0.
|
||||
|
||||
- ethtool_pause_stats()
|
||||
- ethtool_fec_stats()
|
||||
|
@ -181,18 +181,41 @@ To offloading L2 bridging, the switchdev driver/device should support:
|
||||
Static FDB Entries
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The switchdev driver should implement ndo_fdb_add, ndo_fdb_del and ndo_fdb_dump
|
||||
to support static FDB entries installed to the device. Static bridge FDB
|
||||
entries are installed, for example, using iproute2 bridge cmd::
|
||||
A driver which implements the ``ndo_fdb_add``, ``ndo_fdb_del`` and
|
||||
``ndo_fdb_dump`` operations is able to support the command below, which adds a
|
||||
static bridge FDB entry::
|
||||
|
||||
bridge fdb add ADDR dev DEV [vlan VID] [self]
|
||||
bridge fdb add dev DEV ADDRESS [vlan VID] [self] static
|
||||
|
||||
The driver should use the helper switchdev_port_fdb_xxx ops for ndo_fdb_xxx
|
||||
ops, and handle add/delete/dump of SWITCHDEV_OBJ_ID_PORT_FDB object using
|
||||
switchdev_port_obj_xxx ops.
|
||||
(the "static" keyword is non-optional: if not specified, the entry defaults to
|
||||
being "local", which means that it should not be forwarded)
|
||||
|
||||
XXX: what should be done if offloading this rule to hardware fails (for
|
||||
example, due to full capacity in hardware tables) ?
|
||||
The "self" keyword (optional because it is implicit) has the role of
|
||||
instructing the kernel to fulfill the operation through the ``ndo_fdb_add``
|
||||
implementation of the ``DEV`` device itself. If ``DEV`` is a bridge port, this
|
||||
will bypass the bridge and therefore leave the software database out of sync
|
||||
with the hardware one.
|
||||
|
||||
To avoid this, the "master" keyword can be used::
|
||||
|
||||
bridge fdb add dev DEV ADDRESS [vlan VID] master static
|
||||
|
||||
The above command instructs the kernel to search for a master interface of
|
||||
``DEV`` and fulfill the operation through the ``ndo_fdb_add`` method of that.
|
||||
This time, the bridge generates a ``SWITCHDEV_FDB_ADD_TO_DEVICE`` notification
|
||||
which the port driver can handle and use it to program its hardware table. This
|
||||
way, the software and the hardware database will both contain this static FDB
|
||||
entry.
|
||||
|
||||
Note: for new switchdev drivers that offload the Linux bridge, implementing the
|
||||
``ndo_fdb_add`` and ``ndo_fdb_del`` bridge bypass methods is strongly
|
||||
discouraged: all static FDB entries should be added on a bridge port using the
|
||||
"master" flag. The ``ndo_fdb_dump`` is an exception and can be implemented to
|
||||
visualize the hardware tables, if the device does not have an interrupt for
|
||||
notifying the operating system of newly learned/forgotten dynamic FDB
|
||||
addresses. In that case, the hardware FDB might end up having entries that the
|
||||
software FDB does not, and implementing ``ndo_fdb_dump`` is the only way to see
|
||||
them.
|
||||
|
||||
Note: by default, the bridge does not filter on VLAN and only bridges untagged
|
||||
traffic. To enable VLAN support, turn on VLAN filtering::
|
||||
@ -385,3 +408,156 @@ The driver can monitor for updates to arp_tbl using the netevent notifier
|
||||
NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops
|
||||
for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy
|
||||
to know when arp_tbl neighbor entries are purged from the port.
|
||||
|
||||
Device driver expected behavior
|
||||
-------------------------------
|
||||
|
||||
Below is a set of defined behavior that switchdev enabled network devices must
|
||||
adhere to.
|
||||
|
||||
Configuration-less state
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Upon driver bring up, the network devices must be fully operational, and the
|
||||
backing driver must configure the network device such that it is possible to
|
||||
send and receive traffic to this network device and it is properly separated
|
||||
from other network devices/ports (e.g.: as is frequent with a switch ASIC). How
|
||||
this is achieved is heavily hardware dependent, but a simple solution can be to
|
||||
use per-port VLAN identifiers unless a better mechanism is available
|
||||
(proprietary metadata for each network port for instance).
|
||||
|
||||
The network device must be capable of running a full IP protocol stack
|
||||
including multicast, DHCP, IPv4/6, etc. If necessary, it should program the
|
||||
appropriate filters for VLAN, multicast, unicast etc. The underlying device
|
||||
driver must effectively be configured in a similar fashion to what it would do
|
||||
when IGMP snooping is enabled for IP multicast over these switchdev network
|
||||
devices and unsolicited multicast must be filtered as early as possible in
|
||||
the hardware.
|
||||
|
||||
When configuring VLANs on top of the network device, all VLANs must be working,
|
||||
irrespective of the state of other network devices (e.g.: other ports being part
|
||||
of a VLAN-aware bridge doing ingress VID checking). See below for details.
|
||||
|
||||
If the device implements e.g.: VLAN filtering, putting the interface in
|
||||
promiscuous mode should allow the reception of all VLAN tags (including those
|
||||
not present in the filter(s)).
|
||||
|
||||
Bridged switch ports
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When a switchdev enabled network device is added as a bridge member, it should
|
||||
not disrupt any functionality of non-bridged network devices and they
|
||||
should continue to behave as normal network devices. Depending on the bridge
|
||||
configuration knobs below, the expected behavior is documented.
|
||||
|
||||
Bridge VLAN filtering
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Linux bridge allows the configuration of a VLAN filtering mode (statically,
|
||||
at device creation time, and dynamically, during run time) which must be
|
||||
observed by the underlying switchdev network device/hardware:
|
||||
|
||||
- with VLAN filtering turned off: the bridge is strictly VLAN unaware and its
|
||||
data path will process all Ethernet frames as if they are VLAN-untagged.
|
||||
The bridge VLAN database can still be modified, but the modifications should
|
||||
have no effect while VLAN filtering is turned off. Frames ingressing the
|
||||
device with a VID that is not programmed into the bridge/switch's VLAN table
|
||||
must be forwarded and may be processed using a VLAN device (see below).
|
||||
|
||||
- with VLAN filtering turned on: the bridge is VLAN-aware and frames ingressing
|
||||
the device with a VID that is not programmed into the bridges/switch's VLAN
|
||||
table must be dropped (strict VID checking).
|
||||
|
||||
When there is a VLAN device (e.g: sw0p1.100) configured on top of a switchdev
|
||||
network device which is a bridge port member, the behavior of the software
|
||||
network stack must be preserved, or the configuration must be refused if that
|
||||
is not possible.
|
||||
|
||||
- with VLAN filtering turned off, the bridge will process all ingress traffic
|
||||
for the port, except for the traffic tagged with a VLAN ID destined for a
|
||||
VLAN upper. The VLAN upper interface (which consumes the VLAN tag) can even
|
||||
be added to a second bridge, which includes other switch ports or software
|
||||
interfaces. Some approaches to ensure that the forwarding domain for traffic
|
||||
belonging to the VLAN upper interfaces are managed properly:
|
||||
|
||||
* If forwarding destinations can be managed per VLAN, the hardware could be
|
||||
configured to map all traffic, except the packets tagged with a VID
|
||||
belonging to a VLAN upper interface, to an internal VID corresponding to
|
||||
untagged packets. This internal VID spans all ports of the VLAN-unaware
|
||||
bridge. The VID corresponding to the VLAN upper interface spans the
|
||||
physical port of that VLAN interface, as well as the other ports that
|
||||
might be bridged with it.
|
||||
* Treat bridge ports with VLAN upper interfaces as standalone, and let
|
||||
forwarding be handled in the software data path.
|
||||
|
||||
- with VLAN filtering turned on, these VLAN devices can be created as long as
|
||||
the bridge does not have an existing VLAN entry with the same VID on any
|
||||
bridge port. These VLAN devices cannot be enslaved into the bridge since they
|
||||
duplicate functionality/use case with the bridge's VLAN data path processing.
|
||||
|
||||
Non-bridged network ports of the same switch fabric must not be disturbed in any
|
||||
way by the enabling of VLAN filtering on the bridge device(s). If the VLAN
|
||||
filtering setting is global to the entire chip, then the standalone ports
|
||||
should indicate to the network stack that VLAN filtering is required by setting
|
||||
'rx-vlan-filter: on [fixed]' in the ethtool features.
|
||||
|
||||
Because VLAN filtering can be turned on/off at runtime, the switchdev driver
|
||||
must be able to reconfigure the underlying hardware on the fly to honor the
|
||||
toggling of that option and behave appropriately. If that is not possible, the
|
||||
switchdev driver can also refuse to support dynamic toggling of the VLAN
|
||||
filtering knob at runtime and require a destruction of the bridge device(s) and
|
||||
creation of new bridge device(s) with a different VLAN filtering value to
|
||||
ensure VLAN awareness is pushed down to the hardware.
|
||||
|
||||
Even when VLAN filtering in the bridge is turned off, the underlying switch
|
||||
hardware and driver may still configure itself in a VLAN-aware mode provided
|
||||
that the behavior described above is observed.
|
||||
|
||||
The VLAN protocol of the bridge plays a role in deciding whether a packet is
|
||||
treated as tagged or not: a bridge using the 802.1ad protocol must treat both
|
||||
VLAN-untagged packets, as well as packets tagged with 802.1Q headers, as
|
||||
untagged.
|
||||
|
||||
The 802.1p (VID 0) tagged packets must be treated in the same way by the device
|
||||
as untagged packets, since the bridge device does not allow the manipulation of
|
||||
VID 0 in its database.
|
||||
|
||||
When the bridge has VLAN filtering enabled and a PVID is not configured on the
|
||||
ingress port, untagged and 802.1p tagged packets must be dropped. When the bridge
|
||||
has VLAN filtering enabled and a PVID exists on the ingress port, untagged and
|
||||
priority-tagged packets must be accepted and forwarded according to the
|
||||
bridge's port membership of the PVID VLAN. When the bridge has VLAN filtering
|
||||
disabled, the presence/lack of a PVID should not influence the packet
|
||||
forwarding decision.
|
||||
|
||||
Bridge IGMP snooping
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Linux bridge allows the configuration of IGMP snooping (statically, at
|
||||
interface creation time, or dynamically, during runtime) which must be observed
|
||||
by the underlying switchdev network device/hardware in the following way:
|
||||
|
||||
- when IGMP snooping is turned off, multicast traffic must be flooded to all
|
||||
ports within the same bridge that have mcast_flood=true. The CPU/management
|
||||
port should ideally not be flooded (unless the ingress interface has
|
||||
IFF_ALLMULTI or IFF_PROMISC) and continue to learn multicast traffic through
|
||||
the network stack notifications. If the hardware is not capable of doing that
|
||||
then the CPU/management port must also be flooded and multicast filtering
|
||||
happens in software.
|
||||
|
||||
- when IGMP snooping is turned on, multicast traffic must selectively flow
|
||||
to the appropriate network ports (including CPU/management port). Flooding of
|
||||
unknown multicast should be only towards the ports connected to a multicast
|
||||
router (the local device may also act as a multicast router).
|
||||
|
||||
The switch must adhere to RFC 4541 and flood multicast traffic accordingly
|
||||
since that is what the Linux bridge implementation does.
|
||||
|
||||
Because IGMP snooping can be turned on/off at runtime, the switchdev driver
|
||||
must be able to reconfigure the underlying hardware on the fly to honor the
|
||||
toggling of that option and behave appropriately.
|
||||
|
||||
A switchdev driver can also refuse to support dynamic toggling of the multicast
|
||||
snooping knob at runtime and require the destruction of the bridge device(s)
|
||||
and creation of a new bridge device(s) with a different multicast snooping
|
||||
value.
|
||||
|
@ -630,30 +630,45 @@ hardware timestamping on it. This is because the SO_TIMESTAMPING API does not
|
||||
allow the delivery of multiple hardware timestamps for the same packet, so
|
||||
anybody else except for the DSA switch port must be prevented from doing so.
|
||||
|
||||
In code, DSA provides for most of the infrastructure for timestamping already,
|
||||
in generic code: a BPF classifier (``ptp_classify_raw``) is used to identify
|
||||
PTP event messages (any other packets, including PTP general messages, are not
|
||||
timestamped), and provides two hooks to drivers:
|
||||
In the generic layer, DSA provides the following infrastructure for PTP
|
||||
timestamping:
|
||||
|
||||
- ``.port_txtstamp()``: The driver is passed a clone of the timestampable skb
|
||||
to be transmitted, before actually transmitting it. Typically, a switch will
|
||||
have a PTP TX timestamp register (or sometimes a FIFO) where the timestamp
|
||||
becomes available. There may be an IRQ that is raised upon this timestamp's
|
||||
availability, or the driver might have to poll after invoking
|
||||
``dev_queue_xmit()`` towards the host interface. Either way, in the
|
||||
``.port_txtstamp()`` method, the driver only needs to save the clone for
|
||||
later use (when the timestamp becomes available). Each skb is annotated with
|
||||
a pointer to its clone, in ``DSA_SKB_CB(skb)->clone``, to ease the driver's
|
||||
job of keeping track of which clone belongs to which skb.
|
||||
- ``.port_txtstamp()``: a hook called prior to the transmission of
|
||||
packets with a hardware TX timestamping request from user space.
|
||||
This is required for two-step timestamping, since the hardware
|
||||
timestamp becomes available after the actual MAC transmission, so the
|
||||
driver must be prepared to correlate the timestamp with the original
|
||||
packet so that it can re-enqueue the packet back into the socket's
|
||||
error queue. To save the packet for when the timestamp becomes
|
||||
available, the driver can call ``skb_clone_sk`` , save the clone pointer
|
||||
in skb->cb and enqueue a tx skb queue. Typically, a switch will have a
|
||||
PTP TX timestamp register (or sometimes a FIFO) where the timestamp
|
||||
becomes available. In case of a FIFO, the hardware might store
|
||||
key-value pairs of PTP sequence ID/message type/domain number and the
|
||||
actual timestamp. To perform the correlation correctly between the
|
||||
packets in a queue waiting for timestamping and the actual timestamps,
|
||||
drivers can use a BPF classifier (``ptp_classify_raw``) to identify
|
||||
the PTP transport type, and ``ptp_parse_header`` to interpret the PTP
|
||||
header fields. There may be an IRQ that is raised upon this
|
||||
timestamp's availability, or the driver might have to poll after
|
||||
invoking ``dev_queue_xmit()`` towards the host interface.
|
||||
One-step TX timestamping do not require packet cloning, since there is
|
||||
no follow-up message required by the PTP protocol (because the
|
||||
TX timestamp is embedded into the packet by the MAC), and therefore
|
||||
user space does not expect the packet annotated with the TX timestamp
|
||||
to be re-enqueued into its socket's error queue.
|
||||
|
||||
- ``.port_rxtstamp()``: The original (and only) timestampable skb is provided
|
||||
to the driver, for it to annotate it with a timestamp, if that is immediately
|
||||
available, or defer to later. On reception, timestamps might either be
|
||||
available in-band (through metadata in the DSA header, or attached in other
|
||||
ways to the packet), or out-of-band (through another RX timestamping FIFO).
|
||||
Deferral on RX is typically necessary when retrieving the timestamp needs a
|
||||
sleepable context. In that case, it is the responsibility of the DSA driver
|
||||
to call ``netif_rx_ni()`` on the freshly timestamped skb.
|
||||
- ``.port_rxtstamp()``: On RX, the BPF classifier is run by DSA to
|
||||
identify PTP event messages (any other packets, including PTP general
|
||||
messages, are not timestamped). The original (and only) timestampable
|
||||
skb is provided to the driver, for it to annotate it with a timestamp,
|
||||
if that is immediately available, or defer to later. On reception,
|
||||
timestamps might either be available in-band (through metadata in the
|
||||
DSA header, or attached in other ways to the packet), or out-of-band
|
||||
(through another RX timestamping FIFO). Deferral on RX is typically
|
||||
necessary when retrieving the timestamp needs a sleepable context. In
|
||||
that case, it is the responsibility of the DSA driver to call
|
||||
``netif_rx_ni()`` on the freshly timestamped skb.
|
||||
|
||||
3.2.2 Ethernet PHYs
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -70,60 +70,13 @@ First Byte = 0x03 (X25_IFACE_PARAMS)
|
||||
LAPB parameters. To be defined.
|
||||
|
||||
|
||||
Requirements for the device driver
|
||||
----------------------------------
|
||||
|
||||
Possible Problems
|
||||
=================
|
||||
Packets should not be reordered or dropped when delivering between the
|
||||
Packet Layer and the device driver.
|
||||
|
||||
(Henner Eisen, 2000-10-28)
|
||||
|
||||
The X.25 packet layer protocol depends on a reliable datalink service.
|
||||
The LAPB protocol provides such reliable service. But this reliability
|
||||
is not preserved by the Linux network device driver interface:
|
||||
|
||||
- With Linux 2.4.x (and above) SMP kernels, packet ordering is not
|
||||
preserved. Even if a device driver calls netif_rx(skb1) and later
|
||||
netif_rx(skb2), skb2 might be delivered to the network layer
|
||||
earlier that skb1.
|
||||
- Data passed upstream by means of netif_rx() might be dropped by the
|
||||
kernel if the backlog queue is congested.
|
||||
|
||||
The X.25 packet layer protocol will detect this and reset the virtual
|
||||
call in question. But many upper layer protocols are not designed to
|
||||
handle such N-Reset events gracefully. And frequent N-Reset events
|
||||
will always degrade performance.
|
||||
|
||||
Thus, driver authors should make netif_rx() as reliable as possible:
|
||||
|
||||
SMP re-ordering will not occur if the driver's interrupt handler is
|
||||
always executed on the same CPU. Thus,
|
||||
|
||||
- Driver authors should use irq affinity for the interrupt handler.
|
||||
|
||||
The probability of packet loss due to backlog congestion can be
|
||||
reduced by the following measures or a combination thereof:
|
||||
|
||||
(1) Drivers for kernel versions 2.4.x and above should always check the
|
||||
return value of netif_rx(). If it returns NET_RX_DROP, the
|
||||
driver's LAPB protocol must not confirm reception of the frame
|
||||
to the peer.
|
||||
This will reliably suppress packet loss. The LAPB protocol will
|
||||
automatically cause the peer to re-transmit the dropped packet
|
||||
later.
|
||||
The lapb module interface was modified to support this. Its
|
||||
data_indication() method should now transparently pass the
|
||||
netif_rx() return value to the (lapb module) caller.
|
||||
(2) Drivers for kernel versions 2.2.x should always check the global
|
||||
variable netdev_dropping when a new frame is received. The driver
|
||||
should only call netif_rx() if netdev_dropping is zero. Otherwise
|
||||
the driver should not confirm delivery of the frame and drop it.
|
||||
Alternatively, the driver can queue the frame internally and call
|
||||
netif_rx() later when netif_dropping is 0 again. In that case, delivery
|
||||
confirmation should also be deferred such that the internal queue
|
||||
cannot grow to much.
|
||||
This will not reliably avoid packet loss, but the probability
|
||||
of packet loss in netif_rx() path will be significantly reduced.
|
||||
(3) Additionally, driver authors might consider to support
|
||||
CONFIG_NET_HW_FLOWCONTROL. This allows the driver to be woken up
|
||||
when a previously congested backlog queue becomes empty again.
|
||||
The driver could uses this for flow-controlling the peer by means
|
||||
of the LAPB protocol's flow-control service.
|
||||
To avoid packets from being reordered or dropped when delivering from
|
||||
the device driver to the Packet Layer, the device driver should not
|
||||
call "netif_rx" to deliver the received packets. Instead, it should
|
||||
call "netif_receive_skb_core" from softirq context to deliver them.
|
||||
|
17
Documentation/userspace-api/ebpf/index.rst
Normal file
17
Documentation/userspace-api/ebpf/index.rst
Normal file
@ -0,0 +1,17 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
eBPF Userspace API
|
||||
==================
|
||||
|
||||
eBPF is a kernel mechanism to provide a sandboxed runtime environment in the
|
||||
Linux kernel for runtime extension and instrumentation without changing kernel
|
||||
source code or loading kernel modules. eBPF programs can be attached to various
|
||||
kernel subsystems, including networking, tracing and Linux security modules
|
||||
(LSM).
|
||||
|
||||
For internal kernel documentation on eBPF, see Documentation/bpf/index.rst.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
syscall
|
24
Documentation/userspace-api/ebpf/syscall.rst
Normal file
24
Documentation/userspace-api/ebpf/syscall.rst
Normal file
@ -0,0 +1,24 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
eBPF Syscall
|
||||
------------
|
||||
|
||||
:Authors: - Alexei Starovoitov <ast@kernel.org>
|
||||
- Joe Stringer <joe@wand.net.nz>
|
||||
- Michael Kerrisk <mtk.manpages@gmail.com>
|
||||
|
||||
The primary info for the bpf syscall is available in the `man-pages`_
|
||||
for `bpf(2)`_.
|
||||
|
||||
bpf() subcommand reference
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/bpf.h
|
||||
:doc: eBPF Syscall Preamble
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/bpf.h
|
||||
:doc: eBPF Syscall Commands
|
||||
|
||||
.. Links:
|
||||
.. _man-pages: https://www.kernel.org/doc/man-pages/
|
||||
.. _bpf(2): https://man7.org/linux/man-pages/man2/bpf.2.html
|
@ -21,6 +21,7 @@ place where this information is gathered.
|
||||
unshare
|
||||
spec_ctrl
|
||||
accelerators/ocxl
|
||||
ebpf/index
|
||||
ioctl/index
|
||||
iommu
|
||||
media/index
|
||||
|
31
MAINTAINERS
31
MAINTAINERS
@ -1533,6 +1533,7 @@ F: Documentation/devicetree/bindings/dma/owl-dma.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
|
||||
F: Documentation/devicetree/bindings/mmc/owl-mmc.yaml
|
||||
F: Documentation/devicetree/bindings/net/actions,owl-emac.yaml
|
||||
F: Documentation/devicetree/bindings/pinctrl/actions,*
|
||||
F: Documentation/devicetree/bindings/power/actions,owl-sps.txt
|
||||
F: Documentation/devicetree/bindings/timer/actions,owl-timer.txt
|
||||
@ -1545,6 +1546,7 @@ F: drivers/dma/owl-dma.c
|
||||
F: drivers/i2c/busses/i2c-owl.c
|
||||
F: drivers/irqchip/irq-owl-sirq.c
|
||||
F: drivers/mmc/host/owl-mmc.c
|
||||
F: drivers/net/ethernet/actions/
|
||||
F: drivers/pinctrl/actions/*
|
||||
F: drivers/soc/actions/
|
||||
F: include/dt-bindings/power/owl-*
|
||||
@ -3285,6 +3287,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
|
||||
F: Documentation/bpf/
|
||||
F: Documentation/networking/filter.rst
|
||||
F: Documentation/userspace-api/ebpf/
|
||||
F: arch/*/net/*
|
||||
F: include/linux/bpf*
|
||||
F: include/linux/filter.h
|
||||
@ -3299,6 +3302,7 @@ F: net/core/filter.c
|
||||
F: net/sched/act_bpf.c
|
||||
F: net/sched/cls_bpf.c
|
||||
F: samples/bpf/
|
||||
F: scripts/bpf_doc.py
|
||||
F: tools/bpf/
|
||||
F: tools/lib/bpf/
|
||||
F: tools/testing/selftests/bpf/
|
||||
@ -5555,11 +5559,11 @@ F: drivers/net/ethernet/freescale/dpaa2/dpmac*
|
||||
F: drivers/net/ethernet/freescale/dpaa2/dpni*
|
||||
|
||||
DPAA2 ETHERNET SWITCH DRIVER
|
||||
M: Ioana Radulescu <ruxandra.radulescu@nxp.com>
|
||||
M: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/fsl-dpaa2/ethsw
|
||||
F: drivers/net/ethernet/freescale/dpaa2/dpaa2-switch*
|
||||
F: drivers/net/ethernet/freescale/dpaa2/dpsw*
|
||||
|
||||
DPT_I2O SCSI RAID DRIVER
|
||||
M: Adaptec OEM Raid Solutions <aacraid@microsemi.com>
|
||||
@ -8370,11 +8374,12 @@ S: Maintained
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/i2c/hi556.c
|
||||
|
||||
Hyper-V CORE AND DRIVERS
|
||||
Hyper-V/Azure CORE AND DRIVERS
|
||||
M: "K. Y. Srinivasan" <kys@microsoft.com>
|
||||
M: Haiyang Zhang <haiyangz@microsoft.com>
|
||||
M: Stephen Hemminger <sthemmin@microsoft.com>
|
||||
M: Wei Liu <wei.liu@kernel.org>
|
||||
M: Dexuan Cui <decui@microsoft.com>
|
||||
L: linux-hyperv@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
|
||||
@ -8391,6 +8396,7 @@ F: drivers/hid/hid-hyperv.c
|
||||
F: drivers/hv/
|
||||
F: drivers/input/serio/hyperv-keyboard.c
|
||||
F: drivers/iommu/hyperv-iommu.c
|
||||
F: drivers/net/ethernet/microsoft/
|
||||
F: drivers/net/hyperv/
|
||||
F: drivers/pci/controller/pci-hyperv-intf.c
|
||||
F: drivers/pci/controller/pci-hyperv.c
|
||||
@ -8633,7 +8639,6 @@ IBM Power SRIOV Virtual NIC Device Driver
|
||||
M: Dany Madden <drt@linux.ibm.com>
|
||||
M: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
|
||||
R: Thomas Falcon <tlfalcon@linux.ibm.com>
|
||||
R: Lijun Pan <lijunp213@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/ibm/ibmvnic.*
|
||||
@ -10858,6 +10863,7 @@ F: include/linux/mv643xx.h
|
||||
|
||||
MARVELL MV88X3310 PHY DRIVER
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
M: Marek Behun <marek.behun@nic.cz>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/phy/marvell10g.c
|
||||
@ -11080,7 +11086,7 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/radio/radio-maxiradio*
|
||||
|
||||
MCAN MMIO DEVICE DRIVER
|
||||
M: Pankaj Sharma <pankj.sharma@samsung.com>
|
||||
M: Chandrasekar Ramakrishnan <rcsekar@samsung.com>
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml
|
||||
@ -12749,6 +12755,7 @@ W: https://github.com/multipath-tcp/mptcp_net-next/wiki
|
||||
B: https://github.com/multipath-tcp/mptcp_net-next/issues
|
||||
F: Documentation/networking/mptcp-sysctl.rst
|
||||
F: include/net/mptcp.h
|
||||
F: include/trace/events/mptcp.h
|
||||
F: include/uapi/linux/mptcp.h
|
||||
F: net/mptcp/
|
||||
F: tools/testing/selftests/net/mptcp/
|
||||
@ -13033,6 +13040,12 @@ F: drivers/nvmem/
|
||||
F: include/linux/nvmem-consumer.h
|
||||
F: include/linux/nvmem-provider.h
|
||||
|
||||
NXP C45 TJA11XX PHY DRIVER
|
||||
M: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/phy/nxp-c45-tja11xx.c
|
||||
|
||||
NXP FSPI DRIVER
|
||||
M: Ashish Kumar <ashish.kumar@nxp.com>
|
||||
R: Yogesh Gaur <yogeshgaur.83@gmail.com>
|
||||
@ -18222,12 +18235,6 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Odd Fixes
|
||||
F: sound/soc/codecs/tas571x*
|
||||
|
||||
TI TCAN4X5X DEVICE DRIVER
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/can/tcan4x5x.txt
|
||||
F: drivers/net/can/m_can/tcan4x5x*
|
||||
|
||||
TI TRF7970A NFC DRIVER
|
||||
M: Mark Greer <mgreer@animalcreek.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
@ -583,7 +583,7 @@
|
||||
clocks = <&sys_clk 6>;
|
||||
reset-names = "ether";
|
||||
resets = <&sys_rst 6>;
|
||||
phy-mode = "rgmii";
|
||||
phy-mode = "rgmii-id";
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
socionext,syscon-phy-mode = <&soc_glue 0>;
|
||||
|
||||
|
@ -84,6 +84,7 @@ static void __init kirkwood_dt_eth_fixup(void)
|
||||
struct device_node *pnp = of_get_parent(np);
|
||||
struct clk *clk;
|
||||
struct property *pmac;
|
||||
u8 tmpmac[ETH_ALEN];
|
||||
void __iomem *io;
|
||||
u8 *macaddr;
|
||||
u32 reg;
|
||||
@ -93,7 +94,7 @@ static void __init kirkwood_dt_eth_fixup(void)
|
||||
|
||||
/* skip disabled nodes or nodes with valid MAC address*/
|
||||
if (!of_device_is_available(pnp) ||
|
||||
!IS_ERR(of_get_mac_address(np)))
|
||||
!of_get_mac_address(np, tmpmac))
|
||||
goto eth_fixup_skip;
|
||||
|
||||
clk = of_clk_get(pnp, 0);
|
||||
|
@ -1118,6 +1118,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
/* Integrated Endpoint Register Block */
|
||||
ierb@1f0800000 {
|
||||
compatible = "fsl,ls1028a-enetc-ierb";
|
||||
reg = <0x01 0xf0800000 0x0 0x10000>;
|
||||
};
|
||||
|
||||
rcpm: power-controller@1e34040 {
|
||||
compatible = "fsl,ls1028a-rcpm", "fsl,qoriq-rcpm-2.1+";
|
||||
reg = <0x0 0x1e34040 0x0 0x1c>;
|
||||
|
@ -916,8 +916,8 @@
|
||||
"mac_clk_tx", "clk_mac_ref",
|
||||
"aclk_mac", "pclk_mac",
|
||||
"clk_macphy";
|
||||
resets = <&cru SRST_GMAC2PHY_A>, <&cru SRST_MACPHY>;
|
||||
reset-names = "stmmaceth", "mac-phy";
|
||||
resets = <&cru SRST_GMAC2PHY_A>;
|
||||
reset-names = "stmmaceth";
|
||||
phy-mode = "rmii";
|
||||
phy-handle = <&phy>;
|
||||
snps,txpbl = <0x4>;
|
||||
|
@ -734,7 +734,7 @@
|
||||
clocks = <&sys_clk 6>;
|
||||
reset-names = "ether";
|
||||
resets = <&sys_rst 6>;
|
||||
phy-mode = "rgmii";
|
||||
phy-mode = "rgmii-id";
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
socionext,syscon-phy-mode = <&soc_glue 0>;
|
||||
|
||||
|
@ -564,7 +564,7 @@
|
||||
clocks = <&sys_clk 6>;
|
||||
reset-names = "ether";
|
||||
resets = <&sys_rst 6>;
|
||||
phy-mode = "rgmii";
|
||||
phy-mode = "rgmii-id";
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
socionext,syscon-phy-mode = <&soc_glue 0>;
|
||||
|
||||
@ -585,7 +585,7 @@
|
||||
clocks = <&sys_clk 7>;
|
||||
reset-names = "ether";
|
||||
resets = <&sys_rst 7>;
|
||||
phy-mode = "rgmii";
|
||||
phy-mode = "rgmii-id";
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
socionext,syscon-phy-mode = <&soc_glue 1>;
|
||||
|
||||
|
@ -58,37 +58,27 @@ EXPORT_SYMBOL(get_latch_u5);
|
||||
|
||||
static struct resource korina_dev0_res[] = {
|
||||
{
|
||||
.name = "korina_regs",
|
||||
.name = "emac",
|
||||
.start = ETH0_BASE_ADDR,
|
||||
.end = ETH0_BASE_ADDR + sizeof(struct eth_regs),
|
||||
.flags = IORESOURCE_MEM,
|
||||
}, {
|
||||
.name = "korina_rx",
|
||||
.name = "rx",
|
||||
.start = ETH0_DMA_RX_IRQ,
|
||||
.end = ETH0_DMA_RX_IRQ,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}, {
|
||||
.name = "korina_tx",
|
||||
.name = "tx",
|
||||
.start = ETH0_DMA_TX_IRQ,
|
||||
.end = ETH0_DMA_TX_IRQ,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}, {
|
||||
.name = "korina_ovr",
|
||||
.start = ETH0_RX_OVR_IRQ,
|
||||
.end = ETH0_RX_OVR_IRQ,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}, {
|
||||
.name = "korina_und",
|
||||
.start = ETH0_TX_UND_IRQ,
|
||||
.end = ETH0_TX_UND_IRQ,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}, {
|
||||
.name = "korina_dma_rx",
|
||||
.name = "dma_rx",
|
||||
.start = ETH0_RX_DMA_ADDR,
|
||||
.end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
}, {
|
||||
.name = "korina_dma_tx",
|
||||
.name = "dma_tx",
|
||||
.start = ETH0_TX_DMA_ADDR,
|
||||
.end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
@ -105,6 +95,9 @@ static struct platform_device korina_dev0 = {
|
||||
.name = "korina",
|
||||
.resource = korina_dev0_res,
|
||||
.num_resources = ARRAY_SIZE(korina_dev0_res),
|
||||
.dev = {
|
||||
.platform_data = &korina_dev0_data.mac,
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource cf_slot0_res[] = {
|
||||
@ -299,8 +292,6 @@ static int __init plat_setup_devices(void)
|
||||
/* set the uart clock to the current cpu frequency */
|
||||
rb532_uart_res[0].uartclk = idt_cpu_freq;
|
||||
|
||||
dev_set_drvdata(&korina_dev0.dev, &korina_dev0_data);
|
||||
|
||||
gpiod_add_lookup_table(&cf_slot0_gpio_table);
|
||||
return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs));
|
||||
}
|
||||
|
@ -170,8 +170,6 @@ timer@41100 {
|
||||
/include/ "pq3-etsec2-0.dtsi"
|
||||
enet0: ethernet@b0000 {
|
||||
queue-group@b0000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
interrupts = <26 2 0 0 27 2 0 0 28 2 0 0>;
|
||||
};
|
||||
};
|
||||
@ -179,8 +177,6 @@ enet0: ethernet@b0000 {
|
||||
/include/ "pq3-etsec2-1.dtsi"
|
||||
enet1: ethernet@b1000 {
|
||||
queue-group@b1000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
interrupts = <33 2 0 0 34 2 0 0 35 2 0 0>;
|
||||
};
|
||||
};
|
||||
|
@ -190,8 +190,6 @@ crypto@30000 {
|
||||
/include/ "pq3-etsec2-0.dtsi"
|
||||
enet0: ethernet@b0000 {
|
||||
queue-group@b0000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
interrupts = <26 2 0 0 27 2 0 0 28 2 0 0>;
|
||||
};
|
||||
};
|
||||
@ -199,8 +197,6 @@ enet0: ethernet@b0000 {
|
||||
/include/ "pq3-etsec2-1.dtsi"
|
||||
enet1: ethernet@b1000 {
|
||||
queue-group@b1000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
interrupts = <33 2 0 0 34 2 0 0 35 2 0 0>;
|
||||
};
|
||||
};
|
||||
|
@ -171,8 +171,6 @@
|
||||
enet0: ethernet@b0000 {
|
||||
queue-group@b0000 {
|
||||
reg = <0x10000 0x1000>;
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -180,8 +178,6 @@
|
||||
enet1: ethernet@b1000 {
|
||||
queue-group@b1000 {
|
||||
reg = <0x11000 0x1000>;
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -172,29 +172,8 @@
|
||||
/include/ "pq3-mpic-timer-B.dtsi"
|
||||
|
||||
/include/ "pq3-etsec2-0.dtsi"
|
||||
enet0: ethernet@b0000 {
|
||||
queue-group@b0000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "pq3-etsec2-1.dtsi"
|
||||
enet1: ethernet@b1000 {
|
||||
queue-group@b1000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "pq3-etsec2-2.dtsi"
|
||||
enet2: ethernet@b2000 {
|
||||
queue-group@b2000 {
|
||||
fsl,rx-bit-map = <0xff>;
|
||||
fsl,tx-bit-map = <0xff>;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
global-utilities@e0000 {
|
||||
compatible = "fsl,p1010-guts";
|
||||
|
@ -73,7 +73,6 @@ static int __init tsi108_eth_of_init(void)
|
||||
struct device_node *phy, *mdio;
|
||||
hw_info tsi_eth_data;
|
||||
const unsigned int *phy_id;
|
||||
const void *mac_addr;
|
||||
const phandle *ph;
|
||||
|
||||
memset(r, 0, sizeof(r));
|
||||
@ -101,9 +100,7 @@ static int __init tsi108_eth_of_init(void)
|
||||
goto err;
|
||||
}
|
||||
|
||||
mac_addr = of_get_mac_address(np);
|
||||
if (!IS_ERR(mac_addr))
|
||||
ether_addr_copy(tsi_eth_data.mac_addr, mac_addr);
|
||||
of_get_mac_address(np, tsi_eth_data.mac_addr);
|
||||
|
||||
ph = of_get_property(np, "mdio-handle", NULL);
|
||||
mdio = of_find_node_by_phandle(*ph);
|
||||
|
@ -1209,21 +1209,67 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
*/
|
||||
case BPF_STX | BPF_ATOMIC | BPF_DW:
|
||||
case BPF_STX | BPF_ATOMIC | BPF_W:
|
||||
if (insn->imm != BPF_ADD) {
|
||||
{
|
||||
bool is32 = BPF_SIZE(insn->code) == BPF_W;
|
||||
|
||||
switch (insn->imm) {
|
||||
/* {op32|op64} {%w0|%src},%src,off(%dst) */
|
||||
#define EMIT_ATOMIC(op32, op64) do { \
|
||||
EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64), \
|
||||
(insn->imm & BPF_FETCH) ? src_reg : REG_W0, \
|
||||
src_reg, dst_reg, off); \
|
||||
if (is32 && (insn->imm & BPF_FETCH)) \
|
||||
EMIT_ZERO(src_reg); \
|
||||
} while (0)
|
||||
case BPF_ADD:
|
||||
case BPF_ADD | BPF_FETCH:
|
||||
/* {laal|laalg} */
|
||||
EMIT_ATOMIC(0x00fa, 0x00ea);
|
||||
break;
|
||||
case BPF_AND:
|
||||
case BPF_AND | BPF_FETCH:
|
||||
/* {lan|lang} */
|
||||
EMIT_ATOMIC(0x00f4, 0x00e4);
|
||||
break;
|
||||
case BPF_OR:
|
||||
case BPF_OR | BPF_FETCH:
|
||||
/* {lao|laog} */
|
||||
EMIT_ATOMIC(0x00f6, 0x00e6);
|
||||
break;
|
||||
case BPF_XOR:
|
||||
case BPF_XOR | BPF_FETCH:
|
||||
/* {lax|laxg} */
|
||||
EMIT_ATOMIC(0x00f7, 0x00e7);
|
||||
break;
|
||||
#undef EMIT_ATOMIC
|
||||
case BPF_XCHG:
|
||||
/* {ly|lg} %w0,off(%dst) */
|
||||
EMIT6_DISP_LH(0xe3000000,
|
||||
is32 ? 0x0058 : 0x0004, REG_W0, REG_0,
|
||||
dst_reg, off);
|
||||
/* 0: {csy|csg} %w0,%src,off(%dst) */
|
||||
EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030,
|
||||
REG_W0, src_reg, dst_reg, off);
|
||||
/* brc 4,0b */
|
||||
EMIT4_PCREL_RIC(0xa7040000, 4, jit->prg - 6);
|
||||
/* {llgfr|lgr} %src,%w0 */
|
||||
EMIT4(is32 ? 0xb9160000 : 0xb9040000, src_reg, REG_W0);
|
||||
if (is32 && insn_is_zext(&insn[1]))
|
||||
insn_count = 2;
|
||||
break;
|
||||
case BPF_CMPXCHG:
|
||||
/* 0: {csy|csg} %b0,%src,off(%dst) */
|
||||
EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030,
|
||||
BPF_REG_0, src_reg, dst_reg, off);
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown atomic operation %02x\n", insn->imm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* *(u32/u64 *)(dst + off) += src
|
||||
*
|
||||
* BFW_W: laal %w0,%src,off(%dst)
|
||||
* BPF_DW: laalg %w0,%src,off(%dst)
|
||||
*/
|
||||
EMIT6_DISP_LH(0xeb000000,
|
||||
BPF_SIZE(insn->code) == BPF_W ? 0x00fa : 0x00ea,
|
||||
REG_W0, src_reg, dst_reg, off);
|
||||
jit->seen |= SEEN_MEM;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* BPF_LDX
|
||||
*/
|
||||
|
@ -2355,3 +2355,8 @@ out:
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
}
|
||||
|
||||
bool bpf_jit_supports_kfunc_call(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -1390,6 +1390,19 @@ static inline void emit_push_r64(const u8 src[], u8 **pprog)
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void emit_push_r32(const u8 src[], u8 **pprog)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
int cnt = 0;
|
||||
|
||||
/* mov ecx,dword ptr [ebp+off] */
|
||||
EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX), STACK_VAR(src_lo));
|
||||
/* push ecx */
|
||||
EMIT1(0x51);
|
||||
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static u8 get_cond_jmp_opcode(const u8 op, bool is_cmp_lo)
|
||||
{
|
||||
u8 jmp_cond;
|
||||
@ -1459,6 +1472,174 @@ static u8 get_cond_jmp_opcode(const u8 op, bool is_cmp_lo)
|
||||
return jmp_cond;
|
||||
}
|
||||
|
||||
/* i386 kernel compiles with "-mregparm=3". From gcc document:
|
||||
*
|
||||
* ==== snippet ====
|
||||
* regparm (number)
|
||||
* On x86-32 targets, the regparm attribute causes the compiler
|
||||
* to pass arguments number one to (number) if they are of integral
|
||||
* type in registers EAX, EDX, and ECX instead of on the stack.
|
||||
* Functions that take a variable number of arguments continue
|
||||
* to be passed all of their arguments on the stack.
|
||||
* ==== snippet ====
|
||||
*
|
||||
* The first three args of a function will be considered for
|
||||
* putting into the 32bit register EAX, EDX, and ECX.
|
||||
*
|
||||
* Two 32bit registers are used to pass a 64bit arg.
|
||||
*
|
||||
* For example,
|
||||
* void foo(u32 a, u32 b, u32 c, u32 d):
|
||||
* u32 a: EAX
|
||||
* u32 b: EDX
|
||||
* u32 c: ECX
|
||||
* u32 d: stack
|
||||
*
|
||||
* void foo(u64 a, u32 b, u32 c):
|
||||
* u64 a: EAX (lo32) EDX (hi32)
|
||||
* u32 b: ECX
|
||||
* u32 c: stack
|
||||
*
|
||||
* void foo(u32 a, u64 b, u32 c):
|
||||
* u32 a: EAX
|
||||
* u64 b: EDX (lo32) ECX (hi32)
|
||||
* u32 c: stack
|
||||
*
|
||||
* void foo(u32 a, u32 b, u64 c):
|
||||
* u32 a: EAX
|
||||
* u32 b: EDX
|
||||
* u64 c: stack
|
||||
*
|
||||
* The return value will be stored in the EAX (and EDX for 64bit value).
|
||||
*
|
||||
* For example,
|
||||
* u32 foo(u32 a, u32 b, u32 c):
|
||||
* return value: EAX
|
||||
*
|
||||
* u64 foo(u32 a, u32 b, u32 c):
|
||||
* return value: EAX (lo32) EDX (hi32)
|
||||
*
|
||||
* Notes:
|
||||
* The verifier only accepts function having integer and pointers
|
||||
* as its args and return value, so it does not have
|
||||
* struct-by-value.
|
||||
*
|
||||
* emit_kfunc_call() finds out the btf_func_model by calling
|
||||
* bpf_jit_find_kfunc_model(). A btf_func_model
|
||||
* has the details about the number of args, size of each arg,
|
||||
* and the size of the return value.
|
||||
*
|
||||
* It first decides how many args can be passed by EAX, EDX, and ECX.
|
||||
* That will decide what args should be pushed to the stack:
|
||||
* [first_stack_regno, last_stack_regno] are the bpf regnos
|
||||
* that should be pushed to the stack.
|
||||
*
|
||||
* It will first push all args to the stack because the push
|
||||
* will need to use ECX. Then, it moves
|
||||
* [BPF_REG_1, first_stack_regno) to EAX, EDX, and ECX.
|
||||
*
|
||||
* When emitting a call (0xE8), it needs to figure out
|
||||
* the jmp_offset relative to the jit-insn address immediately
|
||||
* following the call (0xE8) instruction. At this point, it knows
|
||||
* the end of the jit-insn address after completely translated the
|
||||
* current (BPF_JMP | BPF_CALL) bpf-insn. It is passed as "end_addr"
|
||||
* to the emit_kfunc_call(). Thus, it can learn the "immediate-follow-call"
|
||||
* address by figuring out how many jit-insn is generated between
|
||||
* the call (0xE8) and the end_addr:
|
||||
* - 0-1 jit-insn (3 bytes each) to restore the esp pointer if there
|
||||
* is arg pushed to the stack.
|
||||
* - 0-2 jit-insns (3 bytes each) to handle the return value.
|
||||
*/
|
||||
static int emit_kfunc_call(const struct bpf_prog *bpf_prog, u8 *end_addr,
|
||||
const struct bpf_insn *insn, u8 **pprog)
|
||||
{
|
||||
const u8 arg_regs[] = { IA32_EAX, IA32_EDX, IA32_ECX };
|
||||
int i, cnt = 0, first_stack_regno, last_stack_regno;
|
||||
int free_arg_regs = ARRAY_SIZE(arg_regs);
|
||||
const struct btf_func_model *fm;
|
||||
int bytes_in_stack = 0;
|
||||
const u8 *cur_arg_reg;
|
||||
u8 *prog = *pprog;
|
||||
s64 jmp_offset;
|
||||
|
||||
fm = bpf_jit_find_kfunc_model(bpf_prog, insn);
|
||||
if (!fm)
|
||||
return -EINVAL;
|
||||
|
||||
first_stack_regno = BPF_REG_1;
|
||||
for (i = 0; i < fm->nr_args; i++) {
|
||||
int regs_needed = fm->arg_size[i] > sizeof(u32) ? 2 : 1;
|
||||
|
||||
if (regs_needed > free_arg_regs)
|
||||
break;
|
||||
|
||||
free_arg_regs -= regs_needed;
|
||||
first_stack_regno++;
|
||||
}
|
||||
|
||||
/* Push the args to the stack */
|
||||
last_stack_regno = BPF_REG_0 + fm->nr_args;
|
||||
for (i = last_stack_regno; i >= first_stack_regno; i--) {
|
||||
if (fm->arg_size[i - 1] > sizeof(u32)) {
|
||||
emit_push_r64(bpf2ia32[i], &prog);
|
||||
bytes_in_stack += 8;
|
||||
} else {
|
||||
emit_push_r32(bpf2ia32[i], &prog);
|
||||
bytes_in_stack += 4;
|
||||
}
|
||||
}
|
||||
|
||||
cur_arg_reg = &arg_regs[0];
|
||||
for (i = BPF_REG_1; i < first_stack_regno; i++) {
|
||||
/* mov e[adc]x,dword ptr [ebp+off] */
|
||||
EMIT3(0x8B, add_2reg(0x40, IA32_EBP, *cur_arg_reg++),
|
||||
STACK_VAR(bpf2ia32[i][0]));
|
||||
if (fm->arg_size[i - 1] > sizeof(u32))
|
||||
/* mov e[adc]x,dword ptr [ebp+off] */
|
||||
EMIT3(0x8B, add_2reg(0x40, IA32_EBP, *cur_arg_reg++),
|
||||
STACK_VAR(bpf2ia32[i][1]));
|
||||
}
|
||||
|
||||
if (bytes_in_stack)
|
||||
/* add esp,"bytes_in_stack" */
|
||||
end_addr -= 3;
|
||||
|
||||
/* mov dword ptr [ebp+off],edx */
|
||||
if (fm->ret_size > sizeof(u32))
|
||||
end_addr -= 3;
|
||||
|
||||
/* mov dword ptr [ebp+off],eax */
|
||||
if (fm->ret_size)
|
||||
end_addr -= 3;
|
||||
|
||||
jmp_offset = (u8 *)__bpf_call_base + insn->imm - end_addr;
|
||||
if (!is_simm32(jmp_offset)) {
|
||||
pr_err("unsupported BPF kernel function jmp_offset:%lld\n",
|
||||
jmp_offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
EMIT1_off32(0xE8, jmp_offset);
|
||||
|
||||
if (fm->ret_size)
|
||||
/* mov dword ptr [ebp+off],eax */
|
||||
EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EAX),
|
||||
STACK_VAR(bpf2ia32[BPF_REG_0][0]));
|
||||
|
||||
if (fm->ret_size > sizeof(u32))
|
||||
/* mov dword ptr [ebp+off],edx */
|
||||
EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EDX),
|
||||
STACK_VAR(bpf2ia32[BPF_REG_0][1]));
|
||||
|
||||
if (bytes_in_stack)
|
||||
/* add esp,"bytes_in_stack" */
|
||||
EMIT3(0x83, add_1reg(0xC0, IA32_ESP), bytes_in_stack);
|
||||
|
||||
*pprog = prog;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||
int oldproglen, struct jit_context *ctx)
|
||||
{
|
||||
@ -1888,6 +2069,18 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||
if (insn->src_reg == BPF_PSEUDO_CALL)
|
||||
goto notyet;
|
||||
|
||||
if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
|
||||
int err;
|
||||
|
||||
err = emit_kfunc_call(bpf_prog,
|
||||
image + addrs[i],
|
||||
insn, &prog);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
func = (u8 *) __bpf_call_base + imm32;
|
||||
jmp_offset = func - (image + addrs[i]);
|
||||
|
||||
@ -2402,3 +2595,8 @@ out:
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
}
|
||||
|
||||
bool bpf_jit_supports_kfunc_call(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/atmdev.h>
|
||||
#include <linux/sonet.h>
|
||||
#include <linux/atm_suni.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
|
@ -1783,12 +1783,6 @@ set_tct(struct idt77252_dev *card, struct vc_map *vc)
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static __inline__ int
|
||||
idt77252_fbq_level(struct idt77252_dev *card, int queue)
|
||||
{
|
||||
return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) & 0x0f;
|
||||
}
|
||||
|
||||
static __inline__ int
|
||||
idt77252_fbq_full(struct idt77252_dev *card, int queue)
|
||||
{
|
||||
|
@ -680,7 +680,7 @@ static void ia_tx_poll (IADEV *iadev) {
|
||||
skb1 = skb_dequeue(&iavcc->txing_skb);
|
||||
}
|
||||
if (!skb1) {
|
||||
IF_EVENT(printk("IA: Vci %d - skb not found requed\n",vcc->vci);)
|
||||
IF_EVENT(printk("IA: Vci %d - skb not found requeued\n",vcc->vci);)
|
||||
ia_enque_head_rtn_q (&iadev->tx_return_q, rtne);
|
||||
break;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/timer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/atm_suni.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/param.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
@ -52,13 +52,6 @@ static inline u32 mips_read32(struct bcma_drv_mips *mcore,
|
||||
return bcma_read32(mcore->core, offset);
|
||||
}
|
||||
|
||||
static inline void mips_write32(struct bcma_drv_mips *mcore,
|
||||
u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
bcma_write32(mcore->core, offset, value);
|
||||
}
|
||||
|
||||
static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
|
||||
{
|
||||
u32 flag;
|
||||
|
@ -425,4 +425,14 @@ config BT_HCIRSI
|
||||
Say Y here to compile support for HCI over Redpine into the
|
||||
kernel or say M to compile as a module.
|
||||
|
||||
config BT_VIRTIO
|
||||
tristate "Virtio Bluetooth driver"
|
||||
depends on VIRTIO
|
||||
help
|
||||
Virtio Bluetooth support driver.
|
||||
This driver supports Virtio Bluetooth devices.
|
||||
|
||||
Say Y here to compile support for HCI over Virtio into the
|
||||
kernel or say M to compile as a module.
|
||||
|
||||
endmenu
|
||||
|
@ -26,6 +26,8 @@ obj-$(CONFIG_BT_BCM) += btbcm.o
|
||||
obj-$(CONFIG_BT_RTL) += btrtl.o
|
||||
obj-$(CONFIG_BT_QCA) += btqca.o
|
||||
|
||||
obj-$(CONFIG_BT_VIRTIO) += virtio_bt.o
|
||||
|
||||
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
|
||||
|
||||
obj-$(CONFIG_BT_HCIRSI) += btrsi.o
|
||||
|
@ -24,6 +24,14 @@
|
||||
#define ECDSA_OFFSET 644
|
||||
#define ECDSA_HEADER_LEN 320
|
||||
|
||||
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
|
||||
struct cmd_write_boot_params {
|
||||
u32 boot_addr;
|
||||
u8 fw_build_num;
|
||||
u8 fw_build_ww;
|
||||
u8 fw_build_yy;
|
||||
} __packed;
|
||||
|
||||
int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_rp_read_bd_addr *bda;
|
||||
@ -208,10 +216,39 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_hw_error);
|
||||
|
||||
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
|
||||
int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
|
||||
{
|
||||
const char *variant;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (ver->hw_platform != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
|
||||
ver->hw_platform);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
case 0x11: /* JfP */
|
||||
case 0x12: /* ThP */
|
||||
case 0x13: /* HrP */
|
||||
case 0x14: /* CcP */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||
ver->hw_variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (ver->fw_variant) {
|
||||
case 0x06:
|
||||
variant = "Bootloader";
|
||||
@ -220,13 +257,16 @@ void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
|
||||
variant = "Firmware";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
bt_dev_err(hdev, "Unsupported firmware variant(%02x)", ver->fw_variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u",
|
||||
variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
|
||||
ver->fw_build_num, ver->fw_build_ww,
|
||||
2000 + ver->fw_build_yy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_version_info);
|
||||
|
||||
@ -364,13 +404,56 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_read_version);
|
||||
|
||||
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
|
||||
int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
|
||||
{
|
||||
const char *variant;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (INTEL_HW_PLATFORM(version->cnvi_bt) != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
|
||||
INTEL_HW_PLATFORM(version->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (INTEL_HW_VARIANT(version->cnvi_bt)) {
|
||||
case 0x17: /* TyP */
|
||||
case 0x18: /* Slr */
|
||||
case 0x19: /* Slr-F */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
|
||||
INTEL_HW_VARIANT(version->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (version->img_type) {
|
||||
case 0x01:
|
||||
variant = "Bootloader";
|
||||
/* It is required that every single firmware fragment is acknowledged
|
||||
* with a command complete event. If the boot parameters indicate
|
||||
* that this bootloader does not send them, then abort the setup.
|
||||
*/
|
||||
if (version->limited_cce != 0x00) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
|
||||
version->limited_cce);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
|
||||
if (version->sbe_type > 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
|
||||
version->sbe_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id);
|
||||
bt_dev_info(hdev, "Secure boot is %s",
|
||||
version->secure_boot ? "enabled" : "disabled");
|
||||
@ -389,15 +472,14 @@ void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *ve
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type);
|
||||
goto done;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
|
||||
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
|
||||
version->build_type, version->build_num);
|
||||
|
||||
done:
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_version_info_tlv);
|
||||
|
||||
@ -455,12 +537,23 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
version->img_type = tlv->val[0];
|
||||
break;
|
||||
case INTEL_TLV_TIME_STAMP:
|
||||
/* If image type is Operational firmware (0x03), then
|
||||
* running FW Calendar Week and Year information can
|
||||
* be extracted from Timestamp information
|
||||
*/
|
||||
version->min_fw_build_cw = tlv->val[0];
|
||||
version->min_fw_build_yy = tlv->val[1];
|
||||
version->timestamp = get_unaligned_le16(tlv->val);
|
||||
break;
|
||||
case INTEL_TLV_BUILD_TYPE:
|
||||
version->build_type = tlv->val[0];
|
||||
break;
|
||||
case INTEL_TLV_BUILD_NUM:
|
||||
/* If image type is Operational firmware (0x03), then
|
||||
* running FW build number can be extracted from the
|
||||
* Build information
|
||||
*/
|
||||
version->min_fw_build_nn = tlv->val[0];
|
||||
version->build_num = get_unaligned_le32(tlv->val);
|
||||
break;
|
||||
case INTEL_TLV_SECURE_BOOT:
|
||||
@ -841,7 +934,7 @@ static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
|
||||
|
||||
static int btintel_download_firmware_payload(struct hci_dev *hdev,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_param, size_t offset)
|
||||
size_t offset)
|
||||
{
|
||||
int err;
|
||||
const u8 *fw_ptr;
|
||||
@ -854,20 +947,6 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (le16_to_cpu(cmd->opcode) == 0xfc0e) {
|
||||
/* The boot parameter is the first 32-bit value
|
||||
* and rest of 3 octets are reserved.
|
||||
*/
|
||||
*boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param);
|
||||
}
|
||||
|
||||
frag_len += sizeof(*cmd) + cmd->plen;
|
||||
|
||||
/* The parameter length of the secure send command requires
|
||||
@ -896,28 +975,131 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool btintel_firmware_version(struct hci_dev *hdev,
|
||||
u8 num, u8 ww, u8 yy,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_addr)
|
||||
{
|
||||
const u8 *fw_ptr;
|
||||
|
||||
fw_ptr = fw->data;
|
||||
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (le16_to_cpu(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) {
|
||||
struct cmd_write_boot_params *params;
|
||||
|
||||
params = (void *)(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_info(hdev, "Boot Address: 0x%x",
|
||||
le32_to_cpu(params->boot_addr));
|
||||
|
||||
bt_dev_info(hdev, "Firmware Version: %u-%u.%u",
|
||||
params->fw_build_num, params->fw_build_ww,
|
||||
params->fw_build_yy);
|
||||
|
||||
return (num == params->fw_build_num &&
|
||||
ww == params->fw_build_ww &&
|
||||
yy == params->fw_build_yy);
|
||||
}
|
||||
|
||||
fw_ptr += sizeof(*cmd) + cmd->plen;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int btintel_download_firmware(struct hci_dev *hdev,
|
||||
struct intel_version *ver,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_param)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* SfP and WsP don't seem to update the firmware version on file
|
||||
* so version checking is currently not possible.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
/* Skip version checking */
|
||||
break;
|
||||
default:
|
||||
/* Skip reading firmware file version in bootloader mode */
|
||||
if (ver->fw_variant == 0x06)
|
||||
break;
|
||||
|
||||
/* Skip download if firmware has the same version */
|
||||
if (btintel_firmware_version(hdev, ver->fw_build_num,
|
||||
ver->fw_build_ww, ver->fw_build_yy,
|
||||
fw, boot_param)) {
|
||||
bt_dev_info(hdev, "Firmware already loaded");
|
||||
/* Return -EALREADY to indicate that the firmware has
|
||||
* already been loaded.
|
||||
*/
|
||||
return -EALREADY;
|
||||
}
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x06 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
* firmware.
|
||||
*
|
||||
* If the firmware version has changed that means it needs to be reset
|
||||
* to bootloader when operational so the new firmware can be loaded.
|
||||
*/
|
||||
if (ver->fw_variant == 0x23)
|
||||
return -EINVAL;
|
||||
|
||||
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return btintel_download_firmware_payload(hdev, fw, boot_param,
|
||||
RSA_HEADER_LEN);
|
||||
return btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_download_firmware);
|
||||
|
||||
int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver,
|
||||
const struct firmware *fw, u32 *boot_param,
|
||||
u8 hw_variant, u8 sbe_type)
|
||||
{
|
||||
int err;
|
||||
u32 css_header_ver;
|
||||
|
||||
/* Skip reading firmware file version in bootloader mode */
|
||||
if (ver->img_type != 0x01) {
|
||||
/* Skip download if firmware has the same version */
|
||||
if (btintel_firmware_version(hdev, ver->min_fw_build_nn,
|
||||
ver->min_fw_build_cw,
|
||||
ver->min_fw_build_yy,
|
||||
fw, boot_param)) {
|
||||
bt_dev_info(hdev, "Firmware already loaded");
|
||||
/* Return -EALREADY to indicate that firmware has
|
||||
* already been loaded.
|
||||
*/
|
||||
return -EALREADY;
|
||||
}
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x01 identifies
|
||||
* the bootloader and the value 0x03 identifies the operational
|
||||
* firmware.
|
||||
*
|
||||
* If the firmware version has changed that means it needs to be reset
|
||||
* to bootloader when operational so the new firmware can be loaded.
|
||||
*/
|
||||
if (ver->img_type == 0x03)
|
||||
return -EINVAL;
|
||||
|
||||
/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
|
||||
* only RSA secure boot engine. Hence, the corresponding sfi file will
|
||||
* have RSA header of 644 bytes followed by Command Buffer.
|
||||
@ -947,7 +1129,7 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
|
||||
err = btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (hw_variant >= 0x17) {
|
||||
@ -968,7 +1150,6 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
return err;
|
||||
|
||||
err = btintel_download_firmware_payload(hdev, fw,
|
||||
boot_param,
|
||||
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
|
||||
if (err)
|
||||
return err;
|
||||
@ -978,7 +1159,6 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
return err;
|
||||
|
||||
err = btintel_download_firmware_payload(hdev, fw,
|
||||
boot_param,
|
||||
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -148,8 +148,8 @@ int btintel_set_diag(struct hci_dev *hdev, bool enable);
|
||||
int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
|
||||
void btintel_hw_error(struct hci_dev *hdev, u8 code);
|
||||
|
||||
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
|
||||
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version);
|
||||
int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
|
||||
int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version);
|
||||
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
|
||||
const void *param);
|
||||
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
|
||||
@ -163,9 +163,10 @@ struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
|
||||
int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param);
|
||||
int btintel_read_boot_params(struct hci_dev *hdev,
|
||||
struct intel_boot_params *params);
|
||||
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
|
||||
u32 *boot_param);
|
||||
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
|
||||
const struct firmware *fw, u32 *boot_param);
|
||||
int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_param, u8 hw_variant,
|
||||
u8 sbe_type);
|
||||
@ -210,14 +211,16 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void btintel_version_info(struct hci_dev *hdev,
|
||||
struct intel_version *ver)
|
||||
static inline int btintel_version_info(struct hci_dev *hdev,
|
||||
struct intel_version *ver)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void btintel_version_info_tlv(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *version)
|
||||
static inline int btintel_version_info_tlv(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *version)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
|
||||
|
@ -399,7 +399,9 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
|
||||
/* MediaTek Bluetooth devices */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01),
|
||||
.driver_info = BTUSB_MEDIATEK },
|
||||
.driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional MediaTek MT7615E Bluetooth devices */
|
||||
{ USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},
|
||||
@ -455,6 +457,8 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xc123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Silicon Wave based devices */
|
||||
{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
|
||||
@ -2400,7 +2404,7 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
static int btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
struct intel_boot_params *params,
|
||||
char *fw_name, size_t len,
|
||||
const char *suffix)
|
||||
@ -2424,9 +2428,10 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
suffix);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv *ver_tlv,
|
||||
@ -2444,6 +2449,44 @@ static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv
|
||||
suffix);
|
||||
}
|
||||
|
||||
static int btusb_download_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(msec));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver,
|
||||
u32 *boot_param)
|
||||
@ -2452,19 +2495,11 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
char fwname[64];
|
||||
int err;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t calltime;
|
||||
|
||||
if (!ver || !boot_param)
|
||||
return -EINVAL;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (INTEL_HW_PLATFORM(ver->cnvi_bt) != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
|
||||
INTEL_HW_PLATFORM(ver->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x03 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
@ -2481,50 +2516,6 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
if (ver->img_type == 0x03) {
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
btintel_check_bdaddr(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (INTEL_HW_VARIANT(ver->cnvi_bt)) {
|
||||
case 0x17: /* TyP */
|
||||
case 0x18: /* Slr */
|
||||
case 0x19: /* Slr-F */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
|
||||
INTEL_HW_VARIANT(ver->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the device is not in bootloader mode, then the only possible
|
||||
* choice is to return an error and abort the device initialization.
|
||||
*/
|
||||
if (ver->img_type != 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware variant (0x%x)",
|
||||
ver->img_type);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* It is required that every single firmware fragment is acknowledged
|
||||
* with a command complete event. If the boot parameters indicate
|
||||
* that this bootloader does not send them, then abort the setup.
|
||||
*/
|
||||
if (ver->limited_cce != 0x00) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
|
||||
ver->limited_cce);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
|
||||
if (ver->sbe_type > 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
|
||||
ver->sbe_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the OTP has no valid Bluetooth device address, then there will
|
||||
@ -2538,7 +2529,8 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
btusb_setup_intel_newgen_get_fw_name(ver, fwname, sizeof(fwname), "sfi");
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err);
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
|
||||
fwname, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2551,22 +2543,28 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
||||
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware_newgen(hdev, fw, boot_param,
|
||||
err = btintel_download_firmware_newgen(hdev, ver, fw, boot_param,
|
||||
INTEL_HW_VARIANT(ver->cnvi_bt),
|
||||
ver->sbe_type);
|
||||
if (err < 0) {
|
||||
if (err == -EALREADY) {
|
||||
/* Firmware has already been loaded */
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
err = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* When FW download fails, send Intel Reset to retry
|
||||
* FW download.
|
||||
*/
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
/* Before switching the device into operational mode and with that
|
||||
* booting the loaded firmware, wait for the bootloader notification
|
||||
@ -2579,26 +2577,9 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
* and thus just timeout if that happens and fail the setup
|
||||
* of this device.
|
||||
*/
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(5000));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
err = -ETIMEDOUT;
|
||||
err = btusb_download_wait(hdev, calltime, 5000);
|
||||
if (err == -ETIMEDOUT)
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
err = -ENOEXEC;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
@ -2614,41 +2595,11 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
char fwname[64];
|
||||
int err;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t calltime;
|
||||
|
||||
if (!ver || !params)
|
||||
return -EINVAL;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (ver->hw_platform != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
|
||||
ver->hw_platform);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
case 0x11: /* JfP */
|
||||
case 0x12: /* ThP */
|
||||
case 0x13: /* HrP */
|
||||
case 0x14: /* CcP */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||
ver->hw_variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btintel_version_info(hdev, ver);
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x06 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
@ -2665,16 +2616,18 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
if (ver->fw_variant == 0x23) {
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
btintel_check_bdaddr(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the device is not in bootloader mode, then the only possible
|
||||
* choice is to return an error and abort the device initialization.
|
||||
*/
|
||||
if (ver->fw_variant != 0x06) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
|
||||
ver->fw_variant);
|
||||
return -ENODEV;
|
||||
/* SfP and WsP don't seem to update the firmware version on file
|
||||
* so version checking is currently possible.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Proceed to download to check if the version matches */
|
||||
goto download;
|
||||
}
|
||||
|
||||
/* Read the secure boot parameters to identify the operating
|
||||
@ -2702,6 +2655,7 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
|
||||
}
|
||||
|
||||
download:
|
||||
/* With this Intel bootloader only the hardware variant and device
|
||||
* revision information are used to select the right firmware for SfP
|
||||
* and WsP.
|
||||
@ -2725,14 +2679,15 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
*/
|
||||
err = btusb_setup_intel_new_get_fw_name(ver, params, fwname,
|
||||
sizeof(fwname), "sfi");
|
||||
if (!err) {
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware naming");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err);
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
|
||||
fwname, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2745,20 +2700,26 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
||||
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware(hdev, fw, boot_param);
|
||||
err = btintel_download_firmware(hdev, ver, fw, boot_param);
|
||||
if (err < 0) {
|
||||
if (err == -EALREADY) {
|
||||
/* Firmware has already been loaded */
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
err = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* When FW download fails, send Intel Reset to retry
|
||||
* FW download.
|
||||
*/
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
/* Before switching the device into operational mode and with that
|
||||
* booting the loaded firmware, wait for the bootloader notification
|
||||
@ -2771,84 +2732,57 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
* and thus just timeout if that happens and fail the setup
|
||||
* of this device.
|
||||
*/
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(5000));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
err = -ETIMEDOUT;
|
||||
err = btusb_download_wait(hdev, calltime, 5000);
|
||||
if (err == -ETIMEDOUT)
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
err = -ENOEXEC;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
static int btusb_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct intel_version ver;
|
||||
struct intel_boot_params params;
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
ktime_t calltime, delta, rettime;
|
||||
ktime_t delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
/* Set the default boot parameter to 0x0 and it is updated to
|
||||
* SKU specific boot parameter after reading Intel_Write_Boot_Params
|
||||
* command while downloading the firmware.
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
*/
|
||||
err = btintel_read_version(hdev, &ver);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(msec));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* controller is already having an operational firmware */
|
||||
if (ver.fw_variant == 0x23)
|
||||
goto finish;
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_intel_boot(struct hci_dev *hdev, u32 boot_addr)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t calltime;
|
||||
int err;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_BOOTING, &data->flags);
|
||||
|
||||
err = btintel_send_intel_reset(hdev, boot_param);
|
||||
err = btintel_send_intel_reset(hdev, boot_addr);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
@ -2862,35 +2796,64 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
* 1 second. However if that happens, then just fail the setup
|
||||
* since something went wrong.
|
||||
*/
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
err = btusb_boot_wait(hdev, calltime, 1000);
|
||||
if (err == -ETIMEDOUT)
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct intel_version ver;
|
||||
struct intel_boot_params params;
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
/* Set the default boot parameter to 0x0 and it is updated to
|
||||
* SKU specific boot parameter after reading Intel_Write_Boot_Params
|
||||
* command while downloading the firmware.
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
*/
|
||||
err = btintel_read_version(hdev, &ver);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
|
||||
err = btintel_version_info(hdev, &ver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* controller is already having an operational firmware */
|
||||
if (ver.fw_variant == 0x23)
|
||||
goto finish;
|
||||
|
||||
err = btusb_intel_boot(hdev, boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
|
||||
err = btusb_setup_intel_new_get_fw_name(&ver, ¶ms, ddcname,
|
||||
sizeof(ddcname), "ddc");
|
||||
|
||||
if (!err) {
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware naming");
|
||||
} else {
|
||||
/* Once the device is running in operational mode, it needs to
|
||||
@ -2947,8 +2910,6 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
ktime_t calltime, delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
struct intel_version_tlv version;
|
||||
@ -2961,8 +2922,6 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
@ -2974,7 +2933,9 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
btintel_version_info_tlv(hdev, &version);
|
||||
err = btintel_version_info_tlv(hdev, &version);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = btusb_intel_download_firmware_newgen(hdev, &version, &boot_param);
|
||||
if (err)
|
||||
@ -2984,52 +2945,9 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
if (version.img_type == 0x03)
|
||||
goto finish;
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_BOOTING, &data->flags);
|
||||
|
||||
err = btintel_send_intel_reset(hdev, boot_param);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
err = btusb_intel_boot(hdev, boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The bootloader will not indicate when the device is ready. This
|
||||
* is done by the operational firmware sending bootup notification.
|
||||
*
|
||||
* Booting into operational firmware should not take longer than
|
||||
* 1 second. However if that happens, then just fail the setup
|
||||
* since something went wrong.
|
||||
*/
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
|
||||
@ -3495,7 +3413,7 @@ static int btusb_mtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwnam
|
||||
fw_ptr = fw->data;
|
||||
fw_bin_ptr = fw_ptr;
|
||||
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
|
||||
section_num = globaldesc->section_num;
|
||||
section_num = le32_to_cpu(globaldesc->section_num);
|
||||
|
||||
for (i = 0; i < section_num; i++) {
|
||||
first_block = 1;
|
||||
@ -3503,8 +3421,8 @@ static int btusb_mtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwnam
|
||||
sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
|
||||
MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
|
||||
|
||||
section_offset = sectionmap->secoffset;
|
||||
dl_size = sectionmap->bin_info_spec.dlsize;
|
||||
section_offset = le32_to_cpu(sectionmap->secoffset);
|
||||
dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
|
||||
|
||||
if (dl_size > 0) {
|
||||
retry = 20;
|
||||
@ -3740,7 +3658,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
||||
int err, status;
|
||||
u32 dev_id;
|
||||
char fw_bin_name[64];
|
||||
u32 fw_version;
|
||||
u32 fw_version = 0;
|
||||
u8 param;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
@ -68,6 +68,8 @@ struct bcm_device_data {
|
||||
* deassert = Bluetooth device may sleep when sleep criteria are met
|
||||
* @shutdown: BT_REG_ON pin,
|
||||
* power up or power down Bluetooth device internal regulators
|
||||
* @reset: BT_RST_N pin,
|
||||
* active low resets the Bluetooth logic core
|
||||
* @set_device_wakeup: callback to toggle BT_WAKE pin
|
||||
* either by accessing @device_wakeup or by calling @btlp
|
||||
* @set_shutdown: callback to toggle BT_REG_ON pin
|
||||
@ -101,6 +103,7 @@ struct bcm_device {
|
||||
const char *name;
|
||||
struct gpio_desc *device_wakeup;
|
||||
struct gpio_desc *shutdown;
|
||||
struct gpio_desc *reset;
|
||||
int (*set_device_wakeup)(struct bcm_device *, bool);
|
||||
int (*set_shutdown)(struct bcm_device *, bool);
|
||||
#ifdef CONFIG_ACPI
|
||||
@ -985,6 +988,15 @@ static int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake)
|
||||
static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered)
|
||||
{
|
||||
gpiod_set_value_cansleep(dev->shutdown, powered);
|
||||
if (dev->reset)
|
||||
/*
|
||||
* The reset line is asserted on powerdown and deasserted
|
||||
* on poweron so the inverse of powered is used. Notice
|
||||
* that the GPIO line BT_RST_N needs to be specified as
|
||||
* active low in the device tree or similar system
|
||||
* description.
|
||||
*/
|
||||
gpiod_set_value_cansleep(dev->reset, !powered);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1050,6 +1062,11 @@ static int bcm_get_resources(struct bcm_device *dev)
|
||||
if (IS_ERR(dev->shutdown))
|
||||
return PTR_ERR(dev->shutdown);
|
||||
|
||||
dev->reset = devm_gpiod_get_optional(dev->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(dev->reset))
|
||||
return PTR_ERR(dev->reset);
|
||||
|
||||
dev->set_device_wakeup = bcm_gpio_set_device_wakeup;
|
||||
dev->set_shutdown = bcm_gpio_set_shutdown;
|
||||
|
||||
@ -1482,6 +1499,8 @@ static struct bcm_device_data bcm43438_device_data = {
|
||||
static const struct of_device_id bcm_bluetooth_of_match[] = {
|
||||
{ .compatible = "brcm,bcm20702a1" },
|
||||
{ .compatible = "brcm,bcm4329-bt" },
|
||||
{ .compatible = "brcm,bcm4330-bt" },
|
||||
{ .compatible = "brcm,bcm4334-bt" },
|
||||
{ .compatible = "brcm,bcm4345c5" },
|
||||
{ .compatible = "brcm,bcm4330-bt" },
|
||||
{ .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data },
|
||||
|
@ -735,7 +735,7 @@ static int intel_setup(struct hci_uart *hu)
|
||||
set_bit(STATE_DOWNLOADING, &intel->flags);
|
||||
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware(hdev, fw, &boot_param);
|
||||
err = btintel_download_firmware(hdev, &ver, fw, &boot_param);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
@ -784,7 +784,10 @@ static int intel_setup(struct hci_uart *hu)
|
||||
done:
|
||||
release_firmware(fw);
|
||||
|
||||
if (err < 0)
|
||||
/* Check if there was an error and if is not -EALREADY which means the
|
||||
* firmware has already been loaded.
|
||||
*/
|
||||
if (err < 0 && err != -EALREADY)
|
||||
return err;
|
||||
|
||||
/* We need to restore the default speed before Intel reset */
|
||||
|
@ -1066,7 +1066,7 @@ static void qca_controller_memdump(struct work_struct *work)
|
||||
* packets in the buffer.
|
||||
*/
|
||||
/* For QCA6390, controller does not lost packets but
|
||||
* sequence number field of packat sometimes has error
|
||||
* sequence number field of packet sometimes has error
|
||||
* bits, so skip this checking for missing packet.
|
||||
*/
|
||||
while ((seq_no > qca_memdump->current_seq_no + 1) &&
|
||||
@ -1571,6 +1571,20 @@ static void qca_cmd_timeout(struct hci_dev *hdev)
|
||||
mutex_unlock(&qca->hci_memdump_lock);
|
||||
}
|
||||
|
||||
static bool qca_prevent_wake(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
bool wakeup;
|
||||
|
||||
/* UART driver handles the interrupt from BT SoC.So we need to use
|
||||
* device handle of UART driver to get the status of device may wakeup.
|
||||
*/
|
||||
wakeup = device_may_wakeup(hu->serdev->ctrl->dev.parent);
|
||||
bt_dev_dbg(hu->hdev, "wakeup status : %d", wakeup);
|
||||
|
||||
return !wakeup;
|
||||
}
|
||||
|
||||
static int qca_wcn3990_init(struct hci_uart *hu)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
@ -1721,6 +1735,7 @@ retry:
|
||||
qca_debugfs_init(hdev);
|
||||
hu->hdev->hw_error = qca_hw_error;
|
||||
hu->hdev->cmd_timeout = qca_cmd_timeout;
|
||||
hu->hdev->prevent_wake = qca_prevent_wake;
|
||||
} else if (ret == -ENOENT) {
|
||||
/* No patch/nvm-config found, run with original fw/config */
|
||||
set_bit(QCA_ROM_FW, &qca->flags);
|
||||
|
401
drivers/bluetooth/virtio_bt.c
Normal file
401
drivers/bluetooth/virtio_bt.c
Normal file
@ -0,0 +1,401 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <uapi/linux/virtio_ids.h>
|
||||
#include <uapi/linux/virtio_bt.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
enum {
|
||||
VIRTBT_VQ_TX,
|
||||
VIRTBT_VQ_RX,
|
||||
VIRTBT_NUM_VQS,
|
||||
};
|
||||
|
||||
struct virtio_bluetooth {
|
||||
struct virtio_device *vdev;
|
||||
struct virtqueue *vqs[VIRTBT_NUM_VQS];
|
||||
struct work_struct rx;
|
||||
struct hci_dev *hdev;
|
||||
};
|
||||
|
||||
static int virtbt_add_inbuf(struct virtio_bluetooth *vbt)
|
||||
{
|
||||
struct virtqueue *vq = vbt->vqs[VIRTBT_VQ_RX];
|
||||
struct scatterlist sg[1];
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
skb = alloc_skb(1000, GFP_KERNEL);
|
||||
sg_init_one(sg, skb->data, 1000);
|
||||
|
||||
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct virtio_bluetooth *vbt = hci_get_drvdata(hdev);
|
||||
|
||||
if (virtbt_add_inbuf(vbt) < 0)
|
||||
return -EIO;
|
||||
|
||||
virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct virtio_bluetooth *vbt = hci_get_drvdata(hdev);
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&vbt->rx);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vbt->vqs); i++) {
|
||||
struct virtqueue *vq = vbt->vqs[i];
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = virtqueue_detach_unused_buf(vq)))
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_flush(struct hci_dev *hdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct virtio_bluetooth *vbt = hci_get_drvdata(hdev);
|
||||
struct scatterlist sg[1];
|
||||
int err;
|
||||
|
||||
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
|
||||
|
||||
sg_init_one(sg, skb->data, skb->len);
|
||||
err = virtqueue_add_outbuf(vbt->vqs[VIRTBT_VQ_TX], sg, 1, skb,
|
||||
GFP_KERNEL);
|
||||
if (err) {
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
virtqueue_kick(vbt->vqs[VIRTBT_VQ_TX]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_setup_zephyr(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Read Build Information */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc08, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
|
||||
|
||||
hci_set_fw_info(hdev, "%s", skb->data + 1);
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_set_bdaddr_zephyr(struct hci_dev *hdev,
|
||||
const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Write BD_ADDR */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc06, 6, bdaddr, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_setup_intel(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Intel Read Version */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Intel Write BD Address */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_setup_realtek(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Read ROM Version */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
bt_dev_info(hdev, "ROM version %u", *((__u8 *) (skb->data + 1)));
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtbt_shutdown_generic(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Reset */
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
|
||||
{
|
||||
__u8 pkt_type;
|
||||
|
||||
pkt_type = *((__u8 *) skb->data);
|
||||
skb_pull(skb, 1);
|
||||
|
||||
switch (pkt_type) {
|
||||
case HCI_EVENT_PKT:
|
||||
case HCI_ACLDATA_PKT:
|
||||
case HCI_SCODATA_PKT:
|
||||
case HCI_ISODATA_PKT:
|
||||
hci_skb_pkt_type(skb) = pkt_type;
|
||||
hci_recv_frame(vbt->hdev, skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void virtbt_rx_work(struct work_struct *work)
|
||||
{
|
||||
struct virtio_bluetooth *vbt = container_of(work,
|
||||
struct virtio_bluetooth, rx);
|
||||
struct sk_buff *skb;
|
||||
unsigned int len;
|
||||
|
||||
skb = virtqueue_get_buf(vbt->vqs[VIRTBT_VQ_RX], &len);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
skb->len = len;
|
||||
virtbt_rx_handle(vbt, skb);
|
||||
|
||||
if (virtbt_add_inbuf(vbt) < 0)
|
||||
return;
|
||||
|
||||
virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]);
|
||||
}
|
||||
|
||||
static void virtbt_tx_done(struct virtqueue *vq)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned int len;
|
||||
|
||||
while ((skb = virtqueue_get_buf(vq, &len)))
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void virtbt_rx_done(struct virtqueue *vq)
|
||||
{
|
||||
struct virtio_bluetooth *vbt = vq->vdev->priv;
|
||||
|
||||
schedule_work(&vbt->rx);
|
||||
}
|
||||
|
||||
static int virtbt_probe(struct virtio_device *vdev)
|
||||
{
|
||||
vq_callback_t *callbacks[VIRTBT_NUM_VQS] = {
|
||||
[VIRTBT_VQ_TX] = virtbt_tx_done,
|
||||
[VIRTBT_VQ_RX] = virtbt_rx_done,
|
||||
};
|
||||
const char *names[VIRTBT_NUM_VQS] = {
|
||||
[VIRTBT_VQ_TX] = "tx",
|
||||
[VIRTBT_VQ_RX] = "rx",
|
||||
};
|
||||
struct virtio_bluetooth *vbt;
|
||||
struct hci_dev *hdev;
|
||||
int err;
|
||||
__u8 type;
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
|
||||
return -ENODEV;
|
||||
|
||||
type = virtio_cread8(vdev, offsetof(struct virtio_bt_config, type));
|
||||
|
||||
switch (type) {
|
||||
case VIRTIO_BT_CONFIG_TYPE_PRIMARY:
|
||||
case VIRTIO_BT_CONFIG_TYPE_AMP:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vbt = kzalloc(sizeof(*vbt), GFP_KERNEL);
|
||||
if (!vbt)
|
||||
return -ENOMEM;
|
||||
|
||||
vdev->priv = vbt;
|
||||
vbt->vdev = vdev;
|
||||
|
||||
INIT_WORK(&vbt->rx, virtbt_rx_work);
|
||||
|
||||
err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, callbacks,
|
||||
names, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
err = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
vbt->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_VIRTIO;
|
||||
hdev->dev_type = type;
|
||||
hci_set_drvdata(hdev, vbt);
|
||||
|
||||
hdev->open = virtbt_open;
|
||||
hdev->close = virtbt_close;
|
||||
hdev->flush = virtbt_flush;
|
||||
hdev->send = virtbt_send_frame;
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) {
|
||||
__u16 vendor;
|
||||
|
||||
virtio_cread(vdev, struct virtio_bt_config, vendor, &vendor);
|
||||
|
||||
switch (vendor) {
|
||||
case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR:
|
||||
hdev->manufacturer = 1521;
|
||||
hdev->setup = virtbt_setup_zephyr;
|
||||
hdev->shutdown = virtbt_shutdown_generic;
|
||||
hdev->set_bdaddr = virtbt_set_bdaddr_zephyr;
|
||||
break;
|
||||
|
||||
case VIRTIO_BT_CONFIG_VENDOR_INTEL:
|
||||
hdev->manufacturer = 2;
|
||||
hdev->setup = virtbt_setup_intel;
|
||||
hdev->shutdown = virtbt_shutdown_generic;
|
||||
hdev->set_bdaddr = virtbt_set_bdaddr_intel;
|
||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
break;
|
||||
|
||||
case VIRTIO_BT_CONFIG_VENDOR_REALTEK:
|
||||
hdev->manufacturer = 93;
|
||||
hdev->setup = virtbt_setup_realtek;
|
||||
hdev->shutdown = virtbt_shutdown_generic;
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) {
|
||||
__u16 msft_opcode;
|
||||
|
||||
virtio_cread(vdev, struct virtio_bt_config,
|
||||
msft_opcode, &msft_opcode);
|
||||
|
||||
hci_set_msft_opcode(hdev, msft_opcode);
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_BT_F_AOSP_EXT))
|
||||
hci_set_aosp_capable(hdev);
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
hci_free_dev(hdev);
|
||||
err = -EBUSY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
vdev->config->del_vqs(vdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void virtbt_remove(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_bluetooth *vbt = vdev->priv;
|
||||
struct hci_dev *hdev = vbt->hdev;
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
vdev->config->reset(vdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
vbt->hdev = NULL;
|
||||
|
||||
vdev->config->del_vqs(vdev);
|
||||
kfree(vbt);
|
||||
}
|
||||
|
||||
static struct virtio_device_id virtbt_table[] = {
|
||||
{ VIRTIO_ID_BT, VIRTIO_DEV_ANY_ID },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(virtio, virtbt_table);
|
||||
|
||||
static const unsigned int virtbt_features[] = {
|
||||
VIRTIO_BT_F_VND_HCI,
|
||||
VIRTIO_BT_F_MSFT_EXT,
|
||||
VIRTIO_BT_F_AOSP_EXT,
|
||||
};
|
||||
|
||||
static struct virtio_driver virtbt_driver = {
|
||||
.driver.name = KBUILD_MODNAME,
|
||||
.driver.owner = THIS_MODULE,
|
||||
.feature_table = virtbt_features,
|
||||
.feature_table_size = ARRAY_SIZE(virtbt_features),
|
||||
.id_table = virtbt_table,
|
||||
.probe = virtbt_probe,
|
||||
.remove = virtbt_remove,
|
||||
};
|
||||
|
||||
module_virtio_driver(virtbt_driver);
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Generic Bluetooth VIRTIO driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
@ -879,7 +879,7 @@ static void mlx5_ib_set_rule_source_port(struct mlx5_ib_dev *dev,
|
||||
misc_parameters_2);
|
||||
|
||||
MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
|
||||
mlx5_eswitch_get_vport_metadata_for_match(esw,
|
||||
mlx5_eswitch_get_vport_metadata_for_match(rep->esw,
|
||||
rep->vport));
|
||||
misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
|
||||
misc_parameters_2);
|
||||
|
@ -20,7 +20,7 @@ mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
||||
rep->rep_data[REP_IB].priv = ibdev;
|
||||
write_lock(&ibdev->port[vport_index].roce.netdev_lock);
|
||||
ibdev->port[vport_index].roce.netdev =
|
||||
mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport);
|
||||
mlx5_ib_get_rep_netdev(rep->esw, rep->vport);
|
||||
write_unlock(&ibdev->port[vport_index].roce.netdev_lock);
|
||||
|
||||
return 0;
|
||||
@ -123,8 +123,7 @@ struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
|
||||
|
||||
rep = dev->port[port - 1].rep;
|
||||
|
||||
return mlx5_eswitch_add_send_to_vport_rule(esw, rep->vport,
|
||||
sq->base.mqp.qpn);
|
||||
return mlx5_eswitch_add_send_to_vport_rule(esw, rep, sq->base.mqp.qpn);
|
||||
}
|
||||
|
||||
static int mlx5r_rep_probe(struct auxiliary_device *adev,
|
||||
|
@ -126,7 +126,6 @@ static struct mlx5_roce *mlx5_get_rep_roce(struct mlx5_ib_dev *dev,
|
||||
struct net_device *ndev,
|
||||
u8 *port_num)
|
||||
{
|
||||
struct mlx5_eswitch *esw = dev->mdev->priv.eswitch;
|
||||
struct net_device *rep_ndev;
|
||||
struct mlx5_ib_port *port;
|
||||
int i;
|
||||
@ -137,7 +136,7 @@ static struct mlx5_roce *mlx5_get_rep_roce(struct mlx5_ib_dev *dev,
|
||||
continue;
|
||||
|
||||
read_lock(&port->roce.netdev_lock);
|
||||
rep_ndev = mlx5_ib_get_rep_netdev(esw,
|
||||
rep_ndev = mlx5_ib_get_rep_netdev(port->rep->esw,
|
||||
port->rep->vport);
|
||||
if (rep_ndev == ndev) {
|
||||
read_unlock(&port->roce.netdev_lock);
|
||||
|
@ -173,13 +173,13 @@
|
||||
#define MAX_FRAGS (32 * MAX_CARDS)
|
||||
|
||||
static LIST_HEAD(HFClist);
|
||||
static spinlock_t HFClock; /* global hfc list lock */
|
||||
static DEFINE_SPINLOCK(HFClock); /* global hfc list lock */
|
||||
|
||||
static void ph_state_change(struct dchannel *);
|
||||
|
||||
static struct hfc_multi *syncmaster;
|
||||
static int plxsd_master; /* if we have a master card (yet) */
|
||||
static spinlock_t plx_lock; /* may not acquire other lock inside */
|
||||
static DEFINE_SPINLOCK(plx_lock); /* may not acquire other lock inside */
|
||||
|
||||
#define TYP_E1 1
|
||||
#define TYP_4S 4
|
||||
@ -2748,8 +2748,6 @@ hfcmulti_interrupt(int intno, void *dev_id)
|
||||
if (hc->ctype != HFC_TYPE_E1)
|
||||
ph_state_irq(hc, r_irq_statech);
|
||||
}
|
||||
if (status & V_EXT_IRQSTA)
|
||||
; /* external IRQ */
|
||||
if (status & V_LOST_STA) {
|
||||
/* LOST IRQ */
|
||||
HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */
|
||||
@ -5482,9 +5480,6 @@ HFCmulti_init(void)
|
||||
printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
|
||||
#endif
|
||||
|
||||
spin_lock_init(&HFClock);
|
||||
spin_lock_init(&plx_lock);
|
||||
|
||||
if (debug & DEBUG_HFCMULTI_INIT)
|
||||
printk(KERN_DEBUG "%s: init entered\n", __func__);
|
||||
|
||||
|
@ -13,14 +13,14 @@
|
||||
#ifndef _IOHELPER_H
|
||||
#define _IOHELPER_H
|
||||
|
||||
typedef u8 (read_reg_func)(void *hwp, u8 offset);
|
||||
typedef void (write_reg_func)(void *hwp, u8 offset, u8 value);
|
||||
typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size);
|
||||
typedef u8 (read_reg_func)(void *hwp, u8 offset);
|
||||
typedef void (write_reg_func)(void *hwp, u8 offset, u8 value);
|
||||
typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size);
|
||||
|
||||
struct _ioport {
|
||||
u32 port;
|
||||
u32 ale;
|
||||
};
|
||||
struct _ioport {
|
||||
u32 port;
|
||||
u32 ale;
|
||||
};
|
||||
|
||||
#define IOFUNC_IO(name, hws, ap) \
|
||||
static u8 Read##name##_IO(void *p, u8 off) { \
|
||||
|
@ -176,9 +176,9 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
/*int spinnest = 0;*/
|
||||
|
||||
spinlock_t dsp_lock; /* global dsp lock */
|
||||
struct list_head dsp_ilist;
|
||||
struct list_head conf_ilist;
|
||||
DEFINE_SPINLOCK(dsp_lock); /* global dsp lock */
|
||||
LIST_HEAD(dsp_ilist);
|
||||
LIST_HEAD(conf_ilist);
|
||||
int dsp_debug;
|
||||
int dsp_options;
|
||||
int dsp_poll, dsp_tics;
|
||||
@ -953,7 +953,6 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
|
||||
{
|
||||
struct dsp *dsp = container_of(ch, struct dsp, ch);
|
||||
u_long flags;
|
||||
int err = 0;
|
||||
|
||||
if (debug & DEBUG_DSP_CTRL)
|
||||
printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
|
||||
@ -998,7 +997,7 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
|
||||
module_put(THIS_MODULE);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1170,10 +1169,6 @@ static int __init dsp_init(void)
|
||||
printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals "
|
||||
"%d jiffies.\n", dsp_poll, dsp_tics);
|
||||
|
||||
spin_lock_init(&dsp_lock);
|
||||
INIT_LIST_HEAD(&dsp_ilist);
|
||||
INIT_LIST_HEAD(&conf_ilist);
|
||||
|
||||
/* init conversion tables */
|
||||
dsp_audio_generate_law_tables();
|
||||
dsp_silence = (dsp_options & DSP_OPT_ULAW) ? 0xff : 0x2a;
|
||||
|
@ -200,7 +200,7 @@
|
||||
|
||||
The complete socket opening and closing is done by a thread.
|
||||
When the thread opened a socket, the hc->socket descriptor is set. Whenever a
|
||||
packet shall be sent to the socket, the hc->socket must be checked wheter not
|
||||
packet shall be sent to the socket, the hc->socket must be checked whether not
|
||||
NULL. To prevent change in socket descriptor, the hc->socket_lock must be used.
|
||||
To change the socket, a recall of l1oip_socket_open() will safely kill the
|
||||
socket process and create a new one.
|
||||
@ -229,8 +229,8 @@
|
||||
static const char *l1oip_revision = "2.00";
|
||||
|
||||
static int l1oip_cnt;
|
||||
static spinlock_t l1oip_lock;
|
||||
static struct list_head l1oip_ilist;
|
||||
static DEFINE_SPINLOCK(l1oip_lock);
|
||||
static LIST_HEAD(l1oip_ilist);
|
||||
|
||||
#define MAX_CARDS 16
|
||||
static u_int type[MAX_CARDS];
|
||||
@ -1440,9 +1440,6 @@ l1oip_init(void)
|
||||
printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n",
|
||||
l1oip_revision);
|
||||
|
||||
INIT_LIST_HEAD(&l1oip_ilist);
|
||||
spin_lock_init(&l1oip_lock);
|
||||
|
||||
if (l1oip_4bit_alloc(ulaw))
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -502,6 +502,8 @@ source "drivers/net/wan/Kconfig"
|
||||
|
||||
source "drivers/net/ieee802154/Kconfig"
|
||||
|
||||
source "drivers/net/wwan/Kconfig"
|
||||
|
||||
config XEN_NETDEV_FRONTEND
|
||||
tristate "Xen network device frontend driver"
|
||||
depends on XEN
|
||||
@ -579,6 +581,7 @@ config NETDEVSIM
|
||||
depends on DEBUG_FS
|
||||
depends on INET
|
||||
depends on IPV6 || IPV6=n
|
||||
depends on PSAMPLE || PSAMPLE=n
|
||||
select NET_DEVLINK
|
||||
help
|
||||
This driver is a developer testing tool and software model that can
|
||||
|
@ -45,7 +45,7 @@ obj-$(CONFIG_ARCNET) += arcnet/
|
||||
obj-$(CONFIG_DEV_APPLETALK) += appletalk/
|
||||
obj-$(CONFIG_CAIF) += caif/
|
||||
obj-$(CONFIG_CAN) += can/
|
||||
obj-y += dsa/
|
||||
obj-$(CONFIG_NET_DSA) += dsa/
|
||||
obj-$(CONFIG_ETHERNET) += ethernet/
|
||||
obj-$(CONFIG_FDDI) += fddi/
|
||||
obj-$(CONFIG_HIPPI) += hippi/
|
||||
@ -68,6 +68,7 @@ obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o
|
||||
obj-$(CONFIG_WAN) += wan/
|
||||
obj-$(CONFIG_WLAN) += wireless/
|
||||
obj-$(CONFIG_IEEE802154) += ieee802154/
|
||||
obj-$(CONFIG_WWAN) += wwan/
|
||||
|
||||
obj-$(CONFIG_VMXNET3) += vmxnet3/
|
||||
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
|
||||
|
@ -59,9 +59,6 @@ static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)
|
||||
* look for EISA/PCI cards in addition to ISA cards).
|
||||
*/
|
||||
static struct devprobe2 isa_probes[] __initdata = {
|
||||
#if defined(CONFIG_HP100) && defined(CONFIG_ISA) /* ISA, EISA */
|
||||
{hp100_probe, 0},
|
||||
#endif
|
||||
#ifdef CONFIG_3C515
|
||||
{tc515_probe, 0},
|
||||
#endif
|
||||
|
@ -218,6 +218,7 @@ static struct socket *bareudp_create_sock(struct net *net, __be16 port)
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
udp_allow_gso(sock->sk);
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
@ -1098,7 +1098,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
|
||||
* If @slave's permanent hw address is different both from its current
|
||||
* address and from @bond's address, then somewhere in the bond there's
|
||||
* a slave that has @slave's permanet address as its current address.
|
||||
* We'll make sure that that slave no longer uses @slave's permanent address.
|
||||
* We'll make sure that slave no longer uses @slave's permanent address.
|
||||
*
|
||||
* Caller must hold RTNL and no other locks
|
||||
*/
|
||||
|
@ -964,7 +964,7 @@ static bool bond_should_notify_peers(struct bonding *bond)
|
||||
}
|
||||
|
||||
/**
|
||||
* change_active_interface - change the active slave into the specified one
|
||||
* bond_change_active_slave - change the active slave into the specified one
|
||||
* @bond: our bonding struct
|
||||
* @new_active: the new slave to make the active one
|
||||
*
|
||||
@ -4391,9 +4391,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
|
||||
int agg_id = 0;
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
WARN_ON(lockdep_is_held(&bond->mode_lock));
|
||||
#endif
|
||||
might_sleep();
|
||||
|
||||
usable_slaves = kzalloc(struct_size(usable_slaves, arr,
|
||||
bond->slave_cnt), GFP_KERNEL);
|
||||
@ -4406,7 +4404,9 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
|
||||
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
|
||||
struct ad_info ad_info;
|
||||
|
||||
spin_lock_bh(&bond->mode_lock);
|
||||
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
|
||||
spin_unlock_bh(&bond->mode_lock);
|
||||
pr_debug("bond_3ad_get_active_agg_info failed\n");
|
||||
/* No active aggragator means it's not safe to use
|
||||
* the previous array.
|
||||
@ -4414,6 +4414,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
|
||||
bond_reset_slave_arr(bond);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock_bh(&bond->mode_lock);
|
||||
agg_id = ad_info.aggregator_id;
|
||||
}
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
|
@ -640,6 +640,15 @@ static void bond_opt_error_interpret(struct bonding *bond,
|
||||
netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n",
|
||||
opt->name);
|
||||
break;
|
||||
case -ENODEV:
|
||||
if (val && val->string) {
|
||||
p = strchr(val->string, '\n');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
netdev_err(bond->dev, "option %s: interface %s does not exist!\n",
|
||||
opt->name, val->string);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ config CAN_FLEXCAN
|
||||
|
||||
config CAN_GRCAN
|
||||
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
|
||||
depends on OF && HAS_DMA
|
||||
depends on OF && HAS_DMA && HAS_IOMEM
|
||||
help
|
||||
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
|
||||
Note that the driver supports little endian, even though little
|
||||
|
@ -132,7 +132,6 @@
|
||||
/* For the high buffers we clear the interrupt bit and newdat */
|
||||
#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_CLR_NEWDAT)
|
||||
|
||||
|
||||
/* Receive setup of message objects */
|
||||
#define IF_COMM_RCV_SETUP (IF_COMM_MASK | IF_COMM_ARB | IF_COMM_CONTROL)
|
||||
|
||||
@ -161,9 +160,7 @@
|
||||
|
||||
#define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB)
|
||||
|
||||
/*
|
||||
* Use IF1 for RX and IF2 for TX
|
||||
*/
|
||||
/* Use IF1 for RX and IF2 for TX */
|
||||
#define IF_RX 0
|
||||
#define IF_TX 1
|
||||
|
||||
@ -173,9 +170,6 @@
|
||||
/* Wait for ~1 sec for INIT bit */
|
||||
#define INIT_WAIT_MS 1000
|
||||
|
||||
/* napi related */
|
||||
#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
|
||||
|
||||
/* c_can lec values */
|
||||
enum c_can_lec_type {
|
||||
LEC_NO_ERROR = 0,
|
||||
@ -189,8 +183,7 @@ enum c_can_lec_type {
|
||||
LEC_MASK = LEC_UNUSED,
|
||||
};
|
||||
|
||||
/*
|
||||
* c_can error types:
|
||||
/* c_can error types:
|
||||
* Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
|
||||
*/
|
||||
enum c_can_bus_error_types {
|
||||
@ -253,7 +246,6 @@ static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj
|
||||
udelay(1);
|
||||
}
|
||||
netdev_err(dev, "Updating object timed out\n");
|
||||
|
||||
}
|
||||
|
||||
static inline void c_can_object_get(struct net_device *dev, int iface,
|
||||
@ -268,8 +260,7 @@ static inline void c_can_object_put(struct net_device *dev, int iface,
|
||||
c_can_obj_update(dev, iface, cmd | IF_COMM_WR, obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: According to documentation clearing TXIE while MSGVAL is set
|
||||
/* Note: According to documentation clearing TXIE while MSGVAL is set
|
||||
* is not allowed, but works nicely on C/DCAN. And that lowers the I/O
|
||||
* load significantly.
|
||||
*/
|
||||
@ -285,8 +276,7 @@ static void c_can_inval_msg_object(struct net_device *dev, int iface, int obj)
|
||||
{
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
|
||||
priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
|
||||
priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
|
||||
priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
|
||||
c_can_inval_tx_object(dev, iface, obj);
|
||||
}
|
||||
|
||||
@ -309,12 +299,11 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
|
||||
if (!rtr)
|
||||
arb |= IF_ARB_TRANSMIT;
|
||||
|
||||
/*
|
||||
* If we change the DIR bit, we need to invalidate the buffer
|
||||
/* If we change the DIR bit, we need to invalidate the buffer
|
||||
* first, i.e. clear the MSGVAL flag in the arbiter.
|
||||
*/
|
||||
if (rtr != (bool)test_bit(idx, &priv->tx_dir)) {
|
||||
u32 obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
|
||||
u32 obj = idx + priv->msg_obj_tx_first;
|
||||
|
||||
c_can_inval_msg_object(dev, iface, obj);
|
||||
change_bit(idx, &priv->tx_dir);
|
||||
@ -447,18 +436,16 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
|
||||
|
||||
if (can_dropped_invalid_skb(dev, skb))
|
||||
return NETDEV_TX_OK;
|
||||
/*
|
||||
* This is not a FIFO. C/D_CAN sends out the buffers
|
||||
/* This is not a FIFO. C/D_CAN sends out the buffers
|
||||
* prioritized. The lowest buffer number wins.
|
||||
*/
|
||||
idx = fls(atomic_read(&priv->tx_active));
|
||||
obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
|
||||
obj = idx + priv->msg_obj_tx_first;
|
||||
|
||||
/* If this is the last buffer, stop the xmit queue */
|
||||
if (idx == C_CAN_MSG_OBJ_TX_NUM - 1)
|
||||
if (idx == priv->msg_obj_tx_num - 1)
|
||||
netif_stop_queue(dev);
|
||||
/*
|
||||
* Store the message in the interface so we can call
|
||||
/* Store the message in the interface so we can call
|
||||
* can_put_echo_skb(). We must do this before we enable
|
||||
* transmit as we might race against do_tx().
|
||||
*/
|
||||
@ -467,7 +454,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
|
||||
can_put_echo_skb(skb, dev, idx, 0);
|
||||
|
||||
/* Update the active bits */
|
||||
atomic_add((1 << idx), &priv->tx_active);
|
||||
atomic_add(BIT(idx), &priv->tx_active);
|
||||
/* Start transmission */
|
||||
c_can_object_put(dev, IF_TX, obj, IF_COMM_TX);
|
||||
|
||||
@ -511,7 +498,7 @@ static int c_can_set_bittiming(struct net_device *dev)
|
||||
reg_brpe = brpe & BRP_EXT_BRPE_MASK;
|
||||
|
||||
netdev_info(dev,
|
||||
"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
|
||||
"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
|
||||
|
||||
ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
|
||||
ctrl_save &= ~CONTROL_INIT;
|
||||
@ -527,8 +514,7 @@ static int c_can_set_bittiming(struct net_device *dev)
|
||||
return c_can_wait_for_ctrl_init(dev, priv, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure C_CAN message objects for Tx and Rx purposes:
|
||||
/* Configure C_CAN message objects for Tx and Rx purposes:
|
||||
* C_CAN provides a total of 32 message objects that can be configured
|
||||
* either for Tx or Rx purposes. Here the first 16 message objects are used as
|
||||
* a reception FIFO. The end of reception FIFO is signified by the EoB bit
|
||||
@ -538,17 +524,18 @@ static int c_can_set_bittiming(struct net_device *dev)
|
||||
*/
|
||||
static void c_can_configure_msg_objects(struct net_device *dev)
|
||||
{
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
int i;
|
||||
|
||||
/* first invalidate all message objects */
|
||||
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
|
||||
for (i = priv->msg_obj_rx_first; i <= priv->msg_obj_num; i++)
|
||||
c_can_inval_msg_object(dev, IF_RX, i);
|
||||
|
||||
/* setup receive message objects */
|
||||
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
|
||||
for (i = priv->msg_obj_rx_first; i < priv->msg_obj_rx_last; i++)
|
||||
c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV);
|
||||
|
||||
c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
|
||||
c_can_setup_receive_object(dev, IF_RX, priv->msg_obj_rx_last, 0, 0,
|
||||
IF_MCONT_RCV_EOB);
|
||||
}
|
||||
|
||||
@ -572,8 +559,7 @@ static int c_can_software_reset(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure C_CAN chip:
|
||||
/* Configure C_CAN chip:
|
||||
* - enable/disable auto-retransmission
|
||||
* - set operating mode
|
||||
* - configure message objects
|
||||
@ -714,12 +700,21 @@ static void c_can_do_tx(struct net_device *dev)
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
u32 idx, obj, pkts = 0, bytes = 0, pend, clr;
|
||||
|
||||
clr = pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
|
||||
if (priv->msg_obj_tx_last > 32)
|
||||
pend = priv->read_reg32(priv, C_CAN_INTPND3_REG);
|
||||
else
|
||||
pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
|
||||
clr = pend;
|
||||
|
||||
while ((idx = ffs(pend))) {
|
||||
idx--;
|
||||
pend &= ~(1 << idx);
|
||||
obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
|
||||
pend &= ~BIT(idx);
|
||||
obj = idx + priv->msg_obj_tx_first;
|
||||
|
||||
/* We use IF_RX interface instead of IF_TX because we
|
||||
* are called from c_can_poll(), which runs inside
|
||||
* NAPI. We are not trasmitting.
|
||||
*/
|
||||
c_can_inval_tx_object(dev, IF_RX, obj);
|
||||
can_get_echo_skb(dev, idx, NULL);
|
||||
bytes += priv->dlc[idx];
|
||||
@ -729,7 +724,7 @@ static void c_can_do_tx(struct net_device *dev)
|
||||
/* Clear the bits in the tx_active mask */
|
||||
atomic_sub(clr, &priv->tx_active);
|
||||
|
||||
if (clr & (1 << (C_CAN_MSG_OBJ_TX_NUM - 1)))
|
||||
if (clr & BIT(priv->msg_obj_tx_num - 1))
|
||||
netif_wake_queue(dev);
|
||||
|
||||
if (pkts) {
|
||||
@ -739,20 +734,18 @@ static void c_can_do_tx(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a gap in the pending bits, that means we either
|
||||
/* If we have a gap in the pending bits, that means we either
|
||||
* raced with the hardware or failed to readout all upper
|
||||
* objects in the last run due to quota limit.
|
||||
*/
|
||||
static u32 c_can_adjust_pending(u32 pend)
|
||||
static u32 c_can_adjust_pending(u32 pend, u32 rx_mask)
|
||||
{
|
||||
u32 weight, lasts;
|
||||
|
||||
if (pend == RECEIVE_OBJECT_BITS)
|
||||
if (pend == rx_mask)
|
||||
return pend;
|
||||
|
||||
/*
|
||||
* If the last set bit is larger than the number of pending
|
||||
/* If the last set bit is larger than the number of pending
|
||||
* bits we have a gap.
|
||||
*/
|
||||
weight = hweight32(pend);
|
||||
@ -762,19 +755,19 @@ static u32 c_can_adjust_pending(u32 pend)
|
||||
if (lasts == weight)
|
||||
return pend;
|
||||
|
||||
/*
|
||||
* Find the first set bit after the gap. We walk backwards
|
||||
/* Find the first set bit after the gap. We walk backwards
|
||||
* from the last set bit.
|
||||
*/
|
||||
for (lasts--; pend & (1 << (lasts - 1)); lasts--);
|
||||
for (lasts--; pend & BIT(lasts - 1); lasts--)
|
||||
;
|
||||
|
||||
return pend & ~((1 << lasts) - 1);
|
||||
return pend & ~GENMASK(lasts - 1, 0);
|
||||
}
|
||||
|
||||
static inline void c_can_rx_object_get(struct net_device *dev,
|
||||
struct c_can_priv *priv, u32 obj)
|
||||
{
|
||||
c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high);
|
||||
c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high);
|
||||
}
|
||||
|
||||
static inline void c_can_rx_finalize(struct net_device *dev,
|
||||
@ -803,8 +796,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This really should not happen, but this covers some
|
||||
/* This really should not happen, but this covers some
|
||||
* odd HW behaviour. Do not remove that unless you
|
||||
* want to brick your machine.
|
||||
*/
|
||||
@ -825,19 +817,22 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
|
||||
|
||||
static inline u32 c_can_get_pending(struct c_can_priv *priv)
|
||||
{
|
||||
u32 pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
|
||||
u32 pend;
|
||||
|
||||
if (priv->msg_obj_rx_last > 16)
|
||||
pend = priv->read_reg32(priv, C_CAN_NEWDAT1_REG);
|
||||
else
|
||||
pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
|
||||
|
||||
return pend;
|
||||
}
|
||||
|
||||
/*
|
||||
* theory of operation:
|
||||
/* theory of operation:
|
||||
*
|
||||
* c_can core saves a received CAN message into the first free message
|
||||
* object it finds free (starting with the lowest). Bits NEWDAT and
|
||||
* INTPND are set for this message object indicating that a new message
|
||||
* has arrived. To work-around this issue, we keep two groups of message
|
||||
* objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT.
|
||||
* has arrived.
|
||||
*
|
||||
* We clear the newdat bit right away.
|
||||
*
|
||||
@ -848,23 +843,16 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
u32 pkts = 0, pend = 0, toread, n;
|
||||
|
||||
/*
|
||||
* It is faster to read only one 16bit register. This is only possible
|
||||
* for a maximum number of 16 objects.
|
||||
*/
|
||||
BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
|
||||
"Implementation does not support more message objects than 16");
|
||||
|
||||
while (quota > 0) {
|
||||
if (!pend) {
|
||||
pend = c_can_get_pending(priv);
|
||||
if (!pend)
|
||||
break;
|
||||
/*
|
||||
* If the pending field has a gap, handle the
|
||||
/* If the pending field has a gap, handle the
|
||||
* bits above the gap first.
|
||||
*/
|
||||
toread = c_can_adjust_pending(pend);
|
||||
toread = c_can_adjust_pending(pend,
|
||||
priv->msg_obj_rx_mask);
|
||||
} else {
|
||||
toread = pend;
|
||||
}
|
||||
@ -883,7 +871,7 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
||||
}
|
||||
|
||||
static int c_can_handle_state_change(struct net_device *dev,
|
||||
enum c_can_bus_error_types error_type)
|
||||
enum c_can_bus_error_types error_type)
|
||||
{
|
||||
unsigned int reg_err_counter;
|
||||
unsigned int rx_err_passive;
|
||||
@ -979,8 +967,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
|
||||
struct can_frame *cf;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/*
|
||||
* early exit if no lec update or no error.
|
||||
/* early exit if no lec update or no error.
|
||||
* no lec update means that no CAN bus event has been detected
|
||||
* since CPU wrote 0x7 value to status reg.
|
||||
*/
|
||||
@ -999,8 +986,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
|
||||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* check for 'last error code' which tells us the
|
||||
/* check for 'last error code' which tells us the
|
||||
* type of the last error to occur on the CAN bus
|
||||
*/
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
@ -1049,7 +1035,8 @@ static int c_can_poll(struct napi_struct *napi, int quota)
|
||||
|
||||
/* Only read the status register if a status interrupt was pending */
|
||||
if (atomic_xchg(&priv->sie_pending, 0)) {
|
||||
priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
|
||||
priv->last_status = priv->read_reg(priv, C_CAN_STS_REG);
|
||||
curr = priv->last_status;
|
||||
/* Ack status on C_CAN. D_CAN is self clearing */
|
||||
if (priv->type != BOSCH_D_CAN)
|
||||
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
|
||||
@ -1147,7 +1134,7 @@ static int c_can_open(struct net_device *dev)
|
||||
|
||||
/* register interrupt handler */
|
||||
err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
|
||||
dev);
|
||||
dev);
|
||||
if (err < 0) {
|
||||
netdev_err(dev, "failed to request interrupt\n");
|
||||
goto exit_irq_fail;
|
||||
@ -1195,17 +1182,31 @@ static int c_can_close(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct net_device *alloc_c_can_dev(void)
|
||||
struct net_device *alloc_c_can_dev(int msg_obj_num)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct c_can_priv *priv;
|
||||
int msg_obj_tx_num = msg_obj_num / 2;
|
||||
|
||||
dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
|
||||
dev = alloc_candev(struct_size(priv, dlc, msg_obj_tx_num),
|
||||
msg_obj_tx_num);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
|
||||
priv->msg_obj_num = msg_obj_num;
|
||||
priv->msg_obj_rx_num = msg_obj_num - msg_obj_tx_num;
|
||||
priv->msg_obj_rx_first = 1;
|
||||
priv->msg_obj_rx_last =
|
||||
priv->msg_obj_rx_first + priv->msg_obj_rx_num - 1;
|
||||
priv->msg_obj_rx_mask = GENMASK(priv->msg_obj_rx_num - 1, 0);
|
||||
|
||||
priv->msg_obj_tx_num = msg_obj_tx_num;
|
||||
priv->msg_obj_tx_first = priv->msg_obj_rx_last + 1;
|
||||
priv->msg_obj_tx_last =
|
||||
priv->msg_obj_tx_first + priv->msg_obj_tx_num - 1;
|
||||
|
||||
netif_napi_add(dev, &priv->napi, c_can_poll, priv->msg_obj_rx_num);
|
||||
|
||||
priv->dev = dev;
|
||||
priv->can.bittiming_const = &c_can_bittiming_const;
|
||||
@ -1239,7 +1240,7 @@ int c_can_power_down(struct net_device *dev)
|
||||
/* Wait for the PDA bit to get set */
|
||||
time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
|
||||
while (!(priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
|
||||
time_after(time_out, jiffies))
|
||||
time_after(time_out, jiffies))
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, time_out))
|
||||
@ -1280,7 +1281,7 @@ int c_can_power_up(struct net_device *dev)
|
||||
/* Wait for the PDA bit to get clear */
|
||||
time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
|
||||
while ((priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
|
||||
time_after(time_out, jiffies))
|
||||
time_after(time_out, jiffies))
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, time_out)) {
|
||||
|
@ -22,23 +22,6 @@
|
||||
#ifndef C_CAN_H
|
||||
#define C_CAN_H
|
||||
|
||||
/* message object split */
|
||||
#define C_CAN_NO_OF_OBJECTS 32
|
||||
#define C_CAN_MSG_OBJ_RX_NUM 16
|
||||
#define C_CAN_MSG_OBJ_TX_NUM 16
|
||||
|
||||
#define C_CAN_MSG_OBJ_RX_FIRST 1
|
||||
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
|
||||
C_CAN_MSG_OBJ_RX_NUM - 1)
|
||||
|
||||
#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
|
||||
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
|
||||
C_CAN_MSG_OBJ_TX_NUM - 1)
|
||||
|
||||
#define C_CAN_MSG_OBJ_RX_SPLIT 9
|
||||
#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
|
||||
#define RECEIVE_OBJECT_BITS 0x0000ffff
|
||||
|
||||
enum reg {
|
||||
C_CAN_CTRL_REG = 0,
|
||||
C_CAN_CTRL_EX_REG,
|
||||
@ -76,6 +59,7 @@ enum reg {
|
||||
C_CAN_NEWDAT2_REG,
|
||||
C_CAN_INTPND1_REG,
|
||||
C_CAN_INTPND2_REG,
|
||||
C_CAN_INTPND3_REG,
|
||||
C_CAN_MSGVAL1_REG,
|
||||
C_CAN_MSGVAL2_REG,
|
||||
C_CAN_FUNCTION_REG,
|
||||
@ -137,6 +121,7 @@ static const u16 __maybe_unused reg_map_d_can[] = {
|
||||
[C_CAN_NEWDAT2_REG] = 0x9E,
|
||||
[C_CAN_INTPND1_REG] = 0xB0,
|
||||
[C_CAN_INTPND2_REG] = 0xB2,
|
||||
[C_CAN_INTPND3_REG] = 0xB4,
|
||||
[C_CAN_MSGVAL1_REG] = 0xC4,
|
||||
[C_CAN_MSGVAL2_REG] = 0xC6,
|
||||
[C_CAN_IF1_COMREQ_REG] = 0x100,
|
||||
@ -164,7 +149,6 @@ static const u16 __maybe_unused reg_map_d_can[] = {
|
||||
};
|
||||
|
||||
enum c_can_dev_id {
|
||||
BOSCH_C_CAN_PLATFORM,
|
||||
BOSCH_C_CAN,
|
||||
BOSCH_D_CAN,
|
||||
};
|
||||
@ -176,6 +160,7 @@ struct raminit_bits {
|
||||
|
||||
struct c_can_driver_data {
|
||||
enum c_can_dev_id id;
|
||||
unsigned int msg_obj_num;
|
||||
|
||||
/* RAMINIT register description. Optional. */
|
||||
const struct raminit_bits *raminit_bits; /* Array of START/DONE bit positions */
|
||||
@ -197,26 +182,34 @@ struct c_can_priv {
|
||||
struct napi_struct napi;
|
||||
struct net_device *dev;
|
||||
struct device *device;
|
||||
unsigned int msg_obj_num;
|
||||
unsigned int msg_obj_rx_num;
|
||||
unsigned int msg_obj_tx_num;
|
||||
unsigned int msg_obj_rx_first;
|
||||
unsigned int msg_obj_rx_last;
|
||||
unsigned int msg_obj_tx_first;
|
||||
unsigned int msg_obj_tx_last;
|
||||
u32 msg_obj_rx_mask;
|
||||
atomic_t tx_active;
|
||||
atomic_t sie_pending;
|
||||
unsigned long tx_dir;
|
||||
int last_status;
|
||||
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);
|
||||
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 */
|
||||
enum c_can_dev_id type;
|
||||
struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */
|
||||
void (*raminit) (const struct c_can_priv *priv, bool enable);
|
||||
void (*raminit)(const struct c_can_priv *priv, bool enable);
|
||||
u32 comm_rcv_high;
|
||||
u32 rxmasked;
|
||||
u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
|
||||
u32 dlc[];
|
||||
};
|
||||
|
||||
struct net_device *alloc_c_can_dev(void);
|
||||
struct net_device *alloc_c_can_dev(int msg_obj_num);
|
||||
void free_c_can_dev(struct net_device *dev);
|
||||
int register_c_can_dev(struct net_device *dev);
|
||||
void unregister_c_can_dev(struct net_device *dev);
|
||||
|
@ -31,6 +31,8 @@ enum c_can_pci_reg_align {
|
||||
struct c_can_pci_data {
|
||||
/* Specify if is C_CAN or D_CAN */
|
||||
enum c_can_dev_id type;
|
||||
/* Number of message objects */
|
||||
unsigned int msg_obj_num;
|
||||
/* Set the register alignment in the memory */
|
||||
enum c_can_pci_reg_align reg_align;
|
||||
/* Set the frequency */
|
||||
@ -41,32 +43,31 @@ struct c_can_pci_data {
|
||||
void (*init)(const struct c_can_priv *priv, bool enable);
|
||||
};
|
||||
|
||||
/*
|
||||
* 16-bit c_can registers can be arranged differently in the memory
|
||||
/* 16-bit c_can registers can be arranged differently in the memory
|
||||
* architecture of different implementations. For example: 16-bit
|
||||
* 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(const struct c_can_priv *priv,
|
||||
enum reg index)
|
||||
enum reg index)
|
||||
{
|
||||
return readw(priv->base + priv->regs[index]);
|
||||
}
|
||||
|
||||
static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
|
||||
enum reg index, u16 val)
|
||||
enum reg index, u16 val)
|
||||
{
|
||||
writew(val, priv->base + priv->regs[index]);
|
||||
}
|
||||
|
||||
static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
|
||||
enum reg index)
|
||||
enum reg index)
|
||||
{
|
||||
return readw(priv->base + 2 * priv->regs[index]);
|
||||
}
|
||||
|
||||
static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
|
||||
enum reg index, u16 val)
|
||||
enum reg index, u16 val)
|
||||
{
|
||||
writew(val, priv->base + 2 * priv->regs[index]);
|
||||
}
|
||||
@ -88,13 +89,13 @@ 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;
|
||||
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)
|
||||
u32 val)
|
||||
{
|
||||
priv->write_reg(priv, index + 1, val >> 16);
|
||||
priv->write_reg(priv, index, val);
|
||||
@ -142,14 +143,13 @@ static int c_can_pci_probe(struct pci_dev *pdev,
|
||||
pci_resource_len(pdev, c_can_pci_data->bar));
|
||||
if (!addr) {
|
||||
dev_err(&pdev->dev,
|
||||
"device has no PCI memory resources, "
|
||||
"failing adapter\n");
|
||||
"device has no PCI memory resources, failing adapter\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_release_regions;
|
||||
}
|
||||
|
||||
/* allocate the c_can device */
|
||||
dev = alloc_c_can_dev();
|
||||
dev = alloc_c_can_dev(c_can_pci_data->msg_obj_num);
|
||||
if (!dev) {
|
||||
ret = -ENOMEM;
|
||||
goto out_iounmap;
|
||||
@ -217,7 +217,7 @@ static int c_can_pci_probe(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
|
||||
KBUILD_MODNAME, priv->regs, dev->irq);
|
||||
KBUILD_MODNAME, priv->regs, dev->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -252,8 +252,9 @@ static void c_can_pci_remove(struct pci_dev *pdev)
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static const struct c_can_pci_data c_can_sta2x11= {
|
||||
static const struct c_can_pci_data c_can_sta2x11 = {
|
||||
.type = BOSCH_C_CAN,
|
||||
.msg_obj_num = 32,
|
||||
.reg_align = C_CAN_REG_ALIGN_32,
|
||||
.freq = 52000000, /* 52 Mhz */
|
||||
.bar = 0,
|
||||
@ -261,6 +262,7 @@ static const struct c_can_pci_data c_can_sta2x11= {
|
||||
|
||||
static const struct c_can_pci_data c_can_pch = {
|
||||
.type = BOSCH_C_CAN,
|
||||
.msg_obj_num = 32,
|
||||
.reg_align = C_CAN_REG_32,
|
||||
.freq = 50000000, /* 50 MHz */
|
||||
.init = c_can_pci_reset_pch,
|
||||
@ -269,7 +271,7 @@ static const struct c_can_pci_data c_can_pch = {
|
||||
|
||||
#define C_CAN_ID(_vend, _dev, _driverdata) { \
|
||||
PCI_DEVICE(_vend, _dev), \
|
||||
.driver_data = (unsigned long)&_driverdata, \
|
||||
.driver_data = (unsigned long)&(_driverdata), \
|
||||
}
|
||||
|
||||
static const struct pci_device_id c_can_pci_tbl[] = {
|
||||
@ -279,6 +281,7 @@ static const struct pci_device_id c_can_pci_tbl[] = {
|
||||
c_can_pch),
|
||||
{},
|
||||
};
|
||||
|
||||
static struct pci_driver c_can_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = c_can_pci_tbl,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user