Pull networking updates from Paolo Abeni: "Core: - Allow live renaming when an interface is up - Add retpoline wrappers for tc, improving considerably the performances of complex queue discipline configurations - Add inet drop monitor support - A few GRO performance improvements - Add infrastructure for atomic dev stats, addressing long standing data races - De-duplicate common code between OVS and conntrack offloading infrastructure - A bunch of UBSAN_BOUNDS/FORTIFY_SOURCE improvements - Netfilter: introduce packet parser for tunneled packets - Replace IPVS timer-based estimators with kthreads to scale up the workload with the number of available CPUs - Add the helper support for connection-tracking OVS offload BPF: - Support for user defined BPF objects: the use case is to allocate own objects, build own object hierarchies and use the building blocks to build own data structures flexibly, for example, linked lists in BPF - Make cgroup local storage available to non-cgroup attached BPF programs - Avoid unnecessary deadlock detection and failures wrt BPF task storage helpers - A relevant bunch of BPF verifier fixes and improvements - Veristat tool improvements to support custom filtering, sorting, and replay of results - Add LLVM disassembler as default library for dumping JITed code - Lots of new BPF documentation for various BPF maps - Add bpf_rcu_read_{,un}lock() support for sleepable programs - Add RCU grace period chaining to BPF to wait for the completion of access from both sleepable and non-sleepable BPF programs - Add support storing struct task_struct objects as kptrs in maps - Improve helper UAPI by explicitly defining BPF_FUNC_xxx integer values - Add libbpf *_opts API-variants for bpf_*_get_fd_by_id() functions Protocols: - TCP: implement Protective Load Balancing across switch links - TCP: allow dynamically disabling TCP-MD5 static key, reverting back to fast[er]-path - UDP: Introduce optional per-netns hash lookup table - IPv6: simplify and cleanup sockets disposal - Netlink: support different type policies for each generic netlink operation - MPTCP: add MSG_FASTOPEN and FastOpen listener side support - MPTCP: add netlink notification support for listener sockets events - SCTP: add VRF support, allowing sctp sockets binding to VRF devices - Add bridging MAC Authentication Bypass (MAB) support - Extensions for Ethernet VPN bridging implementation to better support multicast scenarios - More work for Wi-Fi 7 support, comprising conversion of all the existing drivers to internal TX queue usage - IPSec: introduce a new offload type (packet offload) allowing complete header processing and crypto offloading - IPSec: extended ack support for more descriptive XFRM error reporting - RXRPC: increase SACK table size and move processing into a per-local endpoint kernel thread, reducing considerably the required locking - IEEE 802154: synchronous send frame and extended filtering support, initial support for scanning available 15.4 networks - Tun: bump the link speed from 10Mbps to 10Gbps - Tun/VirtioNet: implement UDP segmentation offload support Driver API: - PHY/SFP: improve power level switching between standard level 1 and the higher power levels - New API for netdev <-> devlink_port linkage - PTP: convert existing drivers to new frequency adjustment implementation - DSA: add support for rx offloading - Autoload DSA tagging driver when dynamically changing protocol - Add new PCP and APPTRUST attributes to Data Center Bridging - Add configuration support for 800Gbps link speed - Add devlink port function attribute to enable/disable RoCE and migratable - Extend devlink-rate to support strict prioriry and weighted fair queuing - Add devlink support to directly reading from region memory - New device tree helper to fetch MAC address from nvmem - New big TCP helper to simplify temporary header stripping New hardware / drivers: - Ethernet: - Marvel Octeon CNF95N and CN10KB Ethernet Switches - Marvel Prestera AC5X Ethernet Switch - WangXun 10 Gigabit NIC - Motorcomm yt8521 Gigabit Ethernet - Microchip ksz9563 Gigabit Ethernet Switch - Microsoft Azure Network Adapter - Linux Automation 10Base-T1L adapter - PHY: - Aquantia AQR112 and AQR412 - Motorcomm YT8531S - PTP: - Orolia ART-CARD - WiFi: - MediaTek Wi-Fi 7 (802.11be) devices - RealTek rtw8821cu, rtw8822bu, rtw8822cu and rtw8723du USB devices - Bluetooth: - Broadcom BCM4377/4378/4387 Bluetooth chipsets - Realtek RTL8852BE and RTL8723DS - Cypress.CYW4373A0 WiFi + Bluetooth combo device Drivers: - CAN: - gs_usb: bus error reporting support - kvaser_usb: listen only and bus error reporting support - Ethernet NICs: - Intel (100G): - extend action skbedit to RX queue mapping - implement devlink-rate support - support direct read from memory - nVidia/Mellanox (mlx5): - SW steering improvements, increasing rules update rate - Support for enhanced events compression - extend H/W offload packet manipulation capabilities - implement IPSec packet offload mode - nVidia/Mellanox (mlx4): - better big TCP support - Netronome Ethernet NICs (nfp): - IPsec offload support - add support for multicast filter - Broadcom: - RSS and PTP support improvements - AMD/SolarFlare: - netlink extened ack improvements - add basic flower matches to offload, and related stats - Virtual NICs: - ibmvnic: introduce affinity hint support - small / embedded: - FreeScale fec: add initial XDP support - Marvel mv643xx_eth: support MII/GMII/RGMII modes for Kirkwood - TI am65-cpsw: add suspend/resume support - Mediatek MT7986: add RX wireless wthernet dispatch support - Realtek 8169: enable GRO software interrupt coalescing per default - Ethernet high-speed switches: - Microchip (sparx5): - add support for Sparx5 TC/flower H/W offload via VCAP - Mellanox mlxsw: - add 802.1X and MAC Authentication Bypass offload support - add ip6gre support - Embedded Ethernet switches: - Mediatek (mtk_eth_soc): - improve PCS implementation, add DSA untag support - enable flow offload support - Renesas: - add rswitch R-Car Gen4 gPTP support - Microchip (lan966x): - add full XDP support - add TC H/W offload via VCAP - enable PTP on bridge interfaces - Microchip (ksz8): - add MTU support for KSZ8 series - Qualcomm 802.11ax WiFi (ath11k): - support configuring channel dwell time during scan - MediaTek WiFi (mt76): - enable Wireless Ethernet Dispatch (WED) offload support - add ack signal support - enable coredump support - remain_on_channel support - Intel WiFi (iwlwifi): - enable Wi-Fi 7 Extremely High Throughput (EHT) PHY capabilities - 320 MHz channels support - RealTek WiFi (rtw89): - new dynamic header firmware format support - wake-over-WLAN support" * tag 'net-next-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2002 commits) ipvs: fix type warning in do_div() on 32 bit net: lan966x: Remove a useless test in lan966x_ptp_add_trap() net: ipa: add IPA v4.7 support dt-bindings: net: qcom,ipa: Add SM6350 compatible bnxt: Use generic HBH removal helper in tx path IPv6/GRO: generic helper to remove temporary HBH/jumbo header in driver selftests: forwarding: Add bridge MDB test selftests: forwarding: Rename bridge_mdb test bridge: mcast: Support replacement of MDB port group entries bridge: mcast: Allow user space to specify MDB entry routing protocol bridge: mcast: Allow user space to add (*, G) with a source list and filter mode bridge: mcast: Add support for (*, G) with a source list and filter mode bridge: mcast: Avoid arming group timer when (S, G) corresponds to a source bridge: mcast: Add a flag for user installed source entries bridge: mcast: Expose __br_multicast_del_group_src() bridge: mcast: Expose br_multicast_new_group_src() bridge: mcast: Add a centralized error path bridge: mcast: Place netlink policy before validation functions bridge: mcast: Split (*, G) and (S, G) addition into different functions bridge: mcast: Do not derive entry type from its filter mode ...
Unified · Split
| @@ -298,3 +298,48 @@ A: NO. · 297 unmodified lines | ||
| 298 | 298 | |
| 299 | 299 | The BTF_ID macro does not cause a function to become part of the ABI |
| 300 | 300 | any more than does the EXPORT_SYMBOL_GPL macro. |
| 301 | + | |
| 302 | +Q: What is the compatibility story for special BPF types in map values? | |
| 303 | +----------------------------------------------------------------------- | |
| 304 | +Q: Users are allowed to embed bpf_spin_lock, bpf_timer fields in their BPF map | |
| 305 | +values (when using BTF support for BPF maps). This allows to use helpers for | |
| 306 | +such objects on these fields inside map values. Users are also allowed to embed | |
| 307 | +pointers to some kernel types (with __kptr and __kptr_ref BTF tags). Will the | |
| 308 | +kernel preserve backwards compatibility for these features? | |
| 309 | + | |
| 310 | +A: It depends. For bpf_spin_lock, bpf_timer: YES, for kptr and everything else: | |
| 311 | +NO, but see below. | |
| 312 | + | |
| 313 | +For struct types that have been added already, like bpf_spin_lock and bpf_timer, | |
| 314 | +the kernel will preserve backwards compatibility, as they are part of UAPI. | |
| 315 | + | |
| 316 | +For kptrs, they are also part of UAPI, but only with respect to the kptr | |
| 317 | +mechanism. The types that you can use with a __kptr and __kptr_ref tagged | |
| 318 | +pointer in your struct are NOT part of the UAPI contract. The supported types can | |
| 319 | +and will change across kernel releases. However, operations like accessing kptr | |
| 320 | +fields and bpf_kptr_xchg() helper will continue to be supported across kernel | |
| 321 | +releases for the supported types. | |
| 322 | + | |
| 323 | +For any other supported struct type, unless explicitly stated in this document | |
| 324 | +and added to bpf.h UAPI header, such types can and will arbitrarily change their | |
| 325 | +size, type, and alignment, or any other user visible API or ABI detail across | |
| 326 | +kernel releases. The users must adapt their BPF programs to the new changes and | |
| 327 | +update them to make sure their programs continue to work correctly. | |
| 328 | + | |
| 329 | +NOTE: BPF subsystem specially reserves the 'bpf\_' prefix for type names, in | |
| 330 | +order to introduce more special fields in the future. Hence, user programs must | |
| 331 | +avoid defining types with 'bpf\_' prefix to not be broken in future releases. | |
| 332 | +In other words, no backwards compatibility is guaranteed if one using a type | |
| 333 | +in BTF with 'bpf\_' prefix. | |
| 334 | + | |
| 335 | +Q: What is the compatibility story for special BPF types in allocated objects? | |
| 336 | +------------------------------------------------------------------------------ | |
| 337 | +Q: Same as above, but for allocated objects (i.e. objects allocated using | |
| 338 | +bpf_obj_new for user defined types). Will the kernel preserve backwards | |
| 339 | +compatibility for these features? | |
| 340 | + | |
| 341 | +A: NO. | |
| 342 | + | |
| 343 | +Unlike map value types, there are no stability guarantees for this case. The | |
| 344 | +whole API to work with allocated objects and any support for special fields | |
| 345 | +inside them is unstable (since it is exposed through kfuncs). | |
| @@ -44,6 +44,33 @@ is a guarantee that the reported issue will be overlooked.** · 43 unmodified lines | ||
| 44 | 44 | Submitting patches |
| 45 | 45 | ================== |
| 46 | 46 | |
| 47 | +Q: How do I run BPF CI on my changes before sending them out for review? | |
| 48 | +------------------------------------------------------------------------ | |
| 49 | +A: BPF CI is GitHub based and hosted at https://github.com/kernel-patches/bpf. | |
| 50 | +While GitHub also provides a CLI that can be used to accomplish the same | |
| 51 | +results, here we focus on the UI based workflow. | |
| 52 | + | |
| 53 | +The following steps lay out how to start a CI run for your patches: | |
| 54 | + | |
| 55 | +- Create a fork of the aforementioned repository in your own account (one time | |
| 56 | + action) | |
| 57 | + | |
| 58 | +- Clone the fork locally, check out a new branch tracking either the bpf-next | |
| 59 | + or bpf branch, and apply your to-be-tested patches on top of it | |
| 60 | + | |
| 61 | +- Push the local branch to your fork and create a pull request against | |
| 62 | + kernel-patches/bpf's bpf-next_base or bpf_base branch, respectively | |
| 63 | + | |
| 64 | +Shortly after the pull request has been created, the CI workflow will run. Note | |
| 65 | +that capacity is shared with patches submitted upstream being checked and so | |
| 66 | +depending on utilization the run can take a while to finish. | |
| 67 | + | |
| 68 | +Note furthermore that both base branches (bpf-next_base and bpf_base) will be | |
| 69 | +updated as patches are pushed to the respective upstream branches they track. As | |
| 70 | +such, your patch set will automatically (be attempted to) be rebased as well. | |
| 71 | +This behavior can result in a CI run being aborted and restarted with the new | |
| 72 | +base line. | |
| 73 | + | |
| 47 | 74 | Q: To which mailing list do I need to submit my BPF patches? |
| 48 | 75 | ------------------------------------------------------------ |
| 49 | 76 | A: Please submit your BPF patches to the bpf kernel mailing list: |
| @@ -0,0 +1,485 @@ | ||
| 1 | +============= | |
| 2 | +BPF Iterators | |
| 3 | +============= | |
| 4 | + | |
| 5 | + | |
| 6 | +---------- | |
| 7 | +Motivation | |
| 8 | +---------- | |
| 9 | + | |
| 10 | +There are a few existing ways to dump kernel data into user space. The most | |
| 11 | +popular one is the ``/proc`` system. For example, ``cat /proc/net/tcp6`` dumps | |
| 12 | +all tcp6 sockets in the system, and ``cat /proc/net/netlink`` dumps all netlink | |
| 13 | +sockets in the system. However, their output format tends to be fixed, and if | |
| 14 | +users want more information about these sockets, they have to patch the kernel, | |
| 15 | +which often takes time to publish upstream and release. The same is true for popular | |
| 16 | +tools like `ss <https://man7.org/linux/man-pages/man8/ss.8.html>`_ where any | |
| 17 | +additional information needs a kernel patch. | |
| 18 | + | |
| 19 | +To solve this problem, the `drgn | |
| 20 | +<https://www.kernel.org/doc/html/latest/bpf/drgn.html>`_ tool is often used to | |
| 21 | +dig out the kernel data with no kernel change. However, the main drawback for | |
| 22 | +drgn is performance, as it cannot do pointer tracing inside the kernel. In | |
| 23 | +addition, drgn cannot validate a pointer value and may read invalid data if the | |
| 24 | +pointer becomes invalid inside the kernel. | |
| 25 | + | |
| 26 | +The BPF iterator solves the above problem by providing flexibility on what data | |
| 27 | +(e.g., tasks, bpf_maps, etc.) to collect by calling BPF programs for each kernel | |
| 28 | +data object. | |
| 29 | + | |
| 30 | +---------------------- | |
| 31 | +How BPF Iterators Work | |
| 32 | +---------------------- | |
| 33 | + | |
| 34 | +A BPF iterator is a type of BPF program that allows users to iterate over | |
| 35 | +specific types of kernel objects. Unlike traditional BPF tracing programs that | |
| 36 | +allow users to define callbacks that are invoked at particular points of | |
| 37 | +execution in the kernel, BPF iterators allow users to define callbacks that | |
| 38 | +should be executed for every entry in a variety of kernel data structures. | |
| 39 | + | |
| 40 | +For example, users can define a BPF iterator that iterates over every task on | |
| 41 | +the system and dumps the total amount of CPU runtime currently used by each of | |
| 42 | +them. Another BPF task iterator may instead dump the cgroup information for each | |
| 43 | +task. Such flexibility is the core value of BPF iterators. | |
| 44 | + | |
| 45 | +A BPF program is always loaded into the kernel at the behest of a user space | |
| 46 | +process. A user space process loads a BPF program by opening and initializing | |
| 47 | +the program skeleton as required and then invoking a syscall to have the BPF | |
| 48 | +program verified and loaded by the kernel. | |
| 49 | + | |
| 50 | +In traditional tracing programs, a program is activated by having user space | |
| 51 | +obtain a ``bpf_link`` to the program with ``bpf_program__attach()``. Once | |
| 52 | +activated, the program callback will be invoked whenever the tracepoint is | |
| 53 | +triggered in the main kernel. For BPF iterator programs, a ``bpf_link`` to the | |
| 54 | +program is obtained using ``bpf_link_create()``, and the program callback is | |
| 55 | +invoked by issuing system calls from user space. | |
| 56 | + | |
| 57 | +Next, let us see how you can use the iterators to iterate on kernel objects and | |
| 58 | +read data. | |
| 59 | + | |
| 60 | +------------------------ | |
| 61 | +How to Use BPF iterators | |
| 62 | +------------------------ | |
| 63 | + | |
| 64 | +BPF selftests are a great resource to illustrate how to use the iterators. In | |
| 65 | +this section, we’ll walk through a BPF selftest which shows how to load and use | |
| 66 | +a BPF iterator program. To begin, we’ll look at `bpf_iter.c | |
| 67 | +<https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/testing/selftests/bpf/prog_tests/bpf_iter.c>`_, | |
| 68 | +which illustrates how to load and trigger BPF iterators on the user space side. | |
| 69 | +Later, we’ll look at a BPF program that runs in kernel space. | |
| 70 | + | |
| 71 | +Loading a BPF iterator in the kernel from user space typically involves the | |
| 72 | +following steps: | |
| 73 | + | |
| 74 | +* The BPF program is loaded into the kernel through ``libbpf``. Once the kernel | |
| 75 | + has verified and loaded the program, it returns a file descriptor (fd) to user | |
| 76 | + space. | |
| 77 | +* Obtain a ``link_fd`` to the BPF program by calling the ``bpf_link_create()`` | |
| 78 | + specified with the BPF program file descriptor received from the kernel. | |
| 79 | +* Next, obtain a BPF iterator file descriptor (``bpf_iter_fd``) by calling the | |
| 80 | + ``bpf_iter_create()`` specified with the ``bpf_link`` received from Step 2. | |
| 81 | +* Trigger the iteration by calling ``read(bpf_iter_fd)`` until no data is | |
| 82 | + available. | |
| 83 | +* Close the iterator fd using ``close(bpf_iter_fd)``. | |
| 84 | +* If needed to reread the data, get a new ``bpf_iter_fd`` and do the read again. | |
| 85 | + | |
| 86 | +The following are a few examples of selftest BPF iterator programs: | |
| 87 | + | |
| 88 | +* `bpf_iter_tcp4.c <https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c>`_ | |
| 89 | +* `bpf_iter_task_vma.c <https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c>`_ | |
| 90 | +* `bpf_iter_task_file.c <https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/testing/selftests/bpf/progs/bpf_iter_task_file.c>`_ | |
| 91 | + | |
| 92 | +Let us look at ``bpf_iter_task_file.c``, which runs in kernel space: | |
| 93 | + | |
| 94 | +Here is the definition of ``bpf_iter__task_file`` in `vmlinux.h | |
| 95 | +<https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html#btf>`_. | |
| 96 | +Any struct name in ``vmlinux.h`` in the format ``bpf_iter__<iter_name>`` | |
| 97 | +represents a BPF iterator. The suffix ``<iter_name>`` represents the type of | |
| 98 | +iterator. | |
| 99 | + | |
| 100 | +:: | |
| 101 | + | |
| 102 | + struct bpf_iter__task_file { | |
| 103 | + union { | |
| 104 | + struct bpf_iter_meta *meta; | |
| 105 | + }; | |
| 106 | + union { | |
| 107 | + struct task_struct *task; | |
| 108 | + }; | |
| 109 | + u32 fd; | |
| 110 | + union { | |
| 111 | + struct file *file; | |
| 112 | + }; | |
| 113 | + }; | |
| 114 | + | |
| 115 | +In the above code, the field 'meta' contains the metadata, which is the same for | |
| 116 | +all BPF iterator programs. The rest of the fields are specific to different | |
| 117 | +iterators. For example, for task_file iterators, the kernel layer provides the | |
| 118 | +'task', 'fd' and 'file' field values. The 'task' and 'file' are `reference | |
| 119 | +counted | |
| 120 | +<https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#file-descriptors-and-reference-counters>`_, | |
| 121 | +so they won't go away when the BPF program runs. | |
| 122 | + | |
| 123 | +Here is a snippet from the ``bpf_iter_task_file.c`` file: | |
| 124 | + | |
| 125 | +:: | |
| 126 | + | |
| 127 | + SEC("iter/task_file") | |
| 128 | + int dump_task_file(struct bpf_iter__task_file *ctx) | |
| 129 | + { | |
| 130 | + struct seq_file *seq = ctx->meta->seq; | |
| 131 | + struct task_struct *task = ctx->task; | |
| 132 | + struct file *file = ctx->file; | |
| 133 | + __u32 fd = ctx->fd; | |
| 134 | + | |
| 135 | + if (task == NULL || file == NULL) | |
| 136 | + return 0; | |
| 137 | + | |
| 138 | + if (ctx->meta->seq_num == 0) { | |
| 139 | + count = 0; | |
| 140 | + BPF_SEQ_PRINTF(seq, " tgid gid fd file\n"); | |
| 141 | + } | |
| 142 | + | |
| 143 | + if (tgid == task->tgid && task->tgid != task->pid) | |
| 144 | + count++; | |
| 145 | + | |
| 146 | + if (last_tgid != task->tgid) { | |
| 147 | + last_tgid = task->tgid; | |
| 148 | + unique_tgid_count++; | |
| 149 | + } | |
| 150 | + | |
| 151 | + BPF_SEQ_PRINTF(seq, "%8d %8d %8d %lx\n", task->tgid, task->pid, fd, | |
| 152 | + (long)file->f_op); | |
| 153 | + return 0; | |
| 154 | + } | |
| 155 | + | |
| 156 | +In the above example, the section name ``SEC(iter/task_file)``, indicates that | |
| 157 | +the program is a BPF iterator program to iterate all files from all tasks. The | |
| 158 | +context of the program is ``bpf_iter__task_file`` struct. | |
| 159 | + | |
| 160 | +The user space program invokes the BPF iterator program running in the kernel | |
| 161 | +by issuing a ``read()`` syscall. Once invoked, the BPF | |
| 162 | +program can export data to user space using a variety of BPF helper functions. | |
| 163 | +You can use either ``bpf_seq_printf()`` (and BPF_SEQ_PRINTF helper macro) or | |
| 164 | +``bpf_seq_write()`` function based on whether you need formatted output or just | |
| 165 | +binary data, respectively. For binary-encoded data, the user space applications | |
| 166 | +can process the data from ``bpf_seq_write()`` as needed. For the formatted data, | |
| 167 | +you can use ``cat <path>`` to print the results similar to ``cat | |
| 168 | +/proc/net/netlink`` after pinning the BPF iterator to the bpffs mount. Later, | |
| 169 | +use ``rm -f <path>`` to remove the pinned iterator. | |
| 170 | + | |
| 171 | +For example, you can use the following command to create a BPF iterator from the | |
| 172 | +``bpf_iter_ipv6_route.o`` object file and pin it to the ``/sys/fs/bpf/my_route`` | |
| 173 | +path: | |
| 174 | + | |
| 175 | +:: | |
| 176 | + | |
| 177 | + $ bpftool iter pin ./bpf_iter_ipv6_route.o /sys/fs/bpf/my_route | |
| 178 | + | |
| 179 | +And then print out the results using the following command: | |
| 180 | + | |
| 181 | +:: | |
| 182 | + | |
| 183 | + $ cat /sys/fs/bpf/my_route | |
| 184 | + | |
| 185 | + | |
| 186 | +------------------------------------------------------- | |
| 187 | +Implement Kernel Support for BPF Iterator Program Types | |
| 188 | +------------------------------------------------------- | |
| 189 | + | |
| 190 | +To implement a BPF iterator in the kernel, the developer must make a one-time | |
| 191 | +change to the following key data structure defined in the `bpf.h | |
| 192 | +<https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/include/linux/bpf.h>`_ | |
| 193 | +file. | |
| 194 | + | |
| 195 | +:: | |
| 196 | + | |
| 197 | + struct bpf_iter_reg { | |
| 198 | + const char *target; | |
| 199 | + bpf_iter_attach_target_t attach_target; | |
| 200 | + bpf_iter_detach_target_t detach_target; | |
| 201 | + bpf_iter_show_fdinfo_t show_fdinfo; | |
| 202 | + bpf_iter_fill_link_info_t fill_link_info; | |
| 203 | + bpf_iter_get_func_proto_t get_func_proto; | |
| 204 | + u32 ctx_arg_info_size; | |
| 205 | + u32 feature; | |
| 206 | + struct bpf_ctx_arg_aux ctx_arg_info[BPF_ITER_CTX_ARG_MAX]; | |
| 207 | + const struct bpf_iter_seq_info *seq_info; | |
| 208 | + }; | |
| 209 | + | |
| 210 | +After filling the data structure fields, call ``bpf_iter_reg_target()`` to | |
| 211 | +register the iterator to the main BPF iterator subsystem. | |
| 212 | + | |
| 213 | +The following is the breakdown for each field in struct ``bpf_iter_reg``. | |
| 214 | + | |
| 215 | +.. list-table:: | |
| 216 | + :widths: 25 50 | |
| 217 | + :header-rows: 1 | |
| 218 | + | |
| 219 | + * - Fields | |
| 220 | + - Description | |
| 221 | + * - target | |
| 222 | + - Specifies the name of the BPF iterator. For example: ``bpf_map``, | |
| 223 | + ``bpf_map_elem``. The name should be different from other ``bpf_iter`` target names in the kernel. | |
| 224 | + * - attach_target and detach_target | |
| 225 | + - Allows for target specific ``link_create`` action since some targets | |
| 226 | + may need special processing. Called during the user space link_create stage. | |
| 227 | + * - show_fdinfo and fill_link_info | |
| 228 | + - Called to fill target specific information when user tries to get link | |
| 229 | + info associated with the iterator. | |
| 230 | + * - get_func_proto | |
| 231 | + - Permits a BPF iterator to access BPF helpers specific to the iterator. | |
| 232 | + * - ctx_arg_info_size and ctx_arg_info | |
| 233 | + - Specifies the verifier states for BPF program arguments associated with | |
| 234 | + the bpf iterator. | |
| 235 | + * - feature | |
| 236 | + - Specifies certain action requests in the kernel BPF iterator | |
| 237 | + infrastructure. Currently, only BPF_ITER_RESCHED is supported. This means | |
| 238 | + that the kernel function cond_resched() is called to avoid other kernel | |
| 239 | + subsystem (e.g., rcu) misbehaving. | |
| 240 | + * - seq_info | |
| 241 | + - Specifies certain action requests in the kernel BPF iterator | |
| 242 | + infrastructure. Currently, only BPF_ITER_RESCHED is supported. This means | |
| 243 | + that the kernel function cond_resched() is called to avoid other kernel | |
| 244 | + subsystem (e.g., rcu) misbehaving. | |
| 245 | + | |
| 246 | + | |
| 247 | +`Click here | |
| 248 | +<https://lore.kernel.org/bpf/20210212183107.50963-2-songliubraving@fb.com/>`_ | |
| 249 | +to see an implementation of the ``task_vma`` BPF iterator in the kernel. | |
| 250 | + | |
| 251 | +--------------------------------- | |
| 252 | +Parameterizing BPF Task Iterators | |
| 253 | +--------------------------------- | |
| 254 | + | |
| 255 | +By default, BPF iterators walk through all the objects of the specified types | |
| 256 | +(processes, cgroups, maps, etc.) across the entire system to read relevant | |
| 257 | +kernel data. But often, there are cases where we only care about a much smaller | |
| 258 | +subset of iterable kernel objects, such as only iterating tasks within a | |
| 259 | +specific process. Therefore, BPF iterator programs support filtering out objects | |
| 260 | +from iteration by allowing user space to configure the iterator program when it | |
| 261 | +is attached. | |
| 262 | + | |
| 263 | +-------------------------- | |
| 264 | +BPF Task Iterator Program | |
| 265 | +-------------------------- | |
| 266 | + | |
| 267 | +The following code is a BPF iterator program to print files and task information | |
| 268 | +through the ``seq_file`` of the iterator. It is a standard BPF iterator program | |
| 269 | +that visits every file of an iterator. We will use this BPF program in our | |
| 270 | +example later. | |
| 271 | + | |
| 272 | +:: | |
| 273 | + | |
| 274 | + #include <vmlinux.h> | |
| 275 | + #include <bpf/bpf_helpers.h> | |
| 276 | + | |
| 277 | + char _license[] SEC("license") = "GPL"; | |
| 278 | + | |
| 279 | + SEC("iter/task_file") | |
| 280 | + int dump_task_file(struct bpf_iter__task_file *ctx) | |
| 281 | + { | |
| 282 | + struct seq_file *seq = ctx->meta->seq; | |
| 283 | + struct task_struct *task = ctx->task; | |
| 284 | + struct file *file = ctx->file; | |
| 285 | + __u32 fd = ctx->fd; | |
| 286 | + if (task == NULL || file == NULL) | |
| 287 | + return 0; | |
| 288 | + if (ctx->meta->seq_num == 0) { | |
| 289 | + BPF_SEQ_PRINTF(seq, " tgid pid fd file\n"); | |
| 290 | + } | |
| 291 | + BPF_SEQ_PRINTF(seq, "%8d %8d %8d %lx\n", task->tgid, task->pid, fd, | |
| 292 | + (long)file->f_op); | |
| 293 | + return 0; | |
| 294 | + } | |
| 295 | + | |
| 296 | +---------------------------------------- | |
| 297 | +Creating a File Iterator with Parameters | |
| 298 | +---------------------------------------- | |
| 299 | + | |
| 300 | +Now, let us look at how to create an iterator that includes only files of a | |
| 301 | +process. | |
| 302 | + | |
| 303 | +First, fill the ``bpf_iter_attach_opts`` struct as shown below: | |
| 304 | + | |
| 305 | +:: | |
| 306 | + | |
| 307 | + LIBBPF_OPTS(bpf_iter_attach_opts, opts); | |
| 308 | + union bpf_iter_link_info linfo; | |
| 309 | + memset(&linfo, 0, sizeof(linfo)); | |
| 310 | + linfo.task.pid = getpid(); | |
| 311 | + opts.link_info = &linfo; | |
| 312 | + opts.link_info_len = sizeof(linfo); | |
| 313 | + | |
| 314 | +``linfo.task.pid``, if it is non-zero, directs the kernel to create an iterator | |
| 315 | +that only includes opened files for the process with the specified ``pid``. In | |
| 316 | +this example, we will only be iterating files for our process. If | |
| 317 | +``linfo.task.pid`` is zero, the iterator will visit every opened file of every | |
| 318 | +process. Similarly, ``linfo.task.tid`` directs the kernel to create an iterator | |
| 319 | +that visits opened files of a specific thread, not a process. In this example, | |
| 320 | +``linfo.task.tid`` is different from ``linfo.task.pid`` only if the thread has a | |
| 321 | +separate file descriptor table. In most circumstances, all process threads share | |
| 322 | +a single file descriptor table. | |
| 323 | + | |
| 324 | +Now, in the userspace program, pass the pointer of struct to the | |
| 325 | +``bpf_program__attach_iter()``. | |
| 326 | + | |
| 327 | +:: | |
| 328 | + | |
| 329 | + link = bpf_program__attach_iter(prog, &opts); iter_fd = | |
| 330 | + bpf_iter_create(bpf_link__fd(link)); | |
| 331 | + | |
| 332 | +If both *tid* and *pid* are zero, an iterator created from this struct | |
| 333 | +``bpf_iter_attach_opts`` will include every opened file of every task in the | |
| 334 | +system (in the namespace, actually.) It is the same as passing a NULL as the | |
| 335 | +second argument to ``bpf_program__attach_iter()``. | |
| 336 | + | |
| 337 | +The whole program looks like the following code: | |
| 338 | + | |
| 339 | +:: | |
| 340 | + | |
| 341 | + #include <stdio.h> | |
| 342 | + #include <unistd.h> | |
| 343 | + #include <bpf/bpf.h> | |
| 344 | + #include <bpf/libbpf.h> | |
| 345 | + #include "bpf_iter_task_ex.skel.h" | |
| 346 | + | |
| 347 | + static int do_read_opts(struct bpf_program *prog, struct bpf_iter_attach_opts *opts) | |
| 348 | + { | |
| 349 | + struct bpf_link *link; | |
| 350 | + char buf[16] = {}; | |
| 351 | + int iter_fd = -1, len; | |
| 352 | + int ret = 0; | |
| 353 | + | |
| 354 | + link = bpf_program__attach_iter(prog, opts); | |
| 355 | + if (!link) { | |
| 356 | + fprintf(stderr, "bpf_program__attach_iter() fails\n"); | |
| 357 | + return -1; | |
| 358 | + } | |
| 359 | + iter_fd = bpf_iter_create(bpf_link__fd(link)); | |
| 360 | + if (iter_fd < 0) { | |
| 361 | + fprintf(stderr, "bpf_iter_create() fails\n"); | |
| 362 | + ret = -1; | |
| 363 | + goto free_link; | |
| 364 | + } | |
| 365 | + /* not check contents, but ensure read() ends without error */ | |
| 366 | + while ((len = read(iter_fd, buf, sizeof(buf) - 1)) > 0) { | |
| 367 | + buf[len] = 0; | |
| 368 | + printf("%s", buf); | |
| 369 | + } | |
| 370 | + printf("\n"); | |
| 371 | + free_link: | |
| 372 | + if (iter_fd >= 0) | |
| 373 | + close(iter_fd); | |
| 374 | + bpf_link__destroy(link); | |
| 375 | + return 0; | |
| 376 | + } | |
| 377 | + | |
| 378 | + static void test_task_file(void) | |
| 379 | + { | |
| 380 | + LIBBPF_OPTS(bpf_iter_attach_opts, opts); | |
| 381 | + struct bpf_iter_task_ex *skel; | |
| 382 | + union bpf_iter_link_info linfo; | |
| 383 | + skel = bpf_iter_task_ex__open_and_load(); | |
| 384 | + if (skel == NULL) | |
| 385 | + return; | |
| 386 | + memset(&linfo, 0, sizeof(linfo)); | |
| 387 | + linfo.task.pid = getpid(); | |
| 388 | + opts.link_info = &linfo; | |
| 389 | + opts.link_info_len = sizeof(linfo); | |
| 390 | + printf("PID %d\n", getpid()); | |
| 391 | + do_read_opts(skel->progs.dump_task_file, &opts); | |
| 392 | + bpf_iter_task_ex__destroy(skel); | |
| 393 | + } | |
| 394 | + | |
| 395 | + int main(int argc, const char * const * argv) | |
| 396 | + { | |
| 397 | + test_task_file(); | |
| 398 | + return 0; | |
| 399 | + } | |
| 400 | + | |
| 401 | +The following lines are the output of the program. | |
| 402 | +:: | |
| 403 | + | |
| 404 | + PID 1859 | |
| 405 | + | |
| 406 | + tgid pid fd file | |
| 407 | + 1859 1859 0 ffffffff82270aa0 | |
| 408 | + 1859 1859 1 ffffffff82270aa0 | |
| 409 | + 1859 1859 2 ffffffff82270aa0 | |
| 410 | + 1859 1859 3 ffffffff82272980 | |
| 411 | + 1859 1859 4 ffffffff8225e120 | |
| 412 | + 1859 1859 5 ffffffff82255120 | |
| 413 | + 1859 1859 6 ffffffff82254f00 | |
| 414 | + 1859 1859 7 ffffffff82254d80 | |
| 415 | + 1859 1859 8 ffffffff8225abe0 | |
| 416 | + | |
| 417 | +------------------ | |
| 418 | +Without Parameters | |
| 419 | +------------------ | |
| 420 | + | |
| 421 | +Let us look at how a BPF iterator without parameters skips files of other | |
| 422 | +processes in the system. In this case, the BPF program has to check the pid or | |
| 423 | +the tid of tasks, or it will receive every opened file in the system (in the | |
| 424 | +current *pid* namespace, actually). So, we usually add a global variable in the | |
| 425 | +BPF program to pass a *pid* to the BPF program. | |
| 426 | + | |
| 427 | +The BPF program would look like the following block. | |
| 428 | + | |
| 429 | + :: | |
| 430 | + | |
| 431 | + ...... | |
| 432 | + int target_pid = 0; | |
| 433 | + | |
| 434 | + SEC("iter/task_file") | |
| 435 | + int dump_task_file(struct bpf_iter__task_file *ctx) | |
| 436 | + { | |
| 437 | + ...... | |
| 438 | + if (task->tgid != target_pid) /* Check task->pid instead to check thread IDs */ | |
| 439 | + return 0; | |
| 440 | + BPF_SEQ_PRINTF(seq, "%8d %8d %8d %lx\n", task->tgid, task->pid, fd, | |
| 441 | + (long)file->f_op); | |
| 442 | + return 0; | |
| 443 | + } | |
| 444 | + | |
| 445 | +The user space program would look like the following block: | |
| 446 | + | |
| 447 | + :: | |
| 448 | + | |
| 449 | + ...... | |
| 450 | + static void test_task_file(void) | |
| 451 | + { | |
| 452 | + ...... | |
| 453 | + skel = bpf_iter_task_ex__open_and_load(); | |
| 454 | + if (skel == NULL) | |
| 455 | + return; | |
| 456 | + skel->bss->target_pid = getpid(); /* process ID. For thread id, use gettid() */ | |
| 457 | + memset(&linfo, 0, sizeof(linfo)); | |
| 458 | + linfo.task.pid = getpid(); | |
| 459 | + opts.link_info = &linfo; | |
| 460 | + opts.link_info_len = sizeof(linfo); | |
| 461 | + ...... | |
| 462 | + } | |
| 463 | + | |
| 464 | +``target_pid`` is a global variable in the BPF program. The user space program | |
| 465 | +should initialize the variable with a process ID to skip opened files of other | |
| 466 | +processes in the BPF program. When you parametrize a BPF iterator, the iterator | |
| 467 | +calls the BPF program fewer times which can save significant resources. | |
| 468 | + | |
| 469 | +--------------------------- | |
| 470 | +Parametrizing VMA Iterators | |
| 471 | +--------------------------- | |
| 472 | + | |
| 473 | +By default, a BPF VMA iterator includes every VMA in every process. However, | |
| 474 | +you can still specify a process or a thread to include only its VMAs. Unlike | |
| 475 | +files, a thread can not have a separate address space (since Linux 2.6.0-test6). | |
| 476 | +Here, using *tid* makes no difference from using *pid*. | |
| 477 | + | |
| 478 | +---------------------------- | |
| 479 | +Parametrizing Task Iterators | |
| 480 | +---------------------------- | |
| 481 | + | |
| 482 | +A BPF task iterator with *pid* includes all tasks (threads) of a process. The | |
| 483 | +BPF program receives these tasks one after another. You can specify a BPF task | |
| 484 | +iterator with *tid* parameter to include only the tasks that match the given | |
| 485 | +*tid*. | |
| @@ -1062,4 +1062,9 @@ format.:: · 1061 unmodified lines | ||
| 1062 | 1062 | 7. Testing |
| 1063 | 1063 | ========== |
| 1064 | 1064 | |
| 1065 | −Kernel bpf selftest `test_btf.c` provides extensive set of BTF-related tests. | |
| 1065 | +The kernel BPF selftest `tools/testing/selftests/bpf/prog_tests/btf.c`_ | |
| 1066 | +provides an extensive set of BTF-related tests. | |
| 1067 | + | |
| 1068 | +.. Links | |
| 1069 | +.. _tools/testing/selftests/bpf/prog_tests/btf.c: | |
| 1070 | + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/prog_tests/btf.c | |
| @@ -24,11 +24,13 @@ that goes into great technical depth about the BPF Architecture. · 23 unmodified lines | ||
| 24 | 24 | maps |
| 25 | 25 | bpf_prog_run |
| 26 | 26 | classic_vs_extended.rst |
| 27 | + bpf_iterators | |
| 27 | 28 | bpf_licensing |
| 28 | 29 | test_debug |
| 29 | 30 | clang-notes |
| 30 | 31 | linux-notes |
| 31 | 32 | other |
| 33 | + redirect | |
| 32 | 34 | |
| 33 | 35 | .. only:: subproject and html |
| 34 | 36 | |
| @@ -122,11 +122,11 @@ BPF_END 0xd0 byte swap operations (see `Byte swap instructions`_ below) · 121 unmodified lines | ||
| 122 | 122 | |
| 123 | 123 | ``BPF_XOR | BPF_K | BPF_ALU`` means:: |
| 124 | 124 | |
| 125 | − src_reg = (u32) src_reg ^ (u32) imm32 | |
| 125 | + dst_reg = (u32) dst_reg ^ (u32) imm32 | |
| 126 | 126 | |
| 127 | 127 | ``BPF_XOR | BPF_K | BPF_ALU64`` means:: |
| 128 | 128 | |
| 129 | − src_reg = src_reg ^ imm32 | |
| 129 | + dst_reg = dst_reg ^ imm32 | |
| 130 | 130 | |
| 131 | 131 | |
| 132 | 132 | Byte swap instructions |
| @@ -72,6 +72,30 @@ argument as its size. By default, without __sz annotation, the size of the type · 71 unmodified lines | ||
| 72 | 72 | of the pointer is used. Without __sz annotation, a kfunc cannot accept a void |
| 73 | 73 | pointer. |
| 74 | 74 | |
| 75 | +2.2.2 __k Annotation | |
| 76 | +-------------------- | |
| 77 | + | |
| 78 | +This annotation is only understood for scalar arguments, where it indicates that | |
| 79 | +the verifier must check the scalar argument to be a known constant, which does | |
| 80 | +not indicate a size parameter, and the value of the constant is relevant to the | |
| 81 | +safety of the program. | |
| 82 | + | |
| 83 | +An example is given below:: | |
| 84 | + | |
| 85 | + void *bpf_obj_new(u32 local_type_id__k, ...) | |
| 86 | + { | |
| 87 | + ... | |
| 88 | + } | |
| 89 | + | |
| 90 | +Here, bpf_obj_new uses local_type_id argument to find out the size of that type | |
| 91 | +ID in program's BTF and return a sized pointer to it. Each type ID will have a | |
| 92 | +distinct size, hence it is crucial to treat each such call as distinct when | |
| 93 | +values don't match during verifier state pruning checks. | |
| 94 | + | |
| 95 | +Hence, whenever a constant scalar argument is accepted by a kfunc which is not a | |
| 96 | +size parameter, and the value of the constant matters for program safety, __k | |
| 97 | +suffix should be used. | |
| 98 | + | |
| 75 | 99 | .. _BPF_kfunc_nodef: |
| 76 | 100 | |
| 77 | 101 | 2.3 Using an existing kernel function |
| @@ -137,22 +161,20 @@ KF_ACQUIRE and KF_RET_NULL flags. · 59 unmodified lines | ||
| 137 | 161 | -------------------------- |
| 138 | 162 | |
| 139 | 163 | The KF_TRUSTED_ARGS flag is used for kfuncs taking pointer arguments. It |
| 140 | −indicates that the all pointer arguments will always have a guaranteed lifetime, | |
| 141 | −and pointers to kernel objects are always passed to helpers in their unmodified | |
| 142 | −form (as obtained from acquire kfuncs). | |
| 164 | +indicates that the all pointer arguments are valid, and that all pointers to | |
| 165 | +BTF objects have been passed in their unmodified form (that is, at a zero | |
| 166 | +offset, and without having been obtained from walking another pointer). | |
| 143 | 167 | |
| 144 | −It can be used to enforce that a pointer to a refcounted object acquired from a | |
| 145 | −kfunc or BPF helper is passed as an argument to this kfunc without any | |
| 146 | −modifications (e.g. pointer arithmetic) such that it is trusted and points to | |
| 147 | −the original object. | |
| 168 | +There are two types of pointers to kernel objects which are considered "valid": | |
| 148 | 169 | |
| 149 | −Meanwhile, it is also allowed pass pointers to normal memory to such kfuncs, | |
| 150 | −but those can have a non-zero offset. | |
| 170 | +1. Pointers which are passed as tracepoint or struct_ops callback arguments. | |
| 171 | +2. Pointers which were returned from a KF_ACQUIRE or KF_KPTR_GET kfunc. | |
| 151 | 172 | |
| 152 | −This flag is often used for kfuncs that operate (change some property, perform | |
| 153 | −some operation) on an object that was obtained using an acquire kfunc. Such | |
| 154 | −kfuncs need an unchanged pointer to ensure the integrity of the operation being | |
| 155 | −performed on the expected object. | |
| 173 | +Pointers to non-BTF objects (e.g. scalar pointers) may also be passed to | |
| 174 | +KF_TRUSTED_ARGS kfuncs, and may have a non-zero offset. | |
| 175 | + | |
| 176 | +The definition of "valid" pointers is subject to change at any time, and has | |
| 177 | +absolutely no ABI stability guarantees. | |
| 156 | 178 | |
| 157 | 179 | 2.4.6 KF_SLEEPABLE flag |
| 158 | 180 | ----------------------- |
| @@ -169,6 +191,15 @@ rebooting or panicking. Due to this additional restrictions apply to these · 10 unmodified lines | ||
| 169 | 191 | calls. At the moment they only require CAP_SYS_BOOT capability, but more can be |
| 170 | 192 | added later. |
| 171 | 193 | |
| 194 | +2.4.8 KF_RCU flag | |
| 195 | +----------------- | |
| 196 | + | |
| 197 | +The KF_RCU flag is used for kfuncs which have a rcu ptr as its argument. | |
| 198 | +When used together with KF_ACQUIRE, it indicates the kfunc should have a | |
| 199 | +single argument which must be a trusted argument or a MEM_RCU pointer. | |
| 200 | +The argument may have reference count of 0 and the kfunc must take this | |
| 201 | +into consideration. | |
| 202 | + | |
| 172 | 203 | 2.5 Registering the kfuncs |
| 173 | 204 | -------------------------- |
| 174 | 205 | |
| @@ -191,3 +222,201 @@ type. An example is shown below:: · 16 unmodified lines | ||
| 191 | 222 | return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_task_kfunc_set); |
| 192 | 223 | } |
| 193 | 224 | late_initcall(init_subsystem); |
| 225 | + | |
| 226 | +3. Core kfuncs | |
| 227 | +============== | |
| 228 | + | |
| 229 | +The BPF subsystem provides a number of "core" kfuncs that are potentially | |
| 230 | +applicable to a wide variety of different possible use cases and programs. | |
| 231 | +Those kfuncs are documented here. | |
| 232 | + | |
| 233 | +3.1 struct task_struct * kfuncs | |
| 234 | +------------------------------- | |
| 235 | + | |
| 236 | +There are a number of kfuncs that allow ``struct task_struct *`` objects to be | |
| 237 | +used as kptrs: | |
| 238 | + | |
| 239 | +.. kernel-doc:: kernel/bpf/helpers.c | |
| 240 | + :identifiers: bpf_task_acquire bpf_task_release | |
| 241 | + | |
| 242 | +These kfuncs are useful when you want to acquire or release a reference to a | |
| 243 | +``struct task_struct *`` that was passed as e.g. a tracepoint arg, or a | |
| 244 | +struct_ops callback arg. For example: | |
| 245 | + | |
| 246 | +.. code-block:: c | |
| 247 | + | |
| 248 | + /** | |
| 249 | + * A trivial example tracepoint program that shows how to | |
| 250 | + * acquire and release a struct task_struct * pointer. | |
| 251 | + */ | |
| 252 | + SEC("tp_btf/task_newtask") | |
| 253 | + int BPF_PROG(task_acquire_release_example, struct task_struct *task, u64 clone_flags) | |
| 254 | + { | |
| 255 | + struct task_struct *acquired; | |
| 256 | + | |
| 257 | + acquired = bpf_task_acquire(task); | |
| 258 | + | |
| 259 | + /* | |
| 260 | + * In a typical program you'd do something like store | |
| 261 | + * the task in a map, and the map will automatically | |
| 262 | + * release it later. Here, we release it manually. | |
| 263 | + */ | |
| 264 | + bpf_task_release(acquired); | |
| 265 | + return 0; | |
| 266 | + } | |
| 267 | + | |
| 268 | +---- | |
| 269 | + | |
| 270 | +A BPF program can also look up a task from a pid. This can be useful if the | |
| 271 | +caller doesn't have a trusted pointer to a ``struct task_struct *`` object that | |
| 272 | +it can acquire a reference on with bpf_task_acquire(). | |
| 273 | + | |
| 274 | +.. kernel-doc:: kernel/bpf/helpers.c | |
| 275 | + :identifiers: bpf_task_from_pid | |
| 276 | + | |
| 277 | +Here is an example of it being used: | |
| 278 | + | |
| 279 | +.. code-block:: c | |
| 280 | + | |
| 281 | + SEC("tp_btf/task_newtask") | |
| 282 | + int BPF_PROG(task_get_pid_example, struct task_struct *task, u64 clone_flags) | |
| 283 | + { | |
| 284 | + struct task_struct *lookup; | |
| 285 | + | |
| 286 | + lookup = bpf_task_from_pid(task->pid); | |
| 287 | + if (!lookup) | |
| 288 | + /* A task should always be found, as %task is a tracepoint arg. */ | |
| 289 | + return -ENOENT; | |
| 290 | + | |
| 291 | + if (lookup->pid != task->pid) { | |
| 292 | + /* bpf_task_from_pid() looks up the task via its | |
| 293 | + * globally-unique pid from the init_pid_ns. Thus, | |
| 294 | + * the pid of the lookup task should always be the | |
| 295 | + * same as the input task. | |
| 296 | + */ | |
| 297 | + bpf_task_release(lookup); | |
| 298 | + return -EINVAL; | |
| 299 | + } | |
| 300 | + | |
| 301 | + /* bpf_task_from_pid() returns an acquired reference, | |
| 302 | + * so it must be dropped before returning from the | |
| 303 | + * tracepoint handler. | |
| 304 | + */ | |
| 305 | + bpf_task_release(lookup); | |
| 306 | + return 0; | |
| 307 | + } | |
| 308 | + | |
| 309 | +3.2 struct cgroup * kfuncs | |
| 310 | +-------------------------- | |
| 311 | + | |
| 312 | +``struct cgroup *`` objects also have acquire and release functions: | |
| 313 | + | |
| 314 | +.. kernel-doc:: kernel/bpf/helpers.c | |
| 315 | + :identifiers: bpf_cgroup_acquire bpf_cgroup_release | |
| 316 | + | |
| 317 | +These kfuncs are used in exactly the same manner as bpf_task_acquire() and | |
| 318 | +bpf_task_release() respectively, so we won't provide examples for them. | |
| 319 | + | |
| 320 | +---- | |
| 321 | + | |
| 322 | +You may also acquire a reference to a ``struct cgroup`` kptr that's already | |
| 323 | +stored in a map using bpf_cgroup_kptr_get(): | |
| 324 | + | |
| 325 | +.. kernel-doc:: kernel/bpf/helpers.c | |
| 326 | + :identifiers: bpf_cgroup_kptr_get | |
| 327 | + | |
| 328 | +Here's an example of how it can be used: | |
| 329 | + | |
| 330 | +.. code-block:: c | |
| 331 | + | |
| 332 | + /* struct containing the struct task_struct kptr which is actually stored in the map. */ | |
| 333 | + struct __cgroups_kfunc_map_value { | |
| 334 | + struct cgroup __kptr_ref * cgroup; | |
| 335 | + }; | |
| 336 | + | |
| 337 | + /* The map containing struct __cgroups_kfunc_map_value entries. */ | |
| 338 | + struct { | |
| 339 | + __uint(type, BPF_MAP_TYPE_HASH); | |
| 340 | + __type(key, int); | |
| 341 | + __type(value, struct __cgroups_kfunc_map_value); | |
| 342 | + __uint(max_entries, 1); | |
| 343 | + } __cgroups_kfunc_map SEC(".maps"); | |
| 344 | + | |
| 345 | + /* ... */ | |
| 346 | + | |
| 347 | + /** | |
| 348 | + * A simple example tracepoint program showing how a | |
| 349 | + * struct cgroup kptr that is stored in a map can | |
| 350 | + * be acquired using the bpf_cgroup_kptr_get() kfunc. | |
| 351 | + */ | |
| 352 | + SEC("tp_btf/cgroup_mkdir") | |
| 353 | + int BPF_PROG(cgroup_kptr_get_example, struct cgroup *cgrp, const char *path) | |
| 354 | + { | |
| 355 | + struct cgroup *kptr; | |
| 356 | + struct __cgroups_kfunc_map_value *v; | |
| 357 | + s32 id = cgrp->self.id; | |
| 358 | + | |
| 359 | + /* Assume a cgroup kptr was previously stored in the map. */ | |
| 360 | + v = bpf_map_lookup_elem(&__cgroups_kfunc_map, &id); | |
| 361 | + if (!v) | |
| 362 | + return -ENOENT; | |
| 363 | + | |
| 364 | + /* Acquire a reference to the cgroup kptr that's already stored in the map. */ | |
| 365 | + kptr = bpf_cgroup_kptr_get(&v->cgroup); | |
| 366 | + if (!kptr) | |
| 367 | + /* If no cgroup was present in the map, it's because | |
| 368 | + * we're racing with another CPU that removed it with | |
| 369 | + * bpf_kptr_xchg() between the bpf_map_lookup_elem() | |
| 370 | + * above, and our call to bpf_cgroup_kptr_get(). | |
| 371 | + * bpf_cgroup_kptr_get() internally safely handles this | |
| 372 | + * race, and will return NULL if the task is no longer | |
| 373 | + * present in the map by the time we invoke the kfunc. | |
| 374 | + */ | |
| 375 | + return -EBUSY; | |
| 376 | + | |
| 377 | + /* Free the reference we just took above. Note that the | |
| 378 | + * original struct cgroup kptr is still in the map. It will | |
| 379 | + * be freed either at a later time if another context deletes | |
| 380 | + * it from the map, or automatically by the BPF subsystem if | |
| 381 | + * it's still present when the map is destroyed. | |
| 382 | + */ | |
| 383 | + bpf_cgroup_release(kptr); | |
| 384 | + | |
| 385 | + return 0; | |
| 386 | + } | |
| 387 | + | |
| 388 | +---- | |
| 389 | + | |
| 390 | +Another kfunc available for interacting with ``struct cgroup *`` objects is | |
| 391 | +bpf_cgroup_ancestor(). This allows callers to access the ancestor of a cgroup, | |
| 392 | +and return it as a cgroup kptr. | |
| 393 | + | |
| 394 | +.. kernel-doc:: kernel/bpf/helpers.c | |
| 395 | + :identifiers: bpf_cgroup_ancestor | |
| 396 | + | |
| 397 | +Eventually, BPF should be updated to allow this to happen with a normal memory | |
| 398 | +load in the program itself. This is currently not possible without more work in | |
| 399 | +the verifier. bpf_cgroup_ancestor() can be used as follows: | |
| 400 | + | |
| 401 | +.. code-block:: c | |
| 402 | + | |
| 403 | + /** | |
| 404 | + * Simple tracepoint example that illustrates how a cgroup's | |
| 405 | + * ancestor can be accessed using bpf_cgroup_ancestor(). | |
| 406 | + */ | |
| 407 | + SEC("tp_btf/cgroup_mkdir") | |
| 408 | + int BPF_PROG(cgrp_ancestor_example, struct cgroup *cgrp, const char *path) | |
| 409 | + { | |
| 410 | + struct cgroup *parent; | |
| 411 | + | |
| 412 | + /* The parent cgroup resides at the level before the current cgroup's level. */ | |
| 413 | + parent = bpf_cgroup_ancestor(cgrp, cgrp->level - 1); | |
| 414 | + if (!parent) | |
| 415 | + return -ENOENT; | |
| 416 | + | |
| 417 | + bpf_printk("Parent id is %d", parent->self.id); | |
| 418 | + | |
| 419 | + /* Return the parent cgroup that was acquired above. */ | |
| 420 | + bpf_cgroup_release(parent); | |
| 421 | + return 0; | |
| 422 | + } | |
| @@ -1,5 +1,7 @@ | ||
| 1 | 1 | .. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
| 2 | 2 | |
| 3 | +.. _libbpf: | |
| 4 | + | |
| 3 | 5 | libbpf |
| 4 | 6 | ====== |
| 5 | 7 | |
| @@ -7,6 +9,7 @@ libbpf · 1 unmodified line | ||
| 7 | 9 | :maxdepth: 1 |
| 8 | 10 | |
| 9 | 11 | API Documentation <https://libbpf.readthedocs.io/en/latest/api.html> |
| 12 | + program_types | |
| 10 | 13 | libbpf_naming_convention |
| 11 | 14 | libbpf_build |
| 12 | 15 | |
| @@ -0,0 +1,203 @@ | ||
| 1 | +.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +.. _program_types_and_elf: | |
| 4 | + | |
| 5 | +Program Types and ELF Sections | |
| 6 | +============================== | |
| 7 | + | |
| 8 | +The table below lists the program types, their attach types where relevant and the ELF section | |
| 9 | +names supported by libbpf for them. The ELF section names follow these rules: | |
| 10 | + | |
| 11 | +- ``type`` is an exact match, e.g. ``SEC("socket")`` | |
| 12 | +- ``type+`` means it can be either exact ``SEC("type")`` or well-formed ``SEC("type/extras")`` | |
| 13 | + with a '``/``' separator between ``type`` and ``extras``. | |
| 14 | + | |
| 15 | +When ``extras`` are specified, they provide details of how to auto-attach the BPF program. The | |
| 16 | +format of ``extras`` depends on the program type, e.g. ``SEC("tracepoint/<category>/<name>")`` | |
| 17 | +for tracepoints or ``SEC("usdt/<path>:<provider>:<name>")`` for USDT probes. The extras are | |
| 18 | +described in more detail in the footnotes. | |
| 19 | + | |
| 20 | + | |
| 21 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 22 | +| Program Type | Attach Type | ELF Section Name | Sleepable | | |
| 23 | ++===========================================+========================================+==================================+===========+ | |
| 24 | +| ``BPF_PROG_TYPE_CGROUP_DEVICE`` | ``BPF_CGROUP_DEVICE`` | ``cgroup/dev`` | | | |
| 25 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 26 | +| ``BPF_PROG_TYPE_CGROUP_SKB`` | | ``cgroup/skb`` | | | |
| 27 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 28 | +| | ``BPF_CGROUP_INET_EGRESS`` | ``cgroup_skb/egress`` | | | |
| 29 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 30 | +| | ``BPF_CGROUP_INET_INGRESS`` | ``cgroup_skb/ingress`` | | | |
| 31 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 32 | +| ``BPF_PROG_TYPE_CGROUP_SOCKOPT`` | ``BPF_CGROUP_GETSOCKOPT`` | ``cgroup/getsockopt`` | | | |
| 33 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 34 | +| | ``BPF_CGROUP_SETSOCKOPT`` | ``cgroup/setsockopt`` | | | |
| 35 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 36 | +| ``BPF_PROG_TYPE_CGROUP_SOCK_ADDR`` | ``BPF_CGROUP_INET4_BIND`` | ``cgroup/bind4`` | | | |
| 37 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 38 | +| | ``BPF_CGROUP_INET4_CONNECT`` | ``cgroup/connect4`` | | | |
| 39 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 40 | +| | ``BPF_CGROUP_INET4_GETPEERNAME`` | ``cgroup/getpeername4`` | | | |
| 41 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 42 | +| | ``BPF_CGROUP_INET4_GETSOCKNAME`` | ``cgroup/getsockname4`` | | | |
| 43 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 44 | +| | ``BPF_CGROUP_INET6_BIND`` | ``cgroup/bind6`` | | | |
| 45 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 46 | +| | ``BPF_CGROUP_INET6_CONNECT`` | ``cgroup/connect6`` | | | |
| 47 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 48 | +| | ``BPF_CGROUP_INET6_GETPEERNAME`` | ``cgroup/getpeername6`` | | | |
| 49 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 50 | +| | ``BPF_CGROUP_INET6_GETSOCKNAME`` | ``cgroup/getsockname6`` | | | |
| 51 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 52 | +| | ``BPF_CGROUP_UDP4_RECVMSG`` | ``cgroup/recvmsg4`` | | | |
| 53 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 54 | +| | ``BPF_CGROUP_UDP4_SENDMSG`` | ``cgroup/sendmsg4`` | | | |
| 55 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 56 | +| | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | | | |
| 57 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 58 | +| | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | | | |
| 59 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 60 | +| ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | | | |
| 61 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 62 | +| | ``BPF_CGROUP_INET6_POST_BIND`` | ``cgroup/post_bind6`` | | | |
| 63 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 64 | +| | ``BPF_CGROUP_INET_SOCK_CREATE`` | ``cgroup/sock_create`` | | | |
| 65 | ++ + +----------------------------------+-----------+ | |
| 66 | +| | | ``cgroup/sock`` | | | |
| 67 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 68 | +| | ``BPF_CGROUP_INET_SOCK_RELEASE`` | ``cgroup/sock_release`` | | | |
| 69 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 70 | +| ``BPF_PROG_TYPE_CGROUP_SYSCTL`` | ``BPF_CGROUP_SYSCTL`` | ``cgroup/sysctl`` | | | |
| 71 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 72 | +| ``BPF_PROG_TYPE_EXT`` | | ``freplace+`` [#fentry]_ | | | |
| 73 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 74 | +| ``BPF_PROG_TYPE_FLOW_DISSECTOR`` | ``BPF_FLOW_DISSECTOR`` | ``flow_dissector`` | | | |
| 75 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 76 | +| ``BPF_PROG_TYPE_KPROBE`` | | ``kprobe+`` [#kprobe]_ | | | |
| 77 | ++ + +----------------------------------+-----------+ | |
| 78 | +| | | ``kretprobe+`` [#kprobe]_ | | | |
| 79 | ++ + +----------------------------------+-----------+ | |
| 80 | +| | | ``ksyscall+`` [#ksyscall]_ | | | |
| 81 | ++ + +----------------------------------+-----------+ | |
| 82 | +| | | ``kretsyscall+`` [#ksyscall]_ | | | |
| 83 | ++ + +----------------------------------+-----------+ | |
| 84 | +| | | ``uprobe+`` [#uprobe]_ | | | |
| 85 | ++ + +----------------------------------+-----------+ | |
| 86 | +| | | ``uprobe.s+`` [#uprobe]_ | Yes | | |
| 87 | ++ + +----------------------------------+-----------+ | |
| 88 | +| | | ``uretprobe+`` [#uprobe]_ | | | |
| 89 | ++ + +----------------------------------+-----------+ | |
| 90 | +| | | ``uretprobe.s+`` [#uprobe]_ | Yes | | |
| 91 | ++ + +----------------------------------+-----------+ | |
| 92 | +| | | ``usdt+`` [#usdt]_ | | | |
| 93 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 94 | +| | ``BPF_TRACE_KPROBE_MULTI`` | ``kprobe.multi+`` [#kpmulti]_ | | | |
| 95 | ++ + +----------------------------------+-----------+ | |
| 96 | +| | | ``kretprobe.multi+`` [#kpmulti]_ | | | |
| 97 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 98 | +| ``BPF_PROG_TYPE_LIRC_MODE2`` | ``BPF_LIRC_MODE2`` | ``lirc_mode2`` | | | |
| 99 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 100 | +| ``BPF_PROG_TYPE_LSM`` | ``BPF_LSM_CGROUP`` | ``lsm_cgroup+`` | | | |
| 101 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 102 | +| | ``BPF_LSM_MAC`` | ``lsm+`` [#lsm]_ | | | |
| 103 | ++ + +----------------------------------+-----------+ | |
| 104 | +| | | ``lsm.s+`` [#lsm]_ | Yes | | |
| 105 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 106 | +| ``BPF_PROG_TYPE_LWT_IN`` | | ``lwt_in`` | | | |
| 107 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 108 | +| ``BPF_PROG_TYPE_LWT_OUT`` | | ``lwt_out`` | | | |
| 109 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 110 | +| ``BPF_PROG_TYPE_LWT_SEG6LOCAL`` | | ``lwt_seg6local`` | | | |
| 111 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 112 | +| ``BPF_PROG_TYPE_LWT_XMIT`` | | ``lwt_xmit`` | | | |
| 113 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 114 | +| ``BPF_PROG_TYPE_PERF_EVENT`` | | ``perf_event`` | | | |
| 115 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 116 | +| ``BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE`` | | ``raw_tp.w+`` [#rawtp]_ | | | |
| 117 | ++ + +----------------------------------+-----------+ | |
| 118 | +| | | ``raw_tracepoint.w+`` | | | |
| 119 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 120 | +| ``BPF_PROG_TYPE_RAW_TRACEPOINT`` | | ``raw_tp+`` [#rawtp]_ | | | |
| 121 | ++ + +----------------------------------+-----------+ | |
| 122 | +| | | ``raw_tracepoint+`` | | | |
| 123 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 124 | +| ``BPF_PROG_TYPE_SCHED_ACT`` | | ``action`` | | | |
| 125 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 126 | +| ``BPF_PROG_TYPE_SCHED_CLS`` | | ``classifier`` | | | |
| 127 | ++ + +----------------------------------+-----------+ | |
| 128 | +| | | ``tc`` | | | |
| 129 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 130 | +| ``BPF_PROG_TYPE_SK_LOOKUP`` | ``BPF_SK_LOOKUP`` | ``sk_lookup`` | | | |
| 131 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 132 | +| ``BPF_PROG_TYPE_SK_MSG`` | ``BPF_SK_MSG_VERDICT`` | ``sk_msg`` | | | |
| 133 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 134 | +| ``BPF_PROG_TYPE_SK_REUSEPORT`` | ``BPF_SK_REUSEPORT_SELECT_OR_MIGRATE`` | ``sk_reuseport/migrate`` | | | |
| 135 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 136 | +| | ``BPF_SK_REUSEPORT_SELECT`` | ``sk_reuseport`` | | | |
| 137 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 138 | +| ``BPF_PROG_TYPE_SK_SKB`` | | ``sk_skb`` | | | |
| 139 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 140 | +| | ``BPF_SK_SKB_STREAM_PARSER`` | ``sk_skb/stream_parser`` | | | |
| 141 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 142 | +| | ``BPF_SK_SKB_STREAM_VERDICT`` | ``sk_skb/stream_verdict`` | | | |
| 143 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 144 | +| ``BPF_PROG_TYPE_SOCKET_FILTER`` | | ``socket`` | | | |
| 145 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 146 | +| ``BPF_PROG_TYPE_SOCK_OPS`` | ``BPF_CGROUP_SOCK_OPS`` | ``sockops`` | | | |
| 147 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 148 | +| ``BPF_PROG_TYPE_STRUCT_OPS`` | | ``struct_ops+`` | | | |
| 149 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 150 | +| ``BPF_PROG_TYPE_SYSCALL`` | | ``syscall`` | Yes | | |
| 151 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 152 | +| ``BPF_PROG_TYPE_TRACEPOINT`` | | ``tp+`` [#tp]_ | | | |
| 153 | ++ + +----------------------------------+-----------+ | |
| 154 | +| | | ``tracepoint+`` [#tp]_ | | | |
| 155 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 156 | +| ``BPF_PROG_TYPE_TRACING`` | ``BPF_MODIFY_RETURN`` | ``fmod_ret+`` [#fentry]_ | | | |
| 157 | ++ + +----------------------------------+-----------+ | |
| 158 | +| | | ``fmod_ret.s+`` [#fentry]_ | Yes | | |
| 159 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 160 | +| | ``BPF_TRACE_FENTRY`` | ``fentry+`` [#fentry]_ | | | |
| 161 | ++ + +----------------------------------+-----------+ | |
| 162 | +| | | ``fentry.s+`` [#fentry]_ | Yes | | |
| 163 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 164 | +| | ``BPF_TRACE_FEXIT`` | ``fexit+`` [#fentry]_ | | | |
| 165 | ++ + +----------------------------------+-----------+ | |
| 166 | +| | | ``fexit.s+`` [#fentry]_ | Yes | | |
| 167 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 168 | +| | ``BPF_TRACE_ITER`` | ``iter+`` [#iter]_ | | | |
| 169 | ++ + +----------------------------------+-----------+ | |
| 170 | +| | | ``iter.s+`` [#iter]_ | Yes | | |
| 171 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 172 | +| | ``BPF_TRACE_RAW_TP`` | ``tp_btf+`` [#fentry]_ | | | |
| 173 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 174 | +| ``BPF_PROG_TYPE_XDP`` | ``BPF_XDP_CPUMAP`` | ``xdp.frags/cpumap`` | | | |
| 175 | ++ + +----------------------------------+-----------+ | |
| 176 | +| | | ``xdp/cpumap`` | | | |
| 177 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 178 | +| | ``BPF_XDP_DEVMAP`` | ``xdp.frags/devmap`` | | | |
| 179 | ++ + +----------------------------------+-----------+ | |
| 180 | +| | | ``xdp/devmap`` | | | |
| 181 | ++ +----------------------------------------+----------------------------------+-----------+ | |
| 182 | +| | ``BPF_XDP`` | ``xdp.frags`` | | | |
| 183 | ++ + +----------------------------------+-----------+ | |
| 184 | +| | | ``xdp`` | | | |
| 185 | ++-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | |
| 186 | + | |
| 187 | + | |
| 188 | +.. rubric:: Footnotes | |
| 189 | + | |
| 190 | +.. [#fentry] The ``fentry`` attach format is ``fentry[.s]/<function>``. | |
| 191 | +.. [#kprobe] The ``kprobe`` attach format is ``kprobe/<function>[+<offset>]``. Valid | |
| 192 | + characters for ``function`` are ``a-zA-Z0-9_.`` and ``offset`` must be a valid | |
| 193 | + non-negative integer. | |
| 194 | +.. [#ksyscall] The ``ksyscall`` attach format is ``ksyscall/<syscall>``. | |
| 195 | +.. [#uprobe] The ``uprobe`` attach format is ``uprobe[.s]/<path>:<function>[+<offset>]``. | |
| 196 | +.. [#usdt] The ``usdt`` attach format is ``usdt/<path>:<provider>:<name>``. | |
| 197 | +.. [#kpmulti] The ``kprobe.multi`` attach format is ``kprobe.multi/<pattern>`` where ``pattern`` | |
| 198 | + supports ``*`` and ``?`` wildcards. Valid characters for pattern are | |
| 199 | + ``a-zA-Z0-9_.*?``. | |
| 200 | +.. [#lsm] The ``lsm`` attachment format is ``lsm[.s]/<hook>``. | |
| 201 | +.. [#rawtp] The ``raw_tp`` attach format is ``raw_tracepoint[.w]/<tracepoint>``. | |
| 202 | +.. [#tp] The ``tracepoint`` attach format is ``tracepoint/<category>/<name>``. | |
| 203 | +.. [#iter] The ``iter`` attach format is ``iter[.s]/<struct-name>``. | |
| @@ -0,0 +1,262 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +================================================ | |
| 5 | +BPF_MAP_TYPE_ARRAY and BPF_MAP_TYPE_PERCPU_ARRAY | |
| 6 | +================================================ | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_ARRAY`` was introduced in kernel version 3.19 | |
| 10 | + - ``BPF_MAP_TYPE_PERCPU_ARRAY`` was introduced in version 4.6 | |
| 11 | + | |
| 12 | +``BPF_MAP_TYPE_ARRAY`` and ``BPF_MAP_TYPE_PERCPU_ARRAY`` provide generic array | |
| 13 | +storage. The key type is an unsigned 32-bit integer (4 bytes) and the map is | |
| 14 | +of constant size. The size of the array is defined in ``max_entries`` at | |
| 15 | +creation time. All array elements are pre-allocated and zero initialized when | |
| 16 | +created. ``BPF_MAP_TYPE_PERCPU_ARRAY`` uses a different memory region for each | |
| 17 | +CPU whereas ``BPF_MAP_TYPE_ARRAY`` uses the same memory region. The value | |
| 18 | +stored can be of any size, however, all array elements are aligned to 8 | |
| 19 | +bytes. | |
| 20 | + | |
| 21 | +Since kernel 5.5, memory mapping may be enabled for ``BPF_MAP_TYPE_ARRAY`` by | |
| 22 | +setting the flag ``BPF_F_MMAPABLE``. The map definition is page-aligned and | |
| 23 | +starts on the first page. Sufficient page-sized and page-aligned blocks of | |
| 24 | +memory are allocated to store all array values, starting on the second page, | |
| 25 | +which in some cases will result in over-allocation of memory. The benefit of | |
| 26 | +using this is increased performance and ease of use since userspace programs | |
| 27 | +would not be required to use helper functions to access and mutate data. | |
| 28 | + | |
| 29 | +Usage | |
| 30 | +===== | |
| 31 | + | |
| 32 | +Kernel BPF | |
| 33 | +---------- | |
| 34 | + | |
| 35 | +bpf_map_lookup_elem() | |
| 36 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 37 | + | |
| 38 | +.. code-block:: c | |
| 39 | + | |
| 40 | + void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) | |
| 41 | + | |
| 42 | +Array elements can be retrieved using the ``bpf_map_lookup_elem()`` helper. | |
| 43 | +This helper returns a pointer into the array element, so to avoid data races | |
| 44 | +with userspace reading the value, the user must use primitives like | |
| 45 | +``__sync_fetch_and_add()`` when updating the value in-place. | |
| 46 | + | |
| 47 | +bpf_map_update_elem() | |
| 48 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 49 | + | |
| 50 | +.. code-block:: c | |
| 51 | + | |
| 52 | + long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) | |
| 53 | + | |
| 54 | +Array elements can be updated using the ``bpf_map_update_elem()`` helper. | |
| 55 | + | |
| 56 | +``bpf_map_update_elem()`` returns 0 on success, or negative error in case of | |
| 57 | +failure. | |
| 58 | + | |
| 59 | +Since the array is of constant size, ``bpf_map_delete_elem()`` is not supported. | |
| 60 | +To clear an array element, you may use ``bpf_map_update_elem()`` to insert a | |
| 61 | +zero value to that index. | |
| 62 | + | |
| 63 | +Per CPU Array | |
| 64 | +------------- | |
| 65 | + | |
| 66 | +Values stored in ``BPF_MAP_TYPE_ARRAY`` can be accessed by multiple programs | |
| 67 | +across different CPUs. To restrict storage to a single CPU, you may use a | |
| 68 | +``BPF_MAP_TYPE_PERCPU_ARRAY``. | |
| 69 | + | |
| 70 | +When using a ``BPF_MAP_TYPE_PERCPU_ARRAY`` the ``bpf_map_update_elem()`` and | |
| 71 | +``bpf_map_lookup_elem()`` helpers automatically access the slot for the current | |
| 72 | +CPU. | |
| 73 | + | |
| 74 | +bpf_map_lookup_percpu_elem() | |
| 75 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 76 | + | |
| 77 | +.. code-block:: c | |
| 78 | + | |
| 79 | + void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) | |
| 80 | + | |
| 81 | +The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the array | |
| 82 | +value for a specific CPU. Returns value on success , or ``NULL`` if no entry was | |
| 83 | +found or ``cpu`` is invalid. | |
| 84 | + | |
| 85 | +Concurrency | |
| 86 | +----------- | |
| 87 | + | |
| 88 | +Since kernel version 5.1, the BPF infrastructure provides ``struct bpf_spin_lock`` | |
| 89 | +to synchronize access. | |
| 90 | + | |
| 91 | +Userspace | |
| 92 | +--------- | |
| 93 | + | |
| 94 | +Access from userspace uses libbpf APIs with the same names as above, with | |
| 95 | +the map identified by its ``fd``. | |
| 96 | + | |
| 97 | +Examples | |
| 98 | +======== | |
| 99 | + | |
| 100 | +Please see the ``tools/testing/selftests/bpf`` directory for functional | |
| 101 | +examples. The code samples below demonstrate API usage. | |
| 102 | + | |
| 103 | +Kernel BPF | |
| 104 | +---------- | |
| 105 | + | |
| 106 | +This snippet shows how to declare an array in a BPF program. | |
| 107 | + | |
| 108 | +.. code-block:: c | |
| 109 | + | |
| 110 | + struct { | |
| 111 | + __uint(type, BPF_MAP_TYPE_ARRAY); | |
| 112 | + __type(key, u32); | |
| 113 | + __type(value, long); | |
| 114 | + __uint(max_entries, 256); | |
| 115 | + } my_map SEC(".maps"); | |
| 116 | + | |
| 117 | + | |
| 118 | +This example BPF program shows how to access an array element. | |
| 119 | + | |
| 120 | +.. code-block:: c | |
| 121 | + | |
| 122 | + int bpf_prog(struct __sk_buff *skb) | |
| 123 | + { | |
| 124 | + struct iphdr ip; | |
| 125 | + int index; | |
| 126 | + long *value; | |
| 127 | + | |
| 128 | + if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip, sizeof(ip)) < 0) | |
| 129 | + return 0; | |
| 130 | + | |
| 131 | + index = ip.protocol; | |
| 132 | + value = bpf_map_lookup_elem(&my_map, &index); | |
| 133 | + if (value) | |
| 134 | + __sync_fetch_and_add(value, skb->len); | |
| 135 | + | |
| 136 | + return 0; | |
| 137 | + } | |
| 138 | + | |
| 139 | +Userspace | |
| 140 | +--------- | |
| 141 | + | |
| 142 | +BPF_MAP_TYPE_ARRAY | |
| 143 | +~~~~~~~~~~~~~~~~~~ | |
| 144 | + | |
| 145 | +This snippet shows how to create an array, using ``bpf_map_create_opts`` to | |
| 146 | +set flags. | |
| 147 | + | |
| 148 | +.. code-block:: c | |
| 149 | + | |
| 150 | + #include <bpf/libbpf.h> | |
| 151 | + #include <bpf/bpf.h> | |
| 152 | + | |
| 153 | + int create_array() | |
| 154 | + { | |
| 155 | + int fd; | |
| 156 | + LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE); | |
| 157 | + | |
| 158 | + fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, | |
| 159 | + "example_array", /* name */ | |
| 160 | + sizeof(__u32), /* key size */ | |
| 161 | + sizeof(long), /* value size */ | |
| 162 | + 256, /* max entries */ | |
| 163 | + &opts); /* create opts */ | |
| 164 | + return fd; | |
| 165 | + } | |
| 166 | + | |
| 167 | +This snippet shows how to initialize the elements of an array. | |
| 168 | + | |
| 169 | +.. code-block:: c | |
| 170 | + | |
| 171 | + int initialize_array(int fd) | |
| 172 | + { | |
| 173 | + __u32 i; | |
| 174 | + long value; | |
| 175 | + int ret; | |
| 176 | + | |
| 177 | + for (i = 0; i < 256; i++) { | |
| 178 | + value = i; | |
| 179 | + ret = bpf_map_update_elem(fd, &i, &value, BPF_ANY); | |
| 180 | + if (ret < 0) | |
| 181 | + return ret; | |
| 182 | + } | |
| 183 | + | |
| 184 | + return ret; | |
| 185 | + } | |
| 186 | + | |
| 187 | +This snippet shows how to retrieve an element value from an array. | |
| 188 | + | |
| 189 | +.. code-block:: c | |
| 190 | + | |
| 191 | + int lookup(int fd) | |
| 192 | + { | |
| 193 | + __u32 index = 42; | |
| 194 | + long value; | |
| 195 | + int ret; | |
| 196 | + | |
| 197 | + ret = bpf_map_lookup_elem(fd, &index, &value); | |
| 198 | + if (ret < 0) | |
| 199 | + return ret; | |
| 200 | + | |
| 201 | + /* use value here */ | |
| 202 | + assert(value == 42); | |
| 203 | + | |
| 204 | + return ret; | |
| 205 | + } | |
| 206 | + | |
| 207 | +BPF_MAP_TYPE_PERCPU_ARRAY | |
| 208 | +~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 209 | + | |
| 210 | +This snippet shows how to initialize the elements of a per CPU array. | |
| 211 | + | |
| 212 | +.. code-block:: c | |
| 213 | + | |
| 214 | + int initialize_array(int fd) | |
| 215 | + { | |
| 216 | + int ncpus = libbpf_num_possible_cpus(); | |
| 217 | + long values[ncpus]; | |
| 218 | + __u32 i, j; | |
| 219 | + int ret; | |
| 220 | + | |
| 221 | + for (i = 0; i < 256 ; i++) { | |
| 222 | + for (j = 0; j < ncpus; j++) | |
| 223 | + values[j] = i; | |
| 224 | + ret = bpf_map_update_elem(fd, &i, &values, BPF_ANY); | |
| 225 | + if (ret < 0) | |
| 226 | + return ret; | |
| 227 | + } | |
| 228 | + | |
| 229 | + return ret; | |
| 230 | + } | |
| 231 | + | |
| 232 | +This snippet shows how to access the per CPU elements of an array value. | |
| 233 | + | |
| 234 | +.. code-block:: c | |
| 235 | + | |
| 236 | + int lookup(int fd) | |
| 237 | + { | |
| 238 | + int ncpus = libbpf_num_possible_cpus(); | |
| 239 | + __u32 index = 42, j; | |
| 240 | + long values[ncpus]; | |
| 241 | + int ret; | |
| 242 | + | |
| 243 | + ret = bpf_map_lookup_elem(fd, &index, &values); | |
| 244 | + if (ret < 0) | |
| 245 | + return ret; | |
| 246 | + | |
| 247 | + for (j = 0; j < ncpus; j++) { | |
| 248 | + /* Use per CPU value here */ | |
| 249 | + assert(values[j] == 42); | |
| 250 | + } | |
| 251 | + | |
| 252 | + return ret; | |
| 253 | + } | |
| 254 | + | |
| 255 | +Semantics | |
| 256 | +========= | |
| 257 | + | |
| 258 | +As shown in the example above, when accessing a ``BPF_MAP_TYPE_PERCPU_ARRAY`` | |
| 259 | +in userspace, each value is an array with ``ncpus`` elements. | |
| 260 | + | |
| 261 | +When calling ``bpf_map_update_elem()`` the flag ``BPF_NOEXIST`` can not be used | |
| 262 | +for these maps. | |
| @@ -0,0 +1,174 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +========================= | |
| 5 | +BPF_MAP_TYPE_BLOOM_FILTER | |
| 6 | +========================= | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_BLOOM_FILTER`` was introduced in kernel version 5.16 | |
| 10 | + | |
| 11 | +``BPF_MAP_TYPE_BLOOM_FILTER`` provides a BPF bloom filter map. Bloom | |
| 12 | +filters are a space-efficient probabilistic data structure used to | |
| 13 | +quickly test whether an element exists in a set. In a bloom filter, | |
| 14 | +false positives are possible whereas false negatives are not. | |
| 15 | + | |
| 16 | +The bloom filter map does not have keys, only values. When the bloom | |
| 17 | +filter map is created, it must be created with a ``key_size`` of 0. The | |
| 18 | +bloom filter map supports two operations: | |
| 19 | + | |
| 20 | +- push: adding an element to the map | |
| 21 | +- peek: determining whether an element is present in the map | |
| 22 | + | |
| 23 | +BPF programs must use ``bpf_map_push_elem`` to add an element to the | |
| 24 | +bloom filter map and ``bpf_map_peek_elem`` to query the map. These | |
| 25 | +operations are exposed to userspace applications using the existing | |
| 26 | +``bpf`` syscall in the following way: | |
| 27 | + | |
| 28 | +- ``BPF_MAP_UPDATE_ELEM`` -> push | |
| 29 | +- ``BPF_MAP_LOOKUP_ELEM`` -> peek | |
| 30 | + | |
| 31 | +The ``max_entries`` size that is specified at map creation time is used | |
| 32 | +to approximate a reasonable bitmap size for the bloom filter, and is not | |
| 33 | +otherwise strictly enforced. If the user wishes to insert more entries | |
| 34 | +into the bloom filter than ``max_entries``, this may lead to a higher | |
| 35 | +false positive rate. | |
| 36 | + | |
| 37 | +The number of hashes to use for the bloom filter is configurable using | |
| 38 | +the lower 4 bits of ``map_extra`` in ``union bpf_attr`` at map creation | |
| 39 | +time. If no number is specified, the default used will be 5 hash | |
| 40 | +functions. In general, using more hashes decreases both the false | |
| 41 | +positive rate and the speed of a lookup. | |
| 42 | + | |
| 43 | +It is not possible to delete elements from a bloom filter map. A bloom | |
| 44 | +filter map may be used as an inner map. The user is responsible for | |
| 45 | +synchronising concurrent updates and lookups to ensure no false negative | |
| 46 | +lookups occur. | |
| 47 | + | |
| 48 | +Usage | |
| 49 | +===== | |
| 50 | + | |
| 51 | +Kernel BPF | |
| 52 | +---------- | |
| 53 | + | |
| 54 | +bpf_map_push_elem() | |
| 55 | +~~~~~~~~~~~~~~~~~~~ | |
| 56 | + | |
| 57 | +.. code-block:: c | |
| 58 | + | |
| 59 | + long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags) | |
| 60 | + | |
| 61 | +A ``value`` can be added to a bloom filter using the | |
| 62 | +``bpf_map_push_elem()`` helper. The ``flags`` parameter must be set to | |
| 63 | +``BPF_ANY`` when adding an entry to the bloom filter. This helper | |
| 64 | +returns ``0`` on success, or negative error in case of failure. | |
| 65 | + | |
| 66 | +bpf_map_peek_elem() | |
| 67 | +~~~~~~~~~~~~~~~~~~~ | |
| 68 | + | |
| 69 | +.. code-block:: c | |
| 70 | + | |
| 71 | + long bpf_map_peek_elem(struct bpf_map *map, void *value) | |
| 72 | + | |
| 73 | +The ``bpf_map_peek_elem()`` helper is used to determine whether | |
| 74 | +``value`` is present in the bloom filter map. This helper returns ``0`` | |
| 75 | +if ``value`` is probably present in the map, or ``-ENOENT`` if ``value`` | |
| 76 | +is definitely not present in the map. | |
| 77 | + | |
| 78 | +Userspace | |
| 79 | +--------- | |
| 80 | + | |
| 81 | +bpf_map_update_elem() | |
| 82 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 83 | + | |
| 84 | +.. code-block:: c | |
| 85 | + | |
| 86 | + int bpf_map_update_elem (int fd, const void *key, const void *value, __u64 flags) | |
| 87 | + | |
| 88 | +A userspace program can add a ``value`` to a bloom filter using libbpf's | |
| 89 | +``bpf_map_update_elem`` function. The ``key`` parameter must be set to | |
| 90 | +``NULL`` and ``flags`` must be set to ``BPF_ANY``. Returns ``0`` on | |
| 91 | +success, or negative error in case of failure. | |
| 92 | + | |
| 93 | +bpf_map_lookup_elem() | |
| 94 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 95 | + | |
| 96 | +.. code-block:: c | |
| 97 | + | |
| 98 | + int bpf_map_lookup_elem (int fd, const void *key, void *value) | |
| 99 | + | |
| 100 | +A userspace program can determine the presence of ``value`` in a bloom | |
| 101 | +filter using libbpf's ``bpf_map_lookup_elem`` function. The ``key`` | |
| 102 | +parameter must be set to ``NULL``. Returns ``0`` if ``value`` is | |
| 103 | +probably present in the map, or ``-ENOENT`` if ``value`` is definitely | |
| 104 | +not present in the map. | |
| 105 | + | |
| 106 | +Examples | |
| 107 | +======== | |
| 108 | + | |
| 109 | +Kernel BPF | |
| 110 | +---------- | |
| 111 | + | |
| 112 | +This snippet shows how to declare a bloom filter in a BPF program: | |
| 113 | + | |
| 114 | +.. code-block:: c | |
| 115 | + | |
| 116 | + struct { | |
| 117 | + __uint(type, BPF_MAP_TYPE_BLOOM_FILTER); | |
| 118 | + __type(value, __u32); | |
| 119 | + __uint(max_entries, 1000); | |
| 120 | + __uint(map_extra, 3); | |
| 121 | + } bloom_filter SEC(".maps"); | |
| 122 | + | |
| 123 | +This snippet shows how to determine presence of a value in a bloom | |
| 124 | +filter in a BPF program: | |
| 125 | + | |
| 126 | +.. code-block:: c | |
| 127 | + | |
| 128 | + void *lookup(__u32 key) | |
| 129 | + { | |
| 130 | + if (bpf_map_peek_elem(&bloom_filter, &key) == 0) { | |
| 131 | + /* Verify not a false positive and fetch an associated | |
| 132 | + * value using a secondary lookup, e.g. in a hash table | |
| 133 | + */ | |
| 134 | + return bpf_map_lookup_elem(&hash_table, &key); | |
| 135 | + } | |
| 136 | + return 0; | |
| 137 | + } | |
| 138 | + | |
| 139 | +Userspace | |
| 140 | +--------- | |
| 141 | + | |
| 142 | +This snippet shows how to use libbpf to create a bloom filter map from | |
| 143 | +userspace: | |
| 144 | + | |
| 145 | +.. code-block:: c | |
| 146 | + | |
| 147 | + int create_bloom() | |
| 148 | + { | |
| 149 | + LIBBPF_OPTS(bpf_map_create_opts, opts, | |
| 150 | + .map_extra = 3); /* number of hashes */ | |
| 151 | + | |
| 152 | + return bpf_map_create(BPF_MAP_TYPE_BLOOM_FILTER, | |
| 153 | + "ipv6_bloom", /* name */ | |
| 154 | + 0, /* key size, must be zero */ | |
| 155 | + sizeof(ipv6_addr), /* value size */ | |
| 156 | + 10000, /* max entries */ | |
| 157 | + &opts); /* create options */ | |
| 158 | + } | |
| 159 | + | |
| 160 | +This snippet shows how to add an element to a bloom filter from | |
| 161 | +userspace: | |
| 162 | + | |
| 163 | +.. code-block:: c | |
| 164 | + | |
| 165 | + int add_element(struct bpf_map *bloom_map, __u32 value) | |
| 166 | + { | |
| 167 | + int bloom_fd = bpf_map__fd(bloom_map); | |
| 168 | + return bpf_map_update_elem(bloom_fd, NULL, &value, BPF_ANY); | |
| 169 | + } | |
| 170 | + | |
| 171 | +References | |
| 172 | +========== | |
| 173 | + | |
| 174 | +https://lwn.net/ml/bpf/20210831225005.2762202-1-joannekoong@fb.com/ | |
| @@ -0,0 +1,109 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Meta Platforms, Inc. and affiliates. | |
| 3 | + | |
| 4 | +========================= | |
| 5 | +BPF_MAP_TYPE_CGRP_STORAGE | |
| 6 | +========================= | |
| 7 | + | |
| 8 | +The ``BPF_MAP_TYPE_CGRP_STORAGE`` map type represents a local fix-sized | |
| 9 | +storage for cgroups. It is only available with ``CONFIG_CGROUPS``. | |
| 10 | +The programs are made available by the same Kconfig. The | |
| 11 | +data for a particular cgroup can be retrieved by looking up the map | |
| 12 | +with that cgroup. | |
| 13 | + | |
| 14 | +This document describes the usage and semantics of the | |
| 15 | +``BPF_MAP_TYPE_CGRP_STORAGE`` map type. | |
| 16 | + | |
| 17 | +Usage | |
| 18 | +===== | |
| 19 | + | |
| 20 | +The map key must be ``sizeof(int)`` representing a cgroup fd. | |
| 21 | +To access the storage in a program, use ``bpf_cgrp_storage_get``:: | |
| 22 | + | |
| 23 | + void *bpf_cgrp_storage_get(struct bpf_map *map, struct cgroup *cgroup, void *value, u64 flags) | |
| 24 | + | |
| 25 | +``flags`` could be 0 or ``BPF_LOCAL_STORAGE_GET_F_CREATE`` which indicates that | |
| 26 | +a new local storage will be created if one does not exist. | |
| 27 | + | |
| 28 | +The local storage can be removed with ``bpf_cgrp_storage_delete``:: | |
| 29 | + | |
| 30 | + long bpf_cgrp_storage_delete(struct bpf_map *map, struct cgroup *cgroup) | |
| 31 | + | |
| 32 | +The map is available to all program types. | |
| 33 | + | |
| 34 | +Examples | |
| 35 | +======== | |
| 36 | + | |
| 37 | +A BPF program example with BPF_MAP_TYPE_CGRP_STORAGE:: | |
| 38 | + | |
| 39 | + #include <vmlinux.h> | |
| 40 | + #include <bpf/bpf_helpers.h> | |
| 41 | + #include <bpf/bpf_tracing.h> | |
| 42 | + | |
| 43 | + struct { | |
| 44 | + __uint(type, BPF_MAP_TYPE_CGRP_STORAGE); | |
| 45 | + __uint(map_flags, BPF_F_NO_PREALLOC); | |
| 46 | + __type(key, int); | |
| 47 | + __type(value, long); | |
| 48 | + } cgrp_storage SEC(".maps"); | |
| 49 | + | |
| 50 | + SEC("tp_btf/sys_enter") | |
| 51 | + int BPF_PROG(on_enter, struct pt_regs *regs, long id) | |
| 52 | + { | |
| 53 | + struct task_struct *task = bpf_get_current_task_btf(); | |
| 54 | + long *ptr; | |
| 55 | + | |
| 56 | + ptr = bpf_cgrp_storage_get(&cgrp_storage, task->cgroups->dfl_cgrp, 0, | |
| 57 | + BPF_LOCAL_STORAGE_GET_F_CREATE); | |
| 58 | + if (ptr) | |
| 59 | + __sync_fetch_and_add(ptr, 1); | |
| 60 | + | |
| 61 | + return 0; | |
| 62 | + } | |
| 63 | + | |
| 64 | +Userspace accessing map declared above:: | |
| 65 | + | |
| 66 | + #include <linux/bpf.h> | |
| 67 | + #include <linux/libbpf.h> | |
| 68 | + | |
| 69 | + __u32 map_lookup(struct bpf_map *map, int cgrp_fd) | |
| 70 | + { | |
| 71 | + __u32 *value; | |
| 72 | + value = bpf_map_lookup_elem(bpf_map__fd(map), &cgrp_fd); | |
| 73 | + if (value) | |
| 74 | + return *value; | |
| 75 | + return 0; | |
| 76 | + } | |
| 77 | + | |
| 78 | +Difference Between BPF_MAP_TYPE_CGRP_STORAGE and BPF_MAP_TYPE_CGROUP_STORAGE | |
| 79 | +============================================================================ | |
| 80 | + | |
| 81 | +The old cgroup storage map ``BPF_MAP_TYPE_CGROUP_STORAGE`` has been marked as | |
| 82 | +deprecated (renamed to ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED``). The new | |
| 83 | +``BPF_MAP_TYPE_CGRP_STORAGE`` map should be used instead. The following | |
| 84 | +illusates the main difference between ``BPF_MAP_TYPE_CGRP_STORAGE`` and | |
| 85 | +``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED``. | |
| 86 | + | |
| 87 | +(1). ``BPF_MAP_TYPE_CGRP_STORAGE`` can be used by all program types while | |
| 88 | + ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED`` is available only to cgroup program types | |
| 89 | + like BPF_CGROUP_INET_INGRESS or BPF_CGROUP_SOCK_OPS, etc. | |
| 90 | + | |
| 91 | +(2). ``BPF_MAP_TYPE_CGRP_STORAGE`` supports local storage for more than one | |
| 92 | + cgroup while ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED`` only supports one cgroup | |
| 93 | + which is attached by a BPF program. | |
| 94 | + | |
| 95 | +(3). ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED`` allocates local storage at attach time so | |
| 96 | + ``bpf_get_local_storage()`` always returns non-NULL local storage. | |
| 97 | + ``BPF_MAP_TYPE_CGRP_STORAGE`` allocates local storage at runtime so | |
| 98 | + it is possible that ``bpf_cgrp_storage_get()`` may return null local storage. | |
| 99 | + To avoid such null local storage issue, user space can do | |
| 100 | + ``bpf_map_update_elem()`` to pre-allocate local storage before a BPF program | |
| 101 | + is attached. | |
| 102 | + | |
| 103 | +(4). ``BPF_MAP_TYPE_CGRP_STORAGE`` supports deleting local storage by a BPF program | |
| 104 | + while ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED`` only deletes storage during | |
| 105 | + prog detach time. | |
| 106 | + | |
| 107 | +So overall, ``BPF_MAP_TYPE_CGRP_STORAGE`` supports all ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED`` | |
| 108 | +functionality and beyond. It is recommended to use ``BPF_MAP_TYPE_CGRP_STORAGE`` | |
| 109 | +instead of ``BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED``. | |
| @@ -0,0 +1,177 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +=================== | |
| 5 | +BPF_MAP_TYPE_CPUMAP | |
| 6 | +=================== | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_CPUMAP`` was introduced in kernel version 4.15 | |
| 10 | + | |
| 11 | +.. kernel-doc:: kernel/bpf/cpumap.c | |
| 12 | + :doc: cpu map | |
| 13 | + | |
| 14 | +An example use-case for this map type is software based Receive Side Scaling (RSS). | |
| 15 | + | |
| 16 | +The CPUMAP represents the CPUs in the system indexed as the map-key, and the | |
| 17 | +map-value is the config setting (per CPUMAP entry). Each CPUMAP entry has a dedicated | |
| 18 | +kernel thread bound to the given CPU to represent the remote CPU execution unit. | |
| 19 | + | |
| 20 | +Starting from Linux kernel version 5.9 the CPUMAP can run a second XDP program | |
| 21 | +on the remote CPU. This allows an XDP program to split its processing across | |
| 22 | +multiple CPUs. For example, a scenario where the initial CPU (that sees/receives | |
| 23 | +the packets) needs to do minimal packet processing and the remote CPU (to which | |
| 24 | +the packet is directed) can afford to spend more cycles processing the frame. The | |
| 25 | +initial CPU is where the XDP redirect program is executed. The remote CPU | |
| 26 | +receives raw ``xdp_frame`` objects. | |
| 27 | + | |
| 28 | +Usage | |
| 29 | +===== | |
| 30 | + | |
| 31 | +Kernel BPF | |
| 32 | +---------- | |
| 33 | +bpf_redirect_map() | |
| 34 | +^^^^^^^^^^^^^^^^^^ | |
| 35 | +.. code-block:: c | |
| 36 | + | |
| 37 | + long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags) | |
| 38 | + | |
| 39 | +Redirect the packet to the endpoint referenced by ``map`` at index ``key``. | |
| 40 | +For ``BPF_MAP_TYPE_CPUMAP`` this map contains references to CPUs. | |
| 41 | + | |
| 42 | +The lower two bits of ``flags`` are used as the return code if the map lookup | |
| 43 | +fails. This is so that the return value can be one of the XDP program return | |
| 44 | +codes up to ``XDP_TX``, as chosen by the caller. | |
| 45 | + | |
| 46 | +User space | |
| 47 | +---------- | |
| 48 | +.. note:: | |
| 49 | + CPUMAP entries can only be updated/looked up/deleted from user space and not | |
| 50 | + from an eBPF program. Trying to call these functions from a kernel eBPF | |
| 51 | + program will result in the program failing to load and a verifier warning. | |
| 52 | + | |
| 53 | +bpf_map_update_elem() | |
| 54 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 55 | +.. code-block:: c | |
| 56 | + | |
| 57 | + int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags); | |
| 58 | + | |
| 59 | +CPU entries can be added or updated using the ``bpf_map_update_elem()`` | |
| 60 | +helper. This helper replaces existing elements atomically. The ``value`` parameter | |
| 61 | +can be ``struct bpf_cpumap_val``. | |
| 62 | + | |
| 63 | + .. code-block:: c | |
| 64 | + | |
| 65 | + struct bpf_cpumap_val { | |
| 66 | + __u32 qsize; /* queue size to remote target CPU */ | |
| 67 | + union { | |
| 68 | + int fd; /* prog fd on map write */ | |
| 69 | + __u32 id; /* prog id on map read */ | |
| 70 | + } bpf_prog; | |
| 71 | + }; | |
| 72 | + | |
| 73 | +The flags argument can be one of the following: | |
| 74 | + - BPF_ANY: Create a new element or update an existing element. | |
| 75 | + - BPF_NOEXIST: Create a new element only if it did not exist. | |
| 76 | + - BPF_EXIST: Update an existing element. | |
| 77 | + | |
| 78 | +bpf_map_lookup_elem() | |
| 79 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 80 | +.. code-block:: c | |
| 81 | + | |
| 82 | + int bpf_map_lookup_elem(int fd, const void *key, void *value); | |
| 83 | + | |
| 84 | +CPU entries can be retrieved using the ``bpf_map_lookup_elem()`` | |
| 85 | +helper. | |
| 86 | + | |
| 87 | +bpf_map_delete_elem() | |
| 88 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 89 | +.. code-block:: c | |
| 90 | + | |
| 91 | + int bpf_map_delete_elem(int fd, const void *key); | |
| 92 | + | |
| 93 | +CPU entries can be deleted using the ``bpf_map_delete_elem()`` | |
| 94 | +helper. This helper will return 0 on success, or negative error in case of | |
| 95 | +failure. | |
| 96 | + | |
| 97 | +Examples | |
| 98 | +======== | |
| 99 | +Kernel | |
| 100 | +------ | |
| 101 | + | |
| 102 | +The following code snippet shows how to declare a ``BPF_MAP_TYPE_CPUMAP`` called | |
| 103 | +``cpu_map`` and how to redirect packets to a remote CPU using a round robin scheme. | |
| 104 | + | |
| 105 | +.. code-block:: c | |
| 106 | + | |
| 107 | + struct { | |
| 108 | + __uint(type, BPF_MAP_TYPE_CPUMAP); | |
| 109 | + __type(key, __u32); | |
| 110 | + __type(value, struct bpf_cpumap_val); | |
| 111 | + __uint(max_entries, 12); | |
| 112 | + } cpu_map SEC(".maps"); | |
| 113 | + | |
| 114 | + struct { | |
| 115 | + __uint(type, BPF_MAP_TYPE_ARRAY); | |
| 116 | + __type(key, __u32); | |
| 117 | + __type(value, __u32); | |
| 118 | + __uint(max_entries, 12); | |
| 119 | + } cpus_available SEC(".maps"); | |
| 120 | + | |
| 121 | + struct { | |
| 122 | + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | |
| 123 | + __type(key, __u32); | |
| 124 | + __type(value, __u32); | |
| 125 | + __uint(max_entries, 1); | |
| 126 | + } cpus_iterator SEC(".maps"); | |
| 127 | + | |
| 128 | + SEC("xdp") | |
| 129 | + int xdp_redir_cpu_round_robin(struct xdp_md *ctx) | |
| 130 | + { | |
| 131 | + __u32 key = 0; | |
| 132 | + __u32 cpu_dest = 0; | |
| 133 | + __u32 *cpu_selected, *cpu_iterator; | |
| 134 | + __u32 cpu_idx; | |
| 135 | + | |
| 136 | + cpu_iterator = bpf_map_lookup_elem(&cpus_iterator, &key); | |
| 137 | + if (!cpu_iterator) | |
| 138 | + return XDP_ABORTED; | |
| 139 | + cpu_idx = *cpu_iterator; | |
| 140 | + | |
| 141 | + *cpu_iterator += 1; | |
| 142 | + if (*cpu_iterator == bpf_num_possible_cpus()) | |
| 143 | + *cpu_iterator = 0; | |
| 144 | + | |
| 145 | + cpu_selected = bpf_map_lookup_elem(&cpus_available, &cpu_idx); | |
| 146 | + if (!cpu_selected) | |
| 147 | + return XDP_ABORTED; | |
| 148 | + cpu_dest = *cpu_selected; | |
| 149 | + | |
| 150 | + if (cpu_dest >= bpf_num_possible_cpus()) | |
| 151 | + return XDP_ABORTED; | |
| 152 | + | |
| 153 | + return bpf_redirect_map(&cpu_map, cpu_dest, 0); | |
| 154 | + } | |
| 155 | + | |
| 156 | +User space | |
| 157 | +---------- | |
| 158 | + | |
| 159 | +The following code snippet shows how to dynamically set the max_entries for a | |
| 160 | +CPUMAP to the max number of cpus available on the system. | |
| 161 | + | |
| 162 | +.. code-block:: c | |
| 163 | + | |
| 164 | + int set_max_cpu_entries(struct bpf_map *cpu_map) | |
| 165 | + { | |
| 166 | + if (bpf_map__set_max_entries(cpu_map, libbpf_num_possible_cpus()) < 0) { | |
| 167 | + fprintf(stderr, "Failed to set max entries for cpu_map map: %s", | |
| 168 | + strerror(errno)); | |
| 169 | + return -1; | |
| 170 | + } | |
| 171 | + return 0; | |
| 172 | + } | |
| 173 | + | |
| 174 | +References | |
| 175 | +=========== | |
| 176 | + | |
| 177 | +- https://developers.redhat.com/blog/2021/05/13/receive-side-scaling-rss-with-ebpf-and-cpumap#redirecting_into_a_cpumap | |
| @@ -0,0 +1,238 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +================================================= | |
| 5 | +BPF_MAP_TYPE_DEVMAP and BPF_MAP_TYPE_DEVMAP_HASH | |
| 6 | +================================================= | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_DEVMAP`` was introduced in kernel version 4.14 | |
| 10 | + - ``BPF_MAP_TYPE_DEVMAP_HASH`` was introduced in kernel version 5.4 | |
| 11 | + | |
| 12 | +``BPF_MAP_TYPE_DEVMAP`` and ``BPF_MAP_TYPE_DEVMAP_HASH`` are BPF maps primarily | |
| 13 | +used as backend maps for the XDP BPF helper call ``bpf_redirect_map()``. | |
| 14 | +``BPF_MAP_TYPE_DEVMAP`` is backed by an array that uses the key as | |
| 15 | +the index to lookup a reference to a net device. While ``BPF_MAP_TYPE_DEVMAP_HASH`` | |
| 16 | +is backed by a hash table that uses a key to lookup a reference to a net device. | |
| 17 | +The user provides either <``key``/ ``ifindex``> or <``key``/ ``struct bpf_devmap_val``> | |
| 18 | +pairs to update the maps with new net devices. | |
| 19 | + | |
| 20 | +.. note:: | |
| 21 | + - The key to a hash map doesn't have to be an ``ifindex``. | |
| 22 | + - While ``BPF_MAP_TYPE_DEVMAP_HASH`` allows for densely packing the net devices | |
| 23 | + it comes at the cost of a hash of the key when performing a look up. | |
| 24 | + | |
| 25 | +The setup and packet enqueue/send code is shared between the two types of | |
| 26 | +devmap; only the lookup and insertion is different. | |
| 27 | + | |
| 28 | +Usage | |
| 29 | +===== | |
| 30 | +Kernel BPF | |
| 31 | +---------- | |
| 32 | +bpf_redirect_map() | |
| 33 | +^^^^^^^^^^^^^^^^^^ | |
| 34 | +.. code-block:: c | |
| 35 | + | |
| 36 | + long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags) | |
| 37 | + | |
| 38 | +Redirect the packet to the endpoint referenced by ``map`` at index ``key``. | |
| 39 | +For ``BPF_MAP_TYPE_DEVMAP`` and ``BPF_MAP_TYPE_DEVMAP_HASH`` this map contains | |
| 40 | +references to net devices (for forwarding packets through other ports). | |
| 41 | + | |
| 42 | +The lower two bits of *flags* are used as the return code if the map lookup | |
| 43 | +fails. This is so that the return value can be one of the XDP program return | |
| 44 | +codes up to ``XDP_TX``, as chosen by the caller. The higher bits of ``flags`` | |
| 45 | +can be set to ``BPF_F_BROADCAST`` or ``BPF_F_EXCLUDE_INGRESS`` as defined | |
| 46 | +below. | |
| 47 | + | |
| 48 | +With ``BPF_F_BROADCAST`` the packet will be broadcast to all the interfaces | |
| 49 | +in the map, with ``BPF_F_EXCLUDE_INGRESS`` the ingress interface will be excluded | |
| 50 | +from the broadcast. | |
| 51 | + | |
| 52 | +.. note:: | |
| 53 | + - The key is ignored if BPF_F_BROADCAST is set. | |
| 54 | + - The broadcast feature can also be used to implement multicast forwarding: | |
| 55 | + simply create multiple DEVMAPs, each one corresponding to a single multicast group. | |
| 56 | + | |
| 57 | +This helper will return ``XDP_REDIRECT`` on success, or the value of the two | |
| 58 | +lower bits of the ``flags`` argument if the map lookup fails. | |
| 59 | + | |
| 60 | +More information about redirection can be found :doc:`redirect` | |
| 61 | + | |
| 62 | +bpf_map_lookup_elem() | |
| 63 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 64 | +.. code-block:: c | |
| 65 | + | |
| 66 | + void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) | |
| 67 | + | |
| 68 | +Net device entries can be retrieved using the ``bpf_map_lookup_elem()`` | |
| 69 | +helper. | |
| 70 | + | |
| 71 | +User space | |
| 72 | +---------- | |
| 73 | +.. note:: | |
| 74 | + DEVMAP entries can only be updated/deleted from user space and not | |
| 75 | + from an eBPF program. Trying to call these functions from a kernel eBPF | |
| 76 | + program will result in the program failing to load and a verifier warning. | |
| 77 | + | |
| 78 | +bpf_map_update_elem() | |
| 79 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 80 | +.. code-block:: c | |
| 81 | + | |
| 82 | + int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags); | |
| 83 | + | |
| 84 | +Net device entries can be added or updated using the ``bpf_map_update_elem()`` | |
| 85 | +helper. This helper replaces existing elements atomically. The ``value`` parameter | |
| 86 | +can be ``struct bpf_devmap_val`` or a simple ``int ifindex`` for backwards | |
| 87 | +compatibility. | |
| 88 | + | |
| 89 | + .. code-block:: c | |
| 90 | + | |
| 91 | + struct bpf_devmap_val { | |
| 92 | + __u32 ifindex; /* device index */ | |
| 93 | + union { | |
| 94 | + int fd; /* prog fd on map write */ | |
| 95 | + __u32 id; /* prog id on map read */ | |
| 96 | + } bpf_prog; | |
| 97 | + }; | |
| 98 | + | |
| 99 | +The ``flags`` argument can be one of the following: | |
| 100 | + - ``BPF_ANY``: Create a new element or update an existing element. | |
| 101 | + - ``BPF_NOEXIST``: Create a new element only if it did not exist. | |
| 102 | + - ``BPF_EXIST``: Update an existing element. | |
| 103 | + | |
| 104 | +DEVMAPs can associate a program with a device entry by adding a ``bpf_prog.fd`` | |
| 105 | +to ``struct bpf_devmap_val``. Programs are run after ``XDP_REDIRECT`` and have | |
| 106 | +access to both Rx device and Tx device. The program associated with the ``fd`` | |
| 107 | +must have type XDP with expected attach type ``xdp_devmap``. | |
| 108 | +When a program is associated with a device index, the program is run on an | |
| 109 | +``XDP_REDIRECT`` and before the buffer is added to the per-cpu queue. Examples | |
| 110 | +of how to attach/use xdp_devmap progs can be found in the kernel selftests: | |
| 111 | + | |
| 112 | +- ``tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c`` | |
| 113 | +- ``tools/testing/selftests/bpf/progs/test_xdp_with_devmap_helpers.c`` | |
| 114 | + | |
| 115 | +bpf_map_lookup_elem() | |
| 116 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 117 | +.. code-block:: c | |
| 118 | + | |
| 119 | +.. c:function:: | |
| 120 | + int bpf_map_lookup_elem(int fd, const void *key, void *value); | |
| 121 | + | |
| 122 | +Net device entries can be retrieved using the ``bpf_map_lookup_elem()`` | |
| 123 | +helper. | |
| 124 | + | |
| 125 | +bpf_map_delete_elem() | |
| 126 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 127 | +.. code-block:: c | |
| 128 | + | |
| 129 | +.. c:function:: | |
| 130 | + int bpf_map_delete_elem(int fd, const void *key); | |
| 131 | + | |
| 132 | +Net device entries can be deleted using the ``bpf_map_delete_elem()`` | |
| 133 | +helper. This helper will return 0 on success, or negative error in case of | |
| 134 | +failure. | |
| 135 | + | |
| 136 | +Examples | |
| 137 | +======== | |
| 138 | + | |
| 139 | +Kernel BPF | |
| 140 | +---------- | |
| 141 | + | |
| 142 | +The following code snippet shows how to declare a ``BPF_MAP_TYPE_DEVMAP`` | |
| 143 | +called tx_port. | |
| 144 | + | |
| 145 | +.. code-block:: c | |
| 146 | + | |
| 147 | + struct { | |
| 148 | + __uint(type, BPF_MAP_TYPE_DEVMAP); | |
| 149 | + __type(key, __u32); | |
| 150 | + __type(value, __u32); | |
| 151 | + __uint(max_entries, 256); | |
| 152 | + } tx_port SEC(".maps"); | |
| 153 | + | |
| 154 | +The following code snippet shows how to declare a ``BPF_MAP_TYPE_DEVMAP_HASH`` | |
| 155 | +called forward_map. | |
| 156 | + | |
| 157 | +.. code-block:: c | |
| 158 | + | |
| 159 | + struct { | |
| 160 | + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); | |
| 161 | + __type(key, __u32); | |
| 162 | + __type(value, struct bpf_devmap_val); | |
| 163 | + __uint(max_entries, 32); | |
| 164 | + } forward_map SEC(".maps"); | |
| 165 | + | |
| 166 | +.. note:: | |
| 167 | + | |
| 168 | + The value type in the DEVMAP above is a ``struct bpf_devmap_val`` | |
| 169 | + | |
| 170 | +The following code snippet shows a simple xdp_redirect_map program. This program | |
| 171 | +would work with a user space program that populates the devmap ``forward_map`` based | |
| 172 | +on ingress ifindexes. The BPF program (below) is redirecting packets using the | |
| 173 | +ingress ``ifindex`` as the ``key``. | |
| 174 | + | |
| 175 | +.. code-block:: c | |
| 176 | + | |
| 177 | + SEC("xdp") | |
| 178 | + int xdp_redirect_map_func(struct xdp_md *ctx) | |
| 179 | + { | |
| 180 | + int index = ctx->ingress_ifindex; | |
| 181 | + | |
| 182 | + return bpf_redirect_map(&forward_map, index, 0); | |
| 183 | + } | |
| 184 | + | |
| 185 | +The following code snippet shows a BPF program that is broadcasting packets to | |
| 186 | +all the interfaces in the ``tx_port`` devmap. | |
| 187 | + | |
| 188 | +.. code-block:: c | |
| 189 | + | |
| 190 | + SEC("xdp") | |
| 191 | + int xdp_redirect_map_func(struct xdp_md *ctx) | |
| 192 | + { | |
| 193 | + return bpf_redirect_map(&tx_port, 0, BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS); | |
| 194 | + } | |
| 195 | + | |
| 196 | +User space | |
| 197 | +---------- | |
| 198 | + | |
| 199 | +The following code snippet shows how to update a devmap called ``tx_port``. | |
| 200 | + | |
| 201 | +.. code-block:: c | |
| 202 | + | |
| 203 | + int update_devmap(int ifindex, int redirect_ifindex) | |
| 204 | + { | |
| 205 | + int ret; | |
| 206 | + | |
| 207 | + ret = bpf_map_update_elem(bpf_map__fd(tx_port), &ifindex, &redirect_ifindex, 0); | |
| 208 | + if (ret < 0) { | |
| 209 | + fprintf(stderr, "Failed to update devmap_ value: %s\n", | |
| 210 | + strerror(errno)); | |
| 211 | + } | |
| 212 | + | |
| 213 | + return ret; | |
| 214 | + } | |
| 215 | + | |
| 216 | +The following code snippet shows how to update a hash_devmap called ``forward_map``. | |
| 217 | + | |
| 218 | +.. code-block:: c | |
| 219 | + | |
| 220 | + int update_devmap(int ifindex, int redirect_ifindex) | |
| 221 | + { | |
| 222 | + struct bpf_devmap_val devmap_val = { .ifindex = redirect_ifindex }; | |
| 223 | + int ret; | |
| 224 | + | |
| 225 | + ret = bpf_map_update_elem(bpf_map__fd(forward_map), &ifindex, &devmap_val, 0); | |
| 226 | + if (ret < 0) { | |
| 227 | + fprintf(stderr, "Failed to update devmap_ value: %s\n", | |
| 228 | + strerror(errno)); | |
| 229 | + } | |
| 230 | + return ret; | |
| 231 | + } | |
| 232 | + | |
| 233 | +References | |
| 234 | +=========== | |
| 235 | + | |
| 236 | +- https://lwn.net/Articles/728146/ | |
| 237 | +- https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=6f9d451ab1a33728adb72d7ff66a7b374d665176 | |
| 238 | +- https://elixir.bootlin.com/linux/latest/source/net/core/filter.c#L4106 | |
| @@ -34,7 +34,14 @@ the ``BPF_F_NO_COMMON_LRU`` flag when calling ``bpf_map_create``. · 33 unmodified lines | ||
| 34 | 34 | Usage |
| 35 | 35 | ===== |
| 36 | 36 | |
| 37 | −.. c:function:: | |
| 37 | +Kernel BPF | |
| 38 | +---------- | |
| 39 | + | |
| 40 | +bpf_map_update_elem() | |
| 41 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 42 | + | |
| 43 | +.. code-block:: c | |
| 44 | + | |
| 38 | 45 | long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) |
| 39 | 46 | |
| 40 | 47 | Hash entries can be added or updated using the ``bpf_map_update_elem()`` |
| @@ -49,14 +56,22 @@ parameter can be used to control the update behaviour: · 8 unmodified lines | ||
| 49 | 56 | ``bpf_map_update_elem()`` returns 0 on success, or negative error in |
| 50 | 57 | case of failure. |
| 51 | 58 | |
| 52 | −.. c:function:: | |
| 59 | +bpf_map_lookup_elem() | |
| 60 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 61 | + | |
| 62 | +.. code-block:: c | |
| 63 | + | |
| 53 | 64 | void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) |
| 54 | 65 | |
| 55 | 66 | Hash entries can be retrieved using the ``bpf_map_lookup_elem()`` |
| 56 | 67 | helper. This helper returns a pointer to the value associated with |
| 57 | 68 | ``key``, or ``NULL`` if no entry was found. |
| 58 | 69 | |
| 59 | −.. c:function:: | |
| 70 | +bpf_map_delete_elem() | |
| 71 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 72 | + | |
| 73 | +.. code-block:: c | |
| 74 | + | |
| 60 | 75 | long bpf_map_delete_elem(struct bpf_map *map, const void *key) |
| 61 | 76 | |
| 62 | 77 | Hash entries can be deleted using the ``bpf_map_delete_elem()`` |
| @@ -70,7 +85,11 @@ For ``BPF_MAP_TYPE_PERCPU_HASH`` and ``BPF_MAP_TYPE_LRU_PERCPU_HASH`` · 7 unmodified lines | ||
| 70 | 85 | the ``bpf_map_update_elem()`` and ``bpf_map_lookup_elem()`` helpers |
| 71 | 86 | automatically access the hash slot for the current CPU. |
| 72 | 87 | |
| 73 | −.. c:function:: | |
| 88 | +bpf_map_lookup_percpu_elem() | |
| 89 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 90 | + | |
| 91 | +.. code-block:: c | |
| 92 | + | |
| 74 | 93 | void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) |
| 75 | 94 | |
| 76 | 95 | The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the |
| @@ -89,7 +108,11 @@ See ``tools/testing/selftests/bpf/progs/test_spin_lock.c``. · 12 unmodified lines | ||
| 89 | 108 | Userspace |
| 90 | 109 | --------- |
| 91 | 110 | |
| 92 | −.. c:function:: | |
| 111 | +bpf_map_get_next_key() | |
| 112 | +~~~~~~~~~~~~~~~~~~~~~~ | |
| 113 | + | |
| 114 | +.. code-block:: c | |
| 115 | + | |
| 93 | 116 | int bpf_map_get_next_key(int fd, const void *cur_key, void *next_key) |
| 94 | 117 | |
| 95 | 118 | In userspace, it is possible to iterate through the keys of a hash using |
| @@ -0,0 +1,197 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +===================== | |
| 5 | +BPF_MAP_TYPE_LPM_TRIE | |
| 6 | +===================== | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_LPM_TRIE`` was introduced in kernel version 4.11 | |
| 10 | + | |
| 11 | +``BPF_MAP_TYPE_LPM_TRIE`` provides a longest prefix match algorithm that | |
| 12 | +can be used to match IP addresses to a stored set of prefixes. | |
| 13 | +Internally, data is stored in an unbalanced trie of nodes that uses | |
| 14 | +``prefixlen,data`` pairs as its keys. The ``data`` is interpreted in | |
| 15 | +network byte order, i.e. big endian, so ``data[0]`` stores the most | |
| 16 | +significant byte. | |
| 17 | + | |
| 18 | +LPM tries may be created with a maximum prefix length that is a multiple | |
| 19 | +of 8, in the range from 8 to 2048. The key used for lookup and update | |
| 20 | +operations is a ``struct bpf_lpm_trie_key``, extended by | |
| 21 | +``max_prefixlen/8`` bytes. | |
| 22 | + | |
| 23 | +- For IPv4 addresses the data length is 4 bytes | |
| 24 | +- For IPv6 addresses the data length is 16 bytes | |
| 25 | + | |
| 26 | +The value type stored in the LPM trie can be any user defined type. | |
| 27 | + | |
| 28 | +.. note:: | |
| 29 | + When creating a map of type ``BPF_MAP_TYPE_LPM_TRIE`` you must set the | |
| 30 | + ``BPF_F_NO_PREALLOC`` flag. | |
| 31 | + | |
| 32 | +Usage | |
| 33 | +===== | |
| 34 | + | |
| 35 | +Kernel BPF | |
| 36 | +---------- | |
| 37 | + | |
| 38 | +bpf_map_lookup_elem() | |
| 39 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 40 | + | |
| 41 | +.. code-block:: c | |
| 42 | + | |
| 43 | + void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) | |
| 44 | + | |
| 45 | +The longest prefix entry for a given data value can be found using the | |
| 46 | +``bpf_map_lookup_elem()`` helper. This helper returns a pointer to the | |
| 47 | +value associated with the longest matching ``key``, or ``NULL`` if no | |
| 48 | +entry was found. | |
| 49 | + | |
| 50 | +The ``key`` should have ``prefixlen`` set to ``max_prefixlen`` when | |
| 51 | +performing longest prefix lookups. For example, when searching for the | |
| 52 | +longest prefix match for an IPv4 address, ``prefixlen`` should be set to | |
| 53 | +``32``. | |
| 54 | + | |
| 55 | +bpf_map_update_elem() | |
| 56 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 57 | + | |
| 58 | +.. code-block:: c | |
| 59 | + | |
| 60 | + long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) | |
| 61 | + | |
| 62 | +Prefix entries can be added or updated using the ``bpf_map_update_elem()`` | |
| 63 | +helper. This helper replaces existing elements atomically. | |
| 64 | + | |
| 65 | +``bpf_map_update_elem()`` returns ``0`` on success, or negative error in | |
| 66 | +case of failure. | |
| 67 | + | |
| 68 | + .. note:: | |
| 69 | + The flags parameter must be one of BPF_ANY, BPF_NOEXIST or BPF_EXIST, | |
| 70 | + but the value is ignored, giving BPF_ANY semantics. | |
| 71 | + | |
| 72 | +bpf_map_delete_elem() | |
| 73 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 74 | + | |
| 75 | +.. code-block:: c | |
| 76 | + | |
| 77 | + long bpf_map_delete_elem(struct bpf_map *map, const void *key) | |
| 78 | + | |
| 79 | +Prefix entries can be deleted using the ``bpf_map_delete_elem()`` | |
| 80 | +helper. This helper will return 0 on success, or negative error in case | |
| 81 | +of failure. | |
| 82 | + | |
| 83 | +Userspace | |
| 84 | +--------- | |
| 85 | + | |
| 86 | +Access from userspace uses libbpf APIs with the same names as above, with | |
| 87 | +the map identified by ``fd``. | |
| 88 | + | |
| 89 | +bpf_map_get_next_key() | |
| 90 | +~~~~~~~~~~~~~~~~~~~~~~ | |
| 91 | + | |
| 92 | +.. code-block:: c | |
| 93 | + | |
| 94 | + int bpf_map_get_next_key (int fd, const void *cur_key, void *next_key) | |
| 95 | + | |
| 96 | +A userspace program can iterate through the entries in an LPM trie using | |
| 97 | +libbpf's ``bpf_map_get_next_key()`` function. The first key can be | |
| 98 | +fetched by calling ``bpf_map_get_next_key()`` with ``cur_key`` set to | |
| 99 | +``NULL``. Subsequent calls will fetch the next key that follows the | |
| 100 | +current key. ``bpf_map_get_next_key()`` returns ``0`` on success, | |
| 101 | +``-ENOENT`` if ``cur_key`` is the last key in the trie, or negative | |
| 102 | +error in case of failure. | |
| 103 | + | |
| 104 | +``bpf_map_get_next_key()`` will iterate through the LPM trie elements | |
| 105 | +from leftmost leaf first. This means that iteration will return more | |
| 106 | +specific keys before less specific ones. | |
| 107 | + | |
| 108 | +Examples | |
| 109 | +======== | |
| 110 | + | |
| 111 | +Please see ``tools/testing/selftests/bpf/test_lpm_map.c`` for examples | |
| 112 | +of LPM trie usage from userspace. The code snippets below demonstrate | |
| 113 | +API usage. | |
| 114 | + | |
| 115 | +Kernel BPF | |
| 116 | +---------- | |
| 117 | + | |
| 118 | +The following BPF code snippet shows how to declare a new LPM trie for IPv4 | |
| 119 | +address prefixes: | |
| 120 | + | |
| 121 | +.. code-block:: c | |
| 122 | + | |
| 123 | + #include <linux/bpf.h> | |
| 124 | + #include <bpf/bpf_helpers.h> | |
| 125 | + | |
| 126 | + struct ipv4_lpm_key { | |
| 127 | + __u32 prefixlen; | |
| 128 | + __u32 data; | |
| 129 | + }; | |
| 130 | + | |
| 131 | + struct { | |
| 132 | + __uint(type, BPF_MAP_TYPE_LPM_TRIE); | |
| 133 | + __type(key, struct ipv4_lpm_key); | |
| 134 | + __type(value, __u32); | |
| 135 | + __uint(map_flags, BPF_F_NO_PREALLOC); | |
| 136 | + __uint(max_entries, 255); | |
| 137 | + } ipv4_lpm_map SEC(".maps"); | |
| 138 | + | |
| 139 | +The following BPF code snippet shows how to lookup by IPv4 address: | |
| 140 | + | |
| 141 | +.. code-block:: c | |
| 142 | + | |
| 143 | + void *lookup(__u32 ipaddr) | |
| 144 | + { | |
| 145 | + struct ipv4_lpm_key key = { | |
| 146 | + .prefixlen = 32, | |
| 147 | + .data = ipaddr | |
| 148 | + }; | |
| 149 | + | |
| 150 | + return bpf_map_lookup_elem(&ipv4_lpm_map, &key); | |
| 151 | + } | |
| 152 | + | |
| 153 | +Userspace | |
| 154 | +--------- | |
| 155 | + | |
| 156 | +The following snippet shows how to insert an IPv4 prefix entry into an | |
| 157 | +LPM trie: | |
| 158 | + | |
| 159 | +.. code-block:: c | |
| 160 | + | |
| 161 | + int add_prefix_entry(int lpm_fd, __u32 addr, __u32 prefixlen, struct value *value) | |
| 162 | + { | |
| 163 | + struct ipv4_lpm_key ipv4_key = { | |
| 164 | + .prefixlen = prefixlen, | |
| 165 | + .data = addr | |
| 166 | + }; | |
| 167 | + return bpf_map_update_elem(lpm_fd, &ipv4_key, value, BPF_ANY); | |
| 168 | + } | |
| 169 | + | |
| 170 | +The following snippet shows a userspace program walking through the entries | |
| 171 | +of an LPM trie: | |
| 172 | + | |
| 173 | + | |
| 174 | +.. code-block:: c | |
| 175 | + | |
| 176 | + #include <bpf/libbpf.h> | |
| 177 | + #include <bpf/bpf.h> | |
| 178 | + | |
| 179 | + void iterate_lpm_trie(int map_fd) | |
| 180 | + { | |
| 181 | + struct ipv4_lpm_key *cur_key = NULL; | |
| 182 | + struct ipv4_lpm_key next_key; | |
| 183 | + struct value value; | |
| 184 | + int err; | |
| 185 | + | |
| 186 | + for (;;) { | |
| 187 | + err = bpf_map_get_next_key(map_fd, cur_key, &next_key); | |
| 188 | + if (err) | |
| 189 | + break; | |
| 190 | + | |
| 191 | + bpf_map_lookup_elem(map_fd, &next_key, &value); | |
| 192 | + | |
| 193 | + /* Use key and value here */ | |
| 194 | + | |
| 195 | + cur_key = &next_key; | |
| 196 | + } | |
| 197 | + } | |
| @@ -0,0 +1,130 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +======================================================== | |
| 5 | +BPF_MAP_TYPE_ARRAY_OF_MAPS and BPF_MAP_TYPE_HASH_OF_MAPS | |
| 6 | +======================================================== | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` and ``BPF_MAP_TYPE_HASH_OF_MAPS`` were | |
| 10 | + introduced in kernel version 4.12 | |
| 11 | + | |
| 12 | +``BPF_MAP_TYPE_ARRAY_OF_MAPS`` and ``BPF_MAP_TYPE_HASH_OF_MAPS`` provide general | |
| 13 | +purpose support for map in map storage. One level of nesting is supported, where | |
| 14 | +an outer map contains instances of a single type of inner map, for example | |
| 15 | +``array_of_maps->sock_map``. | |
| 16 | + | |
| 17 | +When creating an outer map, an inner map instance is used to initialize the | |
| 18 | +metadata that the outer map holds about its inner maps. This inner map has a | |
| 19 | +separate lifetime from the outer map and can be deleted after the outer map has | |
| 20 | +been created. | |
| 21 | + | |
| 22 | +The outer map supports element lookup, update and delete from user space using | |
| 23 | +the syscall API. A BPF program is only allowed to do element lookup in the outer | |
| 24 | +map. | |
| 25 | + | |
| 26 | +.. note:: | |
| 27 | + - Multi-level nesting is not supported. | |
| 28 | + - Any BPF map type can be used as an inner map, except for | |
| 29 | + ``BPF_MAP_TYPE_PROG_ARRAY``. | |
| 30 | + - A BPF program cannot update or delete outer map entries. | |
| 31 | + | |
| 32 | +For ``BPF_MAP_TYPE_ARRAY_OF_MAPS`` the key is an unsigned 32-bit integer index | |
| 33 | +into the array. The array is a fixed size with ``max_entries`` elements that are | |
| 34 | +zero initialized when created. | |
| 35 | + | |
| 36 | +For ``BPF_MAP_TYPE_HASH_OF_MAPS`` the key type can be chosen when defining the | |
| 37 | +map. The kernel is responsible for allocating and freeing key/value pairs, up to | |
| 38 | +the max_entries limit that you specify. Hash maps use pre-allocation of hash | |
| 39 | +table elements by default. The ``BPF_F_NO_PREALLOC`` flag can be used to disable | |
| 40 | +pre-allocation when it is too memory expensive. | |
| 41 | + | |
| 42 | +Usage | |
| 43 | +===== | |
| 44 | + | |
| 45 | +Kernel BPF Helper | |
| 46 | +----------------- | |
| 47 | + | |
| 48 | +bpf_map_lookup_elem() | |
| 49 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 50 | + | |
| 51 | +.. code-block:: c | |
| 52 | + | |
| 53 | + void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) | |
| 54 | + | |
| 55 | +Inner maps can be retrieved using the ``bpf_map_lookup_elem()`` helper. This | |
| 56 | +helper returns a pointer to the inner map, or ``NULL`` if no entry was found. | |
| 57 | + | |
| 58 | +Examples | |
| 59 | +======== | |
| 60 | + | |
| 61 | +Kernel BPF Example | |
| 62 | +------------------ | |
| 63 | + | |
| 64 | +This snippet shows how to create and initialise an array of devmaps in a BPF | |
| 65 | +program. Note that the outer array can only be modified from user space using | |
| 66 | +the syscall API. | |
| 67 | + | |
| 68 | +.. code-block:: c | |
| 69 | + | |
| 70 | + struct inner_map { | |
| 71 | + __uint(type, BPF_MAP_TYPE_DEVMAP); | |
| 72 | + __uint(max_entries, 10); | |
| 73 | + __type(key, __u32); | |
| 74 | + __type(value, __u32); | |
| 75 | + } inner_map1 SEC(".maps"), inner_map2 SEC(".maps"); | |
| 76 | + | |
| 77 | + struct { | |
| 78 | + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | |
| 79 | + __uint(max_entries, 2); | |
| 80 | + __type(key, __u32); | |
| 81 | + __array(values, struct inner_map); | |
| 82 | + } outer_map SEC(".maps") = { | |
| 83 | + .values = { &inner_map1, | |
| 84 | + &inner_map2 } | |
| 85 | + }; | |
| 86 | + | |
| 87 | +See ``progs/test_btf_map_in_map.c`` in ``tools/testing/selftests/bpf`` for more | |
| 88 | +examples of declarative initialisation of outer maps. | |
| 89 | + | |
| 90 | +User Space | |
| 91 | +---------- | |
| 92 | + | |
| 93 | +This snippet shows how to create an array based outer map: | |
| 94 | + | |
| 95 | +.. code-block:: c | |
| 96 | + | |
| 97 | + int create_outer_array(int inner_fd) { | |
| 98 | + LIBBPF_OPTS(bpf_map_create_opts, opts, .inner_map_fd = inner_fd); | |
| 99 | + int fd; | |
| 100 | + | |
| 101 | + fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, | |
| 102 | + "example_array", /* name */ | |
| 103 | + sizeof(__u32), /* key size */ | |
| 104 | + sizeof(__u32), /* value size */ | |
| 105 | + 256, /* max entries */ | |
| 106 | + &opts); /* create opts */ | |
| 107 | + return fd; | |
| 108 | + } | |
| 109 | + | |
| 110 | + | |
| 111 | +This snippet shows how to add an inner map to an outer map: | |
| 112 | + | |
| 113 | +.. code-block:: c | |
| 114 | + | |
| 115 | + int add_devmap(int outer_fd, int index, const char *name) { | |
| 116 | + int fd; | |
| 117 | + | |
| 118 | + fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, name, | |
| 119 | + sizeof(__u32), sizeof(__u32), 256, NULL); | |
| 120 | + if (fd < 0) | |
| 121 | + return fd; | |
| 122 | + | |
| 123 | + return bpf_map_update_elem(outer_fd, &index, &fd, BPF_ANY); | |
| 124 | + } | |
| 125 | + | |
| 126 | +References | |
| 127 | +========== | |
| 128 | + | |
| 129 | +- https://lore.kernel.org/netdev/20170322170035.923581-3-kafai@fb.com/ | |
| 130 | +- https://lore.kernel.org/netdev/20170322170035.923581-4-kafai@fb.com/ | |
| @@ -0,0 +1,146 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +========================================= | |
| 5 | +BPF_MAP_TYPE_QUEUE and BPF_MAP_TYPE_STACK | |
| 6 | +========================================= | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_QUEUE`` and ``BPF_MAP_TYPE_STACK`` were introduced | |
| 10 | + in kernel version 4.20 | |
| 11 | + | |
| 12 | +``BPF_MAP_TYPE_QUEUE`` provides FIFO storage and ``BPF_MAP_TYPE_STACK`` | |
| 13 | +provides LIFO storage for BPF programs. These maps support peek, pop and | |
| 14 | +push operations that are exposed to BPF programs through the respective | |
| 15 | +helpers. These operations are exposed to userspace applications using | |
| 16 | +the existing ``bpf`` syscall in the following way: | |
| 17 | + | |
| 18 | +- ``BPF_MAP_LOOKUP_ELEM`` -> peek | |
| 19 | +- ``BPF_MAP_LOOKUP_AND_DELETE_ELEM`` -> pop | |
| 20 | +- ``BPF_MAP_UPDATE_ELEM`` -> push | |
| 21 | + | |
| 22 | +``BPF_MAP_TYPE_QUEUE`` and ``BPF_MAP_TYPE_STACK`` do not support | |
| 23 | +``BPF_F_NO_PREALLOC``. | |
| 24 | + | |
| 25 | +Usage | |
| 26 | +===== | |
| 27 | + | |
| 28 | +Kernel BPF | |
| 29 | +---------- | |
| 30 | + | |
| 31 | +bpf_map_push_elem() | |
| 32 | +~~~~~~~~~~~~~~~~~~~ | |
| 33 | + | |
| 34 | +.. code-block:: c | |
| 35 | + | |
| 36 | + long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags) | |
| 37 | + | |
| 38 | +An element ``value`` can be added to a queue or stack using the | |
| 39 | +``bpf_map_push_elem`` helper. The ``flags`` parameter must be set to | |
| 40 | +``BPF_ANY`` or ``BPF_EXIST``. If ``flags`` is set to ``BPF_EXIST`` then, | |
| 41 | +when the queue or stack is full, the oldest element will be removed to | |
| 42 | +make room for ``value`` to be added. Returns ``0`` on success, or | |
| 43 | +negative error in case of failure. | |
| 44 | + | |
| 45 | +bpf_map_peek_elem() | |
| 46 | +~~~~~~~~~~~~~~~~~~~ | |
| 47 | + | |
| 48 | +.. code-block:: c | |
| 49 | + | |
| 50 | + long bpf_map_peek_elem(struct bpf_map *map, void *value) | |
| 51 | + | |
| 52 | +This helper fetches an element ``value`` from a queue or stack without | |
| 53 | +removing it. Returns ``0`` on success, or negative error in case of | |
| 54 | +failure. | |
| 55 | + | |
| 56 | +bpf_map_pop_elem() | |
| 57 | +~~~~~~~~~~~~~~~~~~ | |
| 58 | + | |
| 59 | +.. code-block:: c | |
| 60 | + | |
| 61 | + long bpf_map_pop_elem(struct bpf_map *map, void *value) | |
| 62 | + | |
| 63 | +This helper removes an element into ``value`` from a queue or | |
| 64 | +stack. Returns ``0`` on success, or negative error in case of failure. | |
| 65 | + | |
| 66 | + | |
| 67 | +Userspace | |
| 68 | +--------- | |
| 69 | + | |
| 70 | +bpf_map_update_elem() | |
| 71 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 72 | + | |
| 73 | +.. code-block:: c | |
| 74 | + | |
| 75 | + int bpf_map_update_elem (int fd, const void *key, const void *value, __u64 flags) | |
| 76 | + | |
| 77 | +A userspace program can push ``value`` onto a queue or stack using libbpf's | |
| 78 | +``bpf_map_update_elem`` function. The ``key`` parameter must be set to | |
| 79 | +``NULL`` and ``flags`` must be set to ``BPF_ANY`` or ``BPF_EXIST``, with the | |
| 80 | +same semantics as the ``bpf_map_push_elem`` kernel helper. Returns ``0`` on | |
| 81 | +success, or negative error in case of failure. | |
| 82 | + | |
| 83 | +bpf_map_lookup_elem() | |
| 84 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 85 | + | |
| 86 | +.. code-block:: c | |
| 87 | + | |
| 88 | + int bpf_map_lookup_elem (int fd, const void *key, void *value) | |
| 89 | + | |
| 90 | +A userspace program can peek at the ``value`` at the head of a queue or stack | |
| 91 | +using the libbpf ``bpf_map_lookup_elem`` function. The ``key`` parameter must be | |
| 92 | +set to ``NULL``. Returns ``0`` on success, or negative error in case of | |
| 93 | +failure. | |
| 94 | + | |
| 95 | +bpf_map_lookup_and_delete_elem() | |
| 96 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 97 | + | |
| 98 | +.. code-block:: c | |
| 99 | + | |
| 100 | + int bpf_map_lookup_and_delete_elem (int fd, const void *key, void *value) | |
| 101 | + | |
| 102 | +A userspace program can pop a ``value`` from the head of a queue or stack using | |
| 103 | +the libbpf ``bpf_map_lookup_and_delete_elem`` function. The ``key`` parameter | |
| 104 | +must be set to ``NULL``. Returns ``0`` on success, or negative error in case of | |
| 105 | +failure. | |
| 106 | + | |
| 107 | +Examples | |
| 108 | +======== | |
| 109 | + | |
| 110 | +Kernel BPF | |
| 111 | +---------- | |
| 112 | + | |
| 113 | +This snippet shows how to declare a queue in a BPF program: | |
| 114 | + | |
| 115 | +.. code-block:: c | |
| 116 | + | |
| 117 | + struct { | |
| 118 | + __uint(type, BPF_MAP_TYPE_QUEUE); | |
| 119 | + __type(value, __u32); | |
| 120 | + __uint(max_entries, 10); | |
| 121 | + } queue SEC(".maps"); | |
| 122 | + | |
| 123 | + | |
| 124 | +Userspace | |
| 125 | +--------- | |
| 126 | + | |
| 127 | +This snippet shows how to use libbpf's low-level API to create a queue from | |
| 128 | +userspace: | |
| 129 | + | |
| 130 | +.. code-block:: c | |
| 131 | + | |
| 132 | + int create_queue() | |
| 133 | + { | |
| 134 | + return bpf_map_create(BPF_MAP_TYPE_QUEUE, | |
| 135 | + "sample_queue", /* name */ | |
| 136 | + 0, /* key size, must be zero */ | |
| 137 | + sizeof(__u32), /* value size */ | |
| 138 | + 10, /* max entries */ | |
| 139 | + NULL); /* create options */ | |
| 140 | + } | |
| 141 | + | |
| 142 | + | |
| 143 | +References | |
| 144 | +========== | |
| 145 | + | |
| 146 | +https://lwn.net/ml/netdev/153986858555.9127.14517764371945179514.stgit@kernel/ | |
| @@ -0,0 +1,155 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +======================= | |
| 5 | +BPF_MAP_TYPE_SK_STORAGE | |
| 6 | +======================= | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_SK_STORAGE`` was introduced in kernel version 5.2 | |
| 10 | + | |
| 11 | +``BPF_MAP_TYPE_SK_STORAGE`` is used to provide socket-local storage for BPF | |
| 12 | +programs. A map of type ``BPF_MAP_TYPE_SK_STORAGE`` declares the type of storage | |
| 13 | +to be provided and acts as the handle for accessing the socket-local | |
| 14 | +storage. The values for maps of type ``BPF_MAP_TYPE_SK_STORAGE`` are stored | |
| 15 | +locally with each socket instead of with the map. The kernel is responsible for | |
| 16 | +allocating storage for a socket when requested and for freeing the storage when | |
| 17 | +either the map or the socket is deleted. | |
| 18 | + | |
| 19 | +.. note:: | |
| 20 | + - The key type must be ``int`` and ``max_entries`` must be set to ``0``. | |
| 21 | + - The ``BPF_F_NO_PREALLOC`` flag must be used when creating a map for | |
| 22 | + socket-local storage. | |
| 23 | + | |
| 24 | +Usage | |
| 25 | +===== | |
| 26 | + | |
| 27 | +Kernel BPF | |
| 28 | +---------- | |
| 29 | + | |
| 30 | +bpf_sk_storage_get() | |
| 31 | +~~~~~~~~~~~~~~~~~~~~ | |
| 32 | + | |
| 33 | +.. code-block:: c | |
| 34 | + | |
| 35 | + void *bpf_sk_storage_get(struct bpf_map *map, void *sk, void *value, u64 flags) | |
| 36 | + | |
| 37 | +Socket-local storage can be retrieved using the ``bpf_sk_storage_get()`` | |
| 38 | +helper. The helper gets the storage from ``sk`` that is associated with ``map``. | |
| 39 | +If the ``BPF_LOCAL_STORAGE_GET_F_CREATE`` flag is used then | |
| 40 | +``bpf_sk_storage_get()`` will create the storage for ``sk`` if it does not | |
| 41 | +already exist. ``value`` can be used together with | |
| 42 | +``BPF_LOCAL_STORAGE_GET_F_CREATE`` to initialize the storage value, otherwise it | |
| 43 | +will be zero initialized. Returns a pointer to the storage on success, or | |
| 44 | +``NULL`` in case of failure. | |
| 45 | + | |
| 46 | +.. note:: | |
| 47 | + - ``sk`` is a kernel ``struct sock`` pointer for LSM or tracing programs. | |
| 48 | + - ``sk`` is a ``struct bpf_sock`` pointer for other program types. | |
| 49 | + | |
| 50 | +bpf_sk_storage_delete() | |
| 51 | +~~~~~~~~~~~~~~~~~~~~~~~ | |
| 52 | + | |
| 53 | +.. code-block:: c | |
| 54 | + | |
| 55 | + long bpf_sk_storage_delete(struct bpf_map *map, void *sk) | |
| 56 | + | |
| 57 | +Socket-local storage can be deleted using the ``bpf_sk_storage_delete()`` | |
| 58 | +helper. The helper deletes the storage from ``sk`` that is identified by | |
| 59 | +``map``. Returns ``0`` on success, or negative error in case of failure. | |
| 60 | + | |
| 61 | +User space | |
| 62 | +---------- | |
| 63 | + | |
| 64 | +bpf_map_update_elem() | |
| 65 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 66 | + | |
| 67 | +.. code-block:: c | |
| 68 | + | |
| 69 | + int bpf_map_update_elem(int map_fd, const void *key, const void *value, __u64 flags) | |
| 70 | + | |
| 71 | +Socket-local storage for the socket identified by ``key`` belonging to | |
| 72 | +``map_fd`` can be added or updated using the ``bpf_map_update_elem()`` libbpf | |
| 73 | +function. ``key`` must be a pointer to a valid ``fd`` in the user space | |
| 74 | +program. The ``flags`` parameter can be used to control the update behaviour: | |
| 75 | + | |
| 76 | +- ``BPF_ANY`` will create storage for ``fd`` or update existing storage. | |
| 77 | +- ``BPF_NOEXIST`` will create storage for ``fd`` only if it did not already | |
| 78 | + exist, otherwise the call will fail with ``-EEXIST``. | |
| 79 | +- ``BPF_EXIST`` will update existing storage for ``fd`` if it already exists, | |
| 80 | + otherwise the call will fail with ``-ENOENT``. | |
| 81 | + | |
| 82 | +Returns ``0`` on success, or negative error in case of failure. | |
| 83 | + | |
| 84 | +bpf_map_lookup_elem() | |
| 85 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 86 | + | |
| 87 | +.. code-block:: c | |
| 88 | + | |
| 89 | + int bpf_map_lookup_elem(int map_fd, const void *key, void *value) | |
| 90 | + | |
| 91 | +Socket-local storage for the socket identified by ``key`` belonging to | |
| 92 | +``map_fd`` can be retrieved using the ``bpf_map_lookup_elem()`` libbpf | |
| 93 | +function. ``key`` must be a pointer to a valid ``fd`` in the user space | |
| 94 | +program. Returns ``0`` on success, or negative error in case of failure. | |
| 95 | + | |
| 96 | +bpf_map_delete_elem() | |
| 97 | +~~~~~~~~~~~~~~~~~~~~~ | |
| 98 | + | |
| 99 | +.. code-block:: c | |
| 100 | + | |
| 101 | + int bpf_map_delete_elem(int map_fd, const void *key) | |
| 102 | + | |
| 103 | +Socket-local storage for the socket identified by ``key`` belonging to | |
| 104 | +``map_fd`` can be deleted using the ``bpf_map_delete_elem()`` libbpf | |
| 105 | +function. Returns ``0`` on success, or negative error in case of failure. | |
| 106 | + | |
| 107 | +Examples | |
| 108 | +======== | |
| 109 | + | |
| 110 | +Kernel BPF | |
| 111 | +---------- | |
| 112 | + | |
| 113 | +This snippet shows how to declare socket-local storage in a BPF program: | |
| 114 | + | |
| 115 | +.. code-block:: c | |
| 116 | + | |
| 117 | + struct { | |
| 118 | + __uint(type, BPF_MAP_TYPE_SK_STORAGE); | |
| 119 | + __uint(map_flags, BPF_F_NO_PREALLOC); | |
| 120 | + __type(key, int); | |
| 121 | + __type(value, struct my_storage); | |
| 122 | + } socket_storage SEC(".maps"); | |
| 123 | + | |
| 124 | +This snippet shows how to retrieve socket-local storage in a BPF program: | |
| 125 | + | |
| 126 | +.. code-block:: c | |
| 127 | + | |
| 128 | + SEC("sockops") | |
| 129 | + int _sockops(struct bpf_sock_ops *ctx) | |
| 130 | + { | |
| 131 | + struct my_storage *storage; | |
| 132 | + struct bpf_sock *sk; | |
| 133 | + | |
| 134 | + sk = ctx->sk; | |
| 135 | + if (!sk) | |
| 136 | + return 1; | |
| 137 | + | |
| 138 | + storage = bpf_sk_storage_get(&socket_storage, sk, 0, | |
| 139 | + BPF_LOCAL_STORAGE_GET_F_CREATE); | |
| 140 | + if (!storage) | |
| 141 | + return 1; | |
| 142 | + | |
| 143 | + /* Use 'storage' here */ | |
| 144 | + | |
| 145 | + return 1; | |
| 146 | + } | |
| 147 | + | |
| 148 | + | |
| 149 | +Please see the ``tools/testing/selftests/bpf`` directory for functional | |
| 150 | +examples. | |
| 151 | + | |
| 152 | +References | |
| 153 | +========== | |
| 154 | + | |
| 155 | +https://lwn.net/ml/netdev/20190426171103.61892-1-kafai@fb.com/ | |
| @@ -0,0 +1,192 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +=================== | |
| 5 | +BPF_MAP_TYPE_XSKMAP | |
| 6 | +=================== | |
| 7 | + | |
| 8 | +.. note:: | |
| 9 | + - ``BPF_MAP_TYPE_XSKMAP`` was introduced in kernel version 4.18 | |
| 10 | + | |
| 11 | +The ``BPF_MAP_TYPE_XSKMAP`` is used as a backend map for XDP BPF helper | |
| 12 | +call ``bpf_redirect_map()`` and ``XDP_REDIRECT`` action, like 'devmap' and 'cpumap'. | |
| 13 | +This map type redirects raw XDP frames to `AF_XDP`_ sockets (XSKs), a new type of | |
| 14 | +address family in the kernel that allows redirection of frames from a driver to | |
| 15 | +user space without having to traverse the full network stack. An AF_XDP socket | |
| 16 | +binds to a single netdev queue. A mapping of XSKs to queues is shown below: | |
| 17 | + | |
| 18 | +.. code-block:: none | |
| 19 | + | |
| 20 | + +---------------------------------------------------+ | |
| 21 | + | xsk A | xsk B | xsk C |<---+ User space | |
| 22 | + =========================================================|========== | |
| 23 | + | Queue 0 | Queue 1 | Queue 2 | | Kernel | |
| 24 | + +---------------------------------------------------+ | | |
| 25 | + | Netdev eth0 | | | |
| 26 | + +---------------------------------------------------+ | | |
| 27 | + | +=============+ | | | |
| 28 | + | | key | xsk | | | | |
| 29 | + | +---------+ +=============+ | | | |
| 30 | + | | | | 0 | xsk A | | | | |
| 31 | + | | | +-------------+ | | | |
| 32 | + | | | | 1 | xsk B | | | | |
| 33 | + | | BPF |-- redirect -->+-------------+-------------+ | |
| 34 | + | | prog | | 2 | xsk C | | | |
| 35 | + | | | +-------------+ | | |
| 36 | + | | | | | |
| 37 | + | | | | | |
| 38 | + | +---------+ | | |
| 39 | + | | | |
| 40 | + +---------------------------------------------------+ | |
| 41 | + | |
| 42 | +.. note:: | |
| 43 | + An AF_XDP socket that is bound to a certain <netdev/queue_id> will *only* | |
| 44 | + accept XDP frames from that <netdev/queue_id>. If an XDP program tries to redirect | |
| 45 | + from a <netdev/queue_id> other than what the socket is bound to, the frame will | |
| 46 | + not be received on the socket. | |
| 47 | + | |
| 48 | +Typically an XSKMAP is created per netdev. This map contains an array of XSK File | |
| 49 | +Descriptors (FDs). The number of array elements is typically set or adjusted using | |
| 50 | +the ``max_entries`` map parameter. For AF_XDP ``max_entries`` is equal to the number | |
| 51 | +of queues supported by the netdev. | |
| 52 | + | |
| 53 | +.. note:: | |
| 54 | + Both the map key and map value size must be 4 bytes. | |
| 55 | + | |
| 56 | +Usage | |
| 57 | +===== | |
| 58 | + | |
| 59 | +Kernel BPF | |
| 60 | +---------- | |
| 61 | +bpf_redirect_map() | |
| 62 | +^^^^^^^^^^^^^^^^^^ | |
| 63 | +.. code-block:: c | |
| 64 | + | |
| 65 | + long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags) | |
| 66 | + | |
| 67 | +Redirect the packet to the endpoint referenced by ``map`` at index ``key``. | |
| 68 | +For ``BPF_MAP_TYPE_XSKMAP`` this map contains references to XSK FDs | |
| 69 | +for sockets attached to a netdev's queues. | |
| 70 | + | |
| 71 | +.. note:: | |
| 72 | + If the map is empty at an index, the packet is dropped. This means that it is | |
| 73 | + necessary to have an XDP program loaded with at least one XSK in the | |
| 74 | + XSKMAP to be able to get any traffic to user space through the socket. | |
| 75 | + | |
| 76 | +bpf_map_lookup_elem() | |
| 77 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 78 | +.. code-block:: c | |
| 79 | + | |
| 80 | + void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) | |
| 81 | + | |
| 82 | +XSK entry references of type ``struct xdp_sock *`` can be retrieved using the | |
| 83 | +``bpf_map_lookup_elem()`` helper. | |
| 84 | + | |
| 85 | +User space | |
| 86 | +---------- | |
| 87 | +.. note:: | |
| 88 | + XSK entries can only be updated/deleted from user space and not from | |
| 89 | + a BPF program. Trying to call these functions from a kernel BPF program will | |
| 90 | + result in the program failing to load and a verifier warning. | |
| 91 | + | |
| 92 | +bpf_map_update_elem() | |
| 93 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 94 | +.. code-block:: c | |
| 95 | + | |
| 96 | + int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags) | |
| 97 | + | |
| 98 | +XSK entries can be added or updated using the ``bpf_map_update_elem()`` | |
| 99 | +helper. The ``key`` parameter is equal to the queue_id of the queue the XSK | |
| 100 | +is attaching to. And the ``value`` parameter is the FD value of that socket. | |
| 101 | + | |
| 102 | +Under the hood, the XSKMAP update function uses the XSK FD value to retrieve the | |
| 103 | +associated ``struct xdp_sock`` instance. | |
| 104 | + | |
| 105 | +The flags argument can be one of the following: | |
| 106 | + | |
| 107 | +- BPF_ANY: Create a new element or update an existing element. | |
| 108 | +- BPF_NOEXIST: Create a new element only if it did not exist. | |
| 109 | +- BPF_EXIST: Update an existing element. | |
| 110 | + | |
| 111 | +bpf_map_lookup_elem() | |
| 112 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 113 | +.. code-block:: c | |
| 114 | + | |
| 115 | + int bpf_map_lookup_elem(int fd, const void *key, void *value) | |
| 116 | + | |
| 117 | +Returns ``struct xdp_sock *`` or negative error in case of failure. | |
| 118 | + | |
| 119 | +bpf_map_delete_elem() | |
| 120 | +^^^^^^^^^^^^^^^^^^^^^ | |
| 121 | +.. code-block:: c | |
| 122 | + | |
| 123 | + int bpf_map_delete_elem(int fd, const void *key) | |
| 124 | + | |
| 125 | +XSK entries can be deleted using the ``bpf_map_delete_elem()`` | |
| 126 | +helper. This helper will return 0 on success, or negative error in case of | |
| 127 | +failure. | |
| 128 | + | |
| 129 | +.. note:: | |
| 130 | + When `libxdp`_ deletes an XSK it also removes the associated socket | |
| 131 | + entry from the XSKMAP. | |
| 132 | + | |
| 133 | +Examples | |
| 134 | +======== | |
| 135 | +Kernel | |
| 136 | +------ | |
| 137 | + | |
| 138 | +The following code snippet shows how to declare a ``BPF_MAP_TYPE_XSKMAP`` called | |
| 139 | +``xsks_map`` and how to redirect packets to an XSK. | |
| 140 | + | |
| 141 | +.. code-block:: c | |
| 142 | + | |
| 143 | + struct { | |
| 144 | + __uint(type, BPF_MAP_TYPE_XSKMAP); | |
| 145 | + __type(key, __u32); | |
| 146 | + __type(value, __u32); | |
| 147 | + __uint(max_entries, 64); | |
| 148 | + } xsks_map SEC(".maps"); | |
| 149 | + | |
| 150 | + | |
| 151 | + SEC("xdp") | |
| 152 | + int xsk_redir_prog(struct xdp_md *ctx) | |
| 153 | + { | |
| 154 | + __u32 index = ctx->rx_queue_index; | |
| 155 | + | |
| 156 | + if (bpf_map_lookup_elem(&xsks_map, &index)) | |
| 157 | + return bpf_redirect_map(&xsks_map, index, 0); | |
| 158 | + return XDP_PASS; | |
| 159 | + } | |
| 160 | + | |
| 161 | +User space | |
| 162 | +---------- | |
| 163 | + | |
| 164 | +The following code snippet shows how to update an XSKMAP with an XSK entry. | |
| 165 | + | |
| 166 | +.. code-block:: c | |
| 167 | + | |
| 168 | + int update_xsks_map(struct bpf_map *xsks_map, int queue_id, int xsk_fd) | |
| 169 | + { | |
| 170 | + int ret; | |
| 171 | + | |
| 172 | + ret = bpf_map_update_elem(bpf_map__fd(xsks_map), &queue_id, &xsk_fd, 0); | |
| 173 | + if (ret < 0) | |
| 174 | + fprintf(stderr, "Failed to update xsks_map: %s\n", strerror(errno)); | |
| 175 | + | |
| 176 | + return ret; | |
| 177 | + } | |
| 178 | + | |
| 179 | +For an example on how create AF_XDP sockets, please see the AF_XDP-example and | |
| 180 | +AF_XDP-forwarding programs in the `bpf-examples`_ directory in the `libxdp`_ repository. | |
| 181 | +For a detailed explaination of the AF_XDP interface please see: | |
| 182 | + | |
| 183 | +- `libxdp-readme`_. | |
| 184 | +- `AF_XDP`_ kernel documentation. | |
| 185 | + | |
| 186 | +.. note:: | |
| 187 | + The most comprehensive resource for using XSKMAPs and AF_XDP is `libxdp`_. | |
| 188 | + | |
| 189 | +.. _libxdp: https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp | |
| 190 | +.. _AF_XDP: https://www.kernel.org/doc/html/latest/networking/af_xdp.html | |
| 191 | +.. _bpf-examples: https://github.com/xdp-project/bpf-examples | |
| 192 | +.. _libxdp-readme: https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp#using-af_xdp-sockets | |
| @@ -1,52 +1,81 @@ | ||
| 1 | 1 | |
| 2 | −========= | |
| 3 | −eBPF maps | |
| 2 | +======== | |
| 3 | +BPF maps | |
| 4 | +======== | |
| 5 | + | |
| 6 | +BPF 'maps' provide generic storage of different types for sharing data between | |
| 7 | +kernel and user space. There are several storage types available, including | |
| 8 | +hash, array, bloom filter and radix-tree. Several of the map types exist to | |
| 9 | +support specific BPF helpers that perform actions based on the map contents. The | |
| 10 | +maps are accessed from BPF programs via BPF helpers which are documented in the | |
| 11 | +`man-pages`_ for `bpf-helpers(7)`_. | |
| 12 | + | |
| 13 | +BPF maps are accessed from user space via the ``bpf`` syscall, which provides | |
| 14 | +commands to create maps, lookup elements, update elements and delete | |
| 15 | +elements. More details of the BPF syscall are available in | |
| 16 | +:doc:`/userspace-api/ebpf/syscall` and in the `man-pages`_ for `bpf(2)`_. | |
| 17 | + | |
| 18 | +Map Types | |
| 4 | 19 | ========= |
| 5 | 20 | |
| 6 | −'maps' is a generic storage of different types for sharing data between kernel | |
| 7 | −and userspace. | |
| 21 | +.. toctree:: | |
| 22 | + :maxdepth: 1 | |
| 23 | + :glob: | |
| 8 | 24 | |
| 9 | −The maps are accessed from user space via BPF syscall, which has commands: | |
| 25 | + map_* | |
| 10 | 26 | |
| 11 | −- create a map with given type and attributes | |
| 12 | − ``map_fd = bpf(BPF_MAP_CREATE, union bpf_attr *attr, u32 size)`` | |
| 13 | − using attr->map_type, attr->key_size, attr->value_size, attr->max_entries | |
| 14 | − returns process-local file descriptor or negative error | |
| 27 | +Usage Notes | |
| 28 | +=========== | |
| 15 | 29 | |
| 16 | −- lookup key in a given map | |
| 17 | − ``err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)`` | |
| 18 | − using attr->map_fd, attr->key, attr->value | |
| 19 | − returns zero and stores found elem into value or negative error | |
| 30 | +.. c:function:: | |
| 31 | + int bpf(int command, union bpf_attr *attr, u32 size) | |
| 20 | 32 | |
| 21 | −- create or update key/value pair in a given map | |
| 22 | − ``err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)`` | |
| 23 | − using attr->map_fd, attr->key, attr->value | |
| 24 | − returns zero or negative error | |
| 33 | +Use the ``bpf()`` system call to perform the operation specified by | |
| 34 | +``command``. The operation takes parameters provided in ``attr``. The ``size`` | |
| 35 | +argument is the size of the ``union bpf_attr`` in ``attr``. | |
| 25 | 36 | |
| 26 | −- find and delete element by key in a given map | |
| 27 | − ``err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)`` | |
| 28 | − using attr->map_fd, attr->key | |
| 37 | +**BPF_MAP_CREATE** | |
| 29 | 38 | |
| 30 | −- to delete map: close(fd) | |
| 31 | − Exiting process will delete maps automatically | |
| 39 | +Create a map with the desired type and attributes in ``attr``: | |
| 32 | 40 | |
| 33 | −userspace programs use this syscall to create/access maps that eBPF programs | |
| 34 | −are concurrently updating. | |
| 41 | +.. code-block:: c | |
| 35 | 42 | |
| 36 | −maps can have different types: hash, array, bloom filter, radix-tree, etc. | |
| 43 | + int fd; | |
| 44 | + union bpf_attr attr = { | |
| 45 | + .map_type = BPF_MAP_TYPE_ARRAY; /* mandatory */ | |
| 46 | + .key_size = sizeof(__u32); /* mandatory */ | |
| 47 | + .value_size = sizeof(__u32); /* mandatory */ | |
| 48 | + .max_entries = 256; /* mandatory */ | |
| 49 | + .map_flags = BPF_F_MMAPABLE; | |
| 50 | + .map_name = "example_array"; | |
| 51 | + }; | |
| 37 | 52 | |
| 38 | −The map is defined by: | |
| 53 | + fd = bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); | |
| 39 | 54 | |
| 40 | − - type | |
| 41 | − - max number of elements | |
| 42 | − - key size in bytes | |
| 43 | − - value size in bytes | |
| 55 | +Returns a process-local file descriptor on success, or negative error in case of | |
| 56 | +failure. The map can be deleted by calling ``close(fd)``. Maps held by open | |
| 57 | +file descriptors will be deleted automatically when a process exits. | |
| 44 | 58 | |
| 45 | −Map Types | |
| 46 | −========= | |
| 59 | +.. note:: Valid characters for ``map_name`` are ``A-Z``, ``a-z``, ``0-9``, | |
| 60 | + ``'_'`` and ``'.'``. | |
| 47 | 61 | |
| 48 | −.. toctree:: | |
| 49 | − :maxdepth: 1 | |
| 50 | − :glob: | |
| 62 | +**BPF_MAP_LOOKUP_ELEM** | |
| 63 | + | |
| 64 | +Lookup key in a given map using ``attr->map_fd``, ``attr->key``, | |
| 65 | +``attr->value``. Returns zero and stores found elem into ``attr->value`` on | |
| 66 | +success, or negative error on failure. | |
| 67 | + | |
| 68 | +**BPF_MAP_UPDATE_ELEM** | |
| 69 | + | |
| 70 | +Create or update key/value pair in a given map using ``attr->map_fd``, ``attr->key``, | |
| 71 | +``attr->value``. Returns zero on success or negative error on failure. | |
| 72 | + | |
| 73 | +**BPF_MAP_DELETE_ELEM** | |
| 74 | + | |
| 75 | +Find and delete element by key in a given map using ``attr->map_fd``, | |
| 76 | +``attr->key``. Returns zero on success or negative error on failure. | |
| 51 | 77 | |
| 52 | − map_* | |
| 78 | +.. Links: | |
| 79 | +.. _man-pages: https://www.kernel.org/doc/man-pages/ | |
| 80 | +.. _bpf(2): https://man7.org/linux/man-pages/man2/bpf.2.html | |
| 81 | +.. _bpf-helpers(7): https://man7.org/linux/man-pages/man7/bpf-helpers.7.html | |
| @@ -7,3 +7,6 @@ Program Types · 6 unmodified lines | ||
| 7 | 7 | :glob: |
| 8 | 8 | |
| 9 | 9 | prog_* |
| 10 | + | |
| 11 | +For a list of all program types, see :ref:`program_types_and_elf` in | |
| 12 | +the :ref:`libbpf` documentation. | |
| @@ -0,0 +1,81 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +.. Copyright (C) 2022 Red Hat, Inc. | |
| 3 | + | |
| 4 | +======== | |
| 5 | +Redirect | |
| 6 | +======== | |
| 7 | +XDP_REDIRECT | |
| 8 | +############ | |
| 9 | +Supported maps | |
| 10 | +-------------- | |
| 11 | + | |
| 12 | +XDP_REDIRECT works with the following map types: | |
| 13 | + | |
| 14 | +- ``BPF_MAP_TYPE_DEVMAP`` | |
| 15 | +- ``BPF_MAP_TYPE_DEVMAP_HASH`` | |
| 16 | +- ``BPF_MAP_TYPE_CPUMAP`` | |
| 17 | +- ``BPF_MAP_TYPE_XSKMAP`` | |
| 18 | + | |
| 19 | +For more information on these maps, please see the specific map documentation. | |
| 20 | + | |
| 21 | +Process | |
| 22 | +------- | |
| 23 | + | |
| 24 | +.. kernel-doc:: net/core/filter.c | |
| 25 | + :doc: xdp redirect | |
| 26 | + | |
| 27 | +.. note:: | |
| 28 | + Not all drivers support transmitting frames after a redirect, and for | |
| 29 | + those that do, not all of them support non-linear frames. Non-linear xdp | |
| 30 | + bufs/frames are bufs/frames that contain more than one fragment. | |
| 31 | + | |
| 32 | +Debugging packet drops | |
| 33 | +---------------------- | |
| 34 | +Silent packet drops for XDP_REDIRECT can be debugged using: | |
| 35 | + | |
| 36 | +- bpf_trace | |
| 37 | +- perf_record | |
| 38 | + | |
| 39 | +bpf_trace | |
| 40 | +^^^^^^^^^ | |
| 41 | +The following bpftrace command can be used to capture and count all XDP tracepoints: | |
| 42 | + | |
| 43 | +.. code-block:: none | |
| 44 | + | |
| 45 | + sudo bpftrace -e 'tracepoint:xdp:* { @cnt[probe] = count(); }' | |
| 46 | + Attaching 12 probes... | |
| 47 | + ^C | |
| 48 | + | |
| 49 | + @cnt[tracepoint:xdp:mem_connect]: 18 | |
| 50 | + @cnt[tracepoint:xdp:mem_disconnect]: 18 | |
| 51 | + @cnt[tracepoint:xdp:xdp_exception]: 19605 | |
| 52 | + @cnt[tracepoint:xdp:xdp_devmap_xmit]: 1393604 | |
| 53 | + @cnt[tracepoint:xdp:xdp_redirect]: 22292200 | |
| 54 | + | |
| 55 | +.. note:: | |
| 56 | + The various xdp tracepoints can be found in ``source/include/trace/events/xdp.h`` | |
| 57 | + | |
| 58 | +The following bpftrace command can be used to extract the ``ERRNO`` being returned as | |
| 59 | +part of the err parameter: | |
| 60 | + | |
| 61 | +.. code-block:: none | |
| 62 | + | |
| 63 | + sudo bpftrace -e \ | |
| 64 | + 'tracepoint:xdp:xdp_redirect*_err {@redir_errno[-args->err] = count();} | |
| 65 | + tracepoint:xdp:xdp_devmap_xmit {@devmap_errno[-args->err] = count();}' | |
| 66 | + | |
| 67 | +perf record | |
| 68 | +^^^^^^^^^^^ | |
| 69 | +The perf tool also supports recording tracepoints: | |
| 70 | + | |
| 71 | +.. code-block:: none | |
| 72 | + | |
| 73 | + perf record -a -e xdp:xdp_redirect_err \ | |
| 74 | + -e xdp:xdp_redirect_map_err \ | |
| 75 | + -e xdp:xdp_exception \ | |
| 76 | + -e xdp:xdp_devmap_xmit | |
| 77 | + | |
| 78 | +References | |
| 79 | +=========== | |
| 80 | + | |
| 81 | +- https://github.com/xdp-project/xdp-tutorial/tree/master/tracing02-xdp-monitor | |
| @@ -29,6 +29,38 @@ properties: · 28 unmodified lines | ||
| 29 | 29 | interrupts: |
| 30 | 30 | maxItems: 1 |
| 31 | 31 | |
| 32 | + memory-region: | |
| 33 | + items: | |
| 34 | + - description: firmware EMI region | |
| 35 | + - description: firmware ILM region | |
| 36 | + - description: firmware DLM region | |
| 37 | + - description: firmware CPU DATA region | |
| 38 | + - description: firmware BOOT region | |
| 39 | + | |
| 40 | + memory-region-names: | |
| 41 | + items: | |
| 42 | + - const: wo-emi | |
| 43 | + - const: wo-ilm | |
| 44 | + - const: wo-dlm | |
| 45 | + - const: wo-data | |
| 46 | + - const: wo-boot | |
| 47 | + | |
| 48 | + mediatek,wo-ccif: | |
| 49 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 50 | + description: mediatek wed-wo controller interface. | |
| 51 | + | |
| 52 | +allOf: | |
| 53 | + - if: | |
| 54 | + properties: | |
| 55 | + compatible: | |
| 56 | + contains: | |
| 57 | + const: mediatek,mt7622-wed | |
| 58 | + then: | |
| 59 | + properties: | |
| 60 | + memory-region-names: false | |
| 61 | + memory-region: false | |
| 62 | + mediatek,wo-ccif: false | |
| 63 | + | |
| 32 | 64 | required: |
| 33 | 65 | - compatible |
| 34 | 66 | - reg |
| @@ -49,3 +81,23 @@ examples: · 14 unmodified lines | ||
| 49 | 81 | interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_LOW>; |
| 50 | 82 | }; |
| 51 | 83 | }; |
| 84 | + | |
| 85 | + - | | |
| 86 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 87 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 88 | + soc { | |
| 89 | + #address-cells = <2>; | |
| 90 | + #size-cells = <2>; | |
| 91 | + | |
| 92 | + wed@15010000 { | |
| 93 | + compatible = "mediatek,mt7986-wed", "syscon"; | |
| 94 | + reg = <0 0x15010000 0 0x1000>; | |
| 95 | + interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>; | |
| 96 | + | |
| 97 | + memory-region = <&wo_emi>, <&wo_ilm>, <&wo_dlm>, | |
| 98 | + <&wo_data>, <&wo_boot>; | |
| 99 | + memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", | |
| 100 | + "wo-data", "wo-boot"; | |
| 101 | + mediatek,wo-ccif = <&wo_ccif0>; | |
| 102 | + }; | |
| 103 | + }; | |
| @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 6 unmodified lines | ||
| 7 | 7 | title: Freescale INTMUX interrupt multiplexer |
| 8 | 8 | |
| 9 | 9 | maintainers: |
| 10 | − - Joakim Zhang <qiangqing.zhang@nxp.com> | |
| 10 | + - Shawn Guo <shawnguo@kernel.org> | |
| 11 | + - NXP Linux Team <linux-imx@nxp.com> | |
| 11 | 12 | |
| 12 | 13 | properties: |
| 13 | 14 | compatible: |
| @@ -46,6 +46,10 @@ properties: · 45 unmodified lines | ||
| 46 | 46 | interrupts: |
| 47 | 47 | maxItems: 1 |
| 48 | 48 | |
| 49 | + reset-gpios: | |
| 50 | + maxItems: 1 | |
| 51 | + description: GPIO connected to active low reset | |
| 52 | + | |
| 49 | 53 | required: |
| 50 | 54 | - compatible |
| 51 | 55 | - reg |
| @@ -27,7 +27,9 @@ properties: · 26 unmodified lines | ||
| 27 | 27 | - usbb95,772b # ASIX AX88772B |
| 28 | 28 | - usbb95,7e2b # ASIX AX88772B |
| 29 | 29 | |
| 30 | − reg: true | |
| 30 | + reg: | |
| 31 | + maxItems: 1 | |
| 32 | + | |
| 31 | 33 | local-mac-address: true |
| 32 | 34 | mac-address: true |
| 33 | 35 | |
| @@ -1,5 +0,0 @@ | ||
| 1 | −The following properties are common to the Bluetooth controllers: | |
| 2 | − | |
| 3 | −- local-bd-address: array of 6 bytes, specifies the BD address that was | |
| 4 | − uniquely assigned to the Bluetooth device, formatted with least significant | |
| 5 | − byte first (little-endian). | |
| @@ -0,0 +1,29 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/bluetooth/bluetooth-controller.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Bluetooth Controller Generic Binding | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Marcel Holtmann <marcel@holtmann.org> | |
| 11 | + - Johan Hedberg <johan.hedberg@gmail.com> | |
| 12 | + - Luiz Augusto von Dentz <luiz.dentz@gmail.com> | |
| 13 | + | |
| 14 | +properties: | |
| 15 | + $nodename: | |
| 16 | + pattern: "^bluetooth(@.*)?$" | |
| 17 | + | |
| 18 | + local-bd-address: | |
| 19 | + $ref: /schemas/types.yaml#/definitions/uint8-array | |
| 20 | + maxItems: 6 | |
| 21 | + description: | |
| 22 | + Specifies the BD address that was uniquely assigned to the Bluetooth | |
| 23 | + device. Formatted with least significant byte first (little-endian), e.g. | |
| 24 | + in order to assign the address 00:11:22:33:44:55 this property must have | |
| 25 | + the value [55 44 33 22 11 00]. | |
| 26 | + | |
| 27 | +additionalProperties: true | |
| 28 | + | |
| 29 | +... | |
| @@ -0,0 +1,81 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/bluetooth/brcm,bcm4377-bluetooth.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Broadcom BCM4377 family PCIe Bluetooth Chips | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Sven Peter <sven@svenpeter.dev> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + This binding describes Broadcom BCM4377 family PCIe-attached bluetooth chips | |
| 14 | + usually found in Apple machines. The Wi-Fi part of the chip is described in | |
| 15 | + bindings/net/wireless/brcm,bcm4329-fmac.yaml. | |
| 16 | + | |
| 17 | +allOf: | |
| 18 | + - $ref: bluetooth-controller.yaml# | |
| 19 | + | |
| 20 | +properties: | |
| 21 | + compatible: | |
| 22 | + enum: | |
| 23 | + - pci14e4,5fa0 # BCM4377 | |
| 24 | + - pci14e4,5f69 # BCM4378 | |
| 25 | + - pci14e4,5f71 # BCM4387 | |
| 26 | + | |
| 27 | + reg: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + brcm,board-type: | |
| 31 | + $ref: /schemas/types.yaml#/definitions/string | |
| 32 | + description: Board type of the Bluetooth chip. This is used to decouple | |
| 33 | + the overall system board from the Bluetooth module and used to construct | |
| 34 | + firmware and calibration data filenames. | |
| 35 | + On Apple platforms, this should be the Apple module-instance codename | |
| 36 | + prefixed by "apple,", e.g. "apple,atlantisb". | |
| 37 | + pattern: '^apple,.*' | |
| 38 | + | |
| 39 | + brcm,taurus-cal-blob: | |
| 40 | + $ref: /schemas/types.yaml#/definitions/uint8-array | |
| 41 | + description: A per-device calibration blob for the Bluetooth radio. This | |
| 42 | + should be filled in by the bootloader from platform configuration | |
| 43 | + data, if necessary, and will be uploaded to the device. | |
| 44 | + This blob is used if the chip stepping of the Bluetooth module does not | |
| 45 | + support beamforming. | |
| 46 | + | |
| 47 | + brcm,taurus-bf-cal-blob: | |
| 48 | + $ref: /schemas/types.yaml#/definitions/uint8-array | |
| 49 | + description: A per-device calibration blob for the Bluetooth radio. This | |
| 50 | + should be filled in by the bootloader from platform configuration | |
| 51 | + data, if necessary, and will be uploaded to the device. | |
| 52 | + This blob is used if the chip stepping of the Bluetooth module supports | |
| 53 | + beamforming. | |
| 54 | + | |
| 55 | + local-bd-address: true | |
| 56 | + | |
| 57 | +required: | |
| 58 | + - compatible | |
| 59 | + - reg | |
| 60 | + - local-bd-address | |
| 61 | + - brcm,board-type | |
| 62 | + | |
| 63 | +additionalProperties: false | |
| 64 | + | |
| 65 | +examples: | |
| 66 | + - | | |
| 67 | + pcie@a0000000 { | |
| 68 | + #address-cells = <3>; | |
| 69 | + #size-cells = <2>; | |
| 70 | + reg = <0xa0000000 0x1000000>; | |
| 71 | + device_type = "pci"; | |
| 72 | + ranges = <0x43000000 0x6 0xa0000000 0xa0000000 0x0 0x20000000>; | |
| 73 | + | |
| 74 | + bluetooth@0,1 { | |
| 75 | + compatible = "pci14e4,5f69"; | |
| 76 | + reg = <0x100 0x0 0x0 0x0 0x0>; | |
| 77 | + brcm,board-type = "apple,honshu"; | |
| 78 | + /* To be filled by the bootloader */ | |
| 79 | + local-bd-address = [00 00 00 00 00 00]; | |
| 80 | + }; | |
| 81 | + }; | |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | 2 | %YAML 1.2 |
| 3 | 3 | --- |
| 4 | −$id: http://devicetree.org/schemas/net/qualcomm-bluetooth.yaml# | |
| 4 | +$id: http://devicetree.org/schemas/net/bluetooth/qualcomm-bluetooth.yaml# | |
| 5 | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | |
| 7 | 7 | title: Qualcomm Bluetooth Chips |
| @@ -79,8 +79,7 @@ properties: · 71 unmodified lines | ||
| 79 | 79 | firmware-name: |
| 80 | 80 | description: specify the name of nvm firmware to load |
| 81 | 81 | |
| 82 | − local-bd-address: | |
| 83 | − description: see Documentation/devicetree/bindings/net/bluetooth.txt | |
| 82 | + local-bd-address: true | |
| 84 | 83 | |
| 85 | 84 | |
| 86 | 85 | required: |
| @@ -89,6 +88,7 @@ required: · 2 unmodified lines | ||
| 89 | 88 | additionalProperties: false |
| 90 | 89 | |
| 91 | 90 | allOf: |
| 91 | + - $ref: bluetooth-controller.yaml# | |
| 92 | 92 | - if: |
| 93 | 93 | properties: |
| 94 | 94 | compatible: |
| @@ -19,11 +19,14 @@ properties: · 18 unmodified lines | ||
| 19 | 19 | - brcm,bcm4329-bt |
| 20 | 20 | - brcm,bcm4330-bt |
| 21 | 21 | - brcm,bcm4334-bt |
| 22 | + - brcm,bcm43430a0-bt | |
| 23 | + - brcm,bcm43430a1-bt | |
| 22 | 24 | - brcm,bcm43438-bt |
| 23 | 25 | - brcm,bcm4345c5 |
| 24 | 26 | - brcm,bcm43540-bt |
| 25 | 27 | - brcm,bcm4335a0 |
| 26 | 28 | - brcm,bcm4349-bt |
| 29 | + - cypress,cyw4373a0-bt | |
| 27 | 30 | - infineon,cyw55572-bt |
| 28 | 31 | |
| 29 | 32 | shutdown-gpios: |
| @@ -17,6 +17,7 @@ properties: · 16 unmodified lines | ||
| 17 | 17 | compatible: |
| 18 | 18 | oneOf: |
| 19 | 19 | - enum: |
| 20 | + - fsl,imx93-flexcan | |
| 20 | 21 | - fsl,imx8qm-flexcan |
| 21 | 22 | - fsl,imx8mp-flexcan |
| 22 | 23 | - fsl,imx6q-flexcan |
| @@ -9,9 +9,6 @@ title: Renesas R-Car CAN FD Controller · 8 unmodified lines | ||
| 9 | 9 | maintainers: |
| 10 | 10 | - Fabrizio Castro <fabrizio.castro.jz@renesas.com> |
| 11 | 11 | |
| 12 | −allOf: | |
| 13 | − - $ref: can-controller.yaml# | |
| 14 | − | |
| 15 | 12 | properties: |
| 16 | 13 | compatible: |
| 17 | 14 | oneOf: |
| @@ -33,7 +30,7 @@ properties: · 15 unmodified lines | ||
| 33 | 30 | |
| 34 | 31 | - items: |
| 35 | 32 | - enum: |
| 36 | − - renesas,r9a07g043-canfd # RZ/G2UL | |
| 33 | + - renesas,r9a07g043-canfd # RZ/G2UL and RZ/Five | |
| 37 | 34 | - renesas,r9a07g044-canfd # RZ/G2{L,LC} |
| 38 | 35 | - renesas,r9a07g054-canfd # RZ/V2L |
| 39 | 36 | - const: renesas,rzg2l-canfd # RZ/G2L family |
| @@ -77,12 +74,13 @@ properties: · 37 unmodified lines | ||
| 77 | 74 | description: Maximum frequency of the CANFD clock. |
| 78 | 75 | |
| 79 | 76 | patternProperties: |
| 80 | − "^channel[01]$": | |
| 77 | + "^channel[0-7]$": | |
| 81 | 78 | type: object |
| 82 | 79 | description: |
| 83 | − The controller supports two channels and each is represented as a child | |
| 84 | − node. Each child node supports the "status" property only, which | |
| 85 | − is used to enable/disable the respective channel. | |
| 80 | + The controller supports multiple channels and each is represented as a | |
| 81 | + child node. Each channel can be enabled/disabled individually. | |
| 82 | + | |
| 83 | + additionalProperties: false | |
| 86 | 84 | |
| 87 | 85 | required: |
| 88 | 86 | - compatible |
| @@ -98,60 +96,73 @@ required: · 9 unmodified lines | ||
| 98 | 96 | - channel0 |
| 99 | 97 | - channel1 |
| 100 | 98 | |
| 101 | −if: | |
| 102 | − properties: | |
| 103 | − compatible: | |
| 104 | − contains: | |
| 105 | − enum: | |
| 106 | − - renesas,rzg2l-canfd | |
| 107 | −then: | |
| 108 | − properties: | |
| 109 | − interrupts: | |
| 110 | − items: | |
| 111 | − - description: CAN global error interrupt | |
| 112 | − - description: CAN receive FIFO interrupt | |
| 113 | − - description: CAN0 error interrupt | |
| 114 | − - description: CAN0 transmit interrupt | |
| 115 | − - description: CAN0 transmit/receive FIFO receive completion interrupt | |
| 116 | − - description: CAN1 error interrupt | |
| 117 | − - description: CAN1 transmit interrupt | |
| 118 | − - description: CAN1 transmit/receive FIFO receive completion interrupt | |
| 119 | − | |
| 120 | − interrupt-names: | |
| 121 | − items: | |
| 122 | − - const: g_err | |
| 123 | − - const: g_recc | |
| 124 | − - const: ch0_err | |
| 125 | − - const: ch0_rec | |
| 126 | − - const: ch0_trx | |
| 127 | − - const: ch1_err | |
| 128 | − - const: ch1_rec | |
| 129 | − - const: ch1_trx | |
| 130 | − | |
| 131 | − resets: | |
| 132 | − maxItems: 2 | |
| 133 | − | |
| 134 | − reset-names: | |
| 135 | − items: | |
| 136 | − - const: rstp_n | |
| 137 | − - const: rstc_n | |
| 138 | − | |
| 139 | − required: | |
| 140 | − - reset-names | |
| 141 | −else: | |
| 142 | − properties: | |
| 143 | − interrupts: | |
| 144 | − items: | |
| 145 | − - description: Channel interrupt | |
| 146 | − - description: Global interrupt | |
| 147 | − | |
| 148 | − interrupt-names: | |
| 149 | − items: | |
| 150 | − - const: ch_int | |
| 151 | − - const: g_int | |
| 152 | − | |
| 153 | − resets: | |
| 154 | − maxItems: 1 | |
| 99 | +allOf: | |
| 100 | + - $ref: can-controller.yaml# | |
| 101 | + | |
| 102 | + - if: | |
| 103 | + properties: | |
| 104 | + compatible: | |
| 105 | + contains: | |
| 106 | + enum: | |
| 107 | + - renesas,rzg2l-canfd | |
| 108 | + then: | |
| 109 | + properties: | |
| 110 | + interrupts: | |
| 111 | + items: | |
| 112 | + - description: CAN global error interrupt | |
| 113 | + - description: CAN receive FIFO interrupt | |
| 114 | + - description: CAN0 error interrupt | |
| 115 | + - description: CAN0 transmit interrupt | |
| 116 | + - description: CAN0 transmit/receive FIFO receive completion interrupt | |
| 117 | + - description: CAN1 error interrupt | |
| 118 | + - description: CAN1 transmit interrupt | |
| 119 | + - description: CAN1 transmit/receive FIFO receive completion interrupt | |
| 120 | + | |
| 121 | + interrupt-names: | |
| 122 | + items: | |
| 123 | + - const: g_err | |
| 124 | + - const: g_recc | |
| 125 | + - const: ch0_err | |
| 126 | + - const: ch0_rec | |
| 127 | + - const: ch0_trx | |
| 128 | + - const: ch1_err | |
| 129 | + - const: ch1_rec | |
| 130 | + - const: ch1_trx | |
| 131 | + | |
| 132 | + resets: | |
| 133 | + maxItems: 2 | |
| 134 | + | |
| 135 | + reset-names: | |
| 136 | + items: | |
| 137 | + - const: rstp_n | |
| 138 | + - const: rstc_n | |
| 139 | + | |
| 140 | + required: | |
| 141 | + - reset-names | |
| 142 | + else: | |
| 143 | + properties: | |
| 144 | + interrupts: | |
| 145 | + items: | |
| 146 | + - description: Channel interrupt | |
| 147 | + - description: Global interrupt | |
| 148 | + | |
| 149 | + interrupt-names: | |
| 150 | + items: | |
| 151 | + - const: ch_int | |
| 152 | + - const: g_int | |
| 153 | + | |
| 154 | + resets: | |
| 155 | + maxItems: 1 | |
| 156 | + | |
| 157 | + - if: | |
| 158 | + not: | |
| 159 | + properties: | |
| 160 | + compatible: | |
| 161 | + contains: | |
| 162 | + const: renesas,r8a779a0-canfd | |
| 163 | + then: | |
| 164 | + patternProperties: | |
| 165 | + "^channel[2-7]$": false | |
| 155 | 166 | |
| 156 | 167 | unevaluatedProperties: false |
| 157 | 168 | |
| @@ -19,7 +19,8 @@ allOf: · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | properties: |
| 21 | 21 | reg: |
| 22 | − description: Port number | |
| 22 | + items: | |
| 23 | + - description: Port number | |
| 23 | 24 | |
| 24 | 25 | label: |
| 25 | 26 | description: |
| @@ -12,7 +12,7 @@ allOf: · 11 unmodified lines | ||
| 12 | 12 | maintainers: |
| 13 | 13 | - Andrew Lunn <andrew@lunn.ch> |
| 14 | 14 | - Florian Fainelli <f.fainelli@gmail.com> |
| 15 | − - Vivien Didelot <vivien.didelot@gmail.com> | |
| 15 | + - Vladimir Oltean <olteanv@gmail.com> | |
| 16 | 16 | - Kurt Kanzenbach <kurt@linutronix.de> |
| 17 | 17 | |
| 18 | 18 | description: |
| @@ -74,10 +74,10 @@ properties: · 73 unmodified lines | ||
| 74 | 74 | |
| 75 | 75 | properties: |
| 76 | 76 | pcs-handle: |
| 77 | + maxItems: 1 | |
| 77 | 78 | description: |
| 78 | 79 | phandle pointing to a PCS sub-node compatible with |
| 79 | 80 | renesas,rzn1-miic.yaml# |
| 80 | − $ref: /schemas/types.yaml#/definitions/phandle | |
| 81 | 81 | |
| 82 | 82 | unevaluatedProperties: false |
| 83 | 83 | |
| @@ -108,11 +108,17 @@ properties: · 107 unmodified lines | ||
| 108 | 108 | $ref: "#/properties/phy-connection-type" |
| 109 | 109 | |
| 110 | 110 | pcs-handle: |
| 111 | − $ref: /schemas/types.yaml#/definitions/phandle | |
| 111 | + $ref: /schemas/types.yaml#/definitions/phandle-array | |
| 112 | + items: | |
| 113 | + maxItems: 1 | |
| 112 | 114 | description: |
| 113 | 115 | Specifies a reference to a node representing a PCS PHY device on a MDIO |
| 114 | 116 | bus to link with an external PHY (phy-handle) if exists. |
| 115 | 117 | |
| 118 | + pcs-handle-names: | |
| 119 | + description: | |
| 120 | + The name of each PCS in pcs-handle. | |
| 121 | + | |
| 116 | 122 | phy-handle: |
| 117 | 123 | $ref: /schemas/types.yaml#/definitions/phandle |
| 118 | 124 | description: |
| @@ -216,6 +222,9 @@ properties: · 97 unmodified lines | ||
| 216 | 222 | required: |
| 217 | 223 | - speed |
| 218 | 224 | |
| 225 | +dependencies: | |
| 226 | + pcs-handle-names: [pcs-handle] | |
| 227 | + | |
| 219 | 228 | allOf: |
| 220 | 229 | - if: |
| 221 | 230 | properties: |
| @@ -7,7 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 6 unmodified lines | ||
| 7 | 7 | title: Freescale Fast Ethernet Controller (FEC) |
| 8 | 8 | |
| 9 | 9 | maintainers: |
| 10 | − - Joakim Zhang <qiangqing.zhang@nxp.com> | |
| 10 | + - Shawn Guo <shawnguo@kernel.org> | |
| 11 | + - Wei Fang <wei.fang@nxp.com> | |
| 12 | + - NXP Linux Team <linux-imx@nxp.com> | |
| 11 | 13 | |
| 12 | 14 | allOf: |
| 13 | 15 | - $ref: ethernet-controller.yaml# |
| @@ -85,9 +85,39 @@ properties: · 84 unmodified lines | ||
| 85 | 85 | $ref: /schemas/types.yaml#/definitions/phandle |
| 86 | 86 | description: A reference to the IEEE1588 timer |
| 87 | 87 | |
| 88 | + phys: | |
| 89 | + description: A reference to the SerDes lane(s) | |
| 90 | + maxItems: 1 | |
| 91 | + | |
| 92 | + phy-names: | |
| 93 | + items: | |
| 94 | + - const: serdes | |
| 95 | + | |
| 88 | 96 | pcsphy-handle: |
| 89 | − $ref: /schemas/types.yaml#/definitions/phandle | |
| 90 | − description: A reference to the PCS (typically found on the SerDes) | |
| 97 | + $ref: /schemas/types.yaml#/definitions/phandle-array | |
| 98 | + minItems: 1 | |
| 99 | + maxItems: 3 | |
| 100 | + deprecated: true | |
| 101 | + description: See pcs-handle. | |
| 102 | + | |
| 103 | + pcs-handle: | |
| 104 | + minItems: 1 | |
| 105 | + maxItems: 3 | |
| 106 | + description: | | |
| 107 | + A reference to the various PCSs (typically found on the SerDes). If | |
| 108 | + pcs-handle-names is absent, and phy-connection-type is "xgmii", then the first | |
| 109 | + reference will be assumed to be for "xfi". Otherwise, if pcs-handle-names is | |
| 110 | + absent, then the first reference will be assumed to be for "sgmii". | |
| 111 | + | |
| 112 | + pcs-handle-names: | |
| 113 | + minItems: 1 | |
| 114 | + maxItems: 3 | |
| 115 | + items: | |
| 116 | + enum: | |
| 117 | + - sgmii | |
| 118 | + - qsgmii | |
| 119 | + - xfi | |
| 120 | + description: The type of each PCS in pcsphy-handle. | |
| 91 | 121 | |
| 92 | 122 | tbi-handle: |
| 93 | 123 | $ref: /schemas/types.yaml#/definitions/phandle |
| @@ -100,6 +130,10 @@ required: · 6 unmodified lines | ||
| 100 | 130 | - fsl,fman-ports |
| 101 | 131 | - ptp-timer |
| 102 | 132 | |
| 133 | +dependencies: | |
| 134 | + pcs-handle-names: | |
| 135 | + - pcs-handle | |
| 136 | + | |
| 103 | 137 | allOf: |
| 104 | 138 | - $ref: ethernet-controller.yaml# |
| 105 | 139 | - if: |
| @@ -110,14 +144,6 @@ allOf: · 4 unmodified lines | ||
| 110 | 144 | then: |
| 111 | 145 | required: |
| 112 | 146 | - tbi-handle |
| 113 | − - if: | |
| 114 | − properties: | |
| 115 | − compatible: | |
| 116 | − contains: | |
| 117 | − const: fsl,fman-memac | |
| 118 | − then: | |
| 119 | − required: | |
| 120 | − - pcsphy-handle | |
| 121 | 147 | |
| 122 | 148 | unevaluatedProperties: false |
| 123 | 149 | |
| @@ -138,8 +164,9 @@ examples: · 14 unmodified lines | ||
| 138 | 164 | reg = <0xe8000 0x1000>; |
| 139 | 165 | fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; |
| 140 | 166 | ptp-timer = <&ptp_timer0>; |
| 141 | − pcsphy-handle = <&pcsphy4>; | |
| 142 | − phy-handle = <&sgmii_phy1>; | |
| 143 | − phy-connection-type = "sgmii"; | |
| 167 | + pcs-handle = <&pcsphy4>, <&qsgmiib_pcs1>; | |
| 168 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 169 | + phys = <&serdes1 1>; | |
| 170 | + phy-names = "serdes"; | |
| 144 | 171 | }; |
| 145 | 172 | ... |
| @@ -31,7 +31,7 @@ properties: · 30 unmodified lines | ||
| 31 | 31 | phy-mode: true |
| 32 | 32 | |
| 33 | 33 | pcs-handle: |
| 34 | − $ref: /schemas/types.yaml#/definitions/phandle | |
| 34 | + maxItems: 1 | |
| 35 | 35 | description: |
| 36 | 36 | A reference to a node representing a PCS PHY device found on |
| 37 | 37 | the internal MDIO bus. |
| @@ -320,8 +320,9 @@ For internal PHY device on internal mdio bus, a PHY node should be created. · 319 unmodified lines | ||
| 320 | 320 | See the definition of the PHY node in booting-without-of.txt for an |
| 321 | 321 | example of how to define a PHY (Internal PHY has no interrupt line). |
| 322 | 322 | - For "fsl,fman-mdio" compatible internal mdio bus, the PHY is TBI PHY. |
| 323 | −- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY, | |
| 324 | − PCS PHY addr must be '0'. | |
| 323 | +- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY. | |
| 324 | + The PCS PHY address should correspond to the value of the appropriate | |
| 325 | + MDEV_PORT. | |
| 325 | 326 | |
| 326 | 327 | EXAMPLE |
| 327 | 328 | |
| @@ -0,0 +1,62 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/marvell,dfx-server.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Marvell Prestera DFX server | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Miquel Raynal <miquel.raynal@bootlin.com> | |
| 11 | + | |
| 12 | +select: | |
| 13 | + properties: | |
| 14 | + compatible: | |
| 15 | + contains: | |
| 16 | + const: marvell,dfx-server | |
| 17 | + required: | |
| 18 | + - compatible | |
| 19 | + | |
| 20 | +properties: | |
| 21 | + compatible: | |
| 22 | + items: | |
| 23 | + - const: marvell,dfx-server | |
| 24 | + - const: simple-bus | |
| 25 | + | |
| 26 | + reg: | |
| 27 | + maxItems: 1 | |
| 28 | + | |
| 29 | + ranges: true | |
| 30 | + | |
| 31 | + '#address-cells': | |
| 32 | + const: 1 | |
| 33 | + | |
| 34 | + '#size-cells': | |
| 35 | + const: 1 | |
| 36 | + | |
| 37 | +required: | |
| 38 | + - compatible | |
| 39 | + - reg | |
| 40 | + - ranges | |
| 41 | + | |
| 42 | +# The DFX server may expose clocks described as subnodes | |
| 43 | +additionalProperties: | |
| 44 | + type: object | |
| 45 | + | |
| 46 | +examples: | |
| 47 | + - | | |
| 48 | + | |
| 49 | + #define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16)) | |
| 50 | + bus@0 { | |
| 51 | + reg = <0 0>; | |
| 52 | + #address-cells = <2>; | |
| 53 | + #size-cells = <1>; | |
| 54 | + | |
| 55 | + dfx-bus@ac000000 { | |
| 56 | + compatible = "marvell,dfx-server", "simple-bus"; | |
| 57 | + #address-cells = <1>; | |
| 58 | + #size-cells = <1>; | |
| 59 | + ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; | |
| 60 | + reg = <MBUS_ID(0x08, 0x00) 0 0x100000>; | |
| 61 | + }; | |
| 62 | + }; | |
| @@ -0,0 +1,305 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/marvell,pp2.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Marvell CN913X / Marvell Armada 375, 7K, 8K Ethernet Controller | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Marcin Wojtas <mw@semihalf.com> | |
| 11 | + - Russell King <linux@armlinux.org> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + Marvell Armada 375 Ethernet Controller (PPv2.1) | |
| 15 | + Marvell Armada 7K/8K Ethernet Controller (PPv2.2) | |
| 16 | + Marvell CN913X Ethernet Controller (PPv2.3) | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + enum: | |
| 21 | + - marvell,armada-375-pp2 | |
| 22 | + - marvell,armada-7k-pp22 | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + minItems: 3 | |
| 26 | + maxItems: 4 | |
| 27 | + | |
| 28 | + "#address-cells": | |
| 29 | + const: 1 | |
| 30 | + | |
| 31 | + "#size-cells": | |
| 32 | + const: 0 | |
| 33 | + | |
| 34 | + clocks: | |
| 35 | + minItems: 2 | |
| 36 | + items: | |
| 37 | + - description: main controller clock | |
| 38 | + - description: GOP clock | |
| 39 | + - description: MG clock | |
| 40 | + - description: MG Core clock | |
| 41 | + - description: AXI clock | |
| 42 | + | |
| 43 | + clock-names: | |
| 44 | + minItems: 2 | |
| 45 | + items: | |
| 46 | + - const: pp_clk | |
| 47 | + - const: gop_clk | |
| 48 | + - const: mg_clk | |
| 49 | + - const: mg_core_clk | |
| 50 | + - const: axi_clk | |
| 51 | + | |
| 52 | + dma-coherent: true | |
| 53 | + | |
| 54 | + marvell,system-controller: | |
| 55 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 56 | + description: a phandle to the system controller. | |
| 57 | + | |
| 58 | +patternProperties: | |
| 59 | + '^(ethernet-)?port@[0-2]$': | |
| 60 | + type: object | |
| 61 | + description: subnode for each ethernet port. | |
| 62 | + $ref: ethernet-controller.yaml# | |
| 63 | + unevaluatedProperties: false | |
| 64 | + | |
| 65 | + properties: | |
| 66 | + reg: | |
| 67 | + description: ID of the port from the MAC point of view. | |
| 68 | + maximum: 2 | |
| 69 | + | |
| 70 | + interrupts: | |
| 71 | + minItems: 1 | |
| 72 | + maxItems: 10 | |
| 73 | + description: interrupt(s) for the port | |
| 74 | + | |
| 75 | + interrupt-names: | |
| 76 | + minItems: 1 | |
| 77 | + items: | |
| 78 | + - const: hif0 | |
| 79 | + - const: hif1 | |
| 80 | + - const: hif2 | |
| 81 | + - const: hif3 | |
| 82 | + - const: hif4 | |
| 83 | + - const: hif5 | |
| 84 | + - const: hif6 | |
| 85 | + - const: hif7 | |
| 86 | + - const: hif8 | |
| 87 | + - const: link | |
| 88 | + | |
| 89 | + description: > | |
| 90 | + if more than a single interrupt for is given, must be the | |
| 91 | + name associated to the interrupts listed. Valid names are: | |
| 92 | + "hifX", with X in [0..8], and "link". The names "tx-cpu0", | |
| 93 | + "tx-cpu1", "tx-cpu2", "tx-cpu3" and "rx-shared" are supported | |
| 94 | + for backward compatibility but shouldn't be used for new | |
| 95 | + additions. | |
| 96 | + | |
| 97 | + phys: | |
| 98 | + minItems: 1 | |
| 99 | + maxItems: 2 | |
| 100 | + description: > | |
| 101 | + Generic PHY, providing SerDes connectivity. For most modes, | |
| 102 | + one lane is sufficient, but some (e.g. RXAUI) may require two. | |
| 103 | + | |
| 104 | + phy-mode: | |
| 105 | + enum: | |
| 106 | + - gmii | |
| 107 | + - sgmii | |
| 108 | + - rgmii-id | |
| 109 | + - 1000base-x | |
| 110 | + - 2500base-x | |
| 111 | + - 5gbase-r | |
| 112 | + - rxaui | |
| 113 | + - 10gbase-r | |
| 114 | + | |
| 115 | + port-id: | |
| 116 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 117 | + deprecated: true | |
| 118 | + description: > | |
| 119 | + ID of the port from the MAC point of view. | |
| 120 | + Legacy binding for backward compatibility. | |
| 121 | + | |
| 122 | + marvell,loopback: | |
| 123 | + $ref: /schemas/types.yaml#/definitions/flag | |
| 124 | + description: port is loopback mode. | |
| 125 | + | |
| 126 | + gop-port-id: | |
| 127 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 128 | + description: > | |
| 129 | + only for marvell,armada-7k-pp22, ID of the port from the | |
| 130 | + GOP (Group Of Ports) point of view. This ID is used to index the | |
| 131 | + per-port registers in the second register area. | |
| 132 | + | |
| 133 | + required: | |
| 134 | + - reg | |
| 135 | + - interrupts | |
| 136 | + - phy-mode | |
| 137 | + - port-id | |
| 138 | + | |
| 139 | +required: | |
| 140 | + - compatible | |
| 141 | + - reg | |
| 142 | + - clocks | |
| 143 | + - clock-names | |
| 144 | + | |
| 145 | +allOf: | |
| 146 | + - if: | |
| 147 | + properties: | |
| 148 | + compatible: | |
| 149 | + const: marvell,armada-7k-pp22 | |
| 150 | + then: | |
| 151 | + properties: | |
| 152 | + reg: | |
| 153 | + items: | |
| 154 | + - description: Packet Processor registers | |
| 155 | + - description: Networking interfaces registers | |
| 156 | + - description: CM3 address space used for TX Flow Control | |
| 157 | + | |
| 158 | + clocks: | |
| 159 | + minItems: 5 | |
| 160 | + | |
| 161 | + clock-names: | |
| 162 | + minItems: 5 | |
| 163 | + | |
| 164 | + patternProperties: | |
| 165 | + '^(ethernet-)?port@[0-2]$': | |
| 166 | + required: | |
| 167 | + - gop-port-id | |
| 168 | + | |
| 169 | + required: | |
| 170 | + - marvell,system-controller | |
| 171 | + else: | |
| 172 | + properties: | |
| 173 | + reg: | |
| 174 | + items: | |
| 175 | + - description: Packet Processor registers | |
| 176 | + - description: LMS registers | |
| 177 | + - description: Register area per eth0 | |
| 178 | + - description: Register area per eth1 | |
| 179 | + | |
| 180 | + clocks: | |
| 181 | + maxItems: 2 | |
| 182 | + | |
| 183 | + clock-names: | |
| 184 | + maxItems: 2 | |
| 185 | + | |
| 186 | + patternProperties: | |
| 187 | + '^(ethernet-)?port@[0-1]$': | |
| 188 | + properties: | |
| 189 | + reg: | |
| 190 | + maximum: 1 | |
| 191 | + | |
| 192 | + gop-port-id: false | |
| 193 | + | |
| 194 | +additionalProperties: false | |
| 195 | + | |
| 196 | +examples: | |
| 197 | + - | | |
| 198 | + // For Armada 375 variant | |
| 199 | + #include <dt-bindings/interrupt-controller/mvebu-icu.h> | |
| 200 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 201 | + | |
| 202 | + ethernet@f0000 { | |
| 203 | + #address-cells = <1>; | |
| 204 | + #size-cells = <0>; | |
| 205 | + compatible = "marvell,armada-375-pp2"; | |
| 206 | + reg = <0xf0000 0xa000>, | |
| 207 | + <0xc0000 0x3060>, | |
| 208 | + <0xc4000 0x100>, | |
| 209 | + <0xc5000 0x100>; | |
| 210 | + clocks = <&gateclk 3>, <&gateclk 19>; | |
| 211 | + clock-names = "pp_clk", "gop_clk"; | |
| 212 | + | |
| 213 | + ethernet-port@0 { | |
| 214 | + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; | |
| 215 | + reg = <0>; | |
| 216 | + port-id = <0>; /* For backward compatibility. */ | |
| 217 | + phy = <&phy0>; | |
| 218 | + phy-mode = "rgmii-id"; | |
| 219 | + }; | |
| 220 | + | |
| 221 | + ethernet-port@1 { | |
| 222 | + interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; | |
| 223 | + reg = <1>; | |
| 224 | + port-id = <1>; /* For backward compatibility. */ | |
| 225 | + phy = <&phy3>; | |
| 226 | + phy-mode = "gmii"; | |
| 227 | + }; | |
| 228 | + }; | |
| 229 | + | |
| 230 | + - | | |
| 231 | + // For Armada 7k/8k and Cn913x variants | |
| 232 | + #include <dt-bindings/interrupt-controller/mvebu-icu.h> | |
| 233 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 234 | + | |
| 235 | + ethernet@0 { | |
| 236 | + #address-cells = <1>; | |
| 237 | + #size-cells = <0>; | |
| 238 | + compatible = "marvell,armada-7k-pp22"; | |
| 239 | + reg = <0x0 0x100000>, <0x129000 0xb000>, <0x220000 0x800>; | |
| 240 | + clocks = <&cp0_clk 1 3>, <&cp0_clk 1 9>, | |
| 241 | + <&cp0_clk 1 5>, <&cp0_clk 1 6>, <&cp0_clk 1 18>; | |
| 242 | + clock-names = "pp_clk", "gop_clk", "mg_clk", "mg_core_clk", "axi_clk"; | |
| 243 | + marvell,system-controller = <&cp0_syscon0>; | |
| 244 | + | |
| 245 | + ethernet-port@0 { | |
| 246 | + interrupts = <ICU_GRP_NSR 39 IRQ_TYPE_LEVEL_HIGH>, | |
| 247 | + <ICU_GRP_NSR 43 IRQ_TYPE_LEVEL_HIGH>, | |
| 248 | + <ICU_GRP_NSR 47 IRQ_TYPE_LEVEL_HIGH>, | |
| 249 | + <ICU_GRP_NSR 51 IRQ_TYPE_LEVEL_HIGH>, | |
| 250 | + <ICU_GRP_NSR 55 IRQ_TYPE_LEVEL_HIGH>, | |
| 251 | + <ICU_GRP_NSR 59 IRQ_TYPE_LEVEL_HIGH>, | |
| 252 | + <ICU_GRP_NSR 63 IRQ_TYPE_LEVEL_HIGH>, | |
| 253 | + <ICU_GRP_NSR 67 IRQ_TYPE_LEVEL_HIGH>, | |
| 254 | + <ICU_GRP_NSR 71 IRQ_TYPE_LEVEL_HIGH>, | |
| 255 | + <ICU_GRP_NSR 129 IRQ_TYPE_LEVEL_HIGH>; | |
| 256 | + interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", | |
| 257 | + "hif5", "hif6", "hif7", "hif8", "link"; | |
| 258 | + phy-mode = "10gbase-r"; | |
| 259 | + phys = <&cp0_comphy4 0>; | |
| 260 | + reg = <0>; | |
| 261 | + port-id = <0>; /* For backward compatibility. */ | |
| 262 | + gop-port-id = <0>; | |
| 263 | + }; | |
| 264 | + | |
| 265 | + ethernet-port@1 { | |
| 266 | + interrupts = <ICU_GRP_NSR 40 IRQ_TYPE_LEVEL_HIGH>, | |
| 267 | + <ICU_GRP_NSR 44 IRQ_TYPE_LEVEL_HIGH>, | |
| 268 | + <ICU_GRP_NSR 48 IRQ_TYPE_LEVEL_HIGH>, | |
| 269 | + <ICU_GRP_NSR 52 IRQ_TYPE_LEVEL_HIGH>, | |
| 270 | + <ICU_GRP_NSR 56 IRQ_TYPE_LEVEL_HIGH>, | |
| 271 | + <ICU_GRP_NSR 60 IRQ_TYPE_LEVEL_HIGH>, | |
| 272 | + <ICU_GRP_NSR 64 IRQ_TYPE_LEVEL_HIGH>, | |
| 273 | + <ICU_GRP_NSR 68 IRQ_TYPE_LEVEL_HIGH>, | |
| 274 | + <ICU_GRP_NSR 72 IRQ_TYPE_LEVEL_HIGH>, | |
| 275 | + <ICU_GRP_NSR 128 IRQ_TYPE_LEVEL_HIGH>; | |
| 276 | + interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", | |
| 277 | + "hif5", "hif6", "hif7", "hif8", "link"; | |
| 278 | + phy-mode = "rgmii-id"; | |
| 279 | + reg = <1>; | |
| 280 | + port-id = <1>; /* For backward compatibility. */ | |
| 281 | + gop-port-id = <2>; | |
| 282 | + }; | |
| 283 | + | |
| 284 | + ethernet-port@2 { | |
| 285 | + interrupts = <ICU_GRP_NSR 41 IRQ_TYPE_LEVEL_HIGH>, | |
| 286 | + <ICU_GRP_NSR 45 IRQ_TYPE_LEVEL_HIGH>, | |
| 287 | + <ICU_GRP_NSR 49 IRQ_TYPE_LEVEL_HIGH>, | |
| 288 | + <ICU_GRP_NSR 53 IRQ_TYPE_LEVEL_HIGH>, | |
| 289 | + <ICU_GRP_NSR 57 IRQ_TYPE_LEVEL_HIGH>, | |
| 290 | + <ICU_GRP_NSR 61 IRQ_TYPE_LEVEL_HIGH>, | |
| 291 | + <ICU_GRP_NSR 65 IRQ_TYPE_LEVEL_HIGH>, | |
| 292 | + <ICU_GRP_NSR 69 IRQ_TYPE_LEVEL_HIGH>, | |
| 293 | + <ICU_GRP_NSR 73 IRQ_TYPE_LEVEL_HIGH>, | |
| 294 | + <ICU_GRP_NSR 127 IRQ_TYPE_LEVEL_HIGH>; | |
| 295 | + interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", | |
| 296 | + "hif5", "hif6", "hif7", "hif8", "link"; | |
| 297 | + phy-mode = "2500base-x"; | |
| 298 | + managed = "in-band-status"; | |
| 299 | + phys = <&cp0_comphy5 2>; | |
| 300 | + sfp = <&sfp_eth3>; | |
| 301 | + reg = <2>; | |
| 302 | + port-id = <2>; /* For backward compatibility. */ | |
| 303 | + gop-port-id = <3>; | |
| 304 | + }; | |
| 305 | + }; | |
| @@ -1,81 +0,0 @@ | ||
| 1 | −Marvell Prestera Switch Chip bindings | |
| 2 | −------------------------------------- | |
| 3 | − | |
| 4 | −Required properties: | |
| 5 | −- compatible: must be "marvell,prestera" and one of the following | |
| 6 | − "marvell,prestera-98dx3236", | |
| 7 | − "marvell,prestera-98dx3336", | |
| 8 | − "marvell,prestera-98dx4251", | |
| 9 | −- reg: address and length of the register set for the device. | |
| 10 | −- interrupts: interrupt for the device | |
| 11 | − | |
| 12 | −Optional properties: | |
| 13 | −- dfx: phandle reference to the "DFX Server" node | |
| 14 | − | |
| 15 | −Example: | |
| 16 | − | |
| 17 | −switch { | |
| 18 | − compatible = "simple-bus"; | |
| 19 | − #address-cells = <1>; | |
| 20 | − #size-cells = <1>; | |
| 21 | − ranges = <0 MBUS_ID(0x03, 0x00) 0 0x100000>; | |
| 22 | − | |
| 23 | − packet-processor@0 { | |
| 24 | − compatible = "marvell,prestera-98dx3236", "marvell,prestera"; | |
| 25 | − reg = <0 0x4000000>; | |
| 26 | − interrupts = <33>, <34>, <35>; | |
| 27 | − dfx = <&dfx>; | |
| 28 | − }; | |
| 29 | −}; | |
| 30 | − | |
| 31 | −DFX Server bindings | |
| 32 | −------------------- | |
| 33 | − | |
| 34 | −Required properties: | |
| 35 | −- compatible: must be "marvell,dfx-server", "simple-bus" | |
| 36 | −- ranges: describes the address mapping of a memory-mapped bus. | |
| 37 | −- reg: address and length of the register set for the device. | |
| 38 | − | |
| 39 | −Example: | |
| 40 | − | |
| 41 | −dfx-server { | |
| 42 | − compatible = "marvell,dfx-server", "simple-bus"; | |
| 43 | − #address-cells = <1>; | |
| 44 | − #size-cells = <1>; | |
| 45 | − ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; | |
| 46 | − reg = <MBUS_ID(0x08, 0x00) 0 0x100000>; | |
| 47 | −}; | |
| 48 | − | |
| 49 | −Marvell Prestera SwitchDev bindings | |
| 50 | −----------------------------------- | |
| 51 | −Optional properties: | |
| 52 | −- compatible: must be "marvell,prestera" | |
| 53 | −- base-mac-provider: describes handle to node which provides base mac address, | |
| 54 | − might be a static base mac address or nvme cell provider. | |
| 55 | − | |
| 56 | −Example: | |
| 57 | − | |
| 58 | −eeprom_mac_addr: eeprom-mac-addr { | |
| 59 | − compatible = "eeprom,mac-addr-cell"; | |
| 60 | − status = "okay"; | |
| 61 | − | |
| 62 | − nvmem = <&eeprom_at24>; | |
| 63 | −}; | |
| 64 | − | |
| 65 | −prestera { | |
| 66 | − compatible = "marvell,prestera"; | |
| 67 | − status = "okay"; | |
| 68 | − | |
| 69 | − base-mac-provider = <&eeprom_mac_addr>; | |
| 70 | −}; | |
| 71 | − | |
| 72 | −The current implementation of Prestera Switchdev PCI interface driver requires | |
| 73 | −that BAR2 is assigned to 0xf6000000 as base address from the PCI IO range: | |
| 74 | − | |
| 75 | −&cp0_pcie0 { | |
| 76 | − ranges = <0x81000000 0x0 0xfb000000 0x0 0xfb000000 0x0 0xf0000 | |
| 77 | − 0x82000000 0x0 0xf6000000 0x0 0xf6000000 0x0 0x2000000 | |
| 78 | − 0x82000000 0x0 0xf9000000 0x0 0xf9000000 0x0 0x100000>; | |
| 79 | − phys = <&cp0_comphy0 0>; | |
| 80 | − status = "okay"; | |
| 81 | −}; | |
| @@ -0,0 +1,91 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/marvell,prestera.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Marvell Prestera switch family | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Miquel Raynal <miquel.raynal@bootlin.com> | |
| 11 | + | |
| 12 | +properties: | |
| 13 | + compatible: | |
| 14 | + oneOf: | |
| 15 | + - items: | |
| 16 | + - enum: | |
| 17 | + - marvell,prestera-98dx3236 | |
| 18 | + - marvell,prestera-98dx3336 | |
| 19 | + - marvell,prestera-98dx4251 | |
| 20 | + - const: marvell,prestera | |
| 21 | + - enum: | |
| 22 | + - pci11ab,c804 | |
| 23 | + - pci11ab,c80c | |
| 24 | + - pci11ab,cc1e | |
| 25 | + | |
| 26 | + reg: | |
| 27 | + maxItems: 1 | |
| 28 | + | |
| 29 | + interrupts: | |
| 30 | + maxItems: 3 | |
| 31 | + | |
| 32 | + dfx: | |
| 33 | + description: Reference to the DFX Server bus node. | |
| 34 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 35 | + | |
| 36 | + nvmem-cells: true | |
| 37 | + | |
| 38 | + nvmem-cell-names: true | |
| 39 | + | |
| 40 | +if: | |
| 41 | + properties: | |
| 42 | + compatible: | |
| 43 | + contains: | |
| 44 | + const: marvell,prestera | |
| 45 | + | |
| 46 | +# Memory mapped AlleyCat3 family | |
| 47 | +then: | |
| 48 | + properties: | |
| 49 | + nvmem-cells: false | |
| 50 | + nvmem-cell-names: false | |
| 51 | + required: | |
| 52 | + - interrupts | |
| 53 | + | |
| 54 | +# PCI Aldrin family | |
| 55 | +else: | |
| 56 | + properties: | |
| 57 | + interrupts: false | |
| 58 | + dfx: false | |
| 59 | + | |
| 60 | +required: | |
| 61 | + - compatible | |
| 62 | + - reg | |
| 63 | + | |
| 64 | +# Ports can also be described | |
| 65 | +additionalProperties: | |
| 66 | + type: object | |
| 67 | + | |
| 68 | +examples: | |
| 69 | + - | | |
| 70 | + packet-processor@0 { | |
| 71 | + compatible = "marvell,prestera-98dx3236", "marvell,prestera"; | |
| 72 | + reg = <0 0x4000000>; | |
| 73 | + interrupts = <33>, <34>, <35>; | |
| 74 | + dfx = <&dfx>; | |
| 75 | + }; | |
| 76 | + | |
| 77 | + - | | |
| 78 | + pcie@0 { | |
| 79 | + #address-cells = <3>; | |
| 80 | + #size-cells = <2>; | |
| 81 | + ranges = <0x0 0x0 0x0 0x0 0x0 0x0>; | |
| 82 | + reg = <0x0 0x0 0x0 0x0 0x0 0x0>; | |
| 83 | + device_type = "pci"; | |
| 84 | + | |
| 85 | + switch@0,0 { | |
| 86 | + reg = <0x0 0x0 0x0 0x0 0x0>; | |
| 87 | + compatible = "pci11ab,c80c"; | |
| 88 | + nvmem-cells = <&mac_address 0>; | |
| 89 | + nvmem-cell-names = "mac-address"; | |
| 90 | + }; | |
| 91 | + }; | |
| @@ -1,141 +0,0 @@ | ||
| 1 | −* Marvell Armada 375 Ethernet Controller (PPv2.1) | |
| 2 | − Marvell Armada 7K/8K Ethernet Controller (PPv2.2) | |
| 3 | − Marvell CN913X Ethernet Controller (PPv2.3) | |
| 4 | − | |
| 5 | −Required properties: | |
| 6 | − | |
| 7 | −- compatible: should be one of: | |
| 8 | − "marvell,armada-375-pp2" | |
| 9 | − "marvell,armada-7k-pp2" | |
| 10 | −- reg: addresses and length of the register sets for the device. | |
| 11 | − For "marvell,armada-375-pp2", must contain the following register | |
| 12 | − sets: | |
| 13 | − - common controller registers | |
| 14 | − - LMS registers | |
| 15 | − - one register area per Ethernet port | |
| 16 | − For "marvell,armada-7k-pp2" used by 7K/8K and CN913X, must contain the following register | |
| 17 | − sets: | |
| 18 | − - packet processor registers | |
| 19 | − - networking interfaces registers | |
| 20 | − - CM3 address space used for TX Flow Control | |
| 21 | − | |
| 22 | −- clocks: pointers to the reference clocks for this device, consequently: | |
| 23 | − - main controller clock (for both armada-375-pp2 and armada-7k-pp2) | |
| 24 | − - GOP clock (for both armada-375-pp2 and armada-7k-pp2) | |
| 25 | − - MG clock (only for armada-7k-pp2) | |
| 26 | − - MG Core clock (only for armada-7k-pp2) | |
| 27 | − - AXI clock (only for armada-7k-pp2) | |
| 28 | −- clock-names: names of used clocks, must be "pp_clk", "gop_clk", "mg_clk", | |
| 29 | − "mg_core_clk" and "axi_clk" (the 3 latter only for armada-7k-pp2). | |
| 30 | − | |
| 31 | −The ethernet ports are represented by subnodes. At least one port is | |
| 32 | −required. | |
| 33 | − | |
| 34 | −Required properties (port): | |
| 35 | − | |
| 36 | −- interrupts: interrupt(s) for the port | |
| 37 | −- port-id: ID of the port from the MAC point of view | |
| 38 | −- gop-port-id: only for marvell,armada-7k-pp2, ID of the port from the | |
| 39 | − GOP (Group Of Ports) point of view. This ID is used to index the | |
| 40 | − per-port registers in the second register area. | |
| 41 | −- phy-mode: See ethernet.txt file in the same directory | |
| 42 | − | |
| 43 | −Optional properties (port): | |
| 44 | − | |
| 45 | −- marvell,loopback: port is loopback mode | |
| 46 | −- phy: a phandle to a phy node defining the PHY address (as the reg | |
| 47 | − property, a single integer). | |
| 48 | −- interrupt-names: if more than a single interrupt for is given, must be the | |
| 49 | − name associated to the interrupts listed. Valid names are: | |
| 50 | − "hifX", with X in [0..8], and "link". The names "tx-cpu0", | |
| 51 | − "tx-cpu1", "tx-cpu2", "tx-cpu3" and "rx-shared" are supported | |
| 52 | − for backward compatibility but shouldn't be used for new | |
| 53 | − additions. | |
| 54 | −- marvell,system-controller: a phandle to the system controller. | |
| 55 | − | |
| 56 | −Example for marvell,armada-375-pp2: | |
| 57 | − | |
| 58 | −ethernet@f0000 { | |
| 59 | − compatible = "marvell,armada-375-pp2"; | |
| 60 | − reg = <0xf0000 0xa000>, | |
| 61 | − <0xc0000 0x3060>, | |
| 62 | − <0xc4000 0x100>, | |
| 63 | − <0xc5000 0x100>; | |
| 64 | − clocks = <&gateclk 3>, <&gateclk 19>; | |
| 65 | − clock-names = "pp_clk", "gop_clk"; | |
| 66 | − | |
| 67 | − eth0: eth0@c4000 { | |
| 68 | − interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; | |
| 69 | − port-id = <0>; | |
| 70 | − phy = <&phy0>; | |
| 71 | − phy-mode = "gmii"; | |
| 72 | − }; | |
| 73 | − | |
| 74 | − eth1: eth1@c5000 { | |
| 75 | − interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; | |
| 76 | − port-id = <1>; | |
| 77 | − phy = <&phy3>; | |
| 78 | − phy-mode = "gmii"; | |
| 79 | − }; | |
| 80 | −}; | |
| 81 | − | |
| 82 | −Example for marvell,armada-7k-pp2: | |
| 83 | − | |
| 84 | −cpm_ethernet: ethernet@0 { | |
| 85 | − compatible = "marvell,armada-7k-pp22"; | |
| 86 | − reg = <0x0 0x100000>, <0x129000 0xb000>, <0x220000 0x800>; | |
| 87 | − clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>, | |
| 88 | − <&cpm_syscon0 1 5>, <&cpm_syscon0 1 6>, <&cpm_syscon0 1 18>; | |
| 89 | − clock-names = "pp_clk", "gop_clk", "mg_clk", "mg_core_clk", "axi_clk"; | |
| 90 | − | |
| 91 | − eth0: eth0 { | |
| 92 | − interrupts = <ICU_GRP_NSR 39 IRQ_TYPE_LEVEL_HIGH>, | |
| 93 | − <ICU_GRP_NSR 43 IRQ_TYPE_LEVEL_HIGH>, | |
| 94 | − <ICU_GRP_NSR 47 IRQ_TYPE_LEVEL_HIGH>, | |
| 95 | − <ICU_GRP_NSR 51 IRQ_TYPE_LEVEL_HIGH>, | |
| 96 | − <ICU_GRP_NSR 55 IRQ_TYPE_LEVEL_HIGH>, | |
| 97 | − <ICU_GRP_NSR 59 IRQ_TYPE_LEVEL_HIGH>, | |
| 98 | − <ICU_GRP_NSR 63 IRQ_TYPE_LEVEL_HIGH>, | |
| 99 | − <ICU_GRP_NSR 67 IRQ_TYPE_LEVEL_HIGH>, | |
| 100 | − <ICU_GRP_NSR 71 IRQ_TYPE_LEVEL_HIGH>, | |
| 101 | − <ICU_GRP_NSR 129 IRQ_TYPE_LEVEL_HIGH>; | |
| 102 | − interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", | |
| 103 | − "hif5", "hif6", "hif7", "hif8", "link"; | |
| 104 | − port-id = <0>; | |
| 105 | − gop-port-id = <0>; | |
| 106 | − }; | |
| 107 | − | |
| 108 | − eth1: eth1 { | |
| 109 | − interrupts = <ICU_GRP_NSR 40 IRQ_TYPE_LEVEL_HIGH>, | |
| 110 | − <ICU_GRP_NSR 44 IRQ_TYPE_LEVEL_HIGH>, | |
| 111 | − <ICU_GRP_NSR 48 IRQ_TYPE_LEVEL_HIGH>, | |
| 112 | − <ICU_GRP_NSR 52 IRQ_TYPE_LEVEL_HIGH>, | |
| 113 | − <ICU_GRP_NSR 56 IRQ_TYPE_LEVEL_HIGH>, | |
| 114 | − <ICU_GRP_NSR 60 IRQ_TYPE_LEVEL_HIGH>, | |
| 115 | − <ICU_GRP_NSR 64 IRQ_TYPE_LEVEL_HIGH>, | |
| 116 | − <ICU_GRP_NSR 68 IRQ_TYPE_LEVEL_HIGH>, | |
| 117 | − <ICU_GRP_NSR 72 IRQ_TYPE_LEVEL_HIGH>, | |
| 118 | − <ICU_GRP_NSR 128 IRQ_TYPE_LEVEL_HIGH>; | |
| 119 | − interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", | |
| 120 | − "hif5", "hif6", "hif7", "hif8", "link"; | |
| 121 | − port-id = <1>; | |
| 122 | − gop-port-id = <2>; | |
| 123 | − }; | |
| 124 | − | |
| 125 | − eth2: eth2 { | |
| 126 | − interrupts = <ICU_GRP_NSR 41 IRQ_TYPE_LEVEL_HIGH>, | |
| 127 | − <ICU_GRP_NSR 45 IRQ_TYPE_LEVEL_HIGH>, | |
| 128 | − <ICU_GRP_NSR 49 IRQ_TYPE_LEVEL_HIGH>, | |
| 129 | − <ICU_GRP_NSR 53 IRQ_TYPE_LEVEL_HIGH>, | |
| 130 | − <ICU_GRP_NSR 57 IRQ_TYPE_LEVEL_HIGH>, | |
| 131 | − <ICU_GRP_NSR 61 IRQ_TYPE_LEVEL_HIGH>, | |
| 132 | − <ICU_GRP_NSR 65 IRQ_TYPE_LEVEL_HIGH>, | |
| 133 | − <ICU_GRP_NSR 69 IRQ_TYPE_LEVEL_HIGH>, | |
| 134 | − <ICU_GRP_NSR 73 IRQ_TYPE_LEVEL_HIGH>, | |
| 135 | − <ICU_GRP_NSR 127 IRQ_TYPE_LEVEL_HIGH>; | |
| 136 | − interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", | |
| 137 | − "hif5", "hif6", "hif7", "hif8", "link"; | |
| 138 | − port-id = <2>; | |
| 139 | − gop-port-id = <3>; | |
| 140 | − }; | |
| 141 | −}; | |
| @@ -39,7 +39,9 @@ properties: · 38 unmodified lines | ||
| 39 | 39 | - usb424,9e08 # SMSC LAN89530 USB Ethernet Device |
| 40 | 40 | - usb424,ec00 # SMSC9512/9514 USB Hub & Ethernet Device |
| 41 | 41 | |
| 42 | − reg: true | |
| 42 | + reg: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 43 | 45 | local-mac-address: true |
| 44 | 46 | mac-address: true |
| 45 | 47 | |
| @@ -14,7 +14,9 @@ properties: · 13 unmodified lines | ||
| 14 | 14 | oneOf: |
| 15 | 15 | - const: nxp,nxp-nci-i2c |
| 16 | 16 | - items: |
| 17 | − - const: nxp,pn547 | |
| 17 | + - enum: | |
| 18 | + - nxp,nq310 | |
| 19 | + - nxp,pn547 | |
| 18 | 20 | - const: nxp,nxp-nci-i2c |
| 19 | 21 | |
| 20 | 22 | enable-gpios: |
| @@ -7,7 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 6 unmodified lines | ||
| 7 | 7 | title: NXP i.MX8 DWMAC glue layer |
| 8 | 8 | |
| 9 | 9 | maintainers: |
| 10 | − - Joakim Zhang <qiangqing.zhang@nxp.com> | |
| 10 | + - Clark Wang <xiaoning.wang@nxp.com> | |
| 11 | + - Shawn Guo <shawnguo@kernel.org> | |
| 12 | + - NXP Linux Team <linux-imx@nxp.com> | |
| 11 | 13 | |
| 12 | 14 | # We need a select here so we don't match all nodes with 'snps,dwmac' |
| 13 | 15 | select: |
| @@ -0,0 +1,40 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/pcs/fsl,lynx-pcs.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: NXP Lynx PCS | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Ioana Ciornei <ioana.ciornei@nxp.com> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + NXP Lynx 10G and 28G SerDes have Ethernet PCS devices which can be used as | |
| 14 | + protocol controllers. They are accessible over the Ethernet interface's MDIO | |
| 15 | + bus. | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: fsl,lynx-pcs | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | +required: | |
| 25 | + - compatible | |
| 26 | + - reg | |
| 27 | + | |
| 28 | +additionalProperties: false | |
| 29 | + | |
| 30 | +examples: | |
| 31 | + - | | |
| 32 | + mdio-bus { | |
| 33 | + #address-cells = <1>; | |
| 34 | + #size-cells = <0>; | |
| 35 | + | |
| 36 | + qsgmii_pcs1: ethernet-pcs@1 { | |
| 37 | + compatible = "fsl,lynx-pcs"; | |
| 38 | + reg = <1>; | |
| 39 | + }; | |
| 40 | + }; | |
| @@ -123,7 +123,6 @@ examples: · 122 unmodified lines | ||
| 123 | 123 | |
| 124 | 124 | switch_port0: port@0 { |
| 125 | 125 | reg = <0x0>; |
| 126 | − label = "cpu"; | |
| 127 | 126 | ethernet = <ð1>; |
| 128 | 127 | |
| 129 | 128 | phy-mode = "gmii"; |
| @@ -49,6 +49,7 @@ properties: · 48 unmodified lines | ||
| 49 | 49 | - qcom,sc7280-ipa |
| 50 | 50 | - qcom,sdm845-ipa |
| 51 | 51 | - qcom,sdx55-ipa |
| 52 | + - qcom,sm6350-ipa | |
| 52 | 53 | - qcom,sm8350-ipa |
| 53 | 54 | |
| 54 | 55 | reg: |
| @@ -124,19 +125,31 @@ properties: · 69 unmodified lines | ||
| 124 | 125 | - const: ipa-clock-enabled-valid |
| 125 | 126 | - const: ipa-clock-enabled |
| 126 | 127 | |
| 128 | + qcom,gsi-loader: | |
| 129 | + enum: | |
| 130 | + - self | |
| 131 | + - modem | |
| 132 | + - skip | |
| 133 | + description: | |
| 134 | + Indicates how GSI firmware should be loaded. If the AP loads | |
| 135 | + and validates GSI firmware, this property has value "self". | |
| 136 | + If the modem does this, this property has value "modem". | |
| 137 | + Otherwise, "skip" means GSI firmware loading is not required. | |
| 138 | + | |
| 127 | 139 | modem-init: |
| 140 | + deprecated: true | |
| 128 | 141 | type: boolean |
| 129 | 142 | description: |
| 130 | − If present, it indicates that the modem is responsible for | |
| 131 | − performing early IPA initialization, including loading and | |
| 132 | − validating firwmare used by the GSI. | |
| 143 | + This is the older (deprecated) way of indicating how GSI firmware | |
| 144 | + should be loaded. If present, the modem loads GSI firmware; if | |
| 145 | + absent, the AP loads GSI firmware. | |
| 133 | 146 | |
| 134 | 147 | memory-region: |
| 135 | 148 | maxItems: 1 |
| 136 | 149 | description: |
| 137 | 150 | If present, a phandle for a reserved memory area that holds |
| 138 | 151 | the firmware passed to Trust Zone for authentication. Required |
| 139 | − when Trust Zone (not the modem) performs early initialization. | |
| 152 | + when the AP (not the modem) performs early initialization. | |
| 140 | 153 | |
| 141 | 154 | firmware-name: |
| 142 | 155 | $ref: /schemas/types.yaml#/definitions/string |
| @@ -155,22 +168,36 @@ required: · 12 unmodified lines | ||
| 155 | 168 | - interconnects |
| 156 | 169 | - qcom,smem-states |
| 157 | 170 | |
| 158 | −# Either modem-init is present, or memory-region must be present. | |
| 159 | −oneOf: | |
| 160 | − - required: | |
| 161 | − - modem-init | |
| 162 | − - required: | |
| 163 | − - memory-region | |
| 164 | − | |
| 165 | −# If memory-region is present, firmware-name may optionally be present. | |
| 166 | −# But if modem-init is present, firmware-name must not be present. | |
| 167 | −if: | |
| 168 | − required: | |
| 169 | − - modem-init | |
| 170 | −then: | |
| 171 | − not: | |
| 172 | − required: | |
| 173 | − - firmware-name | |
| 171 | +allOf: | |
| 172 | + # If qcom,gsi-loader is present, modem-init must not be present | |
| 173 | + - if: | |
| 174 | + required: | |
| 175 | + - qcom,gsi-loader | |
| 176 | + then: | |
| 177 | + properties: | |
| 178 | + modem-init: false | |
| 179 | + | |
| 180 | + # If qcom,gsi-loader is "self", the AP loads GSI firmware, and | |
| 181 | + # memory-region must be specified | |
| 182 | + if: | |
| 183 | + properties: | |
| 184 | + qcom,gsi-loader: | |
| 185 | + contains: | |
| 186 | + const: self | |
| 187 | + then: | |
| 188 | + required: | |
| 189 | + - memory-region | |
| 190 | + else: | |
| 191 | + # If qcom,gsi-loader is not present, we use deprecated behavior. | |
| 192 | + # If modem-init is not present, the AP loads GSI firmware, and | |
| 193 | + # memory-region must be specified. | |
| 194 | + if: | |
| 195 | + not: | |
| 196 | + required: | |
| 197 | + - modem-init | |
| 198 | + then: | |
| 199 | + required: | |
| 200 | + - memory-region | |
| 174 | 201 | |
| 175 | 202 | additionalProperties: false |
| 176 | 203 | |
| @@ -201,14 +228,17 @@ examples: · 24 unmodified lines | ||
| 201 | 228 | }; |
| 202 | 229 | |
| 203 | 230 | ipa@1e40000 { |
| 204 | − compatible = "qcom,sdm845-ipa"; | |
| 231 | + compatible = "qcom,sc7180-ipa"; | |
| 205 | 232 | |
| 206 | − modem-init; | |
| 233 | + qcom,gsi-loader = "self"; | |
| 234 | + memory-region = <&ipa_fw_mem>; | |
| 235 | + firmware-name = "qcom/sc7180-trogdor/modem/modem.mdt"; | |
| 207 | 236 | |
| 208 | − iommus = <&apps_smmu 0x720 0x3>; | |
| 237 | + iommus = <&apps_smmu 0x440 0x0>, | |
| 238 | + <&apps_smmu 0x442 0x0>; | |
| 209 | 239 | reg = <0x1e40000 0x7000>, |
| 210 | − <0x1e47000 0x2000>, | |
| 211 | − <0x1e04000 0x2c000>; | |
| 240 | + <0x1e47000 0x2000>, | |
| 241 | + <0x1e04000 0x2c000>; | |
| 212 | 242 | reg-names = "ipa-reg", |
| 213 | 243 | "ipa-shared", |
| 214 | 244 | "gsi"; |
| @@ -226,9 +256,9 @@ examples: · 11 unmodified lines | ||
| 226 | 256 | clock-names = "core"; |
| 227 | 257 | |
| 228 | 258 | interconnects = |
| 229 | − <&rsc_hlos MASTER_IPA &rsc_hlos SLAVE_EBI1>, | |
| 230 | − <&rsc_hlos MASTER_IPA &rsc_hlos SLAVE_IMEM>, | |
| 231 | − <&rsc_hlos MASTER_APPSS_PROC &rsc_hlos SLAVE_IPA_CFG>; | |
| 259 | + <&aggre2_noc MASTER_IPA 0 &mc_virt SLAVE_EBI1 0>, | |
| 260 | + <&aggre2_noc MASTER_IPA 0 &system_noc SLAVE_IMEM 0>, | |
| 261 | + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_IPA_CFG 0>; | |
| 232 | 262 | interconnect-names = "memory", |
| 233 | 263 | "imem", |
| 234 | 264 | "config"; |
| @@ -9,14 +9,18 @@ title: Qualcomm IPQ40xx MDIO Controller · 8 unmodified lines | ||
| 9 | 9 | maintainers: |
| 10 | 10 | - Robert Marko <robert.marko@sartura.hr> |
| 11 | 11 | |
| 12 | −allOf: | |
| 13 | − - $ref: "mdio.yaml#" | |
| 14 | − | |
| 15 | 12 | properties: |
| 16 | 13 | compatible: |
| 17 | − enum: | |
| 18 | − - qcom,ipq4019-mdio | |
| 19 | − - qcom,ipq5018-mdio | |
| 14 | + oneOf: | |
| 15 | + - enum: | |
| 16 | + - qcom,ipq4019-mdio | |
| 17 | + - qcom,ipq5018-mdio | |
| 18 | + | |
| 19 | + - items: | |
| 20 | + - enum: | |
| 21 | + - qcom,ipq6018-mdio | |
| 22 | + - qcom,ipq8074-mdio | |
| 23 | + - const: qcom,ipq4019-mdio | |
| 20 | 24 | |
| 21 | 25 | "#address-cells": |
| 22 | 26 | const: 1 |
| @@ -33,10 +37,12 @@ properties: · 10 unmodified lines | ||
| 33 | 37 | address range is only required by the platform IPQ50xx. |
| 34 | 38 | |
| 35 | 39 | clocks: |
| 36 | − maxItems: 1 | |
| 37 | − description: | | |
| 38 | − MDIO clock source frequency fixed to 100MHZ, this clock should be specified | |
| 39 | − by the platform IPQ807x, IPQ60xx and IPQ50xx. | |
| 40 | + items: | |
| 41 | + - description: MDIO clock source frequency fixed to 100MHZ | |
| 42 | + | |
| 43 | + clock-names: | |
| 44 | + items: | |
| 45 | + - const: gcc_mdio_ahb_clk | |
| 40 | 46 | |
| 41 | 47 | required: |
| 42 | 48 | - compatible |
| @@ -44,6 +50,26 @@ required: · 1 unmodified line | ||
| 44 | 50 | - "#address-cells" |
| 45 | 51 | - "#size-cells" |
| 46 | 52 | |
| 53 | +allOf: | |
| 54 | + - $ref: "mdio.yaml#" | |
| 55 | + | |
| 56 | + - if: | |
| 57 | + properties: | |
| 58 | + compatible: | |
| 59 | + contains: | |
| 60 | + enum: | |
| 61 | + - qcom,ipq5018-mdio | |
| 62 | + - qcom,ipq6018-mdio | |
| 63 | + - qcom,ipq8074-mdio | |
| 64 | + then: | |
| 65 | + required: | |
| 66 | + - clocks | |
| 67 | + - clock-names | |
| 68 | + else: | |
| 69 | + properties: | |
| 70 | + clocks: false | |
| 71 | + clock-names: false | |
| 72 | + | |
| 47 | 73 | unevaluatedProperties: false |
| 48 | 74 | |
| 49 | 75 | examples: |
| @@ -20,6 +20,7 @@ properties: · 19 unmodified lines | ||
| 20 | 20 | enum: |
| 21 | 21 | - realtek,rtl8723bs-bt |
| 22 | 22 | - realtek,rtl8723cs-bt |
| 23 | + - realtek,rtl8723ds-bt | |
| 23 | 24 | - realtek,rtl8822cs-bt |
| 24 | 25 | |
| 25 | 26 | device-wake-gpios: |
| @@ -0,0 +1,262 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/renesas,r8a779f0-ether-switch.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Renesas Ethernet Switch | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> | |
| 11 | + | |
| 12 | +properties: | |
| 13 | + compatible: | |
| 14 | + const: renesas,r8a779f0-ether-switch | |
| 15 | + | |
| 16 | + reg: | |
| 17 | + maxItems: 2 | |
| 18 | + | |
| 19 | + reg-names: | |
| 20 | + items: | |
| 21 | + - const: base | |
| 22 | + - const: secure_base | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 47 | |
| 26 | + | |
| 27 | + interrupt-names: | |
| 28 | + items: | |
| 29 | + - const: mfwd_error | |
| 30 | + - const: race_error | |
| 31 | + - const: coma_error | |
| 32 | + - const: gwca0_error | |
| 33 | + - const: gwca1_error | |
| 34 | + - const: etha0_error | |
| 35 | + - const: etha1_error | |
| 36 | + - const: etha2_error | |
| 37 | + - const: gptp0_status | |
| 38 | + - const: gptp1_status | |
| 39 | + - const: mfwd_status | |
| 40 | + - const: race_status | |
| 41 | + - const: coma_status | |
| 42 | + - const: gwca0_status | |
| 43 | + - const: gwca1_status | |
| 44 | + - const: etha0_status | |
| 45 | + - const: etha1_status | |
| 46 | + - const: etha2_status | |
| 47 | + - const: rmac0_status | |
| 48 | + - const: rmac1_status | |
| 49 | + - const: rmac2_status | |
| 50 | + - const: gwca0_rxtx0 | |
| 51 | + - const: gwca0_rxtx1 | |
| 52 | + - const: gwca0_rxtx2 | |
| 53 | + - const: gwca0_rxtx3 | |
| 54 | + - const: gwca0_rxtx4 | |
| 55 | + - const: gwca0_rxtx5 | |
| 56 | + - const: gwca0_rxtx6 | |
| 57 | + - const: gwca0_rxtx7 | |
| 58 | + - const: gwca1_rxtx0 | |
| 59 | + - const: gwca1_rxtx1 | |
| 60 | + - const: gwca1_rxtx2 | |
| 61 | + - const: gwca1_rxtx3 | |
| 62 | + - const: gwca1_rxtx4 | |
| 63 | + - const: gwca1_rxtx5 | |
| 64 | + - const: gwca1_rxtx6 | |
| 65 | + - const: gwca1_rxtx7 | |
| 66 | + - const: gwca0_rxts0 | |
| 67 | + - const: gwca0_rxts1 | |
| 68 | + - const: gwca1_rxts0 | |
| 69 | + - const: gwca1_rxts1 | |
| 70 | + - const: rmac0_mdio | |
| 71 | + - const: rmac1_mdio | |
| 72 | + - const: rmac2_mdio | |
| 73 | + - const: rmac0_phy | |
| 74 | + - const: rmac1_phy | |
| 75 | + - const: rmac2_phy | |
| 76 | + | |
| 77 | + clocks: | |
| 78 | + maxItems: 1 | |
| 79 | + | |
| 80 | + resets: | |
| 81 | + maxItems: 1 | |
| 82 | + | |
| 83 | + iommus: | |
| 84 | + maxItems: 16 | |
| 85 | + | |
| 86 | + power-domains: | |
| 87 | + maxItems: 1 | |
| 88 | + | |
| 89 | + ethernet-ports: | |
| 90 | + type: object | |
| 91 | + additionalProperties: false | |
| 92 | + | |
| 93 | + properties: | |
| 94 | + '#address-cells': | |
| 95 | + description: Port number of ETHA (TSNA). | |
| 96 | + const: 1 | |
| 97 | + | |
| 98 | + '#size-cells': | |
| 99 | + const: 0 | |
| 100 | + | |
| 101 | + patternProperties: | |
| 102 | + "^port@[0-9a-f]+$": | |
| 103 | + type: object | |
| 104 | + $ref: /schemas/net/ethernet-controller.yaml# | |
| 105 | + unevaluatedProperties: false | |
| 106 | + | |
| 107 | + properties: | |
| 108 | + reg: | |
| 109 | + maxItems: 1 | |
| 110 | + description: | |
| 111 | + Port number of ETHA (TSNA). | |
| 112 | + | |
| 113 | + phys: | |
| 114 | + maxItems: 1 | |
| 115 | + description: | |
| 116 | + Phandle of an Ethernet SERDES. | |
| 117 | + | |
| 118 | + mdio: | |
| 119 | + $ref: /schemas/net/mdio.yaml# | |
| 120 | + unevaluatedProperties: false | |
| 121 | + | |
| 122 | + required: | |
| 123 | + - reg | |
| 124 | + - phy-handle | |
| 125 | + - phy-mode | |
| 126 | + - phys | |
| 127 | + - mdio | |
| 128 | + | |
| 129 | +required: | |
| 130 | + - compatible | |
| 131 | + - reg | |
| 132 | + - reg-names | |
| 133 | + - interrupts | |
| 134 | + - interrupt-names | |
| 135 | + - clocks | |
| 136 | + - resets | |
| 137 | + - power-domains | |
| 138 | + - ethernet-ports | |
| 139 | + | |
| 140 | +additionalProperties: false | |
| 141 | + | |
| 142 | +examples: | |
| 143 | + - | | |
| 144 | + #include <dt-bindings/clock/r8a779f0-cpg-mssr.h> | |
| 145 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 146 | + #include <dt-bindings/power/r8a779f0-sysc.h> | |
| 147 | + | |
| 148 | + ethernet@e6880000 { | |
| 149 | + compatible = "renesas,r8a779f0-ether-switch"; | |
| 150 | + reg = <0xe6880000 0x20000>, <0xe68c0000 0x20000>; | |
| 151 | + reg-names = "base", "secure_base"; | |
| 152 | + interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>, | |
| 153 | + <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>, | |
| 154 | + <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>, | |
| 155 | + <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>, | |
| 156 | + <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>, | |
| 157 | + <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>, | |
| 158 | + <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, | |
| 159 | + <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>, | |
| 160 | + <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>, | |
| 161 | + <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>, | |
| 162 | + <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>, | |
| 163 | + <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>, | |
| 164 | + <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>, | |
| 165 | + <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>, | |
| 166 | + <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>, | |
| 167 | + <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>, | |
| 168 | + <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>, | |
| 169 | + <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>, | |
| 170 | + <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>, | |
| 171 | + <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>, | |
| 172 | + <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>, | |
| 173 | + <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>, | |
| 174 | + <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>, | |
| 175 | + <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>, | |
| 176 | + <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>, | |
| 177 | + <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>, | |
| 178 | + <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>, | |
| 179 | + <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>, | |
| 180 | + <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>, | |
| 181 | + <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>, | |
| 182 | + <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>, | |
| 183 | + <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>, | |
| 184 | + <GIC_SPI 291 IRQ_TYPE_LEVEL_HIGH>, | |
| 185 | + <GIC_SPI 292 IRQ_TYPE_LEVEL_HIGH>, | |
| 186 | + <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>, | |
| 187 | + <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>, | |
| 188 | + <GIC_SPI 295 IRQ_TYPE_LEVEL_HIGH>, | |
| 189 | + <GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>, | |
| 190 | + <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>, | |
| 191 | + <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>, | |
| 192 | + <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>, | |
| 193 | + <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>, | |
| 194 | + <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>, | |
| 195 | + <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>, | |
| 196 | + <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>, | |
| 197 | + <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>, | |
| 198 | + <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>; | |
| 199 | + interrupt-names = "mfwd_error", "race_error", | |
| 200 | + "coma_error", "gwca0_error", | |
| 201 | + "gwca1_error", "etha0_error", | |
| 202 | + "etha1_error", "etha2_error", | |
| 203 | + "gptp0_status", "gptp1_status", | |
| 204 | + "mfwd_status", "race_status", | |
| 205 | + "coma_status", "gwca0_status", | |
| 206 | + "gwca1_status", "etha0_status", | |
| 207 | + "etha1_status", "etha2_status", | |
| 208 | + "rmac0_status", "rmac1_status", | |
| 209 | + "rmac2_status", | |
| 210 | + "gwca0_rxtx0", "gwca0_rxtx1", | |
| 211 | + "gwca0_rxtx2", "gwca0_rxtx3", | |
| 212 | + "gwca0_rxtx4", "gwca0_rxtx5", | |
| 213 | + "gwca0_rxtx6", "gwca0_rxtx7", | |
| 214 | + "gwca1_rxtx0", "gwca1_rxtx1", | |
| 215 | + "gwca1_rxtx2", "gwca1_rxtx3", | |
| 216 | + "gwca1_rxtx4", "gwca1_rxtx5", | |
| 217 | + "gwca1_rxtx6", "gwca1_rxtx7", | |
| 218 | + "gwca0_rxts0", "gwca0_rxts1", | |
| 219 | + "gwca1_rxts0", "gwca1_rxts1", | |
| 220 | + "rmac0_mdio", "rmac1_mdio", | |
| 221 | + "rmac2_mdio", | |
| 222 | + "rmac0_phy", "rmac1_phy", | |
| 223 | + "rmac2_phy"; | |
| 224 | + clocks = <&cpg CPG_MOD 1505>; | |
| 225 | + power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>; | |
| 226 | + resets = <&cpg 1505>; | |
| 227 | + | |
| 228 | + ethernet-ports { | |
| 229 | + #address-cells = <1>; | |
| 230 | + #size-cells = <0>; | |
| 231 | + port@0 { | |
| 232 | + reg = <0>; | |
| 233 | + phy-handle = <ð_phy0>; | |
| 234 | + phy-mode = "sgmii"; | |
| 235 | + phys = <ð_serdes 0>; | |
| 236 | + mdio { | |
| 237 | + #address-cells = <1>; | |
| 238 | + #size-cells = <0>; | |
| 239 | + }; | |
| 240 | + }; | |
| 241 | + port@1 { | |
| 242 | + reg = <1>; | |
| 243 | + phy-handle = <ð_phy1>; | |
| 244 | + phy-mode = "sgmii"; | |
| 245 | + phys = <ð_serdes 1>; | |
| 246 | + mdio { | |
| 247 | + #address-cells = <1>; | |
| 248 | + #size-cells = <0>; | |
| 249 | + }; | |
| 250 | + }; | |
| 251 | + port@2 { | |
| 252 | + reg = <2>; | |
| 253 | + phy-handle = <ð_phy2>; | |
| 254 | + phy-mode = "sgmii"; | |
| 255 | + phys = <ð_serdes 2>; | |
| 256 | + mdio { | |
| 257 | + #address-cells = <1>; | |
| 258 | + #size-cells = <0>; | |
| 259 | + }; | |
| 260 | + }; | |
| 261 | + }; | |
| 262 | + }; | |
| @@ -22,7 +22,8 @@ properties: · 21 unmodified lines | ||
| 22 | 22 | phandle of an I2C bus controller for the SFP two wire serial |
| 23 | 23 | |
| 24 | 24 | maximum-power-milliwatt: |
| 25 | − maxItems: 1 | |
| 25 | + minimum: 1000 | |
| 26 | + default: 1000 | |
| 26 | 27 | description: |
| 27 | 28 | Maximum module power consumption Specifies the maximum power consumption |
| 28 | 29 | allowable by a module in the slot, in milli-Watts. Presently, modules can |
| @@ -167,56 +167,238 @@ properties: · 166 unmodified lines | ||
| 167 | 167 | snps,mtl-rx-config: |
| 168 | 168 | $ref: /schemas/types.yaml#/definitions/phandle |
| 169 | 169 | description: |
| 170 | − Multiple RX Queues parameters. Phandle to a node that can | |
| 171 | − contain the following properties | |
| 172 | − * snps,rx-queues-to-use, number of RX queues to be used in the | |
| 173 | − driver | |
| 174 | − * Choose one of these RX scheduling algorithms | |
| 175 | − * snps,rx-sched-sp, Strict priority | |
| 176 | − * snps,rx-sched-wsp, Weighted Strict priority | |
| 177 | − * For each RX queue | |
| 178 | − * Choose one of these modes | |
| 179 | − * snps,dcb-algorithm, Queue to be enabled as DCB | |
| 180 | − * snps,avb-algorithm, Queue to be enabled as AVB | |
| 181 | − * snps,map-to-dma-channel, Channel to map | |
| 182 | − * Specifiy specific packet routing | |
| 183 | − * snps,route-avcp, AV Untagged Control packets | |
| 184 | − * snps,route-ptp, PTP Packets | |
| 185 | − * snps,route-dcbcp, DCB Control Packets | |
| 186 | − * snps,route-up, Untagged Packets | |
| 187 | − * snps,route-multi-broad, Multicast & Broadcast Packets | |
| 188 | − * snps,priority, bitmask of the tagged frames priorities assigned to | |
| 189 | − the queue | |
| 170 | + Multiple RX Queues parameters. Phandle to a node that | |
| 171 | + implements the 'rx-queues-config' object described in | |
| 172 | + this binding. | |
| 173 | + | |
| 174 | + rx-queues-config: | |
| 175 | + type: object | |
| 176 | + properties: | |
| 177 | + snps,rx-queues-to-use: | |
| 178 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 179 | + description: number of RX queues to be used in the driver | |
| 180 | + snps,rx-sched-sp: | |
| 181 | + type: boolean | |
| 182 | + description: Strict priority | |
| 183 | + snps,rx-sched-wsp: | |
| 184 | + type: boolean | |
| 185 | + description: Weighted Strict priority | |
| 186 | + allOf: | |
| 187 | + - if: | |
| 188 | + required: | |
| 189 | + - snps,rx-sched-sp | |
| 190 | + then: | |
| 191 | + properties: | |
| 192 | + snps,rx-sched-wsp: false | |
| 193 | + - if: | |
| 194 | + required: | |
| 195 | + - snps,rx-sched-wsp | |
| 196 | + then: | |
| 197 | + properties: | |
| 198 | + snps,rx-sched-sp: false | |
| 199 | + patternProperties: | |
| 200 | + "^queue[0-9]$": | |
| 201 | + description: Each subnode represents a queue. | |
| 202 | + type: object | |
| 203 | + properties: | |
| 204 | + snps,dcb-algorithm: | |
| 205 | + type: boolean | |
| 206 | + description: Queue to be enabled as DCB | |
| 207 | + snps,avb-algorithm: | |
| 208 | + type: boolean | |
| 209 | + description: Queue to be enabled as AVB | |
| 210 | + snps,map-to-dma-channel: | |
| 211 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 212 | + description: DMA channel id to map | |
| 213 | + snps,route-avcp: | |
| 214 | + type: boolean | |
| 215 | + description: AV Untagged Control packets | |
| 216 | + snps,route-ptp: | |
| 217 | + type: boolean | |
| 218 | + description: PTP Packets | |
| 219 | + snps,route-dcbcp: | |
| 220 | + type: boolean | |
| 221 | + description: DCB Control Packets | |
| 222 | + snps,route-up: | |
| 223 | + type: boolean | |
| 224 | + description: Untagged Packets | |
| 225 | + snps,route-multi-broad: | |
| 226 | + type: boolean | |
| 227 | + description: Multicast & Broadcast Packets | |
| 228 | + snps,priority: | |
| 229 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 230 | + description: Bitmask of the tagged frames priorities assigned to the queue | |
| 231 | + allOf: | |
| 232 | + - if: | |
| 233 | + required: | |
| 234 | + - snps,dcb-algorithm | |
| 235 | + then: | |
| 236 | + properties: | |
| 237 | + snps,avb-algorithm: false | |
| 238 | + - if: | |
| 239 | + required: | |
| 240 | + - snps,avb-algorithm | |
| 241 | + then: | |
| 242 | + properties: | |
| 243 | + snps,dcb-algorithm: false | |
| 244 | + - if: | |
| 245 | + required: | |
| 246 | + - snps,route-avcp | |
| 247 | + then: | |
| 248 | + properties: | |
| 249 | + snps,route-ptp: false | |
| 250 | + snps,route-dcbcp: false | |
| 251 | + snps,route-up: false | |
| 252 | + snps,route-multi-broad: false | |
| 253 | + - if: | |
| 254 | + required: | |
| 255 | + - snps,route-ptp | |
| 256 | + then: | |
| 257 | + properties: | |
| 258 | + snps,route-avcp: false | |
| 259 | + snps,route-dcbcp: false | |
| 260 | + snps,route-up: false | |
| 261 | + snps,route-multi-broad: false | |
| 262 | + - if: | |
| 263 | + required: | |
| 264 | + - snps,route-dcbcp | |
| 265 | + then: | |
| 266 | + properties: | |
| 267 | + snps,route-avcp: false | |
| 268 | + snps,route-ptp: false | |
| 269 | + snps,route-up: false | |
| 270 | + snps,route-multi-broad: false | |
| 271 | + - if: | |
| 272 | + required: | |
| 273 | + - snps,route-up | |
| 274 | + then: | |
| 275 | + properties: | |
| 276 | + snps,route-avcp: false | |
| 277 | + snps,route-ptp: false | |
| 278 | + snps,route-dcbcp: false | |
| 279 | + snps,route-multi-broad: false | |
| 280 | + - if: | |
| 281 | + required: | |
| 282 | + - snps,route-multi-broad | |
| 283 | + then: | |
| 284 | + properties: | |
| 285 | + snps,route-avcp: false | |
| 286 | + snps,route-ptp: false | |
| 287 | + snps,route-dcbcp: false | |
| 288 | + snps,route-up: false | |
| 289 | + additionalProperties: false | |
| 290 | + additionalProperties: false | |
| 190 | 291 | |
| 191 | 292 | snps,mtl-tx-config: |
| 192 | 293 | $ref: /schemas/types.yaml#/definitions/phandle |
| 193 | 294 | description: |
| 194 | − Multiple TX Queues parameters. Phandle to a node that can | |
| 195 | − contain the following properties | |
| 196 | − * snps,tx-queues-to-use, number of TX queues to be used in the | |
| 197 | − driver | |
| 198 | − * Choose one of these TX scheduling algorithms | |
| 199 | − * snps,tx-sched-wrr, Weighted Round Robin | |
| 200 | − * snps,tx-sched-wfq, Weighted Fair Queuing | |
| 201 | − * snps,tx-sched-dwrr, Deficit Weighted Round Robin | |
| 202 | − * snps,tx-sched-sp, Strict priority | |
| 203 | − * For each TX queue | |
| 204 | − * snps,weight, TX queue weight (if using a DCB weight | |
| 205 | − algorithm) | |
| 206 | − * Choose one of these modes | |
| 207 | − * snps,dcb-algorithm, TX queue will be working in DCB | |
| 208 | − * snps,avb-algorithm, TX queue will be working in AVB | |
| 209 | − [Attention] Queue 0 is reserved for legacy traffic | |
| 210 | − and so no AVB is available in this queue. | |
| 211 | − * Configure Credit Base Shaper (if AVB Mode selected) | |
| 212 | − * snps,send_slope, enable Low Power Interface | |
| 213 | − * snps,idle_slope, unlock on WoL | |
| 214 | − * snps,high_credit, max write outstanding req. limit | |
| 215 | − * snps,low_credit, max read outstanding req. limit | |
| 216 | − * snps,priority, bitmask of the priorities assigned to the queue. | |
| 217 | − When a PFC frame is received with priorities matching the bitmask, | |
| 218 | − the queue is blocked from transmitting for the pause time specified | |
| 219 | − in the PFC frame. | |
| 295 | + Multiple TX Queues parameters. Phandle to a node that | |
| 296 | + implements the 'tx-queues-config' object described in | |
| 297 | + this binding. | |
| 298 | + | |
| 299 | + tx-queues-config: | |
| 300 | + type: object | |
| 301 | + properties: | |
| 302 | + snps,tx-queues-to-use: | |
| 303 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 304 | + description: number of TX queues to be used in the driver | |
| 305 | + snps,tx-sched-wrr: | |
| 306 | + type: boolean | |
| 307 | + description: Weighted Round Robin | |
| 308 | + snps,tx-sched-wfq: | |
| 309 | + type: boolean | |
| 310 | + description: Weighted Fair Queuing | |
| 311 | + snps,tx-sched-dwrr: | |
| 312 | + type: boolean | |
| 313 | + description: Deficit Weighted Round Robin | |
| 314 | + snps,tx-sched-sp: | |
| 315 | + type: boolean | |
| 316 | + description: Strict priority | |
| 317 | + allOf: | |
| 318 | + - if: | |
| 319 | + required: | |
| 320 | + - snps,tx-sched-wrr | |
| 321 | + then: | |
| 322 | + properties: | |
| 323 | + snps,tx-sched-wfq: false | |
| 324 | + snps,tx-sched-dwrr: false | |
| 325 | + snps,tx-sched-sp: false | |
| 326 | + - if: | |
| 327 | + required: | |
| 328 | + - snps,tx-sched-wfq | |
| 329 | + then: | |
| 330 | + properties: | |
| 331 | + snps,tx-sched-wrr: false | |
| 332 | + snps,tx-sched-dwrr: false | |
| 333 | + snps,tx-sched-sp: false | |
| 334 | + - if: | |
| 335 | + required: | |
| 336 | + - snps,tx-sched-dwrr | |
| 337 | + then: | |
| 338 | + properties: | |
| 339 | + snps,tx-sched-wrr: false | |
| 340 | + snps,tx-sched-wfq: false | |
| 341 | + snps,tx-sched-sp: false | |
| 342 | + - if: | |
| 343 | + required: | |
| 344 | + - snps,tx-sched-sp | |
| 345 | + then: | |
| 346 | + properties: | |
| 347 | + snps,tx-sched-wrr: false | |
| 348 | + snps,tx-sched-wfq: false | |
| 349 | + snps,tx-sched-dwrr: false | |
| 350 | + patternProperties: | |
| 351 | + "^queue[0-9]$": | |
| 352 | + description: Each subnode represents a queue. | |
| 353 | + type: object | |
| 354 | + properties: | |
| 355 | + snps,weight: | |
| 356 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 357 | + description: TX queue weight (if using a DCB weight algorithm) | |
| 358 | + snps,dcb-algorithm: | |
| 359 | + type: boolean | |
| 360 | + description: TX queue will be working in DCB | |
| 361 | + snps,avb-algorithm: | |
| 362 | + type: boolean | |
| 363 | + description: | |
| 364 | + TX queue will be working in AVB. | |
| 365 | + Queue 0 is reserved for legacy traffic and so no AVB is | |
| 366 | + available in this queue. | |
| 367 | + snps,send_slope: | |
| 368 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 369 | + description: enable Low Power Interface | |
| 370 | + snps,idle_slope: | |
| 371 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 372 | + description: unlock on WoL | |
| 373 | + snps,high_credit: | |
| 374 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 375 | + description: max write outstanding req. limit | |
| 376 | + snps,low_credit: | |
| 377 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 378 | + description: max read outstanding req. limit | |
| 379 | + snps,priority: | |
| 380 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 381 | + description: | |
| 382 | + Bitmask of the tagged frames priorities assigned to the queue. | |
| 383 | + When a PFC frame is received with priorities matching the bitmask, | |
| 384 | + the queue is blocked from transmitting for the pause time specified | |
| 385 | + in the PFC frame. | |
| 386 | + allOf: | |
| 387 | + - if: | |
| 388 | + required: | |
| 389 | + - snps,dcb-algorithm | |
| 390 | + then: | |
| 391 | + properties: | |
| 392 | + snps,avb-algorithm: false | |
| 393 | + - if: | |
| 394 | + required: | |
| 395 | + - snps,avb-algorithm | |
| 396 | + then: | |
| 397 | + properties: | |
| 398 | + snps,dcb-algorithm: false | |
| 399 | + snps,weight: false | |
| 400 | + additionalProperties: false | |
| 401 | + additionalProperties: false | |
| 220 | 402 | |
| 221 | 403 | snps,reset-gpio: |
| 222 | 404 | deprecated: true |
| @@ -463,41 +645,6 @@ additionalProperties: true · 240 unmodified lines | ||
| 463 | 645 | |
| 464 | 646 | examples: |
| 465 | 647 | - | |
| 466 | − stmmac_axi_setup: stmmac-axi-config { | |
| 467 | − snps,wr_osr_lmt = <0xf>; | |
| 468 | − snps,rd_osr_lmt = <0xf>; | |
| 469 | − snps,blen = <256 128 64 32 0 0 0>; | |
| 470 | − }; | |
| 471 | − | |
| 472 | − mtl_rx_setup: rx-queues-config { | |
| 473 | − snps,rx-queues-to-use = <1>; | |
| 474 | − snps,rx-sched-sp; | |
| 475 | − queue0 { | |
| 476 | − snps,dcb-algorithm; | |
| 477 | − snps,map-to-dma-channel = <0x0>; | |
| 478 | − snps,priority = <0x0>; | |
| 479 | − }; | |
| 480 | − }; | |
| 481 | − | |
| 482 | − mtl_tx_setup: tx-queues-config { | |
| 483 | − snps,tx-queues-to-use = <2>; | |
| 484 | − snps,tx-sched-wrr; | |
| 485 | − queue0 { | |
| 486 | − snps,weight = <0x10>; | |
| 487 | − snps,dcb-algorithm; | |
| 488 | − snps,priority = <0x0>; | |
| 489 | − }; | |
| 490 | − | |
| 491 | − queue1 { | |
| 492 | − snps,avb-algorithm; | |
| 493 | − snps,send_slope = <0x1000>; | |
| 494 | − snps,idle_slope = <0x1000>; | |
| 495 | − snps,high_credit = <0x3E800>; | |
| 496 | − snps,low_credit = <0xFFC18000>; | |
| 497 | − snps,priority = <0x1>; | |
| 498 | − }; | |
| 499 | − }; | |
| 500 | − | |
| 501 | 648 | gmac0: ethernet@e0800000 { |
| 502 | 649 | compatible = "snps,dwxgmac-2.10", "snps,dwxgmac"; |
| 503 | 650 | reg = <0xe0800000 0x8000>; |
| @@ -516,6 +663,42 @@ examples: · 12 unmodified lines | ||
| 516 | 663 | snps,axi-config = <&stmmac_axi_setup>; |
| 517 | 664 | snps,mtl-rx-config = <&mtl_rx_setup>; |
| 518 | 665 | snps,mtl-tx-config = <&mtl_tx_setup>; |
| 666 | + | |
| 667 | + stmmac_axi_setup: stmmac-axi-config { | |
| 668 | + snps,wr_osr_lmt = <0xf>; | |
| 669 | + snps,rd_osr_lmt = <0xf>; | |
| 670 | + snps,blen = <256 128 64 32 0 0 0>; | |
| 671 | + }; | |
| 672 | + | |
| 673 | + mtl_rx_setup: rx-queues-config { | |
| 674 | + snps,rx-queues-to-use = <1>; | |
| 675 | + snps,rx-sched-sp; | |
| 676 | + queue0 { | |
| 677 | + snps,dcb-algorithm; | |
| 678 | + snps,map-to-dma-channel = <0x0>; | |
| 679 | + snps,priority = <0x0>; | |
| 680 | + }; | |
| 681 | + }; | |
| 682 | + | |
| 683 | + mtl_tx_setup: tx-queues-config { | |
| 684 | + snps,tx-queues-to-use = <2>; | |
| 685 | + snps,tx-sched-wrr; | |
| 686 | + queue0 { | |
| 687 | + snps,weight = <0x10>; | |
| 688 | + snps,dcb-algorithm; | |
| 689 | + snps,priority = <0x0>; | |
| 690 | + }; | |
| 691 | + | |
| 692 | + queue1 { | |
| 693 | + snps,avb-algorithm; | |
| 694 | + snps,send_slope = <0x1000>; | |
| 695 | + snps,idle_slope = <0x1000>; | |
| 696 | + snps,high_credit = <0x3E800>; | |
| 697 | + snps,low_credit = <0xFFC18000>; | |
| 698 | + snps,priority = <0x1>; | |
| 699 | + }; | |
| 700 | + }; | |
| 701 | + | |
| 519 | 702 | mdio0 { |
| 520 | 703 | #address-cells = <1>; |
| 521 | 704 | #size-cells = <0>; |
| @@ -0,0 +1,73 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/socionext,synquacer-netsec.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Socionext NetSec Ethernet Controller IP | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Jassi Brar <jaswinder.singh@linaro.org> | |
| 11 | + - Ilias Apalodimas <ilias.apalodimas@linaro.org> | |
| 12 | + | |
| 13 | +allOf: | |
| 14 | + - $ref: ethernet-controller.yaml# | |
| 15 | + | |
| 16 | +properties: | |
| 17 | + compatible: | |
| 18 | + const: socionext,synquacer-netsec | |
| 19 | + | |
| 20 | + reg: | |
| 21 | + items: | |
| 22 | + - description: control register area | |
| 23 | + - description: EEPROM holding the MAC address and microengine firmware | |
| 24 | + | |
| 25 | + clocks: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + clock-names: | |
| 29 | + const: phy_ref_clk | |
| 30 | + | |
| 31 | + dma-coherent: true | |
| 32 | + | |
| 33 | + interrupts: | |
| 34 | + maxItems: 1 | |
| 35 | + | |
| 36 | + mdio: | |
| 37 | + $ref: mdio.yaml# | |
| 38 | + | |
| 39 | +required: | |
| 40 | + - compatible | |
| 41 | + - reg | |
| 42 | + - clocks | |
| 43 | + - clock-names | |
| 44 | + - interrupts | |
| 45 | + - mdio | |
| 46 | + | |
| 47 | +unevaluatedProperties: false | |
| 48 | + | |
| 49 | +examples: | |
| 50 | + - | | |
| 51 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 52 | + | |
| 53 | + ethernet@522d0000 { | |
| 54 | + compatible = "socionext,synquacer-netsec"; | |
| 55 | + reg = <0x522d0000 0x10000>, <0x10000000 0x10000>; | |
| 56 | + interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; | |
| 57 | + clocks = <&clk_netsec>; | |
| 58 | + clock-names = "phy_ref_clk"; | |
| 59 | + phy-mode = "rgmii"; | |
| 60 | + max-speed = <1000>; | |
| 61 | + max-frame-size = <9000>; | |
| 62 | + phy-handle = <&phy1>; | |
| 63 | + | |
| 64 | + mdio { | |
| 65 | + #address-cells = <1>; | |
| 66 | + #size-cells = <0>; | |
| 67 | + phy1: ethernet-phy@1 { | |
| 68 | + compatible = "ethernet-phy-ieee802.3-c22"; | |
| 69 | + reg = <1>; | |
| 70 | + }; | |
| 71 | + }; | |
| 72 | + }; | |
| 73 | +... | |
| @@ -1,56 +0,0 @@ | ||
| 1 | −* Socionext NetSec Ethernet Controller IP | |
| 2 | − | |
| 3 | −Required properties: | |
| 4 | −- compatible: Should be "socionext,synquacer-netsec" | |
| 5 | −- reg: Address and length of the control register area, followed by the | |
| 6 | − address and length of the EEPROM holding the MAC address and | |
| 7 | − microengine firmware | |
| 8 | −- interrupts: Should contain ethernet controller interrupt | |
| 9 | −- clocks: phandle to the PHY reference clock | |
| 10 | −- clock-names: Should be "phy_ref_clk" | |
| 11 | −- phy-mode: See ethernet.txt file in the same directory | |
| 12 | −- phy-handle: See ethernet.txt in the same directory. | |
| 13 | − | |
| 14 | −- mdio device tree subnode: When the Netsec has a phy connected to its local | |
| 15 | − mdio, there must be device tree subnode with the following | |
| 16 | − required properties: | |
| 17 | − | |
| 18 | − - #address-cells: Must be <1>. | |
| 19 | − - #size-cells: Must be <0>. | |
| 20 | − | |
| 21 | − For each phy on the mdio bus, there must be a node with the following | |
| 22 | − fields: | |
| 23 | − - compatible: Refer to phy.txt | |
| 24 | − - reg: phy id used to communicate to phy. | |
| 25 | − | |
| 26 | −Optional properties: (See ethernet.txt file in the same directory) | |
| 27 | −- dma-coherent: Boolean property, must only be present if memory | |
| 28 | − accesses performed by the device are cache coherent. | |
| 29 | −- max-speed: See ethernet.txt in the same directory. | |
| 30 | −- max-frame-size: See ethernet.txt in the same directory. | |
| 31 | − | |
| 32 | −The MAC address will be determined using the optional properties | |
| 33 | −defined in ethernet.txt. The 'phy-mode' property is required, but may | |
| 34 | −be set to the empty string if the PHY configuration is programmed by | |
| 35 | −the firmware or set by hardware straps, and needs to be preserved. | |
| 36 | − | |
| 37 | −Example: | |
| 38 | − eth0: ethernet@522d0000 { | |
| 39 | − compatible = "socionext,synquacer-netsec"; | |
| 40 | − reg = <0 0x522d0000 0x0 0x10000>, <0 0x10000000 0x0 0x10000>; | |
| 41 | − interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; | |
| 42 | − clocks = <&clk_netsec>; | |
| 43 | − clock-names = "phy_ref_clk"; | |
| 44 | − phy-mode = "rgmii"; | |
| 45 | − max-speed = <1000>; | |
| 46 | − max-frame-size = <9000>; | |
| 47 | − phy-handle = <&phy1>; | |
| 48 | − | |
| 49 | − mdio { | |
| 50 | − #address-cells = <1>; | |
| 51 | − #size-cells = <0>; | |
| 52 | − phy1: ethernet-phy@1 { | |
| 53 | − compatible = "ethernet-phy-ieee802.3-c22"; | |
| 54 | − reg = <1>; | |
| 55 | − }; | |
| 56 | − }; | |
| @@ -68,6 +68,8 @@ Optional properties: · 67 unmodified lines | ||
| 68 | 68 | - mdio : Child node for MDIO bus. Must be defined if PHY access is |
| 69 | 69 | required through the core's MDIO interface (i.e. always, |
| 70 | 70 | unless the PHY is accessed through a different bus). |
| 71 | + Non-standard MDIO bus frequency is supported via | |
| 72 | + "clock-frequency", see mdio.yaml. | |
| 71 | 73 | |
| 72 | 74 | - pcs-handle: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X |
| 73 | 75 | modes, where "pcs-handle" should be used to point |
| @@ -0,0 +1,51 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/soc/mediatek/mediatek,mt7986-wo-ccif.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: MediaTek Wireless Ethernet Dispatch (WED) WO controller interface for MT7986 | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Lorenzo Bianconi <lorenzo@kernel.org> | |
| 11 | + - Felix Fietkau <nbd@nbd.name> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The MediaTek wo-ccif provides a configuration interface for WED WO | |
| 15 | + controller used to perfrom offload rx packet processing (e.g. 802.11 | |
| 16 | + aggregation packet reordering or rx header translation) on MT7986 soc. | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + items: | |
| 21 | + - enum: | |
| 22 | + - mediatek,mt7986-wo-ccif | |
| 23 | + - const: syscon | |
| 24 | + | |
| 25 | + reg: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + interrupts: | |
| 29 | + maxItems: 1 | |
| 30 | + | |
| 31 | +required: | |
| 32 | + - compatible | |
| 33 | + - reg | |
| 34 | + - interrupts | |
| 35 | + | |
| 36 | +additionalProperties: false | |
| 37 | + | |
| 38 | +examples: | |
| 39 | + - | | |
| 40 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 41 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 42 | + soc { | |
| 43 | + #address-cells = <2>; | |
| 44 | + #size-cells = <2>; | |
| 45 | + | |
| 46 | + syscon@151a5000 { | |
| 47 | + compatible = "mediatek,mt7986-wo-ccif", "syscon"; | |
| 48 | + reg = <0 0x151a5000 0 0x1000>; | |
| 49 | + interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>; | |
| 50 | + }; | |
| 51 | + }; | |
| @@ -42,15 +42,13 @@ properties: · 41 unmodified lines | ||
| 42 | 42 | bluetooth: |
| 43 | 43 | type: object |
| 44 | 44 | additionalProperties: false |
| 45 | + allOf: | |
| 46 | + - $ref: /schemas/net/bluetooth/bluetooth-controller.yaml# | |
| 45 | 47 | properties: |
| 46 | 48 | compatible: |
| 47 | 49 | const: qcom,wcnss-bt |
| 48 | 50 | |
| 49 | − local-bd-address: | |
| 50 | − $ref: /schemas/types.yaml#/definitions/uint8-array | |
| 51 | − maxItems: 6 | |
| 52 | − description: | |
| 53 | − See Documentation/devicetree/bindings/net/bluetooth.txt | |
| 51 | + local-bd-address: true | |
| 54 | 52 | |
| 55 | 53 | required: |
| 56 | 54 | - compatible |
| @@ -566,7 +566,8 @@ miimon · 565 unmodified lines | ||
| 566 | 566 | link monitoring. A value of 100 is a good starting point. |
| 567 | 567 | The use_carrier option, below, affects how the link state is |
| 568 | 568 | determined. See the High Availability section for additional |
| 569 | − information. The default value is 0. | |
| 569 | + information. The default value is 100 if arp_interval is not | |
| 570 | + set. | |
| 570 | 571 | |
| 571 | 572 | min_links |
| 572 | 573 | |
| @@ -956,6 +957,7 @@ xmit_hash_policy · 383 unmodified lines | ||
| 956 | 957 | hash = hash XOR source IP XOR destination IP |
| 957 | 958 | hash = hash XOR (hash RSHIFT 16) |
| 958 | 959 | hash = hash XOR (hash RSHIFT 8) |
| 960 | + hash = hash RSHIFT 1 | |
| 959 | 961 | And then hash is reduced modulo slave count. |
| 960 | 962 | |
| 961 | 963 | If the protocol is IPv6 then the source and destination |
| @@ -1148,6 +1148,39 @@ tuning on deep embedded systems'. The author is running a MPC603e · 1147 unmodified lines | ||
| 1148 | 1148 | load without any problems ... |
| 1149 | 1149 | |
| 1150 | 1150 | |
| 1151 | +Switchable Termination Resistors | |
| 1152 | +-------------------------------- | |
| 1153 | + | |
| 1154 | +CAN bus requires a specific impedance across the differential pair, | |
| 1155 | +typically provided by two 120Ohm resistors on the farthest nodes of | |
| 1156 | +the bus. Some CAN controllers support activating / deactivating a | |
| 1157 | +termination resistor(s) to provide the correct impedance. | |
| 1158 | + | |
| 1159 | +Query the available resistances:: | |
| 1160 | + | |
| 1161 | + $ ip -details link show can0 | |
| 1162 | + ... | |
| 1163 | + termination 120 [ 0, 120 ] | |
| 1164 | + | |
| 1165 | +Activate the terminating resistor:: | |
| 1166 | + | |
| 1167 | + $ ip link set dev can0 type can termination 120 | |
| 1168 | + | |
| 1169 | +Deactivate the terminating resistor:: | |
| 1170 | + | |
| 1171 | + $ ip link set dev can0 type can termination 0 | |
| 1172 | + | |
| 1173 | +To enable termination resistor support to a can-controller, either | |
| 1174 | +implement in the controller's struct can-priv:: | |
| 1175 | + | |
| 1176 | + termination_const | |
| 1177 | + termination_const_cnt | |
| 1178 | + do_set_termination | |
| 1179 | + | |
| 1180 | +or add gpio control with the device tree entries from | |
| 1181 | +Documentation/devicetree/bindings/net/can/can-controller.yaml | |
| 1182 | + | |
| 1183 | + | |
| 1151 | 1184 | The Virtual CAN Driver (vcan) |
| 1152 | 1185 | ----------------------------- |
| 1153 | 1186 | |
| @@ -181,10 +181,13 @@ when necessary using the below listed API:: · 180 unmodified lines | ||
| 181 | 181 | - int dpaa2_mac_connect(struct dpaa2_mac *mac); |
| 182 | 182 | - void dpaa2_mac_disconnect(struct dpaa2_mac *mac); |
| 183 | 183 | |
| 184 | −A phylink integration is necessary only when the partner DPMAC is not of TYPE_FIXED. | |
| 185 | −One can check for this condition using the below API:: | |
| 184 | +A phylink integration is necessary only when the partner DPMAC is not of | |
| 185 | +``TYPE_FIXED``. This means it is either of ``TYPE_PHY``, or of | |
| 186 | +``TYPE_BACKPLANE`` (the difference being the two that in the ``TYPE_BACKPLANE`` | |
| 187 | +mode, the MC firmware does not access the PCS registers). One can check for | |
| 188 | +this condition using the following helper:: | |
| 186 | 189 | |
| 187 | − - bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,struct fsl_mc_io *mc_io); | |
| 190 | + - static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac); | |
| 188 | 191 | |
| 189 | 192 | Before connection to a MAC, the caller must allocate and populate the |
| 190 | 193 | dpaa2_mac structure with the associated net_device, a pointer to the MC portal |
| @@ -23,6 +23,7 @@ Supported Devices · 22 unmodified lines | ||
| 23 | 23 | ================= |
| 24 | 24 | Currently, this driver support following devices: |
| 25 | 25 | * Network controller: Cavium, Inc. Device b200 |
| 26 | + * Network controller: Cavium, Inc. Device b400 | |
| 26 | 27 | |
| 27 | 28 | Interface Control |
| 28 | 29 | ================= |
| @@ -25,7 +25,7 @@ Enabling the driver and kconfig options · 24 unmodified lines | ||
| 25 | 25 | | at build time via kernel Kconfig flags. |
| 26 | 26 | | Basic features, ethernet net device rx/tx offloads and XDP, are available with the most basic flags |
| 27 | 27 | | CONFIG_MLX5_CORE=y/m and CONFIG_MLX5_CORE_EN=y. |
| 28 | −| For the list of advanced features please see below. | |
| 28 | +| For the list of advanced features, please see below. | |
| 29 | 29 | |
| 30 | 30 | **CONFIG_MLX5_CORE=(y/m/n)** (module mlx5_core.ko) |
| 31 | 31 | |
| @@ -89,11 +89,11 @@ Enabling the driver and kconfig options · 57 unmodified lines | ||
| 89 | 89 | |
| 90 | 90 | **CONFIG_MLX5_EN_IPSEC=(y/n)** |
| 91 | 91 | |
| 92 | −| Enables `IPSec XFRM cryptography-offload accelaration <http://www.mellanox.com/related-docs/prod_software/Mellanox_Innova_IPsec_Ethernet_Adapter_Card_User_Manual.pdf>`_. | |
| 92 | +| Enables `IPSec XFRM cryptography-offload acceleration <http://www.mellanox.com/related-docs/prod_software/Mellanox_Innova_IPsec_Ethernet_Adapter_Card_User_Manual.pdf>`_. | |
| 93 | 93 | |
| 94 | 94 | **CONFIG_MLX5_EN_TLS=(y/n)** |
| 95 | 95 | |
| 96 | −| TLS cryptography-offload accelaration. | |
| 96 | +| TLS cryptography-offload acceleration. | |
| 97 | 97 | |
| 98 | 98 | |
| 99 | 99 | **CONFIG_MLX5_INFINIBAND=(y/n/m)** (module mlx5_ib.ko) |
| @@ -139,14 +139,14 @@ flow_steering_mode: Device flow steering mode · 39 unmodified lines | ||
| 139 | 139 | The flow steering mode parameter controls the flow steering mode of the driver. |
| 140 | 140 | Two modes are supported: |
| 141 | 141 | 1. 'dmfs' - Device managed flow steering. |
| 142 | −2. 'smfs - Software/Driver managed flow steering. | |
| 142 | +2. 'smfs' - Software/Driver managed flow steering. | |
| 143 | 143 | |
| 144 | 144 | In DMFS mode, the HW steering entities are created and managed through the |
| 145 | 145 | Firmware. |
| 146 | 146 | In SMFS mode, the HW steering entities are created and managed though by |
| 147 | −the driver directly into Hardware without firmware intervention. | |
| 147 | +the driver directly into hardware without firmware intervention. | |
| 148 | 148 | |
| 149 | −SMFS mode is faster and provides better rule inserstion rate compared to default DMFS mode. | |
| 149 | +SMFS mode is faster and provides better rule insertion rate compared to default DMFS mode. | |
| 150 | 150 | |
| 151 | 151 | User command examples: |
| 152 | 152 | |
| @@ -165,9 +165,9 @@ User command examples: · 12 unmodified lines | ||
| 165 | 165 | enable_roce: RoCE enablement state |
| 166 | 166 | ---------------------------------- |
| 167 | 167 | RoCE enablement state controls driver support for RoCE traffic. |
| 168 | −When RoCE is disabled, there is no gid table, only raw ethernet QPs are supported and traffic on the well known UDP RoCE port is handled as raw ethernet traffic. | |
| 168 | +When RoCE is disabled, there is no gid table, only raw ethernet QPs are supported and traffic on the well-known UDP RoCE port is handled as raw ethernet traffic. | |
| 169 | 169 | |
| 170 | −To change RoCE enablement state a user must change the driverinit cmode value and run devlink reload. | |
| 170 | +To change RoCE enablement state, a user must change the driverinit cmode value and run devlink reload. | |
| 171 | 171 | |
| 172 | 172 | User command examples: |
| 173 | 173 | |
| @@ -186,7 +186,7 @@ User command examples: · 12 unmodified lines | ||
| 186 | 186 | |
| 187 | 187 | esw_port_metadata: Eswitch port metadata state |
| 188 | 188 | ---------------------------------------------- |
| 189 | −When applicable, disabling Eswitch metadata can increase packet rate | |
| 189 | +When applicable, disabling eswitch metadata can increase packet rate | |
| 190 | 190 | up to 20% depending on the use case and packet sizes. |
| 191 | 191 | |
| 192 | 192 | Eswitch port metadata state controls whether to internally tag packets with |
| @@ -253,26 +253,26 @@ mlx5 subfunction · 60 unmodified lines | ||
| 253 | 253 | ================ |
| 254 | 254 | mlx5 supports subfunction management using devlink port (see :ref:`Documentation/networking/devlink/devlink-port.rst <devlink_port>`) interface. |
| 255 | 255 | |
| 256 | −A Subfunction has its own function capabilities and its own resources. This | |
| 256 | +A subfunction has its own function capabilities and its own resources. This | |
| 257 | 257 | means a subfunction has its own dedicated queues (txq, rxq, cq, eq). These |
| 258 | 258 | queues are neither shared nor stolen from the parent PCI function. |
| 259 | 259 | |
| 260 | −When a subfunction is RDMA capable, it has its own QP1, GID table and rdma | |
| 260 | +When a subfunction is RDMA capable, it has its own QP1, GID table, and RDMA | |
| 261 | 261 | resources neither shared nor stolen from the parent PCI function. |
| 262 | 262 | |
| 263 | 263 | A subfunction has a dedicated window in PCI BAR space that is not shared |
| 264 | −with ther other subfunctions or the parent PCI function. This ensures that all | |
| 265 | −devices (netdev, rdma, vdpa etc.) of the subfunction accesses only assigned | |
| 264 | +with the other subfunctions or the parent PCI function. This ensures that all | |
| 265 | +devices (netdev, rdma, vdpa, etc.) of the subfunction accesses only assigned | |
| 266 | 266 | PCI BAR space. |
| 267 | 267 | |
| 268 | −A Subfunction supports eswitch representation through which it supports tc | |
| 268 | +A subfunction supports eswitch representation through which it supports tc | |
| 269 | 269 | offloads. The user configures eswitch to send/receive packets from/to |
| 270 | 270 | the subfunction port. |
| 271 | 271 | |
| 272 | 272 | Subfunctions share PCI level resources such as PCI MSI-X IRQs with |
| 273 | 273 | other subfunctions and/or with its parent PCI function. |
| 274 | 274 | |
| 275 | −Example mlx5 software, system and device view:: | |
| 275 | +Example mlx5 software, system, and device view:: | |
| 276 | 276 | |
| 277 | 277 | _______ |
| 278 | 278 | | admin | |
| @@ -310,7 +310,7 @@ Example mlx5 software, system and device view:: · 31 unmodified lines | ||
| 310 | 310 | | (device add/del) |
| 311 | 311 | _____|____ ____|________ |
| 312 | 312 | | | | subfunction | |
| 313 | − | PCI NIC |---- activate/deactive events---->| host driver | | |
| 313 | + | PCI NIC |--- activate/deactivate events--->| host driver | | |
| 314 | 314 | |__________| | (mlx5_core) | |
| 315 | 315 | |_____________| |
| 316 | 316 | |
| @@ -320,7 +320,7 @@ Subfunction is created using devlink port interface. · 3 unmodified lines | ||
| 320 | 320 | |
| 321 | 321 | $ devlink dev eswitch set pci/0000:06:00.0 mode switchdev |
| 322 | 322 | |
| 323 | −- Add a devlink port of subfunction flaovur:: | |
| 323 | +- Add a devlink port of subfunction flavour:: | |
| 324 | 324 | |
| 325 | 325 | $ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88 |
| 326 | 326 | pci/0000:06:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false |
| @@ -351,46 +351,30 @@ driver. · 24 unmodified lines | ||
| 351 | 351 | |
| 352 | 352 | MAC address setup |
| 353 | 353 | ----------------- |
| 354 | −mlx5 driver provides mechanism to setup the MAC address of the PCI VF/SF. | |
| 354 | +mlx5 driver support devlink port function attr mechanism to setup MAC | |
| 355 | +address. (refer to Documentation/networking/devlink/devlink-port.rst) | |
| 355 | 356 | |
| 356 | −The configured MAC address of the PCI VF/SF will be used by netdevice and rdma | |
| 357 | −device created for the PCI VF/SF. | |
| 357 | +RoCE capability setup | |
| 358 | +--------------------- | |
| 359 | +Not all mlx5 PCI devices/SFs require RoCE capability. | |
| 358 | 360 | |
| 359 | −- Get the MAC address of the VF identified by its unique devlink port index:: | |
| 361 | +When RoCE capability is disabled, it saves 1 Mbytes worth of system memory per | |
| 362 | +PCI devices/SF. | |
| 360 | 363 | |
| 361 | − $ devlink port show pci/0000:06:00.0/2 | |
| 362 | − pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 363 | − function: | |
| 364 | − hw_addr 00:00:00:00:00:00 | |
| 365 | − | |
| 366 | −- Set the MAC address of the VF identified by its unique devlink port index:: | |
| 367 | − | |
| 368 | − $ devlink port function set pci/0000:06:00.0/2 hw_addr 00:11:22:33:44:55 | |
| 369 | − | |
| 370 | − $ devlink port show pci/0000:06:00.0/2 | |
| 371 | − pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 372 | − function: | |
| 373 | − hw_addr 00:11:22:33:44:55 | |
| 364 | +mlx5 driver support devlink port function attr mechanism to setup RoCE | |
| 365 | +capability. (refer to Documentation/networking/devlink/devlink-port.rst) | |
| 374 | 366 | |
| 375 | −- Get the MAC address of the SF identified by its unique devlink port index:: | |
| 367 | +migratable capability setup | |
| 368 | +--------------------------- | |
| 369 | +User who wants mlx5 PCI VFs to be able to perform live migration need to | |
| 370 | +explicitly enable the VF migratable capability. | |
| 376 | 371 | |
| 377 | − $ devlink port show pci/0000:06:00.0/32768 | |
| 378 | − pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcisf pfnum 0 sfnum 88 | |
| 379 | − function: | |
| 380 | − hw_addr 00:00:00:00:00:00 | |
| 381 | − | |
| 382 | −- Set the MAC address of the VF identified by its unique devlink port index:: | |
| 383 | − | |
| 384 | − $ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 | |
| 385 | − | |
| 386 | − $ devlink port show pci/0000:06:00.0/32768 | |
| 387 | − pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcivf pfnum 0 sfnum 88 | |
| 388 | − function: | |
| 389 | − hw_addr 00:00:00:00:88:88 | |
| 372 | +mlx5 driver support devlink port function attr mechanism to setup migratable | |
| 373 | +capability. (refer to Documentation/networking/devlink/devlink-port.rst) | |
| 390 | 374 | |
| 391 | 375 | SF state setup |
| 392 | 376 | -------------- |
| 393 | −To use the SF, the user must active the SF using the SF function state | |
| 377 | +To use the SF, the user must activate the SF using the SF function state | |
| 394 | 378 | attribute. |
| 395 | 379 | |
| 396 | 380 | - Get the state of the SF identified by its unique devlink port index:: |
| @@ -447,7 +431,7 @@ for it. · 50 unmodified lines | ||
| 447 | 431 | |
| 448 | 432 | Additionally, the SF port also gets the event when the driver attaches to the |
| 449 | 433 | auxiliary device of the subfunction. This results in changing the operational |
| 450 | −state of the function. This provides visiblity to the user to decide when is it | |
| 434 | +state of the function. This provides visibility to the user to decide when is it | |
| 451 | 435 | safe to delete the SF port for graceful termination of the subfunction. |
| 452 | 436 | |
| 453 | 437 | - Show the SF port operational state:: |
| @@ -464,14 +448,14 @@ tx reporter · 10 unmodified lines | ||
| 464 | 448 | ----------- |
| 465 | 449 | The tx reporter is responsible for reporting and recovering of the following two error scenarios: |
| 466 | 450 | |
| 467 | −- TX timeout | |
| 451 | +- tx timeout | |
| 468 | 452 | Report on kernel tx timeout detection. |
| 469 | 453 | Recover by searching lost interrupts. |
| 470 | −- TX error completion | |
| 454 | +- tx error completion | |
| 471 | 455 | Report on error tx completion. |
| 472 | − Recover by flushing the TX queue and reset it. | |
| 456 | + Recover by flushing the tx queue and reset it. | |
| 473 | 457 | |
| 474 | −TX reporter also support on demand diagnose callback, on which it provides | |
| 458 | +tx reporter also support on demand diagnose callback, on which it provides | |
| 475 | 459 | real time information of its send queues status. |
| 476 | 460 | |
| 477 | 461 | User commands examples: |
| @@ -491,32 +475,32 @@ rx reporter · 13 unmodified lines | ||
| 491 | 475 | ----------- |
| 492 | 476 | The rx reporter is responsible for reporting and recovering of the following two error scenarios: |
| 493 | 477 | |
| 494 | −- RX queues initialization (population) timeout | |
| 495 | − RX queues descriptors population on ring initialization is done in | |
| 496 | − napi context via triggering an irq, in case of a failure to get | |
| 497 | − the minimum amount of descriptors, a timeout would occur and it | |
| 498 | − could be recoverable by polling the EQ (Event Queue). | |
| 499 | −- RX completions with errors (reported by HW on interrupt context) | |
| 478 | +- rx queues' initialization (population) timeout | |
| 479 | + Population of rx queues' descriptors on ring initialization is done | |
| 480 | + in napi context via triggering an irq. In case of a failure to get | |
| 481 | + the minimum amount of descriptors, a timeout would occur, and | |
| 482 | + descriptors could be recovered by polling the EQ (Event Queue). | |
| 483 | +- rx completions with errors (reported by HW on interrupt context) | |
| 500 | 484 | Report on rx completion error. |
| 501 | 485 | Recover (if needed) by flushing the related queue and reset it. |
| 502 | 486 | |
| 503 | −RX reporter also supports on demand diagnose callback, on which it | |
| 504 | −provides real time information of its receive queues status. | |
| 487 | +rx reporter also supports on demand diagnose callback, on which it | |
| 488 | +provides real time information of its receive queues' status. | |
| 505 | 489 | |
| 506 | −- Diagnose rx queues status, and corresponding completion queue:: | |
| 490 | +- Diagnose rx queues' status and corresponding completion queue:: | |
| 507 | 491 | |
| 508 | 492 | $ devlink health diagnose pci/0000:82:00.0 reporter rx |
| 509 | 493 | |
| 510 | −NOTE: This command has valid output only when interface is up, otherwise the command has empty output. | |
| 494 | +NOTE: This command has valid output only when interface is up. Otherwise, the command has empty output. | |
| 511 | 495 | |
| 512 | 496 | - Show number of rx errors indicated, number of recover flows ended successfully, |
| 513 | − is autorecover enabled and graceful period from last recover:: | |
| 497 | + is autorecover enabled, and graceful period from last recover:: | |
| 514 | 498 | |
| 515 | 499 | $ devlink health show pci/0000:82:00.0 reporter rx |
| 516 | 500 | |
| 517 | 501 | fw reporter |
| 518 | 502 | ----------- |
| 519 | −The fw reporter implements diagnose and dump callbacks. | |
| 503 | +The fw reporter implements `diagnose` and `dump` callbacks. | |
| 520 | 504 | It follows symptoms of fw error such as fw syndrome by triggering |
| 521 | 505 | fw core dump and storing it into the dump buffer. |
| 522 | 506 | The fw reporter diagnose command can be triggered any time by the user to check |
| @@ -537,7 +521,7 @@ running it on other PF or any VF will return "Operation not permitted". · 14 unmodified lines | ||
| 537 | 521 | |
| 538 | 522 | fw fatal reporter |
| 539 | 523 | ----------------- |
| 540 | −The fw fatal reporter implements dump and recover callbacks. | |
| 524 | +The fw fatal reporter implements `dump` and `recover` callbacks. | |
| 541 | 525 | It follows fatal errors indications by CR-space dump and recover flow. |
| 542 | 526 | The CR-space dump uses vsc interface which is valid even if the FW command |
| 543 | 527 | interface is not functional, which is the case in most FW fatal errors. |
| @@ -552,7 +536,7 @@ User commands examples: · 8 unmodified lines | ||
| 552 | 536 | |
| 553 | 537 | $ devlink health recover pci/0000:82:00.0 reporter fw_fatal |
| 554 | 538 | |
| 555 | −- Read FW CR-space dump if already strored or trigger new one:: | |
| 539 | +- Read FW CR-space dump if already stored or trigger new one:: | |
| 556 | 540 | |
| 557 | 541 | $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal |
| 558 | 542 | |
| @@ -561,10 +545,10 @@ NOTE: This command can run only on PF. · 2 unmodified lines | ||
| 561 | 545 | mlx5 tracepoints |
| 562 | 546 | ================ |
| 563 | 547 | |
| 564 | −mlx5 driver provides internal trace points for tracking and debugging using | |
| 548 | +mlx5 driver provides internal tracepoints for tracking and debugging using | |
| 565 | 549 | kernel tracepoints interfaces (refer to Documentation/trace/ftrace.rst). |
| 566 | 550 | |
| 567 | −For the list of support mlx5 events check /sys/kernel/debug/tracing/events/mlx5/ | |
| 551 | +For the list of support mlx5 events, check `/sys/kernel/debug/tracing/events/mlx5/`. | |
| 568 | 552 | |
| 569 | 553 | tc and eswitch offloads tracepoints: |
| 570 | 554 | |
| @@ -1,50 +1,57 @@ | ||
| 1 | 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
| 2 | +.. include:: <isonum.txt> | |
| 2 | 3 | |
| 3 | −============================================= | |
| 4 | −Netronome Flow Processor (NFP) Kernel Drivers | |
| 5 | −============================================= | |
| 4 | +=========================================== | |
| 5 | +Network Flow Processor (NFP) Kernel Drivers | |
| 6 | +=========================================== | |
| 6 | 7 | |
| 7 | −Copyright (c) 2019, Netronome Systems, Inc. | |
| 8 | +:Copyright: |copy| 2019, Netronome Systems, Inc. | |
| 9 | +:Copyright: |copy| 2022, Corigine, Inc. | |
| 8 | 10 | |
| 9 | 11 | Contents |
| 10 | 12 | ======== |
| 11 | 13 | |
| 12 | 14 | - `Overview`_ |
| 13 | 15 | - `Acquiring Firmware`_ |
| 16 | +- `Devlink Info`_ | |
| 17 | +- `Configure Device`_ | |
| 18 | +- `Statistics`_ | |
| 14 | 19 | |
| 15 | 20 | Overview |
| 16 | 21 | ======== |
| 17 | 22 | |
| 18 | −This driver supports Netronome's line of Flow Processor devices, | |
| 19 | −including the NFP4000, NFP5000, and NFP6000 models, which are also | |
| 20 | −incorporated in the company's family of Agilio SmartNICs. The SR-IOV | |
| 21 | −physical and virtual functions for these devices are supported by | |
| 22 | −the driver. | |
| 23 | +This driver supports Netronome and Corigine's line of Network Flow Processor | |
| 24 | +devices, including the NFP3800, NFP4000, NFP5000, and NFP6000 models, which | |
| 25 | +are also incorporated in the companies' family of Agilio SmartNICs. The SR-IOV | |
| 26 | +physical and virtual functions for these devices are supported by the driver. | |
| 23 | 27 | |
| 24 | 28 | Acquiring Firmware |
| 25 | 29 | ================== |
| 26 | 30 | |
| 27 | −The NFP4000 and NFP6000 devices require application specific firmware | |
| 28 | −to function. Application firmware can be located either on the host file system | |
| 31 | +The NFP3800, NFP4000 and NFP6000 devices require application specific firmware | |
| 32 | +to function. Application firmware can be located either on the host file system | |
| 29 | 33 | or in the device flash (if supported by management firmware). |
| 30 | 34 | |
| 31 | 35 | Firmware files on the host filesystem contain card type (`AMDA-*` string), media |
| 32 | −config etc. They should be placed in `/lib/firmware/netronome` directory to | |
| 36 | +config etc. They should be placed in `/lib/firmware/netronome` directory to | |
| 33 | 37 | load firmware from the host file system. |
| 34 | 38 | |
| 35 | 39 | Firmware for basic NIC operation is available in the upstream |
| 36 | 40 | `linux-firmware.git` repository. |
| 37 | 41 | |
| 42 | +A more comprehensive list of firmware can be downloaded from the | |
| 43 | +`Corigine Support site <https://www.corigine.com/DPUDownload.html>`_. | |
| 44 | + | |
| 38 | 45 | Firmware in NVRAM |
| 39 | 46 | ----------------- |
| 40 | 47 | |
| 41 | 48 | Recent versions of management firmware supports loading application |
| 42 | −firmware from flash when the host driver gets probed. The firmware loading | |
| 49 | +firmware from flash when the host driver gets probed. The firmware loading | |
| 43 | 50 | policy configuration may be used to configure this feature appropriately. |
| 44 | 51 | |
| 45 | 52 | Devlink or ethtool can be used to update the application firmware on the device |
| 46 | 53 | flash by providing the appropriate `nic_AMDA*.nffw` file to the respective |
| 47 | −command. Users need to take care to write the correct firmware image for the | |
| 54 | +command. Users need to take care to write the correct firmware image for the | |
| 48 | 55 | card and media configuration to flash. |
| 49 | 56 | |
| 50 | 57 | Available storage space in flash depends on the card being used. |
| @@ -79,9 +86,9 @@ You may need to use hard instead of symbolic links on distributions · 28 unmodified lines | ||
| 79 | 86 | which use old `mkinitrd` command instead of `dracut` (e.g. Ubuntu). |
| 80 | 87 | |
| 81 | 88 | After changing firmware files you may need to regenerate the initramfs |
| 82 | −image. Initramfs contains drivers and firmware files your system may | |
| 83 | −need to boot. Refer to the documentation of your distribution to find | |
| 84 | −out how to update initramfs. Good indication of stale initramfs | |
| 89 | +image. Initramfs contains drivers and firmware files your system may | |
| 90 | +need to boot. Refer to the documentation of your distribution to find | |
| 91 | +out how to update initramfs. Good indication of stale initramfs | |
| 85 | 92 | is system loading wrong driver or firmware on boot, but when driver is |
| 86 | 93 | later reloaded manually everything works correctly. |
| 87 | 94 | |
| @@ -89,9 +96,9 @@ Selecting firmware per device · 1 unmodified line | ||
| 89 | 96 | ----------------------------- |
| 90 | 97 | |
| 91 | 98 | Most commonly all cards on the system use the same type of firmware. |
| 92 | −If you want to load specific firmware image for a specific card, you | |
| 93 | −can use either the PCI bus address or serial number. Driver will print | |
| 94 | −which files it's looking for when it recognizes a NFP device:: | |
| 99 | +If you want to load a specific firmware image for a specific card, you | |
| 100 | +can use either the PCI bus address or serial number. The driver will | |
| 101 | +print which files it's looking for when it recognizes a NFP device:: | |
| 95 | 102 | |
| 96 | 103 | nfp: Looking for firmware file in order of priority: |
| 97 | 104 | nfp: netronome/serial-00-12-34-aa-bb-cc-10-ff.nffw: not found |
| @@ -106,6 +113,15 @@ Note that `serial-*` and `pci-*` files are **not** automatically included · 8 unmodified lines | ||
| 106 | 113 | in initramfs, you will have to refer to documentation of appropriate tools |
| 107 | 114 | to find out how to include them. |
| 108 | 115 | |
| 116 | +Running firmware version | |
| 117 | +------------------------ | |
| 118 | + | |
| 119 | +The version of the loaded firmware for a particular <netdev> interface, | |
| 120 | +(e.g. enp4s0), or an interface's port <netdev port> (e.g. enp4s0np0) can | |
| 121 | +be displayed with the ethtool command:: | |
| 122 | + | |
| 123 | + $ ethtool -i <netdev> | |
| 124 | + | |
| 109 | 125 | Firmware loading policy |
| 110 | 126 | ----------------------- |
| 111 | 127 | |
| @@ -132,6 +148,115 @@ abi_drv_load_ifc · 20 unmodified lines | ||
| 132 | 148 | Defines a list of PF devices allowed to load FW on the device. |
| 133 | 149 | This variable is not currently user configurable. |
| 134 | 150 | |
| 151 | +Devlink Info | |
| 152 | +============ | |
| 153 | + | |
| 154 | +The devlink info command displays the running and stored firmware versions | |
| 155 | +on the device, serial number and board information. | |
| 156 | + | |
| 157 | +Devlink info command example (replace PCI address):: | |
| 158 | + | |
| 159 | + $ devlink dev info pci/0000:03:00.0 | |
| 160 | + pci/0000:03:00.0: | |
| 161 | + driver nfp | |
| 162 | + serial_number CSAAMDA2001-1003000111 | |
| 163 | + versions: | |
| 164 | + fixed: | |
| 165 | + board.id AMDA2001-1003 | |
| 166 | + board.rev 01 | |
| 167 | + board.manufacture CSA | |
| 168 | + board.model mozart | |
| 169 | + running: | |
| 170 | + fw.mgmt 22.10.0-rc3 | |
| 171 | + fw.cpld 0x1000003 | |
| 172 | + fw.app nic-22.09.0 | |
| 173 | + chip.init AMDA-2001-1003 1003000111 | |
| 174 | + stored: | |
| 175 | + fw.bundle_id bspbundle_1003000111 | |
| 176 | + fw.mgmt 22.10.0-rc3 | |
| 177 | + fw.cpld 0x0 | |
| 178 | + chip.init AMDA-2001-1003 1003000111 | |
| 179 | + | |
| 180 | +Configure Device | |
| 181 | +================ | |
| 182 | + | |
| 183 | +This section explains how to use Agilio SmartNICs running basic NIC firmware. | |
| 184 | + | |
| 185 | +Configure interface link-speed | |
| 186 | +------------------------------ | |
| 187 | +The following steps explains how to change between 10G mode and 25G mode on | |
| 188 | +Agilio CX 2x25GbE cards. The changing of port speed must be done in order, | |
| 189 | +port 0 (p0) must be set to 10G before port 1 (p1) may be set to 10G. | |
| 190 | + | |
| 191 | +Down the respective interface(s):: | |
| 192 | + | |
| 193 | + $ ip link set dev <netdev port 0> down | |
| 194 | + $ ip link set dev <netdev port 1> down | |
| 195 | + | |
| 196 | +Set interface link-speed to 10G:: | |
| 197 | + | |
| 198 | + $ ethtool -s <netdev port 0> speed 10000 | |
| 199 | + $ ethtool -s <netdev port 1> speed 10000 | |
| 200 | + | |
| 201 | +Set interface link-speed to 25G:: | |
| 202 | + | |
| 203 | + $ ethtool -s <netdev port 0> speed 25000 | |
| 204 | + $ ethtool -s <netdev port 1> speed 25000 | |
| 205 | + | |
| 206 | +Reload driver for changes to take effect:: | |
| 207 | + | |
| 208 | + $ rmmod nfp; modprobe nfp | |
| 209 | + | |
| 210 | +Configure interface Maximum Transmission Unit (MTU) | |
| 211 | +--------------------------------------------------- | |
| 212 | + | |
| 213 | +The MTU of interfaces can temporarily be set using the iproute2, ip link or | |
| 214 | +ifconfig tools. Note that this change will not persist. Setting this via | |
| 215 | +Network Manager, or another appropriate OS configuration tool, is | |
| 216 | +recommended as changes to the MTU using Network Manager can be made to | |
| 217 | +persist. | |
| 218 | + | |
| 219 | +Set interface MTU to 9000 bytes:: | |
| 220 | + | |
| 221 | + $ ip link set dev <netdev port> mtu 9000 | |
| 222 | + | |
| 223 | +It is the responsibility of the user or the orchestration layer to set | |
| 224 | +appropriate MTU values when handling jumbo frames or utilizing tunnels. For | |
| 225 | +example, if packets sent from a VM are to be encapsulated on the card and | |
| 226 | +egress a physical port, then the MTU of the VF should be set to lower than | |
| 227 | +that of the physical port to account for the extra bytes added by the | |
| 228 | +additional header. If a setup is expected to see fallback traffic between | |
| 229 | +the SmartNIC and the kernel then the user should also ensure that the PF MTU | |
| 230 | +is appropriately set to avoid unexpected drops on this path. | |
| 231 | + | |
| 232 | +Configure Forward Error Correction (FEC) modes | |
| 233 | +---------------------------------------------- | |
| 234 | + | |
| 235 | +Agilio SmartNICs support FEC mode configuration, e.g. Auto, Firecode Base-R, | |
| 236 | +ReedSolomon and Off modes. Each physical port's FEC mode can be set | |
| 237 | +independently using ethtool. The supported FEC modes for an interface can | |
| 238 | +be viewed using:: | |
| 239 | + | |
| 240 | + $ ethtool <netdev> | |
| 241 | + | |
| 242 | +The currently configured FEC mode can be viewed using:: | |
| 243 | + | |
| 244 | + $ ethtool --show-fec <netdev> | |
| 245 | + | |
| 246 | +To force the FEC mode for a particular port, auto-negotiation must be disabled | |
| 247 | +(see the `Auto-negotiation`_ section). An example of how to set the FEC mode | |
| 248 | +to Reed-Solomon is:: | |
| 249 | + | |
| 250 | + $ ethtool --set-fec <netdev> encoding rs | |
| 251 | + | |
| 252 | +Auto-negotiation | |
| 253 | +---------------- | |
| 254 | + | |
| 255 | +To change auto-negotiation settings, the link must first be put down. After the | |
| 256 | +link is down, auto-negotiation can be enabled or disabled using:: | |
| 257 | + | |
| 258 | + ethtool -s <netdev> autoneg <on|off> | |
| 259 | + | |
| 135 | 260 | Statistics |
| 136 | 261 | ========== |
| 137 | 262 | |
| @@ -198,6 +198,11 @@ fw.bundle_id · 197 unmodified lines | ||
| 198 | 198 | |
| 199 | 199 | Unique identifier of the entire firmware bundle. |
| 200 | 200 | |
| 201 | +fw.bootloader | |
| 202 | +------------- | |
| 203 | + | |
| 204 | +Version of the bootloader. | |
| 205 | + | |
| 201 | 206 | Future work |
| 202 | 207 | =========== |
| 203 | 208 | |
| @@ -110,7 +110,7 @@ devlink ports for both the controllers. · 109 unmodified lines | ||
| 110 | 110 | Function configuration |
| 111 | 111 | ====================== |
| 112 | 112 | |
| 113 | −A user can configure the function attribute before enumerating the PCI | |
| 113 | +Users can configure one or more function attributes before enumerating the PCI | |
| 114 | 114 | function. Usually it means, user should configure function attribute |
| 115 | 115 | before a bus specific device for the function is created. However, when |
| 116 | 116 | SRIOV is enabled, virtual function devices are created on the PCI bus. |
| @@ -119,9 +119,127 @@ function device to the driver. For subfunctions, this means user should · 2 unmodified lines | ||
| 119 | 119 | configure port function attribute before activating the port function. |
| 120 | 120 | |
| 121 | 121 | A user may set the hardware address of the function using |
| 122 | −'devlink port function set hw_addr' command. For Ethernet port function | |
| 122 | +`devlink port function set hw_addr` command. For Ethernet port function | |
| 123 | 123 | this means a MAC address. |
| 124 | 124 | |
| 125 | +Users may also set the RoCE capability of the function using | |
| 126 | +`devlink port function set roce` command. | |
| 127 | + | |
| 128 | +Users may also set the function as migratable using | |
| 129 | +'devlink port function set migratable' command. | |
| 130 | + | |
| 131 | +Function attributes | |
| 132 | +=================== | |
| 133 | + | |
| 134 | +MAC address setup | |
| 135 | +----------------- | |
| 136 | +The configured MAC address of the PCI VF/SF will be used by netdevice and rdma | |
| 137 | +device created for the PCI VF/SF. | |
| 138 | + | |
| 139 | +- Get the MAC address of the VF identified by its unique devlink port index:: | |
| 140 | + | |
| 141 | + $ devlink port show pci/0000:06:00.0/2 | |
| 142 | + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 143 | + function: | |
| 144 | + hw_addr 00:00:00:00:00:00 | |
| 145 | + | |
| 146 | +- Set the MAC address of the VF identified by its unique devlink port index:: | |
| 147 | + | |
| 148 | + $ devlink port function set pci/0000:06:00.0/2 hw_addr 00:11:22:33:44:55 | |
| 149 | + | |
| 150 | + $ devlink port show pci/0000:06:00.0/2 | |
| 151 | + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 152 | + function: | |
| 153 | + hw_addr 00:11:22:33:44:55 | |
| 154 | + | |
| 155 | +- Get the MAC address of the SF identified by its unique devlink port index:: | |
| 156 | + | |
| 157 | + $ devlink port show pci/0000:06:00.0/32768 | |
| 158 | + pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcisf pfnum 0 sfnum 88 | |
| 159 | + function: | |
| 160 | + hw_addr 00:00:00:00:00:00 | |
| 161 | + | |
| 162 | +- Set the MAC address of the SF identified by its unique devlink port index:: | |
| 163 | + | |
| 164 | + $ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 | |
| 165 | + | |
| 166 | + $ devlink port show pci/0000:06:00.0/32768 | |
| 167 | + pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcisf pfnum 0 sfnum 88 | |
| 168 | + function: | |
| 169 | + hw_addr 00:00:00:00:88:88 | |
| 170 | + | |
| 171 | +RoCE capability setup | |
| 172 | +--------------------- | |
| 173 | +Not all PCI VFs/SFs require RoCE capability. | |
| 174 | + | |
| 175 | +When RoCE capability is disabled, it saves system memory per PCI VF/SF. | |
| 176 | + | |
| 177 | +When user disables RoCE capability for a VF/SF, user application cannot send or | |
| 178 | +receive any RoCE packets through this VF/SF and RoCE GID table for this PCI | |
| 179 | +will be empty. | |
| 180 | + | |
| 181 | +When RoCE capability is disabled in the device using port function attribute, | |
| 182 | +VF/SF driver cannot override it. | |
| 183 | + | |
| 184 | +- Get RoCE capability of the VF device:: | |
| 185 | + | |
| 186 | + $ devlink port show pci/0000:06:00.0/2 | |
| 187 | + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 188 | + function: | |
| 189 | + hw_addr 00:00:00:00:00:00 roce enable | |
| 190 | + | |
| 191 | +- Set RoCE capability of the VF device:: | |
| 192 | + | |
| 193 | + $ devlink port function set pci/0000:06:00.0/2 roce disable | |
| 194 | + | |
| 195 | + $ devlink port show pci/0000:06:00.0/2 | |
| 196 | + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 197 | + function: | |
| 198 | + hw_addr 00:00:00:00:00:00 roce disable | |
| 199 | + | |
| 200 | +migratable capability setup | |
| 201 | +--------------------------- | |
| 202 | +Live migration is the process of transferring a live virtual machine | |
| 203 | +from one physical host to another without disrupting its normal | |
| 204 | +operation. | |
| 205 | + | |
| 206 | +User who want PCI VFs to be able to perform live migration need to | |
| 207 | +explicitly enable the VF migratable capability. | |
| 208 | + | |
| 209 | +When user enables migratable capability for a VF, and the HV binds the VF to VFIO driver | |
| 210 | +with migration support, the user can migrate the VM with this VF from one HV to a | |
| 211 | +different one. | |
| 212 | + | |
| 213 | +However, when migratable capability is enable, device will disable features which cannot | |
| 214 | +be migrated. Thus migratable cap can impose limitations on a VF so let the user decide. | |
| 215 | + | |
| 216 | +Example of LM with migratable function configuration: | |
| 217 | +- Get migratable capability of the VF device:: | |
| 218 | + | |
| 219 | + $ devlink port show pci/0000:06:00.0/2 | |
| 220 | + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 221 | + function: | |
| 222 | + hw_addr 00:00:00:00:00:00 migratable disable | |
| 223 | + | |
| 224 | +- Set migratable capability of the VF device:: | |
| 225 | + | |
| 226 | + $ devlink port function set pci/0000:06:00.0/2 migratable enable | |
| 227 | + | |
| 228 | + $ devlink port show pci/0000:06:00.0/2 | |
| 229 | + pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | |
| 230 | + function: | |
| 231 | + hw_addr 00:00:00:00:00:00 migratable enable | |
| 232 | + | |
| 233 | +- Bind VF to VFIO driver with migration support:: | |
| 234 | + | |
| 235 | + $ echo <pci_id> > /sys/bus/pci/devices/0000:08:00.0/driver/unbind | |
| 236 | + $ echo mlx5_vfio_pci > /sys/bus/pci/devices/0000:08:00.0/driver_override | |
| 237 | + $ echo <pci_id> > /sys/bus/pci/devices/0000:08:00.0/driver/bind | |
| 238 | + | |
| 239 | +Attach VF to the VM. | |
| 240 | +Start the VM. | |
| 241 | +Perform live migration. | |
| 242 | + | |
| 125 | 243 | Subfunction |
| 126 | 244 | ============ |
| 127 | 245 | |
| @@ -130,10 +248,11 @@ it is deployed. Subfunction is created and deployed in unit of 1. Unlike · 2 unmodified lines | ||
| 130 | 248 | SRIOV VFs, a subfunction doesn't require its own PCI virtual function. |
| 131 | 249 | A subfunction communicates with the hardware through the parent PCI function. |
| 132 | 250 | |
| 133 | −To use a subfunction, 3 steps setup sequence is followed. | |
| 134 | −(1) create - create a subfunction; | |
| 135 | −(2) configure - configure subfunction attributes; | |
| 136 | −(3) deploy - deploy the subfunction; | |
| 251 | +To use a subfunction, 3 steps setup sequence is followed: | |
| 252 | + | |
| 253 | +1) create - create a subfunction; | |
| 254 | +2) configure - configure subfunction attributes; | |
| 255 | +3) deploy - deploy the subfunction; | |
| 137 | 256 | |
| 138 | 257 | Subfunction management is done using devlink port user interface. |
| 139 | 258 | User performs setup on the subfunction management device. |
| @@ -191,13 +310,48 @@ API allows to configure following rate object's parameters: · 51 unmodified lines | ||
| 191 | 310 | ``tx_max`` |
| 192 | 311 | Maximum TX rate value. |
| 193 | 312 | |
| 313 | +``tx_priority`` | |
| 314 | + Allows for usage of strict priority arbiter among siblings. This | |
| 315 | + arbitration scheme attempts to schedule nodes based on their priority | |
| 316 | + as long as the nodes remain within their bandwidth limit. The higher the | |
| 317 | + priority the higher the probability that the node will get selected for | |
| 318 | + scheduling. | |
| 319 | + | |
| 320 | +``tx_weight`` | |
| 321 | + Allows for usage of Weighted Fair Queuing arbitration scheme among | |
| 322 | + siblings. This arbitration scheme can be used simultaneously with the | |
| 323 | + strict priority. As a node is configured with a higher rate it gets more | |
| 324 | + BW relative to it's siblings. Values are relative like a percentage | |
| 325 | + points, they basically tell how much BW should node take relative to | |
| 326 | + it's siblings. | |
| 327 | + | |
| 194 | 328 | ``parent`` |
| 195 | 329 | Parent node name. Parent node rate limits are considered as additional limits |
| 196 | 330 | to all node children limits. ``tx_max`` is an upper limit for children. |
| 197 | 331 | ``tx_share`` is a total bandwidth distributed among children. |
| 198 | 332 | |
| 333 | +``tx_priority`` and ``tx_weight`` can be used simultaneously. In that case | |
| 334 | +nodes with the same priority form a WFQ subgroup in the sibling group | |
| 335 | +and arbitration among them is based on assigned weights. | |
| 336 | + | |
| 337 | +Arbitration flow from the high level: | |
| 338 | + | |
| 339 | +#. Choose a node, or group of nodes with the highest priority that stays | |
| 340 | + within the BW limit and are not blocked. Use ``tx_priority`` as a | |
| 341 | + parameter for this arbitration. | |
| 342 | + | |
| 343 | +#. If group of nodes have the same priority perform WFQ arbitration on | |
| 344 | + that subgroup. Use ``tx_weight`` as a parameter for this arbitration. | |
| 345 | + | |
| 346 | +#. Select the winner node, and continue arbitration flow among it's children, | |
| 347 | + until leaf node is reached, and the winner is established. | |
| 348 | + | |
| 349 | +#. If all the nodes from the highest priority sub-group are satisfied, or | |
| 350 | + overused their assigned BW, move to the lower priority nodes. | |
| 351 | + | |
| 199 | 352 | Driver implementations are allowed to support both or either rate object types |
| 200 | −and setting methods of their parameters. | |
| 353 | +and setting methods of their parameters. Additionally driver implementation | |
| 354 | +may export nodes/leafs and their child-parent relationships. | |
| 201 | 355 | |
| 202 | 356 | Terms and Definitions |
| 203 | 357 | ===================== |
| @@ -31,6 +31,15 @@ in its ``devlink_region_ops`` structure. If snapshot id is not set in · 30 unmodified lines | ||
| 31 | 31 | the ``DEVLINK_CMD_REGION_NEW`` request kernel will allocate one and send |
| 32 | 32 | the snapshot information to user space. |
| 33 | 33 | |
| 34 | +Regions may optionally allow directly reading from their contents without a | |
| 35 | +snapshot. Direct read requests are not atomic. In particular a read request | |
| 36 | +of size 256 bytes or larger will be split into multiple chunks. If atomic | |
| 37 | +access is required, use a snapshot. A driver wishing to enable this for a | |
| 38 | +region should implement the ``.read`` callback in the ``devlink_region_ops`` | |
| 39 | +structure. User space can request a direct read by using the | |
| 40 | +``DEVLINK_ATTR_REGION_DIRECT`` attribute instead of specifying a snapshot | |
| 41 | +id. | |
| 42 | + | |
| 34 | 43 | example usage |
| 35 | 44 | ------------- |
| 36 | 45 | |
| @@ -65,6 +74,10 @@ example usage · 28 unmodified lines | ||
| 65 | 74 | $ devlink region read pci/0000:00:05.0/fw-health snapshot 1 address 0 length 16 |
| 66 | 75 | 0000000000000000 0014 95dc 0014 9514 0035 1670 0034 db30 |
| 67 | 76 | |
| 77 | + # Read from the region without a snapshot | |
| 78 | + $ devlink region read pci/0000:00:05.0/fw-health address 16 length 16 | |
| 79 | + 0000000000000010 0000 0000 ffff ff04 0029 8c00 0028 8cc8 | |
| 80 | + | |
| 68 | 81 | As regions are likely very device or driver specific, no generic regions are |
| 69 | 82 | defined. See the driver-specific documentation files for information on the |
| 70 | 83 | specific regions a driver supports. |
| @@ -485,6 +485,16 @@ be added to the following table: · 484 unmodified lines | ||
| 485 | 485 | - Traps incoming packets that the device decided to drop because |
| 486 | 486 | the destination MAC is not configured in the MAC table and |
| 487 | 487 | the interface is not in promiscuous mode |
| 488 | + * - ``eapol`` | |
| 489 | + - ``control`` | |
| 490 | + - Traps "Extensible Authentication Protocol over LAN" (EAPOL) packets | |
| 491 | + specified in IEEE 802.1X | |
| 492 | + * - ``locked_port`` | |
| 493 | + - ``drop`` | |
| 494 | + - Traps packets that the device decided to drop because they failed the | |
| 495 | + locked bridge port check. That is, packets that were received via a | |
| 496 | + locked port and whose {SMAC, VID} does not correspond to an FDB entry | |
| 497 | + pointing to the port | |
| 488 | 498 | |
| 489 | 499 | Driver-specific Packet Traps |
| 490 | 500 | ============================ |
| @@ -589,6 +599,9 @@ narrow. The description of these groups must be added to the following table: · 98 unmodified lines | ||
| 589 | 599 | * - ``parser_error_drops`` |
| 590 | 600 | - Contains packet traps for packets that were marked by the device during |
| 591 | 601 | parsing as erroneous |
| 602 | + * - ``eapol`` | |
| 603 | + - Contains packet traps for "Extensible Authentication Protocol over LAN" | |
| 604 | + (EAPOL) packets specified in IEEE 802.1X | |
| 592 | 605 | |
| 593 | 606 | Packet Trap Policers |
| 594 | 607 | ==================== |
| @@ -0,0 +1,36 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +========================== | |
| 4 | +etas_es58x devlink support | |
| 5 | +========================== | |
| 6 | + | |
| 7 | +This document describes the devlink features implemented by the | |
| 8 | +``etas_es58x`` device driver. | |
| 9 | + | |
| 10 | +Info versions | |
| 11 | +============= | |
| 12 | + | |
| 13 | +The ``etas_es58x`` driver reports the following versions | |
| 14 | + | |
| 15 | +.. list-table:: devlink info versions implemented | |
| 16 | + :widths: 5 5 90 | |
| 17 | + | |
| 18 | + * - Name | |
| 19 | + - Type | |
| 20 | + - Description | |
| 21 | + * - ``fw`` | |
| 22 | + - running | |
| 23 | + - Version of the firmware running on the device. Also available | |
| 24 | + through ``ethtool -i`` as the first member of the | |
| 25 | + ``firmware-version``. | |
| 26 | + * - ``fw.bootloader`` | |
| 27 | + - running | |
| 28 | + - Version of the bootloader running on the device. Also available | |
| 29 | + through ``ethtool -i`` as the second member of the | |
| 30 | + ``firmware-version``. | |
| 31 | + * - ``board.rev`` | |
| 32 | + - fixed | |
| 33 | + - The hardware revision of the device. | |
| 34 | + * - ``serial_number`` | |
| 35 | + - fixed | |
| 36 | + - The USB serial number. Also available through ``lsusb -v``. | |
| @@ -189,12 +189,21 @@ device data. · 188 unmodified lines | ||
| 189 | 189 | * - ``nvm-flash`` |
| 190 | 190 | - The contents of the entire flash chip, sometimes referred to as |
| 191 | 191 | the device's Non Volatile Memory. |
| 192 | + * - ``shadow-ram`` | |
| 193 | + - The contents of the Shadow RAM, which is loaded from the beginning | |
| 194 | + of the flash. Although the contents are primarily from the flash, | |
| 195 | + this area also contains data generated during device boot which is | |
| 196 | + not stored in flash. | |
| 192 | 197 | * - ``device-caps`` |
| 193 | 198 | - The contents of the device firmware's capabilities buffer. Useful to |
| 194 | 199 | determine the current state and configuration of the device. |
| 195 | 200 | |
| 196 | −Users can request an immediate capture of a snapshot via the | |
| 197 | −``DEVLINK_CMD_REGION_NEW`` | |
| 201 | +Both the ``nvm-flash`` and ``shadow-ram`` regions can be accessed without a | |
| 202 | +snapshot. The ``device-caps`` region requires a snapshot as the contents are | |
| 203 | +sent by firmware and can't be split into separate reads. | |
| 204 | + | |
| 205 | +Users can request an immediate capture of a snapshot for all three regions | |
| 206 | +via the ``DEVLINK_CMD_REGION_NEW`` command. | |
| 198 | 207 | |
| 199 | 208 | .. code:: shell |
| 200 | 209 | |
| @@ -254,3 +263,118 @@ Users can request an immediate capture of a snapshot via the · 53 unmodified lines | ||
| 254 | 263 | 0000000000000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
| 255 | 264 | |
| 256 | 265 | $ devlink region delete pci/0000:01:00.0/device-caps snapshot 1 |
| 266 | + | |
| 267 | +Devlink Rate | |
| 268 | +============ | |
| 269 | + | |
| 270 | +The ``ice`` driver implements devlink-rate API. It allows for offload of | |
| 271 | +the Hierarchical QoS to the hardware. It enables user to group Virtual | |
| 272 | +Functions in a tree structure and assign supported parameters: tx_share, | |
| 273 | +tx_max, tx_priority and tx_weight to each node in a tree. So effectively | |
| 274 | +user gains an ability to control how much bandwidth is allocated for each | |
| 275 | +VF group. This is later enforced by the HW. | |
| 276 | + | |
| 277 | +It is assumed that this feature is mutually exclusive with DCB performed | |
| 278 | +in FW and ADQ, or any driver feature that would trigger changes in QoS, | |
| 279 | +for example creation of the new traffic class. The driver will prevent DCB | |
| 280 | +or ADQ configuration if user started making any changes to the nodes using | |
| 281 | +devlink-rate API. To configure those features a driver reload is necessary. | |
| 282 | +Correspondingly if ADQ or DCB will get configured the driver won't export | |
| 283 | +hierarchy at all, or will remove the untouched hierarchy if those | |
| 284 | +features are enabled after the hierarchy is exported, but before any | |
| 285 | +changes are made. | |
| 286 | + | |
| 287 | +This feature is also dependent on switchdev being enabled in the system. | |
| 288 | +It's required bacause devlink-rate requires devlink-port objects to be | |
| 289 | +present, and those objects are only created in switchdev mode. | |
| 290 | + | |
| 291 | +If the driver is set to the switchdev mode, it will export internal | |
| 292 | +hierarchy the moment VF's are created. Root of the tree is always | |
| 293 | +represented by the node_0. This node can't be deleted by the user. Leaf | |
| 294 | +nodes and nodes with children also can't be deleted. | |
| 295 | + | |
| 296 | +.. list-table:: Attributes supported | |
| 297 | + :widths: 15 85 | |
| 298 | + | |
| 299 | + * - Name | |
| 300 | + - Description | |
| 301 | + * - ``tx_max`` | |
| 302 | + - maximum bandwidth to be consumed by the tree Node. Rate Limit is | |
| 303 | + an absolute number specifying a maximum amount of bytes a Node may | |
| 304 | + consume during the course of one second. Rate limit guarantees | |
| 305 | + that a link will not oversaturate the receiver on the remote end | |
| 306 | + and also enforces an SLA between the subscriber and network | |
| 307 | + provider. | |
| 308 | + * - ``tx_share`` | |
| 309 | + - minimum bandwidth allocated to a tree node when it is not blocked. | |
| 310 | + It specifies an absolute BW. While tx_max defines the maximum | |
| 311 | + bandwidth the node may consume, the tx_share marks committed BW | |
| 312 | + for the Node. | |
| 313 | + * - ``tx_priority`` | |
| 314 | + - allows for usage of strict priority arbiter among siblings. This | |
| 315 | + arbitration scheme attempts to schedule nodes based on their | |
| 316 | + priority as long as the nodes remain within their bandwidth limit. | |
| 317 | + Range 0-7. Nodes with priority 7 have the highest priority and are | |
| 318 | + selected first, while nodes with priority 0 have the lowest | |
| 319 | + priority. Nodes that have the same priority are treated equally. | |
| 320 | + * - ``tx_weight`` | |
| 321 | + - allows for usage of Weighted Fair Queuing arbitration scheme among | |
| 322 | + siblings. This arbitration scheme can be used simultaneously with | |
| 323 | + the strict priority. Range 1-200. Only relative values mater for | |
| 324 | + arbitration. | |
| 325 | + | |
| 326 | +``tx_priority`` and ``tx_weight`` can be used simultaneously. In that case | |
| 327 | +nodes with the same priority form a WFQ subgroup in the sibling group | |
| 328 | +and arbitration among them is based on assigned weights. | |
| 329 | + | |
| 330 | +.. code:: shell | |
| 331 | + | |
| 332 | + # enable switchdev | |
| 333 | + $ devlink dev eswitch set pci/0000:4b:00.0 mode switchdev | |
| 334 | + | |
| 335 | + # at this point driver should export internal hierarchy | |
| 336 | + $ echo 2 > /sys/class/net/ens785np0/device/sriov_numvfs | |
| 337 | + | |
| 338 | + $ devlink port function rate show | |
| 339 | + pci/0000:4b:00.0/node_25: type node parent node_24 | |
| 340 | + pci/0000:4b:00.0/node_24: type node parent node_0 | |
| 341 | + pci/0000:4b:00.0/node_32: type node parent node_31 | |
| 342 | + pci/0000:4b:00.0/node_31: type node parent node_30 | |
| 343 | + pci/0000:4b:00.0/node_30: type node parent node_16 | |
| 344 | + pci/0000:4b:00.0/node_19: type node parent node_18 | |
| 345 | + pci/0000:4b:00.0/node_18: type node parent node_17 | |
| 346 | + pci/0000:4b:00.0/node_17: type node parent node_16 | |
| 347 | + pci/0000:4b:00.0/node_14: type node parent node_5 | |
| 348 | + pci/0000:4b:00.0/node_5: type node parent node_3 | |
| 349 | + pci/0000:4b:00.0/node_13: type node parent node_4 | |
| 350 | + pci/0000:4b:00.0/node_12: type node parent node_4 | |
| 351 | + pci/0000:4b:00.0/node_11: type node parent node_4 | |
| 352 | + pci/0000:4b:00.0/node_10: type node parent node_4 | |
| 353 | + pci/0000:4b:00.0/node_9: type node parent node_4 | |
| 354 | + pci/0000:4b:00.0/node_8: type node parent node_4 | |
| 355 | + pci/0000:4b:00.0/node_7: type node parent node_4 | |
| 356 | + pci/0000:4b:00.0/node_6: type node parent node_4 | |
| 357 | + pci/0000:4b:00.0/node_4: type node parent node_3 | |
| 358 | + pci/0000:4b:00.0/node_3: type node parent node_16 | |
| 359 | + pci/0000:4b:00.0/node_16: type node parent node_15 | |
| 360 | + pci/0000:4b:00.0/node_15: type node parent node_0 | |
| 361 | + pci/0000:4b:00.0/node_2: type node parent node_1 | |
| 362 | + pci/0000:4b:00.0/node_1: type node parent node_0 | |
| 363 | + pci/0000:4b:00.0/node_0: type node | |
| 364 | + pci/0000:4b:00.0/1: type leaf parent node_25 | |
| 365 | + pci/0000:4b:00.0/2: type leaf parent node_25 | |
| 366 | + | |
| 367 | + # let's create some custom node | |
| 368 | + $ devlink port function rate add pci/0000:4b:00.0/node_custom parent node_0 | |
| 369 | + | |
| 370 | + # second custom node | |
| 371 | + $ devlink port function rate add pci/0000:4b:00.0/node_custom_1 parent node_custom | |
| 372 | + | |
| 373 | + # reassign second VF to newly created branch | |
| 374 | + $ devlink port function rate set pci/0000:4b:00.0/2 parent node_custom_1 | |
| 375 | + | |
| 376 | + # assign tx_weight to the VF | |
| 377 | + $ devlink port function rate set pci/0000:4b:00.0/2 tx_weight 5 | |
| 378 | + | |
| 379 | + # assign tx_share to the VF | |
| 380 | + $ devlink port function rate set pci/0000:4b:00.0/2 tx_share 500Mbps | |
| @@ -222,6 +222,7 @@ Userspace to kernel: · 221 unmodified lines | ||
| 222 | 222 | ``ETHTOOL_MSG_MODULE_GET`` get transceiver module parameters |
| 223 | 223 | ``ETHTOOL_MSG_PSE_SET`` set PSE parameters |
| 224 | 224 | ``ETHTOOL_MSG_PSE_GET`` get PSE parameters |
| 225 | + ``ETHTOOL_MSG_RSS_GET`` get RSS settings | |
| 225 | 226 | ===================================== ================================= |
| 226 | 227 | |
| 227 | 228 | Kernel to userspace: |
| @@ -263,6 +264,7 @@ Kernel to userspace: · 35 unmodified lines | ||
| 263 | 264 | ``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info |
| 264 | 265 | ``ETHTOOL_MSG_MODULE_GET_REPLY`` transceiver module parameters |
| 265 | 266 | ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters |
| 267 | + ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings | |
| 266 | 268 | ======================================== ================================= |
| 267 | 269 | |
| 268 | 270 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -491,6 +493,7 @@ Kernel response contents: · 222 unmodified lines | ||
| 491 | 493 | ``ETHTOOL_A_LINKSTATE_SQI_MAX`` u32 Max support SQI value |
| 492 | 494 | ``ETHTOOL_A_LINKSTATE_EXT_STATE`` u8 link extended state |
| 493 | 495 | ``ETHTOOL_A_LINKSTATE_EXT_SUBSTATE`` u8 link extended substate |
| 496 | + ``ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT`` u32 count of link down events | |
| 494 | 497 | ==================================== ====== ============================ |
| 495 | 498 | |
| 496 | 499 | For most NIC drivers, the value of ``ETHTOOL_A_LINKSTATE_LINK`` returns |
| @@ -1686,6 +1689,33 @@ to control PoDL PSE Admin functions. This option is implementing · 1189 unmodified lines | ||
| 1686 | 1689 | ``IEEE 802.3-2018`` 30.15.1.2.1 acPoDLPSEAdminControl. See |
| 1687 | 1690 | ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` for supported values. |
| 1688 | 1691 | |
| 1692 | +RSS_GET | |
| 1693 | +======= | |
| 1694 | + | |
| 1695 | +Get indirection table, hash key and hash function info associated with a | |
| 1696 | +RSS context of an interface similar to ``ETHTOOL_GRSSH`` ioctl request. | |
| 1697 | + | |
| 1698 | +Request contents: | |
| 1699 | + | |
| 1700 | +===================================== ====== ========================== | |
| 1701 | + ``ETHTOOL_A_RSS_HEADER`` nested request header | |
| 1702 | + ``ETHTOOL_A_RSS_CONTEXT`` u32 context number | |
| 1703 | +===================================== ====== ========================== | |
| 1704 | + | |
| 1705 | +Kernel response contents: | |
| 1706 | + | |
| 1707 | +===================================== ====== ========================== | |
| 1708 | + ``ETHTOOL_A_RSS_HEADER`` nested reply header | |
| 1709 | + ``ETHTOOL_A_RSS_HFUNC`` u32 RSS hash func | |
| 1710 | + ``ETHTOOL_A_RSS_INDIR`` binary Indir table bytes | |
| 1711 | + ``ETHTOOL_A_RSS_HKEY`` binary Hash key bytes | |
| 1712 | +===================================== ====== ========================== | |
| 1713 | + | |
| 1714 | +ETHTOOL_A_RSS_HFUNC attribute is bitmap indicating the hash function | |
| 1715 | +being used. Current supported options are toeplitz, xor or crc32. | |
| 1716 | +ETHTOOL_A_RSS_INDIR attribute returns RSS indrection table where each byte | |
| 1717 | +indicates queue number. | |
| 1718 | + | |
| 1689 | 1719 | Request translation |
| 1690 | 1720 | =================== |
| 1691 | 1721 | |
| @@ -1767,7 +1797,7 @@ are netlink only. · 75 unmodified lines | ||
| 1767 | 1797 | ``ETHTOOL_GMODULEEEPROM`` ``ETHTOOL_MSG_MODULE_EEPROM_GET`` |
| 1768 | 1798 | ``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET`` |
| 1769 | 1799 | ``ETHTOOL_SEEE`` ``ETHTOOL_MSG_EEE_SET`` |
| 1770 | − ``ETHTOOL_GRSSH`` n/a | |
| 1800 | + ``ETHTOOL_GRSSH`` ``ETHTOOL_MSG_RSS_GET`` | |
| 1771 | 1801 | ``ETHTOOL_SRSSH`` n/a |
| 1772 | 1802 | ``ETHTOOL_GTUNABLE`` n/a |
| 1773 | 1803 | ``ETHTOOL_STUNABLE`` n/a |
| @@ -104,6 +104,7 @@ Contents: · 103 unmodified lines | ||
| 104 | 104 | switchdev |
| 105 | 105 | sysfs-tagging |
| 106 | 106 | tc-actions-env-rules |
| 107 | + tc-queue-filters | |
| 107 | 108 | tcp-thin |
| 108 | 109 | team |
| 109 | 110 | timestamping |
| @@ -1069,6 +1069,81 @@ tcp_child_ehash_entries - INTEGER · 1068 unmodified lines | ||
| 1069 | 1069 | |
| 1070 | 1070 | Default: 0 |
| 1071 | 1071 | |
| 1072 | +tcp_plb_enabled - BOOLEAN | |
| 1073 | + If set and the underlying congestion control (e.g. DCTCP) supports | |
| 1074 | + and enables PLB feature, TCP PLB (Protective Load Balancing) is | |
| 1075 | + enabled. PLB is described in the following paper: | |
| 1076 | + https://doi.org/10.1145/3544216.3544226. Based on PLB parameters, | |
| 1077 | + upon sensing sustained congestion, TCP triggers a change in | |
| 1078 | + flow label field for outgoing IPv6 packets. A change in flow label | |
| 1079 | + field potentially changes the path of outgoing packets for switches | |
| 1080 | + that use ECMP/WCMP for routing. | |
| 1081 | + | |
| 1082 | + PLB changes socket txhash which results in a change in IPv6 Flow Label | |
| 1083 | + field, and currently no-op for IPv4 headers. It is possible | |
| 1084 | + to apply PLB for IPv4 with other network header fields (e.g. TCP | |
| 1085 | + or IPv4 options) or using encapsulation where outer header is used | |
| 1086 | + by switches to determine next hop. In either case, further host | |
| 1087 | + and switch side changes will be needed. | |
| 1088 | + | |
| 1089 | + When set, PLB assumes that congestion signal (e.g. ECN) is made | |
| 1090 | + available and used by congestion control module to estimate a | |
| 1091 | + congestion measure (e.g. ce_ratio). PLB needs a congestion measure to | |
| 1092 | + make repathing decisions. | |
| 1093 | + | |
| 1094 | + Default: FALSE | |
| 1095 | + | |
| 1096 | +tcp_plb_idle_rehash_rounds - INTEGER | |
| 1097 | + Number of consecutive congested rounds (RTT) seen after which | |
| 1098 | + a rehash can be performed, given there are no packets in flight. | |
| 1099 | + This is referred to as M in PLB paper: | |
| 1100 | + https://doi.org/10.1145/3544216.3544226. | |
| 1101 | + | |
| 1102 | + Possible Values: 0 - 31 | |
| 1103 | + | |
| 1104 | + Default: 3 | |
| 1105 | + | |
| 1106 | +tcp_plb_rehash_rounds - INTEGER | |
| 1107 | + Number of consecutive congested rounds (RTT) seen after which | |
| 1108 | + a forced rehash can be performed. Be careful when setting this | |
| 1109 | + parameter, as a small value increases the risk of retransmissions. | |
| 1110 | + This is referred to as N in PLB paper: | |
| 1111 | + https://doi.org/10.1145/3544216.3544226. | |
| 1112 | + | |
| 1113 | + Possible Values: 0 - 31 | |
| 1114 | + | |
| 1115 | + Default: 12 | |
| 1116 | + | |
| 1117 | +tcp_plb_suspend_rto_sec - INTEGER | |
| 1118 | + Time, in seconds, to suspend PLB in event of an RTO. In order to avoid | |
| 1119 | + having PLB repath onto a connectivity "black hole", after an RTO a TCP | |
| 1120 | + connection suspends PLB repathing for a random duration between 1x and | |
| 1121 | + 2x of this parameter. Randomness is added to avoid concurrent rehashing | |
| 1122 | + of multiple TCP connections. This should be set corresponding to the | |
| 1123 | + amount of time it takes to repair a failed link. | |
| 1124 | + | |
| 1125 | + Possible Values: 0 - 255 | |
| 1126 | + | |
| 1127 | + Default: 60 | |
| 1128 | + | |
| 1129 | +tcp_plb_cong_thresh - INTEGER | |
| 1130 | + Fraction of packets marked with congestion over a round (RTT) to | |
| 1131 | + tag that round as congested. This is referred to as K in the PLB paper: | |
| 1132 | + https://doi.org/10.1145/3544216.3544226. | |
| 1133 | + | |
| 1134 | + The 0-1 fraction range is mapped to 0-256 range to avoid floating | |
| 1135 | + point operations. For example, 128 means that if at least 50% of | |
| 1136 | + the packets in a round were marked as congested then the round | |
| 1137 | + will be tagged as congested. | |
| 1138 | + | |
| 1139 | + Setting threshold to 0 means that PLB repaths every RTT regardless | |
| 1140 | + of congestion. This is not intended behavior for PLB and should be | |
| 1141 | + used only for experimentation purpose. | |
| 1142 | + | |
| 1143 | + Possible Values: 0 - 256 | |
| 1144 | + | |
| 1145 | + Default: 128 | |
| 1146 | + | |
| 1072 | 1147 | UDP variables |
| 1073 | 1148 | ============= |
| 1074 | 1149 | |
| @@ -1102,6 +1177,33 @@ udp_rmem_min - INTEGER · 27 unmodified lines | ||
| 1102 | 1177 | udp_wmem_min - INTEGER |
| 1103 | 1178 | UDP does not have tx memory accounting and this tunable has no effect. |
| 1104 | 1179 | |
| 1180 | +udp_hash_entries - INTEGER | |
| 1181 | + Show the number of hash buckets for UDP sockets in the current | |
| 1182 | + networking namespace. | |
| 1183 | + | |
| 1184 | + A negative value means the networking namespace does not own its | |
| 1185 | + hash buckets and shares the initial networking namespace's one. | |
| 1186 | + | |
| 1187 | +udp_child_ehash_entries - INTEGER | |
| 1188 | + Control the number of hash buckets for UDP sockets in the child | |
| 1189 | + networking namespace, which must be set before clone() or unshare(). | |
| 1190 | + | |
| 1191 | + If the value is not 0, the kernel uses a value rounded up to 2^n | |
| 1192 | + as the actual hash bucket size. 0 is a special value, meaning | |
| 1193 | + the child networking namespace will share the initial networking | |
| 1194 | + namespace's hash buckets. | |
| 1195 | + | |
| 1196 | + Note that the child will use the global one in case the kernel | |
| 1197 | + fails to allocate enough memory. In addition, the global hash | |
| 1198 | + buckets are spread over available NUMA nodes, but the allocation | |
| 1199 | + of the child hash table depends on the current process's NUMA | |
| 1200 | + policy, which could result in performance differences. | |
| 1201 | + | |
| 1202 | + Possible values: 0, 2^n (n: 7 (128) - 16 (64K)) | |
| 1203 | + | |
| 1204 | + Default: 0 | |
| 1205 | + | |
| 1206 | + | |
| 1105 | 1207 | RAW variables |
| 1106 | 1208 | ============= |
| 1107 | 1209 | |
| @@ -3025,6 +3127,15 @@ ecn_enable - BOOLEAN · 1917 unmodified lines | ||
| 3025 | 3127 | |
| 3026 | 3128 | Default: 1 |
| 3027 | 3129 | |
| 3130 | +l3mdev_accept - BOOLEAN | |
| 3131 | + Enabling this option allows a "global" bound socket to work | |
| 3132 | + across L3 master domains (e.g., VRFs) with packets capable of | |
| 3133 | + being received regardless of the L3 domain in which they | |
| 3134 | + originated. Only valid when the kernel was compiled with | |
| 3135 | + CONFIG_NET_L3_MASTER_DEV. | |
| 3136 | + | |
| 3137 | + Default: 1 (enabled) | |
| 3138 | + | |
| 3028 | 3139 | |
| 3029 | 3140 | ``/proc/sys/net/core/*`` |
| 3030 | 3141 | ======================== |
| @@ -129,6 +129,26 @@ drop_packet - INTEGER · 128 unmodified lines | ||
| 129 | 129 | threshold. When the mode 3 is set, the always mode drop rate |
| 130 | 130 | is controlled by the /proc/sys/net/ipv4/vs/am_droprate. |
| 131 | 131 | |
| 132 | +est_cpulist - CPULIST | |
| 133 | + Allowed CPUs for estimation kthreads | |
| 134 | + | |
| 135 | + Syntax: standard cpulist format | |
| 136 | + empty list - stop kthread tasks and estimation | |
| 137 | + default - the system's housekeeping CPUs for kthreads | |
| 138 | + | |
| 139 | + Example: | |
| 140 | + "all": all possible CPUs | |
| 141 | + "0-N": all possible CPUs, N denotes last CPU number | |
| 142 | + "0,1-N:1/2": first and all CPUs with odd number | |
| 143 | + "": empty list | |
| 144 | + | |
| 145 | +est_nice - INTEGER | |
| 146 | + default 0 | |
| 147 | + Valid range: -20 (more favorable) .. 19 (less favorable) | |
| 148 | + | |
| 149 | + Niceness value to use for the estimation kthreads (scheduling | |
| 150 | + priority) | |
| 151 | + | |
| 132 | 152 | expire_nodest_conn - BOOLEAN |
| 133 | 153 | - 0 - disabled (default) |
| 134 | 154 | - not 0 - enabled |
| @@ -304,8 +324,8 @@ run_estimation - BOOLEAN · 169 unmodified lines | ||
| 304 | 324 | 0 - disabled |
| 305 | 325 | not 0 - enabled (default) |
| 306 | 326 | |
| 307 | − If disabled, the estimation will be stop, and you can't see | |
| 308 | − any update on speed estimation data. | |
| 327 | + If disabled, the estimation will be suspended and kthread tasks | |
| 328 | + stopped. | |
| 309 | 329 | |
| 310 | 330 | You can always re-enable estimation by setting this value to 1. |
| 311 | 331 | But be careful, the first estimation after re-enable is not |
| @@ -0,0 +1,37 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +========================= | |
| 4 | +TC queue based filtering | |
| 5 | +========================= | |
| 6 | + | |
| 7 | +TC can be used for directing traffic to either a set of queues or | |
| 8 | +to a single queue on both the transmit and receive side. | |
| 9 | + | |
| 10 | +On the transmit side: | |
| 11 | + | |
| 12 | +1) TC filter directing traffic to a set of queues is achieved | |
| 13 | + using the action skbedit priority for Tx priority selection, | |
| 14 | + the priority maps to a traffic class (set of queues) when | |
| 15 | + the queue-sets are configured using mqprio. | |
| 16 | + | |
| 17 | +2) TC filter directs traffic to a transmit queue with the action | |
| 18 | + skbedit queue_mapping $tx_qid. The action skbedit queue_mapping | |
| 19 | + for transmit queue is executed in software only and cannot be | |
| 20 | + offloaded. | |
| 21 | + | |
| 22 | +Likewise, on the receive side, the two filters for selecting set of | |
| 23 | +queues and/or a single queue are supported as below: | |
| 24 | + | |
| 25 | +1) TC flower filter directs incoming traffic to a set of queues using | |
| 26 | + the 'hw_tc' option. | |
| 27 | + hw_tc $TCID - Specify a hardware traffic class to pass matching | |
| 28 | + packets on to. TCID is in the range 0 through 15. | |
| 29 | + | |
| 30 | +2) TC filter with action skbedit queue_mapping $rx_qid selects a | |
| 31 | + receive queue. The action skbedit queue_mapping for receive queue | |
| 32 | + is supported only in hardware. Multiple filters may compete in | |
| 33 | + the hardware for queue selection. In such case, the hardware | |
| 34 | + pipeline resolves conflicts based on priority. On Intel E810 | |
| 35 | + devices, TC filter directing traffic to a queue have higher | |
| 36 | + priority over flow director filter assigning a queue. The hash | |
| 37 | + filter has lowest priority. | |
| @@ -179,7 +179,8 @@ SOF_TIMESTAMPING_OPT_ID: · 178 unmodified lines | ||
| 179 | 179 | identifier and returns that along with the timestamp. The identifier |
| 180 | 180 | is derived from a per-socket u32 counter (that wraps). For datagram |
| 181 | 181 | sockets, the counter increments with each sent packet. For stream |
| 182 | − sockets, it increments with every byte. | |
| 182 | + sockets, it increments with every byte. For stream sockets, also set | |
| 183 | + SOF_TIMESTAMPING_OPT_ID_TCP, see the section below. | |
| 183 | 184 | |
| 184 | 185 | The counter starts at zero. It is initialized the first time that |
| 185 | 186 | the socket option is enabled. It is reset each time the option is |
| @@ -192,6 +193,35 @@ SOF_TIMESTAMPING_OPT_ID: · 6 unmodified lines | ||
| 192 | 193 | among all possibly concurrently outstanding timestamp requests for |
| 193 | 194 | that socket. |
| 194 | 195 | |
| 196 | +SOF_TIMESTAMPING_OPT_ID_TCP: | |
| 197 | + Pass this modifier along with SOF_TIMESTAMPING_OPT_ID for new TCP | |
| 198 | + timestamping applications. SOF_TIMESTAMPING_OPT_ID defines how the | |
| 199 | + counter increments for stream sockets, but its starting point is | |
| 200 | + not entirely trivial. This option fixes that. | |
| 201 | + | |
| 202 | + For stream sockets, if SOF_TIMESTAMPING_OPT_ID is set, this should | |
| 203 | + always be set too. On datagram sockets the option has no effect. | |
| 204 | + | |
| 205 | + A reasonable expectation is that the counter is reset to zero with | |
| 206 | + the system call, so that a subsequent write() of N bytes generates | |
| 207 | + a timestamp with counter N-1. SOF_TIMESTAMPING_OPT_ID_TCP | |
| 208 | + implements this behavior under all conditions. | |
| 209 | + | |
| 210 | + SOF_TIMESTAMPING_OPT_ID without modifier often reports the same, | |
| 211 | + especially when the socket option is set when no data is in | |
| 212 | + transmission. If data is being transmitted, it may be off by the | |
| 213 | + length of the output queue (SIOCOUTQ). | |
| 214 | + | |
| 215 | + The difference is due to being based on snd_una versus write_seq. | |
| 216 | + snd_una is the offset in the stream acknowledged by the peer. This | |
| 217 | + depends on factors outside of process control, such as network RTT. | |
| 218 | + write_seq is the last byte written by the process. This offset is | |
| 219 | + not affected by external inputs. | |
| 220 | + | |
| 221 | + The difference is subtle and unlikely to be noticed when configured | |
| 222 | + at initial socket creation, when no data is queued or sent. But | |
| 223 | + SOF_TIMESTAMPING_OPT_ID_TCP behavior is more robust regardless of | |
| 224 | + when the socket option is set. | |
| 195 | 225 | |
| 196 | 226 | SOF_TIMESTAMPING_OPT_CMSG: |
| 197 | 227 | Support recv() cmsg for all timestamped packets. Control messages |
| @@ -5,6 +5,7 @@ XFRM device - offloading the IPsec computations · 4 unmodified lines | ||
| 5 | 5 | =============================================== |
| 6 | 6 | |
| 7 | 7 | Shannon Nelson <shannon.nelson@oracle.com> |
| 8 | +Leon Romanovsky <leonro@nvidia.com> | |
| 8 | 9 | |
| 9 | 10 | |
| 10 | 11 | Overview |
| @@ -18,10 +19,21 @@ can radically increase throughput and decrease CPU utilization. The XFRM · 7 unmodified lines | ||
| 18 | 19 | Device interface allows NIC drivers to offer to the stack access to the |
| 19 | 20 | hardware offload. |
| 20 | 21 | |
| 22 | +Right now, there are two types of hardware offload that kernel supports. | |
| 23 | + * IPsec crypto offload: | |
| 24 | + * NIC performs encrypt/decrypt | |
| 25 | + * Kernel does everything else | |
| 26 | + * IPsec packet offload: | |
| 27 | + * NIC performs encrypt/decrypt | |
| 28 | + * NIC does encapsulation | |
| 29 | + * Kernel and NIC have SA and policy in-sync | |
| 30 | + * NIC handles the SA and policies states | |
| 31 | + * The Kernel talks to the keymanager | |
| 32 | + | |
| 21 | 33 | Userland access to the offload is typically through a system such as |
| 22 | 34 | libreswan or KAME/raccoon, but the iproute2 'ip xfrm' command set can |
| 23 | 35 | be handy when experimenting. An example command might look something |
| 24 | −like this:: | |
| 36 | +like this for crypto offload: | |
| 25 | 37 | |
| 26 | 38 | ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport \ |
| 27 | 39 | reqid 0x07 replay-window 32 \ |
| @@ -29,6 +41,17 @@ like this:: · 1 unmodified line | ||
| 29 | 41 | sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp \ |
| 30 | 42 | offload dev eth4 dir in |
| 31 | 43 | |
| 44 | +and for packet offload | |
| 45 | + | |
| 46 | + ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport \ | |
| 47 | + reqid 0x07 replay-window 32 \ | |
| 48 | + aead 'rfc4106(gcm(aes))' 0x44434241343332312423222114131211f4f3f2f1 128 \ | |
| 49 | + sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp \ | |
| 50 | + offload packet dev eth4 dir in | |
| 51 | + | |
| 52 | + ip x p add src 14.0.0.70 dst 14.0.0.52 offload packet dev eth4 dir in | |
| 53 | + tmpl src 14.0.0.70 dst 14.0.0.52 proto esp reqid 10000 mode transport | |
| 54 | + | |
| 32 | 55 | Yes, that's ugly, but that's what shell scripts and/or libreswan are for. |
| 33 | 56 | |
| 34 | 57 | |
| @@ -40,17 +63,24 @@ Callbacks to implement · 5 unmodified lines | ||
| 40 | 63 | |
| 41 | 64 | /* from include/linux/netdevice.h */ |
| 42 | 65 | struct xfrmdev_ops { |
| 66 | + /* Crypto and Packet offload callbacks */ | |
| 43 | 67 | int (*xdo_dev_state_add) (struct xfrm_state *x); |
| 44 | 68 | void (*xdo_dev_state_delete) (struct xfrm_state *x); |
| 45 | 69 | void (*xdo_dev_state_free) (struct xfrm_state *x); |
| 46 | 70 | bool (*xdo_dev_offload_ok) (struct sk_buff *skb, |
| 47 | 71 | struct xfrm_state *x); |
| 48 | 72 | void (*xdo_dev_state_advance_esn) (struct xfrm_state *x); |
| 73 | + | |
| 74 | + /* Solely packet offload callbacks */ | |
| 75 | + void (*xdo_dev_state_update_curlft) (struct xfrm_state *x); | |
| 76 | + int (*xdo_dev_policy_add) (struct xfrm_policy *x); | |
| 77 | + void (*xdo_dev_policy_delete) (struct xfrm_policy *x); | |
| 78 | + void (*xdo_dev_policy_free) (struct xfrm_policy *x); | |
| 49 | 79 | }; |
| 50 | 80 | |
| 51 | −The NIC driver offering ipsec offload will need to implement these | |
| 52 | −callbacks to make the offload available to the network stack's | |
| 53 | −XFRM subsystem. Additionally, the feature bits NETIF_F_HW_ESP and | |
| 81 | +The NIC driver offering ipsec offload will need to implement callbacks | |
| 82 | +relevant to supported offload to make the offload available to the network | |
| 83 | +stack's XFRM subsystem. Additionally, the feature bits NETIF_F_HW_ESP and | |
| 54 | 84 | NETIF_F_HW_ESP_TX_CSUM will signal the availability of the offload. |
| 55 | 85 | |
| 56 | 86 | |
| @@ -79,7 +109,8 @@ and an indication of whether it is for Rx or Tx. The driver should · 22 unmodified lines | ||
| 79 | 109 | |
| 80 | 110 | =========== =================================== |
| 81 | 111 | 0 success |
| 82 | − -EOPNETSUPP offload not supported, try SW IPsec | |
| 112 | + -EOPNETSUPP offload not supported, try SW IPsec, | |
| 113 | + not applicable for packet offload mode | |
| 83 | 114 | other fail the request |
| 84 | 115 | =========== =================================== |
| 85 | 116 | |
| @@ -96,6 +127,7 @@ will serviceable. This can check the packet information to be sure the · 10 unmodified lines | ||
| 96 | 127 | offload can be supported (e.g. IPv4 or IPv6, no IPv4 options, etc) and |
| 97 | 128 | return true of false to signify its support. |
| 98 | 129 | |
| 130 | +Crypto offload mode: | |
| 99 | 131 | When ready to send, the driver needs to inspect the Tx packet for the |
| 100 | 132 | offload information, including the opaque context, and set up the packet |
| 101 | 133 | send accordingly:: |
| @@ -139,13 +171,25 @@ the stack in xfrm_input(). · 37 unmodified lines | ||
| 139 | 171 | In ESN mode, xdo_dev_state_advance_esn() is called from xfrm_replay_advance_esn(). |
| 140 | 172 | Driver will check packet seq number and update HW ESN state machine if needed. |
| 141 | 173 | |
| 174 | +Packet offload mode: | |
| 175 | +HW adds and deletes XFRM headers. So in RX path, XFRM stack is bypassed if HW | |
| 176 | +reported success. In TX path, the packet lefts kernel without extra header | |
| 177 | +and not encrypted, the HW is responsible to perform it. | |
| 178 | + | |
| 142 | 179 | When the SA is removed by the user, the driver's xdo_dev_state_delete() |
| 143 | −is asked to disable the offload. Later, xdo_dev_state_free() is called | |
| 144 | −from a garbage collection routine after all reference counts to the state | |
| 180 | +and xdo_dev_policy_delete() are asked to disable the offload. Later, | |
| 181 | +xdo_dev_state_free() and xdo_dev_policy_free() are called from a garbage | |
| 182 | +collection routine after all reference counts to the state and policy | |
| 145 | 183 | have been removed and any remaining resources can be cleared for the |
| 146 | 184 | offload state. How these are used by the driver will depend on specific |
| 147 | 185 | hardware needs. |
| 148 | 186 | |
| 149 | 187 | As a netdev is set to DOWN the XFRM stack's netdev listener will call |
| 150 | −xdo_dev_state_delete() and xdo_dev_state_free() on any remaining offloaded | |
| 151 | −states. | |
| 188 | +xdo_dev_state_delete(), xdo_dev_policy_delete(), xdo_dev_state_free() and | |
| 189 | +xdo_dev_policy_free() on any remaining offloaded states. | |
| 190 | + | |
| 191 | +Outcome of HW handling packets, the XFRM core can't count hard, soft limits. | |
| 192 | +The HW/driver are responsible to perform it and provide accurate data when | |
| 193 | +xdo_dev_state_update_curlft() is called. In case of one of these limits | |
| 194 | +occuried, the driver needs to call to xfrm_state_check_expire() to make sure | |
| 195 | +that XFRM performs rekeying sequence. | |
| @@ -1932,6 +1932,7 @@ F: Documentation/devicetree/bindings/interrupt-controller/apple,* · 1931 unmodified lines | ||
| 1932 | 1932 | F: Documentation/devicetree/bindings/iommu/apple,dart.yaml |
| 1933 | 1933 | F: Documentation/devicetree/bindings/iommu/apple,sart.yaml |
| 1934 | 1934 | F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml |
| 1935 | +F: Documentation/devicetree/bindings/net/bluetooth/brcm,bcm4377-bluetooth.yaml | |
| 1935 | 1936 | F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml |
| 1936 | 1937 | F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml |
| 1937 | 1938 | F: Documentation/devicetree/bindings/pci/apple,pcie.yaml |
| @@ -1939,6 +1940,7 @@ F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml · 1 unmodified line | ||
| 1939 | 1940 | F: Documentation/devicetree/bindings/power/apple* |
| 1940 | 1941 | F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml |
| 1941 | 1942 | F: arch/arm64/boot/dts/apple/ |
| 1943 | +F: drivers/bluetooth/hci_bcm4377.c | |
| 1942 | 1944 | F: drivers/clk/clk-apple-nco.c |
| 1943 | 1945 | F: drivers/cpufreq/apple-soc-cpufreq.c |
| 1944 | 1946 | F: drivers/dma/apple-admac.c |
| @@ -2470,6 +2472,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) · 525 unmodified lines | ||
| 2470 | 2472 | S: Supported |
| 2471 | 2473 | T: git git://github.com/microchip-ung/linux-upstream.git |
| 2472 | 2474 | F: arch/arm64/boot/dts/microchip/ |
| 2475 | +F: drivers/net/ethernet/microchip/vcap/ | |
| 2473 | 2476 | F: drivers/pinctrl/pinctrl-microchip-sgpio.c |
| 2474 | 2477 | N: sparx5 |
| 2475 | 2478 | |
| @@ -6362,6 +6365,7 @@ F: drivers/net/ethernet/freescale/dpaa2/Kconfig · 3886 unmodified lines | ||
| 6362 | 6365 | F: drivers/net/ethernet/freescale/dpaa2/Makefile |
| 6363 | 6366 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth* |
| 6364 | 6367 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-mac* |
| 6368 | +F: drivers/net/ethernet/freescale/dpaa2/dpaa2-xsk* | |
| 6365 | 6369 | F: drivers/net/ethernet/freescale/dpaa2/dpkg.h |
| 6366 | 6370 | F: drivers/net/ethernet/freescale/dpaa2/dpmac* |
| 6367 | 6371 | F: drivers/net/ethernet/freescale/dpaa2/dpni* |
| @@ -7734,6 +7738,7 @@ ETAS ES58X CAN/USB DRIVER · 1366 unmodified lines | ||
| 7734 | 7738 | M: Vincent Mailhol <mailhol.vincent@wanadoo.fr> |
| 7735 | 7739 | L: linux-can@vger.kernel.org |
| 7736 | 7740 | S: Maintained |
| 7741 | +F: Documentation/networking/devlink/etas_es58x.rst | |
| 7737 | 7742 | F: drivers/net/can/usb/etas_es58x/ |
| 7738 | 7743 | |
| 7739 | 7744 | ETHERNET BRIDGE |
| @@ -8236,7 +8241,10 @@ S: Maintained · 496 unmodified lines | ||
| 8236 | 8241 | F: drivers/i2c/busses/i2c-cpm.c |
| 8237 | 8242 | |
| 8238 | 8243 | FREESCALE IMX / MXC FEC DRIVER |
| 8239 | −M: Joakim Zhang <qiangqing.zhang@nxp.com> | |
| 8244 | +M: Wei Fang <wei.fang@nxp.com> | |
| 8245 | +R: Shenwei Wang <shenwei.wang@nxp.com> | |
| 8246 | +R: Clark Wang <xiaoning.wang@nxp.com> | |
| 8247 | +R: NXP Linux Team <linux-imx@nxp.com> | |
| 8240 | 8248 | L: netdev@vger.kernel.org |
| 8241 | 8249 | S: Maintained |
| 8242 | 8250 | F: Documentation/devicetree/bindings/net/fsl,fec.yaml |
| @@ -9493,8 +9501,9 @@ F: Documentation/devicetree/bindings/iio/humidity/st,hts221.yaml · 1250 unmodified lines | ||
| 9493 | 9501 | F: drivers/iio/humidity/hts221* |
| 9494 | 9502 | |
| 9495 | 9503 | HUAWEI ETHERNET DRIVER |
| 9504 | +M: Cai Huoqing <cai.huoqing@linux.dev> | |
| 9496 | 9505 | L: netdev@vger.kernel.org |
| 9497 | −S: Orphan | |
| 9506 | +S: Maintained | |
| 9498 | 9507 | F: Documentation/networking/device_drivers/ethernet/huawei/hinic.rst |
| 9499 | 9508 | F: drivers/net/ethernet/huawei/hinic/ |
| 9500 | 9509 | |
| @@ -9597,6 +9606,7 @@ F: include/asm-generic/hyperv-tlfs.h · 96 unmodified lines | ||
| 9597 | 9606 | F: include/asm-generic/mshyperv.h |
| 9598 | 9607 | F: include/clocksource/hyperv_timer.h |
| 9599 | 9608 | F: include/linux/hyperv.h |
| 9609 | +F: include/net/mana | |
| 9600 | 9610 | F: include/uapi/linux/hyperv.h |
| 9601 | 9611 | F: net/vmw_vsock/hyperv_transport.c |
| 9602 | 9612 | F: tools/hv/ |
| @@ -12410,7 +12420,7 @@ M: Marcin Wojtas <mw@semihalf.com> · 2807 unmodified lines | ||
| 12410 | 12420 | M: Russell King <linux@armlinux.org.uk> |
| 12411 | 12421 | L: netdev@vger.kernel.org |
| 12412 | 12422 | S: Maintained |
| 12413 | −F: Documentation/devicetree/bindings/net/marvell-pp2.txt | |
| 12423 | +F: Documentation/devicetree/bindings/net/marvell,pp2.yaml | |
| 12414 | 12424 | F: drivers/net/ethernet/marvell/mvpp2/ |
| 12415 | 12425 | |
| 12416 | 12426 | MARVELL MWIFIEX WIRELESS DRIVER |
| @@ -12458,7 +12468,7 @@ F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst · 41 unmodified lines | ||
| 12458 | 12468 | F: drivers/net/ethernet/marvell/octeontx2/af/ |
| 12459 | 12469 | |
| 12460 | 12470 | MARVELL PRESTERA ETHERNET SWITCH DRIVER |
| 12461 | −M: Taras Chornyi <tchornyi@marvell.com> | |
| 12471 | +M: Taras Chornyi <taras.chornyi@plvision.eu> | |
| 12462 | 12472 | S: Supported |
| 12463 | 12473 | W: https://github.com/Marvell-switching/switchdev-prestera |
| 12464 | 12474 | F: drivers/net/ethernet/marvell/prestera/ |
| @@ -13017,6 +13027,7 @@ M: Felix Fietkau <nbd@nbd.name> · 552 unmodified lines | ||
| 13017 | 13027 | M: John Crispin <john@phrozen.org> |
| 13018 | 13028 | M: Sean Wang <sean.wang@mediatek.com> |
| 13019 | 13029 | M: Mark Lee <Mark-MC.Lee@mediatek.com> |
| 13030 | +M: Lorenzo Bianconi <lorenzo@kernel.org> | |
| 13020 | 13031 | L: netdev@vger.kernel.org |
| 13021 | 13032 | S: Maintained |
| 13022 | 13033 | F: drivers/net/ethernet/mediatek/ |
| @@ -14048,6 +14059,7 @@ F: include/uapi/linux/meye.h · 1025 unmodified lines | ||
| 14048 | 14059 | |
| 14049 | 14060 | MOTORCOMM PHY DRIVER |
| 14050 | 14061 | M: Peter Geis <pgwipeout@gmail.com> |
| 14062 | +M: Frank <Frank.Sae@motor-comm.com> | |
| 14051 | 14063 | L: netdev@vger.kernel.org |
| 14052 | 14064 | S: Maintained |
| 14053 | 14065 | F: drivers/net/phy/motorcomm.c |
| @@ -19175,7 +19187,7 @@ M: Jassi Brar <jaswinder.singh@linaro.org> · 5121 unmodified lines | ||
| 19175 | 19187 | M: Ilias Apalodimas <ilias.apalodimas@linaro.org> |
| 19176 | 19188 | L: netdev@vger.kernel.org |
| 19177 | 19189 | S: Maintained |
| 19178 | −F: Documentation/devicetree/bindings/net/socionext-netsec.txt | |
| 19190 | +F: Documentation/devicetree/bindings/net/socionext,synquacer-netsec.yaml | |
| 19179 | 19191 | F: drivers/net/ethernet/socionext/netsec.c |
| 19180 | 19192 | |
| 19181 | 19193 | SOCIONEXT (SNI) Synquacer SPI DRIVER |
| @@ -20828,7 +20840,6 @@ W: https://wireless.wiki.kernel.org/en/users/Drivers/wl12xx · 1646 unmodified lines | ||
| 20828 | 20840 | W: https://wireless.wiki.kernel.org/en/users/Drivers/wl1251 |
| 20829 | 20841 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git |
| 20830 | 20842 | F: drivers/net/wireless/ti/ |
| 20831 | −F: include/linux/wl12xx.h | |
| 20832 | 20843 | |
| 20833 | 20844 | TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER |
| 20834 | 20845 | M: John Stultz <jstultz@google.com> |
| @@ -178,6 +178,8 @@ · 177 unmodified lines | ||
| 178 | 178 | |
| 179 | 179 | /* Network controller */ |
| 180 | 180 | ethernet: ethernet@f0000 { |
| 181 | + #address-cells = <1>; | |
| 182 | + #size-cells = <0>; | |
| 181 | 183 | compatible = "marvell,armada-375-pp2"; |
| 182 | 184 | reg = <0xf0000 0xa000>, /* Packet Processor regs */ |
| 183 | 185 | <0xc0000 0x3060>, /* LMS regs */ |
| @@ -187,15 +189,17 @@ · 3 unmodified lines | ||
| 187 | 189 | clock-names = "pp_clk", "gop_clk"; |
| 188 | 190 | status = "disabled"; |
| 189 | 191 | |
| 190 | − eth0: eth0 { | |
| 192 | + eth0: ethernet-port@0 { | |
| 191 | 193 | interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; |
| 192 | − port-id = <0>; | |
| 194 | + reg = <0>; | |
| 195 | + port-id = <0>; /* For backward compatibility. */ | |
| 193 | 196 | status = "disabled"; |
| 194 | 197 | }; |
| 195 | 198 | |
| 196 | − eth1: eth1 { | |
| 199 | + eth1: ethernet-port@1 { | |
| 197 | 200 | interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; |
| 198 | − port-id = <1>; | |
| 201 | + reg = <1>; | |
| 202 | + port-id = <1>; /* For backward compatibility. */ | |
| 199 | 203 | status = "disabled"; |
| 200 | 204 | }; |
| 201 | 205 | }; |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/init.h> |
| 11 | 11 | #include <linux/kernel.h> |
| 12 | 12 | #include <linux/of_platform.h> |
| 13 | −#include <linux/wl12xx.h> | |
| 14 | 13 | #include <linux/mmc/card.h> |
| 15 | 14 | #include <linux/mmc/host.h> |
| 16 | 15 | #include <linux/power/smartreflex.h> |
| @@ -21,6 +21,10 @@ · 20 unmodified lines | ||
| 21 | 21 | }; |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | +&bluetooth0 { | |
| 25 | + brcm,board-type = "apple,atlantisb"; | |
| 26 | +}; | |
| 27 | + | |
| 24 | 28 | &wifi0 { |
| 25 | 29 | brcm,board-type = "apple,atlantisb"; |
| 26 | 30 | }; |
| @@ -17,6 +17,10 @@ · 16 unmodified lines | ||
| 17 | 17 | model = "Apple MacBook Pro (13-inch, M1, 2020)"; |
| 18 | 18 | }; |
| 19 | 19 | |
| 20 | +&bluetooth0 { | |
| 21 | + brcm,board-type = "apple,honshu"; | |
| 22 | +}; | |
| 23 | + | |
| 20 | 24 | &wifi0 { |
| 21 | 25 | brcm,board-type = "apple,honshu"; |
| 22 | 26 | }; |
| @@ -17,6 +17,10 @@ · 16 unmodified lines | ||
| 17 | 17 | model = "Apple MacBook Air (M1, 2020)"; |
| 18 | 18 | }; |
| 19 | 19 | |
| 20 | +&bluetooth0 { | |
| 21 | + brcm,board-type = "apple,shikoku"; | |
| 22 | +}; | |
| 23 | + | |
| 20 | 24 | &wifi0 { |
| 21 | 25 | brcm,board-type = "apple,shikoku"; |
| 22 | 26 | }; |
| @@ -21,6 +21,10 @@ · 20 unmodified lines | ||
| 21 | 21 | }; |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | +&bluetooth0 { | |
| 25 | + brcm,board-type = "apple,capri"; | |
| 26 | +}; | |
| 27 | + | |
| 24 | 28 | &wifi0 { |
| 25 | 29 | brcm,board-type = "apple,capri"; |
| 26 | 30 | }; |
| @@ -21,6 +21,10 @@ · 20 unmodified lines | ||
| 21 | 21 | }; |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | +&bluetooth0 { | |
| 25 | + brcm,board-type = "apple,santorini"; | |
| 26 | +}; | |
| 27 | + | |
| 24 | 28 | &wifi0 { |
| 25 | 29 | brcm,board-type = "apple,santorini"; |
| 26 | 30 | }; |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | / { |
| 13 | 13 | aliases { |
| 14 | + bluetooth0 = &bluetooth0; | |
| 14 | 15 | serial0 = &serial0; |
| 15 | 16 | serial2 = &serial2; |
| 16 | 17 | wifi0 = &wifi0; |
| @@ -77,6 +78,13 @@ · 60 unmodified lines | ||
| 77 | 78 | local-mac-address = [00 00 00 00 00 00]; |
| 78 | 79 | apple,antenna-sku = "XX"; |
| 79 | 80 | }; |
| 81 | + | |
| 82 | + bluetooth0: bluetooth@0,1 { | |
| 83 | + compatible = "pci14e4,5f69"; | |
| 84 | + reg = <0x10100 0x0 0x0 0x0 0x0>; | |
| 85 | + /* To be filled by the loader */ | |
| 86 | + local-bd-address = [00 00 00 00 00 00]; | |
| 87 | + }; | |
| 80 | 88 | }; |
| 81 | 89 | |
| 82 | 90 | &nco_clkref { |
| @@ -24,9 +24,12 @@ · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | /* these aliases provide the FMan ports mapping */ |
| 26 | 26 | enet0: ethernet@e0000 { |
| 27 | + pcs-handle-names = "qsgmii"; | |
| 27 | 28 | }; |
| 28 | 29 | |
| 29 | 30 | enet1: ethernet@e2000 { |
| 31 | + pcsphy-handle = <&pcsphy1>, <&qsgmiib_pcs1>; | |
| 32 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 30 | 33 | }; |
| 31 | 34 | |
| 32 | 35 | enet2: ethernet@e4000 { |
| @@ -36,11 +39,32 @@ · 3 unmodified lines | ||
| 36 | 39 | }; |
| 37 | 40 | |
| 38 | 41 | enet4: ethernet@e8000 { |
| 42 | + pcsphy-handle = <&pcsphy4>, <&qsgmiib_pcs2>; | |
| 43 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 39 | 44 | }; |
| 40 | 45 | |
| 41 | 46 | enet5: ethernet@ea000 { |
| 47 | + pcsphy-handle = <&pcsphy5>, <&qsgmiib_pcs3>; | |
| 48 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 42 | 49 | }; |
| 43 | 50 | |
| 44 | 51 | enet6: ethernet@f0000 { |
| 45 | 52 | }; |
| 53 | + | |
| 54 | + mdio@e1000 { | |
| 55 | + qsgmiib_pcs1: ethernet-pcs@1 { | |
| 56 | + compatible = "fsl,lynx-pcs"; | |
| 57 | + reg = <0x1>; | |
| 58 | + }; | |
| 59 | + | |
| 60 | + qsgmiib_pcs2: ethernet-pcs@2 { | |
| 61 | + compatible = "fsl,lynx-pcs"; | |
| 62 | + reg = <0x2>; | |
| 63 | + }; | |
| 64 | + | |
| 65 | + qsgmiib_pcs3: ethernet-pcs@3 { | |
| 66 | + compatible = "fsl,lynx-pcs"; | |
| 67 | + reg = <0x3>; | |
| 68 | + }; | |
| 69 | + }; | |
| 46 | 70 | }; |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | ||
| 23 | 23 | &fman0 { |
| 24 | 24 | /* these aliases provide the FMan ports mapping */ |
| 25 | 25 | enet0: ethernet@e0000 { |
| 26 | + pcsphy-handle = <&qsgmiib_pcs3>; | |
| 27 | + pcs-handle-names = "qsgmii"; | |
| 26 | 28 | }; |
| 27 | 29 | |
| 28 | 30 | enet1: ethernet@e2000 { |
| @@ -35,14 +37,37 @@ · 6 unmodified lines | ||
| 35 | 37 | }; |
| 36 | 38 | |
| 37 | 39 | enet4: ethernet@e8000 { |
| 40 | + pcsphy-handle = <&pcsphy4>, <&qsgmiib_pcs1>; | |
| 41 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 38 | 42 | }; |
| 39 | 43 | |
| 40 | 44 | enet5: ethernet@ea000 { |
| 45 | + pcsphy-handle = <&pcsphy5>, <&pcsphy5>; | |
| 46 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 41 | 47 | }; |
| 42 | 48 | |
| 43 | 49 | enet6: ethernet@f0000 { |
| 44 | 50 | }; |
| 45 | 51 | |
| 46 | 52 | enet7: ethernet@f2000 { |
| 53 | + pcsphy-handle = <&pcsphy7>, <&qsgmiib_pcs2>, <&pcsphy7>; | |
| 54 | + pcs-handle-names = "sgmii", "qsgmii", "xfi"; | |
| 55 | + }; | |
| 56 | + | |
| 57 | + mdio@eb000 { | |
| 58 | + qsgmiib_pcs1: ethernet-pcs@1 { | |
| 59 | + compatible = "fsl,lynx-pcs"; | |
| 60 | + reg = <0x1>; | |
| 61 | + }; | |
| 62 | + | |
| 63 | + qsgmiib_pcs2: ethernet-pcs@2 { | |
| 64 | + compatible = "fsl,lynx-pcs"; | |
| 65 | + reg = <0x2>; | |
| 66 | + }; | |
| 67 | + | |
| 68 | + qsgmiib_pcs3: ethernet-pcs@3 { | |
| 69 | + compatible = "fsl,lynx-pcs"; | |
| 70 | + reg = <0x3>; | |
| 71 | + }; | |
| 47 | 72 | }; |
| 48 | 73 | }; |
| @@ -58,6 +58,8 @@ · 57 unmodified lines | ||
| 58 | 58 | ranges = <0x0 0x0 ADDRESSIFY(CP11X_BASE) 0x2000000>; |
| 59 | 59 | |
| 60 | 60 | CP11X_LABEL(ethernet): ethernet@0 { |
| 61 | + #address-cells = <1>; | |
| 62 | + #size-cells = <0>; | |
| 61 | 63 | compatible = "marvell,armada-7k-pp22"; |
| 62 | 64 | reg = <0x0 0x100000>, <0x129000 0xb000>, <0x220000 0x800>; |
| 63 | 65 | clocks = <&CP11X_LABEL(clk) 1 3>, <&CP11X_LABEL(clk) 1 9>, |
| @@ -69,7 +71,7 @@ · 5 unmodified lines | ||
| 69 | 71 | status = "disabled"; |
| 70 | 72 | dma-coherent; |
| 71 | 73 | |
| 72 | − CP11X_LABEL(eth0): eth0 { | |
| 74 | + CP11X_LABEL(eth0): ethernet-port@0 { | |
| 73 | 75 | interrupts = <39 IRQ_TYPE_LEVEL_HIGH>, |
| 74 | 76 | <43 IRQ_TYPE_LEVEL_HIGH>, |
| 75 | 77 | <47 IRQ_TYPE_LEVEL_HIGH>, |
| @@ -83,12 +85,13 @@ · 7 unmodified lines | ||
| 83 | 85 | interrupt-names = "hif0", "hif1", "hif2", |
| 84 | 86 | "hif3", "hif4", "hif5", "hif6", "hif7", |
| 85 | 87 | "hif8", "link"; |
| 86 | − port-id = <0>; | |
| 88 | + reg = <0>; | |
| 89 | + port-id = <0>; /* For backward compatibility. */ | |
| 87 | 90 | gop-port-id = <0>; |
| 88 | 91 | status = "disabled"; |
| 89 | 92 | }; |
| 90 | 93 | |
| 91 | − CP11X_LABEL(eth1): eth1 { | |
| 94 | + CP11X_LABEL(eth1): ethernet-port@1 { | |
| 92 | 95 | interrupts = <40 IRQ_TYPE_LEVEL_HIGH>, |
| 93 | 96 | <44 IRQ_TYPE_LEVEL_HIGH>, |
| 94 | 97 | <48 IRQ_TYPE_LEVEL_HIGH>, |
| @@ -102,12 +105,13 @@ · 7 unmodified lines | ||
| 102 | 105 | interrupt-names = "hif0", "hif1", "hif2", |
| 103 | 106 | "hif3", "hif4", "hif5", "hif6", "hif7", |
| 104 | 107 | "hif8", "link"; |
| 105 | − port-id = <1>; | |
| 108 | + reg = <1>; | |
| 109 | + port-id = <1>; /* For backward compatibility. */ | |
| 106 | 110 | gop-port-id = <2>; |
| 107 | 111 | status = "disabled"; |
| 108 | 112 | }; |
| 109 | 113 | |
| 110 | − CP11X_LABEL(eth2): eth2 { | |
| 114 | + CP11X_LABEL(eth2): ethernet-port@2 { | |
| 111 | 115 | interrupts = <41 IRQ_TYPE_LEVEL_HIGH>, |
| 112 | 116 | <45 IRQ_TYPE_LEVEL_HIGH>, |
| 113 | 117 | <49 IRQ_TYPE_LEVEL_HIGH>, |
| @@ -121,7 +125,8 @@ · 7 unmodified lines | ||
| 121 | 125 | interrupt-names = "hif0", "hif1", "hif2", |
| 122 | 126 | "hif3", "hif4", "hif5", "hif6", "hif7", |
| 123 | 127 | "hif8", "link"; |
| 124 | − port-id = <2>; | |
| 128 | + reg = <2>; | |
| 129 | + port-id = <2>; /* For backward compatibility. */ | |
| 125 | 130 | gop-port-id = <3>; |
| 126 | 131 | status = "disabled"; |
| 127 | 132 | }; |
| @@ -77,6 +77,47 @@ · 76 unmodified lines | ||
| 77 | 77 | no-map; |
| 78 | 78 | reg = <0 0x4fc00000 0 0x00100000>; |
| 79 | 79 | }; |
| 80 | + | |
| 81 | + wo_emi0: wo-emi@4fd00000 { | |
| 82 | + reg = <0 0x4fd00000 0 0x40000>; | |
| 83 | + no-map; | |
| 84 | + }; | |
| 85 | + | |
| 86 | + wo_emi1: wo-emi@4fd40000 { | |
| 87 | + reg = <0 0x4fd40000 0 0x40000>; | |
| 88 | + no-map; | |
| 89 | + }; | |
| 90 | + | |
| 91 | + wo_ilm0: wo-ilm@151e0000 { | |
| 92 | + reg = <0 0x151e0000 0 0x8000>; | |
| 93 | + no-map; | |
| 94 | + }; | |
| 95 | + | |
| 96 | + wo_ilm1: wo-ilm@151f0000 { | |
| 97 | + reg = <0 0x151f0000 0 0x8000>; | |
| 98 | + no-map; | |
| 99 | + }; | |
| 100 | + | |
| 101 | + wo_data: wo-data@4fd80000 { | |
| 102 | + reg = <0 0x4fd80000 0 0x240000>; | |
| 103 | + no-map; | |
| 104 | + }; | |
| 105 | + | |
| 106 | + wo_dlm0: wo-dlm@151e8000 { | |
| 107 | + reg = <0 0x151e8000 0 0x2000>; | |
| 108 | + no-map; | |
| 109 | + }; | |
| 110 | + | |
| 111 | + wo_dlm1: wo-dlm@151f8000 { | |
| 112 | + reg = <0 0x151f8000 0 0x2000>; | |
| 113 | + no-map; | |
| 114 | + }; | |
| 115 | + | |
| 116 | + wo_boot: wo-boot@15194000 { | |
| 117 | + reg = <0 0x15194000 0 0x1000>; | |
| 118 | + no-map; | |
| 119 | + }; | |
| 120 | + | |
| 80 | 121 | }; |
| 81 | 122 | |
| 82 | 123 | timer { |
| @@ -298,6 +339,11 @@ · 215 unmodified lines | ||
| 298 | 339 | reg = <0 0x15010000 0 0x1000>; |
| 299 | 340 | interrupt-parent = <&gic>; |
| 300 | 341 | interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>; |
| 342 | + memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, | |
| 343 | + <&wo_data>, <&wo_boot>; | |
| 344 | + memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", | |
| 345 | + "wo-data", "wo-boot"; | |
| 346 | + mediatek,wo-ccif = <&wo_ccif0>; | |
| 301 | 347 | }; |
| 302 | 348 | |
| 303 | 349 | wed1: wed@15011000 { |
| @@ -306,6 +352,25 @@ · 2 unmodified lines | ||
| 306 | 352 | reg = <0 0x15011000 0 0x1000>; |
| 307 | 353 | interrupt-parent = <&gic>; |
| 308 | 354 | interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>; |
| 355 | + memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>, | |
| 356 | + <&wo_data>, <&wo_boot>; | |
| 357 | + memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", | |
| 358 | + "wo-data", "wo-boot"; | |
| 359 | + mediatek,wo-ccif = <&wo_ccif1>; | |
| 360 | + }; | |
| 361 | + | |
| 362 | + wo_ccif0: syscon@151a5000 { | |
| 363 | + compatible = "mediatek,mt7986-wo-ccif", "syscon"; | |
| 364 | + reg = <0 0x151a5000 0 0x1000>; | |
| 365 | + interrupt-parent = <&gic>; | |
| 366 | + interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>; | |
| 367 | + }; | |
| 368 | + | |
| 369 | + wo_ccif1: syscon@151ad000 { | |
| 370 | + compatible = "mediatek,mt7986-wo-ccif", "syscon"; | |
| 371 | + reg = <0 0x151ad000 0 0x1000>; | |
| 372 | + interrupt-parent = <&gic>; | |
| 373 | + interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>; | |
| 309 | 374 | }; |
| 310 | 375 | |
| 311 | 376 | eth: ethernet@15100000 { |
| @@ -1649,13 +1649,8 @@ static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l, · 1648 unmodified lines | ||
| 1649 | 1649 | struct bpf_prog *p = l->link.prog; |
| 1650 | 1650 | int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); |
| 1651 | 1651 | |
| 1652 | − if (p->aux->sleepable) { | |
| 1653 | − enter_prog = (u64)__bpf_prog_enter_sleepable; | |
| 1654 | − exit_prog = (u64)__bpf_prog_exit_sleepable; | |
| 1655 | − } else { | |
| 1656 | − enter_prog = (u64)__bpf_prog_enter; | |
| 1657 | − exit_prog = (u64)__bpf_prog_exit; | |
| 1658 | − } | |
| 1652 | + enter_prog = (u64)bpf_trampoline_enter(p); | |
| 1653 | + exit_prog = (u64)bpf_trampoline_exit(p); | |
| 1659 | 1654 | |
| 1660 | 1655 | if (l->cookie == 0) { |
| 1661 | 1656 | /* if cookie is zero, one instruction is enough to store it */ |
| @@ -284,7 +284,6 @@ CONFIG_IXGB=m · 283 unmodified lines | ||
| 284 | 284 | CONFIG_SKGE=m |
| 285 | 285 | CONFIG_SKY2=m |
| 286 | 286 | CONFIG_MYRI10GE=m |
| 287 | −CONFIG_FEALNX=m | |
| 288 | 287 | CONFIG_NATSEMI=m |
| 289 | 288 | CONFIG_NS83820=m |
| 290 | 289 | CONFIG_S2IO=m |
| @@ -55,7 +55,8 @@ fman@400000 { · 54 unmodified lines | ||
| 55 | 55 | reg = <0xe0000 0x1000>; |
| 56 | 56 | fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; |
| 57 | 57 | ptp-timer = <&ptp_timer0>; |
| 58 | − pcsphy-handle = <&pcsphy0>; | |
| 58 | + pcsphy-handle = <&pcsphy0>, <&pcsphy0>; | |
| 59 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 59 | 60 | }; |
| 60 | 61 | |
| 61 | 62 | mdio@e1000 { |
| @@ -52,7 +52,15 @@ fman@400000 { · 51 unmodified lines | ||
| 52 | 52 | compatible = "fsl,fman-memac"; |
| 53 | 53 | reg = <0xf0000 0x1000>; |
| 54 | 54 | fsl,fman-ports = <&fman0_rx_0x10 &fman0_tx_0x30>; |
| 55 | − pcsphy-handle = <&pcsphy6>; | |
| 55 | + pcsphy-handle = <&pcsphy6>, <&qsgmiib_pcs2>, <&pcsphy6>; | |
| 56 | + pcs-handle-names = "sgmii", "qsgmii", "xfi"; | |
| 57 | + }; | |
| 58 | + | |
| 59 | + mdio@e9000 { | |
| 60 | + qsgmiib_pcs2: ethernet-pcs@2 { | |
| 61 | + compatible = "fsl,lynx-pcs"; | |
| 62 | + reg = <2>; | |
| 63 | + }; | |
| 56 | 64 | }; |
| 57 | 65 | |
| 58 | 66 | mdio@f1000 { |
| @@ -55,7 +55,15 @@ fman@400000 { · 54 unmodified lines | ||
| 55 | 55 | reg = <0xe2000 0x1000>; |
| 56 | 56 | fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; |
| 57 | 57 | ptp-timer = <&ptp_timer0>; |
| 58 | − pcsphy-handle = <&pcsphy1>; | |
| 58 | + pcsphy-handle = <&pcsphy1>, <&qsgmiia_pcs1>; | |
| 59 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 60 | + }; | |
| 61 | + | |
| 62 | + mdio@e1000 { | |
| 63 | + qsgmiia_pcs1: ethernet-pcs@1 { | |
| 64 | + compatible = "fsl,lynx-pcs"; | |
| 65 | + reg = <1>; | |
| 66 | + }; | |
| 59 | 67 | }; |
| 60 | 68 | |
| 61 | 69 | mdio@e3000 { |
| @@ -52,7 +52,15 @@ fman@400000 { · 51 unmodified lines | ||
| 52 | 52 | compatible = "fsl,fman-memac"; |
| 53 | 53 | reg = <0xf2000 0x1000>; |
| 54 | 54 | fsl,fman-ports = <&fman0_rx_0x11 &fman0_tx_0x31>; |
| 55 | − pcsphy-handle = <&pcsphy7>; | |
| 55 | + pcsphy-handle = <&pcsphy7>, <&qsgmiib_pcs3>, <&pcsphy7>; | |
| 56 | + pcs-handle-names = "sgmii", "qsgmii", "xfi"; | |
| 57 | + }; | |
| 58 | + | |
| 59 | + mdio@e9000 { | |
| 60 | + qsgmiib_pcs3: ethernet-pcs@3 { | |
| 61 | + compatible = "fsl,lynx-pcs"; | |
| 62 | + reg = <3>; | |
| 63 | + }; | |
| 56 | 64 | }; |
| 57 | 65 | |
| 58 | 66 | mdio@f3000 { |
| @@ -0,0 +1,45 @@ | ||
| 1 | +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later | |
| 2 | +/* | |
| 3 | + * QorIQ FMan v3 10g port #2 device tree stub [ controller @ offset 0x400000 ] | |
| 4 | + * | |
| 5 | + * Copyright 2022 Sean Anderson <sean.anderson@seco.com> | |
| 6 | + * Copyright 2012 - 2015 Freescale Semiconductor Inc. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +fman@400000 { | |
| 10 | + fman0_rx_0x08: port@88000 { | |
| 11 | + cell-index = <0x8>; | |
| 12 | + compatible = "fsl,fman-v3-port-rx"; | |
| 13 | + reg = <0x88000 0x1000>; | |
| 14 | + fsl,fman-10g-port; | |
| 15 | + }; | |
| 16 | + | |
| 17 | + fman0_tx_0x28: port@a8000 { | |
| 18 | + cell-index = <0x28>; | |
| 19 | + compatible = "fsl,fman-v3-port-tx"; | |
| 20 | + reg = <0xa8000 0x1000>; | |
| 21 | + fsl,fman-10g-port; | |
| 22 | + }; | |
| 23 | + | |
| 24 | + ethernet@e0000 { | |
| 25 | + cell-index = <0>; | |
| 26 | + compatible = "fsl,fman-memac"; | |
| 27 | + reg = <0xe0000 0x1000>; | |
| 28 | + fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; | |
| 29 | + ptp-timer = <&ptp_timer0>; | |
| 30 | + pcsphy-handle = <&pcsphy0>, <&pcsphy0>; | |
| 31 | + pcs-handle-names = "sgmii", "xfi"; | |
| 32 | + }; | |
| 33 | + | |
| 34 | + mdio@e1000 { | |
| 35 | + #address-cells = <1>; | |
| 36 | + #size-cells = <0>; | |
| 37 | + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; | |
| 38 | + reg = <0xe1000 0x1000>; | |
| 39 | + fsl,erratum-a011043; /* must ignore read errors */ | |
| 40 | + | |
| 41 | + pcsphy0: ethernet-phy@0 { | |
| 42 | + reg = <0x0>; | |
| 43 | + }; | |
| 44 | + }; | |
| 45 | +}; | |
| @@ -0,0 +1,45 @@ | ||
| 1 | +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later | |
| 2 | +/* | |
| 3 | + * QorIQ FMan v3 10g port #3 device tree stub [ controller @ offset 0x400000 ] | |
| 4 | + * | |
| 5 | + * Copyright 2022 Sean Anderson <sean.anderson@seco.com> | |
| 6 | + * Copyright 2012 - 2015 Freescale Semiconductor Inc. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +fman@400000 { | |
| 10 | + fman0_rx_0x09: port@89000 { | |
| 11 | + cell-index = <0x9>; | |
| 12 | + compatible = "fsl,fman-v3-port-rx"; | |
| 13 | + reg = <0x89000 0x1000>; | |
| 14 | + fsl,fman-10g-port; | |
| 15 | + }; | |
| 16 | + | |
| 17 | + fman0_tx_0x29: port@a9000 { | |
| 18 | + cell-index = <0x29>; | |
| 19 | + compatible = "fsl,fman-v3-port-tx"; | |
| 20 | + reg = <0xa9000 0x1000>; | |
| 21 | + fsl,fman-10g-port; | |
| 22 | + }; | |
| 23 | + | |
| 24 | + ethernet@e2000 { | |
| 25 | + cell-index = <1>; | |
| 26 | + compatible = "fsl,fman-memac"; | |
| 27 | + reg = <0xe2000 0x1000>; | |
| 28 | + fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; | |
| 29 | + ptp-timer = <&ptp_timer0>; | |
| 30 | + pcsphy-handle = <&pcsphy1>, <&pcsphy1>; | |
| 31 | + pcs-handle-names = "sgmii", "xfi"; | |
| 32 | + }; | |
| 33 | + | |
| 34 | + mdio@e3000 { | |
| 35 | + #address-cells = <1>; | |
| 36 | + #size-cells = <0>; | |
| 37 | + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; | |
| 38 | + reg = <0xe3000 0x1000>; | |
| 39 | + fsl,erratum-a011043; /* must ignore read errors */ | |
| 40 | + | |
| 41 | + pcsphy1: ethernet-phy@0 { | |
| 42 | + reg = <0x0>; | |
| 43 | + }; | |
| 44 | + }; | |
| 45 | +}; | |
| @@ -51,7 +51,8 @@ fman@400000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe0000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; |
| 53 | 53 | ptp-timer = <&ptp_timer0>; |
| 54 | − pcsphy-handle = <&pcsphy0>; | |
| 54 | + pcsphy-handle = <&pcsphy0>, <&pcsphy0>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 55 | 56 | }; |
| 56 | 57 | |
| 57 | 58 | mdio@e1000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe2000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; |
| 53 | 53 | ptp-timer = <&ptp_timer0>; |
| 54 | − pcsphy-handle = <&pcsphy1>; | |
| 54 | + pcsphy-handle = <&pcsphy1>, <&qsgmiia_pcs1>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e1000 { | |
| 59 | + qsgmiia_pcs1: ethernet-pcs@1 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <1>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@e3000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe4000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman0_rx_0x0a &fman0_tx_0x2a>; |
| 53 | 53 | ptp-timer = <&ptp_timer0>; |
| 54 | − pcsphy-handle = <&pcsphy2>; | |
| 54 | + pcsphy-handle = <&pcsphy2>, <&qsgmiia_pcs2>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e1000 { | |
| 59 | + qsgmiia_pcs2: ethernet-pcs@2 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <2>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@e5000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe6000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman0_rx_0x0b &fman0_tx_0x2b>; |
| 53 | 53 | ptp-timer = <&ptp_timer0>; |
| 54 | − pcsphy-handle = <&pcsphy3>; | |
| 54 | + pcsphy-handle = <&pcsphy3>, <&qsgmiia_pcs3>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e1000 { | |
| 59 | + qsgmiia_pcs3: ethernet-pcs@3 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <3>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@e7000 { |
| @@ -51,7 +51,8 @@ fman@400000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe8000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; |
| 53 | 53 | ptp-timer = <&ptp_timer0>; |
| 54 | − pcsphy-handle = <&pcsphy4>; | |
| 54 | + pcsphy-handle = <&pcsphy4>, <&pcsphy4>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 55 | 56 | }; |
| 56 | 57 | |
| 57 | 58 | mdio@e9000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xea000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman0_rx_0x0d &fman0_tx_0x2d>; |
| 53 | 53 | ptp-timer = <&ptp_timer0>; |
| 54 | − pcsphy-handle = <&pcsphy5>; | |
| 54 | + pcsphy-handle = <&pcsphy5>, <&qsgmiib_pcs1>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e9000 { | |
| 59 | + qsgmiib_pcs1: ethernet-pcs@1 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <1>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@eb000 { |
| @@ -52,7 +52,15 @@ fman@500000 { · 51 unmodified lines | ||
| 52 | 52 | compatible = "fsl,fman-memac"; |
| 53 | 53 | reg = <0xf0000 0x1000>; |
| 54 | 54 | fsl,fman-ports = <&fman1_rx_0x10 &fman1_tx_0x30>; |
| 55 | − pcsphy-handle = <&pcsphy14>; | |
| 55 | + pcsphy-handle = <&pcsphy14>, <&qsgmiid_pcs2>, <&pcsphy14>; | |
| 56 | + pcs-handle-names = "sgmii", "qsgmii", "xfi"; | |
| 57 | + }; | |
| 58 | + | |
| 59 | + mdio@e9000 { | |
| 60 | + qsgmiid_pcs2: ethernet-pcs@2 { | |
| 61 | + compatible = "fsl,lynx-pcs"; | |
| 62 | + reg = <2>; | |
| 63 | + }; | |
| 56 | 64 | }; |
| 57 | 65 | |
| 58 | 66 | mdio@f1000 { |
| @@ -52,7 +52,15 @@ fman@500000 { · 51 unmodified lines | ||
| 52 | 52 | compatible = "fsl,fman-memac"; |
| 53 | 53 | reg = <0xf2000 0x1000>; |
| 54 | 54 | fsl,fman-ports = <&fman1_rx_0x11 &fman1_tx_0x31>; |
| 55 | − pcsphy-handle = <&pcsphy15>; | |
| 55 | + pcsphy-handle = <&pcsphy15>, <&qsgmiid_pcs3>, <&pcsphy15>; | |
| 56 | + pcs-handle-names = "sgmii", "qsgmii", "xfi"; | |
| 57 | + }; | |
| 58 | + | |
| 59 | + mdio@e9000 { | |
| 60 | + qsgmiid_pcs3: ethernet-pcs@3 { | |
| 61 | + compatible = "fsl,lynx-pcs"; | |
| 62 | + reg = <3>; | |
| 63 | + }; | |
| 56 | 64 | }; |
| 57 | 65 | |
| 58 | 66 | mdio@f3000 { |
| @@ -51,7 +51,8 @@ fman@500000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe0000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman1_rx_0x08 &fman1_tx_0x28>; |
| 53 | 53 | ptp-timer = <&ptp_timer1>; |
| 54 | − pcsphy-handle = <&pcsphy8>; | |
| 54 | + pcsphy-handle = <&pcsphy8>, <&pcsphy8>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 55 | 56 | }; |
| 56 | 57 | |
| 57 | 58 | mdio@e1000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe2000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman1_rx_0x09 &fman1_tx_0x29>; |
| 53 | 53 | ptp-timer = <&ptp_timer1>; |
| 54 | − pcsphy-handle = <&pcsphy9>; | |
| 54 | + pcsphy-handle = <&pcsphy9>, <&qsgmiic_pcs1>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e1000 { | |
| 59 | + qsgmiic_pcs1: ethernet-pcs@1 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <1>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@e3000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe4000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman1_rx_0x0a &fman1_tx_0x2a>; |
| 53 | 53 | ptp-timer = <&ptp_timer1>; |
| 54 | − pcsphy-handle = <&pcsphy10>; | |
| 54 | + pcsphy-handle = <&pcsphy10>, <&qsgmiic_pcs2>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e1000 { | |
| 59 | + qsgmiic_pcs2: ethernet-pcs@2 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <2>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@e5000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe6000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman1_rx_0x0b &fman1_tx_0x2b>; |
| 53 | 53 | ptp-timer = <&ptp_timer1>; |
| 54 | − pcsphy-handle = <&pcsphy11>; | |
| 54 | + pcsphy-handle = <&pcsphy11>, <&qsgmiic_pcs3>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e1000 { | |
| 59 | + qsgmiic_pcs3: ethernet-pcs@3 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <3>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@e7000 { |
| @@ -51,7 +51,8 @@ fman@500000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xe8000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman1_rx_0x0c &fman1_tx_0x2c>; |
| 53 | 53 | ptp-timer = <&ptp_timer1>; |
| 54 | − pcsphy-handle = <&pcsphy12>; | |
| 54 | + pcsphy-handle = <&pcsphy12>, <&pcsphy12>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 55 | 56 | }; |
| 56 | 57 | |
| 57 | 58 | mdio@e9000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | ||
| 51 | 51 | reg = <0xea000 0x1000>; |
| 52 | 52 | fsl,fman-ports = <&fman1_rx_0x0d &fman1_tx_0x2d>; |
| 53 | 53 | ptp-timer = <&ptp_timer1>; |
| 54 | − pcsphy-handle = <&pcsphy13>; | |
| 54 | + pcsphy-handle = <&pcsphy13>, <&qsgmiid_pcs1>; | |
| 55 | + pcs-handle-names = "sgmii", "qsgmii"; | |
| 56 | + }; | |
| 57 | + | |
| 58 | + mdio@e9000 { | |
| 59 | + qsgmiid_pcs1: ethernet-pcs@1 { | |
| 60 | + compatible = "fsl,lynx-pcs"; | |
| 61 | + reg = <1>; | |
| 62 | + }; | |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | 65 | mdio@eb000 { |
| @@ -609,8 +609,8 @@ · 608 unmodified lines | ||
| 609 | 609 | /include/ "qoriq-bman1.dtsi" |
| 610 | 610 | |
| 611 | 611 | /include/ "qoriq-fman3-0.dtsi" |
| 612 | −/include/ "qoriq-fman3-0-1g-0.dtsi" | |
| 613 | −/include/ "qoriq-fman3-0-1g-1.dtsi" | |
| 612 | +/include/ "qoriq-fman3-0-10g-2.dtsi" | |
| 613 | +/include/ "qoriq-fman3-0-10g-3.dtsi" | |
| 614 | 614 | /include/ "qoriq-fman3-0-1g-2.dtsi" |
| 615 | 615 | /include/ "qoriq-fman3-0-1g-3.dtsi" |
| 616 | 616 | /include/ "qoriq-fman3-0-1g-4.dtsi" |
| @@ -461,7 +461,6 @@ CONFIG_MV643XX_ETH=m · 460 unmodified lines | ||
| 461 | 461 | CONFIG_SKGE=m |
| 462 | 462 | CONFIG_SKY2=m |
| 463 | 463 | CONFIG_MYRI10GE=m |
| 464 | −CONFIG_FEALNX=m | |
| 465 | 464 | CONFIG_NATSEMI=m |
| 466 | 465 | CONFIG_NS83820=m |
| 467 | 466 | CONFIG_PCMCIA_AXNET=m |
| @@ -136,6 +136,25 @@ static bool in_auipc_jalr_range(s64 val) · 135 unmodified lines | ||
| 136 | 136 | val < ((1L << 31) - (1L << 11)); |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | +/* Emit fixed-length instructions for address */ | |
| 140 | +static int emit_addr(u8 rd, u64 addr, bool extra_pass, struct rv_jit_context *ctx) | |
| 141 | +{ | |
| 142 | + u64 ip = (u64)(ctx->insns + ctx->ninsns); | |
| 143 | + s64 off = addr - ip; | |
| 144 | + s64 upper = (off + (1 << 11)) >> 12; | |
| 145 | + s64 lower = off & 0xfff; | |
| 146 | + | |
| 147 | + if (extra_pass && !in_auipc_jalr_range(off)) { | |
| 148 | + pr_err("bpf-jit: target offset 0x%llx is out of range\n", off); | |
| 149 | + return -ERANGE; | |
| 150 | + } | |
| 151 | + | |
| 152 | + emit(rv_auipc(rd, upper), ctx); | |
| 153 | + emit(rv_addi(rd, rd, lower), ctx); | |
| 154 | + return 0; | |
| 155 | +} | |
| 156 | + | |
| 157 | +/* Emit variable-length instructions for 32-bit and 64-bit imm */ | |
| 139 | 158 | static void emit_imm(u8 rd, s64 val, struct rv_jit_context *ctx) |
| 140 | 159 | { |
| 141 | 160 | /* Note that the immediate from the add is sign-extended, |
| @@ -1050,7 +1069,15 @@ out_be: · 908 unmodified lines | ||
| 1050 | 1069 | u64 imm64; |
| 1051 | 1070 | |
| 1052 | 1071 | imm64 = (u64)insn1.imm << 32 | (u32)imm; |
| 1053 | − emit_imm(rd, imm64, ctx); | |
| 1072 | + if (bpf_pseudo_func(insn)) { | |
| 1073 | + /* fixed-length insns for extra jit pass */ | |
| 1074 | + ret = emit_addr(rd, imm64, extra_pass, ctx); | |
| 1075 | + if (ret) | |
| 1076 | + return ret; | |
| 1077 | + } else { | |
| 1078 | + emit_imm(rd, imm64, ctx); | |
| 1079 | + } | |
| 1080 | + | |
| 1054 | 1081 | return 1; |
| 1055 | 1082 | } |
| 1056 | 1083 | |
| @@ -555,11 +555,11 @@ void bpf_jit_compile(struct bpf_prog *fp) · 554 unmodified lines | ||
| 555 | 555 | emit_skb_load16(vlan_tci, r_A); |
| 556 | 556 | break; |
| 557 | 557 | case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT: |
| 558 | − __emit_skb_load8(__pkt_vlan_present_offset, r_A); | |
| 559 | − if (PKT_VLAN_PRESENT_BIT) | |
| 560 | − emit_alu_K(SRL, PKT_VLAN_PRESENT_BIT); | |
| 561 | − if (PKT_VLAN_PRESENT_BIT < 7) | |
| 562 | − emit_andi(r_A, 1, r_A); | |
| 558 | + emit_skb_load32(vlan_all, r_A); | |
| 559 | + emit_cmpi(r_A, 0); | |
| 560 | + emit_branch_off(BE, 12); | |
| 561 | + emit_nop(); | |
| 562 | + emit_loadimm(1, r_A); | |
| 563 | 563 | break; |
| 564 | 564 | case BPF_LD | BPF_W | BPF_LEN: |
| 565 | 565 | emit_skb_load32(len, r_A); |
| @@ -891,6 +891,65 @@ static void emit_nops(u8 **pprog, int len) · 890 unmodified lines | ||
| 891 | 891 | *pprog = prog; |
| 892 | 892 | } |
| 893 | 893 | |
| 894 | +/* emit the 3-byte VEX prefix | |
| 895 | + * | |
| 896 | + * r: same as rex.r, extra bit for ModRM reg field | |
| 897 | + * x: same as rex.x, extra bit for SIB index field | |
| 898 | + * b: same as rex.b, extra bit for ModRM r/m, or SIB base | |
| 899 | + * m: opcode map select, encoding escape bytes e.g. 0x0f38 | |
| 900 | + * w: same as rex.w (32 bit or 64 bit) or opcode specific | |
| 901 | + * src_reg2: additional source reg (encoded as BPF reg) | |
| 902 | + * l: vector length (128 bit or 256 bit) or reserved | |
| 903 | + * pp: opcode prefix (none, 0x66, 0xf2 or 0xf3) | |
| 904 | + */ | |
| 905 | +static void emit_3vex(u8 **pprog, bool r, bool x, bool b, u8 m, | |
| 906 | + bool w, u8 src_reg2, bool l, u8 pp) | |
| 907 | +{ | |
| 908 | + u8 *prog = *pprog; | |
| 909 | + const u8 b0 = 0xc4; /* first byte of 3-byte VEX prefix */ | |
| 910 | + u8 b1, b2; | |
| 911 | + u8 vvvv = reg2hex[src_reg2]; | |
| 912 | + | |
| 913 | + /* reg2hex gives only the lower 3 bit of vvvv */ | |
| 914 | + if (is_ereg(src_reg2)) | |
| 915 | + vvvv |= 1 << 3; | |
| 916 | + | |
| 917 | + /* | |
| 918 | + * 2nd byte of 3-byte VEX prefix | |
| 919 | + * ~ means bit inverted encoding | |
| 920 | + * | |
| 921 | + * 7 0 | |
| 922 | + * +---+---+---+---+---+---+---+---+ | |
| 923 | + * |~R |~X |~B | m | | |
| 924 | + * +---+---+---+---+---+---+---+---+ | |
| 925 | + */ | |
| 926 | + b1 = (!r << 7) | (!x << 6) | (!b << 5) | (m & 0x1f); | |
| 927 | + /* | |
| 928 | + * 3rd byte of 3-byte VEX prefix | |
| 929 | + * | |
| 930 | + * 7 0 | |
| 931 | + * +---+---+---+---+---+---+---+---+ | |
| 932 | + * | W | ~vvvv | L | pp | | |
| 933 | + * +---+---+---+---+---+---+---+---+ | |
| 934 | + */ | |
| 935 | + b2 = (w << 7) | ((~vvvv & 0xf) << 3) | (l << 2) | (pp & 3); | |
| 936 | + | |
| 937 | + EMIT3(b0, b1, b2); | |
| 938 | + *pprog = prog; | |
| 939 | +} | |
| 940 | + | |
| 941 | +/* emit BMI2 shift instruction */ | |
| 942 | +static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op) | |
| 943 | +{ | |
| 944 | + u8 *prog = *pprog; | |
| 945 | + bool r = is_ereg(dst_reg); | |
| 946 | + u8 m = 2; /* escape code 0f38 */ | |
| 947 | + | |
| 948 | + emit_3vex(&prog, r, false, r, m, is64, src_reg, false, op); | |
| 949 | + EMIT2(0xf7, add_2reg(0xC0, dst_reg, dst_reg)); | |
| 950 | + *pprog = prog; | |
| 951 | +} | |
| 952 | + | |
| 894 | 953 | #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp))) |
| 895 | 954 | |
| 896 | 955 | static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image, |
| @@ -1137,17 +1196,38 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image · 240 unmodified lines | ||
| 1137 | 1196 | case BPF_ALU64 | BPF_LSH | BPF_X: |
| 1138 | 1197 | case BPF_ALU64 | BPF_RSH | BPF_X: |
| 1139 | 1198 | case BPF_ALU64 | BPF_ARSH | BPF_X: |
| 1199 | + /* BMI2 shifts aren't better when shift count is already in rcx */ | |
| 1200 | + if (boot_cpu_has(X86_FEATURE_BMI2) && src_reg != BPF_REG_4) { | |
| 1201 | + /* shrx/sarx/shlx dst_reg, dst_reg, src_reg */ | |
| 1202 | + bool w = (BPF_CLASS(insn->code) == BPF_ALU64); | |
| 1203 | + u8 op; | |
| 1204 | + | |
| 1205 | + switch (BPF_OP(insn->code)) { | |
| 1206 | + case BPF_LSH: | |
| 1207 | + op = 1; /* prefix 0x66 */ | |
| 1208 | + break; | |
| 1209 | + case BPF_RSH: | |
| 1210 | + op = 3; /* prefix 0xf2 */ | |
| 1211 | + break; | |
| 1212 | + case BPF_ARSH: | |
| 1213 | + op = 2; /* prefix 0xf3 */ | |
| 1214 | + break; | |
| 1215 | + } | |
| 1140 | 1216 | |
| 1141 | − /* Check for bad case when dst_reg == rcx */ | |
| 1142 | − if (dst_reg == BPF_REG_4) { | |
| 1143 | − /* mov r11, dst_reg */ | |
| 1144 | − EMIT_mov(AUX_REG, dst_reg); | |
| 1145 | − dst_reg = AUX_REG; | |
| 1217 | + emit_shiftx(&prog, dst_reg, src_reg, w, op); | |
| 1218 | + | |
| 1219 | + break; | |
| 1146 | 1220 | } |
| 1147 | 1221 | |
| 1148 | 1222 | if (src_reg != BPF_REG_4) { /* common case */ |
| 1149 | − EMIT1(0x51); /* push rcx */ | |
| 1150 | − | |
| 1223 | + /* Check for bad case when dst_reg == rcx */ | |
| 1224 | + if (dst_reg == BPF_REG_4) { | |
| 1225 | + /* mov r11, dst_reg */ | |
| 1226 | + EMIT_mov(AUX_REG, dst_reg); | |
| 1227 | + dst_reg = AUX_REG; | |
| 1228 | + } else { | |
| 1229 | + EMIT1(0x51); /* push rcx */ | |
| 1230 | + } | |
| 1151 | 1231 | /* mov rcx, src_reg */ |
| 1152 | 1232 | EMIT_mov(BPF_REG_4, src_reg); |
| 1153 | 1233 | } |
| @@ -1159,12 +1239,14 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image · 5 unmodified lines | ||
| 1159 | 1239 | b3 = simple_alu_opcodes[BPF_OP(insn->code)]; |
| 1160 | 1240 | EMIT2(0xD3, add_1reg(b3, dst_reg)); |
| 1161 | 1241 | |
| 1162 | − if (src_reg != BPF_REG_4) | |
| 1163 | − EMIT1(0x59); /* pop rcx */ | |
| 1242 | + if (src_reg != BPF_REG_4) { | |
| 1243 | + if (insn->dst_reg == BPF_REG_4) | |
| 1244 | + /* mov dst_reg, r11 */ | |
| 1245 | + EMIT_mov(insn->dst_reg, AUX_REG); | |
| 1246 | + else | |
| 1247 | + EMIT1(0x59); /* pop rcx */ | |
| 1248 | + } | |
| 1164 | 1249 | |
| 1165 | − if (insn->dst_reg == BPF_REG_4) | |
| 1166 | − /* mov dst_reg, r11 */ | |
| 1167 | − EMIT_mov(insn->dst_reg, AUX_REG); | |
| 1168 | 1250 | break; |
| 1169 | 1251 | |
| 1170 | 1252 | case BPF_ALU | BPF_END | BPF_FROM_BE: |
| @@ -1226,8 +1308,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image · 55 unmodified lines | ||
| 1226 | 1308 | |
| 1227 | 1309 | /* speculation barrier */ |
| 1228 | 1310 | case BPF_ST | BPF_NOSPEC: |
| 1229 | − if (boot_cpu_has(X86_FEATURE_XMM2)) | |
| 1230 | − EMIT_LFENCE(); | |
| 1311 | + EMIT_LFENCE(); | |
| 1231 | 1312 | break; |
| 1232 | 1313 | |
| 1233 | 1314 | /* ST: *(u8*)(dst_reg + off) = imm */ |
| @@ -1813,10 +1894,6 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, · 579 unmodified lines | ||
| 1813 | 1894 | struct bpf_tramp_link *l, int stack_size, |
| 1814 | 1895 | int run_ctx_off, bool save_ret) |
| 1815 | 1896 | { |
| 1816 | − void (*exit)(struct bpf_prog *prog, u64 start, | |
| 1817 | − struct bpf_tramp_run_ctx *run_ctx) = __bpf_prog_exit; | |
| 1818 | − u64 (*enter)(struct bpf_prog *prog, | |
| 1819 | − struct bpf_tramp_run_ctx *run_ctx) = __bpf_prog_enter; | |
| 1820 | 1897 | u8 *prog = *pprog; |
| 1821 | 1898 | u8 *jmp_insn; |
| 1822 | 1899 | int ctx_cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); |
| @@ -1835,23 +1912,12 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, · 12 unmodified lines | ||
| 1835 | 1912 | */ |
| 1836 | 1913 | emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_1, -run_ctx_off + ctx_cookie_off); |
| 1837 | 1914 | |
| 1838 | − if (p->aux->sleepable) { | |
| 1839 | − enter = __bpf_prog_enter_sleepable; | |
| 1840 | − exit = __bpf_prog_exit_sleepable; | |
| 1841 | − } else if (p->type == BPF_PROG_TYPE_STRUCT_OPS) { | |
| 1842 | − enter = __bpf_prog_enter_struct_ops; | |
| 1843 | − exit = __bpf_prog_exit_struct_ops; | |
| 1844 | − } else if (p->expected_attach_type == BPF_LSM_CGROUP) { | |
| 1845 | − enter = __bpf_prog_enter_lsm_cgroup; | |
| 1846 | − exit = __bpf_prog_exit_lsm_cgroup; | |
| 1847 | − } | |
| 1848 | − | |
| 1849 | 1915 | /* arg1: mov rdi, progs[i] */ |
| 1850 | 1916 | emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, (u32) (long) p); |
| 1851 | 1917 | /* arg2: lea rsi, [rbp - ctx_cookie_off] */ |
| 1852 | 1918 | EMIT4(0x48, 0x8D, 0x75, -run_ctx_off); |
| 1853 | 1919 | |
| 1854 | − if (emit_call(&prog, enter, prog)) | |
| 1920 | + if (emit_call(&prog, bpf_trampoline_enter(p), prog)) | |
| 1855 | 1921 | return -EINVAL; |
| 1856 | 1922 | /* remember prog start time returned by __bpf_prog_enter */ |
| 1857 | 1923 | emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0); |
| @@ -1896,7 +1962,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, · 38 unmodified lines | ||
| 1896 | 1962 | emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6); |
| 1897 | 1963 | /* arg3: lea rdx, [rbp - run_ctx_off] */ |
| 1898 | 1964 | EMIT4(0x48, 0x8D, 0x55, -run_ctx_off); |
| 1899 | − if (emit_call(&prog, exit, prog)) | |
| 1965 | + if (emit_call(&prog, bpf_trampoline_exit(p), prog)) | |
| 1900 | 1966 | return -EINVAL; |
| 1901 | 1967 | |
| 1902 | 1968 | *pprog = prog; |
| @@ -82,6 +82,7 @@ static void bcma_gpio_irq_unmask(struct irq_data *d) · 81 unmodified lines | ||
| 82 | 82 | int gpio = irqd_to_hwirq(d); |
| 83 | 83 | u32 val = bcma_chipco_gpio_in(cc, BIT(gpio)); |
| 84 | 84 | |
| 85 | + gpiochip_enable_irq(gc, gpio); | |
| 85 | 86 | bcma_chipco_gpio_polarity(cc, BIT(gpio), val); |
| 86 | 87 | bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio)); |
| 87 | 88 | } |
| @@ -93,12 +94,15 @@ static void bcma_gpio_irq_mask(struct irq_data *d) · 5 unmodified lines | ||
| 93 | 94 | int gpio = irqd_to_hwirq(d); |
| 94 | 95 | |
| 95 | 96 | bcma_chipco_gpio_intmask(cc, BIT(gpio), 0); |
| 97 | + gpiochip_disable_irq(gc, gpio); | |
| 96 | 98 | } |
| 97 | 99 | |
| 98 | −static struct irq_chip bcma_gpio_irq_chip = { | |
| 100 | +static const struct irq_chip bcma_gpio_irq_chip = { | |
| 99 | 101 | .name = "BCMA-GPIO", |
| 100 | 102 | .irq_mask = bcma_gpio_irq_mask, |
| 101 | 103 | .irq_unmask = bcma_gpio_irq_unmask, |
| 104 | + .flags = IRQCHIP_IMMUTABLE, | |
| 105 | + GPIOCHIP_IRQ_RESOURCE_HELPERS, | |
| 102 | 106 | }; |
| 103 | 107 | |
| 104 | 108 | static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id) |
| @@ -139,7 +143,7 @@ static int bcma_gpio_irq_init(struct bcma_drv_cc *cc) · 34 unmodified lines | ||
| 139 | 143 | bcma_chipco_gpio_intmask(cc, ~0, 0); |
| 140 | 144 | bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO); |
| 141 | 145 | |
| 142 | − girq->chip = &bcma_gpio_irq_chip; | |
| 146 | + gpio_irq_chip_set_chip(girq, &bcma_gpio_irq_chip); | |
| 143 | 147 | /* This will let us handle the parent IRQ in the driver */ |
| 144 | 148 | girq->parent_handler = NULL; |
| 145 | 149 | girq->num_parents = 0; |
| @@ -344,8 +344,10 @@ static int bcma_register_devices(struct bcma_bus *bus) · 343 unmodified lines | ||
| 344 | 344 | err = bcma_gpio_init(&bus->drv_cc); |
| 345 | 345 | if (err == -ENOTSUPP) |
| 346 | 346 | bcma_debug(bus, "GPIO driver not activated\n"); |
| 347 | − else if (err) | |
| 347 | + else if (err) { | |
| 348 | 348 | bcma_err(bus, "Error registering GPIO driver: %i\n", err); |
| 349 | + return err; | |
| 350 | + } | |
| 349 | 351 | |
| 350 | 352 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
| 351 | 353 | err = bcma_chipco_watchdog_register(&bus->drv_cc); |
| @@ -165,7 +165,7 @@ static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom, · 164 unmodified lines | ||
| 165 | 165 | return err; |
| 166 | 166 | |
| 167 | 167 | revision = sprom[words - 1] & SSB_SPROM_REVISION_REV; |
| 168 | − if (revision != 8 && revision != 9 && revision != 10) { | |
| 168 | + if (revision < 8 || revision > 11) { | |
| 169 | 169 | pr_err("Unsupported SPROM revision: %d\n", revision); |
| 170 | 170 | return -ENOENT; |
| 171 | 171 | } |
| @@ -45,6 +45,17 @@ config BT_HCIBTUSB_AUTOSUSPEND · 44 unmodified lines | ||
| 45 | 45 | This can be overridden by passing btusb.enable_autosuspend=[y|n] |
| 46 | 46 | on the kernel commandline. |
| 47 | 47 | |
| 48 | +config BT_HCIBTUSB_POLL_SYNC | |
| 49 | + bool "Enable USB poll_sync for Bluetooth USB devices by default" | |
| 50 | + depends on BT_HCIBTUSB | |
| 51 | + default y | |
| 52 | + help | |
| 53 | + poll_sync synchronizes the USB data and event endpoints by | |
| 54 | + prioritizing the later. | |
| 55 | + | |
| 56 | + Say Y here to enable USB poll_sync for Bluetooth USB devices by | |
| 57 | + default. | |
| 58 | + | |
| 48 | 59 | config BT_HCIBTUSB_BCM |
| 49 | 60 | bool "Broadcom protocol support" |
| 50 | 61 | depends on BT_HCIBTUSB |
| @@ -274,6 +285,18 @@ config BT_HCIBCM203X · 223 unmodified lines | ||
| 274 | 285 | Say Y here to compile support for HCI BCM203x devices into the |
| 275 | 286 | kernel or say M to compile it as module (bcm203x). |
| 276 | 287 | |
| 288 | + | |
| 289 | +config BT_HCIBCM4377 | |
| 290 | + tristate "HCI BCM4377/4378/4387 PCIe driver" | |
| 291 | + depends on PCI | |
| 292 | + select FW_LOADER | |
| 293 | + help | |
| 294 | + Support for Broadcom BCM4377/4378/4387 Bluetooth chipsets attached via | |
| 295 | + PCIe. These are usually found in Apple machines. | |
| 296 | + | |
| 297 | + Say Y here to compile support for HCI BCM4377 family devices into the | |
| 298 | + kernel or say M to compile it as module (hci_bcm4377). | |
| 299 | + | |
| 277 | 300 | config BT_HCIBPA10X |
| 278 | 301 | tristate "HCI BPA10x USB driver" |
| 279 | 302 | depends on USB |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o |
| 7 | 7 | obj-$(CONFIG_BT_HCIUART) += hci_uart.o |
| 8 | 8 | obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o |
| 9 | +obj-$(CONFIG_BT_HCIBCM4377) += hci_bcm4377.o | |
| 9 | 10 | obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o |
| 10 | 11 | obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o |
| 11 | 12 | obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | #define CMD_WRITE_BOOT_PARAMS 0xfc0e |
| 28 | 28 | struct cmd_write_boot_params { |
| 29 | − u32 boot_addr; | |
| 29 | + __le32 boot_addr; | |
| 30 | 30 | u8 fw_build_num; |
| 31 | 31 | u8 fw_build_ww; |
| 32 | 32 | u8 fw_build_yy; |
| @@ -1783,19 +1783,19 @@ static int btintel_get_fw_name(struct intel_version *ver, · 1750 unmodified lines | ||
| 1783 | 1783 | case 0x0b: /* SfP */ |
| 1784 | 1784 | case 0x0c: /* WsP */ |
| 1785 | 1785 | snprintf(fw_name, len, "intel/ibt-%u-%u.%s", |
| 1786 | − le16_to_cpu(ver->hw_variant), | |
| 1787 | − le16_to_cpu(params->dev_revid), | |
| 1788 | − suffix); | |
| 1786 | + ver->hw_variant, | |
| 1787 | + le16_to_cpu(params->dev_revid), | |
| 1788 | + suffix); | |
| 1789 | 1789 | break; |
| 1790 | 1790 | case 0x11: /* JfP */ |
| 1791 | 1791 | case 0x12: /* ThP */ |
| 1792 | 1792 | case 0x13: /* HrP */ |
| 1793 | 1793 | case 0x14: /* CcP */ |
| 1794 | 1794 | snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s", |
| 1795 | − le16_to_cpu(ver->hw_variant), | |
| 1796 | − le16_to_cpu(ver->hw_revision), | |
| 1797 | − le16_to_cpu(ver->fw_revision), | |
| 1798 | − suffix); | |
| 1795 | + ver->hw_variant, | |
| 1796 | + ver->hw_revision, | |
| 1797 | + ver->fw_revision, | |
| 1798 | + suffix); | |
| 1799 | 1799 | break; |
| 1800 | 1800 | default: |
| 1801 | 1801 | return -EINVAL; |
| @@ -2524,7 +2524,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) · 722 unmodified lines | ||
| 2524 | 2524 | */ |
| 2525 | 2525 | err = btintel_read_version(hdev, &ver); |
| 2526 | 2526 | if (err) |
| 2527 | − return err; | |
| 2527 | + break; | |
| 2528 | 2528 | |
| 2529 | 2529 | /* Apply the device specific HCI quirks |
| 2530 | 2530 | * |
| @@ -2566,7 +2566,8 @@ static int btintel_setup_combined(struct hci_dev *hdev) · 35 unmodified lines | ||
| 2566 | 2566 | default: |
| 2567 | 2567 | bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", |
| 2568 | 2568 | INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); |
| 2569 | − return -EINVAL; | |
| 2569 | + err = -EINVAL; | |
| 2570 | + break; | |
| 2570 | 2571 | } |
| 2571 | 2572 | |
| 2572 | 2573 | exit_error: |
| @@ -781,6 +781,13 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) · 780 unmodified lines | ||
| 781 | 781 | case CHIP_ID_8852C: |
| 782 | 782 | set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); |
| 783 | 783 | set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); |
| 784 | + | |
| 785 | + /* RTL8852C needs to transmit mSBC data continuously without | |
| 786 | + * the zero length of USB packets for the ALT 6 supported chips | |
| 787 | + */ | |
| 788 | + if (btrtl_dev->project_id == CHIP_ID_8852C) | |
| 789 | + btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP); | |
| 790 | + | |
| 784 | 791 | hci_set_aosp_capable(hdev); |
| 785 | 792 | break; |
| 786 | 793 | default: |
| @@ -47,6 +47,27 @@ struct rtl_vendor_config { · 46 unmodified lines | ||
| 47 | 47 | struct rtl_vendor_config_entry entry[]; |
| 48 | 48 | } __packed; |
| 49 | 49 | |
| 50 | +enum { | |
| 51 | + REALTEK_ALT6_CONTINUOUS_TX_CHIP, | |
| 52 | + | |
| 53 | + __REALTEK_NUM_FLAGS, | |
| 54 | +}; | |
| 55 | + | |
| 56 | +struct btrealtek_data { | |
| 57 | + DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS); | |
| 58 | +}; | |
| 59 | + | |
| 60 | +#define btrealtek_set_flag(hdev, nr) \ | |
| 61 | + do { \ | |
| 62 | + struct btrealtek_data *realtek = hci_get_priv((hdev)); \ | |
| 63 | + set_bit((nr), realtek->flags); \ | |
| 64 | + } while (0) | |
| 65 | + | |
| 66 | +#define btrealtek_get_flag(hdev) \ | |
| 67 | + (((struct btrealtek_data *)hci_get_priv(hdev))->flags) | |
| 68 | + | |
| 69 | +#define btrealtek_test_flag(hdev, nr) test_bit((nr), btrealtek_get_flag(hdev)) | |
| 70 | + | |
| 50 | 71 | #if IS_ENABLED(CONFIG_BT_RTL) |
| 51 | 72 | |
| 52 | 73 | struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | static bool disable_scofix; |
| 33 | 33 | static bool force_scofix; |
| 34 | 34 | static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND); |
| 35 | +static bool enable_poll_sync = IS_ENABLED(CONFIG_BT_HCIBTUSB_POLL_SYNC); | |
| 35 | 36 | static bool reset = true; |
| 36 | 37 | |
| 37 | 38 | static struct usb_driver btusb_driver; |
| @@ -316,6 +317,90 @@ static const struct usb_device_id blacklist_table[] = { · 278 unmodified lines | ||
| 316 | 317 | { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 | |
| 317 | 318 | BTUSB_WIDEBAND_SPEECH | |
| 318 | 319 | BTUSB_VALID_LE_STATES }, |
| 320 | + { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 | | |
| 321 | + BTUSB_WIDEBAND_SPEECH | | |
| 322 | + BTUSB_VALID_LE_STATES }, | |
| 323 | + { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 | | |
| 324 | + BTUSB_WIDEBAND_SPEECH | | |
| 325 | + BTUSB_VALID_LE_STATES }, | |
| 326 | + { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 | | |
| 327 | + BTUSB_WIDEBAND_SPEECH | | |
| 328 | + BTUSB_VALID_LE_STATES }, | |
| 329 | + { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 | | |
| 330 | + BTUSB_WIDEBAND_SPEECH | | |
| 331 | + BTUSB_VALID_LE_STATES }, | |
| 332 | + { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 | | |
| 333 | + BTUSB_WIDEBAND_SPEECH | | |
| 334 | + BTUSB_VALID_LE_STATES }, | |
| 335 | + { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 | | |
| 336 | + BTUSB_WIDEBAND_SPEECH | | |
| 337 | + BTUSB_VALID_LE_STATES }, | |
| 338 | + { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 | | |
| 339 | + BTUSB_WIDEBAND_SPEECH | | |
| 340 | + BTUSB_VALID_LE_STATES }, | |
| 341 | + { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 | | |
| 342 | + BTUSB_WIDEBAND_SPEECH | | |
| 343 | + BTUSB_VALID_LE_STATES }, | |
| 344 | + { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 | | |
| 345 | + BTUSB_WIDEBAND_SPEECH | | |
| 346 | + BTUSB_VALID_LE_STATES }, | |
| 347 | + { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 | | |
| 348 | + BTUSB_WIDEBAND_SPEECH | | |
| 349 | + BTUSB_VALID_LE_STATES }, | |
| 350 | + { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 | | |
| 351 | + BTUSB_WIDEBAND_SPEECH | | |
| 352 | + BTUSB_VALID_LE_STATES }, | |
| 353 | + { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 | | |
| 354 | + BTUSB_WIDEBAND_SPEECH | | |
| 355 | + BTUSB_VALID_LE_STATES }, | |
| 356 | + { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 | | |
| 357 | + BTUSB_WIDEBAND_SPEECH | | |
| 358 | + BTUSB_VALID_LE_STATES }, | |
| 359 | + { USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 | | |
| 360 | + BTUSB_WIDEBAND_SPEECH | | |
| 361 | + BTUSB_VALID_LE_STATES }, | |
| 362 | + { USB_DEVICE(0x0489, 0xe0ca), .driver_info = BTUSB_QCA_WCN6855 | | |
| 363 | + BTUSB_WIDEBAND_SPEECH | | |
| 364 | + BTUSB_VALID_LE_STATES }, | |
| 365 | + { USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 | | |
| 366 | + BTUSB_WIDEBAND_SPEECH | | |
| 367 | + BTUSB_VALID_LE_STATES }, | |
| 368 | + { USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 | | |
| 369 | + BTUSB_WIDEBAND_SPEECH | | |
| 370 | + BTUSB_VALID_LE_STATES }, | |
| 371 | + { USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 | | |
| 372 | + BTUSB_WIDEBAND_SPEECH | | |
| 373 | + BTUSB_VALID_LE_STATES }, | |
| 374 | + { USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 | | |
| 375 | + BTUSB_WIDEBAND_SPEECH | | |
| 376 | + BTUSB_VALID_LE_STATES }, | |
| 377 | + { USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 | | |
| 378 | + BTUSB_WIDEBAND_SPEECH | | |
| 379 | + BTUSB_VALID_LE_STATES }, | |
| 380 | + { USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 | | |
| 381 | + BTUSB_WIDEBAND_SPEECH | | |
| 382 | + BTUSB_VALID_LE_STATES }, | |
| 383 | + { USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 | | |
| 384 | + BTUSB_WIDEBAND_SPEECH | | |
| 385 | + BTUSB_VALID_LE_STATES }, | |
| 386 | + { USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 | | |
| 387 | + BTUSB_WIDEBAND_SPEECH | | |
| 388 | + BTUSB_VALID_LE_STATES }, | |
| 389 | + { USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 | | |
| 390 | + BTUSB_WIDEBAND_SPEECH | | |
| 391 | + BTUSB_VALID_LE_STATES }, | |
| 392 | + { USB_DEVICE(0x04ca, 0x3a22), .driver_info = BTUSB_QCA_WCN6855 | | |
| 393 | + BTUSB_WIDEBAND_SPEECH | | |
| 394 | + BTUSB_VALID_LE_STATES }, | |
| 395 | + { USB_DEVICE(0x04ca, 0x3a24), .driver_info = BTUSB_QCA_WCN6855 | | |
| 396 | + BTUSB_WIDEBAND_SPEECH | | |
| 397 | + BTUSB_VALID_LE_STATES }, | |
| 398 | + { USB_DEVICE(0x04ca, 0x3a26), .driver_info = BTUSB_QCA_WCN6855 | | |
| 399 | + BTUSB_WIDEBAND_SPEECH | | |
| 400 | + BTUSB_VALID_LE_STATES }, | |
| 401 | + { USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 | | |
| 402 | + BTUSB_WIDEBAND_SPEECH | | |
| 403 | + BTUSB_VALID_LE_STATES }, | |
| 319 | 404 | |
| 320 | 405 | /* QCA WCN785x chipset */ |
| 321 | 406 | { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 | |
| @@ -413,6 +498,10 @@ static const struct usb_device_id blacklist_table[] = { · 91 unmodified lines | ||
| 413 | 498 | { USB_DEVICE(0x0bda, 0xc822), .driver_info = BTUSB_REALTEK | |
| 414 | 499 | BTUSB_WIDEBAND_SPEECH }, |
| 415 | 500 | |
| 501 | + /* Realtek 8822CU Bluetooth devices */ | |
| 502 | + { USB_DEVICE(0x13d3, 0x3549), .driver_info = BTUSB_REALTEK | | |
| 503 | + BTUSB_WIDEBAND_SPEECH }, | |
| 504 | + | |
| 416 | 505 | /* Realtek 8852AE Bluetooth devices */ |
| 417 | 506 | { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | |
| 418 | 507 | BTUSB_WIDEBAND_SPEECH }, |
| @@ -443,6 +532,10 @@ static const struct usb_device_id blacklist_table[] = { · 24 unmodified lines | ||
| 443 | 532 | { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | |
| 444 | 533 | BTUSB_WIDEBAND_SPEECH }, |
| 445 | 534 | |
| 535 | + /* Realtek 8852BE Bluetooth devices */ | |
| 536 | + { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK | | |
| 537 | + BTUSB_WIDEBAND_SPEECH }, | |
| 538 | + | |
| 446 | 539 | /* Realtek Bluetooth devices */ |
| 447 | 540 | { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), |
| 448 | 541 | .driver_info = BTUSB_REALTEK }, |
| @@ -511,6 +604,9 @@ static const struct usb_device_id blacklist_table[] = { · 62 unmodified lines | ||
| 511 | 604 | { USB_DEVICE(0x0489, 0xe0e2), .driver_info = BTUSB_MEDIATEK | |
| 512 | 605 | BTUSB_WIDEBAND_SPEECH | |
| 513 | 606 | BTUSB_VALID_LE_STATES }, |
| 607 | + { USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK | | |
| 608 | + BTUSB_WIDEBAND_SPEECH | | |
| 609 | + BTUSB_VALID_LE_STATES }, | |
| 514 | 610 | |
| 515 | 611 | /* Additional Realtek 8723AE Bluetooth devices */ |
| 516 | 612 | { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, |
| @@ -543,6 +639,8 @@ static const struct usb_device_id blacklist_table[] = { · 26 unmodified lines | ||
| 543 | 639 | BTUSB_WIDEBAND_SPEECH }, |
| 544 | 640 | { USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK | |
| 545 | 641 | BTUSB_WIDEBAND_SPEECH }, |
| 642 | + { USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK | | |
| 643 | + BTUSB_WIDEBAND_SPEECH }, | |
| 546 | 644 | |
| 547 | 645 | /* Additional Realtek 8821AE Bluetooth devices */ |
| 548 | 646 | { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, |
| @@ -632,6 +730,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { · 83 unmodified lines | ||
| 632 | 730 | #define BTUSB_TX_WAIT_VND_EVT 13 |
| 633 | 731 | #define BTUSB_WAKEUP_AUTOSUSPEND 14 |
| 634 | 732 | #define BTUSB_USE_ALT3_FOR_WBS 15 |
| 733 | +#define BTUSB_ALT6_CONTINUOUS_TX 16 | |
| 635 | 734 | |
| 636 | 735 | struct btusb_data { |
| 637 | 736 | struct hci_dev *hdev; |
| @@ -696,6 +795,28 @@ struct btusb_data { · 58 unmodified lines | ||
| 696 | 795 | unsigned cmd_timeout_cnt; |
| 697 | 796 | }; |
| 698 | 797 | |
| 798 | +static void btusb_reset(struct hci_dev *hdev) | |
| 799 | +{ | |
| 800 | + struct btusb_data *data; | |
| 801 | + int err; | |
| 802 | + | |
| 803 | + if (hdev->reset) { | |
| 804 | + hdev->reset(hdev); | |
| 805 | + return; | |
| 806 | + } | |
| 807 | + | |
| 808 | + data = hci_get_drvdata(hdev); | |
| 809 | + /* This is not an unbalanced PM reference since the device will reset */ | |
| 810 | + err = usb_autopm_get_interface(data->intf); | |
| 811 | + if (err) { | |
| 812 | + bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err); | |
| 813 | + return; | |
| 814 | + } | |
| 815 | + | |
| 816 | + bt_dev_err(hdev, "Resetting usb device."); | |
| 817 | + usb_queue_reset_device(data->intf); | |
| 818 | +} | |
| 819 | + | |
| 699 | 820 | static void btusb_intel_cmd_timeout(struct hci_dev *hdev) |
| 700 | 821 | { |
| 701 | 822 | struct btusb_data *data = hci_get_drvdata(hdev); |
| @@ -705,7 +826,7 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev) · 3 unmodified lines | ||
| 705 | 826 | return; |
| 706 | 827 | |
| 707 | 828 | if (!reset_gpio) { |
| 708 | − bt_dev_err(hdev, "No way to reset. Ignoring and continuing"); | |
| 829 | + btusb_reset(hdev); | |
| 709 | 830 | return; |
| 710 | 831 | } |
| 711 | 832 | |
| @@ -736,7 +857,7 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev) · 24 unmodified lines | ||
| 736 | 857 | return; |
| 737 | 858 | |
| 738 | 859 | if (!reset_gpio) { |
| 739 | − bt_dev_err(hdev, "No gpio to reset Realtek device, ignoring"); | |
| 860 | + btusb_reset(hdev); | |
| 740 | 861 | return; |
| 741 | 862 | } |
| 742 | 863 | |
| @@ -761,7 +882,6 @@ static void btusb_qca_cmd_timeout(struct hci_dev *hdev) · 18 unmodified lines | ||
| 761 | 882 | { |
| 762 | 883 | struct btusb_data *data = hci_get_drvdata(hdev); |
| 763 | 884 | struct gpio_desc *reset_gpio = data->reset_gpio; |
| 764 | − int err; | |
| 765 | 885 | |
| 766 | 886 | if (++data->cmd_timeout_cnt < 5) |
| 767 | 887 | return; |
| @@ -787,13 +907,7 @@ static void btusb_qca_cmd_timeout(struct hci_dev *hdev) · 19 unmodified lines | ||
| 787 | 907 | return; |
| 788 | 908 | } |
| 789 | 909 | |
| 790 | − bt_dev_err(hdev, "Multiple cmd timeouts seen. Resetting usb device."); | |
| 791 | − /* This is not an unbalanced PM reference since the device will reset */ | |
| 792 | − err = usb_autopm_get_interface(data->intf); | |
| 793 | − if (!err) | |
| 794 | − usb_queue_reset_device(data->intf); | |
| 795 | − else | |
| 796 | − bt_dev_err(hdev, "Failed usb_autopm_get_interface with %d", err); | |
| 910 | + btusb_reset(hdev); | |
| 797 | 911 | } |
| 798 | 912 | |
| 799 | 913 | static inline void btusb_free_frags(struct btusb_data *data) |
| @@ -802,13 +916,13 @@ static inline void btusb_free_frags(struct btusb_data *data) · 2 unmodified lines | ||
| 802 | 916 | |
| 803 | 917 | spin_lock_irqsave(&data->rxlock, flags); |
| 804 | 918 | |
| 805 | − kfree_skb(data->evt_skb); | |
| 919 | + dev_kfree_skb_irq(data->evt_skb); | |
| 806 | 920 | data->evt_skb = NULL; |
| 807 | 921 | |
| 808 | − kfree_skb(data->acl_skb); | |
| 922 | + dev_kfree_skb_irq(data->acl_skb); | |
| 809 | 923 | data->acl_skb = NULL; |
| 810 | 924 | |
| 811 | − kfree_skb(data->sco_skb); | |
| 925 | + dev_kfree_skb_irq(data->sco_skb); | |
| 812 | 926 | data->sco_skb = NULL; |
| 813 | 927 | |
| 814 | 928 | spin_unlock_irqrestore(&data->rxlock, flags); |
| @@ -962,6 +1076,34 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count) · 147 unmodified lines | ||
| 962 | 1076 | return err; |
| 963 | 1077 | } |
| 964 | 1078 | |
| 1079 | +static bool btusb_validate_sco_handle(struct hci_dev *hdev, | |
| 1080 | + struct hci_sco_hdr *hdr) | |
| 1081 | +{ | |
| 1082 | + __u16 handle; | |
| 1083 | + | |
| 1084 | + if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) | |
| 1085 | + // Can't validate, userspace controls everything. | |
| 1086 | + return true; | |
| 1087 | + | |
| 1088 | + /* | |
| 1089 | + * USB isochronous transfers are not designed to be reliable and may | |
| 1090 | + * lose fragments. When this happens, the next first fragment | |
| 1091 | + * encountered might actually be a continuation fragment. | |
| 1092 | + * Validate the handle to detect it and drop it, or else the upper | |
| 1093 | + * layer will get garbage for a while. | |
| 1094 | + */ | |
| 1095 | + | |
| 1096 | + handle = hci_handle(__le16_to_cpu(hdr->handle)); | |
| 1097 | + | |
| 1098 | + switch (hci_conn_lookup_type(hdev, handle)) { | |
| 1099 | + case SCO_LINK: | |
| 1100 | + case ESCO_LINK: | |
| 1101 | + return true; | |
| 1102 | + default: | |
| 1103 | + return false; | |
| 1104 | + } | |
| 1105 | +} | |
| 1106 | + | |
| 965 | 1107 | static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) |
| 966 | 1108 | { |
| 967 | 1109 | struct sk_buff *skb; |
| @@ -994,9 +1136,12 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) · 26 unmodified lines | ||
| 994 | 1136 | |
| 995 | 1137 | if (skb->len == HCI_SCO_HDR_SIZE) { |
| 996 | 1138 | /* Complete SCO header */ |
| 997 | − hci_skb_expect(skb) = hci_sco_hdr(skb)->dlen; | |
| 1139 | + struct hci_sco_hdr *hdr = hci_sco_hdr(skb); | |
| 998 | 1140 | |
| 999 | − if (skb_tailroom(skb) < hci_skb_expect(skb)) { | |
| 1141 | + hci_skb_expect(skb) = hdr->dlen; | |
| 1142 | + | |
| 1143 | + if (skb_tailroom(skb) < hci_skb_expect(skb) || | |
| 1144 | + !btusb_validate_sco_handle(data->hdev, hdr)) { | |
| 1000 | 1145 | kfree_skb(skb); |
| 1001 | 1146 | skb = NULL; |
| 1002 | 1147 | |
| @@ -1276,11 +1421,17 @@ static void btusb_isoc_complete(struct urb *urb) · 273 unmodified lines | ||
| 1276 | 1421 | static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len, |
| 1277 | 1422 | int mtu, struct btusb_data *data) |
| 1278 | 1423 | { |
| 1279 | − int i, offset = 0; | |
| 1424 | + int i = 0, offset = 0; | |
| 1280 | 1425 | unsigned int interval; |
| 1281 | 1426 | |
| 1282 | 1427 | BT_DBG("len %d mtu %d", len, mtu); |
| 1283 | 1428 | |
| 1429 | + /* For mSBC ALT 6 settings some chips need to transmit the data | |
| 1430 | + * continuously without the zero length of USB packets. | |
| 1431 | + */ | |
| 1432 | + if (test_bit(BTUSB_ALT6_CONTINUOUS_TX, &data->flags)) | |
| 1433 | + goto ignore_usb_alt6_packet_flow; | |
| 1434 | + | |
| 1284 | 1435 | /* For mSBC ALT 6 setting the host will send the packet at continuous |
| 1285 | 1436 | * flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting |
| 1286 | 1437 | * 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets. |
| @@ -1300,6 +1451,7 @@ static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len, · 13 unmodified lines | ||
| 1300 | 1451 | urb->iso_frame_desc[i].length = offset; |
| 1301 | 1452 | } |
| 1302 | 1453 | |
| 1454 | +ignore_usb_alt6_packet_flow: | |
| 1303 | 1455 | if (len && i < BTUSB_MAX_ISOC_FRAMES) { |
| 1304 | 1456 | urb->iso_frame_desc[i].offset = offset; |
| 1305 | 1457 | urb->iso_frame_desc[i].length = len; |
| @@ -1981,10 +2133,11 @@ static void btusb_work(struct work_struct *work) · 675 unmodified lines | ||
| 1981 | 2133 | if (btusb_switch_alt_setting(hdev, new_alts) < 0) |
| 1982 | 2134 | bt_dev_err(hdev, "set USB alt:(%d) failed!", new_alts); |
| 1983 | 2135 | } else { |
| 1984 | − clear_bit(BTUSB_ISOC_RUNNING, &data->flags); | |
| 1985 | 2136 | usb_kill_anchored_urbs(&data->isoc_anchor); |
| 1986 | 2137 | |
| 1987 | − __set_isoc_interface(hdev, 0); | |
| 2138 | + if (test_and_clear_bit(BTUSB_ISOC_RUNNING, &data->flags)) | |
| 2139 | + __set_isoc_interface(hdev, 0); | |
| 2140 | + | |
| 1988 | 2141 | if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags)) |
| 1989 | 2142 | usb_autopm_put_interface(data->isoc ? data->isoc : data->intf); |
| 1990 | 2143 | } |
| @@ -2048,18 +2201,19 @@ static int btusb_setup_csr(struct hci_dev *hdev) · 57 unmodified lines | ||
| 2048 | 2201 | return err; |
| 2049 | 2202 | } |
| 2050 | 2203 | |
| 2051 | − if (skb->len != sizeof(struct hci_rp_read_local_version)) { | |
| 2204 | + rp = skb_pull_data(skb, sizeof(*rp)); | |
| 2205 | + if (!rp) { | |
| 2052 | 2206 | bt_dev_err(hdev, "CSR: Local version length mismatch"); |
| 2053 | 2207 | kfree_skb(skb); |
| 2054 | 2208 | return -EIO; |
| 2055 | 2209 | } |
| 2056 | 2210 | |
| 2057 | − rp = (struct hci_rp_read_local_version *)skb->data; | |
| 2211 | + bt_dev_info(hdev, "CSR: Setting up dongle with HCI ver=%u rev=%04x", | |
| 2212 | + rp->hci_ver, le16_to_cpu(rp->hci_rev)); | |
| 2058 | 2213 | |
| 2059 | − bt_dev_info(hdev, "CSR: Setting up dongle with HCI ver=%u rev=%04x; LMP ver=%u subver=%04x; manufacturer=%u", | |
| 2060 | − le16_to_cpu(rp->hci_ver), le16_to_cpu(rp->hci_rev), | |
| 2061 | − le16_to_cpu(rp->lmp_ver), le16_to_cpu(rp->lmp_subver), | |
| 2062 | − le16_to_cpu(rp->manufacturer)); | |
| 2214 | + bt_dev_info(hdev, "LMP ver=%u subver=%04x; manufacturer=%u", | |
| 2215 | + rp->lmp_ver, le16_to_cpu(rp->lmp_subver), | |
| 2216 | + le16_to_cpu(rp->manufacturer)); | |
| 2063 | 2217 | |
| 2064 | 2218 | /* Detect a wide host of Chinese controllers that aren't CSR. |
| 2065 | 2219 | * |
| @@ -2089,29 +2243,29 @@ static int btusb_setup_csr(struct hci_dev *hdev) · 23 unmodified lines | ||
| 2089 | 2243 | * third-party BT 4.0 dongle reuses it. |
| 2090 | 2244 | */ |
| 2091 | 2245 | else if (le16_to_cpu(rp->lmp_subver) <= 0x034e && |
| 2092 | − le16_to_cpu(rp->hci_ver) > BLUETOOTH_VER_1_1) | |
| 2246 | + rp->hci_ver > BLUETOOTH_VER_1_1) | |
| 2093 | 2247 | is_fake = true; |
| 2094 | 2248 | |
| 2095 | 2249 | else if (le16_to_cpu(rp->lmp_subver) <= 0x0529 && |
| 2096 | − le16_to_cpu(rp->hci_ver) > BLUETOOTH_VER_1_2) | |
| 2250 | + rp->hci_ver > BLUETOOTH_VER_1_2) | |
| 2097 | 2251 | is_fake = true; |
| 2098 | 2252 | |
| 2099 | 2253 | else if (le16_to_cpu(rp->lmp_subver) <= 0x0c5c && |
| 2100 | − le16_to_cpu(rp->hci_ver) > BLUETOOTH_VER_2_0) | |
| 2254 | + rp->hci_ver > BLUETOOTH_VER_2_0) | |
| 2101 | 2255 | is_fake = true; |
| 2102 | 2256 | |
| 2103 | 2257 | else if (le16_to_cpu(rp->lmp_subver) <= 0x1899 && |
| 2104 | − le16_to_cpu(rp->hci_ver) > BLUETOOTH_VER_2_1) | |
| 2258 | + rp->hci_ver > BLUETOOTH_VER_2_1) | |
| 2105 | 2259 | is_fake = true; |
| 2106 | 2260 | |
| 2107 | 2261 | else if (le16_to_cpu(rp->lmp_subver) <= 0x22bb && |
| 2108 | − le16_to_cpu(rp->hci_ver) > BLUETOOTH_VER_4_0) | |
| 2262 | + rp->hci_ver > BLUETOOTH_VER_4_0) | |
| 2109 | 2263 | is_fake = true; |
| 2110 | 2264 | |
| 2111 | 2265 | /* Other clones which beat all the above checks */ |
| 2112 | 2266 | else if (bcdDevice == 0x0134 && |
| 2113 | 2267 | le16_to_cpu(rp->lmp_subver) == 0x0c5c && |
| 2114 | − le16_to_cpu(rp->hci_ver) == BLUETOOTH_VER_2_0) | |
| 2268 | + rp->hci_ver == BLUETOOTH_VER_2_0) | |
| 2115 | 2269 | is_fake = true; |
| 2116 | 2270 | |
| 2117 | 2271 | if (is_fake) { |
| @@ -2321,6 +2475,19 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) · 203 unmodified lines | ||
| 2321 | 2475 | return -EILSEQ; |
| 2322 | 2476 | } |
| 2323 | 2477 | |
| 2478 | +static int btusb_setup_realtek(struct hci_dev *hdev) | |
| 2479 | +{ | |
| 2480 | + struct btusb_data *data = hci_get_drvdata(hdev); | |
| 2481 | + int ret; | |
| 2482 | + | |
| 2483 | + ret = btrtl_setup_realtek(hdev); | |
| 2484 | + | |
| 2485 | + if (btrealtek_test_flag(data->hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP)) | |
| 2486 | + set_bit(BTUSB_ALT6_CONTINUOUS_TX, &data->flags); | |
| 2487 | + | |
| 2488 | + return ret; | |
| 2489 | +} | |
| 2490 | + | |
| 2324 | 2491 | /* UHW CR mapping */ |
| 2325 | 2492 | #define MTK_BT_MISC 0x70002510 |
| 2326 | 2493 | #define MTK_BT_SUBSYS_RST 0x70002610 |
| @@ -3256,7 +3423,7 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, · 929 unmodified lines | ||
| 3256 | 3423 | |
| 3257 | 3424 | if (ver_rom & ~0xffffU) { |
| 3258 | 3425 | rver_rom_high = le16_to_cpu(rver->rom_version_high); |
| 3259 | − rver_rom = le32_to_cpu(rver_rom_high << 16 | rver_rom_low); | |
| 3426 | + rver_rom = rver_rom_high << 16 | rver_rom_low; | |
| 3260 | 3427 | } else { |
| 3261 | 3428 | rver_rom = rver_rom_low; |
| 3262 | 3429 | } |
| @@ -3761,6 +3928,9 @@ static int btusb_probe(struct usb_interface *intf, · 498 unmodified lines | ||
| 3761 | 3928 | /* Override the rx handlers */ |
| 3762 | 3929 | data->recv_event = btusb_recv_event_intel; |
| 3763 | 3930 | data->recv_bulk = btusb_recv_bulk_intel; |
| 3931 | + } else if (id->driver_info & BTUSB_REALTEK) { | |
| 3932 | + /* Allocate extra space for Realtek device */ | |
| 3933 | + priv_size += sizeof(struct btrealtek_data); | |
| 3764 | 3934 | } |
| 3765 | 3935 | |
| 3766 | 3936 | data->recv_acl = hci_recv_frame; |
| @@ -3919,7 +4089,7 @@ static int btusb_probe(struct usb_interface *intf, · 152 unmodified lines | ||
| 3919 | 4089 | |
| 3920 | 4090 | if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) && |
| 3921 | 4091 | (id->driver_info & BTUSB_REALTEK)) { |
| 3922 | − hdev->setup = btrtl_setup_realtek; | |
| 4092 | + hdev->setup = btusb_setup_realtek; | |
| 3923 | 4093 | hdev->shutdown = btrtl_shutdown_realtek; |
| 3924 | 4094 | hdev->cmd_timeout = btusb_rtl_cmd_timeout; |
| 3925 | 4095 | |
| @@ -4004,6 +4174,8 @@ static int btusb_probe(struct usb_interface *intf, · 78 unmodified lines | ||
| 4004 | 4174 | if (enable_autosuspend) |
| 4005 | 4175 | usb_enable_autosuspend(data->udev); |
| 4006 | 4176 | |
| 4177 | + data->poll_sync = enable_poll_sync; | |
| 4178 | + | |
| 4007 | 4179 | err = hci_register_dev(hdev); |
| 4008 | 4180 | if (err < 0) |
| 4009 | 4181 | goto out_free_dev; |
| @@ -53,11 +53,13 @@ · 52 unmodified lines | ||
| 53 | 53 | * struct bcm_device_data - device specific data |
| 54 | 54 | * @no_early_set_baudrate: Disallow set baudrate before driver setup() |
| 55 | 55 | * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it |
| 56 | + * @no_uart_clock_set: UART clock set command for >3Mbps mode is unavailable | |
| 56 | 57 | * @max_autobaud_speed: max baudrate supported by device in autobaud mode |
| 57 | 58 | */ |
| 58 | 59 | struct bcm_device_data { |
| 59 | 60 | bool no_early_set_baudrate; |
| 60 | 61 | bool drive_rts_on_open; |
| 62 | + bool no_uart_clock_set; | |
| 61 | 63 | u32 max_autobaud_speed; |
| 62 | 64 | }; |
| 63 | 65 | |
| @@ -100,6 +102,7 @@ struct bcm_device_data { · 36 unmodified lines | ||
| 100 | 102 | * @is_suspended: whether flow control is currently disabled |
| 101 | 103 | * @no_early_set_baudrate: don't set_baudrate before setup() |
| 102 | 104 | * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it |
| 105 | + * @no_uart_clock_set: UART clock set command for >3Mbps mode is unavailable | |
| 103 | 106 | * @pcm_int_params: keep the initial PCM configuration |
| 104 | 107 | * @use_autobaud_mode: start Bluetooth device in autobaud mode |
| 105 | 108 | * @max_autobaud_speed: max baudrate supported by device in autobaud mode |
| @@ -140,6 +143,7 @@ struct bcm_device { · 34 unmodified lines | ||
| 140 | 143 | #endif |
| 141 | 144 | bool no_early_set_baudrate; |
| 142 | 145 | bool drive_rts_on_open; |
| 146 | + bool no_uart_clock_set; | |
| 143 | 147 | bool use_autobaud_mode; |
| 144 | 148 | u8 pcm_int_params[5]; |
| 145 | 149 | u32 max_autobaud_speed; |
| @@ -172,10 +176,11 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) · 26 unmodified lines | ||
| 172 | 176 | static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) |
| 173 | 177 | { |
| 174 | 178 | struct hci_dev *hdev = hu->hdev; |
| 179 | + struct bcm_data *bcm = hu->priv; | |
| 175 | 180 | struct sk_buff *skb; |
| 176 | 181 | struct bcm_update_uart_baud_rate param; |
| 177 | 182 | |
| 178 | − if (speed > 3000000) { | |
| 183 | + if (speed > 3000000 && !bcm->dev->no_uart_clock_set) { | |
| 179 | 184 | struct bcm_write_uart_clock_setting clock; |
| 180 | 185 | |
| 181 | 186 | clock.type = BCM_UART_CLOCK_48MHZ; |
| @@ -1529,6 +1534,7 @@ static int bcm_serdev_probe(struct serdev_device *serdev) · 1347 unmodified lines | ||
| 1529 | 1534 | bcmdev->max_autobaud_speed = data->max_autobaud_speed; |
| 1530 | 1535 | bcmdev->no_early_set_baudrate = data->no_early_set_baudrate; |
| 1531 | 1536 | bcmdev->drive_rts_on_open = data->drive_rts_on_open; |
| 1537 | + bcmdev->no_uart_clock_set = data->no_uart_clock_set; | |
| 1532 | 1538 | } |
| 1533 | 1539 | |
| 1534 | 1540 | return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto); |
| @@ -1550,6 +1556,10 @@ static struct bcm_device_data bcm43438_device_data = { · 15 unmodified lines | ||
| 1550 | 1556 | .drive_rts_on_open = true, |
| 1551 | 1557 | }; |
| 1552 | 1558 | |
| 1559 | +static struct bcm_device_data cyw4373a0_device_data = { | |
| 1560 | + .no_uart_clock_set = true, | |
| 1561 | +}; | |
| 1562 | + | |
| 1553 | 1563 | static struct bcm_device_data cyw55572_device_data = { |
| 1554 | 1564 | .max_autobaud_speed = 921600, |
| 1555 | 1565 | }; |
| @@ -1566,6 +1576,7 @@ static const struct of_device_id bcm_bluetooth_of_match[] = { · 10 unmodified lines | ||
| 1566 | 1576 | { .compatible = "brcm,bcm4349-bt", .data = &bcm43438_device_data }, |
| 1567 | 1577 | { .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data }, |
| 1568 | 1578 | { .compatible = "brcm,bcm4335a0" }, |
| 1579 | + { .compatible = "cypress,cyw4373a0-bt", .data = &cyw4373a0_device_data }, | |
| 1569 | 1580 | { .compatible = "infineon,cyw55572-bt", .data = &cyw55572_device_data }, |
| 1570 | 1581 | { }, |
| 1571 | 1582 | }; |
| @@ -0,0 +1,2514 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only OR MIT | |
| 2 | +/* | |
| 3 | + * Bluetooth HCI driver for Broadcom 4377/4378/4387 devices attached via PCIe | |
| 4 | + * | |
| 5 | + * Copyright (C) The Asahi Linux Contributors | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/async.h> | |
| 9 | +#include <linux/bitfield.h> | |
| 10 | +#include <linux/completion.h> | |
| 11 | +#include <linux/dma-mapping.h> | |
| 12 | +#include <linux/dmi.h> | |
| 13 | +#include <linux/firmware.h> | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/msi.h> | |
| 16 | +#include <linux/of.h> | |
| 17 | +#include <linux/pci.h> | |
| 18 | +#include <linux/printk.h> | |
| 19 | + | |
| 20 | +#include <asm/unaligned.h> | |
| 21 | + | |
| 22 | +#include <net/bluetooth/bluetooth.h> | |
| 23 | +#include <net/bluetooth/hci_core.h> | |
| 24 | + | |
| 25 | +enum bcm4377_chip { | |
| 26 | + BCM4377 = 0, | |
| 27 | + BCM4378, | |
| 28 | + BCM4387, | |
| 29 | +}; | |
| 30 | + | |
| 31 | +#define BCM4377_DEVICE_ID 0x5fa0 | |
| 32 | +#define BCM4378_DEVICE_ID 0x5f69 | |
| 33 | +#define BCM4387_DEVICE_ID 0x5f71 | |
| 34 | + | |
| 35 | +#define BCM4377_TIMEOUT 1000 | |
| 36 | + | |
| 37 | +/* | |
| 38 | + * These devices only support DMA transactions inside a 32bit window | |
| 39 | + * (possibly to avoid 64 bit arithmetic). The window size cannot exceed | |
| 40 | + * 0xffffffff but is always aligned down to the previous 0x200 byte boundary | |
| 41 | + * which effectively limits the window to [start, start+0xfffffe00]. | |
| 42 | + * We just limit the DMA window to [0, 0xfffffe00] to make sure we don't | |
| 43 | + * run into this limitation. | |
| 44 | + */ | |
| 45 | +#define BCM4377_DMA_MASK 0xfffffe00 | |
| 46 | + | |
| 47 | +#define BCM4377_PCIECFG_BAR0_WINDOW1 0x80 | |
| 48 | +#define BCM4377_PCIECFG_BAR0_WINDOW2 0x70 | |
| 49 | +#define BCM4377_PCIECFG_BAR0_CORE2_WINDOW1 0x74 | |
| 50 | +#define BCM4377_PCIECFG_BAR0_CORE2_WINDOW2 0x78 | |
| 51 | +#define BCM4377_PCIECFG_BAR2_WINDOW 0x84 | |
| 52 | + | |
| 53 | +#define BCM4377_PCIECFG_BAR0_CORE2_WINDOW1_DEFAULT 0x18011000 | |
| 54 | +#define BCM4377_PCIECFG_BAR2_WINDOW_DEFAULT 0x19000000 | |
| 55 | + | |
| 56 | +#define BCM4377_PCIECFG_SUBSYSTEM_CTRL 0x88 | |
| 57 | + | |
| 58 | +#define BCM4377_BAR0_FW_DOORBELL 0x140 | |
| 59 | +#define BCM4377_BAR0_RTI_CONTROL 0x144 | |
| 60 | + | |
| 61 | +#define BCM4377_BAR0_SLEEP_CONTROL 0x150 | |
| 62 | +#define BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE 0 | |
| 63 | +#define BCM4377_BAR0_SLEEP_CONTROL_AWAKE 2 | |
| 64 | +#define BCM4377_BAR0_SLEEP_CONTROL_QUIESCE 3 | |
| 65 | + | |
| 66 | +#define BCM4377_BAR0_DOORBELL 0x174 | |
| 67 | +#define BCM4377_BAR0_DOORBELL_VALUE GENMASK(31, 16) | |
| 68 | +#define BCM4377_BAR0_DOORBELL_IDX GENMASK(15, 8) | |
| 69 | +#define BCM4377_BAR0_DOORBELL_RING BIT(5) | |
| 70 | + | |
| 71 | +#define BCM4377_BAR0_HOST_WINDOW_LO 0x590 | |
| 72 | +#define BCM4377_BAR0_HOST_WINDOW_HI 0x594 | |
| 73 | +#define BCM4377_BAR0_HOST_WINDOW_SIZE 0x598 | |
| 74 | + | |
| 75 | +#define BCM4377_BAR2_BOOTSTAGE 0x200454 | |
| 76 | + | |
| 77 | +#define BCM4377_BAR2_FW_LO 0x200478 | |
| 78 | +#define BCM4377_BAR2_FW_HI 0x20047c | |
| 79 | +#define BCM4377_BAR2_FW_SIZE 0x200480 | |
| 80 | + | |
| 81 | +#define BCM4377_BAR2_CONTEXT_ADDR_LO 0x20048c | |
| 82 | +#define BCM4377_BAR2_CONTEXT_ADDR_HI 0x200450 | |
| 83 | + | |
| 84 | +#define BCM4377_BAR2_RTI_STATUS 0x20045c | |
| 85 | +#define BCM4377_BAR2_RTI_WINDOW_LO 0x200494 | |
| 86 | +#define BCM4377_BAR2_RTI_WINDOW_HI 0x200498 | |
| 87 | +#define BCM4377_BAR2_RTI_WINDOW_SIZE 0x20049c | |
| 88 | + | |
| 89 | +#define BCM4377_OTP_SIZE 0xe0 | |
| 90 | +#define BCM4377_OTP_SYS_VENDOR 0x15 | |
| 91 | +#define BCM4377_OTP_CIS 0x80 | |
| 92 | +#define BCM4377_OTP_VENDOR_HDR 0x00000008 | |
| 93 | +#define BCM4377_OTP_MAX_PARAM_LEN 16 | |
| 94 | + | |
| 95 | +#define BCM4377_N_TRANSFER_RINGS 9 | |
| 96 | +#define BCM4377_N_COMPLETION_RINGS 6 | |
| 97 | + | |
| 98 | +#define BCM4377_MAX_RING_SIZE 256 | |
| 99 | + | |
| 100 | +#define BCM4377_MSGID_GENERATION GENMASK(15, 8) | |
| 101 | +#define BCM4377_MSGID_ID GENMASK(7, 0) | |
| 102 | + | |
| 103 | +#define BCM4377_RING_N_ENTRIES 128 | |
| 104 | + | |
| 105 | +#define BCM4377_CONTROL_MSG_SIZE 0x34 | |
| 106 | +#define BCM4377_XFER_RING_MAX_INPLACE_PAYLOAD_SIZE (4 * 0xff) | |
| 107 | + | |
| 108 | +#define MAX_ACL_PAYLOAD_SIZE (HCI_MAX_FRAME_SIZE + HCI_ACL_HDR_SIZE) | |
| 109 | +#define MAX_SCO_PAYLOAD_SIZE (HCI_MAX_SCO_SIZE + HCI_SCO_HDR_SIZE) | |
| 110 | +#define MAX_EVENT_PAYLOAD_SIZE (HCI_MAX_EVENT_SIZE + HCI_EVENT_HDR_SIZE) | |
| 111 | + | |
| 112 | +enum bcm4377_otp_params_type { | |
| 113 | + BCM4377_OTP_BOARD_PARAMS, | |
| 114 | + BCM4377_OTP_CHIP_PARAMS | |
| 115 | +}; | |
| 116 | + | |
| 117 | +enum bcm4377_transfer_ring_id { | |
| 118 | + BCM4377_XFER_RING_CONTROL = 0, | |
| 119 | + BCM4377_XFER_RING_HCI_H2D = 1, | |
| 120 | + BCM4377_XFER_RING_HCI_D2H = 2, | |
| 121 | + BCM4377_XFER_RING_SCO_H2D = 3, | |
| 122 | + BCM4377_XFER_RING_SCO_D2H = 4, | |
| 123 | + BCM4377_XFER_RING_ACL_H2D = 5, | |
| 124 | + BCM4377_XFER_RING_ACL_D2H = 6, | |
| 125 | +}; | |
| 126 | + | |
| 127 | +enum bcm4377_completion_ring_id { | |
| 128 | + BCM4377_ACK_RING_CONTROL = 0, | |
| 129 | + BCM4377_ACK_RING_HCI_ACL = 1, | |
| 130 | + BCM4377_EVENT_RING_HCI_ACL = 2, | |
| 131 | + BCM4377_ACK_RING_SCO = 3, | |
| 132 | + BCM4377_EVENT_RING_SCO = 4, | |
| 133 | +}; | |
| 134 | + | |
| 135 | +enum bcm4377_doorbell { | |
| 136 | + BCM4377_DOORBELL_CONTROL = 0, | |
| 137 | + BCM4377_DOORBELL_HCI_H2D = 1, | |
| 138 | + BCM4377_DOORBELL_HCI_D2H = 2, | |
| 139 | + BCM4377_DOORBELL_ACL_H2D = 3, | |
| 140 | + BCM4377_DOORBELL_ACL_D2H = 4, | |
| 141 | + BCM4377_DOORBELL_SCO = 6, | |
| 142 | +}; | |
| 143 | + | |
| 144 | +/* | |
| 145 | + * Transfer ring entry | |
| 146 | + * | |
| 147 | + * flags: Flags to indicate if the payload is appended or mapped | |
| 148 | + * len: Payload length | |
| 149 | + * payload: Optional payload DMA address | |
| 150 | + * id: Message id to recognize the answer in the completion ring entry | |
| 151 | + */ | |
| 152 | +struct bcm4377_xfer_ring_entry { | |
| 153 | +#define BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED BIT(0) | |
| 154 | +#define BCM4377_XFER_RING_FLAG_PAYLOAD_IN_FOOTER BIT(1) | |
| 155 | + u8 flags; | |
| 156 | + __le16 len; | |
| 157 | + u8 _unk0; | |
| 158 | + __le64 payload; | |
| 159 | + __le16 id; | |
| 160 | + u8 _unk1[2]; | |
| 161 | +} __packed; | |
| 162 | +static_assert(sizeof(struct bcm4377_xfer_ring_entry) == 0x10); | |
| 163 | + | |
| 164 | +/* | |
| 165 | + * Completion ring entry | |
| 166 | + * | |
| 167 | + * flags: Flags to indicate if the payload is appended or mapped. If the payload | |
| 168 | + * is mapped it can be found in the buffer of the corresponding transfer | |
| 169 | + * ring message. | |
| 170 | + * ring_id: Transfer ring ID which required this message | |
| 171 | + * msg_id: Message ID specified in transfer ring entry | |
| 172 | + * len: Payload length | |
| 173 | + */ | |
| 174 | +struct bcm4377_completion_ring_entry { | |
| 175 | + u8 flags; | |
| 176 | + u8 _unk0; | |
| 177 | + __le16 ring_id; | |
| 178 | + __le16 msg_id; | |
| 179 | + __le32 len; | |
| 180 | + u8 _unk1[6]; | |
| 181 | +} __packed; | |
| 182 | +static_assert(sizeof(struct bcm4377_completion_ring_entry) == 0x10); | |
| 183 | + | |
| 184 | +enum bcm4377_control_message_type { | |
| 185 | + BCM4377_CONTROL_MSG_CREATE_XFER_RING = 1, | |
| 186 | + BCM4377_CONTROL_MSG_CREATE_COMPLETION_RING = 2, | |
| 187 | + BCM4377_CONTROL_MSG_DESTROY_XFER_RING = 3, | |
| 188 | + BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING = 4, | |
| 189 | +}; | |
| 190 | + | |
| 191 | +/* | |
| 192 | + * Control message used to create a completion ring | |
| 193 | + * | |
| 194 | + * msg_type: Must be BCM4377_CONTROL_MSG_CREATE_COMPLETION_RING | |
| 195 | + * header_size: Unknown, but probably reserved space in front of the entry | |
| 196 | + * footer_size: Number of 32 bit words reserved for payloads after the entry | |
| 197 | + * id/id_again: Completion ring index | |
| 198 | + * ring_iova: DMA address of the ring buffer | |
| 199 | + * n_elements: Number of elements inside the ring buffer | |
| 200 | + * msi: MSI index, doesn't work for all rings though and should be zero | |
| 201 | + * intmod_delay: Unknown delay | |
| 202 | + * intmod_bytes: Unknown | |
| 203 | + */ | |
| 204 | +struct bcm4377_create_completion_ring_msg { | |
| 205 | + u8 msg_type; | |
| 206 | + u8 header_size; | |
| 207 | + u8 footer_size; | |
| 208 | + u8 _unk0; | |
| 209 | + __le16 id; | |
| 210 | + __le16 id_again; | |
| 211 | + __le64 ring_iova; | |
| 212 | + __le16 n_elements; | |
| 213 | + __le32 unk; | |
| 214 | + u8 _unk1[6]; | |
| 215 | + __le16 msi; | |
| 216 | + __le16 intmod_delay; | |
| 217 | + __le32 intmod_bytes; | |
| 218 | + __le16 _unk2; | |
| 219 | + __le32 _unk3; | |
| 220 | + u8 _unk4[10]; | |
| 221 | +} __packed; | |
| 222 | +static_assert(sizeof(struct bcm4377_create_completion_ring_msg) == | |
| 223 | + BCM4377_CONTROL_MSG_SIZE); | |
| 224 | + | |
| 225 | +/* | |
| 226 | + * Control ring message used to destroy a completion ring | |
| 227 | + * | |
| 228 | + * msg_type: Must be BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING | |
| 229 | + * ring_id: Completion ring to be destroyed | |
| 230 | + */ | |
| 231 | +struct bcm4377_destroy_completion_ring_msg { | |
| 232 | + u8 msg_type; | |
| 233 | + u8 _pad0; | |
| 234 | + __le16 ring_id; | |
| 235 | + u8 _pad1[48]; | |
| 236 | +} __packed; | |
| 237 | +static_assert(sizeof(struct bcm4377_destroy_completion_ring_msg) == | |
| 238 | + BCM4377_CONTROL_MSG_SIZE); | |
| 239 | + | |
| 240 | +/* | |
| 241 | + * Control message used to create a transfer ring | |
| 242 | + * | |
| 243 | + * msg_type: Must be BCM4377_CONTROL_MSG_CREATE_XFER_RING | |
| 244 | + * header_size: Number of 32 bit words reserved for unknown content before the | |
| 245 | + * entry | |
| 246 | + * footer_size: Number of 32 bit words reserved for payloads after the entry | |
| 247 | + * ring_id/ring_id_again: Transfer ring index | |
| 248 | + * ring_iova: DMA address of the ring buffer | |
| 249 | + * n_elements: Number of elements inside the ring buffer | |
| 250 | + * completion_ring_id: Completion ring index for acknowledgements and events | |
| 251 | + * doorbell: Doorbell index used to notify device of new entries | |
| 252 | + * flags: Transfer ring flags | |
| 253 | + * - virtual: set if there is no associated shared memory and only the | |
| 254 | + * corresponding completion ring is used | |
| 255 | + * - sync: only set for the SCO rings | |
| 256 | + */ | |
| 257 | +struct bcm4377_create_transfer_ring_msg { | |
| 258 | + u8 msg_type; | |
| 259 | + u8 header_size; | |
| 260 | + u8 footer_size; | |
| 261 | + u8 _unk0; | |
| 262 | + __le16 ring_id; | |
| 263 | + __le16 ring_id_again; | |
| 264 | + __le64 ring_iova; | |
| 265 | + u8 _unk1[8]; | |
| 266 | + __le16 n_elements; | |
| 267 | + __le16 completion_ring_id; | |
| 268 | + __le16 doorbell; | |
| 269 | +#define BCM4377_XFER_RING_FLAG_VIRTUAL BIT(7) | |
| 270 | +#define BCM4377_XFER_RING_FLAG_SYNC BIT(8) | |
| 271 | + __le16 flags; | |
| 272 | + u8 _unk2[20]; | |
| 273 | +} __packed; | |
| 274 | +static_assert(sizeof(struct bcm4377_create_transfer_ring_msg) == | |
| 275 | + BCM4377_CONTROL_MSG_SIZE); | |
| 276 | + | |
| 277 | +/* | |
| 278 | + * Control ring message used to destroy a transfer ring | |
| 279 | + * | |
| 280 | + * msg_type: Must be BCM4377_CONTROL_MSG_DESTROY_XFER_RING | |
| 281 | + * ring_id: Transfer ring to be destroyed | |
| 282 | + */ | |
| 283 | +struct bcm4377_destroy_transfer_ring_msg { | |
| 284 | + u8 msg_type; | |
| 285 | + u8 _pad0; | |
| 286 | + __le16 ring_id; | |
| 287 | + u8 _pad1[48]; | |
| 288 | +} __packed; | |
| 289 | +static_assert(sizeof(struct bcm4377_destroy_transfer_ring_msg) == | |
| 290 | + BCM4377_CONTROL_MSG_SIZE); | |
| 291 | + | |
| 292 | +/* | |
| 293 | + * "Converged IPC" context struct used to make the device aware of all other | |
| 294 | + * shared memory structures. A pointer to this structure is configured inside a | |
| 295 | + * MMIO register. | |
| 296 | + * | |
| 297 | + * version: Protocol version, must be 2. | |
| 298 | + * size: Size of this structure, must be 0x68. | |
| 299 | + * enabled_caps: Enabled capabilities. Unknown bitfield but should be 2. | |
| 300 | + * peripheral_info_addr: DMA address for a 0x20 buffer to which the device will | |
| 301 | + * write unknown contents | |
| 302 | + * {completion,xfer}_ring_{tails,heads}_addr: DMA pointers to ring heads/tails | |
| 303 | + * n_completion_rings: Number of completion rings, the firmware only works if | |
| 304 | + * this is set to BCM4377_N_COMPLETION_RINGS. | |
| 305 | + * n_xfer_rings: Number of transfer rings, the firmware only works if | |
| 306 | + * this is set to BCM4377_N_TRANSFER_RINGS. | |
| 307 | + * control_completion_ring_addr: Control completion ring buffer DMA address | |
| 308 | + * control_xfer_ring_addr: Control transfer ring buffer DMA address | |
| 309 | + * control_xfer_ring_n_entries: Number of control transfer ring entries | |
| 310 | + * control_completion_ring_n_entries: Number of control completion ring entries | |
| 311 | + * control_xfer_ring_doorbell: Control transfer ring doorbell | |
| 312 | + * control_completion_ring_doorbell: Control completion ring doorbell, | |
| 313 | + * must be set to 0xffff | |
| 314 | + * control_xfer_ring_msi: Control completion ring MSI index, must be 0 | |
| 315 | + * control_completion_ring_msi: Control completion ring MSI index, must be 0. | |
| 316 | + * control_xfer_ring_header_size: Number of 32 bit words reserved in front of | |
| 317 | + * every control transfer ring entry | |
| 318 | + * control_xfer_ring_footer_size: Number of 32 bit words reserved after every | |
| 319 | + * control transfer ring entry | |
| 320 | + * control_completion_ring_header_size: Number of 32 bit words reserved in front | |
| 321 | + * of every control completion ring entry | |
| 322 | + * control_completion_ring_footer_size: Number of 32 bit words reserved after | |
| 323 | + * every control completion ring entry | |
| 324 | + * scratch_pad: Optional scratch pad DMA address | |
| 325 | + * scratch_pad_size: Scratch pad size | |
| 326 | + */ | |
| 327 | +struct bcm4377_context { | |
| 328 | + __le16 version; | |
| 329 | + __le16 size; | |
| 330 | + __le32 enabled_caps; | |
| 331 | + | |
| 332 | + __le64 peripheral_info_addr; | |
| 333 | + | |
| 334 | + /* ring heads and tails */ | |
| 335 | + __le64 completion_ring_heads_addr; | |
| 336 | + __le64 xfer_ring_tails_addr; | |
| 337 | + __le64 completion_ring_tails_addr; | |
| 338 | + __le64 xfer_ring_heads_addr; | |
| 339 | + __le16 n_completion_rings; | |
| 340 | + __le16 n_xfer_rings; | |
| 341 | + | |
| 342 | + /* control ring configuration */ | |
| 343 | + __le64 control_completion_ring_addr; | |
| 344 | + __le64 control_xfer_ring_addr; | |
| 345 | + __le16 control_xfer_ring_n_entries; | |
| 346 | + __le16 control_completion_ring_n_entries; | |
| 347 | + __le16 control_xfer_ring_doorbell; | |
| 348 | + __le16 control_completion_ring_doorbell; | |
| 349 | + __le16 control_xfer_ring_msi; | |
| 350 | + __le16 control_completion_ring_msi; | |
| 351 | + u8 control_xfer_ring_header_size; | |
| 352 | + u8 control_xfer_ring_footer_size; | |
| 353 | + u8 control_completion_ring_header_size; | |
| 354 | + u8 control_completion_ring_footer_size; | |
| 355 | + | |
| 356 | + __le16 _unk0; | |
| 357 | + __le16 _unk1; | |
| 358 | + | |
| 359 | + __le64 scratch_pad; | |
| 360 | + __le32 scratch_pad_size; | |
| 361 | + | |
| 362 | + __le32 _unk3; | |
| 363 | +} __packed; | |
| 364 | +static_assert(sizeof(struct bcm4377_context) == 0x68); | |
| 365 | + | |
| 366 | +#define BCM4378_CALIBRATION_CHUNK_SIZE 0xe6 | |
| 367 | +struct bcm4378_hci_send_calibration_cmd { | |
| 368 | + u8 unk; | |
| 369 | + __le16 blocks_left; | |
| 370 | + u8 data[BCM4378_CALIBRATION_CHUNK_SIZE]; | |
| 371 | +} __packed; | |
| 372 | + | |
| 373 | +#define BCM4378_PTB_CHUNK_SIZE 0xcf | |
| 374 | +struct bcm4378_hci_send_ptb_cmd { | |
| 375 | + __le16 blocks_left; | |
| 376 | + u8 data[BCM4378_PTB_CHUNK_SIZE]; | |
| 377 | +} __packed; | |
| 378 | + | |
| 379 | +/* | |
| 380 | + * Shared memory structure used to store the ring head and tail pointers. | |
| 381 | + */ | |
| 382 | +struct bcm4377_ring_state { | |
| 383 | + __le16 completion_ring_head[BCM4377_N_COMPLETION_RINGS]; | |
| 384 | + __le16 completion_ring_tail[BCM4377_N_COMPLETION_RINGS]; | |
| 385 | + __le16 xfer_ring_head[BCM4377_N_TRANSFER_RINGS]; | |
| 386 | + __le16 xfer_ring_tail[BCM4377_N_TRANSFER_RINGS]; | |
| 387 | +}; | |
| 388 | + | |
| 389 | +/* | |
| 390 | + * A transfer ring can be used in two configurations: | |
| 391 | + * 1) Send control or HCI messages to the device which are then acknowledged | |
| 392 | + * in the corresponding completion ring | |
| 393 | + * 2) Receiving HCI frames from the devices. In this case the transfer ring | |
| 394 | + * itself contains empty messages that are acknowledged once data is | |
| 395 | + * available from the device. If the payloads fit inside the footers | |
| 396 | + * of the completion ring the transfer ring can be configured to be | |
| 397 | + * virtual such that it has no ring buffer. | |
| 398 | + * | |
| 399 | + * ring_id: ring index hardcoded in the firmware | |
| 400 | + * doorbell: doorbell index to notify device of new entries | |
| 401 | + * payload_size: optional in-place payload size | |
| 402 | + * mapped_payload_size: optional out-of-place payload size | |
| 403 | + * completion_ring: index of corresponding completion ring | |
| 404 | + * n_entries: number of entries inside this ring | |
| 405 | + * generation: ring generation; incremented on hci_open to detect stale messages | |
| 406 | + * sync: set to true for SCO rings | |
| 407 | + * virtual: set to true if this ring has no entries and is just required to | |
| 408 | + * setup a corresponding completion ring for device->host messages | |
| 409 | + * d2h_buffers_only: set to true if this ring is only used to provide large | |
| 410 | + * buffers used by device->host messages in the completion | |
| 411 | + * ring | |
| 412 | + * allow_wait: allow to wait for messages to be acknowledged | |
| 413 | + * enabled: true once the ring has been created and can be used | |
| 414 | + * ring: ring buffer for entries (struct bcm4377_xfer_ring_entry) | |
| 415 | + * ring_dma: DMA address for ring entry buffer | |
| 416 | + * payloads: payload buffer for mapped_payload_size payloads | |
| 417 | + * payloads_dma:DMA address for payload buffer | |
| 418 | + * events: pointer to array of completions if waiting is allowed | |
| 419 | + * msgids: bitmap to keep track of used message ids | |
| 420 | + * lock: Spinlock to protect access to ring structurs used in the irq handler | |
| 421 | + */ | |
| 422 | +struct bcm4377_transfer_ring { | |
| 423 | + enum bcm4377_transfer_ring_id ring_id; | |
| 424 | + enum bcm4377_doorbell doorbell; | |
| 425 | + size_t payload_size; | |
| 426 | + size_t mapped_payload_size; | |
| 427 | + u8 completion_ring; | |
| 428 | + u16 n_entries; | |
| 429 | + u8 generation; | |
| 430 | + | |
| 431 | + bool sync; | |
| 432 | + bool virtual; | |
| 433 | + bool d2h_buffers_only; | |
| 434 | + bool allow_wait; | |
| 435 | + bool enabled; | |
| 436 | + | |
| 437 | + void *ring; | |
| 438 | + dma_addr_t ring_dma; | |
| 439 | + | |
| 440 | + void *payloads; | |
| 441 | + dma_addr_t payloads_dma; | |
| 442 | + | |
| 443 | + struct completion **events; | |
| 444 | + DECLARE_BITMAP(msgids, BCM4377_MAX_RING_SIZE); | |
| 445 | + spinlock_t lock; | |
| 446 | +}; | |
| 447 | + | |
| 448 | +/* | |
| 449 | + * A completion ring can be either used to either acknowledge messages sent in | |
| 450 | + * the corresponding transfer ring or to receive messages associated with the | |
| 451 | + * transfer ring. When used to receive messages the transfer ring either | |
| 452 | + * has no ring buffer and is only advanced ("virtual transfer ring") or it | |
| 453 | + * only contains empty DMA buffers to be used for the payloads. | |
| 454 | + * | |
| 455 | + * ring_id: completion ring id, hardcoded in firmware | |
| 456 | + * payload_size: optional payload size after each entry | |
| 457 | + * delay: unknown delay | |
| 458 | + * n_entries: number of entries in this ring | |
| 459 | + * enabled: true once the ring has been created and can be used | |
| 460 | + * ring: ring buffer for entries (struct bcm4377_completion_ring_entry) | |
| 461 | + * ring_dma: DMA address of ring buffer | |
| 462 | + * transfer_rings: bitmap of corresponding transfer ring ids | |
| 463 | + */ | |
| 464 | +struct bcm4377_completion_ring { | |
| 465 | + enum bcm4377_completion_ring_id ring_id; | |
| 466 | + u16 payload_size; | |
| 467 | + u16 delay; | |
| 468 | + u16 n_entries; | |
| 469 | + bool enabled; | |
| 470 | + | |
| 471 | + void *ring; | |
| 472 | + dma_addr_t ring_dma; | |
| 473 | + | |
| 474 | + unsigned long transfer_rings; | |
| 475 | +}; | |
| 476 | + | |
| 477 | +struct bcm4377_data; | |
| 478 | + | |
| 479 | +/* | |
| 480 | + * Chip-specific configuration struct | |
| 481 | + * | |
| 482 | + * id: Chip id (e.g. 0x4377 for BCM4377) | |
| 483 | + * otp_offset: Offset to the start of the OTP inside BAR0 | |
| 484 | + * bar0_window1: Backplane address mapped to the first window in BAR0 | |
| 485 | + * bar0_window2: Backplane address mapped to the second window in BAR0 | |
| 486 | + * bar0_core2_window2: Optional backplane address mapped to the second core's | |
| 487 | + * second window in BAR0 | |
| 488 | + * has_bar0_core2_window2: Set to true if this chip requires the second core's | |
| 489 | + * second window to be configured | |
| 490 | + * clear_pciecfg_subsystem_ctrl_bit19: Set to true if bit 19 in the | |
| 491 | + * vendor-specific subsystem control | |
| 492 | + * register has to be cleared | |
| 493 | + * disable_aspm: Set to true if ASPM must be disabled due to hardware errata | |
| 494 | + * broken_ext_scan: Set to true if the chip erroneously claims to support | |
| 495 | + * extended scanning | |
| 496 | + * broken_mws_transport_config: Set to true if the chip erroneously claims to | |
| 497 | + * support MWS Transport Configuration | |
| 498 | + * send_calibration: Optional callback to send calibration data | |
| 499 | + * send_ptb: Callback to send "PTB" regulatory/calibration data | |
| 500 | + */ | |
| 501 | +struct bcm4377_hw { | |
| 502 | + unsigned int id; | |
| 503 | + | |
| 504 | + u32 otp_offset; | |
| 505 | + | |
| 506 | + u32 bar0_window1; | |
| 507 | + u32 bar0_window2; | |
| 508 | + u32 bar0_core2_window2; | |
| 509 | + | |
| 510 | + unsigned long has_bar0_core2_window2 : 1; | |
| 511 | + unsigned long clear_pciecfg_subsystem_ctrl_bit19 : 1; | |
| 512 | + unsigned long disable_aspm : 1; | |
| 513 | + unsigned long broken_ext_scan : 1; | |
| 514 | + unsigned long broken_mws_transport_config : 1; | |
| 515 | + | |
| 516 | + int (*send_calibration)(struct bcm4377_data *bcm4377); | |
| 517 | + int (*send_ptb)(struct bcm4377_data *bcm4377, | |
| 518 | + const struct firmware *fw); | |
| 519 | +}; | |
| 520 | + | |
| 521 | +static const struct bcm4377_hw bcm4377_hw_variants[]; | |
| 522 | +static const struct dmi_system_id bcm4377_dmi_board_table[]; | |
| 523 | + | |
| 524 | +/* | |
| 525 | + * Private struct associated with each device containing global state | |
| 526 | + * | |
| 527 | + * pdev: Pointer to associated struct pci_dev | |
| 528 | + * hdev: Pointer to associated strucy hci_dev | |
| 529 | + * bar0: iomem pointing to BAR0 | |
| 530 | + * bar1: iomem pointing to BAR2 | |
| 531 | + * bootstage: Current value of the bootstage | |
| 532 | + * rti_status: Current "RTI" status value | |
| 533 | + * hw: Pointer to chip-specific struct bcm4377_hw | |
| 534 | + * taurus_cal_blob: "Taurus" calibration blob used for some chips | |
| 535 | + * taurus_cal_size: "Taurus" calibration blob size | |
| 536 | + * taurus_beamforming_cal_blob: "Taurus" beamforming calibration blob used for | |
| 537 | + * some chips | |
| 538 | + * taurus_beamforming_cal_size: "Taurus" beamforming calibration blob size | |
| 539 | + * stepping: Chip stepping read from OTP; used for firmware selection | |
| 540 | + * vendor: Antenna vendor read from OTP; used for firmware selection | |
| 541 | + * board_type: Board type from FDT or DMI match; used for firmware selection | |
| 542 | + * event: Event for changed bootstage or rti_status; used for booting firmware | |
| 543 | + * ctx: "Converged IPC" context | |
| 544 | + * ctx_dma: "Converged IPC" context DMA address | |
| 545 | + * ring_state: Shared memory buffer containing ring head and tail indexes | |
| 546 | + * ring_state_dma: DMA address for ring_state | |
| 547 | + * {control,hci_acl,sco}_ack_ring: Completion rings used to acknowledge messages | |
| 548 | + * {hci_acl,sco}_event_ring: Completion rings used for device->host messages | |
| 549 | + * control_h2d_ring: Transfer ring used for control messages | |
| 550 | + * {hci,sco,acl}_h2d_ring: Transfer ring used to transfer HCI frames | |
| 551 | + * {hci,sco,acl}_d2h_ring: Transfer ring used to receive HCI frames in the | |
| 552 | + * corresponding completion ring | |
| 553 | + */ | |
| 554 | +struct bcm4377_data { | |
| 555 | + struct pci_dev *pdev; | |
| 556 | + struct hci_dev *hdev; | |
| 557 | + | |
| 558 | + void __iomem *bar0; | |
| 559 | + void __iomem *bar2; | |
| 560 | + | |
| 561 | + u32 bootstage; | |
| 562 | + u32 rti_status; | |
| 563 | + | |
| 564 | + const struct bcm4377_hw *hw; | |
| 565 | + | |
| 566 | + const void *taurus_cal_blob; | |
| 567 | + int taurus_cal_size; | |
| 568 | + const void *taurus_beamforming_cal_blob; | |
| 569 | + int taurus_beamforming_cal_size; | |
| 570 | + | |
| 571 | + char stepping[BCM4377_OTP_MAX_PARAM_LEN]; | |
| 572 | + char vendor[BCM4377_OTP_MAX_PARAM_LEN]; | |
| 573 | + const char *board_type; | |
| 574 | + | |
| 575 | + struct completion event; | |
| 576 | + | |
| 577 | + struct bcm4377_context *ctx; | |
| 578 | + dma_addr_t ctx_dma; | |
| 579 | + | |
| 580 | + struct bcm4377_ring_state *ring_state; | |
| 581 | + dma_addr_t ring_state_dma; | |
| 582 | + | |
| 583 | + /* | |
| 584 | + * The HCI and ACL rings have to be merged because this structure is | |
| 585 | + * hardcoded in the firmware. | |
| 586 | + */ | |
| 587 | + struct bcm4377_completion_ring control_ack_ring; | |
| 588 | + struct bcm4377_completion_ring hci_acl_ack_ring; | |
| 589 | + struct bcm4377_completion_ring hci_acl_event_ring; | |
| 590 | + struct bcm4377_completion_ring sco_ack_ring; | |
| 591 | + struct bcm4377_completion_ring sco_event_ring; | |
| 592 | + | |
| 593 | + struct bcm4377_transfer_ring control_h2d_ring; | |
| 594 | + struct bcm4377_transfer_ring hci_h2d_ring; | |
| 595 | + struct bcm4377_transfer_ring hci_d2h_ring; | |
| 596 | + struct bcm4377_transfer_ring sco_h2d_ring; | |
| 597 | + struct bcm4377_transfer_ring sco_d2h_ring; | |
| 598 | + struct bcm4377_transfer_ring acl_h2d_ring; | |
| 599 | + struct bcm4377_transfer_ring acl_d2h_ring; | |
| 600 | +}; | |
| 601 | + | |
| 602 | +static void bcm4377_ring_doorbell(struct bcm4377_data *bcm4377, u8 doorbell, | |
| 603 | + u16 val) | |
| 604 | +{ | |
| 605 | + u32 db = 0; | |
| 606 | + | |
| 607 | + db |= FIELD_PREP(BCM4377_BAR0_DOORBELL_VALUE, val); | |
| 608 | + db |= FIELD_PREP(BCM4377_BAR0_DOORBELL_IDX, doorbell); | |
| 609 | + db |= BCM4377_BAR0_DOORBELL_RING; | |
| 610 | + | |
| 611 | + dev_dbg(&bcm4377->pdev->dev, "write %d to doorbell #%d (0x%x)\n", val, | |
| 612 | + doorbell, db); | |
| 613 | + iowrite32(db, bcm4377->bar0 + BCM4377_BAR0_DOORBELL); | |
| 614 | +} | |
| 615 | + | |
| 616 | +static int bcm4377_extract_msgid(struct bcm4377_data *bcm4377, | |
| 617 | + struct bcm4377_transfer_ring *ring, | |
| 618 | + u16 raw_msgid, u8 *msgid) | |
| 619 | +{ | |
| 620 | + u8 generation = FIELD_GET(BCM4377_MSGID_GENERATION, raw_msgid); | |
| 621 | + *msgid = FIELD_GET(BCM4377_MSGID_ID, raw_msgid); | |
| 622 | + | |
| 623 | + if (generation != ring->generation) { | |
| 624 | + dev_warn( | |
| 625 | + &bcm4377->pdev->dev, | |
| 626 | + "invalid message generation %d should be %d in entry for ring %d\n", | |
| 627 | + generation, ring->generation, ring->ring_id); | |
| 628 | + return -EINVAL; | |
| 629 | + } | |
| 630 | + | |
| 631 | + if (*msgid >= ring->n_entries) { | |
| 632 | + dev_warn(&bcm4377->pdev->dev, | |
| 633 | + "invalid message id in entry for ring %d: %d > %d\n", | |
| 634 | + ring->ring_id, *msgid, ring->n_entries); | |
| 635 | + return -EINVAL; | |
| 636 | + } | |
| 637 | + | |
| 638 | + return 0; | |
| 639 | +} | |
| 640 | + | |
| 641 | +static void bcm4377_handle_event(struct bcm4377_data *bcm4377, | |
| 642 | + struct bcm4377_transfer_ring *ring, | |
| 643 | + u16 raw_msgid, u8 entry_flags, u8 type, | |
| 644 | + void *payload, size_t len) | |
| 645 | +{ | |
| 646 | + struct sk_buff *skb; | |
| 647 | + u16 head; | |
| 648 | + u8 msgid; | |
| 649 | + unsigned long flags; | |
| 650 | + | |
| 651 | + spin_lock_irqsave(&ring->lock, flags); | |
| 652 | + if (!ring->enabled) { | |
| 653 | + dev_warn(&bcm4377->pdev->dev, | |
| 654 | + "event for disabled transfer ring %d\n", | |
| 655 | + ring->ring_id); | |
| 656 | + goto out; | |
| 657 | + } | |
| 658 | + | |
| 659 | + if (ring->d2h_buffers_only && | |
| 660 | + entry_flags & BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED) { | |
| 661 | + if (bcm4377_extract_msgid(bcm4377, ring, raw_msgid, &msgid)) | |
| 662 | + goto out; | |
| 663 | + | |
| 664 | + if (len > ring->mapped_payload_size) { | |
| 665 | + dev_warn( | |
| 666 | + &bcm4377->pdev->dev, | |
| 667 | + "invalid payload len in event for ring %d: %zu > %zu\n", | |
| 668 | + ring->ring_id, len, ring->mapped_payload_size); | |
| 669 | + goto out; | |
| 670 | + } | |
| 671 | + | |
| 672 | + payload = ring->payloads + msgid * ring->mapped_payload_size; | |
| 673 | + } | |
| 674 | + | |
| 675 | + skb = bt_skb_alloc(len, GFP_ATOMIC); | |
| 676 | + if (!skb) | |
| 677 | + goto out; | |
| 678 | + | |
| 679 | + memcpy(skb_put(skb, len), payload, len); | |
| 680 | + hci_skb_pkt_type(skb) = type; | |
| 681 | + hci_recv_frame(bcm4377->hdev, skb); | |
| 682 | + | |
| 683 | +out: | |
| 684 | + head = le16_to_cpu(bcm4377->ring_state->xfer_ring_head[ring->ring_id]); | |
| 685 | + head = (head + 1) % ring->n_entries; | |
| 686 | + bcm4377->ring_state->xfer_ring_head[ring->ring_id] = cpu_to_le16(head); | |
| 687 | + | |
| 688 | + bcm4377_ring_doorbell(bcm4377, ring->doorbell, head); | |
| 689 | + | |
| 690 | + spin_unlock_irqrestore(&ring->lock, flags); | |
| 691 | +} | |
| 692 | + | |
| 693 | +static void bcm4377_handle_ack(struct bcm4377_data *bcm4377, | |
| 694 | + struct bcm4377_transfer_ring *ring, | |
| 695 | + u16 raw_msgid) | |
| 696 | +{ | |
| 697 | + unsigned long flags; | |
| 698 | + u8 msgid; | |
| 699 | + | |
| 700 | + spin_lock_irqsave(&ring->lock, flags); | |
| 701 | + | |
| 702 | + if (bcm4377_extract_msgid(bcm4377, ring, raw_msgid, &msgid)) | |
| 703 | + goto unlock; | |
| 704 | + | |
| 705 | + if (!test_bit(msgid, ring->msgids)) { | |
| 706 | + dev_warn( | |
| 707 | + &bcm4377->pdev->dev, | |
| 708 | + "invalid message id in ack for ring %d: %d is not used\n", | |
| 709 | + ring->ring_id, msgid); | |
| 710 | + goto unlock; | |
| 711 | + } | |
| 712 | + | |
| 713 | + if (ring->allow_wait && ring->events[msgid]) { | |
| 714 | + complete(ring->events[msgid]); | |
| 715 | + ring->events[msgid] = NULL; | |
| 716 | + } | |
| 717 | + | |
| 718 | + bitmap_release_region(ring->msgids, msgid, ring->n_entries); | |
| 719 | + | |
| 720 | +unlock: | |
| 721 | + spin_unlock_irqrestore(&ring->lock, flags); | |
| 722 | +} | |
| 723 | + | |
| 724 | +static void bcm4377_handle_completion(struct bcm4377_data *bcm4377, | |
| 725 | + struct bcm4377_completion_ring *ring, | |
| 726 | + u16 pos) | |
| 727 | +{ | |
| 728 | + struct bcm4377_completion_ring_entry *entry; | |
| 729 | + u16 msg_id, transfer_ring; | |
| 730 | + size_t entry_size, data_len; | |
| 731 | + void *data; | |
| 732 | + | |
| 733 | + if (pos >= ring->n_entries) { | |
| 734 | + dev_warn(&bcm4377->pdev->dev, | |
| 735 | + "invalid offset %d for completion ring %d\n", pos, | |
| 736 | + ring->ring_id); | |
| 737 | + return; | |
| 738 | + } | |
| 739 | + | |
| 740 | + entry_size = sizeof(*entry) + ring->payload_size; | |
| 741 | + entry = ring->ring + pos * entry_size; | |
| 742 | + data = ring->ring + pos * entry_size + sizeof(*entry); | |
| 743 | + data_len = le32_to_cpu(entry->len); | |
| 744 | + msg_id = le16_to_cpu(entry->msg_id); | |
| 745 | + transfer_ring = le16_to_cpu(entry->ring_id); | |
| 746 | + | |
| 747 | + if ((ring->transfer_rings & BIT(transfer_ring)) == 0) { | |
| 748 | + dev_warn( | |
| 749 | + &bcm4377->pdev->dev, | |
| 750 | + "invalid entry at offset %d for transfer ring %d in completion ring %d\n", | |
| 751 | + pos, transfer_ring, ring->ring_id); | |
| 752 | + return; | |
| 753 | + } | |
| 754 | + | |
| 755 | + dev_dbg(&bcm4377->pdev->dev, | |
| 756 | + "entry in completion ring %d for transfer ring %d with msg_id %d\n", | |
| 757 | + ring->ring_id, transfer_ring, msg_id); | |
| 758 | + | |
| 759 | + switch (transfer_ring) { | |
| 760 | + case BCM4377_XFER_RING_CONTROL: | |
| 761 | + bcm4377_handle_ack(bcm4377, &bcm4377->control_h2d_ring, msg_id); | |
| 762 | + break; | |
| 763 | + case BCM4377_XFER_RING_HCI_H2D: | |
| 764 | + bcm4377_handle_ack(bcm4377, &bcm4377->hci_h2d_ring, msg_id); | |
| 765 | + break; | |
| 766 | + case BCM4377_XFER_RING_SCO_H2D: | |
| 767 | + bcm4377_handle_ack(bcm4377, &bcm4377->sco_h2d_ring, msg_id); | |
| 768 | + break; | |
| 769 | + case BCM4377_XFER_RING_ACL_H2D: | |
| 770 | + bcm4377_handle_ack(bcm4377, &bcm4377->acl_h2d_ring, msg_id); | |
| 771 | + break; | |
| 772 | + | |
| 773 | + case BCM4377_XFER_RING_HCI_D2H: | |
| 774 | + bcm4377_handle_event(bcm4377, &bcm4377->hci_d2h_ring, msg_id, | |
| 775 | + entry->flags, HCI_EVENT_PKT, data, | |
| 776 | + data_len); | |
| 777 | + break; | |
| 778 | + case BCM4377_XFER_RING_SCO_D2H: | |
| 779 | + bcm4377_handle_event(bcm4377, &bcm4377->sco_d2h_ring, msg_id, | |
| 780 | + entry->flags, HCI_SCODATA_PKT, data, | |
| 781 | + data_len); | |
| 782 | + break; | |
| 783 | + case BCM4377_XFER_RING_ACL_D2H: | |
| 784 | + bcm4377_handle_event(bcm4377, &bcm4377->acl_d2h_ring, msg_id, | |
| 785 | + entry->flags, HCI_ACLDATA_PKT, data, | |
| 786 | + data_len); | |
| 787 | + break; | |
| 788 | + | |
| 789 | + default: | |
| 790 | + dev_warn( | |
| 791 | + &bcm4377->pdev->dev, | |
| 792 | + "entry in completion ring %d for unknown transfer ring %d with msg_id %d\n", | |
| 793 | + ring->ring_id, transfer_ring, msg_id); | |
| 794 | + } | |
| 795 | +} | |
| 796 | + | |
| 797 | +static void bcm4377_poll_completion_ring(struct bcm4377_data *bcm4377, | |
| 798 | + struct bcm4377_completion_ring *ring) | |
| 799 | +{ | |
| 800 | + u16 tail; | |
| 801 | + __le16 *heads = bcm4377->ring_state->completion_ring_head; | |
| 802 | + __le16 *tails = bcm4377->ring_state->completion_ring_tail; | |
| 803 | + | |
| 804 | + if (!ring->enabled) | |
| 805 | + return; | |
| 806 | + | |
| 807 | + tail = le16_to_cpu(tails[ring->ring_id]); | |
| 808 | + dev_dbg(&bcm4377->pdev->dev, | |
| 809 | + "completion ring #%d: head: %d, tail: %d\n", ring->ring_id, | |
| 810 | + le16_to_cpu(heads[ring->ring_id]), tail); | |
| 811 | + | |
| 812 | + while (tail != le16_to_cpu(READ_ONCE(heads[ring->ring_id]))) { | |
| 813 | + /* | |
| 814 | + * ensure the CPU doesn't speculate through the comparison. | |
| 815 | + * otherwise it might already read the (empty) queue entry | |
| 816 | + * before the updated head has been loaded and checked. | |
| 817 | + */ | |
| 818 | + dma_rmb(); | |
| 819 | + | |
| 820 | + bcm4377_handle_completion(bcm4377, ring, tail); | |
| 821 | + | |
| 822 | + tail = (tail + 1) % ring->n_entries; | |
| 823 | + tails[ring->ring_id] = cpu_to_le16(tail); | |
| 824 | + } | |
| 825 | +} | |
| 826 | + | |
| 827 | +static irqreturn_t bcm4377_irq(int irq, void *data) | |
| 828 | +{ | |
| 829 | + struct bcm4377_data *bcm4377 = data; | |
| 830 | + u32 bootstage, rti_status; | |
| 831 | + | |
| 832 | + bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE); | |
| 833 | + rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS); | |
| 834 | + | |
| 835 | + if (bootstage != bcm4377->bootstage || | |
| 836 | + rti_status != bcm4377->rti_status) { | |
| 837 | + dev_dbg(&bcm4377->pdev->dev, | |
| 838 | + "bootstage = %d -> %d, rti state = %d -> %d\n", | |
| 839 | + bcm4377->bootstage, bootstage, bcm4377->rti_status, | |
| 840 | + rti_status); | |
| 841 | + complete(&bcm4377->event); | |
| 842 | + bcm4377->bootstage = bootstage; | |
| 843 | + bcm4377->rti_status = rti_status; | |
| 844 | + } | |
| 845 | + | |
| 846 | + if (rti_status > 2) | |
| 847 | + dev_err(&bcm4377->pdev->dev, "RTI status is %d\n", rti_status); | |
| 848 | + | |
| 849 | + bcm4377_poll_completion_ring(bcm4377, &bcm4377->control_ack_ring); | |
| 850 | + bcm4377_poll_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring); | |
| 851 | + bcm4377_poll_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring); | |
| 852 | + bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_ack_ring); | |
| 853 | + bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_event_ring); | |
| 854 | + | |
| 855 | + return IRQ_HANDLED; | |
| 856 | +} | |
| 857 | + | |
| 858 | +static int bcm4377_enqueue(struct bcm4377_data *bcm4377, | |
| 859 | + struct bcm4377_transfer_ring *ring, void *data, | |
| 860 | + size_t len, bool wait) | |
| 861 | +{ | |
| 862 | + unsigned long flags; | |
| 863 | + struct bcm4377_xfer_ring_entry *entry; | |
| 864 | + void *payload; | |
| 865 | + size_t offset; | |
| 866 | + u16 head, tail, new_head; | |
| 867 | + u16 raw_msgid; | |
| 868 | + int ret, msgid; | |
| 869 | + DECLARE_COMPLETION_ONSTACK(event); | |
| 870 | + | |
| 871 | + if (len > ring->payload_size && len > ring->mapped_payload_size) { | |
| 872 | + dev_warn( | |
| 873 | + &bcm4377->pdev->dev, | |
| 874 | + "payload len %zu is too large for ring %d (max is %zu or %zu)\n", | |
| 875 | + len, ring->ring_id, ring->payload_size, | |
| 876 | + ring->mapped_payload_size); | |
| 877 | + return -EINVAL; | |
| 878 | + } | |
| 879 | + if (wait && !ring->allow_wait) | |
| 880 | + return -EINVAL; | |
| 881 | + if (ring->virtual) | |
| 882 | + return -EINVAL; | |
| 883 | + | |
| 884 | + spin_lock_irqsave(&ring->lock, flags); | |
| 885 | + | |
| 886 | + head = le16_to_cpu(bcm4377->ring_state->xfer_ring_head[ring->ring_id]); | |
| 887 | + tail = le16_to_cpu(bcm4377->ring_state->xfer_ring_tail[ring->ring_id]); | |
| 888 | + | |
| 889 | + new_head = (head + 1) % ring->n_entries; | |
| 890 | + | |
| 891 | + if (new_head == tail) { | |
| 892 | + dev_warn(&bcm4377->pdev->dev, | |
| 893 | + "can't send message because ring %d is full\n", | |
| 894 | + ring->ring_id); | |
| 895 | + ret = -EINVAL; | |
| 896 | + goto out; | |
| 897 | + } | |
| 898 | + | |
| 899 | + msgid = bitmap_find_free_region(ring->msgids, ring->n_entries, 0); | |
| 900 | + if (msgid < 0) { | |
| 901 | + dev_warn(&bcm4377->pdev->dev, | |
| 902 | + "can't find message id for ring %d\n", ring->ring_id); | |
| 903 | + ret = -EINVAL; | |
| 904 | + goto out; | |
| 905 | + } | |
| 906 | + | |
| 907 | + raw_msgid = FIELD_PREP(BCM4377_MSGID_GENERATION, ring->generation); | |
| 908 | + raw_msgid |= FIELD_PREP(BCM4377_MSGID_ID, msgid); | |
| 909 | + | |
| 910 | + offset = head * (sizeof(*entry) + ring->payload_size); | |
| 911 | + entry = ring->ring + offset; | |
| 912 | + | |
| 913 | + memset(entry, 0, sizeof(*entry)); | |
| 914 | + entry->id = cpu_to_le16(raw_msgid); | |
| 915 | + entry->len = cpu_to_le16(len); | |
| 916 | + | |
| 917 | + if (len <= ring->payload_size) { | |
| 918 | + entry->flags = BCM4377_XFER_RING_FLAG_PAYLOAD_IN_FOOTER; | |
| 919 | + payload = ring->ring + offset + sizeof(*entry); | |
| 920 | + } else { | |
| 921 | + entry->flags = BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED; | |
| 922 | + entry->payload = cpu_to_le64(ring->payloads_dma + | |
| 923 | + msgid * ring->mapped_payload_size); | |
| 924 | + payload = ring->payloads + msgid * ring->mapped_payload_size; | |
| 925 | + } | |
| 926 | + | |
| 927 | + memcpy(payload, data, len); | |
| 928 | + | |
| 929 | + if (wait) | |
| 930 | + ring->events[msgid] = &event; | |
| 931 | + | |
| 932 | + /* | |
| 933 | + * The 4377 chips stop responding to any commands as soon as they | |
| 934 | + * have been idle for a while. Poking the sleep control register here | |
| 935 | + * makes them come alive again. | |
| 936 | + */ | |
| 937 | + iowrite32(BCM4377_BAR0_SLEEP_CONTROL_AWAKE, | |
| 938 | + bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL); | |
| 939 | + | |
| 940 | + dev_dbg(&bcm4377->pdev->dev, | |
| 941 | + "updating head for transfer queue #%d to %d\n", ring->ring_id, | |
| 942 | + new_head); | |
| 943 | + bcm4377->ring_state->xfer_ring_head[ring->ring_id] = | |
| 944 | + cpu_to_le16(new_head); | |
| 945 | + | |
| 946 | + if (!ring->sync) | |
| 947 | + bcm4377_ring_doorbell(bcm4377, ring->doorbell, new_head); | |
| 948 | + ret = 0; | |
| 949 | + | |
| 950 | +out: | |
| 951 | + spin_unlock_irqrestore(&ring->lock, flags); | |
| 952 | + | |
| 953 | + if (ret == 0 && wait) { | |
| 954 | + ret = wait_for_completion_interruptible_timeout( | |
| 955 | + &event, BCM4377_TIMEOUT); | |
| 956 | + if (ret == 0) | |
| 957 | + ret = -ETIMEDOUT; | |
| 958 | + else if (ret > 0) | |
| 959 | + ret = 0; | |
| 960 | + | |
| 961 | + spin_lock_irqsave(&ring->lock, flags); | |
| 962 | + ring->events[msgid] = NULL; | |
| 963 | + spin_unlock_irqrestore(&ring->lock, flags); | |
| 964 | + } | |
| 965 | + | |
| 966 | + return ret; | |
| 967 | +} | |
| 968 | + | |
| 969 | +static int bcm4377_create_completion_ring(struct bcm4377_data *bcm4377, | |
| 970 | + struct bcm4377_completion_ring *ring) | |
| 971 | +{ | |
| 972 | + struct bcm4377_create_completion_ring_msg msg; | |
| 973 | + int ret; | |
| 974 | + | |
| 975 | + if (ring->enabled) { | |
| 976 | + dev_warn(&bcm4377->pdev->dev, | |
| 977 | + "completion ring %d already enabled\n", ring->ring_id); | |
| 978 | + return 0; | |
| 979 | + } | |
| 980 | + | |
| 981 | + memset(ring->ring, 0, | |
| 982 | + ring->n_entries * (sizeof(struct bcm4377_completion_ring_entry) + | |
| 983 | + ring->payload_size)); | |
| 984 | + memset(&msg, 0, sizeof(msg)); | |
| 985 | + msg.msg_type = BCM4377_CONTROL_MSG_CREATE_COMPLETION_RING; | |
| 986 | + msg.id = cpu_to_le16(ring->ring_id); | |
| 987 | + msg.id_again = cpu_to_le16(ring->ring_id); | |
| 988 | + msg.ring_iova = cpu_to_le64(ring->ring_dma); | |
| 989 | + msg.n_elements = cpu_to_le16(ring->n_entries); | |
| 990 | + msg.intmod_bytes = cpu_to_le32(0xffffffff); | |
| 991 | + msg.unk = cpu_to_le32(0xffffffff); | |
| 992 | + msg.intmod_delay = cpu_to_le16(ring->delay); | |
| 993 | + msg.footer_size = ring->payload_size / 4; | |
| 994 | + | |
| 995 | + ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, | |
| 996 | + sizeof(msg), true); | |
| 997 | + if (!ret) | |
| 998 | + ring->enabled = true; | |
| 999 | + | |
| 1000 | + return ret; | |
| 1001 | +} | |
| 1002 | + | |
| 1003 | +static int bcm4377_destroy_completion_ring(struct bcm4377_data *bcm4377, | |
| 1004 | + struct bcm4377_completion_ring *ring) | |
| 1005 | +{ | |
| 1006 | + struct bcm4377_destroy_completion_ring_msg msg; | |
| 1007 | + int ret; | |
| 1008 | + | |
| 1009 | + memset(&msg, 0, sizeof(msg)); | |
| 1010 | + msg.msg_type = BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING; | |
| 1011 | + msg.ring_id = cpu_to_le16(ring->ring_id); | |
| 1012 | + | |
| 1013 | + ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, | |
| 1014 | + sizeof(msg), true); | |
| 1015 | + if (ret) | |
| 1016 | + dev_warn(&bcm4377->pdev->dev, | |
| 1017 | + "failed to destroy completion ring %d\n", | |
| 1018 | + ring->ring_id); | |
| 1019 | + | |
| 1020 | + ring->enabled = false; | |
| 1021 | + return ret; | |
| 1022 | +} | |
| 1023 | + | |
| 1024 | +static int bcm4377_create_transfer_ring(struct bcm4377_data *bcm4377, | |
| 1025 | + struct bcm4377_transfer_ring *ring) | |
| 1026 | +{ | |
| 1027 | + struct bcm4377_create_transfer_ring_msg msg; | |
| 1028 | + u16 flags = 0; | |
| 1029 | + int ret, i; | |
| 1030 | + unsigned long spinlock_flags; | |
| 1031 | + | |
| 1032 | + if (ring->virtual) | |
| 1033 | + flags |= BCM4377_XFER_RING_FLAG_VIRTUAL; | |
| 1034 | + if (ring->sync) | |
| 1035 | + flags |= BCM4377_XFER_RING_FLAG_SYNC; | |
| 1036 | + | |
| 1037 | + spin_lock_irqsave(&ring->lock, spinlock_flags); | |
| 1038 | + memset(&msg, 0, sizeof(msg)); | |
| 1039 | + msg.msg_type = BCM4377_CONTROL_MSG_CREATE_XFER_RING; | |
| 1040 | + msg.ring_id = cpu_to_le16(ring->ring_id); | |
| 1041 | + msg.ring_id_again = cpu_to_le16(ring->ring_id); | |
| 1042 | + msg.ring_iova = cpu_to_le64(ring->ring_dma); | |
| 1043 | + msg.n_elements = cpu_to_le16(ring->n_entries); | |
| 1044 | + msg.completion_ring_id = cpu_to_le16(ring->completion_ring); | |
| 1045 | + msg.doorbell = cpu_to_le16(ring->doorbell); | |
| 1046 | + msg.flags = cpu_to_le16(flags); | |
| 1047 | + msg.footer_size = ring->payload_size / 4; | |
| 1048 | + | |
| 1049 | + bcm4377->ring_state->xfer_ring_head[ring->ring_id] = 0; | |
| 1050 | + bcm4377->ring_state->xfer_ring_tail[ring->ring_id] = 0; | |
| 1051 | + ring->generation++; | |
| 1052 | + spin_unlock_irqrestore(&ring->lock, spinlock_flags); | |
| 1053 | + | |
| 1054 | + ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, | |
| 1055 | + sizeof(msg), true); | |
| 1056 | + | |
| 1057 | + spin_lock_irqsave(&ring->lock, spinlock_flags); | |
| 1058 | + | |
| 1059 | + if (ring->d2h_buffers_only) { | |
| 1060 | + for (i = 0; i < ring->n_entries; ++i) { | |
| 1061 | + struct bcm4377_xfer_ring_entry *entry = | |
| 1062 | + ring->ring + i * sizeof(*entry); | |
| 1063 | + u16 raw_msgid = FIELD_PREP(BCM4377_MSGID_GENERATION, | |
| 1064 | + ring->generation); | |
| 1065 | + raw_msgid |= FIELD_PREP(BCM4377_MSGID_ID, i); | |
| 1066 | + | |
| 1067 | + memset(entry, 0, sizeof(*entry)); | |
| 1068 | + entry->id = cpu_to_le16(raw_msgid); | |
| 1069 | + entry->len = cpu_to_le16(ring->mapped_payload_size); | |
| 1070 | + entry->flags = BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED; | |
| 1071 | + entry->payload = | |
| 1072 | + cpu_to_le64(ring->payloads_dma + | |
| 1073 | + i * ring->mapped_payload_size); | |
| 1074 | + } | |
| 1075 | + } | |
| 1076 | + | |
| 1077 | + /* | |
| 1078 | + * send some messages if this is a device->host ring to allow the device | |
| 1079 | + * to reply by acknowledging them in the completion ring | |
| 1080 | + */ | |
| 1081 | + if (ring->virtual || ring->d2h_buffers_only) { | |
| 1082 | + bcm4377->ring_state->xfer_ring_head[ring->ring_id] = | |
| 1083 | + cpu_to_le16(0xf); | |
| 1084 | + bcm4377_ring_doorbell(bcm4377, ring->doorbell, 0xf); | |
| 1085 | + } | |
| 1086 | + | |
| 1087 | + ring->enabled = true; | |
| 1088 | + spin_unlock_irqrestore(&ring->lock, spinlock_flags); | |
| 1089 | + | |
| 1090 | + return ret; | |
| 1091 | +} | |
| 1092 | + | |
| 1093 | +static int bcm4377_destroy_transfer_ring(struct bcm4377_data *bcm4377, | |
| 1094 | + struct bcm4377_transfer_ring *ring) | |
| 1095 | +{ | |
| 1096 | + struct bcm4377_destroy_transfer_ring_msg msg; | |
| 1097 | + int ret; | |
| 1098 | + | |
| 1099 | + memset(&msg, 0, sizeof(msg)); | |
| 1100 | + msg.msg_type = BCM4377_CONTROL_MSG_DESTROY_XFER_RING; | |
| 1101 | + msg.ring_id = cpu_to_le16(ring->ring_id); | |
| 1102 | + | |
| 1103 | + ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, | |
| 1104 | + sizeof(msg), true); | |
| 1105 | + if (ret) | |
| 1106 | + dev_warn(&bcm4377->pdev->dev, | |
| 1107 | + "failed to destroy transfer ring %d\n", ring->ring_id); | |
| 1108 | + | |
| 1109 | + ring->enabled = false; | |
| 1110 | + return ret; | |
| 1111 | +} | |
| 1112 | + | |
| 1113 | +static int __bcm4378_send_calibration_chunk(struct bcm4377_data *bcm4377, | |
| 1114 | + const void *data, size_t data_len, | |
| 1115 | + u16 blocks_left) | |
| 1116 | +{ | |
| 1117 | + struct bcm4378_hci_send_calibration_cmd cmd; | |
| 1118 | + struct sk_buff *skb; | |
| 1119 | + | |
| 1120 | + if (data_len > sizeof(cmd.data)) | |
| 1121 | + return -EINVAL; | |
| 1122 | + | |
| 1123 | + memset(&cmd, 0, sizeof(cmd)); | |
| 1124 | + cmd.unk = 0x03; | |
| 1125 | + cmd.blocks_left = cpu_to_le16(blocks_left); | |
| 1126 | + memcpy(cmd.data, data, data_len); | |
| 1127 | + | |
| 1128 | + skb = __hci_cmd_sync(bcm4377->hdev, 0xfd97, sizeof(cmd), &cmd, | |
| 1129 | + HCI_INIT_TIMEOUT); | |
| 1130 | + if (IS_ERR(skb)) | |
| 1131 | + return PTR_ERR(skb); | |
| 1132 | + | |
| 1133 | + kfree_skb(skb); | |
| 1134 | + return 0; | |
| 1135 | +} | |
| 1136 | + | |
| 1137 | +static int __bcm4378_send_calibration(struct bcm4377_data *bcm4377, | |
| 1138 | + const void *data, size_t data_size) | |
| 1139 | +{ | |
| 1140 | + int ret; | |
| 1141 | + size_t i, left, transfer_len; | |
| 1142 | + size_t blocks = | |
| 1143 | + DIV_ROUND_UP(data_size, (size_t)BCM4378_CALIBRATION_CHUNK_SIZE); | |
| 1144 | + | |
| 1145 | + if (!data) { | |
| 1146 | + dev_err(&bcm4377->pdev->dev, | |
| 1147 | + "no calibration data available.\n"); | |
| 1148 | + return -ENOENT; | |
| 1149 | + } | |
| 1150 | + | |
| 1151 | + for (i = 0, left = data_size; i < blocks; ++i, left -= transfer_len) { | |
| 1152 | + transfer_len = | |
| 1153 | + min_t(size_t, left, BCM4378_CALIBRATION_CHUNK_SIZE); | |
| 1154 | + | |
| 1155 | + ret = __bcm4378_send_calibration_chunk( | |
| 1156 | + bcm4377, data + i * BCM4378_CALIBRATION_CHUNK_SIZE, | |
| 1157 | + transfer_len, blocks - i - 1); | |
| 1158 | + if (ret) { | |
| 1159 | + dev_err(&bcm4377->pdev->dev, | |
| 1160 | + "send calibration chunk failed with %d\n", ret); | |
| 1161 | + return ret; | |
| 1162 | + } | |
| 1163 | + } | |
| 1164 | + | |
| 1165 | + return 0; | |
| 1166 | +} | |
| 1167 | + | |
| 1168 | +static int bcm4378_send_calibration(struct bcm4377_data *bcm4377) | |
| 1169 | +{ | |
| 1170 | + if ((strcmp(bcm4377->stepping, "b1") == 0) || | |
| 1171 | + strcmp(bcm4377->stepping, "b3") == 0) | |
| 1172 | + return __bcm4378_send_calibration( | |
| 1173 | + bcm4377, bcm4377->taurus_beamforming_cal_blob, | |
| 1174 | + bcm4377->taurus_beamforming_cal_size); | |
| 1175 | + else | |
| 1176 | + return __bcm4378_send_calibration(bcm4377, | |
| 1177 | + bcm4377->taurus_cal_blob, | |
| 1178 | + bcm4377->taurus_cal_size); | |
| 1179 | +} | |
| 1180 | + | |
| 1181 | +static int bcm4387_send_calibration(struct bcm4377_data *bcm4377) | |
| 1182 | +{ | |
| 1183 | + if (strcmp(bcm4377->stepping, "c2") == 0) | |
| 1184 | + return __bcm4378_send_calibration( | |
| 1185 | + bcm4377, bcm4377->taurus_beamforming_cal_blob, | |
| 1186 | + bcm4377->taurus_beamforming_cal_size); | |
| 1187 | + else | |
| 1188 | + return __bcm4378_send_calibration(bcm4377, | |
| 1189 | + bcm4377->taurus_cal_blob, | |
| 1190 | + bcm4377->taurus_cal_size); | |
| 1191 | +} | |
| 1192 | + | |
| 1193 | +static const struct firmware *bcm4377_request_blob(struct bcm4377_data *bcm4377, | |
| 1194 | + const char *suffix) | |
| 1195 | +{ | |
| 1196 | + const struct firmware *fw; | |
| 1197 | + char name0[64], name1[64]; | |
| 1198 | + int ret; | |
| 1199 | + | |
| 1200 | + snprintf(name0, sizeof(name0), "brcm/brcmbt%04x%s-%s-%s.%s", | |
| 1201 | + bcm4377->hw->id, bcm4377->stepping, bcm4377->board_type, | |
| 1202 | + bcm4377->vendor, suffix); | |
| 1203 | + snprintf(name1, sizeof(name1), "brcm/brcmbt%04x%s-%s.%s", | |
| 1204 | + bcm4377->hw->id, bcm4377->stepping, bcm4377->board_type, | |
| 1205 | + suffix); | |
| 1206 | + dev_dbg(&bcm4377->pdev->dev, "Trying to load firmware: '%s' or '%s'\n", | |
| 1207 | + name0, name1); | |
| 1208 | + | |
| 1209 | + ret = firmware_request_nowarn(&fw, name0, &bcm4377->pdev->dev); | |
| 1210 | + if (!ret) | |
| 1211 | + return fw; | |
| 1212 | + ret = firmware_request_nowarn(&fw, name1, &bcm4377->pdev->dev); | |
| 1213 | + if (!ret) | |
| 1214 | + return fw; | |
| 1215 | + | |
| 1216 | + dev_err(&bcm4377->pdev->dev, | |
| 1217 | + "Unable to load firmware; tried '%s' and '%s'\n", name0, name1); | |
| 1218 | + return NULL; | |
| 1219 | +} | |
| 1220 | + | |
| 1221 | +static int bcm4377_send_ptb(struct bcm4377_data *bcm4377, | |
| 1222 | + const struct firmware *fw) | |
| 1223 | +{ | |
| 1224 | + struct sk_buff *skb; | |
| 1225 | + | |
| 1226 | + skb = __hci_cmd_sync(bcm4377->hdev, 0xfd98, fw->size, fw->data, | |
| 1227 | + HCI_INIT_TIMEOUT); | |
| 1228 | + /* | |
| 1229 | + * This command seems to always fail on more recent firmware versions | |
| 1230 | + * (even in traces taken from the macOS driver). It's unclear why this | |
| 1231 | + * happens but because the PTB file contains calibration and/or | |
| 1232 | + * regulatory data and may be required on older firmware we still try to | |
| 1233 | + * send it here just in case and just ignore if it fails. | |
| 1234 | + */ | |
| 1235 | + if (!IS_ERR(skb)) | |
| 1236 | + kfree_skb(skb); | |
| 1237 | + return 0; | |
| 1238 | +} | |
| 1239 | + | |
| 1240 | +static int bcm4378_send_ptb_chunk(struct bcm4377_data *bcm4377, | |
| 1241 | + const void *data, size_t data_len, | |
| 1242 | + u16 blocks_left) | |
| 1243 | +{ | |
| 1244 | + struct bcm4378_hci_send_ptb_cmd cmd; | |
| 1245 | + struct sk_buff *skb; | |
| 1246 | + | |
| 1247 | + if (data_len > BCM4378_PTB_CHUNK_SIZE) | |
| 1248 | + return -EINVAL; | |
| 1249 | + | |
| 1250 | + memset(&cmd, 0, sizeof(cmd)); | |
| 1251 | + cmd.blocks_left = cpu_to_le16(blocks_left); | |
| 1252 | + memcpy(cmd.data, data, data_len); | |
| 1253 | + | |
| 1254 | + skb = __hci_cmd_sync(bcm4377->hdev, 0xfe0d, sizeof(cmd), &cmd, | |
| 1255 | + HCI_INIT_TIMEOUT); | |
| 1256 | + if (IS_ERR(skb)) | |
| 1257 | + return PTR_ERR(skb); | |
| 1258 | + | |
| 1259 | + kfree_skb(skb); | |
| 1260 | + return 0; | |
| 1261 | +} | |
| 1262 | + | |
| 1263 | +static int bcm4378_send_ptb(struct bcm4377_data *bcm4377, | |
| 1264 | + const struct firmware *fw) | |
| 1265 | +{ | |
| 1266 | + size_t chunks = DIV_ROUND_UP(fw->size, (size_t)BCM4378_PTB_CHUNK_SIZE); | |
| 1267 | + size_t i, left, transfer_len; | |
| 1268 | + int ret; | |
| 1269 | + | |
| 1270 | + for (i = 0, left = fw->size; i < chunks; ++i, left -= transfer_len) { | |
| 1271 | + transfer_len = min_t(size_t, left, BCM4378_PTB_CHUNK_SIZE); | |
| 1272 | + | |
| 1273 | + dev_dbg(&bcm4377->pdev->dev, "sending ptb chunk %zu/%zu\n", | |
| 1274 | + i + 1, chunks); | |
| 1275 | + ret = bcm4378_send_ptb_chunk( | |
| 1276 | + bcm4377, fw->data + i * BCM4378_PTB_CHUNK_SIZE, | |
| 1277 | + transfer_len, chunks - i - 1); | |
| 1278 | + if (ret) { | |
| 1279 | + dev_err(&bcm4377->pdev->dev, | |
| 1280 | + "sending ptb chunk %zu failed (%d)", i, ret); | |
| 1281 | + return ret; | |
| 1282 | + } | |
| 1283 | + } | |
| 1284 | + | |
| 1285 | + return 0; | |
| 1286 | +} | |
| 1287 | + | |
| 1288 | +static int bcm4377_hci_open(struct hci_dev *hdev) | |
| 1289 | +{ | |
| 1290 | + struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); | |
| 1291 | + int ret; | |
| 1292 | + | |
| 1293 | + dev_dbg(&bcm4377->pdev->dev, "creating rings\n"); | |
| 1294 | + | |
| 1295 | + ret = bcm4377_create_completion_ring(bcm4377, | |
| 1296 | + &bcm4377->hci_acl_ack_ring); | |
| 1297 | + if (ret) | |
| 1298 | + return ret; | |
| 1299 | + ret = bcm4377_create_completion_ring(bcm4377, | |
| 1300 | + &bcm4377->hci_acl_event_ring); | |
| 1301 | + if (ret) | |
| 1302 | + goto destroy_hci_acl_ack; | |
| 1303 | + ret = bcm4377_create_completion_ring(bcm4377, &bcm4377->sco_ack_ring); | |
| 1304 | + if (ret) | |
| 1305 | + goto destroy_hci_acl_event; | |
| 1306 | + ret = bcm4377_create_completion_ring(bcm4377, &bcm4377->sco_event_ring); | |
| 1307 | + if (ret) | |
| 1308 | + goto destroy_sco_ack; | |
| 1309 | + dev_dbg(&bcm4377->pdev->dev, | |
| 1310 | + "all completion rings successfully created!\n"); | |
| 1311 | + | |
| 1312 | + ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); | |
| 1313 | + if (ret) | |
| 1314 | + goto destroy_sco_event; | |
| 1315 | + ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); | |
| 1316 | + if (ret) | |
| 1317 | + goto destroy_hci_h2d; | |
| 1318 | + ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); | |
| 1319 | + if (ret) | |
| 1320 | + goto destroy_hci_d2h; | |
| 1321 | + ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); | |
| 1322 | + if (ret) | |
| 1323 | + goto destroy_sco_h2d; | |
| 1324 | + ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); | |
| 1325 | + if (ret) | |
| 1326 | + goto destroy_sco_d2h; | |
| 1327 | + ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->acl_d2h_ring); | |
| 1328 | + if (ret) | |
| 1329 | + goto destroy_acl_h2d; | |
| 1330 | + dev_dbg(&bcm4377->pdev->dev, | |
| 1331 | + "all transfer rings successfully created!\n"); | |
| 1332 | + | |
| 1333 | + return 0; | |
| 1334 | + | |
| 1335 | +destroy_acl_h2d: | |
| 1336 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); | |
| 1337 | +destroy_sco_d2h: | |
| 1338 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); | |
| 1339 | +destroy_sco_h2d: | |
| 1340 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); | |
| 1341 | +destroy_hci_d2h: | |
| 1342 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); | |
| 1343 | +destroy_hci_h2d: | |
| 1344 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); | |
| 1345 | +destroy_sco_event: | |
| 1346 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_event_ring); | |
| 1347 | +destroy_sco_ack: | |
| 1348 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_ack_ring); | |
| 1349 | +destroy_hci_acl_event: | |
| 1350 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring); | |
| 1351 | +destroy_hci_acl_ack: | |
| 1352 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring); | |
| 1353 | + | |
| 1354 | + dev_err(&bcm4377->pdev->dev, "Creating rings failed with %d\n", ret); | |
| 1355 | + return ret; | |
| 1356 | +} | |
| 1357 | + | |
| 1358 | +static int bcm4377_hci_close(struct hci_dev *hdev) | |
| 1359 | +{ | |
| 1360 | + struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); | |
| 1361 | + | |
| 1362 | + dev_dbg(&bcm4377->pdev->dev, "destroying rings in hci_close\n"); | |
| 1363 | + | |
| 1364 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->acl_d2h_ring); | |
| 1365 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); | |
| 1366 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); | |
| 1367 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); | |
| 1368 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); | |
| 1369 | + bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); | |
| 1370 | + | |
| 1371 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_event_ring); | |
| 1372 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_ack_ring); | |
| 1373 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring); | |
| 1374 | + bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring); | |
| 1375 | + | |
| 1376 | + return 0; | |
| 1377 | +} | |
| 1378 | + | |
| 1379 | +static bool bcm4377_is_valid_bdaddr(struct bcm4377_data *bcm4377, | |
| 1380 | + bdaddr_t *addr) | |
| 1381 | +{ | |
| 1382 | + if (addr->b[0] != 0x93) | |
| 1383 | + return true; | |
| 1384 | + if (addr->b[1] != 0x76) | |
| 1385 | + return true; | |
| 1386 | + if (addr->b[2] != 0x00) | |
| 1387 | + return true; | |
| 1388 | + if (addr->b[4] != (bcm4377->hw->id & 0xff)) | |
| 1389 | + return true; | |
| 1390 | + if (addr->b[5] != (bcm4377->hw->id >> 8)) | |
| 1391 | + return true; | |
| 1392 | + return false; | |
| 1393 | +} | |
| 1394 | + | |
| 1395 | +static int bcm4377_check_bdaddr(struct bcm4377_data *bcm4377) | |
| 1396 | +{ | |
| 1397 | + struct hci_rp_read_bd_addr *bda; | |
| 1398 | + struct sk_buff *skb; | |
| 1399 | + | |
| 1400 | + skb = __hci_cmd_sync(bcm4377->hdev, HCI_OP_READ_BD_ADDR, 0, NULL, | |
| 1401 | + HCI_INIT_TIMEOUT); | |
| 1402 | + if (IS_ERR(skb)) { | |
| 1403 | + int err = PTR_ERR(skb); | |
| 1404 | + | |
| 1405 | + dev_err(&bcm4377->pdev->dev, "HCI_OP_READ_BD_ADDR failed (%d)", | |
| 1406 | + err); | |
| 1407 | + return err; | |
| 1408 | + } | |
| 1409 | + | |
| 1410 | + if (skb->len != sizeof(*bda)) { | |
| 1411 | + dev_err(&bcm4377->pdev->dev, | |
| 1412 | + "HCI_OP_READ_BD_ADDR reply length invalid"); | |
| 1413 | + kfree_skb(skb); | |
| 1414 | + return -EIO; | |
| 1415 | + } | |
| 1416 | + | |
| 1417 | + bda = (struct hci_rp_read_bd_addr *)skb->data; | |
| 1418 | + if (!bcm4377_is_valid_bdaddr(bcm4377, &bda->bdaddr)) | |
| 1419 | + set_bit(HCI_QUIRK_INVALID_BDADDR, &bcm4377->hdev->quirks); | |
| 1420 | + | |
| 1421 | + kfree_skb(skb); | |
| 1422 | + return 0; | |
| 1423 | +} | |
| 1424 | + | |
| 1425 | +static int bcm4377_hci_setup(struct hci_dev *hdev) | |
| 1426 | +{ | |
| 1427 | + struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); | |
| 1428 | + const struct firmware *fw; | |
| 1429 | + int ret; | |
| 1430 | + | |
| 1431 | + if (bcm4377->hw->send_calibration) { | |
| 1432 | + ret = bcm4377->hw->send_calibration(bcm4377); | |
| 1433 | + if (ret) | |
| 1434 | + return ret; | |
| 1435 | + } | |
| 1436 | + | |
| 1437 | + fw = bcm4377_request_blob(bcm4377, "ptb"); | |
| 1438 | + if (!fw) { | |
| 1439 | + dev_err(&bcm4377->pdev->dev, "failed to load PTB data"); | |
| 1440 | + return -ENOENT; | |
| 1441 | + } | |
| 1442 | + | |
| 1443 | + ret = bcm4377->hw->send_ptb(bcm4377, fw); | |
| 1444 | + release_firmware(fw); | |
| 1445 | + if (ret) | |
| 1446 | + return ret; | |
| 1447 | + | |
| 1448 | + return bcm4377_check_bdaddr(bcm4377); | |
| 1449 | +} | |
| 1450 | + | |
| 1451 | +static int bcm4377_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | |
| 1452 | +{ | |
| 1453 | + struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); | |
| 1454 | + struct bcm4377_transfer_ring *ring; | |
| 1455 | + int ret; | |
| 1456 | + | |
| 1457 | + switch (hci_skb_pkt_type(skb)) { | |
| 1458 | + case HCI_COMMAND_PKT: | |
| 1459 | + hdev->stat.cmd_tx++; | |
| 1460 | + ring = &bcm4377->hci_h2d_ring; | |
| 1461 | + break; | |
| 1462 | + | |
| 1463 | + case HCI_ACLDATA_PKT: | |
| 1464 | + hdev->stat.acl_tx++; | |
| 1465 | + ring = &bcm4377->acl_h2d_ring; | |
| 1466 | + break; | |
| 1467 | + | |
| 1468 | + case HCI_SCODATA_PKT: | |
| 1469 | + hdev->stat.sco_tx++; | |
| 1470 | + ring = &bcm4377->sco_h2d_ring; | |
| 1471 | + break; | |
| 1472 | + | |
| 1473 | + default: | |
| 1474 | + return -EILSEQ; | |
| 1475 | + } | |
| 1476 | + | |
| 1477 | + ret = bcm4377_enqueue(bcm4377, ring, skb->data, skb->len, false); | |
| 1478 | + if (ret < 0) { | |
| 1479 | + hdev->stat.err_tx++; | |
| 1480 | + return ret; | |
| 1481 | + } | |
| 1482 | + | |
| 1483 | + hdev->stat.byte_tx += skb->len; | |
| 1484 | + kfree_skb(skb); | |
| 1485 | + return ret; | |
| 1486 | +} | |
| 1487 | + | |
| 1488 | +static int bcm4377_hci_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) | |
| 1489 | +{ | |
| 1490 | + struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); | |
| 1491 | + struct sk_buff *skb; | |
| 1492 | + int err; | |
| 1493 | + | |
| 1494 | + skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); | |
| 1495 | + if (IS_ERR(skb)) { | |
| 1496 | + err = PTR_ERR(skb); | |
| 1497 | + dev_err(&bcm4377->pdev->dev, | |
| 1498 | + "Change address command failed (%d)", err); | |
| 1499 | + return err; | |
| 1500 | + } | |
| 1501 | + kfree_skb(skb); | |
| 1502 | + | |
| 1503 | + return 0; | |
| 1504 | +} | |
| 1505 | + | |
| 1506 | +static int bcm4377_alloc_transfer_ring(struct bcm4377_data *bcm4377, | |
| 1507 | + struct bcm4377_transfer_ring *ring) | |
| 1508 | +{ | |
| 1509 | + size_t entry_size; | |
| 1510 | + | |
| 1511 | + spin_lock_init(&ring->lock); | |
| 1512 | + ring->payload_size = ALIGN(ring->payload_size, 4); | |
| 1513 | + ring->mapped_payload_size = ALIGN(ring->mapped_payload_size, 4); | |
| 1514 | + | |
| 1515 | + if (ring->payload_size > BCM4377_XFER_RING_MAX_INPLACE_PAYLOAD_SIZE) | |
| 1516 | + return -EINVAL; | |
| 1517 | + if (ring->n_entries > BCM4377_MAX_RING_SIZE) | |
| 1518 | + return -EINVAL; | |
| 1519 | + if (ring->virtual && ring->allow_wait) | |
| 1520 | + return -EINVAL; | |
| 1521 | + | |
| 1522 | + if (ring->d2h_buffers_only) { | |
| 1523 | + if (ring->virtual) | |
| 1524 | + return -EINVAL; | |
| 1525 | + if (ring->payload_size) | |
| 1526 | + return -EINVAL; | |
| 1527 | + if (!ring->mapped_payload_size) | |
| 1528 | + return -EINVAL; | |
| 1529 | + } | |
| 1530 | + if (ring->virtual) | |
| 1531 | + return 0; | |
| 1532 | + | |
| 1533 | + entry_size = | |
| 1534 | + ring->payload_size + sizeof(struct bcm4377_xfer_ring_entry); | |
| 1535 | + ring->ring = dmam_alloc_coherent(&bcm4377->pdev->dev, | |
| 1536 | + ring->n_entries * entry_size, | |
| 1537 | + &ring->ring_dma, GFP_KERNEL); | |
| 1538 | + if (!ring->ring) | |
| 1539 | + return -ENOMEM; | |
| 1540 | + | |
| 1541 | + if (ring->allow_wait) { | |
| 1542 | + ring->events = devm_kcalloc(&bcm4377->pdev->dev, | |
| 1543 | + ring->n_entries, | |
| 1544 | + sizeof(*ring->events), GFP_KERNEL); | |
| 1545 | + if (!ring->events) | |
| 1546 | + return -ENOMEM; | |
| 1547 | + } | |
| 1548 | + | |
| 1549 | + if (ring->mapped_payload_size) { | |
| 1550 | + ring->payloads = dmam_alloc_coherent( | |
| 1551 | + &bcm4377->pdev->dev, | |
| 1552 | + ring->n_entries * ring->mapped_payload_size, | |
| 1553 | + &ring->payloads_dma, GFP_KERNEL); | |
| 1554 | + if (!ring->payloads) | |
| 1555 | + return -ENOMEM; | |
| 1556 | + } | |
| 1557 | + | |
| 1558 | + return 0; | |
| 1559 | +} | |
| 1560 | + | |
| 1561 | +static int bcm4377_alloc_completion_ring(struct bcm4377_data *bcm4377, | |
| 1562 | + struct bcm4377_completion_ring *ring) | |
| 1563 | +{ | |
| 1564 | + size_t entry_size; | |
| 1565 | + | |
| 1566 | + ring->payload_size = ALIGN(ring->payload_size, 4); | |
| 1567 | + if (ring->payload_size > BCM4377_XFER_RING_MAX_INPLACE_PAYLOAD_SIZE) | |
| 1568 | + return -EINVAL; | |
| 1569 | + if (ring->n_entries > BCM4377_MAX_RING_SIZE) | |
| 1570 | + return -EINVAL; | |
| 1571 | + | |
| 1572 | + entry_size = ring->payload_size + | |
| 1573 | + sizeof(struct bcm4377_completion_ring_entry); | |
| 1574 | + | |
| 1575 | + ring->ring = dmam_alloc_coherent(&bcm4377->pdev->dev, | |
| 1576 | + ring->n_entries * entry_size, | |
| 1577 | + &ring->ring_dma, GFP_KERNEL); | |
| 1578 | + if (!ring->ring) | |
| 1579 | + return -ENOMEM; | |
| 1580 | + return 0; | |
| 1581 | +} | |
| 1582 | + | |
| 1583 | +static int bcm4377_init_context(struct bcm4377_data *bcm4377) | |
| 1584 | +{ | |
| 1585 | + struct device *dev = &bcm4377->pdev->dev; | |
| 1586 | + dma_addr_t peripheral_info_dma; | |
| 1587 | + | |
| 1588 | + bcm4377->ctx = dmam_alloc_coherent(dev, sizeof(*bcm4377->ctx), | |
| 1589 | + &bcm4377->ctx_dma, GFP_KERNEL); | |
| 1590 | + if (!bcm4377->ctx) | |
| 1591 | + return -ENOMEM; | |
| 1592 | + memset(bcm4377->ctx, 0, sizeof(*bcm4377->ctx)); | |
| 1593 | + | |
| 1594 | + bcm4377->ring_state = | |
| 1595 | + dmam_alloc_coherent(dev, sizeof(*bcm4377->ring_state), | |
| 1596 | + &bcm4377->ring_state_dma, GFP_KERNEL); | |
| 1597 | + if (!bcm4377->ring_state) | |
| 1598 | + return -ENOMEM; | |
| 1599 | + memset(bcm4377->ring_state, 0, sizeof(*bcm4377->ring_state)); | |
| 1600 | + | |
| 1601 | + bcm4377->ctx->version = cpu_to_le16(1); | |
| 1602 | + bcm4377->ctx->size = cpu_to_le16(sizeof(*bcm4377->ctx)); | |
| 1603 | + bcm4377->ctx->enabled_caps = cpu_to_le32(2); | |
| 1604 | + | |
| 1605 | + /* | |
| 1606 | + * The BT device will write 0x20 bytes of data to this buffer but | |
| 1607 | + * the exact contents are unknown. It only needs to exist for BT | |
| 1608 | + * to work such that we can just allocate and then ignore it. | |
| 1609 | + */ | |
| 1610 | + if (!dmam_alloc_coherent(&bcm4377->pdev->dev, 0x20, | |
| 1611 | + &peripheral_info_dma, GFP_KERNEL)) | |
| 1612 | + return -ENOMEM; | |
| 1613 | + bcm4377->ctx->peripheral_info_addr = cpu_to_le64(peripheral_info_dma); | |
| 1614 | + | |
| 1615 | + bcm4377->ctx->xfer_ring_heads_addr = cpu_to_le64( | |
| 1616 | + bcm4377->ring_state_dma + | |
| 1617 | + offsetof(struct bcm4377_ring_state, xfer_ring_head)); | |
| 1618 | + bcm4377->ctx->xfer_ring_tails_addr = cpu_to_le64( | |
| 1619 | + bcm4377->ring_state_dma + | |
| 1620 | + offsetof(struct bcm4377_ring_state, xfer_ring_tail)); | |
| 1621 | + bcm4377->ctx->completion_ring_heads_addr = cpu_to_le64( | |
| 1622 | + bcm4377->ring_state_dma + | |
| 1623 | + offsetof(struct bcm4377_ring_state, completion_ring_head)); | |
| 1624 | + bcm4377->ctx->completion_ring_tails_addr = cpu_to_le64( | |
| 1625 | + bcm4377->ring_state_dma + | |
| 1626 | + offsetof(struct bcm4377_ring_state, completion_ring_tail)); | |
| 1627 | + | |
| 1628 | + bcm4377->ctx->n_completion_rings = | |
| 1629 | + cpu_to_le16(BCM4377_N_COMPLETION_RINGS); | |
| 1630 | + bcm4377->ctx->n_xfer_rings = cpu_to_le16(BCM4377_N_TRANSFER_RINGS); | |
| 1631 | + | |
| 1632 | + bcm4377->ctx->control_completion_ring_addr = | |
| 1633 | + cpu_to_le64(bcm4377->control_ack_ring.ring_dma); | |
| 1634 | + bcm4377->ctx->control_completion_ring_n_entries = | |
| 1635 | + cpu_to_le16(bcm4377->control_ack_ring.n_entries); | |
| 1636 | + bcm4377->ctx->control_completion_ring_doorbell = cpu_to_le16(0xffff); | |
| 1637 | + bcm4377->ctx->control_completion_ring_msi = 0; | |
| 1638 | + bcm4377->ctx->control_completion_ring_header_size = 0; | |
| 1639 | + bcm4377->ctx->control_completion_ring_footer_size = 0; | |
| 1640 | + | |
| 1641 | + bcm4377->ctx->control_xfer_ring_addr = | |
| 1642 | + cpu_to_le64(bcm4377->control_h2d_ring.ring_dma); | |
| 1643 | + bcm4377->ctx->control_xfer_ring_n_entries = | |
| 1644 | + cpu_to_le16(bcm4377->control_h2d_ring.n_entries); | |
| 1645 | + bcm4377->ctx->control_xfer_ring_doorbell = | |
| 1646 | + cpu_to_le16(bcm4377->control_h2d_ring.doorbell); | |
| 1647 | + bcm4377->ctx->control_xfer_ring_msi = 0; | |
| 1648 | + bcm4377->ctx->control_xfer_ring_header_size = 0; | |
| 1649 | + bcm4377->ctx->control_xfer_ring_footer_size = | |
| 1650 | + bcm4377->control_h2d_ring.payload_size / 4; | |
| 1651 | + | |
| 1652 | + dev_dbg(&bcm4377->pdev->dev, "context initialized at IOVA %pad", | |
| 1653 | + &bcm4377->ctx_dma); | |
| 1654 | + | |
| 1655 | + return 0; | |
| 1656 | +} | |
| 1657 | + | |
| 1658 | +static int bcm4377_prepare_rings(struct bcm4377_data *bcm4377) | |
| 1659 | +{ | |
| 1660 | + int ret; | |
| 1661 | + | |
| 1662 | + /* | |
| 1663 | + * Even though many of these settings appear to be configurable | |
| 1664 | + * when sending the "create ring" messages most of these are | |
| 1665 | + * actually hardcoded in some (and quite possibly all) firmware versions | |
| 1666 | + * and changing them on the host has no effect. | |
| 1667 | + * Specifically, this applies to at least the doorbells, the transfer | |
| 1668 | + * and completion ring ids and their mapping (e.g. both HCI and ACL | |
| 1669 | + * entries will always be queued in completion rings 1 and 2 no matter | |
| 1670 | + * what we configure here). | |
| 1671 | + */ | |
| 1672 | + bcm4377->control_ack_ring.ring_id = BCM4377_ACK_RING_CONTROL; | |
| 1673 | + bcm4377->control_ack_ring.n_entries = 32; | |
| 1674 | + bcm4377->control_ack_ring.transfer_rings = | |
| 1675 | + BIT(BCM4377_XFER_RING_CONTROL); | |
| 1676 | + | |
| 1677 | + bcm4377->hci_acl_ack_ring.ring_id = BCM4377_ACK_RING_HCI_ACL; | |
| 1678 | + bcm4377->hci_acl_ack_ring.n_entries = 2 * BCM4377_RING_N_ENTRIES; | |
| 1679 | + bcm4377->hci_acl_ack_ring.transfer_rings = | |
| 1680 | + BIT(BCM4377_XFER_RING_HCI_H2D) | BIT(BCM4377_XFER_RING_ACL_H2D); | |
| 1681 | + bcm4377->hci_acl_ack_ring.delay = 1000; | |
| 1682 | + | |
| 1683 | + /* | |
| 1684 | + * A payload size of MAX_EVENT_PAYLOAD_SIZE is enough here since large | |
| 1685 | + * ACL packets will be transmitted inside buffers mapped via | |
| 1686 | + * acl_d2h_ring anyway. | |
| 1687 | + */ | |
| 1688 | + bcm4377->hci_acl_event_ring.ring_id = BCM4377_EVENT_RING_HCI_ACL; | |
| 1689 | + bcm4377->hci_acl_event_ring.payload_size = MAX_EVENT_PAYLOAD_SIZE; | |
| 1690 | + bcm4377->hci_acl_event_ring.n_entries = 2 * BCM4377_RING_N_ENTRIES; | |
| 1691 | + bcm4377->hci_acl_event_ring.transfer_rings = | |
| 1692 | + BIT(BCM4377_XFER_RING_HCI_D2H) | BIT(BCM4377_XFER_RING_ACL_D2H); | |
| 1693 | + bcm4377->hci_acl_event_ring.delay = 1000; | |
| 1694 | + | |
| 1695 | + bcm4377->sco_ack_ring.ring_id = BCM4377_ACK_RING_SCO; | |
| 1696 | + bcm4377->sco_ack_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1697 | + bcm4377->sco_ack_ring.transfer_rings = BIT(BCM4377_XFER_RING_SCO_H2D); | |
| 1698 | + | |
| 1699 | + bcm4377->sco_event_ring.ring_id = BCM4377_EVENT_RING_SCO; | |
| 1700 | + bcm4377->sco_event_ring.payload_size = MAX_SCO_PAYLOAD_SIZE; | |
| 1701 | + bcm4377->sco_event_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1702 | + bcm4377->sco_event_ring.transfer_rings = BIT(BCM4377_XFER_RING_SCO_D2H); | |
| 1703 | + | |
| 1704 | + bcm4377->control_h2d_ring.ring_id = BCM4377_XFER_RING_CONTROL; | |
| 1705 | + bcm4377->control_h2d_ring.doorbell = BCM4377_DOORBELL_CONTROL; | |
| 1706 | + bcm4377->control_h2d_ring.payload_size = BCM4377_CONTROL_MSG_SIZE; | |
| 1707 | + bcm4377->control_h2d_ring.completion_ring = BCM4377_ACK_RING_CONTROL; | |
| 1708 | + bcm4377->control_h2d_ring.allow_wait = true; | |
| 1709 | + bcm4377->control_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1710 | + | |
| 1711 | + bcm4377->hci_h2d_ring.ring_id = BCM4377_XFER_RING_HCI_H2D; | |
| 1712 | + bcm4377->hci_h2d_ring.doorbell = BCM4377_DOORBELL_HCI_H2D; | |
| 1713 | + bcm4377->hci_h2d_ring.payload_size = MAX_EVENT_PAYLOAD_SIZE; | |
| 1714 | + bcm4377->hci_h2d_ring.completion_ring = BCM4377_ACK_RING_HCI_ACL; | |
| 1715 | + bcm4377->hci_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1716 | + | |
| 1717 | + bcm4377->hci_d2h_ring.ring_id = BCM4377_XFER_RING_HCI_D2H; | |
| 1718 | + bcm4377->hci_d2h_ring.doorbell = BCM4377_DOORBELL_HCI_D2H; | |
| 1719 | + bcm4377->hci_d2h_ring.completion_ring = BCM4377_EVENT_RING_HCI_ACL; | |
| 1720 | + bcm4377->hci_d2h_ring.virtual = true; | |
| 1721 | + bcm4377->hci_d2h_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1722 | + | |
| 1723 | + bcm4377->sco_h2d_ring.ring_id = BCM4377_XFER_RING_SCO_H2D; | |
| 1724 | + bcm4377->sco_h2d_ring.doorbell = BCM4377_DOORBELL_SCO; | |
| 1725 | + bcm4377->sco_h2d_ring.payload_size = MAX_SCO_PAYLOAD_SIZE; | |
| 1726 | + bcm4377->sco_h2d_ring.completion_ring = BCM4377_ACK_RING_SCO; | |
| 1727 | + bcm4377->sco_h2d_ring.sync = true; | |
| 1728 | + bcm4377->sco_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1729 | + | |
| 1730 | + bcm4377->sco_d2h_ring.ring_id = BCM4377_XFER_RING_SCO_D2H; | |
| 1731 | + bcm4377->sco_d2h_ring.doorbell = BCM4377_DOORBELL_SCO; | |
| 1732 | + bcm4377->sco_d2h_ring.completion_ring = BCM4377_EVENT_RING_SCO; | |
| 1733 | + bcm4377->sco_d2h_ring.virtual = true; | |
| 1734 | + bcm4377->sco_d2h_ring.sync = true; | |
| 1735 | + bcm4377->sco_d2h_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1736 | + | |
| 1737 | + /* | |
| 1738 | + * This ring has to use mapped_payload_size because the largest ACL | |
| 1739 | + * packet doesn't fit inside the largest possible footer | |
| 1740 | + */ | |
| 1741 | + bcm4377->acl_h2d_ring.ring_id = BCM4377_XFER_RING_ACL_H2D; | |
| 1742 | + bcm4377->acl_h2d_ring.doorbell = BCM4377_DOORBELL_ACL_H2D; | |
| 1743 | + bcm4377->acl_h2d_ring.mapped_payload_size = MAX_ACL_PAYLOAD_SIZE; | |
| 1744 | + bcm4377->acl_h2d_ring.completion_ring = BCM4377_ACK_RING_HCI_ACL; | |
| 1745 | + bcm4377->acl_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1746 | + | |
| 1747 | + /* | |
| 1748 | + * This ring only contains empty buffers to be used by incoming | |
| 1749 | + * ACL packets that do not fit inside the footer of hci_acl_event_ring | |
| 1750 | + */ | |
| 1751 | + bcm4377->acl_d2h_ring.ring_id = BCM4377_XFER_RING_ACL_D2H; | |
| 1752 | + bcm4377->acl_d2h_ring.doorbell = BCM4377_DOORBELL_ACL_D2H; | |
| 1753 | + bcm4377->acl_d2h_ring.completion_ring = BCM4377_EVENT_RING_HCI_ACL; | |
| 1754 | + bcm4377->acl_d2h_ring.d2h_buffers_only = true; | |
| 1755 | + bcm4377->acl_d2h_ring.mapped_payload_size = MAX_ACL_PAYLOAD_SIZE; | |
| 1756 | + bcm4377->acl_d2h_ring.n_entries = BCM4377_RING_N_ENTRIES; | |
| 1757 | + | |
| 1758 | + /* | |
| 1759 | + * no need for any cleanup since this is only called from _probe | |
| 1760 | + * and only devres-managed allocations are used | |
| 1761 | + */ | |
| 1762 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->control_h2d_ring); | |
| 1763 | + if (ret) | |
| 1764 | + return ret; | |
| 1765 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); | |
| 1766 | + if (ret) | |
| 1767 | + return ret; | |
| 1768 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); | |
| 1769 | + if (ret) | |
| 1770 | + return ret; | |
| 1771 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); | |
| 1772 | + if (ret) | |
| 1773 | + return ret; | |
| 1774 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); | |
| 1775 | + if (ret) | |
| 1776 | + return ret; | |
| 1777 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); | |
| 1778 | + if (ret) | |
| 1779 | + return ret; | |
| 1780 | + ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->acl_d2h_ring); | |
| 1781 | + if (ret) | |
| 1782 | + return ret; | |
| 1783 | + | |
| 1784 | + ret = bcm4377_alloc_completion_ring(bcm4377, | |
| 1785 | + &bcm4377->control_ack_ring); | |
| 1786 | + if (ret) | |
| 1787 | + return ret; | |
| 1788 | + ret = bcm4377_alloc_completion_ring(bcm4377, | |
| 1789 | + &bcm4377->hci_acl_ack_ring); | |
| 1790 | + if (ret) | |
| 1791 | + return ret; | |
| 1792 | + ret = bcm4377_alloc_completion_ring(bcm4377, | |
| 1793 | + &bcm4377->hci_acl_event_ring); | |
| 1794 | + if (ret) | |
| 1795 | + return ret; | |
| 1796 | + ret = bcm4377_alloc_completion_ring(bcm4377, &bcm4377->sco_ack_ring); | |
| 1797 | + if (ret) | |
| 1798 | + return ret; | |
| 1799 | + ret = bcm4377_alloc_completion_ring(bcm4377, &bcm4377->sco_event_ring); | |
| 1800 | + if (ret) | |
| 1801 | + return ret; | |
| 1802 | + | |
| 1803 | + dev_dbg(&bcm4377->pdev->dev, "all rings allocated and prepared\n"); | |
| 1804 | + | |
| 1805 | + return 0; | |
| 1806 | +} | |
| 1807 | + | |
| 1808 | +static int bcm4377_boot(struct bcm4377_data *bcm4377) | |
| 1809 | +{ | |
| 1810 | + const struct firmware *fw; | |
| 1811 | + void *bfr; | |
| 1812 | + dma_addr_t fw_dma; | |
| 1813 | + int ret = 0; | |
| 1814 | + u32 bootstage, rti_status; | |
| 1815 | + | |
| 1816 | + bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE); | |
| 1817 | + rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS); | |
| 1818 | + | |
| 1819 | + if (bootstage != 0) { | |
| 1820 | + dev_err(&bcm4377->pdev->dev, "bootstage is %d and not 0\n", | |
| 1821 | + bootstage); | |
| 1822 | + return -EINVAL; | |
| 1823 | + } | |
| 1824 | + | |
| 1825 | + if (rti_status != 0) { | |
| 1826 | + dev_err(&bcm4377->pdev->dev, "RTI status is %d and not 0\n", | |
| 1827 | + rti_status); | |
| 1828 | + return -EINVAL; | |
| 1829 | + } | |
| 1830 | + | |
| 1831 | + fw = bcm4377_request_blob(bcm4377, "bin"); | |
| 1832 | + if (!fw) { | |
| 1833 | + dev_err(&bcm4377->pdev->dev, "Failed to load firmware\n"); | |
| 1834 | + return -ENOENT; | |
| 1835 | + } | |
| 1836 | + | |
| 1837 | + bfr = dma_alloc_coherent(&bcm4377->pdev->dev, fw->size, &fw_dma, | |
| 1838 | + GFP_KERNEL); | |
| 1839 | + if (!bfr) { | |
| 1840 | + ret = -ENOMEM; | |
| 1841 | + goto out_release_fw; | |
| 1842 | + } | |
| 1843 | + | |
| 1844 | + memcpy(bfr, fw->data, fw->size); | |
| 1845 | + | |
| 1846 | + iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_LO); | |
| 1847 | + iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_HI); | |
| 1848 | + iowrite32(BCM4377_DMA_MASK, | |
| 1849 | + bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_SIZE); | |
| 1850 | + | |
| 1851 | + iowrite32(lower_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_LO); | |
| 1852 | + iowrite32(upper_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_HI); | |
| 1853 | + iowrite32(fw->size, bcm4377->bar2 + BCM4377_BAR2_FW_SIZE); | |
| 1854 | + iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_FW_DOORBELL); | |
| 1855 | + | |
| 1856 | + dev_dbg(&bcm4377->pdev->dev, "waiting for firmware to boot\n"); | |
| 1857 | + | |
| 1858 | + ret = wait_for_completion_interruptible_timeout(&bcm4377->event, | |
| 1859 | + BCM4377_TIMEOUT); | |
| 1860 | + if (ret == 0) { | |
| 1861 | + ret = -ETIMEDOUT; | |
| 1862 | + goto out_dma_free; | |
| 1863 | + } else if (ret < 0) { | |
| 1864 | + goto out_dma_free; | |
| 1865 | + } | |
| 1866 | + | |
| 1867 | + if (bcm4377->bootstage != 2) { | |
| 1868 | + dev_err(&bcm4377->pdev->dev, "boostage %d != 2\n", | |
| 1869 | + bcm4377->bootstage); | |
| 1870 | + ret = -ENXIO; | |
| 1871 | + goto out_dma_free; | |
| 1872 | + } | |
| 1873 | + | |
| 1874 | + dev_dbg(&bcm4377->pdev->dev, "firmware has booted (stage = %x)\n", | |
| 1875 | + bcm4377->bootstage); | |
| 1876 | + ret = 0; | |
| 1877 | + | |
| 1878 | +out_dma_free: | |
| 1879 | + dma_free_coherent(&bcm4377->pdev->dev, fw->size, bfr, fw_dma); | |
| 1880 | +out_release_fw: | |
| 1881 | + release_firmware(fw); | |
| 1882 | + return ret; | |
| 1883 | +} | |
| 1884 | + | |
| 1885 | +static int bcm4377_setup_rti(struct bcm4377_data *bcm4377) | |
| 1886 | +{ | |
| 1887 | + int ret; | |
| 1888 | + | |
| 1889 | + dev_dbg(&bcm4377->pdev->dev, "starting RTI\n"); | |
| 1890 | + iowrite32(1, bcm4377->bar0 + BCM4377_BAR0_RTI_CONTROL); | |
| 1891 | + | |
| 1892 | + ret = wait_for_completion_interruptible_timeout(&bcm4377->event, | |
| 1893 | + BCM4377_TIMEOUT); | |
| 1894 | + if (ret == 0) { | |
| 1895 | + dev_err(&bcm4377->pdev->dev, | |
| 1896 | + "timed out while waiting for RTI to transition to state 1"); | |
| 1897 | + return -ETIMEDOUT; | |
| 1898 | + } else if (ret < 0) { | |
| 1899 | + return ret; | |
| 1900 | + } | |
| 1901 | + | |
| 1902 | + if (bcm4377->rti_status != 1) { | |
| 1903 | + dev_err(&bcm4377->pdev->dev, "RTI did not ack state 1 (%d)\n", | |
| 1904 | + bcm4377->rti_status); | |
| 1905 | + return -ENODEV; | |
| 1906 | + } | |
| 1907 | + dev_dbg(&bcm4377->pdev->dev, "RTI is in state 1\n"); | |
| 1908 | + | |
| 1909 | + /* allow access to the entire IOVA space again */ | |
| 1910 | + iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_LO); | |
| 1911 | + iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_HI); | |
| 1912 | + iowrite32(BCM4377_DMA_MASK, | |
| 1913 | + bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_SIZE); | |
| 1914 | + | |
| 1915 | + /* setup "Converged IPC" context */ | |
| 1916 | + iowrite32(lower_32_bits(bcm4377->ctx_dma), | |
| 1917 | + bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_LO); | |
| 1918 | + iowrite32(upper_32_bits(bcm4377->ctx_dma), | |
| 1919 | + bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_HI); | |
| 1920 | + iowrite32(2, bcm4377->bar0 + BCM4377_BAR0_RTI_CONTROL); | |
| 1921 | + | |
| 1922 | + ret = wait_for_completion_interruptible_timeout(&bcm4377->event, | |
| 1923 | + BCM4377_TIMEOUT); | |
| 1924 | + if (ret == 0) { | |
| 1925 | + dev_err(&bcm4377->pdev->dev, | |
| 1926 | + "timed out while waiting for RTI to transition to state 2"); | |
| 1927 | + return -ETIMEDOUT; | |
| 1928 | + } else if (ret < 0) { | |
| 1929 | + return ret; | |
| 1930 | + } | |
| 1931 | + | |
| 1932 | + if (bcm4377->rti_status != 2) { | |
| 1933 | + dev_err(&bcm4377->pdev->dev, "RTI did not ack state 2 (%d)\n", | |
| 1934 | + bcm4377->rti_status); | |
| 1935 | + return -ENODEV; | |
| 1936 | + } | |
| 1937 | + | |
| 1938 | + dev_dbg(&bcm4377->pdev->dev, | |
| 1939 | + "RTI is in state 2; control ring is ready\n"); | |
| 1940 | + bcm4377->control_ack_ring.enabled = true; | |
| 1941 | + | |
| 1942 | + return 0; | |
| 1943 | +} | |
| 1944 | + | |
| 1945 | +static int bcm4377_parse_otp_board_params(struct bcm4377_data *bcm4377, | |
| 1946 | + char tag, const char *val, size_t len) | |
| 1947 | +{ | |
| 1948 | + if (tag != 'V') | |
| 1949 | + return 0; | |
| 1950 | + if (len >= sizeof(bcm4377->vendor)) | |
| 1951 | + return -EINVAL; | |
| 1952 | + | |
| 1953 | + strscpy(bcm4377->vendor, val, len + 1); | |
| 1954 | + return 0; | |
| 1955 | +} | |
| 1956 | + | |
| 1957 | +static int bcm4377_parse_otp_chip_params(struct bcm4377_data *bcm4377, char tag, | |
| 1958 | + const char *val, size_t len) | |
| 1959 | +{ | |
| 1960 | + size_t idx = 0; | |
| 1961 | + | |
| 1962 | + if (tag != 's') | |
| 1963 | + return 0; | |
| 1964 | + if (len >= sizeof(bcm4377->stepping)) | |
| 1965 | + return -EINVAL; | |
| 1966 | + | |
| 1967 | + while (len != 0) { | |
| 1968 | + bcm4377->stepping[idx] = tolower(val[idx]); | |
| 1969 | + if (val[idx] == '\0') | |
| 1970 | + return 0; | |
| 1971 | + | |
| 1972 | + idx++; | |
| 1973 | + len--; | |
| 1974 | + } | |
| 1975 | + | |
| 1976 | + bcm4377->stepping[idx] = '\0'; | |
| 1977 | + return 0; | |
| 1978 | +} | |
| 1979 | + | |
| 1980 | +static int bcm4377_parse_otp_str(struct bcm4377_data *bcm4377, const u8 *str, | |
| 1981 | + enum bcm4377_otp_params_type type) | |
| 1982 | +{ | |
| 1983 | + const char *p; | |
| 1984 | + int ret; | |
| 1985 | + | |
| 1986 | + p = skip_spaces(str); | |
| 1987 | + while (*p) { | |
| 1988 | + char tag = *p++; | |
| 1989 | + const char *end; | |
| 1990 | + size_t len; | |
| 1991 | + | |
| 1992 | + if (*p++ != '=') /* implicit NUL check */ | |
| 1993 | + return -EINVAL; | |
| 1994 | + | |
| 1995 | + /* *p might be NUL here, if so end == p and len == 0 */ | |
| 1996 | + end = strchrnul(p, ' '); | |
| 1997 | + len = end - p; | |
| 1998 | + | |
| 1999 | + /* leave 1 byte for NUL in destination string */ | |
| 2000 | + if (len > (BCM4377_OTP_MAX_PARAM_LEN - 1)) | |
| 2001 | + return -EINVAL; | |
| 2002 | + | |
| 2003 | + switch (type) { | |
| 2004 | + case BCM4377_OTP_BOARD_PARAMS: | |
| 2005 | + ret = bcm4377_parse_otp_board_params(bcm4377, tag, p, | |
| 2006 | + len); | |
| 2007 | + break; | |
| 2008 | + case BCM4377_OTP_CHIP_PARAMS: | |
| 2009 | + ret = bcm4377_parse_otp_chip_params(bcm4377, tag, p, | |
| 2010 | + len); | |
| 2011 | + break; | |
| 2012 | + default: | |
| 2013 | + ret = -EINVAL; | |
| 2014 | + break; | |
| 2015 | + } | |
| 2016 | + | |
| 2017 | + if (ret) | |
| 2018 | + return ret; | |
| 2019 | + | |
| 2020 | + /* Skip to next arg, if any */ | |
| 2021 | + p = skip_spaces(end); | |
| 2022 | + } | |
| 2023 | + | |
| 2024 | + return 0; | |
| 2025 | +} | |
| 2026 | + | |
| 2027 | +static int bcm4377_parse_otp_sys_vendor(struct bcm4377_data *bcm4377, u8 *otp, | |
| 2028 | + size_t size) | |
| 2029 | +{ | |
| 2030 | + int idx = 4; | |
| 2031 | + const char *chip_params; | |
| 2032 | + const char *board_params; | |
| 2033 | + int ret; | |
| 2034 | + | |
| 2035 | + /* 4-byte header and two empty strings */ | |
| 2036 | + if (size < 6) | |
| 2037 | + return -EINVAL; | |
| 2038 | + | |
| 2039 | + if (get_unaligned_le32(otp) != BCM4377_OTP_VENDOR_HDR) | |
| 2040 | + return -EINVAL; | |
| 2041 | + | |
| 2042 | + chip_params = &otp[idx]; | |
| 2043 | + | |
| 2044 | + /* Skip first string, including terminator */ | |
| 2045 | + idx += strnlen(chip_params, size - idx) + 1; | |
| 2046 | + if (idx >= size) | |
| 2047 | + return -EINVAL; | |
| 2048 | + | |
| 2049 | + board_params = &otp[idx]; | |
| 2050 | + | |
| 2051 | + /* Skip to terminator of second string */ | |
| 2052 | + idx += strnlen(board_params, size - idx); | |
| 2053 | + if (idx >= size) | |
| 2054 | + return -EINVAL; | |
| 2055 | + | |
| 2056 | + /* At this point both strings are guaranteed NUL-terminated */ | |
| 2057 | + dev_dbg(&bcm4377->pdev->dev, | |
| 2058 | + "OTP: chip_params='%s' board_params='%s'\n", chip_params, | |
| 2059 | + board_params); | |
| 2060 | + | |
| 2061 | + ret = bcm4377_parse_otp_str(bcm4377, chip_params, | |
| 2062 | + BCM4377_OTP_CHIP_PARAMS); | |
| 2063 | + if (ret) | |
| 2064 | + return ret; | |
| 2065 | + | |
| 2066 | + ret = bcm4377_parse_otp_str(bcm4377, board_params, | |
| 2067 | + BCM4377_OTP_BOARD_PARAMS); | |
| 2068 | + if (ret) | |
| 2069 | + return ret; | |
| 2070 | + | |
| 2071 | + if (!bcm4377->stepping[0] || !bcm4377->vendor[0]) | |
| 2072 | + return -EINVAL; | |
| 2073 | + | |
| 2074 | + dev_dbg(&bcm4377->pdev->dev, "OTP: stepping=%s, vendor=%s\n", | |
| 2075 | + bcm4377->stepping, bcm4377->vendor); | |
| 2076 | + return 0; | |
| 2077 | +} | |
| 2078 | + | |
| 2079 | +static int bcm4377_parse_otp(struct bcm4377_data *bcm4377) | |
| 2080 | +{ | |
| 2081 | + u8 *otp; | |
| 2082 | + int i; | |
| 2083 | + int ret = -ENOENT; | |
| 2084 | + | |
| 2085 | + otp = kzalloc(BCM4377_OTP_SIZE, GFP_KERNEL); | |
| 2086 | + if (!otp) | |
| 2087 | + return -ENOMEM; | |
| 2088 | + | |
| 2089 | + for (i = 0; i < BCM4377_OTP_SIZE; ++i) | |
| 2090 | + otp[i] = ioread8(bcm4377->bar0 + bcm4377->hw->otp_offset + i); | |
| 2091 | + | |
| 2092 | + i = 0; | |
| 2093 | + while (i < (BCM4377_OTP_SIZE - 1)) { | |
| 2094 | + u8 type = otp[i]; | |
| 2095 | + u8 length = otp[i + 1]; | |
| 2096 | + | |
| 2097 | + if (type == 0) | |
| 2098 | + break; | |
| 2099 | + | |
| 2100 | + if ((i + 2 + length) > BCM4377_OTP_SIZE) | |
| 2101 | + break; | |
| 2102 | + | |
| 2103 | + switch (type) { | |
| 2104 | + case BCM4377_OTP_SYS_VENDOR: | |
| 2105 | + dev_dbg(&bcm4377->pdev->dev, | |
| 2106 | + "OTP @ 0x%x (%d): SYS_VENDOR", i, length); | |
| 2107 | + ret = bcm4377_parse_otp_sys_vendor(bcm4377, &otp[i + 2], | |
| 2108 | + length); | |
| 2109 | + break; | |
| 2110 | + case BCM4377_OTP_CIS: | |
| 2111 | + dev_dbg(&bcm4377->pdev->dev, "OTP @ 0x%x (%d): CIS", i, | |
| 2112 | + length); | |
| 2113 | + break; | |
| 2114 | + default: | |
| 2115 | + dev_dbg(&bcm4377->pdev->dev, "OTP @ 0x%x (%d): unknown", | |
| 2116 | + i, length); | |
| 2117 | + break; | |
| 2118 | + } | |
| 2119 | + | |
| 2120 | + i += 2 + length; | |
| 2121 | + } | |
| 2122 | + | |
| 2123 | + kfree(otp); | |
| 2124 | + return ret; | |
| 2125 | +} | |
| 2126 | + | |
| 2127 | +static int bcm4377_init_cfg(struct bcm4377_data *bcm4377) | |
| 2128 | +{ | |
| 2129 | + int ret; | |
| 2130 | + u32 ctrl; | |
| 2131 | + | |
| 2132 | + ret = pci_write_config_dword(bcm4377->pdev, | |
| 2133 | + BCM4377_PCIECFG_BAR0_WINDOW1, | |
| 2134 | + bcm4377->hw->bar0_window1); | |
| 2135 | + if (ret) | |
| 2136 | + return ret; | |
| 2137 | + | |
| 2138 | + ret = pci_write_config_dword(bcm4377->pdev, | |
| 2139 | + BCM4377_PCIECFG_BAR0_WINDOW2, | |
| 2140 | + bcm4377->hw->bar0_window2); | |
| 2141 | + if (ret) | |
| 2142 | + return ret; | |
| 2143 | + | |
| 2144 | + ret = pci_write_config_dword( | |
| 2145 | + bcm4377->pdev, BCM4377_PCIECFG_BAR0_CORE2_WINDOW1, | |
| 2146 | + BCM4377_PCIECFG_BAR0_CORE2_WINDOW1_DEFAULT); | |
| 2147 | + if (ret) | |
| 2148 | + return ret; | |
| 2149 | + | |
| 2150 | + if (bcm4377->hw->has_bar0_core2_window2) { | |
| 2151 | + ret = pci_write_config_dword(bcm4377->pdev, | |
| 2152 | + BCM4377_PCIECFG_BAR0_CORE2_WINDOW2, | |
| 2153 | + bcm4377->hw->bar0_core2_window2); | |
| 2154 | + if (ret) | |
| 2155 | + return ret; | |
| 2156 | + } | |
| 2157 | + | |
| 2158 | + ret = pci_write_config_dword(bcm4377->pdev, BCM4377_PCIECFG_BAR2_WINDOW, | |
| 2159 | + BCM4377_PCIECFG_BAR2_WINDOW_DEFAULT); | |
| 2160 | + if (ret) | |
| 2161 | + return ret; | |
| 2162 | + | |
| 2163 | + ret = pci_read_config_dword(bcm4377->pdev, | |
| 2164 | + BCM4377_PCIECFG_SUBSYSTEM_CTRL, &ctrl); | |
| 2165 | + if (ret) | |
| 2166 | + return ret; | |
| 2167 | + | |
| 2168 | + if (bcm4377->hw->clear_pciecfg_subsystem_ctrl_bit19) | |
| 2169 | + ctrl &= ~BIT(19); | |
| 2170 | + ctrl |= BIT(16); | |
| 2171 | + | |
| 2172 | + return pci_write_config_dword(bcm4377->pdev, | |
| 2173 | + BCM4377_PCIECFG_SUBSYSTEM_CTRL, ctrl); | |
| 2174 | +} | |
| 2175 | + | |
| 2176 | +static int bcm4377_probe_dmi(struct bcm4377_data *bcm4377) | |
| 2177 | +{ | |
| 2178 | + const struct dmi_system_id *board_type_dmi_id; | |
| 2179 | + | |
| 2180 | + board_type_dmi_id = dmi_first_match(bcm4377_dmi_board_table); | |
| 2181 | + if (board_type_dmi_id && board_type_dmi_id->driver_data) { | |
| 2182 | + bcm4377->board_type = board_type_dmi_id->driver_data; | |
| 2183 | + dev_dbg(&bcm4377->pdev->dev, | |
| 2184 | + "found board type via DMI match: %s\n", | |
| 2185 | + bcm4377->board_type); | |
| 2186 | + } | |
| 2187 | + | |
| 2188 | + return 0; | |
| 2189 | +} | |
| 2190 | + | |
| 2191 | +static int bcm4377_probe_of(struct bcm4377_data *bcm4377) | |
| 2192 | +{ | |
| 2193 | + struct device_node *np = bcm4377->pdev->dev.of_node; | |
| 2194 | + int ret; | |
| 2195 | + | |
| 2196 | + if (!np) | |
| 2197 | + return 0; | |
| 2198 | + | |
| 2199 | + ret = of_property_read_string(np, "brcm,board-type", | |
| 2200 | + &bcm4377->board_type); | |
| 2201 | + if (ret) { | |
| 2202 | + dev_err(&bcm4377->pdev->dev, "no brcm,board-type property\n"); | |
| 2203 | + return ret; | |
| 2204 | + } | |
| 2205 | + | |
| 2206 | + bcm4377->taurus_beamforming_cal_blob = | |
| 2207 | + of_get_property(np, "brcm,taurus-bf-cal-blob", | |
| 2208 | + &bcm4377->taurus_beamforming_cal_size); | |
| 2209 | + if (!bcm4377->taurus_beamforming_cal_blob) { | |
| 2210 | + dev_err(&bcm4377->pdev->dev, | |
| 2211 | + "no brcm,taurus-bf-cal-blob property\n"); | |
| 2212 | + return -ENOENT; | |
| 2213 | + } | |
| 2214 | + bcm4377->taurus_cal_blob = of_get_property(np, "brcm,taurus-cal-blob", | |
| 2215 | + &bcm4377->taurus_cal_size); | |
| 2216 | + if (!bcm4377->taurus_cal_blob) { | |
| 2217 | + dev_err(&bcm4377->pdev->dev, | |
| 2218 | + "no brcm,taurus-cal-blob property\n"); | |
| 2219 | + return -ENOENT; | |
| 2220 | + } | |
| 2221 | + | |
| 2222 | + return 0; | |
| 2223 | +} | |
| 2224 | + | |
| 2225 | +static void bcm4377_disable_aspm(struct bcm4377_data *bcm4377) | |
| 2226 | +{ | |
| 2227 | + pci_disable_link_state(bcm4377->pdev, | |
| 2228 | + PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); | |
| 2229 | + | |
| 2230 | + /* | |
| 2231 | + * pci_disable_link_state can fail if either CONFIG_PCIEASPM is disabled | |
| 2232 | + * or if the BIOS hasn't handed over control to us. We must *always* | |
| 2233 | + * disable ASPM for this device due to hardware errata though. | |
| 2234 | + */ | |
| 2235 | + pcie_capability_clear_word(bcm4377->pdev, PCI_EXP_LNKCTL, | |
| 2236 | + PCI_EXP_LNKCTL_ASPMC); | |
| 2237 | +} | |
| 2238 | + | |
| 2239 | +static void bcm4377_pci_free_irq_vectors(void *data) | |
| 2240 | +{ | |
| 2241 | + pci_free_irq_vectors(data); | |
| 2242 | +} | |
| 2243 | + | |
| 2244 | +static void bcm4377_hci_free_dev(void *data) | |
| 2245 | +{ | |
| 2246 | + hci_free_dev(data); | |
| 2247 | +} | |
| 2248 | + | |
| 2249 | +static void bcm4377_hci_unregister_dev(void *data) | |
| 2250 | +{ | |
| 2251 | + hci_unregister_dev(data); | |
| 2252 | +} | |
| 2253 | + | |
| 2254 | +static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |
| 2255 | +{ | |
| 2256 | + struct bcm4377_data *bcm4377; | |
| 2257 | + struct hci_dev *hdev; | |
| 2258 | + int ret, irq; | |
| 2259 | + | |
| 2260 | + ret = dma_set_mask_and_coherent(&pdev->dev, BCM4377_DMA_MASK); | |
| 2261 | + if (ret) | |
| 2262 | + return ret; | |
| 2263 | + | |
| 2264 | + bcm4377 = devm_kzalloc(&pdev->dev, sizeof(*bcm4377), GFP_KERNEL); | |
| 2265 | + if (!bcm4377) | |
| 2266 | + return -ENOMEM; | |
| 2267 | + | |
| 2268 | + bcm4377->pdev = pdev; | |
| 2269 | + bcm4377->hw = &bcm4377_hw_variants[id->driver_data]; | |
| 2270 | + init_completion(&bcm4377->event); | |
| 2271 | + | |
| 2272 | + ret = bcm4377_prepare_rings(bcm4377); | |
| 2273 | + if (ret) | |
| 2274 | + return ret; | |
| 2275 | + | |
| 2276 | + ret = bcm4377_init_context(bcm4377); | |
| 2277 | + if (ret) | |
| 2278 | + return ret; | |
| 2279 | + | |
| 2280 | + ret = bcm4377_probe_dmi(bcm4377); | |
| 2281 | + if (ret) | |
| 2282 | + return ret; | |
| 2283 | + ret = bcm4377_probe_of(bcm4377); | |
| 2284 | + if (ret) | |
| 2285 | + return ret; | |
| 2286 | + if (!bcm4377->board_type) { | |
| 2287 | + dev_err(&pdev->dev, "unable to determine board type\n"); | |
| 2288 | + return -ENODEV; | |
| 2289 | + } | |
| 2290 | + | |
| 2291 | + if (bcm4377->hw->disable_aspm) | |
| 2292 | + bcm4377_disable_aspm(bcm4377); | |
| 2293 | + | |
| 2294 | + ret = pci_reset_function_locked(pdev); | |
| 2295 | + if (ret) | |
| 2296 | + dev_warn( | |
| 2297 | + &pdev->dev, | |
| 2298 | + "function level reset failed with %d; trying to continue anyway\n", | |
| 2299 | + ret); | |
| 2300 | + | |
| 2301 | + /* | |
| 2302 | + * If this number is too low and we try to access any BAR too | |
| 2303 | + * early the device will crash. Experiments have shown that | |
| 2304 | + * approximately 50 msec is the minimum amount we have to wait. | |
| 2305 | + * Let's double that to be safe. | |
| 2306 | + */ | |
| 2307 | + msleep(100); | |
| 2308 | + | |
| 2309 | + ret = pcim_enable_device(pdev); | |
| 2310 | + if (ret) | |
| 2311 | + return ret; | |
| 2312 | + pci_set_master(pdev); | |
| 2313 | + | |
| 2314 | + ret = bcm4377_init_cfg(bcm4377); | |
| 2315 | + if (ret) | |
| 2316 | + return ret; | |
| 2317 | + | |
| 2318 | + bcm4377->bar0 = pcim_iomap(pdev, 0, 0); | |
| 2319 | + if (!bcm4377->bar0) | |
| 2320 | + return -EBUSY; | |
| 2321 | + bcm4377->bar2 = pcim_iomap(pdev, 2, 0); | |
| 2322 | + if (!bcm4377->bar2) | |
| 2323 | + return -EBUSY; | |
| 2324 | + | |
| 2325 | + ret = bcm4377_parse_otp(bcm4377); | |
| 2326 | + if (ret) { | |
| 2327 | + dev_err(&pdev->dev, "Reading OTP failed with %d\n", ret); | |
| 2328 | + return ret; | |
| 2329 | + } | |
| 2330 | + | |
| 2331 | + /* | |
| 2332 | + * Legacy interrupts result in an IRQ storm because we don't know where | |
| 2333 | + * the interrupt mask and status registers for these chips are. | |
| 2334 | + * MSIs are acked automatically instead. | |
| 2335 | + */ | |
| 2336 | + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); | |
| 2337 | + if (ret < 0) | |
| 2338 | + return -ENODEV; | |
| 2339 | + ret = devm_add_action_or_reset(&pdev->dev, bcm4377_pci_free_irq_vectors, | |
| 2340 | + pdev); | |
| 2341 | + if (ret) | |
| 2342 | + return ret; | |
| 2343 | + | |
| 2344 | + irq = pci_irq_vector(pdev, 0); | |
| 2345 | + if (irq <= 0) | |
| 2346 | + return -ENODEV; | |
| 2347 | + | |
| 2348 | + ret = devm_request_irq(&pdev->dev, irq, bcm4377_irq, 0, "bcm4377", | |
| 2349 | + bcm4377); | |
| 2350 | + if (ret) | |
| 2351 | + return ret; | |
| 2352 | + | |
| 2353 | + hdev = hci_alloc_dev(); | |
| 2354 | + if (!hdev) | |
| 2355 | + return -ENOMEM; | |
| 2356 | + ret = devm_add_action_or_reset(&pdev->dev, bcm4377_hci_free_dev, hdev); | |
| 2357 | + if (ret) | |
| 2358 | + return ret; | |
| 2359 | + | |
| 2360 | + bcm4377->hdev = hdev; | |
| 2361 | + | |
| 2362 | + hdev->bus = HCI_PCI; | |
| 2363 | + hdev->dev_type = HCI_PRIMARY; | |
| 2364 | + hdev->open = bcm4377_hci_open; | |
| 2365 | + hdev->close = bcm4377_hci_close; | |
| 2366 | + hdev->send = bcm4377_hci_send_frame; | |
| 2367 | + hdev->set_bdaddr = bcm4377_hci_set_bdaddr; | |
| 2368 | + hdev->setup = bcm4377_hci_setup; | |
| 2369 | + | |
| 2370 | + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); | |
| 2371 | + if (bcm4377->hw->broken_mws_transport_config) | |
| 2372 | + set_bit(HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG, &hdev->quirks); | |
| 2373 | + if (bcm4377->hw->broken_ext_scan) | |
| 2374 | + set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks); | |
| 2375 | + | |
| 2376 | + pci_set_drvdata(pdev, bcm4377); | |
| 2377 | + hci_set_drvdata(hdev, bcm4377); | |
| 2378 | + SET_HCIDEV_DEV(hdev, &pdev->dev); | |
| 2379 | + | |
| 2380 | + ret = bcm4377_boot(bcm4377); | |
| 2381 | + if (ret) | |
| 2382 | + return ret; | |
| 2383 | + | |
| 2384 | + ret = bcm4377_setup_rti(bcm4377); | |
| 2385 | + if (ret) | |
| 2386 | + return ret; | |
| 2387 | + | |
| 2388 | + ret = hci_register_dev(hdev); | |
| 2389 | + if (ret) | |
| 2390 | + return ret; | |
| 2391 | + return devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev, | |
| 2392 | + hdev); | |
| 2393 | +} | |
| 2394 | + | |
| 2395 | +static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state) | |
| 2396 | +{ | |
| 2397 | + struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev); | |
| 2398 | + int ret; | |
| 2399 | + | |
| 2400 | + ret = hci_suspend_dev(bcm4377->hdev); | |
| 2401 | + if (ret) | |
| 2402 | + return ret; | |
| 2403 | + | |
| 2404 | + iowrite32(BCM4377_BAR0_SLEEP_CONTROL_QUIESCE, | |
| 2405 | + bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL); | |
| 2406 | + | |
| 2407 | + return 0; | |
| 2408 | +} | |
| 2409 | + | |
| 2410 | +static int bcm4377_resume(struct pci_dev *pdev) | |
| 2411 | +{ | |
| 2412 | + struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev); | |
| 2413 | + | |
| 2414 | + iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE, | |
| 2415 | + bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL); | |
| 2416 | + | |
| 2417 | + return hci_resume_dev(bcm4377->hdev); | |
| 2418 | +} | |
| 2419 | + | |
| 2420 | +static const struct dmi_system_id bcm4377_dmi_board_table[] = { | |
| 2421 | + { | |
| 2422 | + .matches = { | |
| 2423 | + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), | |
| 2424 | + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"), | |
| 2425 | + }, | |
| 2426 | + .driver_data = "apple,formosa", | |
| 2427 | + }, | |
| 2428 | + { | |
| 2429 | + .matches = { | |
| 2430 | + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), | |
| 2431 | + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,4"), | |
| 2432 | + }, | |
| 2433 | + .driver_data = "apple,formosa", | |
| 2434 | + }, | |
| 2435 | + { | |
| 2436 | + .matches = { | |
| 2437 | + DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), | |
| 2438 | + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,3"), | |
| 2439 | + }, | |
| 2440 | + .driver_data = "apple,formosa", | |
| 2441 | + }, | |
| 2442 | + {} | |
| 2443 | +}; | |
| 2444 | + | |
| 2445 | +static const struct bcm4377_hw bcm4377_hw_variants[] = { | |
| 2446 | + [BCM4377] = { | |
| 2447 | + .id = 0x4377, | |
| 2448 | + .otp_offset = 0x4120, | |
| 2449 | + .bar0_window1 = 0x1800b000, | |
| 2450 | + .bar0_window2 = 0x1810c000, | |
| 2451 | + .disable_aspm = true, | |
| 2452 | + .broken_ext_scan = true, | |
| 2453 | + .send_ptb = bcm4377_send_ptb, | |
| 2454 | + }, | |
| 2455 | + | |
| 2456 | + [BCM4378] = { | |
| 2457 | + .id = 0x4378, | |
| 2458 | + .otp_offset = 0x4120, | |
| 2459 | + .bar0_window1 = 0x18002000, | |
| 2460 | + .bar0_window2 = 0x1810a000, | |
| 2461 | + .bar0_core2_window2 = 0x18107000, | |
| 2462 | + .has_bar0_core2_window2 = true, | |
| 2463 | + .broken_mws_transport_config = true, | |
| 2464 | + .send_calibration = bcm4378_send_calibration, | |
| 2465 | + .send_ptb = bcm4378_send_ptb, | |
| 2466 | + }, | |
| 2467 | + | |
| 2468 | + [BCM4387] = { | |
| 2469 | + .id = 0x4387, | |
| 2470 | + .otp_offset = 0x413c, | |
| 2471 | + .bar0_window1 = 0x18002000, | |
| 2472 | + .bar0_window2 = 0x18109000, | |
| 2473 | + .bar0_core2_window2 = 0x18106000, | |
| 2474 | + .has_bar0_core2_window2 = true, | |
| 2475 | + .clear_pciecfg_subsystem_ctrl_bit19 = true, | |
| 2476 | + .broken_mws_transport_config = true, | |
| 2477 | + .send_calibration = bcm4387_send_calibration, | |
| 2478 | + .send_ptb = bcm4378_send_ptb, | |
| 2479 | + }, | |
| 2480 | +}; | |
| 2481 | + | |
| 2482 | +#define BCM4377_DEVID_ENTRY(id) \ | |
| 2483 | + { \ | |
| 2484 | + PCI_VENDOR_ID_BROADCOM, BCM##id##_DEVICE_ID, PCI_ANY_ID, \ | |
| 2485 | + PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \ | |
| 2486 | + BCM##id \ | |
| 2487 | + } | |
| 2488 | + | |
| 2489 | +static const struct pci_device_id bcm4377_devid_table[] = { | |
| 2490 | + BCM4377_DEVID_ENTRY(4377), | |
| 2491 | + BCM4377_DEVID_ENTRY(4378), | |
| 2492 | + BCM4377_DEVID_ENTRY(4387), | |
| 2493 | + {}, | |
| 2494 | +}; | |
| 2495 | +MODULE_DEVICE_TABLE(pci, bcm4377_devid_table); | |
| 2496 | + | |
| 2497 | +static struct pci_driver bcm4377_pci_driver = { | |
| 2498 | + .name = "hci_bcm4377", | |
| 2499 | + .id_table = bcm4377_devid_table, | |
| 2500 | + .probe = bcm4377_probe, | |
| 2501 | + .suspend = bcm4377_suspend, | |
| 2502 | + .resume = bcm4377_resume, | |
| 2503 | +}; | |
| 2504 | +module_pci_driver(bcm4377_pci_driver); | |
| 2505 | + | |
| 2506 | +MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); | |
| 2507 | +MODULE_DESCRIPTION("Bluetooth support for Broadcom 4377/4378/4387 devices"); | |
| 2508 | +MODULE_LICENSE("Dual MIT/GPL"); | |
| 2509 | +MODULE_FIRMWARE("brcm/brcmbt4377*.bin"); | |
| 2510 | +MODULE_FIRMWARE("brcm/brcmbt4377*.ptb"); | |
| 2511 | +MODULE_FIRMWARE("brcm/brcmbt4378*.bin"); | |
| 2512 | +MODULE_FIRMWARE("brcm/brcmbt4378*.ptb"); | |
| 2513 | +MODULE_FIRMWARE("brcm/brcmbt4387*.bin"); | |
| 2514 | +MODULE_FIRMWARE("brcm/brcmbt4387*.ptb"); | |
| @@ -378,7 +378,7 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) · 377 unmodified lines | ||
| 378 | 378 | i++; |
| 379 | 379 | |
| 380 | 380 | __skb_unlink(skb, &bcsp->unack); |
| 381 | − kfree_skb(skb); | |
| 381 | + dev_kfree_skb_irq(skb); | |
| 382 | 382 | } |
| 383 | 383 | |
| 384 | 384 | if (skb_queue_empty(&bcsp->unack)) |
| @@ -313,7 +313,7 @@ static void h5_pkt_cull(struct h5 *h5) · 312 unmodified lines | ||
| 313 | 313 | break; |
| 314 | 314 | |
| 315 | 315 | __skb_unlink(skb, &h5->unack); |
| 316 | − kfree_skb(skb); | |
| 316 | + dev_kfree_skb_irq(skb); | |
| 317 | 317 | } |
| 318 | 318 | |
| 319 | 319 | if (skb_queue_empty(&h5->unack)) |
| @@ -345,7 +345,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb) · 344 unmodified lines | ||
| 345 | 345 | default: |
| 346 | 346 | BT_ERR("illegal hcill state: %ld (losing packet)", |
| 347 | 347 | ll->hcill_state); |
| 348 | − kfree_skb(skb); | |
| 348 | + dev_kfree_skb_irq(skb); | |
| 349 | 349 | break; |
| 350 | 350 | } |
| 351 | 351 | |
| @@ -918,7 +918,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) · 917 unmodified lines | ||
| 918 | 918 | default: |
| 919 | 919 | BT_ERR("Illegal tx state: %d (losing packet)", |
| 920 | 920 | qca->tx_ibs_state); |
| 921 | − kfree_skb(skb); | |
| 921 | + dev_kfree_skb_irq(skb); | |
| 922 | 922 | break; |
| 923 | 923 | } |
| 924 | 924 | |
| @@ -1771,7 +1771,8 @@ retry: · 846 unmodified lines | ||
| 1771 | 1771 | qca_debugfs_init(hdev); |
| 1772 | 1772 | hu->hdev->hw_error = qca_hw_error; |
| 1773 | 1773 | hu->hdev->cmd_timeout = qca_cmd_timeout; |
| 1774 | − hu->hdev->wakeup = qca_wakeup; | |
| 1774 | + if (device_can_wakeup(hu->serdev->ctrl->dev.parent)) | |
| 1775 | + hu->hdev->wakeup = qca_wakeup; | |
| 1775 | 1776 | } else if (ret == -ENOENT) { |
| 1776 | 1777 | /* No patch/nvm-config found, run with original fw/config */ |
| 1777 | 1778 | set_bit(QCA_ROM_FW, &qca->flags); |
| @@ -50,8 +50,11 @@ static int virtbt_add_inbuf(struct virtio_bluetooth *vbt) · 49 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | static int virtbt_open(struct hci_dev *hdev) |
| 52 | 52 | { |
| 53 | − struct virtio_bluetooth *vbt = hci_get_drvdata(hdev); | |
| 53 | + return 0; | |
| 54 | +} | |
| 54 | 55 | |
| 56 | +static int virtbt_open_vdev(struct virtio_bluetooth *vbt) | |
| 57 | +{ | |
| 55 | 58 | if (virtbt_add_inbuf(vbt) < 0) |
| 56 | 59 | return -EIO; |
| 57 | 60 | |
| @@ -61,7 +64,11 @@ static int virtbt_open(struct hci_dev *hdev) · 3 unmodified lines | ||
| 61 | 64 | |
| 62 | 65 | static int virtbt_close(struct hci_dev *hdev) |
| 63 | 66 | { |
| 64 | − struct virtio_bluetooth *vbt = hci_get_drvdata(hdev); | |
| 67 | + return 0; | |
| 68 | +} | |
| 69 | + | |
| 70 | +static int virtbt_close_vdev(struct virtio_bluetooth *vbt) | |
| 71 | +{ | |
| 65 | 72 | int i; |
| 66 | 73 | |
| 67 | 74 | cancel_work_sync(&vbt->rx); |
| @@ -306,7 +313,12 @@ static int virtbt_probe(struct virtio_device *vdev) · 238 unmodified lines | ||
| 306 | 313 | if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) { |
| 307 | 314 | __u16 vendor; |
| 308 | 315 | |
| 309 | − virtio_cread(vdev, struct virtio_bt_config, vendor, &vendor); | |
| 316 | + if (virtio_has_feature(vdev, VIRTIO_BT_F_CONFIG_V2)) | |
| 317 | + virtio_cread(vdev, struct virtio_bt_config_v2, | |
| 318 | + vendor, &vendor); | |
| 319 | + else | |
| 320 | + virtio_cread(vdev, struct virtio_bt_config, | |
| 321 | + vendor, &vendor); | |
| 310 | 322 | |
| 311 | 323 | switch (vendor) { |
| 312 | 324 | case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR: |
| @@ -339,8 +351,12 @@ static int virtbt_probe(struct virtio_device *vdev) · 26 unmodified lines | ||
| 339 | 351 | if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) { |
| 340 | 352 | __u16 msft_opcode; |
| 341 | 353 | |
| 342 | − virtio_cread(vdev, struct virtio_bt_config, | |
| 343 | − msft_opcode, &msft_opcode); | |
| 354 | + if (virtio_has_feature(vdev, VIRTIO_BT_F_CONFIG_V2)) | |
| 355 | + virtio_cread(vdev, struct virtio_bt_config_v2, | |
| 356 | + msft_opcode, &msft_opcode); | |
| 357 | + else | |
| 358 | + virtio_cread(vdev, struct virtio_bt_config, | |
| 359 | + msft_opcode, &msft_opcode); | |
| 344 | 360 | |
| 345 | 361 | hci_set_msft_opcode(hdev, msft_opcode); |
| 346 | 362 | } |
| @@ -354,8 +370,15 @@ static int virtbt_probe(struct virtio_device *vdev) · 7 unmodified lines | ||
| 354 | 370 | goto failed; |
| 355 | 371 | } |
| 356 | 372 | |
| 373 | + virtio_device_ready(vdev); | |
| 374 | + err = virtbt_open_vdev(vbt); | |
| 375 | + if (err) | |
| 376 | + goto open_failed; | |
| 377 | + | |
| 357 | 378 | return 0; |
| 358 | 379 | |
| 380 | +open_failed: | |
| 381 | + hci_free_dev(hdev); | |
| 359 | 382 | failed: |
| 360 | 383 | vdev->config->del_vqs(vdev); |
| 361 | 384 | return err; |
| @@ -368,6 +391,7 @@ static void virtbt_remove(struct virtio_device *vdev) · 6 unmodified lines | ||
| 368 | 391 | |
| 369 | 392 | hci_unregister_dev(hdev); |
| 370 | 393 | virtio_reset_device(vdev); |
| 394 | + virtbt_close_vdev(vbt); | |
| 371 | 395 | |
| 372 | 396 | hci_free_dev(hdev); |
| 373 | 397 | vbt->hdev = NULL; |
| @@ -387,6 +411,7 @@ static const unsigned int virtbt_features[] = { · 13 unmodified lines | ||
| 387 | 411 | VIRTIO_BT_F_VND_HCI, |
| 388 | 412 | VIRTIO_BT_F_MSFT_EXT, |
| 389 | 413 | VIRTIO_BT_F_AOSP_EXT, |
| 414 | + VIRTIO_BT_F_CONFIG_V2, | |
| 390 | 415 | }; |
| 391 | 416 | |
| 392 | 417 | static struct virtio_driver virtbt_driver = { |
| @@ -76,10 +76,6 @@ static int otx2_cpt_devlink_info_get(struct devlink *dl, · 75 unmodified lines | ||
| 76 | 76 | struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf; |
| 77 | 77 | int err; |
| 78 | 78 | |
| 79 | − err = devlink_info_driver_name_put(req, "rvu_cptpf"); | |
| 80 | − if (err) | |
| 81 | − return err; | |
| 82 | − | |
| 83 | 79 | err = otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp, |
| 84 | 80 | "fw.ae", OTX2_CPT_AE_TYPES); |
| 85 | 81 | if (err) |
| @@ -706,7 +706,7 @@ static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts) · 705 unmodified lines | ||
| 706 | 706 | return -EOPNOTSUPP; |
| 707 | 707 | } |
| 708 | 708 | |
| 709 | −static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta) | |
| 709 | +static int hv_ptp_adjfine(struct ptp_clock_info *ptp, long delta) | |
| 710 | 710 | { |
| 711 | 711 | return -EOPNOTSUPP; |
| 712 | 712 | } |
| @@ -724,7 +724,7 @@ static struct ptp_clock_info ptp_hyperv_info = { · 11 unmodified lines | ||
| 724 | 724 | .name = "hyperv", |
| 725 | 725 | .enable = hv_ptp_enable, |
| 726 | 726 | .adjtime = hv_ptp_adjtime, |
| 727 | − .adjfreq = hv_ptp_adjfreq, | |
| 727 | + .adjfine = hv_ptp_adjfine, | |
| 728 | 728 | .gettime64 = hv_ptp_gettime, |
| 729 | 729 | .settime64 = hv_ptp_settime, |
| 730 | 730 | .owner = THIS_MODULE, |
| @@ -230,8 +230,7 @@ static bool mlx5_ib_invalidate_range(struct mmu_interval_notifier *mni, · 229 unmodified lines | ||
| 230 | 230 | struct ib_umem_odp *umem_odp = |
| 231 | 231 | container_of(mni, struct ib_umem_odp, notifier); |
| 232 | 232 | struct mlx5_ib_mr *mr; |
| 233 | − const u64 umr_block_mask = (MLX5_UMR_MTT_ALIGNMENT / | |
| 234 | − sizeof(struct mlx5_mtt)) - 1; | |
| 233 | + const u64 umr_block_mask = MLX5_UMR_MTT_NUM_ENTRIES_ALIGNMENT - 1; | |
| 235 | 234 | u64 idx = 0, blk_start_idx = 0; |
| 236 | 235 | u64 invalidations = 0; |
| 237 | 236 | unsigned long start; |
| @@ -418,7 +418,7 @@ int mlx5r_umr_rereg_pd_access(struct mlx5_ib_mr *mr, struct ib_pd *pd, · 417 unmodified lines | ||
| 418 | 418 | } |
| 419 | 419 | |
| 420 | 420 | #define MLX5_MAX_UMR_CHUNK \ |
| 421 | − ((1 << (MLX5_MAX_UMR_SHIFT + 4)) - MLX5_UMR_MTT_ALIGNMENT) | |
| 421 | + ((1 << (MLX5_MAX_UMR_SHIFT + 4)) - MLX5_UMR_FLEX_ALIGNMENT) | |
| 422 | 422 | #define MLX5_SPARE_UMR_CHUNK 0x10000 |
| 423 | 423 | |
| 424 | 424 | /* |
| @@ -428,11 +428,11 @@ int mlx5r_umr_rereg_pd_access(struct mlx5_ib_mr *mr, struct ib_pd *pd, · 3 unmodified lines | ||
| 428 | 428 | */ |
| 429 | 429 | static void *mlx5r_umr_alloc_xlt(size_t *nents, size_t ent_size, gfp_t gfp_mask) |
| 430 | 430 | { |
| 431 | − const size_t xlt_chunk_align = MLX5_UMR_MTT_ALIGNMENT / ent_size; | |
| 431 | + const size_t xlt_chunk_align = MLX5_UMR_FLEX_ALIGNMENT / ent_size; | |
| 432 | 432 | size_t size; |
| 433 | 433 | void *res = NULL; |
| 434 | 434 | |
| 435 | − static_assert(PAGE_SIZE % MLX5_UMR_MTT_ALIGNMENT == 0); | |
| 435 | + static_assert(PAGE_SIZE % MLX5_UMR_FLEX_ALIGNMENT == 0); | |
| 436 | 436 | |
| 437 | 437 | /* |
| 438 | 438 | * MLX5_IB_UPD_XLT_ATOMIC doesn't signal an atomic context just that the |
| @@ -666,7 +666,7 @@ int mlx5r_umr_update_mr_pas(struct mlx5_ib_mr *mr, unsigned int flags) · 227 unmodified lines | ||
| 666 | 666 | } |
| 667 | 667 | |
| 668 | 668 | final_size = (void *)cur_mtt - (void *)mtt; |
| 669 | − sg.length = ALIGN(final_size, MLX5_UMR_MTT_ALIGNMENT); | |
| 669 | + sg.length = ALIGN(final_size, MLX5_UMR_FLEX_ALIGNMENT); | |
| 670 | 670 | memset(cur_mtt, 0, sg.length - final_size); |
| 671 | 671 | mlx5r_umr_final_update_xlt(dev, &wqe, mr, &sg, flags); |
| 672 | 672 | |
| @@ -690,7 +690,7 @@ int mlx5r_umr_update_xlt(struct mlx5_ib_mr *mr, u64 idx, int npages, · 17 unmodified lines | ||
| 690 | 690 | int desc_size = (flags & MLX5_IB_UPD_XLT_INDIRECT) |
| 691 | 691 | ? sizeof(struct mlx5_klm) |
| 692 | 692 | : sizeof(struct mlx5_mtt); |
| 693 | − const int page_align = MLX5_UMR_MTT_ALIGNMENT / desc_size; | |
| 693 | + const int page_align = MLX5_UMR_FLEX_ALIGNMENT / desc_size; | |
| 694 | 694 | struct mlx5_ib_dev *dev = mr_to_mdev(mr); |
| 695 | 695 | struct device *ddev = &dev->mdev->pdev->dev; |
| 696 | 696 | const int page_mask = page_align - 1; |
| @@ -711,7 +711,7 @@ int mlx5r_umr_update_xlt(struct mlx5_ib_mr *mr, u64 idx, int npages, · 14 unmodified lines | ||
| 711 | 711 | if (WARN_ON(!mr->umem->is_odp)) |
| 712 | 712 | return -EINVAL; |
| 713 | 713 | |
| 714 | − /* UMR copies MTTs in units of MLX5_UMR_MTT_ALIGNMENT bytes, | |
| 714 | + /* UMR copies MTTs in units of MLX5_UMR_FLEX_ALIGNMENT bytes, | |
| 715 | 715 | * so we need to align the offset and length accordingly |
| 716 | 716 | */ |
| 717 | 717 | if (idx & page_mask) { |
| @@ -748,7 +748,7 @@ int mlx5r_umr_update_xlt(struct mlx5_ib_mr *mr, u64 idx, int npages, · 30 unmodified lines | ||
| 748 | 748 | mlx5_odp_populate_xlt(xlt, idx, npages, mr, flags); |
| 749 | 749 | dma_sync_single_for_device(ddev, sg.addr, sg.length, |
| 750 | 750 | DMA_TO_DEVICE); |
| 751 | − sg.length = ALIGN(size_to_map, MLX5_UMR_MTT_ALIGNMENT); | |
| 751 | + sg.length = ALIGN(size_to_map, MLX5_UMR_FLEX_ALIGNMENT); | |
| 752 | 752 | |
| 753 | 753 | if (pages_mapped + pages_iter >= pages_to_map) |
| 754 | 754 | mlx5r_umr_final_update_xlt(dev, &wqe, mr, &sg, flags); |
| @@ -75,6 +75,7 @@ enum ad_link_speed_type { · 74 unmodified lines | ||
| 75 | 75 | AD_LINK_SPEED_100000MBPS, |
| 76 | 76 | AD_LINK_SPEED_200000MBPS, |
| 77 | 77 | AD_LINK_SPEED_400000MBPS, |
| 78 | + AD_LINK_SPEED_800000MBPS, | |
| 78 | 79 | }; |
| 79 | 80 | |
| 80 | 81 | /* compare MAC addresses */ |
| @@ -251,6 +252,7 @@ static inline int __check_agg_selection_timer(struct port *port) · 170 unmodified lines | ||
| 251 | 252 | * %AD_LINK_SPEED_100000MBPS |
| 252 | 253 | * %AD_LINK_SPEED_200000MBPS |
| 253 | 254 | * %AD_LINK_SPEED_400000MBPS |
| 255 | + * %AD_LINK_SPEED_800000MBPS | |
| 254 | 256 | */ |
| 255 | 257 | static u16 __get_link_speed(struct port *port) |
| 256 | 258 | { |
| @@ -326,6 +328,10 @@ static u16 __get_link_speed(struct port *port) · 69 unmodified lines | ||
| 326 | 328 | speed = AD_LINK_SPEED_400000MBPS; |
| 327 | 329 | break; |
| 328 | 330 | |
| 331 | + case SPEED_800000: | |
| 332 | + speed = AD_LINK_SPEED_800000MBPS; | |
| 333 | + break; | |
| 334 | + | |
| 329 | 335 | default: |
| 330 | 336 | /* unknown speed value from ethtool. shouldn't happen */ |
| 331 | 337 | if (slave->speed != SPEED_UNKNOWN) |
| @@ -753,6 +759,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) · 421 unmodified lines | ||
| 753 | 759 | case AD_LINK_SPEED_400000MBPS: |
| 754 | 760 | bandwidth = nports * 400000; |
| 755 | 761 | break; |
| 762 | + case AD_LINK_SPEED_800000MBPS: | |
| 763 | + bandwidth = nports * 800000; | |
| 764 | + break; | |
| 756 | 765 | default: |
| 757 | 766 | bandwidth = 0; /* to silence the compiler */ |
| 758 | 767 | } |
| @@ -307,7 +307,7 @@ netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, · 306 unmodified lines | ||
| 307 | 307 | return dev_queue_xmit(skb); |
| 308 | 308 | } |
| 309 | 309 | |
| 310 | −bool bond_sk_check(struct bonding *bond) | |
| 310 | +static bool bond_sk_check(struct bonding *bond) | |
| 311 | 311 | { |
| 312 | 312 | switch (BOND_MODE(bond)) { |
| 313 | 313 | case BOND_MODE_8023AD: |
| @@ -1398,13 +1398,6 @@ static netdev_features_t bond_fix_features(struct net_device *dev, · 1084 unmodified lines | ||
| 1398 | 1398 | netdev_features_t mask; |
| 1399 | 1399 | struct slave *slave; |
| 1400 | 1400 | |
| 1401 | −#if IS_ENABLED(CONFIG_TLS_DEVICE) | |
| 1402 | − if (bond_sk_check(bond)) | |
| 1403 | − features |= BOND_TLS_FEATURES; | |
| 1404 | − else | |
| 1405 | − features &= ~BOND_TLS_FEATURES; | |
| 1406 | −#endif | |
| 1407 | − | |
| 1408 | 1401 | mask = features; |
| 1409 | 1402 | |
| 1410 | 1403 | features &= ~NETIF_F_ONE_FOR_ALL; |
| @@ -1639,13 +1632,19 @@ static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave, · 228 unmodified lines | ||
| 1639 | 1632 | { |
| 1640 | 1633 | struct netdev_lag_upper_info lag_upper_info; |
| 1641 | 1634 | enum netdev_lag_tx_type type; |
| 1635 | + int err; | |
| 1642 | 1636 | |
| 1643 | 1637 | type = bond_lag_tx_type(bond); |
| 1644 | 1638 | lag_upper_info.tx_type = type; |
| 1645 | 1639 | lag_upper_info.hash_type = bond_lag_hash_type(bond, type); |
| 1646 | 1640 | |
| 1647 | − return netdev_master_upper_dev_link(slave->dev, bond->dev, slave, | |
| 1648 | − &lag_upper_info, extack); | |
| 1641 | + err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave, | |
| 1642 | + &lag_upper_info, extack); | |
| 1643 | + if (err) | |
| 1644 | + return err; | |
| 1645 | + | |
| 1646 | + slave->dev->flags |= IFF_SLAVE; | |
| 1647 | + return 0; | |
| 1649 | 1648 | } |
| 1650 | 1649 | |
| 1651 | 1650 | static void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave) |
| @@ -1957,8 +1956,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, · 305 unmodified lines | ||
| 1957 | 1956 | } |
| 1958 | 1957 | } |
| 1959 | 1958 | |
| 1960 | − /* set slave flag before open to prevent IPv6 addrconf */ | |
| 1961 | − slave_dev->flags |= IFF_SLAVE; | |
| 1959 | + /* set no_addrconf flag before open to prevent IPv6 addrconf */ | |
| 1960 | + slave_dev->priv_flags |= IFF_NO_ADDRCONF; | |
| 1962 | 1961 | |
| 1963 | 1962 | /* open the slave since the application closed it */ |
| 1964 | 1963 | res = dev_open(slave_dev, extack); |
| @@ -2261,7 +2260,7 @@ err_close: · 296 unmodified lines | ||
| 2261 | 2260 | dev_close(slave_dev); |
| 2262 | 2261 | |
| 2263 | 2262 | err_restore_mac: |
| 2264 | − slave_dev->flags &= ~IFF_SLAVE; | |
| 2263 | + slave_dev->priv_flags &= ~IFF_NO_ADDRCONF; | |
| 2265 | 2264 | if (!bond->params.fail_over_mac || |
| 2266 | 2265 | BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { |
| 2267 | 2266 | /* XXX TODO - fom follow mode needs to change master's |
| @@ -2453,6 +2452,8 @@ static int __bond_release_one(struct net_device *bond_dev, · 185 unmodified lines | ||
| 2453 | 2452 | /* close slave before restoring its mac address */ |
| 2454 | 2453 | dev_close(slave_dev); |
| 2455 | 2454 | |
| 2455 | + slave_dev->priv_flags &= ~IFF_NO_ADDRCONF; | |
| 2456 | + | |
| 2456 | 2457 | if (bond->params.fail_over_mac != BOND_FOM_ACTIVE || |
| 2457 | 2458 | BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { |
| 2458 | 2459 | /* restore original ("permanent") mac address */ |
| @@ -2531,12 +2532,21 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in · 72 unmodified lines | ||
| 2531 | 2532 | /* called with rcu_read_lock() */ |
| 2532 | 2533 | static int bond_miimon_inspect(struct bonding *bond) |
| 2533 | 2534 | { |
| 2535 | + bool ignore_updelay = false; | |
| 2534 | 2536 | int link_state, commit = 0; |
| 2535 | 2537 | struct list_head *iter; |
| 2536 | 2538 | struct slave *slave; |
| 2537 | − bool ignore_updelay; | |
| 2538 | 2539 | |
| 2539 | − ignore_updelay = !rcu_dereference(bond->curr_active_slave); | |
| 2540 | + if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) { | |
| 2541 | + ignore_updelay = !rcu_dereference(bond->curr_active_slave); | |
| 2542 | + } else { | |
| 2543 | + struct bond_up_slave *usable_slaves; | |
| 2544 | + | |
| 2545 | + usable_slaves = rcu_dereference(bond->usable_slaves); | |
| 2546 | + | |
| 2547 | + if (usable_slaves && usable_slaves->count == 0) | |
| 2548 | + ignore_updelay = true; | |
| 2549 | + } | |
| 2540 | 2550 | |
| 2541 | 2551 | bond_for_each_slave_rcu(bond, slave, iter) { |
| 2542 | 2552 | bond_propose_link_state(slave, BOND_LINK_NOCHANGE); |
| @@ -5813,10 +5823,6 @@ void bond_setup(struct net_device *bond_dev) · 3270 unmodified lines | ||
| 5813 | 5823 | if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) |
| 5814 | 5824 | bond_dev->features |= BOND_XFRM_FEATURES; |
| 5815 | 5825 | #endif /* CONFIG_XFRM_OFFLOAD */ |
| 5816 | −#if IS_ENABLED(CONFIG_TLS_DEVICE) | |
| 5817 | − if (bond_sk_check(bond)) | |
| 5818 | − bond_dev->features |= BOND_TLS_FEATURES; | |
| 5819 | −#endif | |
| 5820 | 5826 | } |
| 5821 | 5827 | |
| 5822 | 5828 | /* Destroy a bonding device. |
| @@ -842,19 +842,6 @@ static bool bond_set_xfrm_features(struct bonding *bond) · 841 unmodified lines | ||
| 842 | 842 | return true; |
| 843 | 843 | } |
| 844 | 844 | |
| 845 | −static bool bond_set_tls_features(struct bonding *bond) | |
| 846 | −{ | |
| 847 | − if (!IS_ENABLED(CONFIG_TLS_DEVICE)) | |
| 848 | − return false; | |
| 849 | − | |
| 850 | − if (bond_sk_check(bond)) | |
| 851 | − bond->dev->wanted_features |= BOND_TLS_FEATURES; | |
| 852 | − else | |
| 853 | − bond->dev->wanted_features &= ~BOND_TLS_FEATURES; | |
| 854 | − | |
| 855 | − return true; | |
| 856 | −} | |
| 857 | − | |
| 858 | 845 | static int bond_option_mode_set(struct bonding *bond, |
| 859 | 846 | const struct bond_opt_value *newval) |
| 860 | 847 | { |
| @@ -885,7 +872,6 @@ static int bond_option_mode_set(struct bonding *bond, · 24 unmodified lines | ||
| 885 | 872 | bool update = false; |
| 886 | 873 | |
| 887 | 874 | update |= bond_set_xfrm_features(bond); |
| 888 | − update |= bond_set_tls_features(bond); | |
| 889 | 875 | |
| 890 | 876 | if (update) |
| 891 | 877 | netdev_update_features(bond->dev); |
| @@ -1418,10 +1404,6 @@ static int bond_option_xmit_hash_policy_set(struct bonding *bond, · 526 unmodified lines | ||
| 1418 | 1404 | newval->string, newval->value); |
| 1419 | 1405 | bond->params.xmit_policy = newval->value; |
| 1420 | 1406 | |
| 1421 | − if (bond->dev->reg_state == NETREG_REGISTERED) | |
| 1422 | − if (bond_set_tls_features(bond)) | |
| 1423 | − netdev_update_features(bond->dev); | |
| 1424 | − | |
| 1425 | 1407 | return 0; |
| 1426 | 1408 | } |
| 1427 | 1409 | |
| @@ -198,14 +198,6 @@ config CAN_XILINXCAN · 197 unmodified lines | ||
| 198 | 198 | Xilinx CAN driver. This driver supports both soft AXI CAN IP and |
| 199 | 199 | Zynq CANPS IP. |
| 200 | 200 | |
| 201 | −config PCH_CAN | |
| 202 | − tristate "Intel EG20T PCH CAN controller" | |
| 203 | − depends on PCI && (X86_32 || COMPILE_TEST) | |
| 204 | − help | |
| 205 | − This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which | |
| 206 | − is an IOH for x86 embedded processor (Intel Atom E6xx series). | |
| 207 | − This driver can access CAN bus. | |
| 208 | − | |
| 209 | 201 | source "drivers/net/can/c_can/Kconfig" |
| 210 | 202 | source "drivers/net/can/cc770/Kconfig" |
| 211 | 203 | source "drivers/net/can/ctucanfd/Kconfig" |
| @@ -30,6 +30,5 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ · 29 unmodified lines | ||
| 30 | 30 | obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o |
| 31 | 31 | obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o |
| 32 | 32 | obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o |
| 33 | −obj-$(CONFIG_PCH_CAN) += pch_can.o | |
| 34 | 33 | |
| 35 | 34 | subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG |
| @@ -20,5 +20,6 @@ config CAN_C_CAN_PCI · 19 unmodified lines | ||
| 20 | 20 | depends on PCI |
| 21 | 21 | help |
| 22 | 22 | This driver adds support for the C_CAN/D_CAN chips connected |
| 23 | − to the PCI bus. | |
| 23 | + to the PCI bus. E.g. for the C_CAN controller IP inside the | |
| 24 | + Intel Atom E6xx series IOH (aka EG20T 'PCH CAN'). | |
| 24 | 25 | endif |
| @@ -290,8 +290,7 @@ static int c_can_plat_probe(struct platform_device *pdev) · 289 unmodified lines | ||
| 290 | 290 | goto exit; |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | − mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 294 | − addr = devm_ioremap_resource(&pdev->dev, mem); | |
| 293 | + addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); | |
| 295 | 294 | if (IS_ERR(addr)) { |
| 296 | 295 | ret = PTR_ERR(addr); |
| 297 | 296 | goto exit; |
| @@ -23,7 +23,7 @@ config CAN_CTUCANFD_PCI · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | config CAN_CTUCANFD_PLATFORM |
| 25 | 25 | tristate "CTU CAN-FD IP core platform (FPGA, SoC) driver" |
| 26 | − depends on HAS_IOMEM && (OF || COMPILE_TEST) | |
| 26 | + depends on HAS_IOMEM && OF | |
| 27 | 27 | select CAN_CTUCANFD |
| 28 | 28 | help |
| 29 | 29 | The core has been tested together with OpenCores SJA1000 |
| @@ -345,6 +345,15 @@ static struct flexcan_devtype_data fsl_imx8mp_devtype_data = { · 344 unmodified lines | ||
| 345 | 345 | FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR, |
| 346 | 346 | }; |
| 347 | 347 | |
| 348 | +static struct flexcan_devtype_data fsl_imx93_devtype_data = { | |
| 349 | + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | | |
| 350 | + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX | | |
| 351 | + FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_AUTO_STOP_MODE | | |
| 352 | + FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC | | |
| 353 | + FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX | | |
| 354 | + FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR, | |
| 355 | +}; | |
| 356 | + | |
| 348 | 357 | static const struct flexcan_devtype_data fsl_vf610_devtype_data = { |
| 349 | 358 | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | |
| 350 | 359 | FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX | |
| @@ -532,9 +541,14 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) · 181 unmodified lines | ||
| 532 | 541 | ret = flexcan_stop_mode_enable_scfw(priv, true); |
| 533 | 542 | if (ret < 0) |
| 534 | 543 | return ret; |
| 535 | − } else { | |
| 544 | + } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) { | |
| 536 | 545 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
| 537 | 546 | 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); |
| 547 | + } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) { | |
| 548 | + /* For the auto stop mode, software do nothing, hardware will cover | |
| 549 | + * all the operation automatically after system go into low power mode. | |
| 550 | + */ | |
| 551 | + return 0; | |
| 538 | 552 | } |
| 539 | 553 | |
| 540 | 554 | return flexcan_low_power_enter_ack(priv); |
| @@ -551,7 +565,7 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) · 10 unmodified lines | ||
| 551 | 565 | ret = flexcan_stop_mode_enable_scfw(priv, false); |
| 552 | 566 | if (ret < 0) |
| 553 | 567 | return ret; |
| 554 | − } else { | |
| 568 | + } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) { | |
| 555 | 569 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
| 556 | 570 | 1 << priv->stm.req_bit, 0); |
| 557 | 571 | } |
| @@ -560,6 +574,12 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) · 2 unmodified lines | ||
| 560 | 574 | reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; |
| 561 | 575 | priv->write(reg_mcr, ®s->mcr); |
| 562 | 576 | |
| 577 | + /* For the auto stop mode, hardware will exist stop mode | |
| 578 | + * automatically after system go out of low power mode. | |
| 579 | + */ | |
| 580 | + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) | |
| 581 | + return 0; | |
| 582 | + | |
| 563 | 583 | return flexcan_low_power_exit_ack(priv); |
| 564 | 584 | } |
| 565 | 585 | |
| @@ -1974,6 +1994,8 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) · 1408 unmodified lines | ||
| 1974 | 1994 | ret = flexcan_setup_stop_mode_scfw(pdev); |
| 1975 | 1995 | else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) |
| 1976 | 1996 | ret = flexcan_setup_stop_mode_gpr(pdev); |
| 1997 | + else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) | |
| 1998 | + ret = 0; | |
| 1977 | 1999 | else |
| 1978 | 2000 | /* return 0 directly if doesn't support stop mode feature */ |
| 1979 | 2001 | return 0; |
| @@ -1992,6 +2014,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) · 12 unmodified lines | ||
| 1992 | 2014 | static const struct of_device_id flexcan_of_match[] = { |
| 1993 | 2015 | { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, |
| 1994 | 2016 | { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, |
| 2017 | + { .compatible = "fsl,imx93-flexcan", .data = &fsl_imx93_devtype_data, }, | |
| 1995 | 2018 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, |
| 1996 | 2019 | { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, |
| 1997 | 2020 | { .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, }, |
| @@ -2299,8 +2322,16 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device) · 301 unmodified lines | ||
| 2299 | 2322 | if (netif_running(dev)) { |
| 2300 | 2323 | int err; |
| 2301 | 2324 | |
| 2302 | − if (device_may_wakeup(device)) | |
| 2325 | + if (device_may_wakeup(device)) { | |
| 2303 | 2326 | flexcan_enable_wakeup_irq(priv, true); |
| 2327 | + /* For auto stop mode, need to keep the clock on before | |
| 2328 | + * system go into low power mode. After system go into | |
| 2329 | + * low power mode, hardware will config the flexcan into | |
| 2330 | + * stop mode, and gate off the clock automatically. | |
| 2331 | + */ | |
| 2332 | + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) | |
| 2333 | + return 0; | |
| 2334 | + } | |
| 2304 | 2335 | |
| 2305 | 2336 | err = pm_runtime_force_suspend(device); |
| 2306 | 2337 | if (err) |
| @@ -68,6 +68,8 @@ · 67 unmodified lines | ||
| 68 | 68 | #define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15) |
| 69 | 69 | /* Device supports RX via FIFO */ |
| 70 | 70 | #define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16) |
| 71 | +/* auto enter stop mode to support wakeup */ | |
| 72 | +#define FLEXCAN_QUIRK_AUTO_STOP_MODE BIT(17) | |
| 71 | 73 | |
| 72 | 74 | struct flexcan_devtype_data { |
| 73 | 75 | u32 quirks; /* quirks needed for different IP cores */ |
| @@ -9,20 +9,20 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | #include <linux/bitfield.h> |
| 12 | +#include <linux/can/dev.h> | |
| 12 | 13 | #include <linux/ethtool.h> |
| 13 | 14 | #include <linux/interrupt.h> |
| 14 | 15 | #include <linux/io.h> |
| 16 | +#include <linux/iopoll.h> | |
| 15 | 17 | #include <linux/kernel.h> |
| 16 | 18 | #include <linux/module.h> |
| 17 | 19 | #include <linux/netdevice.h> |
| 18 | 20 | #include <linux/of.h> |
| 19 | 21 | #include <linux/of_device.h> |
| 22 | +#include <linux/phy/phy.h> | |
| 23 | +#include <linux/pinctrl/consumer.h> | |
| 20 | 24 | #include <linux/platform_device.h> |
| 21 | 25 | #include <linux/pm_runtime.h> |
| 22 | −#include <linux/iopoll.h> | |
| 23 | −#include <linux/can/dev.h> | |
| 24 | −#include <linux/pinctrl/consumer.h> | |
| 25 | −#include <linux/phy/phy.h> | |
| 26 | 26 | |
| 27 | 27 | #include "m_can.h" |
| 28 | 28 | |
| @@ -156,6 +156,7 @@ enum m_can_reg { · 127 unmodified lines | ||
| 156 | 156 | #define PSR_EW BIT(6) |
| 157 | 157 | #define PSR_EP BIT(5) |
| 158 | 158 | #define PSR_LEC_MASK GENMASK(2, 0) |
| 159 | +#define PSR_DLEC_MASK GENMASK(10, 8) | |
| 159 | 160 | |
| 160 | 161 | /* Interrupt Register (IR) */ |
| 161 | 162 | #define IR_ALL_INT 0xffffffff |
| @@ -209,7 +210,7 @@ enum m_can_reg { · 47 unmodified lines | ||
| 209 | 210 | |
| 210 | 211 | /* Interrupts for version >= 3.1.x */ |
| 211 | 212 | #define IR_ERR_LEC_31X (IR_PED | IR_PEA) |
| 212 | −#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \ | |
| 213 | +#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \ | |
| 213 | 214 | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \ |
| 214 | 215 | IR_RF0L) |
| 215 | 216 | #define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X) |
| @@ -368,9 +369,14 @@ m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset, u32 *val) · 152 unmodified lines | ||
| 368 | 369 | return cdev->ops->read_fifo(cdev, addr_offset, val, 1); |
| 369 | 370 | } |
| 370 | 371 | |
| 372 | +static inline bool _m_can_tx_fifo_full(u32 txfqs) | |
| 373 | +{ | |
| 374 | + return !!(txfqs & TXFQS_TFQF); | |
| 375 | +} | |
| 376 | + | |
| 371 | 377 | static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev) |
| 372 | 378 | { |
| 373 | − return !!(m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQF); | |
| 379 | + return _m_can_tx_fifo_full(m_can_read(cdev, M_CAN_TXFQS)); | |
| 374 | 380 | } |
| 375 | 381 | |
| 376 | 382 | static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) |
| @@ -471,19 +477,16 @@ static void m_can_receive_skb(struct m_can_classdev *cdev, · 94 unmodified lines | ||
| 471 | 477 | } |
| 472 | 478 | } |
| 473 | 479 | |
| 474 | −static int m_can_read_fifo(struct net_device *dev, u32 rxfs) | |
| 480 | +static int m_can_read_fifo(struct net_device *dev, u32 fgi) | |
| 475 | 481 | { |
| 476 | 482 | struct net_device_stats *stats = &dev->stats; |
| 477 | 483 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 478 | 484 | struct canfd_frame *cf; |
| 479 | 485 | struct sk_buff *skb; |
| 480 | 486 | struct id_and_dlc fifo_header; |
| 481 | − u32 fgi; | |
| 482 | 487 | u32 timestamp = 0; |
| 483 | 488 | int err; |
| 484 | 489 | |
| 485 | − /* calculate the fifo get index for where to read data */ | |
| 486 | − fgi = FIELD_GET(RXFS_FGI_MASK, rxfs); | |
| 487 | 490 | err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID, &fifo_header, 2); |
| 488 | 491 | if (err) |
| 489 | 492 | goto out_fail; |
| @@ -527,9 +530,6 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs) · 37 unmodified lines | ||
| 527 | 530 | } |
| 528 | 531 | stats->rx_packets++; |
| 529 | 532 | |
| 530 | − /* acknowledge rx fifo 0 */ | |
| 531 | − m_can_write(cdev, M_CAN_RXF0A, fgi); | |
| 532 | − | |
| 533 | 533 | timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16; |
| 534 | 534 | |
| 535 | 535 | m_can_receive_skb(cdev, skb, timestamp); |
| @@ -548,7 +548,11 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota) · 12 unmodified lines | ||
| 548 | 548 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 549 | 549 | u32 pkts = 0; |
| 550 | 550 | u32 rxfs; |
| 551 | − int err; | |
| 551 | + u32 rx_count; | |
| 552 | + u32 fgi; | |
| 553 | + int ack_fgi = -1; | |
| 554 | + int i; | |
| 555 | + int err = 0; | |
| 552 | 556 | |
| 553 | 557 | rxfs = m_can_read(cdev, M_CAN_RXF0S); |
| 554 | 558 | if (!(rxfs & RXFS_FFL_MASK)) { |
| @@ -556,16 +560,26 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota) · 1 unmodified line | ||
| 556 | 560 | return 0; |
| 557 | 561 | } |
| 558 | 562 | |
| 559 | − while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) { | |
| 560 | − err = m_can_read_fifo(dev, rxfs); | |
| 563 | + rx_count = FIELD_GET(RXFS_FFL_MASK, rxfs); | |
| 564 | + fgi = FIELD_GET(RXFS_FGI_MASK, rxfs); | |
| 565 | + | |
| 566 | + for (i = 0; i < rx_count && quota > 0; ++i) { | |
| 567 | + err = m_can_read_fifo(dev, fgi); | |
| 561 | 568 | if (err) |
| 562 | − return err; | |
| 569 | + break; | |
| 563 | 570 | |
| 564 | 571 | quota--; |
| 565 | 572 | pkts++; |
| 566 | − rxfs = m_can_read(cdev, M_CAN_RXF0S); | |
| 573 | + ack_fgi = fgi; | |
| 574 | + fgi = (++fgi >= cdev->mcfg[MRAM_RXF0].num ? 0 : fgi); | |
| 567 | 575 | } |
| 568 | 576 | |
| 577 | + if (ack_fgi != -1) | |
| 578 | + m_can_write(cdev, M_CAN_RXF0A, ack_fgi); | |
| 579 | + | |
| 580 | + if (err) | |
| 581 | + return err; | |
| 582 | + | |
| 569 | 583 | return pkts; |
| 570 | 584 | } |
| 571 | 585 | |
| @@ -816,11 +830,9 @@ static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus) · 244 unmodified lines | ||
| 816 | 830 | netdev_err(dev, "Message RAM access failure occurred\n"); |
| 817 | 831 | } |
| 818 | 832 | |
| 819 | −static inline bool is_lec_err(u32 psr) | |
| 833 | +static inline bool is_lec_err(u8 lec) | |
| 820 | 834 | { |
| 821 | − psr &= LEC_UNUSED; | |
| 822 | − | |
| 823 | − return psr && (psr != LEC_UNUSED); | |
| 835 | + return lec != LEC_NO_ERROR && lec != LEC_NO_CHANGE; | |
| 824 | 836 | } |
| 825 | 837 | |
| 826 | 838 | static inline bool m_can_is_protocol_err(u32 irqstatus) |
| @@ -875,9 +887,20 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, · 48 unmodified lines | ||
| 875 | 887 | work_done += m_can_handle_lost_msg(dev); |
| 876 | 888 | |
| 877 | 889 | /* handle lec errors on the bus */ |
| 878 | − if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && | |
| 879 | − is_lec_err(psr)) | |
| 880 | − work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED); | |
| 890 | + if (cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { | |
| 891 | + u8 lec = FIELD_GET(PSR_LEC_MASK, psr); | |
| 892 | + u8 dlec = FIELD_GET(PSR_DLEC_MASK, psr); | |
| 893 | + | |
| 894 | + if (is_lec_err(lec)) { | |
| 895 | + netdev_dbg(dev, "Arbitration phase error detected\n"); | |
| 896 | + work_done += m_can_handle_lec_err(dev, lec); | |
| 897 | + } | |
| 898 | + | |
| 899 | + if (is_lec_err(dlec)) { | |
| 900 | + netdev_dbg(dev, "Data phase error detected\n"); | |
| 901 | + work_done += m_can_handle_lec_err(dev, dlec); | |
| 902 | + } | |
| 903 | + } | |
| 881 | 904 | |
| 882 | 905 | /* handle protocol errors in arbitration phase */ |
| 883 | 906 | if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && |
| @@ -890,14 +913,12 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, · 6 unmodified lines | ||
| 890 | 913 | return work_done; |
| 891 | 914 | } |
| 892 | 915 | |
| 893 | −static int m_can_rx_handler(struct net_device *dev, int quota) | |
| 916 | +static int m_can_rx_handler(struct net_device *dev, int quota, u32 irqstatus) | |
| 894 | 917 | { |
| 895 | 918 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 896 | 919 | int rx_work_or_err; |
| 897 | 920 | int work_done = 0; |
| 898 | − u32 irqstatus, psr; | |
| 899 | 921 | |
| 900 | − irqstatus = cdev->irqstatus | m_can_read(cdev, M_CAN_IR); | |
| 901 | 922 | if (!irqstatus) |
| 902 | 923 | goto end; |
| 903 | 924 | |
| @@ -922,13 +943,13 @@ static int m_can_rx_handler(struct net_device *dev, int quota) · 18 unmodified lines | ||
| 922 | 943 | } |
| 923 | 944 | } |
| 924 | 945 | |
| 925 | − psr = m_can_read(cdev, M_CAN_PSR); | |
| 926 | − | |
| 927 | 946 | if (irqstatus & IR_ERR_STATE) |
| 928 | − work_done += m_can_handle_state_errors(dev, psr); | |
| 947 | + work_done += m_can_handle_state_errors(dev, | |
| 948 | + m_can_read(cdev, M_CAN_PSR)); | |
| 929 | 949 | |
| 930 | 950 | if (irqstatus & IR_ERR_BUS_30X) |
| 931 | − work_done += m_can_handle_bus_errors(dev, irqstatus, psr); | |
| 951 | + work_done += m_can_handle_bus_errors(dev, irqstatus, | |
| 952 | + m_can_read(cdev, M_CAN_PSR)); | |
| 932 | 953 | |
| 933 | 954 | if (irqstatus & IR_RF0N) { |
| 934 | 955 | rx_work_or_err = m_can_do_rx_poll(dev, (quota - work_done)); |
| @@ -941,12 +962,12 @@ end: · 6 unmodified lines | ||
| 941 | 962 | return work_done; |
| 942 | 963 | } |
| 943 | 964 | |
| 944 | −static int m_can_rx_peripheral(struct net_device *dev) | |
| 965 | +static int m_can_rx_peripheral(struct net_device *dev, u32 irqstatus) | |
| 945 | 966 | { |
| 946 | 967 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 947 | 968 | int work_done; |
| 948 | 969 | |
| 949 | − work_done = m_can_rx_handler(dev, NAPI_POLL_WEIGHT); | |
| 970 | + work_done = m_can_rx_handler(dev, NAPI_POLL_WEIGHT, irqstatus); | |
| 950 | 971 | |
| 951 | 972 | /* Don't re-enable interrupts if the driver had a fatal error |
| 952 | 973 | * (e.g., FIFO read failure). |
| @@ -962,8 +983,11 @@ static int m_can_poll(struct napi_struct *napi, int quota) · 9 unmodified lines | ||
| 962 | 983 | struct net_device *dev = napi->dev; |
| 963 | 984 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 964 | 985 | int work_done; |
| 986 | + u32 irqstatus; | |
| 987 | + | |
| 988 | + irqstatus = cdev->irqstatus | m_can_read(cdev, M_CAN_IR); | |
| 965 | 989 | |
| 966 | − work_done = m_can_rx_handler(dev, quota); | |
| 990 | + work_done = m_can_rx_handler(dev, quota, irqstatus); | |
| 967 | 991 | |
| 968 | 992 | /* Don't re-enable interrupts if the driver had a fatal error |
| 969 | 993 | * (e.g., FIFO read failure). |
| @@ -1004,7 +1028,9 @@ static int m_can_echo_tx_event(struct net_device *dev) · 34 unmodified lines | ||
| 1004 | 1028 | u32 txe_count = 0; |
| 1005 | 1029 | u32 m_can_txefs; |
| 1006 | 1030 | u32 fgi = 0; |
| 1031 | + int ack_fgi = -1; | |
| 1007 | 1032 | int i = 0; |
| 1033 | + int err = 0; | |
| 1008 | 1034 | unsigned int msg_mark; |
| 1009 | 1035 | |
| 1010 | 1036 | struct m_can_classdev *cdev = netdev_priv(dev); |
| @@ -1014,34 +1040,34 @@ static int m_can_echo_tx_event(struct net_device *dev) · 3 unmodified lines | ||
| 1014 | 1040 | |
| 1015 | 1041 | /* Get Tx Event fifo element count */ |
| 1016 | 1042 | txe_count = FIELD_GET(TXEFS_EFFL_MASK, m_can_txefs); |
| 1043 | + fgi = FIELD_GET(TXEFS_EFGI_MASK, m_can_txefs); | |
| 1017 | 1044 | |
| 1018 | 1045 | /* Get and process all sent elements */ |
| 1019 | 1046 | for (i = 0; i < txe_count; i++) { |
| 1020 | 1047 | u32 txe, timestamp = 0; |
| 1021 | − int err; | |
| 1022 | − | |
| 1023 | − /* retrieve get index */ | |
| 1024 | − fgi = FIELD_GET(TXEFS_EFGI_MASK, m_can_read(cdev, M_CAN_TXEFS)); | |
| 1025 | 1048 | |
| 1026 | 1049 | /* get message marker, timestamp */ |
| 1027 | 1050 | err = m_can_txe_fifo_read(cdev, fgi, 4, &txe); |
| 1028 | 1051 | if (err) { |
| 1029 | 1052 | netdev_err(dev, "TXE FIFO read returned %d\n", err); |
| 1030 | − return err; | |
| 1053 | + break; | |
| 1031 | 1054 | } |
| 1032 | 1055 | |
| 1033 | 1056 | msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe); |
| 1034 | 1057 | timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16; |
| 1035 | 1058 | |
| 1036 | − /* ack txe element */ | |
| 1037 | − m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK, | |
| 1038 | − fgi)); | |
| 1059 | + ack_fgi = fgi; | |
| 1060 | + fgi = (++fgi >= cdev->mcfg[MRAM_TXE].num ? 0 : fgi); | |
| 1039 | 1061 | |
| 1040 | 1062 | /* update stats */ |
| 1041 | 1063 | m_can_tx_update_stats(cdev, msg_mark, timestamp); |
| 1042 | 1064 | } |
| 1043 | 1065 | |
| 1044 | − return 0; | |
| 1066 | + if (ack_fgi != -1) | |
| 1067 | + m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK, | |
| 1068 | + ack_fgi)); | |
| 1069 | + | |
| 1070 | + return err; | |
| 1045 | 1071 | } |
| 1046 | 1072 | |
| 1047 | 1073 | static irqreturn_t m_can_isr(int irq, void *dev_id) |
| @@ -1073,7 +1099,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) · 25 unmodified lines | ||
| 1073 | 1099 | m_can_disable_all_interrupts(cdev); |
| 1074 | 1100 | if (!cdev->is_peripheral) |
| 1075 | 1101 | napi_schedule(&cdev->napi); |
| 1076 | − else if (m_can_rx_peripheral(dev) < 0) | |
| 1102 | + else if (m_can_rx_peripheral(dev, ir) < 0) | |
| 1077 | 1103 | goto out_fail; |
| 1078 | 1104 | } |
| 1079 | 1105 | |
| @@ -1233,10 +1259,17 @@ static int m_can_set_bittiming(struct net_device *dev) · 153 unmodified lines | ||
| 1233 | 1259 | * - setup bittiming |
| 1234 | 1260 | * - configure timestamp generation |
| 1235 | 1261 | */ |
| 1236 | −static void m_can_chip_config(struct net_device *dev) | |
| 1262 | +static int m_can_chip_config(struct net_device *dev) | |
| 1237 | 1263 | { |
| 1238 | 1264 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 1239 | 1265 | u32 cccr, test; |
| 1266 | + int err; | |
| 1267 | + | |
| 1268 | + err = m_can_init_ram(cdev); | |
| 1269 | + if (err) { | |
| 1270 | + dev_err(cdev->dev, "Message RAM configuration failed\n"); | |
| 1271 | + return err; | |
| 1272 | + } | |
| 1240 | 1273 | |
| 1241 | 1274 | m_can_config_endisable(cdev, true); |
| 1242 | 1275 | |
| @@ -1360,18 +1393,25 @@ static void m_can_chip_config(struct net_device *dev) · 117 unmodified lines | ||
| 1360 | 1393 | |
| 1361 | 1394 | if (cdev->ops->init) |
| 1362 | 1395 | cdev->ops->init(cdev); |
| 1396 | + | |
| 1397 | + return 0; | |
| 1363 | 1398 | } |
| 1364 | 1399 | |
| 1365 | −static void m_can_start(struct net_device *dev) | |
| 1400 | +static int m_can_start(struct net_device *dev) | |
| 1366 | 1401 | { |
| 1367 | 1402 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 1403 | + int ret; | |
| 1368 | 1404 | |
| 1369 | 1405 | /* basic m_can configuration */ |
| 1370 | − m_can_chip_config(dev); | |
| 1406 | + ret = m_can_chip_config(dev); | |
| 1407 | + if (ret) | |
| 1408 | + return ret; | |
| 1371 | 1409 | |
| 1372 | 1410 | cdev->can.state = CAN_STATE_ERROR_ACTIVE; |
| 1373 | 1411 | |
| 1374 | 1412 | m_can_enable_all_interrupts(cdev); |
| 1413 | + | |
| 1414 | + return 0; | |
| 1375 | 1415 | } |
| 1376 | 1416 | |
| 1377 | 1417 | static int m_can_set_mode(struct net_device *dev, enum can_mode mode) |
| @@ -1585,6 +1625,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) · 207 unmodified lines | ||
| 1585 | 1625 | struct sk_buff *skb = cdev->tx_skb; |
| 1586 | 1626 | struct id_and_dlc fifo_header; |
| 1587 | 1627 | u32 cccr, fdflags; |
| 1628 | + u32 txfqs; | |
| 1588 | 1629 | int err; |
| 1589 | 1630 | int putidx; |
| 1590 | 1631 | |
| @@ -1641,8 +1682,10 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) · 50 unmodified lines | ||
| 1641 | 1682 | } else { |
| 1642 | 1683 | /* Transmit routine for version >= v3.1.x */ |
| 1643 | 1684 | |
| 1685 | + txfqs = m_can_read(cdev, M_CAN_TXFQS); | |
| 1686 | + | |
| 1644 | 1687 | /* Check if FIFO full */ |
| 1645 | − if (m_can_tx_fifo_full(cdev)) { | |
| 1688 | + if (_m_can_tx_fifo_full(txfqs)) { | |
| 1646 | 1689 | /* This shouldn't happen */ |
| 1647 | 1690 | netif_stop_queue(dev); |
| 1648 | 1691 | netdev_warn(dev, |
| @@ -1658,8 +1701,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) · 9 unmodified lines | ||
| 1658 | 1701 | } |
| 1659 | 1702 | |
| 1660 | 1703 | /* get put index for frame */ |
| 1661 | − putidx = FIELD_GET(TXFQS_TFQPI_MASK, | |
| 1662 | − m_can_read(cdev, M_CAN_TXFQS)); | |
| 1704 | + putidx = FIELD_GET(TXFQS_TFQPI_MASK, txfqs); | |
| 1663 | 1705 | |
| 1664 | 1706 | /* Construct DLC Field, with CAN-FD configuration. |
| 1665 | 1707 | * Use the put index of the fifo as the message marker, |
| @@ -1799,7 +1841,9 @@ static int m_can_open(struct net_device *dev) · 133 unmodified lines | ||
| 1799 | 1841 | } |
| 1800 | 1842 | |
| 1801 | 1843 | /* start the m_can controller */ |
| 1802 | − m_can_start(dev); | |
| 1844 | + err = m_can_start(dev); | |
| 1845 | + if (err) | |
| 1846 | + goto exit_irq_fail; | |
| 1803 | 1847 | |
| 1804 | 1848 | if (!cdev->is_peripheral) |
| 1805 | 1849 | napi_enable(&cdev->napi); |
| @@ -2058,9 +2102,13 @@ int m_can_class_resume(struct device *dev) · 252 unmodified lines | ||
| 2058 | 2102 | ret = m_can_clk_start(cdev); |
| 2059 | 2103 | if (ret) |
| 2060 | 2104 | return ret; |
| 2105 | + ret = m_can_start(ndev); | |
| 2106 | + if (ret) { | |
| 2107 | + m_can_clk_stop(cdev); | |
| 2108 | + | |
| 2109 | + return ret; | |
| 2110 | + } | |
| 2061 | 2111 | |
| 2062 | − m_can_init_ram(cdev); | |
| 2063 | − m_can_start(ndev); | |
| 2064 | 2112 | netif_device_attach(ndev); |
| 2065 | 2113 | netif_start_queue(ndev); |
| 2066 | 2114 | } |
| @@ -7,27 +7,27 @@ · 6 unmodified lines | ||
| 7 | 7 | #define _CAN_M_CAN_H_ |
| 8 | 8 | |
| 9 | 9 | #include <linux/can/core.h> |
| 10 | +#include <linux/can/dev.h> | |
| 10 | 11 | #include <linux/can/rx-offload.h> |
| 12 | +#include <linux/clk.h> | |
| 11 | 13 | #include <linux/completion.h> |
| 14 | +#include <linux/delay.h> | |
| 12 | 15 | #include <linux/device.h> |
| 13 | 16 | #include <linux/dma-mapping.h> |
| 14 | 17 | #include <linux/freezer.h> |
| 15 | −#include <linux/slab.h> | |
| 16 | −#include <linux/uaccess.h> | |
| 17 | −#include <linux/clk.h> | |
| 18 | −#include <linux/delay.h> | |
| 19 | 18 | #include <linux/interrupt.h> |
| 20 | 19 | #include <linux/io.h> |
| 20 | +#include <linux/iopoll.h> | |
| 21 | 21 | #include <linux/kernel.h> |
| 22 | 22 | #include <linux/module.h> |
| 23 | 23 | #include <linux/netdevice.h> |
| 24 | 24 | #include <linux/of.h> |
| 25 | 25 | #include <linux/of_device.h> |
| 26 | −#include <linux/pm_runtime.h> | |
| 27 | −#include <linux/iopoll.h> | |
| 28 | −#include <linux/can/dev.h> | |
| 29 | −#include <linux/pinctrl/consumer.h> | |
| 30 | 26 | #include <linux/phy/phy.h> |
| 27 | +#include <linux/pinctrl/consumer.h> | |
| 28 | +#include <linux/pm_runtime.h> | |
| 29 | +#include <linux/slab.h> | |
| 30 | +#include <linux/uaccess.h> | |
| 31 | 31 | |
| 32 | 32 | /* m_can lec values */ |
| 33 | 33 | enum m_can_lec_type { |
| @@ -38,7 +38,7 @@ enum m_can_lec_type { · 4 unmodified lines | ||
| 38 | 38 | LEC_BIT1_ERROR, |
| 39 | 39 | LEC_BIT0_ERROR, |
| 40 | 40 | LEC_CRC_ERROR, |
| 41 | − LEC_UNUSED, | |
| 41 | + LEC_NO_CHANGE, | |
| 42 | 42 | }; |
| 43 | 43 | |
| 44 | 44 | enum m_can_mram_cfg { |
| @@ -5,8 +5,8 @@ · 4 unmodified lines | ||
| 5 | 5 | // |
| 6 | 6 | // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ |
| 7 | 7 | |
| 8 | −#include <linux/platform_device.h> | |
| 9 | 8 | #include <linux/phy/phy.h> |
| 9 | +#include <linux/platform_device.h> | |
| 10 | 10 | |
| 11 | 11 | #include "m_can.h" |
| 12 | 12 | |
| @@ -140,10 +140,6 @@ static int m_can_plat_probe(struct platform_device *pdev) · 127 unmodified lines | ||
| 140 | 140 | |
| 141 | 141 | platform_set_drvdata(pdev, mcan_class); |
| 142 | 142 | |
| 143 | − ret = m_can_init_ram(mcan_class); | |
| 144 | − if (ret) | |
| 145 | − goto probe_fail; | |
| 146 | − | |
| 147 | 143 | pm_runtime_enable(mcan_class->dev); |
| 148 | 144 | ret = m_can_class_register(mcan_class); |
| 149 | 145 | if (ret) |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #define TCAN4X5X_DEV_ID1 0x04 |
| 11 | 11 | #define TCAN4X5X_REV 0x08 |
| 12 | 12 | #define TCAN4X5X_STATUS 0x0C |
| 13 | −#define TCAN4X5X_ERROR_STATUS 0x10 | |
| 13 | +#define TCAN4X5X_ERROR_STATUS_MASK 0x10 | |
| 14 | 14 | #define TCAN4X5X_CONTROL 0x14 |
| 15 | 15 | |
| 16 | 16 | #define TCAN4X5X_CONFIG 0x800 |
| @@ -204,17 +204,7 @@ static int tcan4x5x_clear_interrupts(struct m_can_classdev *cdev) · 187 unmodified lines | ||
| 204 | 204 | if (ret) |
| 205 | 205 | return ret; |
| 206 | 206 | |
| 207 | − ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_MCAN_INT_REG, | |
| 208 | − TCAN4X5X_ENABLE_MCAN_INT); | |
| 209 | − if (ret) | |
| 210 | − return ret; | |
| 211 | − | |
| 212 | − ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_FLAGS, | |
| 213 | − TCAN4X5X_CLEAR_ALL_INT); | |
| 214 | − if (ret) | |
| 215 | − return ret; | |
| 216 | − | |
| 217 | − return tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS, | |
| 207 | + return tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_FLAGS, | |
| 218 | 208 | TCAN4X5X_CLEAR_ALL_INT); |
| 219 | 209 | } |
| 220 | 210 | |
| @@ -234,8 +224,8 @@ static int tcan4x5x_init(struct m_can_classdev *cdev) · 13 unmodified lines | ||
| 234 | 224 | if (ret) |
| 235 | 225 | return ret; |
| 236 | 226 | |
| 237 | − /* Zero out the MCAN buffers */ | |
| 238 | − ret = m_can_init_ram(cdev); | |
| 227 | + ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS_MASK, | |
| 228 | + TCAN4X5X_CLEAR_ALL_INT); | |
| 239 | 229 | if (ret) |
| 240 | 230 | return ret; |
| 241 | 231 | |
| @@ -90,16 +90,47 @@ static int tcan4x5x_regmap_read(void *context, · 89 unmodified lines | ||
| 90 | 90 | return 0; |
| 91 | 91 | } |
| 92 | 92 | |
| 93 | −static const struct regmap_range tcan4x5x_reg_table_yes_range[] = { | |
| 94 | − regmap_reg_range(0x0000, 0x002c), /* Device ID and SPI Registers */ | |
| 95 | − regmap_reg_range(0x0800, 0x083c), /* Device configuration registers and Interrupt Flags*/ | |
| 93 | +static const struct regmap_range tcan4x5x_reg_table_wr_range[] = { | |
| 94 | + /* Device ID and SPI Registers */ | |
| 95 | + regmap_reg_range(0x000c, 0x0010), | |
| 96 | + /* Device configuration registers and Interrupt Flags*/ | |
| 97 | + regmap_reg_range(0x0800, 0x080c), | |
| 98 | + regmap_reg_range(0x0814, 0x0814), | |
| 99 | + regmap_reg_range(0x0820, 0x0820), | |
| 100 | + regmap_reg_range(0x0830, 0x0830), | |
| 101 | + /* M_CAN */ | |
| 102 | + regmap_reg_range(0x100c, 0x102c), | |
| 103 | + regmap_reg_range(0x1048, 0x1048), | |
| 104 | + regmap_reg_range(0x1050, 0x105c), | |
| 105 | + regmap_reg_range(0x1080, 0x1088), | |
| 106 | + regmap_reg_range(0x1090, 0x1090), | |
| 107 | + regmap_reg_range(0x1098, 0x10a0), | |
| 108 | + regmap_reg_range(0x10a8, 0x10b0), | |
| 109 | + regmap_reg_range(0x10b8, 0x10c0), | |
| 110 | + regmap_reg_range(0x10c8, 0x10c8), | |
| 111 | + regmap_reg_range(0x10d0, 0x10d4), | |
| 112 | + regmap_reg_range(0x10e0, 0x10e4), | |
| 113 | + regmap_reg_range(0x10f0, 0x10f0), | |
| 114 | + regmap_reg_range(0x10f8, 0x10f8), | |
| 115 | + /* MRAM */ | |
| 116 | + regmap_reg_range(0x8000, 0x87fc), | |
| 117 | +}; | |
| 118 | + | |
| 119 | +static const struct regmap_range tcan4x5x_reg_table_rd_range[] = { | |
| 120 | + regmap_reg_range(0x0000, 0x0010), /* Device ID and SPI Registers */ | |
| 121 | + regmap_reg_range(0x0800, 0x0830), /* Device configuration registers and Interrupt Flags*/ | |
| 96 | 122 | regmap_reg_range(0x1000, 0x10fc), /* M_CAN */ |
| 97 | 123 | regmap_reg_range(0x8000, 0x87fc), /* MRAM */ |
| 98 | 124 | }; |
| 99 | 125 | |
| 100 | −static const struct regmap_access_table tcan4x5x_reg_table = { | |
| 101 | − .yes_ranges = tcan4x5x_reg_table_yes_range, | |
| 102 | − .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_yes_range), | |
| 126 | +static const struct regmap_access_table tcan4x5x_reg_table_wr = { | |
| 127 | + .yes_ranges = tcan4x5x_reg_table_wr_range, | |
| 128 | + .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_wr_range), | |
| 129 | +}; | |
| 130 | + | |
| 131 | +static const struct regmap_access_table tcan4x5x_reg_table_rd = { | |
| 132 | + .yes_ranges = tcan4x5x_reg_table_rd_range, | |
| 133 | + .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_rd_range), | |
| 103 | 134 | }; |
| 104 | 135 | |
| 105 | 136 | static const struct regmap_config tcan4x5x_regmap = { |
| @@ -107,8 +138,8 @@ static const struct regmap_config tcan4x5x_regmap = { · 1 unmodified line | ||
| 107 | 138 | .reg_stride = 4, |
| 108 | 139 | .pad_bits = 8, |
| 109 | 140 | .val_bits = 32, |
| 110 | − .wr_table = &tcan4x5x_reg_table, | |
| 111 | − .rd_table = &tcan4x5x_reg_table, | |
| 141 | + .wr_table = &tcan4x5x_reg_table_wr, | |
| 142 | + .rd_table = &tcan4x5x_reg_table_rd, | |
| 112 | 143 | .max_register = TCAN4X5X_MAX_REGISTER, |
| 113 | 144 | .cache_type = REGCACHE_NONE, |
| 114 | 145 | .read_flag_mask = (__force unsigned long) |
| @@ -1,1249 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (C) 1999 - 2010 Intel Corporation. | |
| 4 | − * Copyright (C) 2010 LAPIS SEMICONDUCTOR CO., LTD. | |
| 5 | − */ | |
| 6 | − | |
| 7 | −#include <linux/interrupt.h> | |
| 8 | −#include <linux/delay.h> | |
| 9 | −#include <linux/ethtool.h> | |
| 10 | −#include <linux/io.h> | |
| 11 | −#include <linux/module.h> | |
| 12 | −#include <linux/sched.h> | |
| 13 | −#include <linux/pci.h> | |
| 14 | −#include <linux/kernel.h> | |
| 15 | −#include <linux/types.h> | |
| 16 | −#include <linux/errno.h> | |
| 17 | −#include <linux/netdevice.h> | |
| 18 | −#include <linux/skbuff.h> | |
| 19 | −#include <linux/can.h> | |
| 20 | −#include <linux/can/dev.h> | |
| 21 | −#include <linux/can/error.h> | |
| 22 | − | |
| 23 | −#define PCH_CTRL_INIT BIT(0) /* The INIT bit of CANCONT register. */ | |
| 24 | −#define PCH_CTRL_IE BIT(1) /* The IE bit of CAN control register */ | |
| 25 | −#define PCH_CTRL_IE_SIE_EIE (BIT(3) | BIT(2) | BIT(1)) | |
| 26 | −#define PCH_CTRL_CCE BIT(6) | |
| 27 | −#define PCH_CTRL_OPT BIT(7) /* The OPT bit of CANCONT register. */ | |
| 28 | −#define PCH_OPT_SILENT BIT(3) /* The Silent bit of CANOPT reg. */ | |
| 29 | −#define PCH_OPT_LBACK BIT(4) /* The LoopBack bit of CANOPT reg. */ | |
| 30 | − | |
| 31 | −#define PCH_CMASK_RX_TX_SET 0x00f3 | |
| 32 | −#define PCH_CMASK_RX_TX_GET 0x0073 | |
| 33 | −#define PCH_CMASK_ALL 0xff | |
| 34 | −#define PCH_CMASK_NEWDAT BIT(2) | |
| 35 | −#define PCH_CMASK_CLRINTPND BIT(3) | |
| 36 | −#define PCH_CMASK_CTRL BIT(4) | |
| 37 | −#define PCH_CMASK_ARB BIT(5) | |
| 38 | −#define PCH_CMASK_MASK BIT(6) | |
| 39 | −#define PCH_CMASK_RDWR BIT(7) | |
| 40 | −#define PCH_IF_MCONT_NEWDAT BIT(15) | |
| 41 | −#define PCH_IF_MCONT_MSGLOST BIT(14) | |
| 42 | −#define PCH_IF_MCONT_INTPND BIT(13) | |
| 43 | −#define PCH_IF_MCONT_UMASK BIT(12) | |
| 44 | −#define PCH_IF_MCONT_TXIE BIT(11) | |
| 45 | −#define PCH_IF_MCONT_RXIE BIT(10) | |
| 46 | −#define PCH_IF_MCONT_RMTEN BIT(9) | |
| 47 | −#define PCH_IF_MCONT_TXRQXT BIT(8) | |
| 48 | −#define PCH_IF_MCONT_EOB BIT(7) | |
| 49 | −#define PCH_IF_MCONT_DLC (BIT(0) | BIT(1) | BIT(2) | BIT(3)) | |
| 50 | −#define PCH_MASK2_MDIR_MXTD (BIT(14) | BIT(15)) | |
| 51 | −#define PCH_ID2_DIR BIT(13) | |
| 52 | −#define PCH_ID2_XTD BIT(14) | |
| 53 | −#define PCH_ID_MSGVAL BIT(15) | |
| 54 | −#define PCH_IF_CREQ_BUSY BIT(15) | |
| 55 | − | |
| 56 | −#define PCH_STATUS_INT 0x8000 | |
| 57 | −#define PCH_RP 0x00008000 | |
| 58 | −#define PCH_REC 0x00007f00 | |
| 59 | −#define PCH_TEC 0x000000ff | |
| 60 | − | |
| 61 | −#define PCH_TX_OK BIT(3) | |
| 62 | −#define PCH_RX_OK BIT(4) | |
| 63 | −#define PCH_EPASSIV BIT(5) | |
| 64 | −#define PCH_EWARN BIT(6) | |
| 65 | −#define PCH_BUS_OFF BIT(7) | |
| 66 | − | |
| 67 | −/* bit position of certain controller bits. */ | |
| 68 | −#define PCH_BIT_BRP_SHIFT 0 | |
| 69 | −#define PCH_BIT_SJW_SHIFT 6 | |
| 70 | −#define PCH_BIT_TSEG1_SHIFT 8 | |
| 71 | −#define PCH_BIT_TSEG2_SHIFT 12 | |
| 72 | −#define PCH_BIT_BRPE_BRPE_SHIFT 6 | |
| 73 | − | |
| 74 | −#define PCH_MSK_BITT_BRP 0x3f | |
| 75 | −#define PCH_MSK_BRPE_BRPE 0x3c0 | |
| 76 | −#define PCH_MSK_CTRL_IE_SIE_EIE 0x07 | |
| 77 | −#define PCH_COUNTER_LIMIT 10 | |
| 78 | − | |
| 79 | −#define PCH_CAN_CLK 50000000 /* 50MHz */ | |
| 80 | − | |
| 81 | −/* | |
| 82 | − * Define the number of message object. | |
| 83 | − * PCH CAN communications are done via Message RAM. | |
| 84 | − * The Message RAM consists of 32 message objects. | |
| 85 | − */ | |
| 86 | −#define PCH_RX_OBJ_NUM 26 | |
| 87 | −#define PCH_TX_OBJ_NUM 6 | |
| 88 | −#define PCH_RX_OBJ_START 1 | |
| 89 | −#define PCH_RX_OBJ_END PCH_RX_OBJ_NUM | |
| 90 | −#define PCH_TX_OBJ_START (PCH_RX_OBJ_END + 1) | |
| 91 | −#define PCH_TX_OBJ_END (PCH_RX_OBJ_NUM + PCH_TX_OBJ_NUM) | |
| 92 | − | |
| 93 | −#define PCH_FIFO_THRESH 16 | |
| 94 | − | |
| 95 | −/* TxRqst2 show status of MsgObjNo.17~32 */ | |
| 96 | −#define PCH_TREQ2_TX_MASK (((1 << PCH_TX_OBJ_NUM) - 1) <<\ | |
| 97 | − (PCH_RX_OBJ_END - 16)) | |
| 98 | − | |
| 99 | −enum pch_ifreg { | |
| 100 | − PCH_RX_IFREG, | |
| 101 | − PCH_TX_IFREG, | |
| 102 | −}; | |
| 103 | − | |
| 104 | −enum pch_can_err { | |
| 105 | − PCH_STUF_ERR = 1, | |
| 106 | − PCH_FORM_ERR, | |
| 107 | − PCH_ACK_ERR, | |
| 108 | − PCH_BIT1_ERR, | |
| 109 | − PCH_BIT0_ERR, | |
| 110 | − PCH_CRC_ERR, | |
| 111 | − PCH_LEC_ALL, | |
| 112 | −}; | |
| 113 | − | |
| 114 | −enum pch_can_mode { | |
| 115 | − PCH_CAN_ENABLE, | |
| 116 | − PCH_CAN_DISABLE, | |
| 117 | − PCH_CAN_ALL, | |
| 118 | − PCH_CAN_NONE, | |
| 119 | − PCH_CAN_STOP, | |
| 120 | − PCH_CAN_RUN, | |
| 121 | −}; | |
| 122 | − | |
| 123 | −struct pch_can_if_regs { | |
| 124 | − u32 creq; | |
| 125 | − u32 cmask; | |
| 126 | − u32 mask1; | |
| 127 | − u32 mask2; | |
| 128 | − u32 id1; | |
| 129 | − u32 id2; | |
| 130 | − u32 mcont; | |
| 131 | − u32 data[4]; | |
| 132 | − u32 rsv[13]; | |
| 133 | −}; | |
| 134 | − | |
| 135 | −struct pch_can_regs { | |
| 136 | − u32 cont; | |
| 137 | − u32 stat; | |
| 138 | − u32 errc; | |
| 139 | − u32 bitt; | |
| 140 | − u32 intr; | |
| 141 | − u32 opt; | |
| 142 | − u32 brpe; | |
| 143 | − u32 reserve; | |
| 144 | − struct pch_can_if_regs ifregs[2]; /* [0]=if1 [1]=if2 */ | |
| 145 | − u32 reserve1[8]; | |
| 146 | − u32 treq1; | |
| 147 | − u32 treq2; | |
| 148 | − u32 reserve2[6]; | |
| 149 | − u32 data1; | |
| 150 | − u32 data2; | |
| 151 | − u32 reserve3[6]; | |
| 152 | − u32 canipend1; | |
| 153 | − u32 canipend2; | |
| 154 | − u32 reserve4[6]; | |
| 155 | − u32 canmval1; | |
| 156 | − u32 canmval2; | |
| 157 | − u32 reserve5[37]; | |
| 158 | − u32 srst; | |
| 159 | −}; | |
| 160 | − | |
| 161 | −struct pch_can_priv { | |
| 162 | − struct can_priv can; | |
| 163 | − struct pci_dev *dev; | |
| 164 | − u32 tx_enable[PCH_TX_OBJ_END]; | |
| 165 | − u32 rx_enable[PCH_TX_OBJ_END]; | |
| 166 | − u32 rx_link[PCH_TX_OBJ_END]; | |
| 167 | − u32 int_enables; | |
| 168 | − struct net_device *ndev; | |
| 169 | − struct pch_can_regs __iomem *regs; | |
| 170 | − struct napi_struct napi; | |
| 171 | − int tx_obj; /* Point next Tx Obj index */ | |
| 172 | − int use_msi; | |
| 173 | −}; | |
| 174 | − | |
| 175 | −static const struct can_bittiming_const pch_can_bittiming_const = { | |
| 176 | − .name = KBUILD_MODNAME, | |
| 177 | − .tseg1_min = 2, | |
| 178 | − .tseg1_max = 16, | |
| 179 | − .tseg2_min = 1, | |
| 180 | − .tseg2_max = 8, | |
| 181 | − .sjw_max = 4, | |
| 182 | − .brp_min = 1, | |
| 183 | − .brp_max = 1024, /* 6bit + extended 4bit */ | |
| 184 | − .brp_inc = 1, | |
| 185 | −}; | |
| 186 | − | |
| 187 | −static const struct pci_device_id pch_pci_tbl[] = { | |
| 188 | − {PCI_VENDOR_ID_INTEL, 0x8818, PCI_ANY_ID, PCI_ANY_ID,}, | |
| 189 | − {0,} | |
| 190 | −}; | |
| 191 | −MODULE_DEVICE_TABLE(pci, pch_pci_tbl); | |
| 192 | − | |
| 193 | −static inline void pch_can_bit_set(void __iomem *addr, u32 mask) | |
| 194 | −{ | |
| 195 | − iowrite32(ioread32(addr) | mask, addr); | |
| 196 | −} | |
| 197 | − | |
| 198 | −static inline void pch_can_bit_clear(void __iomem *addr, u32 mask) | |
| 199 | −{ | |
| 200 | − iowrite32(ioread32(addr) & ~mask, addr); | |
| 201 | −} | |
| 202 | − | |
| 203 | −static void pch_can_set_run_mode(struct pch_can_priv *priv, | |
| 204 | − enum pch_can_mode mode) | |
| 205 | −{ | |
| 206 | − switch (mode) { | |
| 207 | − case PCH_CAN_RUN: | |
| 208 | − pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_INIT); | |
| 209 | − break; | |
| 210 | − | |
| 211 | − case PCH_CAN_STOP: | |
| 212 | − pch_can_bit_set(&priv->regs->cont, PCH_CTRL_INIT); | |
| 213 | − break; | |
| 214 | − | |
| 215 | − default: | |
| 216 | − netdev_err(priv->ndev, "%s -> Invalid Mode.\n", __func__); | |
| 217 | − break; | |
| 218 | − } | |
| 219 | −} | |
| 220 | − | |
| 221 | −static void pch_can_set_optmode(struct pch_can_priv *priv) | |
| 222 | −{ | |
| 223 | − u32 reg_val = ioread32(&priv->regs->opt); | |
| 224 | − | |
| 225 | − if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) | |
| 226 | − reg_val |= PCH_OPT_SILENT; | |
| 227 | − | |
| 228 | − if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) | |
| 229 | − reg_val |= PCH_OPT_LBACK; | |
| 230 | − | |
| 231 | − pch_can_bit_set(&priv->regs->cont, PCH_CTRL_OPT); | |
| 232 | − iowrite32(reg_val, &priv->regs->opt); | |
| 233 | −} | |
| 234 | − | |
| 235 | −static void pch_can_rw_msg_obj(void __iomem *creq_addr, u32 num) | |
| 236 | −{ | |
| 237 | − int counter = PCH_COUNTER_LIMIT; | |
| 238 | − u32 ifx_creq; | |
| 239 | − | |
| 240 | − iowrite32(num, creq_addr); | |
| 241 | − while (counter) { | |
| 242 | − ifx_creq = ioread32(creq_addr) & PCH_IF_CREQ_BUSY; | |
| 243 | − if (!ifx_creq) | |
| 244 | − break; | |
| 245 | − counter--; | |
| 246 | − udelay(1); | |
| 247 | − } | |
| 248 | − if (!counter) | |
| 249 | − pr_err("%s:IF1 BUSY Flag is set forever.\n", __func__); | |
| 250 | −} | |
| 251 | − | |
| 252 | −static void pch_can_set_int_enables(struct pch_can_priv *priv, | |
| 253 | − enum pch_can_mode interrupt_no) | |
| 254 | −{ | |
| 255 | − switch (interrupt_no) { | |
| 256 | − case PCH_CAN_DISABLE: | |
| 257 | − pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE); | |
| 258 | − break; | |
| 259 | − | |
| 260 | − case PCH_CAN_ALL: | |
| 261 | − pch_can_bit_set(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); | |
| 262 | − break; | |
| 263 | − | |
| 264 | − case PCH_CAN_NONE: | |
| 265 | − pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); | |
| 266 | − break; | |
| 267 | − | |
| 268 | − default: | |
| 269 | − netdev_err(priv->ndev, "Invalid interrupt number.\n"); | |
| 270 | − break; | |
| 271 | − } | |
| 272 | −} | |
| 273 | − | |
| 274 | −static void pch_can_set_rxtx(struct pch_can_priv *priv, u32 buff_num, | |
| 275 | − int set, enum pch_ifreg dir) | |
| 276 | −{ | |
| 277 | − u32 ie; | |
| 278 | − | |
| 279 | − if (dir) | |
| 280 | − ie = PCH_IF_MCONT_TXIE; | |
| 281 | − else | |
| 282 | − ie = PCH_IF_MCONT_RXIE; | |
| 283 | − | |
| 284 | − /* Reading the Msg buffer from Message RAM to IF1/2 registers. */ | |
| 285 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask); | |
| 286 | − pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num); | |
| 287 | − | |
| 288 | − /* Setting the IF1/2MASK1 register to access MsgVal and RxIE bits */ | |
| 289 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_ARB | PCH_CMASK_CTRL, | |
| 290 | − &priv->regs->ifregs[dir].cmask); | |
| 291 | − | |
| 292 | − if (set) { | |
| 293 | − /* Setting the MsgVal and RxIE/TxIE bits */ | |
| 294 | − pch_can_bit_set(&priv->regs->ifregs[dir].mcont, ie); | |
| 295 | − pch_can_bit_set(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL); | |
| 296 | − } else { | |
| 297 | − /* Clearing the MsgVal and RxIE/TxIE bits */ | |
| 298 | − pch_can_bit_clear(&priv->regs->ifregs[dir].mcont, ie); | |
| 299 | − pch_can_bit_clear(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL); | |
| 300 | − } | |
| 301 | − | |
| 302 | − pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num); | |
| 303 | −} | |
| 304 | − | |
| 305 | −static void pch_can_set_rx_all(struct pch_can_priv *priv, int set) | |
| 306 | −{ | |
| 307 | − int i; | |
| 308 | − | |
| 309 | − /* Traversing to obtain the object configured as receivers. */ | |
| 310 | − for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) | |
| 311 | − pch_can_set_rxtx(priv, i, set, PCH_RX_IFREG); | |
| 312 | −} | |
| 313 | − | |
| 314 | −static void pch_can_set_tx_all(struct pch_can_priv *priv, int set) | |
| 315 | −{ | |
| 316 | − int i; | |
| 317 | − | |
| 318 | − /* Traversing to obtain the object configured as transmit object. */ | |
| 319 | − for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) | |
| 320 | − pch_can_set_rxtx(priv, i, set, PCH_TX_IFREG); | |
| 321 | −} | |
| 322 | − | |
| 323 | −static u32 pch_can_int_pending(struct pch_can_priv *priv) | |
| 324 | −{ | |
| 325 | − return ioread32(&priv->regs->intr) & 0xffff; | |
| 326 | −} | |
| 327 | − | |
| 328 | −static void pch_can_clear_if_buffers(struct pch_can_priv *priv) | |
| 329 | −{ | |
| 330 | − int i; /* Msg Obj ID (1~32) */ | |
| 331 | − | |
| 332 | − for (i = PCH_RX_OBJ_START; i <= PCH_TX_OBJ_END; i++) { | |
| 333 | − iowrite32(PCH_CMASK_RX_TX_SET, &priv->regs->ifregs[0].cmask); | |
| 334 | − iowrite32(0xffff, &priv->regs->ifregs[0].mask1); | |
| 335 | − iowrite32(0xffff, &priv->regs->ifregs[0].mask2); | |
| 336 | − iowrite32(0x0, &priv->regs->ifregs[0].id1); | |
| 337 | − iowrite32(0x0, &priv->regs->ifregs[0].id2); | |
| 338 | − iowrite32(0x0, &priv->regs->ifregs[0].mcont); | |
| 339 | − iowrite32(0x0, &priv->regs->ifregs[0].data[0]); | |
| 340 | − iowrite32(0x0, &priv->regs->ifregs[0].data[1]); | |
| 341 | − iowrite32(0x0, &priv->regs->ifregs[0].data[2]); | |
| 342 | − iowrite32(0x0, &priv->regs->ifregs[0].data[3]); | |
| 343 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | | |
| 344 | − PCH_CMASK_ARB | PCH_CMASK_CTRL, | |
| 345 | − &priv->regs->ifregs[0].cmask); | |
| 346 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i); | |
| 347 | − } | |
| 348 | −} | |
| 349 | − | |
| 350 | −static void pch_can_config_rx_tx_buffers(struct pch_can_priv *priv) | |
| 351 | −{ | |
| 352 | − int i; | |
| 353 | − | |
| 354 | − for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) { | |
| 355 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); | |
| 356 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i); | |
| 357 | − | |
| 358 | − iowrite32(0x0, &priv->regs->ifregs[0].id1); | |
| 359 | − iowrite32(0x0, &priv->regs->ifregs[0].id2); | |
| 360 | − | |
| 361 | − pch_can_bit_set(&priv->regs->ifregs[0].mcont, | |
| 362 | − PCH_IF_MCONT_UMASK); | |
| 363 | − | |
| 364 | − /* In case FIFO mode, Last EoB of Rx Obj must be 1 */ | |
| 365 | − if (i == PCH_RX_OBJ_END) | |
| 366 | − pch_can_bit_set(&priv->regs->ifregs[0].mcont, | |
| 367 | − PCH_IF_MCONT_EOB); | |
| 368 | − else | |
| 369 | − pch_can_bit_clear(&priv->regs->ifregs[0].mcont, | |
| 370 | − PCH_IF_MCONT_EOB); | |
| 371 | − | |
| 372 | − iowrite32(0, &priv->regs->ifregs[0].mask1); | |
| 373 | − pch_can_bit_clear(&priv->regs->ifregs[0].mask2, | |
| 374 | − 0x1fff | PCH_MASK2_MDIR_MXTD); | |
| 375 | − | |
| 376 | − /* Setting CMASK for writing */ | |
| 377 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB | | |
| 378 | − PCH_CMASK_CTRL, &priv->regs->ifregs[0].cmask); | |
| 379 | − | |
| 380 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i); | |
| 381 | − } | |
| 382 | − | |
| 383 | − for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) { | |
| 384 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[1].cmask); | |
| 385 | − pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i); | |
| 386 | − | |
| 387 | − /* Resetting DIR bit for reception */ | |
| 388 | − iowrite32(0x0, &priv->regs->ifregs[1].id1); | |
| 389 | − iowrite32(PCH_ID2_DIR, &priv->regs->ifregs[1].id2); | |
| 390 | − | |
| 391 | − /* Setting EOB bit for transmitter */ | |
| 392 | − iowrite32(PCH_IF_MCONT_EOB | PCH_IF_MCONT_UMASK, | |
| 393 | − &priv->regs->ifregs[1].mcont); | |
| 394 | − | |
| 395 | − iowrite32(0, &priv->regs->ifregs[1].mask1); | |
| 396 | − pch_can_bit_clear(&priv->regs->ifregs[1].mask2, 0x1fff); | |
| 397 | − | |
| 398 | − /* Setting CMASK for writing */ | |
| 399 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB | | |
| 400 | − PCH_CMASK_CTRL, &priv->regs->ifregs[1].cmask); | |
| 401 | − | |
| 402 | − pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i); | |
| 403 | − } | |
| 404 | −} | |
| 405 | − | |
| 406 | −static void pch_can_init(struct pch_can_priv *priv) | |
| 407 | −{ | |
| 408 | − /* Stopping the Can device. */ | |
| 409 | − pch_can_set_run_mode(priv, PCH_CAN_STOP); | |
| 410 | − | |
| 411 | − /* Clearing all the message object buffers. */ | |
| 412 | − pch_can_clear_if_buffers(priv); | |
| 413 | − | |
| 414 | − /* Configuring the respective message object as either rx/tx object. */ | |
| 415 | − pch_can_config_rx_tx_buffers(priv); | |
| 416 | − | |
| 417 | − /* Enabling the interrupts. */ | |
| 418 | − pch_can_set_int_enables(priv, PCH_CAN_ALL); | |
| 419 | −} | |
| 420 | − | |
| 421 | −static void pch_can_release(struct pch_can_priv *priv) | |
| 422 | −{ | |
| 423 | − /* Stooping the CAN device. */ | |
| 424 | − pch_can_set_run_mode(priv, PCH_CAN_STOP); | |
| 425 | − | |
| 426 | − /* Disabling the interrupts. */ | |
| 427 | − pch_can_set_int_enables(priv, PCH_CAN_NONE); | |
| 428 | − | |
| 429 | − /* Disabling all the receive object. */ | |
| 430 | − pch_can_set_rx_all(priv, 0); | |
| 431 | − | |
| 432 | − /* Disabling all the transmit object. */ | |
| 433 | − pch_can_set_tx_all(priv, 0); | |
| 434 | −} | |
| 435 | − | |
| 436 | −/* This function clears interrupt(s) from the CAN device. */ | |
| 437 | −static void pch_can_int_clr(struct pch_can_priv *priv, u32 mask) | |
| 438 | −{ | |
| 439 | − /* Clear interrupt for transmit object */ | |
| 440 | − if ((mask >= PCH_RX_OBJ_START) && (mask <= PCH_RX_OBJ_END)) { | |
| 441 | − /* Setting CMASK for clearing the reception interrupts. */ | |
| 442 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB, | |
| 443 | − &priv->regs->ifregs[0].cmask); | |
| 444 | − | |
| 445 | − /* Clearing the Dir bit. */ | |
| 446 | − pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR); | |
| 447 | − | |
| 448 | − /* Clearing NewDat & IntPnd */ | |
| 449 | − pch_can_bit_clear(&priv->regs->ifregs[0].mcont, | |
| 450 | − PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND); | |
| 451 | − | |
| 452 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, mask); | |
| 453 | − } else if ((mask >= PCH_TX_OBJ_START) && (mask <= PCH_TX_OBJ_END)) { | |
| 454 | − /* | |
| 455 | − * Setting CMASK for clearing interrupts for frame transmission. | |
| 456 | − */ | |
| 457 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB, | |
| 458 | − &priv->regs->ifregs[1].cmask); | |
| 459 | − | |
| 460 | − /* Resetting the ID registers. */ | |
| 461 | − pch_can_bit_set(&priv->regs->ifregs[1].id2, | |
| 462 | − PCH_ID2_DIR | (0x7ff << 2)); | |
| 463 | − iowrite32(0x0, &priv->regs->ifregs[1].id1); | |
| 464 | − | |
| 465 | − /* Clearing NewDat, TxRqst & IntPnd */ | |
| 466 | − pch_can_bit_clear(&priv->regs->ifregs[1].mcont, | |
| 467 | − PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND | | |
| 468 | − PCH_IF_MCONT_TXRQXT); | |
| 469 | − pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, mask); | |
| 470 | − } | |
| 471 | −} | |
| 472 | − | |
| 473 | −static void pch_can_reset(struct pch_can_priv *priv) | |
| 474 | −{ | |
| 475 | − /* write to sw reset register */ | |
| 476 | − iowrite32(1, &priv->regs->srst); | |
| 477 | − iowrite32(0, &priv->regs->srst); | |
| 478 | −} | |
| 479 | − | |
| 480 | −static void pch_can_error(struct net_device *ndev, u32 status) | |
| 481 | −{ | |
| 482 | − struct sk_buff *skb; | |
| 483 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 484 | − struct can_frame *cf; | |
| 485 | − u32 errc, lec; | |
| 486 | − struct net_device_stats *stats = &(priv->ndev->stats); | |
| 487 | − enum can_state state = priv->can.state; | |
| 488 | − | |
| 489 | − skb = alloc_can_err_skb(ndev, &cf); | |
| 490 | − if (!skb) | |
| 491 | − return; | |
| 492 | − | |
| 493 | − errc = ioread32(&priv->regs->errc); | |
| 494 | − if (status & PCH_BUS_OFF) { | |
| 495 | − pch_can_set_tx_all(priv, 0); | |
| 496 | − pch_can_set_rx_all(priv, 0); | |
| 497 | − state = CAN_STATE_BUS_OFF; | |
| 498 | − cf->can_id |= CAN_ERR_BUSOFF; | |
| 499 | − priv->can.can_stats.bus_off++; | |
| 500 | − can_bus_off(ndev); | |
| 501 | − } else { | |
| 502 | − cf->can_id |= CAN_ERR_CNT; | |
| 503 | − cf->data[6] = errc & PCH_TEC; | |
| 504 | − cf->data[7] = (errc & PCH_REC) >> 8; | |
| 505 | − } | |
| 506 | − | |
| 507 | − /* Warning interrupt. */ | |
| 508 | − if (status & PCH_EWARN) { | |
| 509 | − state = CAN_STATE_ERROR_WARNING; | |
| 510 | − priv->can.can_stats.error_warning++; | |
| 511 | − cf->can_id |= CAN_ERR_CRTL; | |
| 512 | − if (((errc & PCH_REC) >> 8) > 96) | |
| 513 | − cf->data[1] |= CAN_ERR_CRTL_RX_WARNING; | |
| 514 | − if ((errc & PCH_TEC) > 96) | |
| 515 | − cf->data[1] |= CAN_ERR_CRTL_TX_WARNING; | |
| 516 | − netdev_dbg(ndev, | |
| 517 | − "%s -> Error Counter is more than 96.\n", __func__); | |
| 518 | − } | |
| 519 | − /* Error passive interrupt. */ | |
| 520 | − if (status & PCH_EPASSIV) { | |
| 521 | − priv->can.can_stats.error_passive++; | |
| 522 | − state = CAN_STATE_ERROR_PASSIVE; | |
| 523 | − cf->can_id |= CAN_ERR_CRTL; | |
| 524 | − if (errc & PCH_RP) | |
| 525 | − cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; | |
| 526 | − if ((errc & PCH_TEC) > 127) | |
| 527 | − cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; | |
| 528 | − netdev_dbg(ndev, | |
| 529 | − "%s -> CAN controller is ERROR PASSIVE .\n", __func__); | |
| 530 | − } | |
| 531 | − | |
| 532 | − lec = status & PCH_LEC_ALL; | |
| 533 | − switch (lec) { | |
| 534 | − case PCH_STUF_ERR: | |
| 535 | − cf->data[2] |= CAN_ERR_PROT_STUFF; | |
| 536 | − priv->can.can_stats.bus_error++; | |
| 537 | − stats->rx_errors++; | |
| 538 | − break; | |
| 539 | − case PCH_FORM_ERR: | |
| 540 | − cf->data[2] |= CAN_ERR_PROT_FORM; | |
| 541 | − priv->can.can_stats.bus_error++; | |
| 542 | − stats->rx_errors++; | |
| 543 | − break; | |
| 544 | − case PCH_ACK_ERR: | |
| 545 | − cf->can_id |= CAN_ERR_ACK; | |
| 546 | − priv->can.can_stats.bus_error++; | |
| 547 | − stats->rx_errors++; | |
| 548 | − break; | |
| 549 | − case PCH_BIT1_ERR: | |
| 550 | − case PCH_BIT0_ERR: | |
| 551 | − cf->data[2] |= CAN_ERR_PROT_BIT; | |
| 552 | − priv->can.can_stats.bus_error++; | |
| 553 | − stats->rx_errors++; | |
| 554 | − break; | |
| 555 | − case PCH_CRC_ERR: | |
| 556 | − cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; | |
| 557 | − priv->can.can_stats.bus_error++; | |
| 558 | − stats->rx_errors++; | |
| 559 | − break; | |
| 560 | − case PCH_LEC_ALL: /* Written by CPU. No error status */ | |
| 561 | − break; | |
| 562 | − } | |
| 563 | − | |
| 564 | − priv->can.state = state; | |
| 565 | − netif_receive_skb(skb); | |
| 566 | −} | |
| 567 | − | |
| 568 | −static irqreturn_t pch_can_interrupt(int irq, void *dev_id) | |
| 569 | −{ | |
| 570 | − struct net_device *ndev = (struct net_device *)dev_id; | |
| 571 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 572 | − | |
| 573 | − if (!pch_can_int_pending(priv)) | |
| 574 | − return IRQ_NONE; | |
| 575 | − | |
| 576 | − pch_can_set_int_enables(priv, PCH_CAN_NONE); | |
| 577 | − napi_schedule(&priv->napi); | |
| 578 | − return IRQ_HANDLED; | |
| 579 | −} | |
| 580 | − | |
| 581 | −static void pch_fifo_thresh(struct pch_can_priv *priv, int obj_id) | |
| 582 | −{ | |
| 583 | − if (obj_id < PCH_FIFO_THRESH) { | |
| 584 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | | |
| 585 | − PCH_CMASK_ARB, &priv->regs->ifregs[0].cmask); | |
| 586 | − | |
| 587 | − /* Clearing the Dir bit. */ | |
| 588 | − pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR); | |
| 589 | − | |
| 590 | − /* Clearing NewDat & IntPnd */ | |
| 591 | − pch_can_bit_clear(&priv->regs->ifregs[0].mcont, | |
| 592 | − PCH_IF_MCONT_INTPND); | |
| 593 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id); | |
| 594 | − } else if (obj_id > PCH_FIFO_THRESH) { | |
| 595 | − pch_can_int_clr(priv, obj_id); | |
| 596 | − } else if (obj_id == PCH_FIFO_THRESH) { | |
| 597 | − int cnt; | |
| 598 | − for (cnt = 0; cnt < PCH_FIFO_THRESH; cnt++) | |
| 599 | − pch_can_int_clr(priv, cnt + 1); | |
| 600 | − } | |
| 601 | −} | |
| 602 | − | |
| 603 | −static void pch_can_rx_msg_lost(struct net_device *ndev, int obj_id) | |
| 604 | −{ | |
| 605 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 606 | − struct net_device_stats *stats = &(priv->ndev->stats); | |
| 607 | − struct sk_buff *skb; | |
| 608 | − struct can_frame *cf; | |
| 609 | − | |
| 610 | − netdev_dbg(priv->ndev, "Msg Obj is overwritten.\n"); | |
| 611 | − pch_can_bit_clear(&priv->regs->ifregs[0].mcont, | |
| 612 | − PCH_IF_MCONT_MSGLOST); | |
| 613 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL, | |
| 614 | − &priv->regs->ifregs[0].cmask); | |
| 615 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id); | |
| 616 | − | |
| 617 | − skb = alloc_can_err_skb(ndev, &cf); | |
| 618 | − if (!skb) | |
| 619 | − return; | |
| 620 | − | |
| 621 | − cf->can_id |= CAN_ERR_CRTL; | |
| 622 | − cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; | |
| 623 | − stats->rx_over_errors++; | |
| 624 | − stats->rx_errors++; | |
| 625 | − | |
| 626 | − netif_receive_skb(skb); | |
| 627 | −} | |
| 628 | − | |
| 629 | −static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota) | |
| 630 | −{ | |
| 631 | − u32 reg; | |
| 632 | − canid_t id; | |
| 633 | − int rcv_pkts = 0; | |
| 634 | − struct sk_buff *skb; | |
| 635 | − struct can_frame *cf; | |
| 636 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 637 | − struct net_device_stats *stats = &(priv->ndev->stats); | |
| 638 | − int i; | |
| 639 | − u32 id2; | |
| 640 | − u16 data_reg; | |
| 641 | − | |
| 642 | − do { | |
| 643 | − /* Reading the message object from the Message RAM */ | |
| 644 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); | |
| 645 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_num); | |
| 646 | − | |
| 647 | − /* Reading the MCONT register. */ | |
| 648 | − reg = ioread32(&priv->regs->ifregs[0].mcont); | |
| 649 | − | |
| 650 | − if (reg & PCH_IF_MCONT_EOB) | |
| 651 | − break; | |
| 652 | − | |
| 653 | − /* If MsgLost bit set. */ | |
| 654 | − if (reg & PCH_IF_MCONT_MSGLOST) { | |
| 655 | − pch_can_rx_msg_lost(ndev, obj_num); | |
| 656 | − rcv_pkts++; | |
| 657 | − quota--; | |
| 658 | − obj_num++; | |
| 659 | − continue; | |
| 660 | − } else if (!(reg & PCH_IF_MCONT_NEWDAT)) { | |
| 661 | − obj_num++; | |
| 662 | − continue; | |
| 663 | − } | |
| 664 | − | |
| 665 | − skb = alloc_can_skb(priv->ndev, &cf); | |
| 666 | − if (!skb) { | |
| 667 | − netdev_err(ndev, "alloc_can_skb Failed\n"); | |
| 668 | − return rcv_pkts; | |
| 669 | − } | |
| 670 | − | |
| 671 | − /* Get Received data */ | |
| 672 | − id2 = ioread32(&priv->regs->ifregs[0].id2); | |
| 673 | − if (id2 & PCH_ID2_XTD) { | |
| 674 | − id = (ioread32(&priv->regs->ifregs[0].id1) & 0xffff); | |
| 675 | − id |= (((id2) & 0x1fff) << 16); | |
| 676 | − cf->can_id = id | CAN_EFF_FLAG; | |
| 677 | − } else { | |
| 678 | − id = (id2 >> 2) & CAN_SFF_MASK; | |
| 679 | − cf->can_id = id; | |
| 680 | − } | |
| 681 | − | |
| 682 | − cf->len = can_cc_dlc2len((ioread32(&priv->regs-> | |
| 683 | − ifregs[0].mcont)) & 0xF); | |
| 684 | − | |
| 685 | − if (id2 & PCH_ID2_DIR) { | |
| 686 | − cf->can_id |= CAN_RTR_FLAG; | |
| 687 | − } else { | |
| 688 | − for (i = 0; i < cf->len; i += 2) { | |
| 689 | − data_reg = ioread16(&priv->regs->ifregs[0].data[i / 2]); | |
| 690 | − cf->data[i] = data_reg; | |
| 691 | − cf->data[i + 1] = data_reg >> 8; | |
| 692 | − } | |
| 693 | − | |
| 694 | − stats->rx_bytes += cf->len; | |
| 695 | − } | |
| 696 | − stats->rx_packets++; | |
| 697 | − rcv_pkts++; | |
| 698 | − quota--; | |
| 699 | − netif_receive_skb(skb); | |
| 700 | − | |
| 701 | − pch_fifo_thresh(priv, obj_num); | |
| 702 | − obj_num++; | |
| 703 | − } while (quota > 0); | |
| 704 | − | |
| 705 | − return rcv_pkts; | |
| 706 | −} | |
| 707 | − | |
| 708 | −static void pch_can_tx_complete(struct net_device *ndev, u32 int_stat) | |
| 709 | −{ | |
| 710 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 711 | − struct net_device_stats *stats = &(priv->ndev->stats); | |
| 712 | − | |
| 713 | − stats->tx_bytes += can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_END - 1, | |
| 714 | − NULL); | |
| 715 | − stats->tx_packets++; | |
| 716 | − iowrite32(PCH_CMASK_RX_TX_GET | PCH_CMASK_CLRINTPND, | |
| 717 | − &priv->regs->ifregs[1].cmask); | |
| 718 | − pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, int_stat); | |
| 719 | − if (int_stat == PCH_TX_OBJ_END) | |
| 720 | − netif_wake_queue(ndev); | |
| 721 | −} | |
| 722 | − | |
| 723 | −static int pch_can_poll(struct napi_struct *napi, int quota) | |
| 724 | −{ | |
| 725 | − struct net_device *ndev = napi->dev; | |
| 726 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 727 | − u32 int_stat; | |
| 728 | − u32 reg_stat; | |
| 729 | − int quota_save = quota; | |
| 730 | − | |
| 731 | − int_stat = pch_can_int_pending(priv); | |
| 732 | − if (!int_stat) | |
| 733 | − goto end; | |
| 734 | − | |
| 735 | − if (int_stat == PCH_STATUS_INT) { | |
| 736 | − reg_stat = ioread32(&priv->regs->stat); | |
| 737 | − | |
| 738 | − if ((reg_stat & (PCH_BUS_OFF | PCH_LEC_ALL)) && | |
| 739 | − ((reg_stat & PCH_LEC_ALL) != PCH_LEC_ALL)) { | |
| 740 | − pch_can_error(ndev, reg_stat); | |
| 741 | − quota--; | |
| 742 | − } | |
| 743 | − | |
| 744 | − if (reg_stat & (PCH_TX_OK | PCH_RX_OK)) | |
| 745 | − pch_can_bit_clear(&priv->regs->stat, | |
| 746 | − reg_stat & (PCH_TX_OK | PCH_RX_OK)); | |
| 747 | − | |
| 748 | − int_stat = pch_can_int_pending(priv); | |
| 749 | − } | |
| 750 | − | |
| 751 | − if (quota == 0) | |
| 752 | − goto end; | |
| 753 | − | |
| 754 | − if ((int_stat >= PCH_RX_OBJ_START) && (int_stat <= PCH_RX_OBJ_END)) { | |
| 755 | − quota -= pch_can_rx_normal(ndev, int_stat, quota); | |
| 756 | − } else if ((int_stat >= PCH_TX_OBJ_START) && | |
| 757 | − (int_stat <= PCH_TX_OBJ_END)) { | |
| 758 | − /* Handle transmission interrupt */ | |
| 759 | − pch_can_tx_complete(ndev, int_stat); | |
| 760 | − } | |
| 761 | − | |
| 762 | −end: | |
| 763 | − napi_complete(napi); | |
| 764 | − pch_can_set_int_enables(priv, PCH_CAN_ALL); | |
| 765 | − | |
| 766 | − return quota_save - quota; | |
| 767 | −} | |
| 768 | − | |
| 769 | −static int pch_set_bittiming(struct net_device *ndev) | |
| 770 | −{ | |
| 771 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 772 | − const struct can_bittiming *bt = &priv->can.bittiming; | |
| 773 | − u32 canbit; | |
| 774 | − u32 bepe; | |
| 775 | − | |
| 776 | − /* Setting the CCE bit for accessing the Can Timing register. */ | |
| 777 | − pch_can_bit_set(&priv->regs->cont, PCH_CTRL_CCE); | |
| 778 | − | |
| 779 | − canbit = (bt->brp - 1) & PCH_MSK_BITT_BRP; | |
| 780 | − canbit |= (bt->sjw - 1) << PCH_BIT_SJW_SHIFT; | |
| 781 | − canbit |= (bt->phase_seg1 + bt->prop_seg - 1) << PCH_BIT_TSEG1_SHIFT; | |
| 782 | − canbit |= (bt->phase_seg2 - 1) << PCH_BIT_TSEG2_SHIFT; | |
| 783 | − bepe = ((bt->brp - 1) & PCH_MSK_BRPE_BRPE) >> PCH_BIT_BRPE_BRPE_SHIFT; | |
| 784 | − iowrite32(canbit, &priv->regs->bitt); | |
| 785 | − iowrite32(bepe, &priv->regs->brpe); | |
| 786 | − pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_CCE); | |
| 787 | − | |
| 788 | − return 0; | |
| 789 | −} | |
| 790 | − | |
| 791 | −static void pch_can_start(struct net_device *ndev) | |
| 792 | −{ | |
| 793 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 794 | − | |
| 795 | − if (priv->can.state != CAN_STATE_STOPPED) | |
| 796 | − pch_can_reset(priv); | |
| 797 | − | |
| 798 | − pch_set_bittiming(ndev); | |
| 799 | − pch_can_set_optmode(priv); | |
| 800 | − | |
| 801 | − pch_can_set_tx_all(priv, 1); | |
| 802 | − pch_can_set_rx_all(priv, 1); | |
| 803 | − | |
| 804 | − /* Setting the CAN to run mode. */ | |
| 805 | − pch_can_set_run_mode(priv, PCH_CAN_RUN); | |
| 806 | − | |
| 807 | − priv->can.state = CAN_STATE_ERROR_ACTIVE; | |
| 808 | − | |
| 809 | − return; | |
| 810 | −} | |
| 811 | − | |
| 812 | −static int pch_can_do_set_mode(struct net_device *ndev, enum can_mode mode) | |
| 813 | −{ | |
| 814 | − int ret = 0; | |
| 815 | − | |
| 816 | − switch (mode) { | |
| 817 | − case CAN_MODE_START: | |
| 818 | − pch_can_start(ndev); | |
| 819 | − netif_wake_queue(ndev); | |
| 820 | − break; | |
| 821 | − default: | |
| 822 | − ret = -EOPNOTSUPP; | |
| 823 | − break; | |
| 824 | − } | |
| 825 | − | |
| 826 | − return ret; | |
| 827 | −} | |
| 828 | − | |
| 829 | −static int pch_can_open(struct net_device *ndev) | |
| 830 | −{ | |
| 831 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 832 | − int retval; | |
| 833 | − | |
| 834 | − /* Registering the interrupt. */ | |
| 835 | − retval = request_irq(priv->dev->irq, pch_can_interrupt, IRQF_SHARED, | |
| 836 | − ndev->name, ndev); | |
| 837 | − if (retval) { | |
| 838 | − netdev_err(ndev, "request_irq failed.\n"); | |
| 839 | − goto req_irq_err; | |
| 840 | − } | |
| 841 | − | |
| 842 | − /* Open common can device */ | |
| 843 | − retval = open_candev(ndev); | |
| 844 | − if (retval) { | |
| 845 | − netdev_err(ndev, "open_candev() failed %d\n", retval); | |
| 846 | − goto err_open_candev; | |
| 847 | − } | |
| 848 | − | |
| 849 | − pch_can_init(priv); | |
| 850 | − pch_can_start(ndev); | |
| 851 | − napi_enable(&priv->napi); | |
| 852 | − netif_start_queue(ndev); | |
| 853 | − | |
| 854 | − return 0; | |
| 855 | − | |
| 856 | −err_open_candev: | |
| 857 | − free_irq(priv->dev->irq, ndev); | |
| 858 | −req_irq_err: | |
| 859 | − pch_can_release(priv); | |
| 860 | − | |
| 861 | − return retval; | |
| 862 | −} | |
| 863 | − | |
| 864 | −static int pch_close(struct net_device *ndev) | |
| 865 | −{ | |
| 866 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 867 | − | |
| 868 | − netif_stop_queue(ndev); | |
| 869 | − napi_disable(&priv->napi); | |
| 870 | − pch_can_release(priv); | |
| 871 | − free_irq(priv->dev->irq, ndev); | |
| 872 | − close_candev(ndev); | |
| 873 | − priv->can.state = CAN_STATE_STOPPED; | |
| 874 | − return 0; | |
| 875 | −} | |
| 876 | − | |
| 877 | −static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev) | |
| 878 | −{ | |
| 879 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 880 | − struct can_frame *cf = (struct can_frame *)skb->data; | |
| 881 | − int tx_obj_no; | |
| 882 | − int i; | |
| 883 | − u32 id2; | |
| 884 | − | |
| 885 | − if (can_dev_dropped_skb(ndev, skb)) | |
| 886 | − return NETDEV_TX_OK; | |
| 887 | − | |
| 888 | − tx_obj_no = priv->tx_obj; | |
| 889 | − if (priv->tx_obj == PCH_TX_OBJ_END) { | |
| 890 | − if (ioread32(&priv->regs->treq2) & PCH_TREQ2_TX_MASK) | |
| 891 | − netif_stop_queue(ndev); | |
| 892 | − | |
| 893 | − priv->tx_obj = PCH_TX_OBJ_START; | |
| 894 | − } else { | |
| 895 | − priv->tx_obj++; | |
| 896 | − } | |
| 897 | − | |
| 898 | − /* Setting the CMASK register. */ | |
| 899 | − pch_can_bit_set(&priv->regs->ifregs[1].cmask, PCH_CMASK_ALL); | |
| 900 | − | |
| 901 | − /* If ID extended is set. */ | |
| 902 | − if (cf->can_id & CAN_EFF_FLAG) { | |
| 903 | − iowrite32(cf->can_id & 0xffff, &priv->regs->ifregs[1].id1); | |
| 904 | − id2 = ((cf->can_id >> 16) & 0x1fff) | PCH_ID2_XTD; | |
| 905 | − } else { | |
| 906 | − iowrite32(0, &priv->regs->ifregs[1].id1); | |
| 907 | − id2 = (cf->can_id & CAN_SFF_MASK) << 2; | |
| 908 | − } | |
| 909 | − | |
| 910 | − id2 |= PCH_ID_MSGVAL; | |
| 911 | − | |
| 912 | − /* If remote frame has to be transmitted.. */ | |
| 913 | − if (!(cf->can_id & CAN_RTR_FLAG)) | |
| 914 | − id2 |= PCH_ID2_DIR; | |
| 915 | − | |
| 916 | − iowrite32(id2, &priv->regs->ifregs[1].id2); | |
| 917 | − | |
| 918 | − /* Copy data to register */ | |
| 919 | − for (i = 0; i < cf->len; i += 2) { | |
| 920 | − iowrite16(cf->data[i] | (cf->data[i + 1] << 8), | |
| 921 | − &priv->regs->ifregs[1].data[i / 2]); | |
| 922 | − } | |
| 923 | − | |
| 924 | − can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1, 0); | |
| 925 | − | |
| 926 | − /* Set the size of the data. Update if2_mcont */ | |
| 927 | − iowrite32(cf->len | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT | | |
| 928 | − PCH_IF_MCONT_TXIE, &priv->regs->ifregs[1].mcont); | |
| 929 | − | |
| 930 | − pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, tx_obj_no); | |
| 931 | − | |
| 932 | − return NETDEV_TX_OK; | |
| 933 | −} | |
| 934 | − | |
| 935 | −static const struct net_device_ops pch_can_netdev_ops = { | |
| 936 | − .ndo_open = pch_can_open, | |
| 937 | − .ndo_stop = pch_close, | |
| 938 | − .ndo_start_xmit = pch_xmit, | |
| 939 | − .ndo_change_mtu = can_change_mtu, | |
| 940 | −}; | |
| 941 | − | |
| 942 | −static const struct ethtool_ops pch_can_ethtool_ops = { | |
| 943 | − .get_ts_info = ethtool_op_get_ts_info, | |
| 944 | −}; | |
| 945 | − | |
| 946 | −static void pch_can_remove(struct pci_dev *pdev) | |
| 947 | −{ | |
| 948 | − struct net_device *ndev = pci_get_drvdata(pdev); | |
| 949 | − struct pch_can_priv *priv = netdev_priv(ndev); | |
| 950 | − | |
| 951 | − unregister_candev(priv->ndev); | |
| 952 | − if (priv->use_msi) | |
| 953 | − pci_disable_msi(priv->dev); | |
| 954 | − pci_release_regions(pdev); | |
| 955 | − pci_disable_device(pdev); | |
| 956 | − pch_can_reset(priv); | |
| 957 | − pci_iounmap(pdev, priv->regs); | |
| 958 | − free_candev(priv->ndev); | |
| 959 | −} | |
| 960 | − | |
| 961 | −static void __maybe_unused pch_can_set_int_custom(struct pch_can_priv *priv) | |
| 962 | −{ | |
| 963 | − /* Clearing the IE, SIE and EIE bits of Can control register. */ | |
| 964 | − pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); | |
| 965 | − | |
| 966 | − /* Appropriately setting them. */ | |
| 967 | − pch_can_bit_set(&priv->regs->cont, | |
| 968 | − ((priv->int_enables & PCH_MSK_CTRL_IE_SIE_EIE) << 1)); | |
| 969 | −} | |
| 970 | − | |
| 971 | −/* This function retrieves interrupt enabled for the CAN device. */ | |
| 972 | −static u32 __maybe_unused pch_can_get_int_enables(struct pch_can_priv *priv) | |
| 973 | −{ | |
| 974 | − /* Obtaining the status of IE, SIE and EIE interrupt bits. */ | |
| 975 | − return (ioread32(&priv->regs->cont) & PCH_CTRL_IE_SIE_EIE) >> 1; | |
| 976 | −} | |
| 977 | − | |
| 978 | −static u32 __maybe_unused pch_can_get_rxtx_ir(struct pch_can_priv *priv, | |
| 979 | − u32 buff_num, enum pch_ifreg dir) | |
| 980 | −{ | |
| 981 | − u32 ie, enable; | |
| 982 | − | |
| 983 | − if (dir) | |
| 984 | − ie = PCH_IF_MCONT_RXIE; | |
| 985 | − else | |
| 986 | − ie = PCH_IF_MCONT_TXIE; | |
| 987 | − | |
| 988 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask); | |
| 989 | − pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num); | |
| 990 | − | |
| 991 | − if (((ioread32(&priv->regs->ifregs[dir].id2)) & PCH_ID_MSGVAL) && | |
| 992 | − ((ioread32(&priv->regs->ifregs[dir].mcont)) & ie)) | |
| 993 | − enable = 1; | |
| 994 | − else | |
| 995 | − enable = 0; | |
| 996 | − | |
| 997 | − return enable; | |
| 998 | −} | |
| 999 | − | |
| 1000 | −static void __maybe_unused pch_can_set_rx_buffer_link(struct pch_can_priv *priv, | |
| 1001 | − u32 buffer_num, int set) | |
| 1002 | −{ | |
| 1003 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); | |
| 1004 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); | |
| 1005 | − iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL, | |
| 1006 | − &priv->regs->ifregs[0].cmask); | |
| 1007 | − if (set) | |
| 1008 | − pch_can_bit_clear(&priv->regs->ifregs[0].mcont, | |
| 1009 | − PCH_IF_MCONT_EOB); | |
| 1010 | − else | |
| 1011 | − pch_can_bit_set(&priv->regs->ifregs[0].mcont, PCH_IF_MCONT_EOB); | |
| 1012 | − | |
| 1013 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); | |
| 1014 | −} | |
| 1015 | − | |
| 1016 | −static u32 __maybe_unused pch_can_get_rx_buffer_link(struct pch_can_priv *priv, | |
| 1017 | − u32 buffer_num) | |
| 1018 | −{ | |
| 1019 | − u32 link; | |
| 1020 | − | |
| 1021 | − iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); | |
| 1022 | − pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); | |
| 1023 | − | |
| 1024 | − if (ioread32(&priv->regs->ifregs[0].mcont) & PCH_IF_MCONT_EOB) | |
| 1025 | − link = 0; | |
| 1026 | − else | |
| 1027 | − link = 1; | |
| 1028 | − return link; | |
| 1029 | −} | |
| 1030 | − | |
| 1031 | −static int __maybe_unused pch_can_get_buffer_status(struct pch_can_priv *priv) | |
| 1032 | −{ | |
| 1033 | − return (ioread32(&priv->regs->treq1) & 0xffff) | | |
| 1034 | − (ioread32(&priv->regs->treq2) << 16); | |
| 1035 | −} | |
| 1036 | − | |
| 1037 | −static int __maybe_unused pch_can_suspend(struct device *dev_d) | |
| 1038 | −{ | |
| 1039 | − int i; | |
| 1040 | − u32 buf_stat; /* Variable for reading the transmit buffer status. */ | |
| 1041 | − int counter = PCH_COUNTER_LIMIT; | |
| 1042 | − | |
| 1043 | − struct net_device *dev = dev_get_drvdata(dev_d); | |
| 1044 | − struct pch_can_priv *priv = netdev_priv(dev); | |
| 1045 | − | |
| 1046 | − /* Stop the CAN controller */ | |
| 1047 | − pch_can_set_run_mode(priv, PCH_CAN_STOP); | |
| 1048 | − | |
| 1049 | − /* Indicate that we are aboutto/in suspend */ | |
| 1050 | − priv->can.state = CAN_STATE_STOPPED; | |
| 1051 | − | |
| 1052 | − /* Waiting for all transmission to complete. */ | |
| 1053 | − while (counter) { | |
| 1054 | − buf_stat = pch_can_get_buffer_status(priv); | |
| 1055 | − if (!buf_stat) | |
| 1056 | − break; | |
| 1057 | − counter--; | |
| 1058 | − udelay(1); | |
| 1059 | − } | |
| 1060 | − if (!counter) | |
| 1061 | − dev_err(dev_d, "%s -> Transmission time out.\n", __func__); | |
| 1062 | − | |
| 1063 | − /* Save interrupt configuration and then disable them */ | |
| 1064 | − priv->int_enables = pch_can_get_int_enables(priv); | |
| 1065 | − pch_can_set_int_enables(priv, PCH_CAN_DISABLE); | |
| 1066 | − | |
| 1067 | − /* Save Tx buffer enable state */ | |
| 1068 | − for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) | |
| 1069 | − priv->tx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i, | |
| 1070 | − PCH_TX_IFREG); | |
| 1071 | − | |
| 1072 | − /* Disable all Transmit buffers */ | |
| 1073 | − pch_can_set_tx_all(priv, 0); | |
| 1074 | − | |
| 1075 | − /* Save Rx buffer enable state */ | |
| 1076 | − for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) { | |
| 1077 | − priv->rx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i, | |
| 1078 | − PCH_RX_IFREG); | |
| 1079 | − priv->rx_link[i - 1] = pch_can_get_rx_buffer_link(priv, i); | |
| 1080 | − } | |
| 1081 | − | |
| 1082 | − /* Disable all Receive buffers */ | |
| 1083 | − pch_can_set_rx_all(priv, 0); | |
| 1084 | − | |
| 1085 | − return 0; | |
| 1086 | −} | |
| 1087 | − | |
| 1088 | −static int __maybe_unused pch_can_resume(struct device *dev_d) | |
| 1089 | −{ | |
| 1090 | − int i; | |
| 1091 | − struct net_device *dev = dev_get_drvdata(dev_d); | |
| 1092 | − struct pch_can_priv *priv = netdev_priv(dev); | |
| 1093 | − | |
| 1094 | − priv->can.state = CAN_STATE_ERROR_ACTIVE; | |
| 1095 | − | |
| 1096 | − /* Disabling all interrupts. */ | |
| 1097 | − pch_can_set_int_enables(priv, PCH_CAN_DISABLE); | |
| 1098 | − | |
| 1099 | − /* Setting the CAN device in Stop Mode. */ | |
| 1100 | − pch_can_set_run_mode(priv, PCH_CAN_STOP); | |
| 1101 | − | |
| 1102 | − /* Configuring the transmit and receive buffers. */ | |
| 1103 | − pch_can_config_rx_tx_buffers(priv); | |
| 1104 | − | |
| 1105 | − /* Restore the CAN state */ | |
| 1106 | − pch_set_bittiming(dev); | |
| 1107 | − | |
| 1108 | − /* Listen/Active */ | |
| 1109 | − pch_can_set_optmode(priv); | |
| 1110 | − | |
| 1111 | − /* Enabling the transmit buffer. */ | |
| 1112 | − for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) | |
| 1113 | − pch_can_set_rxtx(priv, i, priv->tx_enable[i - 1], PCH_TX_IFREG); | |
| 1114 | − | |
| 1115 | − /* Configuring the receive buffer and enabling them. */ | |
| 1116 | − for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) { | |
| 1117 | − /* Restore buffer link */ | |
| 1118 | − pch_can_set_rx_buffer_link(priv, i, priv->rx_link[i - 1]); | |
| 1119 | − | |
| 1120 | − /* Restore buffer enables */ | |
| 1121 | − pch_can_set_rxtx(priv, i, priv->rx_enable[i - 1], PCH_RX_IFREG); | |
| 1122 | − } | |
| 1123 | − | |
| 1124 | − /* Enable CAN Interrupts */ | |
| 1125 | − pch_can_set_int_custom(priv); | |
| 1126 | − | |
| 1127 | − /* Restore Run Mode */ | |
| 1128 | − pch_can_set_run_mode(priv, PCH_CAN_RUN); | |
| 1129 | − | |
| 1130 | − return 0; | |
| 1131 | −} | |
| 1132 | − | |
| 1133 | −static int pch_can_get_berr_counter(const struct net_device *dev, | |
| 1134 | − struct can_berr_counter *bec) | |
| 1135 | −{ | |
| 1136 | − struct pch_can_priv *priv = netdev_priv(dev); | |
| 1137 | − u32 errc = ioread32(&priv->regs->errc); | |
| 1138 | − | |
| 1139 | − bec->txerr = errc & PCH_TEC; | |
| 1140 | − bec->rxerr = (errc & PCH_REC) >> 8; | |
| 1141 | − | |
| 1142 | − return 0; | |
| 1143 | −} | |
| 1144 | − | |
| 1145 | −static int pch_can_probe(struct pci_dev *pdev, | |
| 1146 | − const struct pci_device_id *id) | |
| 1147 | −{ | |
| 1148 | − struct net_device *ndev; | |
| 1149 | − struct pch_can_priv *priv; | |
| 1150 | − int rc; | |
| 1151 | − void __iomem *addr; | |
| 1152 | − | |
| 1153 | − rc = pci_enable_device(pdev); | |
| 1154 | − if (rc) { | |
| 1155 | − dev_err(&pdev->dev, "Failed pci_enable_device %d\n", rc); | |
| 1156 | − goto probe_exit_endev; | |
| 1157 | − } | |
| 1158 | − | |
| 1159 | − rc = pci_request_regions(pdev, KBUILD_MODNAME); | |
| 1160 | − if (rc) { | |
| 1161 | − dev_err(&pdev->dev, "Failed pci_request_regions %d\n", rc); | |
| 1162 | − goto probe_exit_pcireq; | |
| 1163 | − } | |
| 1164 | − | |
| 1165 | − addr = pci_iomap(pdev, 1, 0); | |
| 1166 | − if (!addr) { | |
| 1167 | − rc = -EIO; | |
| 1168 | − dev_err(&pdev->dev, "Failed pci_iomap\n"); | |
| 1169 | − goto probe_exit_ipmap; | |
| 1170 | − } | |
| 1171 | − | |
| 1172 | − ndev = alloc_candev(sizeof(struct pch_can_priv), PCH_TX_OBJ_END); | |
| 1173 | − if (!ndev) { | |
| 1174 | − rc = -ENOMEM; | |
| 1175 | − dev_err(&pdev->dev, "Failed alloc_candev\n"); | |
| 1176 | − goto probe_exit_alloc_candev; | |
| 1177 | − } | |
| 1178 | − | |
| 1179 | − priv = netdev_priv(ndev); | |
| 1180 | − priv->ndev = ndev; | |
| 1181 | − priv->regs = addr; | |
| 1182 | − priv->dev = pdev; | |
| 1183 | − priv->can.bittiming_const = &pch_can_bittiming_const; | |
| 1184 | − priv->can.do_set_mode = pch_can_do_set_mode; | |
| 1185 | − priv->can.do_get_berr_counter = pch_can_get_berr_counter; | |
| 1186 | − priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | | |
| 1187 | − CAN_CTRLMODE_LOOPBACK; | |
| 1188 | − priv->tx_obj = PCH_TX_OBJ_START; /* Point head of Tx Obj */ | |
| 1189 | − | |
| 1190 | − ndev->irq = pdev->irq; | |
| 1191 | − ndev->flags |= IFF_ECHO; | |
| 1192 | − | |
| 1193 | − pci_set_drvdata(pdev, ndev); | |
| 1194 | − SET_NETDEV_DEV(ndev, &pdev->dev); | |
| 1195 | − ndev->netdev_ops = &pch_can_netdev_ops; | |
| 1196 | − ndev->ethtool_ops = &pch_can_ethtool_ops; | |
| 1197 | − priv->can.clock.freq = PCH_CAN_CLK; /* Hz */ | |
| 1198 | − | |
| 1199 | − netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END); | |
| 1200 | − | |
| 1201 | − rc = pci_enable_msi(priv->dev); | |
| 1202 | − if (rc) { | |
| 1203 | − netdev_err(ndev, "PCH CAN opened without MSI\n"); | |
| 1204 | − priv->use_msi = 0; | |
| 1205 | − } else { | |
| 1206 | − netdev_err(ndev, "PCH CAN opened with MSI\n"); | |
| 1207 | − pci_set_master(pdev); | |
| 1208 | − priv->use_msi = 1; | |
| 1209 | − } | |
| 1210 | − | |
| 1211 | − rc = register_candev(ndev); | |
| 1212 | − if (rc) { | |
| 1213 | − dev_err(&pdev->dev, "Failed register_candev %d\n", rc); | |
| 1214 | − goto probe_exit_reg_candev; | |
| 1215 | − } | |
| 1216 | − | |
| 1217 | − return 0; | |
| 1218 | − | |
| 1219 | −probe_exit_reg_candev: | |
| 1220 | − if (priv->use_msi) | |
| 1221 | − pci_disable_msi(priv->dev); | |
| 1222 | − free_candev(ndev); | |
| 1223 | −probe_exit_alloc_candev: | |
| 1224 | − pci_iounmap(pdev, addr); | |
| 1225 | −probe_exit_ipmap: | |
| 1226 | − pci_release_regions(pdev); | |
| 1227 | −probe_exit_pcireq: | |
| 1228 | − pci_disable_device(pdev); | |
| 1229 | −probe_exit_endev: | |
| 1230 | − return rc; | |
| 1231 | −} | |
| 1232 | − | |
| 1233 | −static SIMPLE_DEV_PM_OPS(pch_can_pm_ops, | |
| 1234 | − pch_can_suspend, | |
| 1235 | − pch_can_resume); | |
| 1236 | − | |
| 1237 | −static struct pci_driver pch_can_pci_driver = { | |
| 1238 | − .name = "pch_can", | |
| 1239 | − .id_table = pch_pci_tbl, | |
| 1240 | − .probe = pch_can_probe, | |
| 1241 | − .remove = pch_can_remove, | |
| 1242 | − .driver.pm = &pch_can_pm_ops, | |
| 1243 | −}; | |
| 1244 | − | |
| 1245 | −module_pci_driver(pch_can_pci_driver); | |
| 1246 | − | |
| 1247 | −MODULE_DESCRIPTION("Intel EG20T PCH CAN(Controller Area Network) Driver"); | |
| 1248 | −MODULE_LICENSE("GPL v2"); | |
| 1249 | −MODULE_VERSION("0.94"); | |
| @@ -41,12 +41,6 @@ · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | #define RCANFD_DRV_NAME "rcar_canfd" |
| 43 | 43 | |
| 44 | −enum rcanfd_chip_id { | |
| 45 | − RENESAS_RCAR_GEN3 = 0, | |
| 46 | − RENESAS_RZG2L, | |
| 47 | − RENESAS_R8A779A0, | |
| 48 | −}; | |
| 49 | − | |
| 50 | 44 | /* Global register bits */ |
| 51 | 45 | |
| 52 | 46 | /* RSCFDnCFDGRMCFG */ |
| @@ -522,6 +516,14 @@ enum rcar_canfd_fcanclk { · 469 unmodified lines | ||
| 522 | 516 | |
| 523 | 517 | struct rcar_canfd_global; |
| 524 | 518 | |
| 519 | +struct rcar_canfd_hw_info { | |
| 520 | + u8 max_channels; | |
| 521 | + u8 postdiv; | |
| 522 | + /* hardware features */ | |
| 523 | + unsigned shared_global_irqs:1; /* Has shared global irqs */ | |
| 524 | + unsigned multi_channel_irqs:1; /* Has multiple channel irqs */ | |
| 525 | +}; | |
| 526 | + | |
| 525 | 527 | /* Channel priv data */ |
| 526 | 528 | struct rcar_canfd_channel { |
| 527 | 529 | struct can_priv can; /* Must be the first member */ |
| @@ -547,8 +549,7 @@ struct rcar_canfd_global { · 19 unmodified lines | ||
| 547 | 549 | bool fdmode; /* CAN FD or Classical CAN only mode */ |
| 548 | 550 | struct reset_control *rstc1; |
| 549 | 551 | struct reset_control *rstc2; |
| 550 | − enum rcanfd_chip_id chip_id; | |
| 551 | − u32 max_channels; | |
| 552 | + const struct rcar_canfd_hw_info *info; | |
| 552 | 553 | }; |
| 553 | 554 | |
| 554 | 555 | /* CAN FD mode nominal rate constants */ |
| @@ -590,10 +591,28 @@ static const struct can_bittiming_const rcar_canfd_bittiming_const = { · 35 unmodified lines | ||
| 590 | 591 | .brp_inc = 1, |
| 591 | 592 | }; |
| 592 | 593 | |
| 594 | +static const struct rcar_canfd_hw_info rcar_gen3_hw_info = { | |
| 595 | + .max_channels = 2, | |
| 596 | + .postdiv = 2, | |
| 597 | + .shared_global_irqs = 1, | |
| 598 | +}; | |
| 599 | + | |
| 600 | +static const struct rcar_canfd_hw_info rzg2l_hw_info = { | |
| 601 | + .max_channels = 2, | |
| 602 | + .postdiv = 1, | |
| 603 | + .multi_channel_irqs = 1, | |
| 604 | +}; | |
| 605 | + | |
| 606 | +static const struct rcar_canfd_hw_info r8a779a0_hw_info = { | |
| 607 | + .max_channels = 8, | |
| 608 | + .postdiv = 2, | |
| 609 | + .shared_global_irqs = 1, | |
| 610 | +}; | |
| 611 | + | |
| 593 | 612 | /* Helper functions */ |
| 594 | 613 | static inline bool is_v3u(struct rcar_canfd_global *gpriv) |
| 595 | 614 | { |
| 596 | − return gpriv->chip_id == RENESAS_R8A779A0; | |
| 615 | + return gpriv->info == &r8a779a0_hw_info; | |
| 597 | 616 | } |
| 598 | 617 | |
| 599 | 618 | static inline u32 reg_v3u(struct rcar_canfd_global *gpriv, |
| @@ -721,7 +740,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) · 121 unmodified lines | ||
| 721 | 740 | rcar_canfd_set_mode(gpriv); |
| 722 | 741 | |
| 723 | 742 | /* Transition all Channels to reset mode */ |
| 724 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) { | |
| 743 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { | |
| 725 | 744 | rcar_canfd_clear_bit(gpriv->base, |
| 726 | 745 | RCANFD_CCTR(ch), RCANFD_CCTR_CSLPR); |
| 727 | 746 | |
| @@ -762,7 +781,7 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv) · 34 unmodified lines | ||
| 762 | 781 | rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg); |
| 763 | 782 | |
| 764 | 783 | /* Channel configuration settings */ |
| 765 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) { | |
| 784 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { | |
| 766 | 785 | rcar_canfd_set_bit(gpriv->base, RCANFD_CCTR(ch), |
| 767 | 786 | RCANFD_CCTR_ERRD); |
| 768 | 787 | rcar_canfd_update_bit(gpriv->base, RCANFD_CCTR(ch), |
| @@ -1142,7 +1161,7 @@ static irqreturn_t rcar_canfd_global_err_interrupt(int irq, void *dev_id) · 373 unmodified lines | ||
| 1142 | 1161 | struct rcar_canfd_global *gpriv = dev_id; |
| 1143 | 1162 | u32 ch; |
| 1144 | 1163 | |
| 1145 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) | |
| 1164 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) | |
| 1146 | 1165 | rcar_canfd_handle_global_err(gpriv, ch); |
| 1147 | 1166 | |
| 1148 | 1167 | return IRQ_HANDLED; |
| @@ -1174,7 +1193,7 @@ static irqreturn_t rcar_canfd_global_receive_fifo_interrupt(int irq, void *dev_i · 25 unmodified lines | ||
| 1174 | 1193 | struct rcar_canfd_global *gpriv = dev_id; |
| 1175 | 1194 | u32 ch; |
| 1176 | 1195 | |
| 1177 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) | |
| 1196 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) | |
| 1178 | 1197 | rcar_canfd_handle_global_receive(gpriv, ch); |
| 1179 | 1198 | |
| 1180 | 1199 | return IRQ_HANDLED; |
| @@ -1188,7 +1207,7 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id) · 7 unmodified lines | ||
| 1188 | 1207 | /* Global error interrupts still indicate a condition specific |
| 1189 | 1208 | * to a channel. RxFIFO interrupt is a global interrupt. |
| 1190 | 1209 | */ |
| 1191 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) { | |
| 1210 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { | |
| 1192 | 1211 | rcar_canfd_handle_global_err(gpriv, ch); |
| 1193 | 1212 | rcar_canfd_handle_global_receive(gpriv, ch); |
| 1194 | 1213 | } |
| @@ -1284,7 +1303,7 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) · 89 unmodified lines | ||
| 1284 | 1303 | u32 ch; |
| 1285 | 1304 | |
| 1286 | 1305 | /* Common FIFO is a per channel resource */ |
| 1287 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) { | |
| 1306 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { | |
| 1288 | 1307 | rcar_canfd_handle_channel_err(gpriv, ch); |
| 1289 | 1308 | rcar_canfd_handle_channel_tx(gpriv, ch); |
| 1290 | 1309 | } |
| @@ -1696,6 +1715,7 @@ static const struct ethtool_ops rcar_canfd_ethtool_ops = { · 405 unmodified lines | ||
| 1696 | 1715 | static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, |
| 1697 | 1716 | u32 fcan_freq) |
| 1698 | 1717 | { |
| 1718 | + const struct rcar_canfd_hw_info *info = gpriv->info; | |
| 1699 | 1719 | struct platform_device *pdev = gpriv->pdev; |
| 1700 | 1720 | struct rcar_canfd_channel *priv; |
| 1701 | 1721 | struct net_device *ndev; |
| @@ -1718,7 +1738,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, · 16 unmodified lines | ||
| 1718 | 1738 | priv->can.clock.freq = fcan_freq; |
| 1719 | 1739 | dev_info(&pdev->dev, "can_clk rate is %u\n", priv->can.clock.freq); |
| 1720 | 1740 | |
| 1721 | − if (gpriv->chip_id == RENESAS_RZG2L) { | |
| 1741 | + if (info->multi_channel_irqs) { | |
| 1722 | 1742 | char *irq_name; |
| 1723 | 1743 | int err_irq; |
| 1724 | 1744 | int tx_irq; |
| @@ -1818,6 +1838,7 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch) · 93 unmodified lines | ||
| 1818 | 1838 | |
| 1819 | 1839 | static int rcar_canfd_probe(struct platform_device *pdev) |
| 1820 | 1840 | { |
| 1841 | + const struct rcar_canfd_hw_info *info; | |
| 1821 | 1842 | void __iomem *addr; |
| 1822 | 1843 | u32 sts, ch, fcan_freq; |
| 1823 | 1844 | struct rcar_canfd_global *gpriv; |
| @@ -1826,18 +1847,15 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 1826 | 1847 | int err, ch_irq, g_irq; |
| 1827 | 1848 | int g_err_irq, g_recc_irq; |
| 1828 | 1849 | bool fdmode = true; /* CAN FD only mode - default */ |
| 1829 | − enum rcanfd_chip_id chip_id; | |
| 1830 | − int max_channels; | |
| 1831 | 1850 | char name[9] = "channelX"; |
| 1832 | 1851 | int i; |
| 1833 | 1852 | |
| 1834 | − chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev); | |
| 1835 | − max_channels = chip_id == RENESAS_R8A779A0 ? 8 : 2; | |
| 1853 | + info = of_device_get_match_data(&pdev->dev); | |
| 1836 | 1854 | |
| 1837 | 1855 | if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd")) |
| 1838 | 1856 | fdmode = false; /* Classical CAN only mode */ |
| 1839 | 1857 | |
| 1840 | − for (i = 0; i < max_channels; ++i) { | |
| 1858 | + for (i = 0; i < info->max_channels; ++i) { | |
| 1841 | 1859 | name[7] = '0' + i; |
| 1842 | 1860 | of_child = of_get_child_by_name(pdev->dev.of_node, name); |
| 1843 | 1861 | if (of_child && of_device_is_available(of_child)) |
| @@ -1845,7 +1863,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 1845 | 1863 | of_node_put(of_child); |
| 1846 | 1864 | } |
| 1847 | 1865 | |
| 1848 | − if (chip_id != RENESAS_RZG2L) { | |
| 1866 | + if (info->shared_global_irqs) { | |
| 1849 | 1867 | ch_irq = platform_get_irq_byname_optional(pdev, "ch_int"); |
| 1850 | 1868 | if (ch_irq < 0) { |
| 1851 | 1869 | /* For backward compatibility get irq by index */ |
| @@ -1879,20 +1897,19 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 27 unmodified lines | ||
| 1879 | 1897 | gpriv->pdev = pdev; |
| 1880 | 1898 | gpriv->channels_mask = channels_mask; |
| 1881 | 1899 | gpriv->fdmode = fdmode; |
| 1882 | − gpriv->chip_id = chip_id; | |
| 1883 | − gpriv->max_channels = max_channels; | |
| 1884 | − | |
| 1885 | − if (gpriv->chip_id == RENESAS_RZG2L) { | |
| 1886 | − gpriv->rstc1 = devm_reset_control_get_exclusive(&pdev->dev, "rstp_n"); | |
| 1887 | − if (IS_ERR(gpriv->rstc1)) | |
| 1888 | − return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1), | |
| 1889 | − "failed to get rstp_n\n"); | |
| 1890 | − | |
| 1891 | − gpriv->rstc2 = devm_reset_control_get_exclusive(&pdev->dev, "rstc_n"); | |
| 1892 | − if (IS_ERR(gpriv->rstc2)) | |
| 1893 | − return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2), | |
| 1894 | − "failed to get rstc_n\n"); | |
| 1895 | − } | |
| 1900 | + gpriv->info = info; | |
| 1901 | + | |
| 1902 | + gpriv->rstc1 = devm_reset_control_get_optional_exclusive(&pdev->dev, | |
| 1903 | + "rstp_n"); | |
| 1904 | + if (IS_ERR(gpriv->rstc1)) | |
| 1905 | + return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1), | |
| 1906 | + "failed to get rstp_n\n"); | |
| 1907 | + | |
| 1908 | + gpriv->rstc2 = devm_reset_control_get_optional_exclusive(&pdev->dev, | |
| 1909 | + "rstc_n"); | |
| 1910 | + if (IS_ERR(gpriv->rstc2)) | |
| 1911 | + return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2), | |
| 1912 | + "failed to get rstc_n\n"); | |
| 1896 | 1913 | |
| 1897 | 1914 | /* Peripheral clock */ |
| 1898 | 1915 | gpriv->clkp = devm_clk_get(&pdev->dev, "fck"); |
| @@ -1917,9 +1934,9 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 18 unmodified lines | ||
| 1917 | 1934 | } |
| 1918 | 1935 | fcan_freq = clk_get_rate(gpriv->can_clk); |
| 1919 | 1936 | |
| 1920 | − if (gpriv->fcan == RCANFD_CANFDCLK && gpriv->chip_id != RENESAS_RZG2L) | |
| 1937 | + if (gpriv->fcan == RCANFD_CANFDCLK) | |
| 1921 | 1938 | /* CANFD clock is further divided by (1/2) within the IP */ |
| 1922 | − fcan_freq /= 2; | |
| 1939 | + fcan_freq /= info->postdiv; | |
| 1923 | 1940 | |
| 1924 | 1941 | addr = devm_platform_ioremap_resource(pdev, 0); |
| 1925 | 1942 | if (IS_ERR(addr)) { |
| @@ -1929,7 +1946,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 1929 | 1946 | gpriv->base = addr; |
| 1930 | 1947 | |
| 1931 | 1948 | /* Request IRQ that's common for both channels */ |
| 1932 | − if (gpriv->chip_id != RENESAS_RZG2L) { | |
| 1949 | + if (info->shared_global_irqs) { | |
| 1933 | 1950 | err = devm_request_irq(&pdev->dev, ch_irq, |
| 1934 | 1951 | rcar_canfd_channel_interrupt, 0, |
| 1935 | 1952 | "canfd.ch_int", gpriv); |
| @@ -1995,7 +2012,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 59 unmodified lines | ||
| 1995 | 2012 | rcar_canfd_configure_controller(gpriv); |
| 1996 | 2013 | |
| 1997 | 2014 | /* Configure per channel attributes */ |
| 1998 | − for_each_set_bit(ch, &gpriv->channels_mask, max_channels) { | |
| 2015 | + for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) { | |
| 1999 | 2016 | /* Configure Channel's Rx fifo */ |
| 2000 | 2017 | rcar_canfd_configure_rx(gpriv, ch); |
| 2001 | 2018 | |
| @@ -2021,7 +2038,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 19 unmodified lines | ||
| 2021 | 2038 | goto fail_mode; |
| 2022 | 2039 | } |
| 2023 | 2040 | |
| 2024 | − for_each_set_bit(ch, &gpriv->channels_mask, max_channels) { | |
| 2041 | + for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) { | |
| 2025 | 2042 | err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq); |
| 2026 | 2043 | if (err) |
| 2027 | 2044 | goto fail_channel; |
| @@ -2033,7 +2050,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 2033 | 2050 | return 0; |
| 2034 | 2051 | |
| 2035 | 2052 | fail_channel: |
| 2036 | − for_each_set_bit(ch, &gpriv->channels_mask, max_channels) | |
| 2053 | + for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) | |
| 2037 | 2054 | rcar_canfd_channel_remove(gpriv, ch); |
| 2038 | 2055 | fail_mode: |
| 2039 | 2056 | rcar_canfd_disable_global_interrupts(gpriv); |
| @@ -2054,7 +2071,7 @@ static int rcar_canfd_remove(struct platform_device *pdev) · 14 unmodified lines | ||
| 2054 | 2071 | rcar_canfd_reset_controller(gpriv); |
| 2055 | 2072 | rcar_canfd_disable_global_interrupts(gpriv); |
| 2056 | 2073 | |
| 2057 | − for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) { | |
| 2074 | + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { | |
| 2058 | 2075 | rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]); |
| 2059 | 2076 | rcar_canfd_channel_remove(gpriv, ch); |
| 2060 | 2077 | } |
| @@ -2082,9 +2099,9 @@ static SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend, · 21 unmodified lines | ||
| 2082 | 2099 | rcar_canfd_resume); |
| 2083 | 2100 | |
| 2084 | 2101 | static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = { |
| 2085 | − { .compatible = "renesas,rcar-gen3-canfd", .data = (void *)RENESAS_RCAR_GEN3 }, | |
| 2086 | − { .compatible = "renesas,rzg2l-canfd", .data = (void *)RENESAS_RZG2L }, | |
| 2087 | − { .compatible = "renesas,r8a779a0-canfd", .data = (void *)RENESAS_R8A779A0 }, | |
| 2102 | + { .compatible = "renesas,rcar-gen3-canfd", .data = &rcar_gen3_hw_info }, | |
| 2103 | + { .compatible = "renesas,rzg2l-canfd", .data = &rzg2l_hw_info }, | |
| 2104 | + { .compatible = "renesas,r8a779a0-canfd", .data = &r8a779a0_hw_info }, | |
| 2088 | 2105 | { } |
| 2089 | 2106 | }; |
| 2090 | 2107 | |
| @@ -30,6 +30,7 @@ config CAN_ESD_USB · 29 unmodified lines | ||
| 30 | 30 | config CAN_ETAS_ES58X |
| 31 | 31 | tristate "ETAS ES58X CAN/USB interfaces" |
| 32 | 32 | select CRC16 |
| 33 | + select NET_DEVLINK | |
| 33 | 34 | help |
| 34 | 35 | This driver supports the ES581.4, ES582.1 and ES584.1 interfaces |
| 35 | 36 | from ETAS GmbH (https://www.etas.com/en/products/es58x.php). |
| @@ -38,10 +39,13 @@ config CAN_ETAS_ES58X · 2 unmodified lines | ||
| 38 | 39 | will be called etas_es58x. |
| 39 | 40 | |
| 40 | 41 | config CAN_GS_USB |
| 41 | − tristate "Geschwister Schneider UG interfaces" | |
| 42 | + tristate "Geschwister Schneider UG and candleLight compatible interfaces" | |
| 42 | 43 | help |
| 43 | − This driver supports the Geschwister Schneider and bytewerk.org | |
| 44 | − candleLight USB CAN interfaces USB/CAN devices | |
| 44 | + This driver supports the Geschwister Schneider and | |
| 45 | + bytewerk.org candleLight compatible | |
| 46 | + (https://github.com/candle-usb/candleLight_fw) USB/CAN | |
| 47 | + interfaces. | |
| 48 | + | |
| 45 | 49 | If unsure choose N, |
| 46 | 50 | choose Y for built in support, |
| 47 | 51 | M to compile as module (module will be named: gs_usb). |
| @@ -1,3 +1,3 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x.o |
| 3 | −etas_es58x-y = es58x_core.o es581_4.o es58x_fd.o | |
| 3 | +etas_es58x-y = es58x_core.o es58x_devlink.o es581_4.o es58x_fd.o | |
| @@ -6,12 +6,12 @@ · 5 unmodified lines | ||
| 6 | 6 | * |
| 7 | 7 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 8 | 8 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. |
| 9 | − * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 9 | + * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | +#include <asm/unaligned.h> | |
| 12 | 13 | #include <linux/kernel.h> |
| 13 | 14 | #include <linux/units.h> |
| 14 | −#include <asm/unaligned.h> | |
| 15 | 15 | |
| 16 | 16 | #include "es58x_core.h" |
| 17 | 17 | #include "es581_4.h" |
| @@ -7,15 +7,16 @@ · 6 unmodified lines | ||
| 7 | 7 | * |
| 8 | 8 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 9 | 9 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. |
| 10 | − * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 10 | + * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 11 | 11 | */ |
| 12 | 12 | |
| 13 | +#include <asm/unaligned.h> | |
| 14 | +#include <linux/crc16.h> | |
| 13 | 15 | #include <linux/ethtool.h> |
| 14 | 16 | #include <linux/kernel.h> |
| 15 | 17 | #include <linux/module.h> |
| 16 | 18 | #include <linux/usb.h> |
| 17 | −#include <linux/crc16.h> | |
| 18 | −#include <asm/unaligned.h> | |
| 19 | +#include <net/devlink.h> | |
| 19 | 20 | |
| 20 | 21 | #include "es58x_core.h" |
| 21 | 22 | |
| @@ -2038,10 +2039,16 @@ static int es58x_set_mode(struct net_device *netdev, enum can_mode mode) · 2016 unmodified lines | ||
| 2038 | 2039 | * @es58x_dev: ES58X device. |
| 2039 | 2040 | * @priv: ES58X private parameters related to the network device. |
| 2040 | 2041 | * @channel_idx: Index of the network device. |
| 2042 | + * | |
| 2043 | + * Return: zero on success, errno if devlink port could not be | |
| 2044 | + * properly registered. | |
| 2041 | 2045 | */ |
| 2042 | −static void es58x_init_priv(struct es58x_device *es58x_dev, | |
| 2043 | − struct es58x_priv *priv, int channel_idx) | |
| 2046 | +static int es58x_init_priv(struct es58x_device *es58x_dev, | |
| 2047 | + struct es58x_priv *priv, int channel_idx) | |
| 2044 | 2048 | { |
| 2049 | + struct devlink_port_attrs attrs = { | |
| 2050 | + .flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL, | |
| 2051 | + }; | |
| 2045 | 2052 | const struct es58x_parameters *param = es58x_dev->param; |
| 2046 | 2053 | struct can_priv *can = &priv->can; |
| 2047 | 2054 | |
| @@ -2060,6 +2067,10 @@ static void es58x_init_priv(struct es58x_device *es58x_dev, · 12 unmodified lines | ||
| 2060 | 2067 | can->state = CAN_STATE_STOPPED; |
| 2061 | 2068 | can->ctrlmode_supported = param->ctrlmode_supported; |
| 2062 | 2069 | can->do_set_mode = es58x_set_mode; |
| 2070 | + | |
| 2071 | + devlink_port_attrs_set(&priv->devlink_port, &attrs); | |
| 2072 | + return devlink_port_register(priv_to_devlink(es58x_dev), | |
| 2073 | + &priv->devlink_port, channel_idx); | |
| 2063 | 2074 | } |
| 2064 | 2075 | |
| 2065 | 2076 | /** |
| @@ -2083,7 +2094,10 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx) · 17 unmodified lines | ||
| 2083 | 2094 | } |
| 2084 | 2095 | SET_NETDEV_DEV(netdev, dev); |
| 2085 | 2096 | es58x_dev->netdev[channel_idx] = netdev; |
| 2086 | − es58x_init_priv(es58x_dev, es58x_priv(netdev), channel_idx); | |
| 2097 | + ret = es58x_init_priv(es58x_dev, es58x_priv(netdev), channel_idx); | |
| 2098 | + if (ret) | |
| 2099 | + goto free_candev; | |
| 2100 | + SET_NETDEV_DEVLINK_PORT(netdev, &es58x_priv(netdev)->devlink_port); | |
| 2087 | 2101 | |
| 2088 | 2102 | netdev->netdev_ops = &es58x_netdev_ops; |
| 2089 | 2103 | netdev->ethtool_ops = &es58x_ethtool_ops; |
| @@ -2091,16 +2105,20 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx) · 1 unmodified line | ||
| 2091 | 2105 | netdev->dev_port = channel_idx; |
| 2092 | 2106 | |
| 2093 | 2107 | ret = register_candev(netdev); |
| 2094 | − if (ret) { | |
| 2095 | − es58x_dev->netdev[channel_idx] = NULL; | |
| 2096 | − free_candev(netdev); | |
| 2097 | − return ret; | |
| 2098 | − } | |
| 2108 | + if (ret) | |
| 2109 | + goto devlink_port_unregister; | |
| 2099 | 2110 | |
| 2100 | 2111 | netdev_queue_set_dql_min_limit(netdev_get_tx_queue(netdev, 0), |
| 2101 | 2112 | es58x_dev->param->dql_min_limit); |
| 2102 | 2113 | |
| 2103 | 2114 | return ret; |
| 2115 | + | |
| 2116 | + devlink_port_unregister: | |
| 2117 | + devlink_port_unregister(&es58x_priv(netdev)->devlink_port); | |
| 2118 | + free_candev: | |
| 2119 | + es58x_dev->netdev[channel_idx] = NULL; | |
| 2120 | + free_candev(netdev); | |
| 2121 | + return ret; | |
| 2104 | 2122 | } |
| 2105 | 2123 | |
| 2106 | 2124 | /** |
| @@ -2117,53 +2135,12 @@ static void es58x_free_netdevs(struct es58x_device *es58x_dev) · 10 unmodified lines | ||
| 2117 | 2135 | if (!netdev) |
| 2118 | 2136 | continue; |
| 2119 | 2137 | unregister_candev(netdev); |
| 2138 | + devlink_port_unregister(&es58x_priv(netdev)->devlink_port); | |
| 2120 | 2139 | es58x_dev->netdev[i] = NULL; |
| 2121 | 2140 | free_candev(netdev); |
| 2122 | 2141 | } |
| 2123 | 2142 | } |
| 2124 | 2143 | |
| 2125 | −/** | |
| 2126 | − * es58x_get_product_info() - Get the product information and print them. | |
| 2127 | − * @es58x_dev: ES58X device. | |
| 2128 | − * | |
| 2129 | − * Do a synchronous call to get the product information. | |
| 2130 | − * | |
| 2131 | − * Return: zero on success, errno when any error occurs. | |
| 2132 | − */ | |
| 2133 | −static int es58x_get_product_info(struct es58x_device *es58x_dev) | |
| 2134 | −{ | |
| 2135 | − struct usb_device *udev = es58x_dev->udev; | |
| 2136 | − const int es58x_prod_info_idx = 6; | |
| 2137 | − /* Empirical tests show a prod_info length of maximum 83, | |
| 2138 | − * below should be more than enough. | |
| 2139 | − */ | |
| 2140 | − const size_t prod_info_len = 127; | |
| 2141 | − char *prod_info; | |
| 2142 | − int ret; | |
| 2143 | − | |
| 2144 | − prod_info = kmalloc(prod_info_len, GFP_KERNEL); | |
| 2145 | − if (!prod_info) | |
| 2146 | − return -ENOMEM; | |
| 2147 | − | |
| 2148 | − ret = usb_string(udev, es58x_prod_info_idx, prod_info, prod_info_len); | |
| 2149 | − if (ret < 0) { | |
| 2150 | − dev_err(es58x_dev->dev, | |
| 2151 | − "%s: Could not read the product info: %pe\n", | |
| 2152 | − __func__, ERR_PTR(ret)); | |
| 2153 | − goto out_free; | |
| 2154 | − } | |
| 2155 | − if (ret >= prod_info_len - 1) { | |
| 2156 | − dev_warn(es58x_dev->dev, | |
| 2157 | − "%s: Buffer is too small, result might be truncated\n", | |
| 2158 | − __func__); | |
| 2159 | − } | |
| 2160 | − dev_info(es58x_dev->dev, "Product info: %s\n", prod_info); | |
| 2161 | − | |
| 2162 | − out_free: | |
| 2163 | − kfree(prod_info); | |
| 2164 | − return ret < 0 ? ret : 0; | |
| 2165 | −} | |
| 2166 | − | |
| 2167 | 2144 | /** |
| 2168 | 2145 | * es58x_init_es58x_dev() - Initialize the ES58X device. |
| 2169 | 2146 | * @intf: USB interface. |
| @@ -2177,6 +2154,7 @@ static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf, · 7 unmodified lines | ||
| 2177 | 2154 | { |
| 2178 | 2155 | struct device *dev = &intf->dev; |
| 2179 | 2156 | struct es58x_device *es58x_dev; |
| 2157 | + struct devlink *devlink; | |
| 2180 | 2158 | const struct es58x_parameters *param; |
| 2181 | 2159 | const struct es58x_operators *ops; |
| 2182 | 2160 | struct usb_device *udev = interface_to_usbdev(intf); |
| @@ -2199,11 +2177,12 @@ static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf, · 16 unmodified lines | ||
| 2199 | 2177 | ops = &es581_4_ops; |
| 2200 | 2178 | } |
| 2201 | 2179 | |
| 2202 | − es58x_dev = devm_kzalloc(dev, es58x_sizeof_es58x_device(param), | |
| 2203 | − GFP_KERNEL); | |
| 2204 | − if (!es58x_dev) | |
| 2180 | + devlink = devlink_alloc(&es58x_dl_ops, es58x_sizeof_es58x_device(param), | |
| 2181 | + dev); | |
| 2182 | + if (!devlink) | |
| 2205 | 2183 | return ERR_PTR(-ENOMEM); |
| 2206 | 2184 | |
| 2185 | + es58x_dev = devlink_priv(devlink); | |
| 2207 | 2186 | es58x_dev->param = param; |
| 2208 | 2187 | es58x_dev->ops = ops; |
| 2209 | 2188 | es58x_dev->dev = dev; |
| @@ -2240,25 +2219,24 @@ static int es58x_probe(struct usb_interface *intf, · 30 unmodified lines | ||
| 2240 | 2219 | const struct usb_device_id *id) |
| 2241 | 2220 | { |
| 2242 | 2221 | struct es58x_device *es58x_dev; |
| 2243 | − int ch_idx, ret; | |
| 2222 | + int ch_idx; | |
| 2244 | 2223 | |
| 2245 | 2224 | es58x_dev = es58x_init_es58x_dev(intf, id->driver_info); |
| 2246 | 2225 | if (IS_ERR(es58x_dev)) |
| 2247 | 2226 | return PTR_ERR(es58x_dev); |
| 2248 | 2227 | |
| 2249 | − ret = es58x_get_product_info(es58x_dev); | |
| 2250 | − if (ret) | |
| 2251 | − return ret; | |
| 2228 | + es58x_parse_product_info(es58x_dev); | |
| 2229 | + devlink_register(priv_to_devlink(es58x_dev)); | |
| 2252 | 2230 | |
| 2253 | 2231 | for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++) { |
| 2254 | − ret = es58x_init_netdev(es58x_dev, ch_idx); | |
| 2232 | + int ret = es58x_init_netdev(es58x_dev, ch_idx); | |
| 2255 | 2233 | if (ret) { |
| 2256 | 2234 | es58x_free_netdevs(es58x_dev); |
| 2257 | 2235 | return ret; |
| 2258 | 2236 | } |
| 2259 | 2237 | } |
| 2260 | 2238 | |
| 2261 | − return ret; | |
| 2239 | + return 0; | |
| 2262 | 2240 | } |
| 2263 | 2241 | |
| 2264 | 2242 | /** |
| @@ -2275,8 +2253,10 @@ static void es58x_disconnect(struct usb_interface *intf) · 10 unmodified lines | ||
| 2275 | 2253 | dev_info(&intf->dev, "Disconnecting %s %s\n", |
| 2276 | 2254 | es58x_dev->udev->manufacturer, es58x_dev->udev->product); |
| 2277 | 2255 | |
| 2256 | + devlink_unregister(priv_to_devlink(es58x_dev)); | |
| 2278 | 2257 | es58x_free_netdevs(es58x_dev); |
| 2279 | 2258 | es58x_free_urbs(es58x_dev); |
| 2259 | + devlink_free(priv_to_devlink(es58x_dev)); | |
| 2280 | 2260 | usb_set_intfdata(intf, NULL); |
| 2281 | 2261 | } |
| 2282 | 2262 | |
| @@ -6,17 +6,18 @@ · 5 unmodified lines | ||
| 6 | 6 | * |
| 7 | 7 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 8 | 8 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. |
| 9 | − * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 9 | + * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | #ifndef __ES58X_COMMON_H__ |
| 13 | 13 | #define __ES58X_COMMON_H__ |
| 14 | 14 | |
| 15 | −#include <linux/types.h> | |
| 16 | −#include <linux/usb.h> | |
| 17 | −#include <linux/netdevice.h> | |
| 18 | 15 | #include <linux/can.h> |
| 19 | 16 | #include <linux/can/dev.h> |
| 17 | +#include <linux/netdevice.h> | |
| 18 | +#include <linux/types.h> | |
| 19 | +#include <linux/usb.h> | |
| 20 | +#include <net/devlink.h> | |
| 20 | 21 | |
| 21 | 22 | #include "es581_4.h" |
| 22 | 23 | #include "es58x_fd.h" |
| @@ -230,6 +231,7 @@ union es58x_urb_cmd { · 207 unmodified lines | ||
| 230 | 231 | * @can: struct can_priv must be the first member (Socket CAN relies |
| 231 | 232 | * on the fact that function netdev_priv() returns a pointer to |
| 232 | 233 | * a struct can_priv). |
| 234 | + * @devlink_port: devlink instance for the network interface. | |
| 233 | 235 | * @es58x_dev: pointer to the corresponding ES58X device. |
| 234 | 236 | * @tx_urb: Used as a buffer to concatenate the TX messages and to do |
| 235 | 237 | * a bulk send. Please refer to es58x_start_xmit() for more |
| @@ -255,6 +257,7 @@ union es58x_urb_cmd { · 19 unmodified lines | ||
| 255 | 257 | */ |
| 256 | 258 | struct es58x_priv { |
| 257 | 259 | struct can_priv can; |
| 260 | + struct devlink_port devlink_port; | |
| 258 | 261 | struct es58x_device *es58x_dev; |
| 259 | 262 | struct urb *tx_urb; |
| 260 | 263 | |
| @@ -356,6 +359,39 @@ struct es58x_operators { · 95 unmodified lines | ||
| 356 | 359 | int (*get_timestamp)(struct es58x_device *es58x_dev); |
| 357 | 360 | }; |
| 358 | 361 | |
| 362 | +/** | |
| 363 | + * struct es58x_sw_version - Version number of the firmware or the | |
| 364 | + * bootloader. | |
| 365 | + * @major: Version major number, represented on two digits. | |
| 366 | + * @minor: Version minor number, represented on two digits. | |
| 367 | + * @revision: Version revision number, represented on two digits. | |
| 368 | + * | |
| 369 | + * The firmware and the bootloader share the same format: "xx.xx.xx" | |
| 370 | + * where 'x' is a digit. Both can be retrieved from the product | |
| 371 | + * information string. | |
| 372 | + */ | |
| 373 | +struct es58x_sw_version { | |
| 374 | + u8 major; | |
| 375 | + u8 minor; | |
| 376 | + u8 revision; | |
| 377 | +}; | |
| 378 | + | |
| 379 | +/** | |
| 380 | + * struct es58x_hw_revision - Hardware revision number. | |
| 381 | + * @letter: Revision letter. | |
| 382 | + * @major: Version major number, represented on three digits. | |
| 383 | + * @minor: Version minor number, represented on three digits. | |
| 384 | + * | |
| 385 | + * The hardware revision uses its own format: "axxx/xxx" where 'a' is | |
| 386 | + * a letter and 'x' a digit. It can be retrieved from the product | |
| 387 | + * information string. | |
| 388 | + */ | |
| 389 | +struct es58x_hw_revision { | |
| 390 | + char letter; | |
| 391 | + u16 major; | |
| 392 | + u16 minor; | |
| 393 | +}; | |
| 394 | + | |
| 359 | 395 | /** |
| 360 | 396 | * struct es58x_device - All information specific to an ES58X device. |
| 361 | 397 | * @dev: Device information. |
| @@ -373,6 +409,9 @@ struct es58x_operators { · 11 unmodified lines | ||
| 373 | 409 | * queue wake/stop logic should prevent this URB from getting |
| 374 | 410 | * empty. Please refer to es58x_get_tx_urb() for more details. |
| 375 | 411 | * @tx_urbs_idle_cnt: number of urbs in @tx_urbs_idle. |
| 412 | + * @firmware_version: The firmware version number. | |
| 413 | + * @bootloader_version: The bootloader version number. | |
| 414 | + * @hardware_revision: The hardware revision number. | |
| 376 | 415 | * @ktime_req_ns: kernel timestamp when es58x_set_realtime_diff_ns() |
| 377 | 416 | * was called. |
| 378 | 417 | * @realtime_diff_ns: difference in nanoseconds between the clocks of |
| @@ -408,6 +447,10 @@ struct es58x_device { · 29 unmodified lines | ||
| 408 | 447 | struct usb_anchor tx_urbs_idle; |
| 409 | 448 | atomic_t tx_urbs_idle_cnt; |
| 410 | 449 | |
| 450 | + struct es58x_sw_version firmware_version; | |
| 451 | + struct es58x_sw_version bootloader_version; | |
| 452 | + struct es58x_hw_revision hardware_revision; | |
| 453 | + | |
| 411 | 454 | u64 ktime_req_ns; |
| 412 | 455 | s64 realtime_diff_ns; |
| 413 | 456 | |
| @@ -674,6 +717,7 @@ static inline enum es58x_flag es58x_get_flags(const struct sk_buff *skb) · 260 unmodified lines | ||
| 674 | 717 | return es58x_flags; |
| 675 | 718 | } |
| 676 | 719 | |
| 720 | +/* es58x_core.c. */ | |
| 677 | 721 | int es58x_can_get_echo_skb(struct net_device *netdev, u32 packet_idx, |
| 678 | 722 | u64 *tstamps, unsigned int pkts); |
| 679 | 723 | int es58x_tx_ack_msg(struct net_device *netdev, u16 tx_free_entries, |
| @@ -691,9 +735,15 @@ int es58x_rx_cmd_ret_u32(struct net_device *netdev, · 11 unmodified lines | ||
| 691 | 735 | int es58x_send_msg(struct es58x_device *es58x_dev, u8 cmd_type, u8 cmd_id, |
| 692 | 736 | const void *msg, u16 cmd_len, int channel_idx); |
| 693 | 737 | |
| 738 | +/* es58x_devlink.c. */ | |
| 739 | +void es58x_parse_product_info(struct es58x_device *es58x_dev); | |
| 740 | +extern const struct devlink_ops es58x_dl_ops; | |
| 741 | + | |
| 742 | +/* es581_4.c. */ | |
| 694 | 743 | extern const struct es58x_parameters es581_4_param; |
| 695 | 744 | extern const struct es58x_operators es581_4_ops; |
| 696 | 745 | |
| 746 | +/* es58x_fd.c. */ | |
| 697 | 747 | extern const struct es58x_parameters es58x_fd_param; |
| 698 | 748 | extern const struct es58x_operators es58x_fd_ops; |
| 699 | 749 | |
| @@ -0,0 +1,235 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces. | |
| 4 | + * | |
| 5 | + * File es58x_devlink.c: report the product information using devlink. | |
| 6 | + * | |
| 7 | + * Copyright (c) 2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include <linux/ctype.h> | |
| 11 | +#include <linux/device.h> | |
| 12 | +#include <linux/usb.h> | |
| 13 | +#include <net/devlink.h> | |
| 14 | + | |
| 15 | +#include "es58x_core.h" | |
| 16 | + | |
| 17 | +/* USB descriptor index containing the product information string. */ | |
| 18 | +#define ES58X_PROD_INFO_IDX 6 | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * es58x_parse_sw_version() - Extract boot loader or firmware version. | |
| 22 | + * @es58x_dev: ES58X device. | |
| 23 | + * @prod_info: USB custom string returned by the device. | |
| 24 | + * @prefix: Select which information should be parsed. Set it to "FW" | |
| 25 | + * to parse the firmware version or to "BL" to parse the | |
| 26 | + * bootloader version. | |
| 27 | + * | |
| 28 | + * The @prod_info string contains the firmware and the bootloader | |
| 29 | + * version number all prefixed by a magic string and concatenated with | |
| 30 | + * other numbers. Depending on the device, the firmware (bootloader) | |
| 31 | + * format is either "FW_Vxx.xx.xx" ("BL_Vxx.xx.xx") or "FW:xx.xx.xx" | |
| 32 | + * ("BL:xx.xx.xx") where 'x' represents a digit. @prod_info must | |
| 33 | + * contains the common part of those prefixes: "FW" or "BL". | |
| 34 | + * | |
| 35 | + * Parse @prod_info and store the version number in | |
| 36 | + * &es58x_dev.firmware_version or &es58x_dev.bootloader_version | |
| 37 | + * according to @prefix value. | |
| 38 | + * | |
| 39 | + * Return: zero on success, -EINVAL if @prefix contains an invalid | |
| 40 | + * value and -EBADMSG if @prod_info could not be parsed. | |
| 41 | + */ | |
| 42 | +static int es58x_parse_sw_version(struct es58x_device *es58x_dev, | |
| 43 | + const char *prod_info, const char *prefix) | |
| 44 | +{ | |
| 45 | + struct es58x_sw_version *version; | |
| 46 | + int major, minor, revision; | |
| 47 | + | |
| 48 | + if (!strcmp(prefix, "FW")) | |
| 49 | + version = &es58x_dev->firmware_version; | |
| 50 | + else if (!strcmp(prefix, "BL")) | |
| 51 | + version = &es58x_dev->bootloader_version; | |
| 52 | + else | |
| 53 | + return -EINVAL; | |
| 54 | + | |
| 55 | + /* Go to prefix */ | |
| 56 | + prod_info = strstr(prod_info, prefix); | |
| 57 | + if (!prod_info) | |
| 58 | + return -EBADMSG; | |
| 59 | + /* Go to beginning of the version number */ | |
| 60 | + while (!isdigit(*prod_info)) { | |
| 61 | + prod_info++; | |
| 62 | + if (!*prod_info) | |
| 63 | + return -EBADMSG; | |
| 64 | + } | |
| 65 | + | |
| 66 | + if (sscanf(prod_info, "%2u.%2u.%2u", &major, &minor, &revision) != 3) | |
| 67 | + return -EBADMSG; | |
| 68 | + | |
| 69 | + version->major = major; | |
| 70 | + version->minor = minor; | |
| 71 | + version->revision = revision; | |
| 72 | + | |
| 73 | + return 0; | |
| 74 | +} | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * es58x_parse_hw_rev() - Extract hardware revision number. | |
| 78 | + * @es58x_dev: ES58X device. | |
| 79 | + * @prod_info: USB custom string returned by the device. | |
| 80 | + * | |
| 81 | + * @prod_info contains the hardware revision prefixed by a magic | |
| 82 | + * string and conquenated together with other numbers. Depending on | |
| 83 | + * the device, the hardware revision format is either | |
| 84 | + * "HW_VER:axxx/xxx" or "HR:axxx/xxx" where 'a' represents a letter | |
| 85 | + * and 'x' a digit. | |
| 86 | + * | |
| 87 | + * Parse @prod_info and store the hardware revision number in | |
| 88 | + * &es58x_dev.hardware_revision. | |
| 89 | + * | |
| 90 | + * Return: zero on success, -EBADMSG if @prod_info could not be | |
| 91 | + * parsed. | |
| 92 | + */ | |
| 93 | +static int es58x_parse_hw_rev(struct es58x_device *es58x_dev, | |
| 94 | + const char *prod_info) | |
| 95 | +{ | |
| 96 | + char letter; | |
| 97 | + int major, minor; | |
| 98 | + | |
| 99 | + /* The only occurrence of 'H' is in the hardware revision prefix. */ | |
| 100 | + prod_info = strchr(prod_info, 'H'); | |
| 101 | + if (!prod_info) | |
| 102 | + return -EBADMSG; | |
| 103 | + /* Go to beginning of the hardware revision */ | |
| 104 | + prod_info = strchr(prod_info, ':'); | |
| 105 | + if (!prod_info) | |
| 106 | + return -EBADMSG; | |
| 107 | + prod_info++; | |
| 108 | + | |
| 109 | + if (sscanf(prod_info, "%c%3u/%3u", &letter, &major, &minor) != 3) | |
| 110 | + return -EBADMSG; | |
| 111 | + | |
| 112 | + es58x_dev->hardware_revision.letter = letter; | |
| 113 | + es58x_dev->hardware_revision.major = major; | |
| 114 | + es58x_dev->hardware_revision.minor = minor; | |
| 115 | + | |
| 116 | + return 0; | |
| 117 | +} | |
| 118 | + | |
| 119 | +/** | |
| 120 | + * es58x_parse_product_info() - Parse the ES58x product information | |
| 121 | + * string. | |
| 122 | + * @es58x_dev: ES58X device. | |
| 123 | + * | |
| 124 | + * Retrieve the product information string and parse it to extract the | |
| 125 | + * firmware version, the bootloader version and the hardware | |
| 126 | + * revision. | |
| 127 | + * | |
| 128 | + * If the function fails, simply emit a log message and continue | |
| 129 | + * because product information is not critical for the driver to | |
| 130 | + * operate. | |
| 131 | + */ | |
| 132 | +void es58x_parse_product_info(struct es58x_device *es58x_dev) | |
| 133 | +{ | |
| 134 | + char *prod_info; | |
| 135 | + | |
| 136 | + prod_info = usb_cache_string(es58x_dev->udev, ES58X_PROD_INFO_IDX); | |
| 137 | + if (!prod_info) { | |
| 138 | + dev_warn(es58x_dev->dev, | |
| 139 | + "could not retrieve the product info string\n"); | |
| 140 | + return; | |
| 141 | + } | |
| 142 | + | |
| 143 | + if (es58x_parse_sw_version(es58x_dev, prod_info, "FW") || | |
| 144 | + es58x_parse_sw_version(es58x_dev, prod_info, "BL") || | |
| 145 | + es58x_parse_hw_rev(es58x_dev, prod_info)) | |
| 146 | + dev_info(es58x_dev->dev, | |
| 147 | + "could not parse product info: '%s'\n", prod_info); | |
| 148 | + | |
| 149 | + kfree(prod_info); | |
| 150 | +} | |
| 151 | + | |
| 152 | +/** | |
| 153 | + * es58x_sw_version_is_set() - Check if the version is a valid number. | |
| 154 | + * @sw_ver: Version number of either the firmware or the bootloader. | |
| 155 | + * | |
| 156 | + * If &es58x_sw_version.major, &es58x_sw_version.minor and | |
| 157 | + * &es58x_sw_version.revision are all zero, the product string could | |
| 158 | + * not be parsed and the version number is invalid. | |
| 159 | + */ | |
| 160 | +static inline bool es58x_sw_version_is_set(struct es58x_sw_version *sw_ver) | |
| 161 | +{ | |
| 162 | + return sw_ver->major || sw_ver->minor || sw_ver->revision; | |
| 163 | +} | |
| 164 | + | |
| 165 | +/** | |
| 166 | + * es58x_hw_revision_is_set() - Check if the revision is a valid number. | |
| 167 | + * @hw_rev: Revision number of the hardware. | |
| 168 | + * | |
| 169 | + * If &es58x_hw_revision.letter is the null character, the product | |
| 170 | + * string could not be parsed and the hardware revision number is | |
| 171 | + * invalid. | |
| 172 | + */ | |
| 173 | +static inline bool es58x_hw_revision_is_set(struct es58x_hw_revision *hw_rev) | |
| 174 | +{ | |
| 175 | + return hw_rev->letter != '\0'; | |
| 176 | +} | |
| 177 | + | |
| 178 | +/** | |
| 179 | + * es58x_devlink_info_get() - Report the product information. | |
| 180 | + * @devlink: Devlink. | |
| 181 | + * @req: skb wrapper where to put requested information. | |
| 182 | + * @extack: Unused. | |
| 183 | + * | |
| 184 | + * Report the firmware version, the bootloader version, the hardware | |
| 185 | + * revision and the serial number through netlink. | |
| 186 | + * | |
| 187 | + * Return: zero on success, errno when any error occurs. | |
| 188 | + */ | |
| 189 | +static int es58x_devlink_info_get(struct devlink *devlink, | |
| 190 | + struct devlink_info_req *req, | |
| 191 | + struct netlink_ext_ack *extack) | |
| 192 | +{ | |
| 193 | + struct es58x_device *es58x_dev = devlink_priv(devlink); | |
| 194 | + struct es58x_sw_version *fw_ver = &es58x_dev->firmware_version; | |
| 195 | + struct es58x_sw_version *bl_ver = &es58x_dev->bootloader_version; | |
| 196 | + struct es58x_hw_revision *hw_rev = &es58x_dev->hardware_revision; | |
| 197 | + char buf[max(sizeof("xx.xx.xx"), sizeof("axxx/xxx"))]; | |
| 198 | + int ret = 0; | |
| 199 | + | |
| 200 | + if (es58x_sw_version_is_set(fw_ver)) { | |
| 201 | + snprintf(buf, sizeof(buf), "%02u.%02u.%02u", | |
| 202 | + fw_ver->major, fw_ver->minor, fw_ver->revision); | |
| 203 | + ret = devlink_info_version_running_put(req, | |
| 204 | + DEVLINK_INFO_VERSION_GENERIC_FW, | |
| 205 | + buf); | |
| 206 | + if (ret) | |
| 207 | + return ret; | |
| 208 | + } | |
| 209 | + | |
| 210 | + if (es58x_sw_version_is_set(bl_ver)) { | |
| 211 | + snprintf(buf, sizeof(buf), "%02u.%02u.%02u", | |
| 212 | + bl_ver->major, bl_ver->minor, bl_ver->revision); | |
| 213 | + ret = devlink_info_version_running_put(req, | |
| 214 | + DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER, | |
| 215 | + buf); | |
| 216 | + if (ret) | |
| 217 | + return ret; | |
| 218 | + } | |
| 219 | + | |
| 220 | + if (es58x_hw_revision_is_set(hw_rev)) { | |
| 221 | + snprintf(buf, sizeof(buf), "%c%03u/%03u", | |
| 222 | + hw_rev->letter, hw_rev->major, hw_rev->minor); | |
| 223 | + ret = devlink_info_version_fixed_put(req, | |
| 224 | + DEVLINK_INFO_VERSION_GENERIC_BOARD_REV, | |
| 225 | + buf); | |
| 226 | + if (ret) | |
| 227 | + return ret; | |
| 228 | + } | |
| 229 | + | |
| 230 | + return devlink_info_serial_number_put(req, es58x_dev->udev->serial); | |
| 231 | +} | |
| 232 | + | |
| 233 | +const struct devlink_ops es58x_dl_ops = { | |
| 234 | + .info_get = es58x_devlink_info_get, | |
| 235 | +}; | |
| @@ -8,12 +8,12 @@ · 7 unmodified lines | ||
| 8 | 8 | * |
| 9 | 9 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 10 | 10 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. |
| 11 | − * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 11 | + * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | +#include <asm/unaligned.h> | |
| 14 | 15 | #include <linux/kernel.h> |
| 15 | 16 | #include <linux/units.h> |
| 16 | −#include <asm/unaligned.h> | |
| 17 | 17 | |
| 18 | 18 | #include "es58x_core.h" |
| 19 | 19 | #include "es58x_fd.h" |
| @@ -66,6 +66,7 @@ enum gs_usb_breq { · 65 unmodified lines | ||
| 66 | 66 | GS_USB_BREQ_BT_CONST_EXT, |
| 67 | 67 | GS_USB_BREQ_SET_TERMINATION, |
| 68 | 68 | GS_USB_BREQ_GET_TERMINATION, |
| 69 | + GS_USB_BREQ_GET_STATE, | |
| 69 | 70 | }; |
| 70 | 71 | |
| 71 | 72 | enum gs_can_mode { |
| @@ -134,6 +135,8 @@ struct gs_device_config { · 62 unmodified lines | ||
| 134 | 135 | /* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */ |
| 135 | 136 | /* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */ |
| 136 | 137 | /* GS_CAN_FEATURE_TERMINATION BIT(11) */ |
| 138 | +#define GS_CAN_MODE_BERR_REPORTING BIT(12) | |
| 139 | +/* GS_CAN_FEATURE_GET_STATE BIT(13) */ | |
| 137 | 140 | |
| 138 | 141 | struct gs_device_mode { |
| 139 | 142 | __le32 mode; |
| @@ -174,7 +177,9 @@ struct gs_device_termination_state { · 34 unmodified lines | ||
| 174 | 177 | #define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) |
| 175 | 178 | #define GS_CAN_FEATURE_BT_CONST_EXT BIT(10) |
| 176 | 179 | #define GS_CAN_FEATURE_TERMINATION BIT(11) |
| 177 | −#define GS_CAN_FEATURE_MASK GENMASK(11, 0) | |
| 180 | +#define GS_CAN_FEATURE_BERR_REPORTING BIT(12) | |
| 181 | +#define GS_CAN_FEATURE_GET_STATE BIT(13) | |
| 182 | +#define GS_CAN_FEATURE_MASK GENMASK(13, 0) | |
| 178 | 183 | |
| 179 | 184 | /* internal quirks - keep in GS_CAN_FEATURE space for now */ |
| 180 | 185 | |
| @@ -294,7 +299,6 @@ struct gs_can { · 113 unmodified lines | ||
| 294 | 299 | |
| 295 | 300 | struct net_device *netdev; |
| 296 | 301 | struct usb_device *udev; |
| 297 | − struct usb_interface *iface; | |
| 298 | 302 | |
| 299 | 303 | struct can_bittiming_const bt_const, data_bt_const; |
| 300 | 304 | unsigned int channel; /* channel number */ |
| @@ -378,8 +382,7 @@ static int gs_cmd_reset(struct gs_can *dev) · 77 unmodified lines | ||
| 378 | 382 | .mode = GS_CAN_MODE_RESET, |
| 379 | 383 | }; |
| 380 | 384 | |
| 381 | − return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | |
| 382 | − GS_USB_BREQ_MODE, | |
| 385 | + return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_MODE, | |
| 383 | 386 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 384 | 387 | dev->channel, 0, &dm, sizeof(dm), 1000, |
| 385 | 388 | GFP_KERNEL); |
| @@ -391,8 +394,7 @@ static inline int gs_usb_get_timestamp(const struct gs_can *dev, · 5 unmodified lines | ||
| 391 | 394 | __le32 timestamp; |
| 392 | 395 | int rc; |
| 393 | 396 | |
| 394 | − rc = usb_control_msg_recv(interface_to_usbdev(dev->iface), 0, | |
| 395 | − GS_USB_BREQ_TIMESTAMP, | |
| 397 | + rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_TIMESTAMP, | |
| 396 | 398 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 397 | 399 | dev->channel, 0, |
| 398 | 400 | ×tamp, sizeof(timestamp), |
| @@ -669,8 +671,7 @@ static int gs_usb_set_bittiming(struct net_device *netdev) · 270 unmodified lines | ||
| 669 | 671 | }; |
| 670 | 672 | |
| 671 | 673 | /* request bit timings */ |
| 672 | − return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | |
| 673 | − GS_USB_BREQ_BITTIMING, | |
| 674 | + return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_BITTIMING, | |
| 674 | 675 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 675 | 676 | dev->channel, 0, &dbt, sizeof(dbt), 1000, |
| 676 | 677 | GFP_KERNEL); |
| @@ -693,8 +694,7 @@ static int gs_usb_set_data_bittiming(struct net_device *netdev) · 16 unmodified lines | ||
| 693 | 694 | request = GS_USB_BREQ_QUIRK_CANTACT_PRO_DATA_BITTIMING; |
| 694 | 695 | |
| 695 | 696 | /* request data bit timings */ |
| 696 | − return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | |
| 697 | − request, | |
| 697 | + return usb_control_msg_send(dev->udev, 0, request, | |
| 698 | 698 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 699 | 699 | dev->channel, 0, &dbt, sizeof(dbt), 1000, |
| 700 | 700 | GFP_KERNEL); |
| @@ -843,8 +843,6 @@ static int gs_can_open(struct net_device *netdev) · 142 unmodified lines | ||
| 843 | 843 | |
| 844 | 844 | ctrlmode = dev->can.ctrlmode; |
| 845 | 845 | if (ctrlmode & CAN_CTRLMODE_FD) { |
| 846 | − flags |= GS_CAN_MODE_FD; | |
| 847 | − | |
| 848 | 846 | if (dev->feature & GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX) |
| 849 | 847 | dev->hf_size_tx = struct_size(hf, canfd_quirk, 1); |
| 850 | 848 | else |
| @@ -911,31 +909,34 @@ static int gs_can_open(struct net_device *netdev) · 60 unmodified lines | ||
| 911 | 909 | /* flags */ |
| 912 | 910 | if (ctrlmode & CAN_CTRLMODE_LOOPBACK) |
| 913 | 911 | flags |= GS_CAN_MODE_LOOP_BACK; |
| 914 | − else if (ctrlmode & CAN_CTRLMODE_LISTENONLY) | |
| 912 | + | |
| 913 | + if (ctrlmode & CAN_CTRLMODE_LISTENONLY) | |
| 915 | 914 | flags |= GS_CAN_MODE_LISTEN_ONLY; |
| 916 | 915 | |
| 917 | − /* Controller is not allowed to retry TX | |
| 918 | − * this mode is unavailable on atmels uc3c hardware | |
| 919 | − */ | |
| 916 | + if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) | |
| 917 | + flags |= GS_CAN_MODE_TRIPLE_SAMPLE; | |
| 918 | + | |
| 920 | 919 | if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) |
| 921 | 920 | flags |= GS_CAN_MODE_ONE_SHOT; |
| 922 | 921 | |
| 923 | − if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) | |
| 924 | − flags |= GS_CAN_MODE_TRIPLE_SAMPLE; | |
| 922 | + if (ctrlmode & CAN_CTRLMODE_BERR_REPORTING) | |
| 923 | + flags |= GS_CAN_MODE_BERR_REPORTING; | |
| 924 | + | |
| 925 | + if (ctrlmode & CAN_CTRLMODE_FD) | |
| 926 | + flags |= GS_CAN_MODE_FD; | |
| 925 | 927 | |
| 926 | 928 | /* if hardware supports timestamps, enable it */ |
| 927 | − if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) | |
| 929 | + if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) { | |
| 928 | 930 | flags |= GS_CAN_MODE_HW_TIMESTAMP; |
| 929 | 931 | |
| 930 | − /* start polling timestamp */ | |
| 931 | − if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) | |
| 932 | + /* start polling timestamp */ | |
| 932 | 933 | gs_usb_timestamp_init(dev); |
| 934 | + } | |
| 933 | 935 | |
| 934 | 936 | /* finally start device */ |
| 935 | 937 | dev->can.state = CAN_STATE_ERROR_ACTIVE; |
| 936 | 938 | dm.flags = cpu_to_le32(flags); |
| 937 | − rc = usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | |
| 938 | − GS_USB_BREQ_MODE, | |
| 939 | + rc = usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_MODE, | |
| 939 | 940 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 940 | 941 | dev->channel, 0, &dm, sizeof(dm), 1000, |
| 941 | 942 | GFP_KERNEL); |
| @@ -954,6 +955,41 @@ static int gs_can_open(struct net_device *netdev) · 12 unmodified lines | ||
| 954 | 955 | return 0; |
| 955 | 956 | } |
| 956 | 957 | |
| 958 | +static int gs_usb_get_state(const struct net_device *netdev, | |
| 959 | + struct can_berr_counter *bec, | |
| 960 | + enum can_state *state) | |
| 961 | +{ | |
| 962 | + struct gs_can *dev = netdev_priv(netdev); | |
| 963 | + struct gs_device_state ds; | |
| 964 | + int rc; | |
| 965 | + | |
| 966 | + rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_GET_STATE, | |
| 967 | + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | |
| 968 | + dev->channel, 0, | |
| 969 | + &ds, sizeof(ds), | |
| 970 | + USB_CTRL_GET_TIMEOUT, | |
| 971 | + GFP_KERNEL); | |
| 972 | + if (rc) | |
| 973 | + return rc; | |
| 974 | + | |
| 975 | + if (le32_to_cpu(ds.state) >= CAN_STATE_MAX) | |
| 976 | + return -EOPNOTSUPP; | |
| 977 | + | |
| 978 | + *state = le32_to_cpu(ds.state); | |
| 979 | + bec->txerr = le32_to_cpu(ds.txerr); | |
| 980 | + bec->rxerr = le32_to_cpu(ds.rxerr); | |
| 981 | + | |
| 982 | + return 0; | |
| 983 | +} | |
| 984 | + | |
| 985 | +static int gs_usb_can_get_berr_counter(const struct net_device *netdev, | |
| 986 | + struct can_berr_counter *bec) | |
| 987 | +{ | |
| 988 | + enum can_state state; | |
| 989 | + | |
| 990 | + return gs_usb_get_state(netdev, bec, &state); | |
| 991 | +} | |
| 992 | + | |
| 957 | 993 | static int gs_can_close(struct net_device *netdev) |
| 958 | 994 | { |
| 959 | 995 | int rc; |
| @@ -1021,8 +1057,7 @@ static int gs_usb_set_identify(struct net_device *netdev, bool do_identify) · 61 unmodified lines | ||
| 1021 | 1057 | else |
| 1022 | 1058 | imode.mode = cpu_to_le32(GS_CAN_IDENTIFY_OFF); |
| 1023 | 1059 | |
| 1024 | − return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | |
| 1025 | − GS_USB_BREQ_IDENTIFY, | |
| 1060 | + return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_IDENTIFY, | |
| 1026 | 1061 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 1027 | 1062 | dev->channel, 0, &imode, sizeof(imode), 100, |
| 1028 | 1063 | GFP_KERNEL); |
| @@ -1075,8 +1110,7 @@ static int gs_usb_get_termination(struct net_device *netdev, u16 *term) · 46 unmodified lines | ||
| 1075 | 1110 | struct gs_device_termination_state term_state; |
| 1076 | 1111 | int rc; |
| 1077 | 1112 | |
| 1078 | − rc = usb_control_msg_recv(interface_to_usbdev(dev->iface), 0, | |
| 1079 | − GS_USB_BREQ_GET_TERMINATION, | |
| 1113 | + rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_GET_TERMINATION, | |
| 1080 | 1114 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 1081 | 1115 | dev->channel, 0, |
| 1082 | 1116 | &term_state, sizeof(term_state), 1000, |
| @@ -1102,8 +1136,7 @@ static int gs_usb_set_termination(struct net_device *netdev, u16 term) · 19 unmodified lines | ||
| 1102 | 1136 | else |
| 1103 | 1137 | term_state.state = cpu_to_le32(GS_CAN_TERMINATION_STATE_OFF); |
| 1104 | 1138 | |
| 1105 | − return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | |
| 1106 | − GS_USB_BREQ_SET_TERMINATION, | |
| 1139 | + return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_SET_TERMINATION, | |
| 1107 | 1140 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 1108 | 1141 | dev->channel, 0, |
| 1109 | 1142 | &term_state, sizeof(term_state), 1000, |
| @@ -1153,6 +1186,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, · 43 unmodified lines | ||
| 1153 | 1186 | netdev->ethtool_ops = &gs_usb_ethtool_ops; |
| 1154 | 1187 | |
| 1155 | 1188 | netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ |
| 1189 | + netdev->dev_id = channel; | |
| 1156 | 1190 | |
| 1157 | 1191 | /* dev setup */ |
| 1158 | 1192 | strcpy(dev->bt_const.name, KBUILD_MODNAME); |
| @@ -1166,7 +1200,6 @@ static struct gs_can *gs_make_candev(unsigned int channel, · 7 unmodified lines | ||
| 1166 | 1200 | dev->bt_const.brp_inc = le32_to_cpu(bt_const.brp_inc); |
| 1167 | 1201 | |
| 1168 | 1202 | dev->udev = interface_to_usbdev(intf); |
| 1169 | − dev->iface = intf; | |
| 1170 | 1203 | dev->netdev = netdev; |
| 1171 | 1204 | dev->channel = channel; |
| 1172 | 1205 | |
| @@ -1224,6 +1257,12 @@ static struct gs_can *gs_make_candev(unsigned int channel, · 51 unmodified lines | ||
| 1224 | 1257 | } |
| 1225 | 1258 | } |
| 1226 | 1259 | |
| 1260 | + if (feature & GS_CAN_FEATURE_BERR_REPORTING) | |
| 1261 | + dev->can.ctrlmode_supported |= CAN_CTRLMODE_BERR_REPORTING; | |
| 1262 | + | |
| 1263 | + if (feature & GS_CAN_FEATURE_GET_STATE) | |
| 1264 | + dev->can.do_get_berr_counter = gs_usb_can_get_berr_counter; | |
| 1265 | + | |
| 1227 | 1266 | /* The CANtact Pro from LinkLayer Labs is based on the |
| 1228 | 1267 | * LPC54616 µC, which is affected by the NXP LPC USB transfer |
| 1229 | 1268 | * erratum. However, the current firmware (version 2) doesn't |
| @@ -1,8 +1,3 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o |
| 3 | 3 | kvaser_usb-y = kvaser_usb_core.o kvaser_usb_leaf.o kvaser_usb_hydra.o |
| 4 | − | |
| 5 | −# FIXME: temporarily silence -Warray-bounds on non W=1+ builds | |
| 6 | −ifndef KBUILD_EXTRA_WARN | |
| 7 | −CFLAGS_kvaser_usb_hydra.o += -Wno-array-bounds | |
| 8 | −endif | |
| @@ -76,6 +76,14 @@ struct kvaser_usb_tx_urb_context { · 75 unmodified lines | ||
| 76 | 76 | u32 echo_index; |
| 77 | 77 | }; |
| 78 | 78 | |
| 79 | +struct kvaser_usb_busparams { | |
| 80 | + __le32 bitrate; | |
| 81 | + u8 tseg1; | |
| 82 | + u8 tseg2; | |
| 83 | + u8 sjw; | |
| 84 | + u8 nsamples; | |
| 85 | +} __packed; | |
| 86 | + | |
| 79 | 87 | struct kvaser_usb { |
| 80 | 88 | struct usb_device *udev; |
| 81 | 89 | struct usb_interface *intf; |
| @@ -104,13 +112,19 @@ struct kvaser_usb_net_priv { · 22 unmodified lines | ||
| 104 | 112 | struct can_priv can; |
| 105 | 113 | struct can_berr_counter bec; |
| 106 | 114 | |
| 115 | + /* subdriver-specific data */ | |
| 116 | + void *sub_priv; | |
| 117 | + | |
| 107 | 118 | struct kvaser_usb *dev; |
| 108 | 119 | struct net_device *netdev; |
| 109 | 120 | int channel; |
| 110 | 121 | |
| 111 | − struct completion start_comp, stop_comp, flush_comp; | |
| 122 | + struct completion start_comp, stop_comp, flush_comp, | |
| 123 | + get_busparams_comp; | |
| 112 | 124 | struct usb_anchor tx_submitted; |
| 113 | 125 | |
| 126 | + struct kvaser_usb_busparams busparams_nominal, busparams_data; | |
| 127 | + | |
| 114 | 128 | spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */ |
| 115 | 129 | int active_tx_contexts; |
| 116 | 130 | struct kvaser_usb_tx_urb_context tx_contexts[]; |
| @@ -120,11 +134,15 @@ struct kvaser_usb_net_priv { · 3 unmodified lines | ||
| 120 | 134 | * struct kvaser_usb_dev_ops - Device specific functions |
| 121 | 135 | * @dev_set_mode: used for can.do_set_mode |
| 122 | 136 | * @dev_set_bittiming: used for can.do_set_bittiming |
| 137 | + * @dev_get_busparams: readback arbitration busparams | |
| 123 | 138 | * @dev_set_data_bittiming: used for can.do_set_data_bittiming |
| 139 | + * @dev_get_data_busparams: readback data busparams | |
| 124 | 140 | * @dev_get_berr_counter: used for can.do_get_berr_counter |
| 125 | 141 | * |
| 126 | 142 | * @dev_setup_endpoints: setup USB in and out endpoints |
| 127 | 143 | * @dev_init_card: initialize card |
| 144 | + * @dev_init_channel: initialize channel | |
| 145 | + * @dev_remove_channel: uninitialize channel | |
| 128 | 146 | * @dev_get_software_info: get software info |
| 129 | 147 | * @dev_get_software_details: get software details |
| 130 | 148 | * @dev_get_card_info: get card info |
| @@ -140,12 +158,18 @@ struct kvaser_usb_net_priv { · 9 unmodified lines | ||
| 140 | 158 | */ |
| 141 | 159 | struct kvaser_usb_dev_ops { |
| 142 | 160 | int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode); |
| 143 | − int (*dev_set_bittiming)(struct net_device *netdev); | |
| 144 | − int (*dev_set_data_bittiming)(struct net_device *netdev); | |
| 161 | + int (*dev_set_bittiming)(const struct net_device *netdev, | |
| 162 | + const struct kvaser_usb_busparams *busparams); | |
| 163 | + int (*dev_get_busparams)(struct kvaser_usb_net_priv *priv); | |
| 164 | + int (*dev_set_data_bittiming)(const struct net_device *netdev, | |
| 165 | + const struct kvaser_usb_busparams *busparams); | |
| 166 | + int (*dev_get_data_busparams)(struct kvaser_usb_net_priv *priv); | |
| 145 | 167 | int (*dev_get_berr_counter)(const struct net_device *netdev, |
| 146 | 168 | struct can_berr_counter *bec); |
| 147 | 169 | int (*dev_setup_endpoints)(struct kvaser_usb *dev); |
| 148 | 170 | int (*dev_init_card)(struct kvaser_usb *dev); |
| 171 | + int (*dev_init_channel)(struct kvaser_usb_net_priv *priv); | |
| 172 | + void (*dev_remove_channel)(struct kvaser_usb_net_priv *priv); | |
| 149 | 173 | int (*dev_get_software_info)(struct kvaser_usb *dev); |
| 150 | 174 | int (*dev_get_software_details)(struct kvaser_usb *dev); |
| 151 | 175 | int (*dev_get_card_info)(struct kvaser_usb *dev); |
| @@ -440,10 +440,6 @@ static int kvaser_usb_open(struct net_device *netdev) · 439 unmodified lines | ||
| 440 | 440 | if (err) |
| 441 | 441 | return err; |
| 442 | 442 | |
| 443 | − err = kvaser_usb_setup_rx_urbs(dev); | |
| 444 | − if (err) | |
| 445 | − goto error; | |
| 446 | − | |
| 447 | 443 | err = ops->dev_set_opt_mode(priv); |
| 448 | 444 | if (err) |
| 449 | 445 | goto error; |
| @@ -534,6 +530,91 @@ static int kvaser_usb_close(struct net_device *netdev) · 84 unmodified lines | ||
| 534 | 530 | return 0; |
| 535 | 531 | } |
| 536 | 532 | |
| 533 | +static int kvaser_usb_set_bittiming(struct net_device *netdev) | |
| 534 | +{ | |
| 535 | + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); | |
| 536 | + struct kvaser_usb *dev = priv->dev; | |
| 537 | + const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops; | |
| 538 | + struct can_bittiming *bt = &priv->can.bittiming; | |
| 539 | + struct kvaser_usb_busparams busparams; | |
| 540 | + int tseg1 = bt->prop_seg + bt->phase_seg1; | |
| 541 | + int tseg2 = bt->phase_seg2; | |
| 542 | + int sjw = bt->sjw; | |
| 543 | + int err; | |
| 544 | + | |
| 545 | + busparams.bitrate = cpu_to_le32(bt->bitrate); | |
| 546 | + busparams.sjw = (u8)sjw; | |
| 547 | + busparams.tseg1 = (u8)tseg1; | |
| 548 | + busparams.tseg2 = (u8)tseg2; | |
| 549 | + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) | |
| 550 | + busparams.nsamples = 3; | |
| 551 | + else | |
| 552 | + busparams.nsamples = 1; | |
| 553 | + | |
| 554 | + err = ops->dev_set_bittiming(netdev, &busparams); | |
| 555 | + if (err) | |
| 556 | + return err; | |
| 557 | + | |
| 558 | + err = kvaser_usb_setup_rx_urbs(priv->dev); | |
| 559 | + if (err) | |
| 560 | + return err; | |
| 561 | + | |
| 562 | + err = ops->dev_get_busparams(priv); | |
| 563 | + if (err) { | |
| 564 | + /* Treat EOPNOTSUPP as success */ | |
| 565 | + if (err == -EOPNOTSUPP) | |
| 566 | + err = 0; | |
| 567 | + return err; | |
| 568 | + } | |
| 569 | + | |
| 570 | + if (memcmp(&busparams, &priv->busparams_nominal, | |
| 571 | + sizeof(priv->busparams_nominal)) != 0) | |
| 572 | + err = -EINVAL; | |
| 573 | + | |
| 574 | + return err; | |
| 575 | +} | |
| 576 | + | |
| 577 | +static int kvaser_usb_set_data_bittiming(struct net_device *netdev) | |
| 578 | +{ | |
| 579 | + struct kvaser_usb_net_priv *priv = netdev_priv(netdev); | |
| 580 | + struct kvaser_usb *dev = priv->dev; | |
| 581 | + const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops; | |
| 582 | + struct can_bittiming *dbt = &priv->can.data_bittiming; | |
| 583 | + struct kvaser_usb_busparams busparams; | |
| 584 | + int tseg1 = dbt->prop_seg + dbt->phase_seg1; | |
| 585 | + int tseg2 = dbt->phase_seg2; | |
| 586 | + int sjw = dbt->sjw; | |
| 587 | + int err; | |
| 588 | + | |
| 589 | + if (!ops->dev_set_data_bittiming || | |
| 590 | + !ops->dev_get_data_busparams) | |
| 591 | + return -EOPNOTSUPP; | |
| 592 | + | |
| 593 | + busparams.bitrate = cpu_to_le32(dbt->bitrate); | |
| 594 | + busparams.sjw = (u8)sjw; | |
| 595 | + busparams.tseg1 = (u8)tseg1; | |
| 596 | + busparams.tseg2 = (u8)tseg2; | |
| 597 | + busparams.nsamples = 1; | |
| 598 | + | |
| 599 | + err = ops->dev_set_data_bittiming(netdev, &busparams); | |
| 600 | + if (err) | |
| 601 | + return err; | |
| 602 | + | |
| 603 | + err = kvaser_usb_setup_rx_urbs(priv->dev); | |
| 604 | + if (err) | |
| 605 | + return err; | |
| 606 | + | |
| 607 | + err = ops->dev_get_data_busparams(priv); | |
| 608 | + if (err) | |
| 609 | + return err; | |
| 610 | + | |
| 611 | + if (memcmp(&busparams, &priv->busparams_data, | |
| 612 | + sizeof(priv->busparams_data)) != 0) | |
| 613 | + err = -EINVAL; | |
| 614 | + | |
| 615 | + return err; | |
| 616 | +} | |
| 617 | + | |
| 537 | 618 | static void kvaser_usb_write_bulk_callback(struct urb *urb) |
| 538 | 619 | { |
| 539 | 620 | struct kvaser_usb_tx_urb_context *context = urb->context; |
| @@ -684,6 +765,7 @@ static const struct ethtool_ops kvaser_usb_ethtool_ops_hwts = { · 144 unmodified lines | ||
| 684 | 765 | |
| 685 | 766 | static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) |
| 686 | 767 | { |
| 768 | + const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops; | |
| 687 | 769 | int i; |
| 688 | 770 | |
| 689 | 771 | for (i = 0; i < dev->nchannels; i++) { |
| @@ -699,6 +781,9 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) · 9 unmodified lines | ||
| 699 | 781 | if (!dev->nets[i]) |
| 700 | 782 | continue; |
| 701 | 783 | |
| 784 | + if (ops->dev_remove_channel) | |
| 785 | + ops->dev_remove_channel(dev->nets[i]); | |
| 786 | + | |
| 702 | 787 | free_candev(dev->nets[i]->netdev); |
| 703 | 788 | } |
| 704 | 789 | } |
| @@ -730,6 +815,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) · 25 unmodified lines | ||
| 730 | 815 | init_completion(&priv->start_comp); |
| 731 | 816 | init_completion(&priv->stop_comp); |
| 732 | 817 | init_completion(&priv->flush_comp); |
| 818 | + init_completion(&priv->get_busparams_comp); | |
| 733 | 819 | priv->can.ctrlmode_supported = 0; |
| 734 | 820 | |
| 735 | 821 | priv->dev = dev; |
| @@ -742,7 +828,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) · 6 unmodified lines | ||
| 742 | 828 | priv->can.state = CAN_STATE_STOPPED; |
| 743 | 829 | priv->can.clock.freq = dev->cfg->clock.freq; |
| 744 | 830 | priv->can.bittiming_const = dev->cfg->bittiming_const; |
| 745 | − priv->can.do_set_bittiming = ops->dev_set_bittiming; | |
| 831 | + priv->can.do_set_bittiming = kvaser_usb_set_bittiming; | |
| 746 | 832 | priv->can.do_set_mode = ops->dev_set_mode; |
| 747 | 833 | if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) || |
| 748 | 834 | (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP)) |
| @@ -754,7 +840,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) · 5 unmodified lines | ||
| 754 | 840 | |
| 755 | 841 | if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { |
| 756 | 842 | priv->can.data_bittiming_const = dev->cfg->data_bittiming_const; |
| 757 | − priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming; | |
| 843 | + priv->can.do_set_data_bittiming = kvaser_usb_set_data_bittiming; | |
| 758 | 844 | } |
| 759 | 845 | |
| 760 | 846 | netdev->flags |= IFF_ECHO; |
| @@ -772,17 +858,26 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) · 11 unmodified lines | ||
| 772 | 858 | |
| 773 | 859 | dev->nets[channel] = priv; |
| 774 | 860 | |
| 861 | + if (ops->dev_init_channel) { | |
| 862 | + err = ops->dev_init_channel(priv); | |
| 863 | + if (err) | |
| 864 | + goto err; | |
| 865 | + } | |
| 866 | + | |
| 775 | 867 | err = register_candev(netdev); |
| 776 | 868 | if (err) { |
| 777 | 869 | dev_err(&dev->intf->dev, "Failed to register CAN device\n"); |
| 778 | − free_candev(netdev); | |
| 779 | − dev->nets[channel] = NULL; | |
| 780 | − return err; | |
| 870 | + goto err; | |
| 781 | 871 | } |
| 782 | 872 | |
| 783 | 873 | netdev_dbg(netdev, "device registered\n"); |
| 784 | 874 | |
| 785 | 875 | return 0; |
| 876 | + | |
| 877 | +err: | |
| 878 | + free_candev(netdev); | |
| 879 | + dev->nets[channel] = NULL; | |
| 880 | + return err; | |
| 786 | 881 | } |
| 787 | 882 | |
| 788 | 883 | static int kvaser_usb_probe(struct usb_interface *intf, |
| @@ -45,6 +45,8 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt; · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | /* Minihydra command IDs */ |
| 47 | 47 | #define CMD_SET_BUSPARAMS_REQ 16 |
| 48 | +#define CMD_GET_BUSPARAMS_REQ 17 | |
| 49 | +#define CMD_GET_BUSPARAMS_RESP 18 | |
| 48 | 50 | #define CMD_GET_CHIP_STATE_REQ 19 |
| 49 | 51 | #define CMD_CHIP_STATE_EVENT 20 |
| 50 | 52 | #define CMD_SET_DRIVERMODE_REQ 21 |
| @@ -196,21 +198,26 @@ struct kvaser_cmd_chip_state_event { · 145 unmodified lines | ||
| 196 | 198 | #define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO 0x01 |
| 197 | 199 | #define KVASER_USB_HYDRA_BUS_MODE_NONISO 0x02 |
| 198 | 200 | struct kvaser_cmd_set_busparams { |
| 199 | − __le32 bitrate; | |
| 200 | − u8 tseg1; | |
| 201 | − u8 tseg2; | |
| 202 | − u8 sjw; | |
| 203 | − u8 nsamples; | |
| 201 | + struct kvaser_usb_busparams busparams_nominal; | |
| 204 | 202 | u8 reserved0[4]; |
| 205 | − __le32 bitrate_d; | |
| 206 | − u8 tseg1_d; | |
| 207 | − u8 tseg2_d; | |
| 208 | − u8 sjw_d; | |
| 209 | − u8 nsamples_d; | |
| 203 | + struct kvaser_usb_busparams busparams_data; | |
| 210 | 204 | u8 canfd_mode; |
| 211 | 205 | u8 reserved1[7]; |
| 212 | 206 | } __packed; |
| 213 | 207 | |
| 208 | +/* Busparam type */ | |
| 209 | +#define KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN 0x00 | |
| 210 | +#define KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD 0x01 | |
| 211 | +struct kvaser_cmd_get_busparams_req { | |
| 212 | + u8 type; | |
| 213 | + u8 reserved[27]; | |
| 214 | +} __packed; | |
| 215 | + | |
| 216 | +struct kvaser_cmd_get_busparams_res { | |
| 217 | + struct kvaser_usb_busparams busparams; | |
| 218 | + u8 reserved[20]; | |
| 219 | +} __packed; | |
| 220 | + | |
| 214 | 221 | /* Ctrl modes */ |
| 215 | 222 | #define KVASER_USB_HYDRA_CTRLMODE_NORMAL 0x01 |
| 216 | 223 | #define KVASER_USB_HYDRA_CTRLMODE_LISTEN 0x02 |
| @@ -281,6 +288,8 @@ struct kvaser_cmd { · 64 unmodified lines | ||
| 281 | 288 | struct kvaser_cmd_error_event error_event; |
| 282 | 289 | |
| 283 | 290 | struct kvaser_cmd_set_busparams set_busparams_req; |
| 291 | + struct kvaser_cmd_get_busparams_req get_busparams_req; | |
| 292 | + struct kvaser_cmd_get_busparams_res get_busparams_res; | |
| 284 | 293 | |
| 285 | 294 | struct kvaser_cmd_chip_state_event chip_state_event; |
| 286 | 295 | |
| @@ -363,6 +372,10 @@ struct kvaser_cmd_ext { · 76 unmodified lines | ||
| 363 | 372 | } __packed; |
| 364 | 373 | } __packed; |
| 365 | 374 | |
| 375 | +struct kvaser_usb_net_hydra_priv { | |
| 376 | + int pending_get_busparams_type; | |
| 377 | +}; | |
| 378 | + | |
| 366 | 379 | static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = { |
| 367 | 380 | .name = "kvaser_usb_kcan", |
| 368 | 381 | .tseg1_min = 1, |
| @@ -840,6 +853,39 @@ static void kvaser_usb_hydra_flush_queue_reply(const struct kvaser_usb *dev, · 471 unmodified lines | ||
| 840 | 853 | complete(&priv->flush_comp); |
| 841 | 854 | } |
| 842 | 855 | |
| 856 | +static void kvaser_usb_hydra_get_busparams_reply(const struct kvaser_usb *dev, | |
| 857 | + const struct kvaser_cmd *cmd) | |
| 858 | +{ | |
| 859 | + struct kvaser_usb_net_priv *priv; | |
| 860 | + struct kvaser_usb_net_hydra_priv *hydra; | |
| 861 | + | |
| 862 | + priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); | |
| 863 | + if (!priv) | |
| 864 | + return; | |
| 865 | + | |
| 866 | + hydra = priv->sub_priv; | |
| 867 | + if (!hydra) | |
| 868 | + return; | |
| 869 | + | |
| 870 | + switch (hydra->pending_get_busparams_type) { | |
| 871 | + case KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN: | |
| 872 | + memcpy(&priv->busparams_nominal, &cmd->get_busparams_res.busparams, | |
| 873 | + sizeof(priv->busparams_nominal)); | |
| 874 | + break; | |
| 875 | + case KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD: | |
| 876 | + memcpy(&priv->busparams_data, &cmd->get_busparams_res.busparams, | |
| 877 | + sizeof(priv->busparams_nominal)); | |
| 878 | + break; | |
| 879 | + default: | |
| 880 | + dev_warn(&dev->intf->dev, "Unknown get_busparams_type %d\n", | |
| 881 | + hydra->pending_get_busparams_type); | |
| 882 | + break; | |
| 883 | + } | |
| 884 | + hydra->pending_get_busparams_type = -1; | |
| 885 | + | |
| 886 | + complete(&priv->get_busparams_comp); | |
| 887 | +} | |
| 888 | + | |
| 843 | 889 | static void |
| 844 | 890 | kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv, |
| 845 | 891 | u8 bus_status, |
| @@ -1326,6 +1372,10 @@ static void kvaser_usb_hydra_handle_cmd_std(const struct kvaser_usb *dev, · 480 unmodified lines | ||
| 1326 | 1372 | kvaser_usb_hydra_state_event(dev, cmd); |
| 1327 | 1373 | break; |
| 1328 | 1374 | |
| 1375 | + case CMD_GET_BUSPARAMS_RESP: | |
| 1376 | + kvaser_usb_hydra_get_busparams_reply(dev, cmd); | |
| 1377 | + break; | |
| 1378 | + | |
| 1329 | 1379 | case CMD_ERROR_EVENT: |
| 1330 | 1380 | kvaser_usb_hydra_error_event(dev, cmd); |
| 1331 | 1381 | break; |
| @@ -1522,15 +1572,58 @@ static int kvaser_usb_hydra_set_mode(struct net_device *netdev, · 190 unmodified lines | ||
| 1522 | 1572 | return err; |
| 1523 | 1573 | } |
| 1524 | 1574 | |
| 1525 | −static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev) | |
| 1575 | +static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv, | |
| 1576 | + int busparams_type) | |
| 1577 | +{ | |
| 1578 | + struct kvaser_usb *dev = priv->dev; | |
| 1579 | + struct kvaser_usb_net_hydra_priv *hydra = priv->sub_priv; | |
| 1580 | + struct kvaser_cmd *cmd; | |
| 1581 | + int err; | |
| 1582 | + | |
| 1583 | + if (!hydra) | |
| 1584 | + return -EINVAL; | |
| 1585 | + | |
| 1586 | + cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); | |
| 1587 | + if (!cmd) | |
| 1588 | + return -ENOMEM; | |
| 1589 | + | |
| 1590 | + cmd->header.cmd_no = CMD_GET_BUSPARAMS_REQ; | |
| 1591 | + kvaser_usb_hydra_set_cmd_dest_he | |
| 1592 | + (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); | |
| 1593 | + kvaser_usb_hydra_set_cmd_transid | |
| 1594 | + (cmd, kvaser_usb_hydra_get_next_transid(dev)); | |
| 1595 | + cmd->get_busparams_req.type = busparams_type; | |
| 1596 | + hydra->pending_get_busparams_type = busparams_type; | |
| 1597 | + | |
| 1598 | + reinit_completion(&priv->get_busparams_comp); | |
| 1599 | + | |
| 1600 | + err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); | |
| 1601 | + if (err) | |
| 1602 | + return err; | |
| 1603 | + | |
| 1604 | + if (!wait_for_completion_timeout(&priv->get_busparams_comp, | |
| 1605 | + msecs_to_jiffies(KVASER_USB_TIMEOUT))) | |
| 1606 | + return -ETIMEDOUT; | |
| 1607 | + | |
| 1608 | + return err; | |
| 1609 | +} | |
| 1610 | + | |
| 1611 | +static int kvaser_usb_hydra_get_nominal_busparams(struct kvaser_usb_net_priv *priv) | |
| 1612 | +{ | |
| 1613 | + return kvaser_usb_hydra_get_busparams(priv, KVASER_USB_HYDRA_BUSPARAM_TYPE_CAN); | |
| 1614 | +} | |
| 1615 | + | |
| 1616 | +static int kvaser_usb_hydra_get_data_busparams(struct kvaser_usb_net_priv *priv) | |
| 1617 | +{ | |
| 1618 | + return kvaser_usb_hydra_get_busparams(priv, KVASER_USB_HYDRA_BUSPARAM_TYPE_CANFD); | |
| 1619 | +} | |
| 1620 | + | |
| 1621 | +static int kvaser_usb_hydra_set_bittiming(const struct net_device *netdev, | |
| 1622 | + const struct kvaser_usb_busparams *busparams) | |
| 1526 | 1623 | { |
| 1527 | 1624 | struct kvaser_cmd *cmd; |
| 1528 | 1625 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1529 | − struct can_bittiming *bt = &priv->can.bittiming; | |
| 1530 | 1626 | struct kvaser_usb *dev = priv->dev; |
| 1531 | − int tseg1 = bt->prop_seg + bt->phase_seg1; | |
| 1532 | − int tseg2 = bt->phase_seg2; | |
| 1533 | − int sjw = bt->sjw; | |
| 1534 | 1627 | int err; |
| 1535 | 1628 | |
| 1536 | 1629 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
| @@ -1538,11 +1631,8 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev) · 1 unmodified line | ||
| 1538 | 1631 | return -ENOMEM; |
| 1539 | 1632 | |
| 1540 | 1633 | cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ; |
| 1541 | − cmd->set_busparams_req.bitrate = cpu_to_le32(bt->bitrate); | |
| 1542 | − cmd->set_busparams_req.sjw = (u8)sjw; | |
| 1543 | − cmd->set_busparams_req.tseg1 = (u8)tseg1; | |
| 1544 | − cmd->set_busparams_req.tseg2 = (u8)tseg2; | |
| 1545 | − cmd->set_busparams_req.nsamples = 1; | |
| 1634 | + memcpy(&cmd->set_busparams_req.busparams_nominal, busparams, | |
| 1635 | + sizeof(cmd->set_busparams_req.busparams_nominal)); | |
| 1546 | 1636 | |
| 1547 | 1637 | kvaser_usb_hydra_set_cmd_dest_he |
| 1548 | 1638 | (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); |
| @@ -1556,15 +1646,12 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev) · 7 unmodified lines | ||
| 1556 | 1646 | return err; |
| 1557 | 1647 | } |
| 1558 | 1648 | |
| 1559 | −static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev) | |
| 1649 | +static int kvaser_usb_hydra_set_data_bittiming(const struct net_device *netdev, | |
| 1650 | + const struct kvaser_usb_busparams *busparams) | |
| 1560 | 1651 | { |
| 1561 | 1652 | struct kvaser_cmd *cmd; |
| 1562 | 1653 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1563 | − struct can_bittiming *dbt = &priv->can.data_bittiming; | |
| 1564 | 1654 | struct kvaser_usb *dev = priv->dev; |
| 1565 | − int tseg1 = dbt->prop_seg + dbt->phase_seg1; | |
| 1566 | − int tseg2 = dbt->phase_seg2; | |
| 1567 | − int sjw = dbt->sjw; | |
| 1568 | 1655 | int err; |
| 1569 | 1656 | |
| 1570 | 1657 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
| @@ -1572,11 +1659,8 @@ static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev) · 1 unmodified line | ||
| 1572 | 1659 | return -ENOMEM; |
| 1573 | 1660 | |
| 1574 | 1661 | cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ; |
| 1575 | − cmd->set_busparams_req.bitrate_d = cpu_to_le32(dbt->bitrate); | |
| 1576 | − cmd->set_busparams_req.sjw_d = (u8)sjw; | |
| 1577 | − cmd->set_busparams_req.tseg1_d = (u8)tseg1; | |
| 1578 | − cmd->set_busparams_req.tseg2_d = (u8)tseg2; | |
| 1579 | − cmd->set_busparams_req.nsamples_d = 1; | |
| 1662 | + memcpy(&cmd->set_busparams_req.busparams_data, busparams, | |
| 1663 | + sizeof(cmd->set_busparams_req.busparams_data)); | |
| 1580 | 1664 | |
| 1581 | 1665 | if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { |
| 1582 | 1666 | if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) |
| @@ -1683,6 +1767,19 @@ static int kvaser_usb_hydra_init_card(struct kvaser_usb *dev) · 100 unmodified lines | ||
| 1683 | 1767 | return 0; |
| 1684 | 1768 | } |
| 1685 | 1769 | |
| 1770 | +static int kvaser_usb_hydra_init_channel(struct kvaser_usb_net_priv *priv) | |
| 1771 | +{ | |
| 1772 | + struct kvaser_usb_net_hydra_priv *hydra; | |
| 1773 | + | |
| 1774 | + hydra = devm_kzalloc(&priv->dev->intf->dev, sizeof(*hydra), GFP_KERNEL); | |
| 1775 | + if (!hydra) | |
| 1776 | + return -ENOMEM; | |
| 1777 | + | |
| 1778 | + priv->sub_priv = hydra; | |
| 1779 | + | |
| 1780 | + return 0; | |
| 1781 | +} | |
| 1782 | + | |
| 1686 | 1783 | static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev) |
| 1687 | 1784 | { |
| 1688 | 1785 | struct kvaser_cmd cmd; |
| @@ -2027,10 +2124,13 @@ kvaser_usb_hydra_frame_to_cmd(const struct kvaser_usb_net_priv *priv, · 338 unmodified lines | ||
| 2027 | 2124 | const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = { |
| 2028 | 2125 | .dev_set_mode = kvaser_usb_hydra_set_mode, |
| 2029 | 2126 | .dev_set_bittiming = kvaser_usb_hydra_set_bittiming, |
| 2127 | + .dev_get_busparams = kvaser_usb_hydra_get_nominal_busparams, | |
| 2030 | 2128 | .dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming, |
| 2129 | + .dev_get_data_busparams = kvaser_usb_hydra_get_data_busparams, | |
| 2031 | 2130 | .dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter, |
| 2032 | 2131 | .dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints, |
| 2033 | 2132 | .dev_init_card = kvaser_usb_hydra_init_card, |
| 2133 | + .dev_init_channel = kvaser_usb_hydra_init_channel, | |
| 2034 | 2134 | .dev_get_software_info = kvaser_usb_hydra_get_software_info, |
| 2035 | 2135 | .dev_get_software_details = kvaser_usb_hydra_get_software_details, |
| 2036 | 2136 | .dev_get_card_info = kvaser_usb_hydra_get_card_info, |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/types.h> |
| 22 | 22 | #include <linux/units.h> |
| 23 | 23 | #include <linux/usb.h> |
| 24 | +#include <linux/workqueue.h> | |
| 24 | 25 | |
| 25 | 26 | #include <linux/can.h> |
| 26 | 27 | #include <linux/can/dev.h> |
| @@ -56,6 +57,9 @@ · 29 unmodified lines | ||
| 56 | 57 | #define CMD_RX_EXT_MESSAGE 14 |
| 57 | 58 | #define CMD_TX_EXT_MESSAGE 15 |
| 58 | 59 | #define CMD_SET_BUS_PARAMS 16 |
| 60 | +#define CMD_GET_BUS_PARAMS 17 | |
| 61 | +#define CMD_GET_BUS_PARAMS_REPLY 18 | |
| 62 | +#define CMD_GET_CHIP_STATE 19 | |
| 59 | 63 | #define CMD_CHIP_STATE_EVENT 20 |
| 60 | 64 | #define CMD_SET_CTRL_MODE 21 |
| 61 | 65 | #define CMD_RESET_CHIP 24 |
| @@ -70,10 +74,13 @@ · 8 unmodified lines | ||
| 70 | 74 | #define CMD_GET_CARD_INFO_REPLY 35 |
| 71 | 75 | #define CMD_GET_SOFTWARE_INFO 38 |
| 72 | 76 | #define CMD_GET_SOFTWARE_INFO_REPLY 39 |
| 77 | +#define CMD_ERROR_EVENT 45 | |
| 73 | 78 | #define CMD_FLUSH_QUEUE 48 |
| 74 | 79 | #define CMD_TX_ACKNOWLEDGE 50 |
| 75 | 80 | #define CMD_CAN_ERROR_EVENT 51 |
| 76 | 81 | #define CMD_FLUSH_QUEUE_REPLY 68 |
| 82 | +#define CMD_GET_CAPABILITIES_REQ 95 | |
| 83 | +#define CMD_GET_CAPABILITIES_RESP 96 | |
| 77 | 84 | |
| 78 | 85 | #define CMD_LEAF_LOG_MESSAGE 106 |
| 79 | 86 | |
| @@ -83,6 +90,8 @@ · 3 unmodified lines | ||
| 83 | 90 | #define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5) |
| 84 | 91 | #define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6) |
| 85 | 92 | |
| 93 | +#define KVASER_USB_LEAF_SWOPTION_EXT_CAP BIT(12) | |
| 94 | + | |
| 86 | 95 | /* error factors */ |
| 87 | 96 | #define M16C_EF_ACKE BIT(0) |
| 88 | 97 | #define M16C_EF_CRCE BIT(1) |
| @@ -157,11 +166,7 @@ struct usbcan_cmd_softinfo { · 68 unmodified lines | ||
| 157 | 166 | struct kvaser_cmd_busparams { |
| 158 | 167 | u8 tid; |
| 159 | 168 | u8 channel; |
| 160 | − __le32 bitrate; | |
| 161 | − u8 tseg1; | |
| 162 | − u8 tseg2; | |
| 163 | − u8 sjw; | |
| 164 | − u8 no_samp; | |
| 169 | + struct kvaser_usb_busparams busparams; | |
| 165 | 170 | } __packed; |
| 166 | 171 | |
| 167 | 172 | struct kvaser_cmd_tx_can { |
| @@ -230,7 +235,7 @@ struct kvaser_cmd_tx_acknowledge_header { · 62 unmodified lines | ||
| 230 | 235 | u8 tid; |
| 231 | 236 | } __packed; |
| 232 | 237 | |
| 233 | −struct leaf_cmd_error_event { | |
| 238 | +struct leaf_cmd_can_error_event { | |
| 234 | 239 | u8 tid; |
| 235 | 240 | u8 flags; |
| 236 | 241 | __le16 time[3]; |
| @@ -242,7 +247,7 @@ struct leaf_cmd_error_event { · 5 unmodified lines | ||
| 242 | 247 | u8 error_factor; |
| 243 | 248 | } __packed; |
| 244 | 249 | |
| 245 | −struct usbcan_cmd_error_event { | |
| 250 | +struct usbcan_cmd_can_error_event { | |
| 246 | 251 | u8 tid; |
| 247 | 252 | u8 padding; |
| 248 | 253 | u8 tx_errors_count_ch0; |
| @@ -254,6 +259,28 @@ struct usbcan_cmd_error_event { · 5 unmodified lines | ||
| 254 | 259 | __le16 time; |
| 255 | 260 | } __packed; |
| 256 | 261 | |
| 262 | +/* CMD_ERROR_EVENT error codes */ | |
| 263 | +#define KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL 0x8 | |
| 264 | +#define KVASER_USB_LEAF_ERROR_EVENT_PARAM 0x9 | |
| 265 | + | |
| 266 | +struct leaf_cmd_error_event { | |
| 267 | + u8 tid; | |
| 268 | + u8 error_code; | |
| 269 | + __le16 timestamp[3]; | |
| 270 | + __le16 padding; | |
| 271 | + __le16 info1; | |
| 272 | + __le16 info2; | |
| 273 | +} __packed; | |
| 274 | + | |
| 275 | +struct usbcan_cmd_error_event { | |
| 276 | + u8 tid; | |
| 277 | + u8 error_code; | |
| 278 | + __le16 info1; | |
| 279 | + __le16 info2; | |
| 280 | + __le16 timestamp; | |
| 281 | + __le16 padding; | |
| 282 | +} __packed; | |
| 283 | + | |
| 257 | 284 | struct kvaser_cmd_ctrl_mode { |
| 258 | 285 | u8 tid; |
| 259 | 286 | u8 channel; |
| @@ -278,6 +305,28 @@ struct leaf_cmd_log_message { · 18 unmodified lines | ||
| 278 | 305 | u8 data[8]; |
| 279 | 306 | } __packed; |
| 280 | 307 | |
| 308 | +/* Sub commands for cap_req and cap_res */ | |
| 309 | +#define KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE 0x02 | |
| 310 | +#define KVASER_USB_LEAF_CAP_CMD_ERR_REPORT 0x05 | |
| 311 | +struct kvaser_cmd_cap_req { | |
| 312 | + __le16 padding0; | |
| 313 | + __le16 cap_cmd; | |
| 314 | + __le16 padding1; | |
| 315 | + __le16 channel; | |
| 316 | +} __packed; | |
| 317 | + | |
| 318 | +/* Status codes for cap_res */ | |
| 319 | +#define KVASER_USB_LEAF_CAP_STAT_OK 0x00 | |
| 320 | +#define KVASER_USB_LEAF_CAP_STAT_NOT_IMPL 0x01 | |
| 321 | +#define KVASER_USB_LEAF_CAP_STAT_UNAVAIL 0x02 | |
| 322 | +struct kvaser_cmd_cap_res { | |
| 323 | + __le16 padding; | |
| 324 | + __le16 cap_cmd; | |
| 325 | + __le16 status; | |
| 326 | + __le32 mask; | |
| 327 | + __le32 value; | |
| 328 | +} __packed; | |
| 329 | + | |
| 281 | 330 | struct kvaser_cmd { |
| 282 | 331 | u8 len; |
| 283 | 332 | u8 id; |
| @@ -293,14 +342,18 @@ struct kvaser_cmd { · 9 unmodified lines | ||
| 293 | 342 | struct leaf_cmd_softinfo softinfo; |
| 294 | 343 | struct leaf_cmd_rx_can rx_can; |
| 295 | 344 | struct leaf_cmd_chip_state_event chip_state_event; |
| 296 | − struct leaf_cmd_error_event error_event; | |
| 345 | + struct leaf_cmd_can_error_event can_error_event; | |
| 297 | 346 | struct leaf_cmd_log_message log_message; |
| 347 | + struct leaf_cmd_error_event error_event; | |
| 348 | + struct kvaser_cmd_cap_req cap_req; | |
| 349 | + struct kvaser_cmd_cap_res cap_res; | |
| 298 | 350 | } __packed leaf; |
| 299 | 351 | |
| 300 | 352 | union { |
| 301 | 353 | struct usbcan_cmd_softinfo softinfo; |
| 302 | 354 | struct usbcan_cmd_rx_can rx_can; |
| 303 | 355 | struct usbcan_cmd_chip_state_event chip_state_event; |
| 356 | + struct usbcan_cmd_can_error_event can_error_event; | |
| 304 | 357 | struct usbcan_cmd_error_event error_event; |
| 305 | 358 | } __packed usbcan; |
| 306 | 359 | |
| @@ -323,7 +376,10 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = { · 16 unmodified lines | ||
| 323 | 376 | [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can), |
| 324 | 377 | [CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message), |
| 325 | 378 | [CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event), |
| 326 | − [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event), | |
| 379 | + [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.can_error_event), | |
| 380 | + [CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res), | |
| 381 | + [CMD_GET_BUS_PARAMS_REPLY] = kvaser_fsize(u.busparams), | |
| 382 | + [CMD_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event), | |
| 327 | 383 | /* ignored events: */ |
| 328 | 384 | [CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY, |
| 329 | 385 | }; |
| @@ -337,7 +393,8 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = { · 7 unmodified lines | ||
| 337 | 393 | [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), |
| 338 | 394 | [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), |
| 339 | 395 | [CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event), |
| 340 | − [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event), | |
| 396 | + [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event), | |
| 397 | + [CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event), | |
| 341 | 398 | /* ignored events: */ |
| 342 | 399 | [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY, |
| 343 | 400 | }; |
| @@ -365,6 +422,15 @@ struct kvaser_usb_err_summary { · 21 unmodified lines | ||
| 365 | 422 | }; |
| 366 | 423 | }; |
| 367 | 424 | |
| 425 | +struct kvaser_usb_net_leaf_priv { | |
| 426 | + struct kvaser_usb_net_priv *net; | |
| 427 | + | |
| 428 | + struct delayed_work chip_state_req_work; | |
| 429 | + | |
| 430 | + /* started but not reported as bus-on yet */ | |
| 431 | + bool joining_bus; | |
| 432 | +}; | |
| 433 | + | |
| 368 | 434 | static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = { |
| 369 | 435 | .name = "kvaser_usb_ucii", |
| 370 | 436 | .tseg1_min = 4, |
| @@ -606,6 +672,9 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev, · 235 unmodified lines | ||
| 606 | 672 | dev->fw_version = le32_to_cpu(softinfo->fw_version); |
| 607 | 673 | dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx); |
| 608 | 674 | |
| 675 | + if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP) | |
| 676 | + dev->card_data.capabilities |= KVASER_USB_CAP_EXT_CAP; | |
| 677 | + | |
| 609 | 678 | if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) { |
| 610 | 679 | /* Firmware expects bittiming parameters calculated for 16MHz |
| 611 | 680 | * clock, regardless of the actual clock |
| @@ -693,6 +762,116 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev) · 81 unmodified lines | ||
| 693 | 762 | return 0; |
| 694 | 763 | } |
| 695 | 764 | |
| 765 | +static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev, | |
| 766 | + u16 cap_cmd_req, u16 *status) | |
| 767 | +{ | |
| 768 | + struct kvaser_usb_dev_card_data *card_data = &dev->card_data; | |
| 769 | + struct kvaser_cmd *cmd; | |
| 770 | + u32 value = 0; | |
| 771 | + u32 mask = 0; | |
| 772 | + u16 cap_cmd_res; | |
| 773 | + int err; | |
| 774 | + int i; | |
| 775 | + | |
| 776 | + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | |
| 777 | + if (!cmd) | |
| 778 | + return -ENOMEM; | |
| 779 | + | |
| 780 | + cmd->id = CMD_GET_CAPABILITIES_REQ; | |
| 781 | + cmd->u.leaf.cap_req.cap_cmd = cpu_to_le16(cap_cmd_req); | |
| 782 | + cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_cap_req); | |
| 783 | + | |
| 784 | + err = kvaser_usb_send_cmd(dev, cmd, cmd->len); | |
| 785 | + if (err) | |
| 786 | + goto end; | |
| 787 | + | |
| 788 | + err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd); | |
| 789 | + if (err) | |
| 790 | + goto end; | |
| 791 | + | |
| 792 | + *status = le16_to_cpu(cmd->u.leaf.cap_res.status); | |
| 793 | + | |
| 794 | + if (*status != KVASER_USB_LEAF_CAP_STAT_OK) | |
| 795 | + goto end; | |
| 796 | + | |
| 797 | + cap_cmd_res = le16_to_cpu(cmd->u.leaf.cap_res.cap_cmd); | |
| 798 | + switch (cap_cmd_res) { | |
| 799 | + case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE: | |
| 800 | + case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT: | |
| 801 | + value = le32_to_cpu(cmd->u.leaf.cap_res.value); | |
| 802 | + mask = le32_to_cpu(cmd->u.leaf.cap_res.mask); | |
| 803 | + break; | |
| 804 | + default: | |
| 805 | + dev_warn(&dev->intf->dev, "Unknown capability command %u\n", | |
| 806 | + cap_cmd_res); | |
| 807 | + break; | |
| 808 | + } | |
| 809 | + | |
| 810 | + for (i = 0; i < dev->nchannels; i++) { | |
| 811 | + if (BIT(i) & (value & mask)) { | |
| 812 | + switch (cap_cmd_res) { | |
| 813 | + case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE: | |
| 814 | + card_data->ctrlmode_supported |= | |
| 815 | + CAN_CTRLMODE_LISTENONLY; | |
| 816 | + break; | |
| 817 | + case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT: | |
| 818 | + card_data->capabilities |= | |
| 819 | + KVASER_USB_CAP_BERR_CAP; | |
| 820 | + break; | |
| 821 | + } | |
| 822 | + } | |
| 823 | + } | |
| 824 | + | |
| 825 | +end: | |
| 826 | + kfree(cmd); | |
| 827 | + | |
| 828 | + return err; | |
| 829 | +} | |
| 830 | + | |
| 831 | +static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev) | |
| 832 | +{ | |
| 833 | + int err; | |
| 834 | + u16 status; | |
| 835 | + | |
| 836 | + if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) { | |
| 837 | + dev_info(&dev->intf->dev, | |
| 838 | + "No extended capability support. Upgrade device firmware.\n"); | |
| 839 | + return 0; | |
| 840 | + } | |
| 841 | + | |
| 842 | + err = kvaser_usb_leaf_get_single_capability(dev, | |
| 843 | + KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE, | |
| 844 | + &status); | |
| 845 | + if (err) | |
| 846 | + return err; | |
| 847 | + if (status) | |
| 848 | + dev_info(&dev->intf->dev, | |
| 849 | + "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n", | |
| 850 | + status); | |
| 851 | + | |
| 852 | + err = kvaser_usb_leaf_get_single_capability(dev, | |
| 853 | + KVASER_USB_LEAF_CAP_CMD_ERR_REPORT, | |
| 854 | + &status); | |
| 855 | + if (err) | |
| 856 | + return err; | |
| 857 | + if (status) | |
| 858 | + dev_info(&dev->intf->dev, | |
| 859 | + "KVASER_USB_LEAF_CAP_CMD_ERR_REPORT failed %u\n", | |
| 860 | + status); | |
| 861 | + | |
| 862 | + return 0; | |
| 863 | +} | |
| 864 | + | |
| 865 | +static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev) | |
| 866 | +{ | |
| 867 | + int err = 0; | |
| 868 | + | |
| 869 | + if (dev->driver_info->family == KVASER_LEAF) | |
| 870 | + err = kvaser_usb_leaf_get_capabilities_leaf(dev); | |
| 871 | + | |
| 872 | + return err; | |
| 873 | +} | |
| 874 | + | |
| 696 | 875 | static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev, |
| 697 | 876 | const struct kvaser_cmd *cmd) |
| 698 | 877 | { |
| @@ -721,7 +900,7 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev, · 22 unmodified lines | ||
| 721 | 900 | context = &priv->tx_contexts[tid % dev->max_tx_urbs]; |
| 722 | 901 | |
| 723 | 902 | /* Sometimes the state change doesn't come after a bus-off event */ |
| 724 | − if (priv->can.restart_ms && priv->can.state >= CAN_STATE_BUS_OFF) { | |
| 903 | + if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) { | |
| 725 | 904 | struct sk_buff *skb; |
| 726 | 905 | struct can_frame *cf; |
| 727 | 906 | |
| @@ -774,11 +953,22 @@ static int kvaser_usb_leaf_simple_cmd_async(struct kvaser_usb_net_priv *priv, · 46 unmodified lines | ||
| 774 | 953 | return err; |
| 775 | 954 | } |
| 776 | 955 | |
| 956 | +static void kvaser_usb_leaf_chip_state_req_work(struct work_struct *work) | |
| 957 | +{ | |
| 958 | + struct kvaser_usb_net_leaf_priv *leaf = | |
| 959 | + container_of(work, struct kvaser_usb_net_leaf_priv, | |
| 960 | + chip_state_req_work.work); | |
| 961 | + struct kvaser_usb_net_priv *priv = leaf->net; | |
| 962 | + | |
| 963 | + kvaser_usb_leaf_simple_cmd_async(priv, CMD_GET_CHIP_STATE); | |
| 964 | +} | |
| 965 | + | |
| 777 | 966 | static void |
| 778 | 967 | kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, |
| 779 | 968 | const struct kvaser_usb_err_summary *es, |
| 780 | 969 | struct can_frame *cf) |
| 781 | 970 | { |
| 971 | + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | |
| 782 | 972 | struct kvaser_usb *dev = priv->dev; |
| 783 | 973 | struct net_device_stats *stats = &priv->netdev->stats; |
| 784 | 974 | enum can_state cur_state, new_state, tx_state, rx_state; |
| @@ -792,20 +982,32 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, · 7 unmodified lines | ||
| 792 | 982 | new_state = CAN_STATE_BUS_OFF; |
| 793 | 983 | } else if (es->status & M16C_STATE_BUS_PASSIVE) { |
| 794 | 984 | new_state = CAN_STATE_ERROR_PASSIVE; |
| 795 | − } else if (es->status & M16C_STATE_BUS_ERROR) { | |
| 985 | + } else if ((es->status & M16C_STATE_BUS_ERROR) && | |
| 986 | + cur_state >= CAN_STATE_BUS_OFF) { | |
| 796 | 987 | /* Guard against spurious error events after a busoff */ |
| 797 | − if (cur_state < CAN_STATE_BUS_OFF) { | |
| 798 | − if (es->txerr >= 128 || es->rxerr >= 128) | |
| 799 | − new_state = CAN_STATE_ERROR_PASSIVE; | |
| 800 | − else if (es->txerr >= 96 || es->rxerr >= 96) | |
| 801 | − new_state = CAN_STATE_ERROR_WARNING; | |
| 802 | − else if (cur_state > CAN_STATE_ERROR_ACTIVE) | |
| 803 | − new_state = CAN_STATE_ERROR_ACTIVE; | |
| 804 | − } | |
| 988 | + } else if (es->txerr >= 128 || es->rxerr >= 128) { | |
| 989 | + new_state = CAN_STATE_ERROR_PASSIVE; | |
| 990 | + } else if (es->txerr >= 96 || es->rxerr >= 96) { | |
| 991 | + new_state = CAN_STATE_ERROR_WARNING; | |
| 992 | + } else { | |
| 993 | + new_state = CAN_STATE_ERROR_ACTIVE; | |
| 805 | 994 | } |
| 806 | 995 | |
| 807 | − if (!es->status) | |
| 808 | − new_state = CAN_STATE_ERROR_ACTIVE; | |
| 996 | + /* 0bfd:0124 FW 4.18.778 was observed to send the initial | |
| 997 | + * CMD_CHIP_STATE_EVENT after CMD_START_CHIP with M16C_STATE_BUS_OFF | |
| 998 | + * bit set if the channel was bus-off when it was last stopped (even | |
| 999 | + * across chip resets). This bit will clear shortly afterwards, without | |
| 1000 | + * triggering a second unsolicited chip state event. | |
| 1001 | + * Ignore this initial bus-off. | |
| 1002 | + */ | |
| 1003 | + if (leaf->joining_bus) { | |
| 1004 | + if (new_state == CAN_STATE_BUS_OFF) { | |
| 1005 | + netdev_dbg(priv->netdev, "ignoring bus-off during startup"); | |
| 1006 | + new_state = cur_state; | |
| 1007 | + } else { | |
| 1008 | + leaf->joining_bus = false; | |
| 1009 | + } | |
| 1010 | + } | |
| 809 | 1011 | |
| 810 | 1012 | if (new_state != cur_state) { |
| 811 | 1013 | tx_state = (es->txerr >= es->rxerr) ? new_state : 0; |
| @@ -815,7 +1017,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, · 3 unmodified lines | ||
| 815 | 1017 | } |
| 816 | 1018 | |
| 817 | 1019 | if (priv->can.restart_ms && |
| 818 | − cur_state >= CAN_STATE_BUS_OFF && | |
| 1020 | + cur_state == CAN_STATE_BUS_OFF && | |
| 819 | 1021 | new_state < CAN_STATE_BUS_OFF) |
| 820 | 1022 | priv->can.can_stats.restarts++; |
| 821 | 1023 | |
| @@ -849,6 +1051,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, · 27 unmodified lines | ||
| 849 | 1051 | struct sk_buff *skb; |
| 850 | 1052 | struct net_device_stats *stats; |
| 851 | 1053 | struct kvaser_usb_net_priv *priv; |
| 1054 | + struct kvaser_usb_net_leaf_priv *leaf; | |
| 852 | 1055 | enum can_state old_state, new_state; |
| 853 | 1056 | |
| 854 | 1057 | if (es->channel >= dev->nchannels) { |
| @@ -858,8 +1061,13 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, · 3 unmodified lines | ||
| 858 | 1061 | } |
| 859 | 1062 | |
| 860 | 1063 | priv = dev->nets[es->channel]; |
| 1064 | + leaf = priv->sub_priv; | |
| 861 | 1065 | stats = &priv->netdev->stats; |
| 862 | 1066 | |
| 1067 | + /* Ignore e.g. state change to bus-off reported just after stopping */ | |
| 1068 | + if (!netif_running(priv->netdev)) | |
| 1069 | + return; | |
| 1070 | + | |
| 863 | 1071 | /* Update all of the CAN interface's state and error counters before |
| 864 | 1072 | * trying any memory allocation that can actually fail with -ENOMEM. |
| 865 | 1073 | * |
| @@ -874,6 +1082,17 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, · 8 unmodified lines | ||
| 874 | 1082 | kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf); |
| 875 | 1083 | new_state = priv->can.state; |
| 876 | 1084 | |
| 1085 | + /* If there are errors, request status updates periodically as we do | |
| 1086 | + * not get automatic notifications of improved state. | |
| 1087 | + * Also request updates if we saw a stale BUS_OFF during startup | |
| 1088 | + * (joining_bus). | |
| 1089 | + */ | |
| 1090 | + if (new_state < CAN_STATE_BUS_OFF && | |
| 1091 | + (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE || | |
| 1092 | + leaf->joining_bus)) | |
| 1093 | + schedule_delayed_work(&leaf->chip_state_req_work, | |
| 1094 | + msecs_to_jiffies(500)); | |
| 1095 | + | |
| 877 | 1096 | skb = alloc_can_err_skb(priv->netdev, &cf); |
| 878 | 1097 | if (!skb) { |
| 879 | 1098 | stats->rx_dropped++; |
| @@ -891,7 +1110,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, · 11 unmodified lines | ||
| 891 | 1110 | } |
| 892 | 1111 | |
| 893 | 1112 | if (priv->can.restart_ms && |
| 894 | − old_state >= CAN_STATE_BUS_OFF && | |
| 1113 | + old_state == CAN_STATE_BUS_OFF && | |
| 895 | 1114 | new_state < CAN_STATE_BUS_OFF) { |
| 896 | 1115 | cf->can_id |= CAN_ERR_RESTARTED; |
| 897 | 1116 | netif_carrier_on(priv->netdev); |
| @@ -990,11 +1209,11 @@ static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev, · 92 unmodified lines | ||
| 990 | 1209 | |
| 991 | 1210 | case CMD_CAN_ERROR_EVENT: |
| 992 | 1211 | es.channel = 0; |
| 993 | − es.status = cmd->u.usbcan.error_event.status_ch0; | |
| 994 | − es.txerr = cmd->u.usbcan.error_event.tx_errors_count_ch0; | |
| 995 | − es.rxerr = cmd->u.usbcan.error_event.rx_errors_count_ch0; | |
| 1212 | + es.status = cmd->u.usbcan.can_error_event.status_ch0; | |
| 1213 | + es.txerr = cmd->u.usbcan.can_error_event.tx_errors_count_ch0; | |
| 1214 | + es.rxerr = cmd->u.usbcan.can_error_event.rx_errors_count_ch0; | |
| 996 | 1215 | es.usbcan.other_ch_status = |
| 997 | − cmd->u.usbcan.error_event.status_ch1; | |
| 1216 | + cmd->u.usbcan.can_error_event.status_ch1; | |
| 998 | 1217 | kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es); |
| 999 | 1218 | |
| 1000 | 1219 | /* The USBCAN firmware supports up to 2 channels. |
| @@ -1002,13 +1221,13 @@ static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev, · 1 unmodified line | ||
| 1002 | 1221 | */ |
| 1003 | 1222 | if (dev->nchannels == MAX_USBCAN_NET_DEVICES) { |
| 1004 | 1223 | es.channel = 1; |
| 1005 | − es.status = cmd->u.usbcan.error_event.status_ch1; | |
| 1224 | + es.status = cmd->u.usbcan.can_error_event.status_ch1; | |
| 1006 | 1225 | es.txerr = |
| 1007 | − cmd->u.usbcan.error_event.tx_errors_count_ch1; | |
| 1226 | + cmd->u.usbcan.can_error_event.tx_errors_count_ch1; | |
| 1008 | 1227 | es.rxerr = |
| 1009 | − cmd->u.usbcan.error_event.rx_errors_count_ch1; | |
| 1228 | + cmd->u.usbcan.can_error_event.rx_errors_count_ch1; | |
| 1010 | 1229 | es.usbcan.other_ch_status = |
| 1011 | − cmd->u.usbcan.error_event.status_ch0; | |
| 1230 | + cmd->u.usbcan.can_error_event.status_ch0; | |
| 1012 | 1231 | kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es); |
| 1013 | 1232 | } |
| 1014 | 1233 | break; |
| @@ -1025,11 +1244,11 @@ static void kvaser_usb_leaf_leaf_rx_error(const struct kvaser_usb *dev, · 10 unmodified lines | ||
| 1025 | 1244 | |
| 1026 | 1245 | switch (cmd->id) { |
| 1027 | 1246 | case CMD_CAN_ERROR_EVENT: |
| 1028 | − es.channel = cmd->u.leaf.error_event.channel; | |
| 1029 | − es.status = cmd->u.leaf.error_event.status; | |
| 1030 | − es.txerr = cmd->u.leaf.error_event.tx_errors_count; | |
| 1031 | − es.rxerr = cmd->u.leaf.error_event.rx_errors_count; | |
| 1032 | − es.leaf.error_factor = cmd->u.leaf.error_event.error_factor; | |
| 1247 | + es.channel = cmd->u.leaf.can_error_event.channel; | |
| 1248 | + es.status = cmd->u.leaf.can_error_event.status; | |
| 1249 | + es.txerr = cmd->u.leaf.can_error_event.tx_errors_count; | |
| 1250 | + es.rxerr = cmd->u.leaf.can_error_event.rx_errors_count; | |
| 1251 | + es.leaf.error_factor = cmd->u.leaf.can_error_event.error_factor; | |
| 1033 | 1252 | break; |
| 1034 | 1253 | case CMD_LEAF_LOG_MESSAGE: |
| 1035 | 1254 | es.channel = cmd->u.leaf.log_message.channel; |
| @@ -1162,6 +1381,74 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev, · 126 unmodified lines | ||
| 1162 | 1381 | netif_rx(skb); |
| 1163 | 1382 | } |
| 1164 | 1383 | |
| 1384 | +static void kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb *dev, | |
| 1385 | + const struct kvaser_cmd *cmd) | |
| 1386 | +{ | |
| 1387 | + u16 info1 = 0; | |
| 1388 | + | |
| 1389 | + switch (dev->driver_info->family) { | |
| 1390 | + case KVASER_LEAF: | |
| 1391 | + info1 = le16_to_cpu(cmd->u.leaf.error_event.info1); | |
| 1392 | + break; | |
| 1393 | + case KVASER_USBCAN: | |
| 1394 | + info1 = le16_to_cpu(cmd->u.usbcan.error_event.info1); | |
| 1395 | + break; | |
| 1396 | + } | |
| 1397 | + | |
| 1398 | + /* info1 will contain the offending cmd_no */ | |
| 1399 | + switch (info1) { | |
| 1400 | + case CMD_SET_CTRL_MODE: | |
| 1401 | + dev_warn(&dev->intf->dev, | |
| 1402 | + "CMD_SET_CTRL_MODE error in parameter\n"); | |
| 1403 | + break; | |
| 1404 | + | |
| 1405 | + case CMD_SET_BUS_PARAMS: | |
| 1406 | + dev_warn(&dev->intf->dev, | |
| 1407 | + "CMD_SET_BUS_PARAMS error in parameter\n"); | |
| 1408 | + break; | |
| 1409 | + | |
| 1410 | + default: | |
| 1411 | + dev_warn(&dev->intf->dev, | |
| 1412 | + "Unhandled parameter error event cmd_no (%u)\n", | |
| 1413 | + info1); | |
| 1414 | + break; | |
| 1415 | + } | |
| 1416 | +} | |
| 1417 | + | |
| 1418 | +static void kvaser_usb_leaf_error_event(const struct kvaser_usb *dev, | |
| 1419 | + const struct kvaser_cmd *cmd) | |
| 1420 | +{ | |
| 1421 | + u8 error_code = 0; | |
| 1422 | + | |
| 1423 | + switch (dev->driver_info->family) { | |
| 1424 | + case KVASER_LEAF: | |
| 1425 | + error_code = cmd->u.leaf.error_event.error_code; | |
| 1426 | + break; | |
| 1427 | + case KVASER_USBCAN: | |
| 1428 | + error_code = cmd->u.usbcan.error_event.error_code; | |
| 1429 | + break; | |
| 1430 | + } | |
| 1431 | + | |
| 1432 | + switch (error_code) { | |
| 1433 | + case KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL: | |
| 1434 | + /* Received additional CAN message, when firmware TX queue is | |
| 1435 | + * already full. Something is wrong with the driver. | |
| 1436 | + * This should never happen! | |
| 1437 | + */ | |
| 1438 | + dev_err(&dev->intf->dev, | |
| 1439 | + "Received error event TX_QUEUE_FULL\n"); | |
| 1440 | + break; | |
| 1441 | + case KVASER_USB_LEAF_ERROR_EVENT_PARAM: | |
| 1442 | + kvaser_usb_leaf_error_event_parameter(dev, cmd); | |
| 1443 | + break; | |
| 1444 | + | |
| 1445 | + default: | |
| 1446 | + dev_warn(&dev->intf->dev, | |
| 1447 | + "Unhandled error event (%d)\n", error_code); | |
| 1448 | + break; | |
| 1449 | + } | |
| 1450 | +} | |
| 1451 | + | |
| 1165 | 1452 | static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev, |
| 1166 | 1453 | const struct kvaser_cmd *cmd) |
| 1167 | 1454 | { |
| @@ -1202,6 +1489,25 @@ static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev, · 34 unmodified lines | ||
| 1202 | 1489 | complete(&priv->stop_comp); |
| 1203 | 1490 | } |
| 1204 | 1491 | |
| 1492 | +static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev, | |
| 1493 | + const struct kvaser_cmd *cmd) | |
| 1494 | +{ | |
| 1495 | + struct kvaser_usb_net_priv *priv; | |
| 1496 | + u8 channel = cmd->u.busparams.channel; | |
| 1497 | + | |
| 1498 | + if (channel >= dev->nchannels) { | |
| 1499 | + dev_err(&dev->intf->dev, | |
| 1500 | + "Invalid channel number (%d)\n", channel); | |
| 1501 | + return; | |
| 1502 | + } | |
| 1503 | + | |
| 1504 | + priv = dev->nets[channel]; | |
| 1505 | + memcpy(&priv->busparams_nominal, &cmd->u.busparams.busparams, | |
| 1506 | + sizeof(priv->busparams_nominal)); | |
| 1507 | + | |
| 1508 | + complete(&priv->get_busparams_comp); | |
| 1509 | +} | |
| 1510 | + | |
| 1205 | 1511 | static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev, |
| 1206 | 1512 | const struct kvaser_cmd *cmd) |
| 1207 | 1513 | { |
| @@ -1240,6 +1546,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev, · 32 unmodified lines | ||
| 1240 | 1546 | kvaser_usb_leaf_tx_acknowledge(dev, cmd); |
| 1241 | 1547 | break; |
| 1242 | 1548 | |
| 1549 | + case CMD_ERROR_EVENT: | |
| 1550 | + kvaser_usb_leaf_error_event(dev, cmd); | |
| 1551 | + break; | |
| 1552 | + | |
| 1553 | + case CMD_GET_BUS_PARAMS_REPLY: | |
| 1554 | + kvaser_usb_leaf_get_busparams_reply(dev, cmd); | |
| 1555 | + break; | |
| 1556 | + | |
| 1243 | 1557 | /* Ignored commands */ |
| 1244 | 1558 | case CMD_USBCAN_CLOCK_OVERFLOW_EVENT: |
| 1245 | 1559 | if (dev->driver_info->family != KVASER_USBCAN) |
| @@ -1318,8 +1632,11 @@ static int kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv *priv) · 72 unmodified lines | ||
| 1318 | 1632 | |
| 1319 | 1633 | static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv) |
| 1320 | 1634 | { |
| 1635 | + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | |
| 1321 | 1636 | int err; |
| 1322 | 1637 | |
| 1638 | + leaf->joining_bus = true; | |
| 1639 | + | |
| 1323 | 1640 | reinit_completion(&priv->start_comp); |
| 1324 | 1641 | |
| 1325 | 1642 | err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP, |
| @@ -1336,10 +1653,13 @@ static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv) · 10 unmodified lines | ||
| 1336 | 1653 | |
| 1337 | 1654 | static int kvaser_usb_leaf_stop_chip(struct kvaser_usb_net_priv *priv) |
| 1338 | 1655 | { |
| 1656 | + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | |
| 1339 | 1657 | int err; |
| 1340 | 1658 | |
| 1341 | 1659 | reinit_completion(&priv->stop_comp); |
| 1342 | 1660 | |
| 1661 | + cancel_delayed_work(&leaf->chip_state_req_work); | |
| 1662 | + | |
| 1343 | 1663 | err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_STOP_CHIP, |
| 1344 | 1664 | priv->channel); |
| 1345 | 1665 | if (err) |
| @@ -1386,10 +1706,35 @@ static int kvaser_usb_leaf_init_card(struct kvaser_usb *dev) · 40 unmodified lines | ||
| 1386 | 1706 | return 0; |
| 1387 | 1707 | } |
| 1388 | 1708 | |
| 1389 | −static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev) | |
| 1709 | +static int kvaser_usb_leaf_init_channel(struct kvaser_usb_net_priv *priv) | |
| 1710 | +{ | |
| 1711 | + struct kvaser_usb_net_leaf_priv *leaf; | |
| 1712 | + | |
| 1713 | + leaf = devm_kzalloc(&priv->dev->intf->dev, sizeof(*leaf), GFP_KERNEL); | |
| 1714 | + if (!leaf) | |
| 1715 | + return -ENOMEM; | |
| 1716 | + | |
| 1717 | + leaf->net = priv; | |
| 1718 | + INIT_DELAYED_WORK(&leaf->chip_state_req_work, | |
| 1719 | + kvaser_usb_leaf_chip_state_req_work); | |
| 1720 | + | |
| 1721 | + priv->sub_priv = leaf; | |
| 1722 | + | |
| 1723 | + return 0; | |
| 1724 | +} | |
| 1725 | + | |
| 1726 | +static void kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv *priv) | |
| 1727 | +{ | |
| 1728 | + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | |
| 1729 | + | |
| 1730 | + if (leaf) | |
| 1731 | + cancel_delayed_work_sync(&leaf->chip_state_req_work); | |
| 1732 | +} | |
| 1733 | + | |
| 1734 | +static int kvaser_usb_leaf_set_bittiming(const struct net_device *netdev, | |
| 1735 | + const struct kvaser_usb_busparams *busparams) | |
| 1390 | 1736 | { |
| 1391 | 1737 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1392 | − struct can_bittiming *bt = &priv->can.bittiming; | |
| 1393 | 1738 | struct kvaser_usb *dev = priv->dev; |
| 1394 | 1739 | struct kvaser_cmd *cmd; |
| 1395 | 1740 | int rc; |
| @@ -1402,15 +1747,8 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev) · 6 unmodified lines | ||
| 1402 | 1747 | cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams); |
| 1403 | 1748 | cmd->u.busparams.channel = priv->channel; |
| 1404 | 1749 | cmd->u.busparams.tid = 0xff; |
| 1405 | − cmd->u.busparams.bitrate = cpu_to_le32(bt->bitrate); | |
| 1406 | − cmd->u.busparams.sjw = bt->sjw; | |
| 1407 | − cmd->u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1; | |
| 1408 | − cmd->u.busparams.tseg2 = bt->phase_seg2; | |
| 1409 | − | |
| 1410 | − if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) | |
| 1411 | − cmd->u.busparams.no_samp = 3; | |
| 1412 | − else | |
| 1413 | − cmd->u.busparams.no_samp = 1; | |
| 1750 | + memcpy(&cmd->u.busparams.busparams, busparams, | |
| 1751 | + sizeof(cmd->u.busparams.busparams)); | |
| 1414 | 1752 | |
| 1415 | 1753 | rc = kvaser_usb_send_cmd(dev, cmd, cmd->len); |
| 1416 | 1754 | |
| @@ -1418,16 +1756,40 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev) · 1 unmodified line | ||
| 1418 | 1756 | return rc; |
| 1419 | 1757 | } |
| 1420 | 1758 | |
| 1759 | +static int kvaser_usb_leaf_get_busparams(struct kvaser_usb_net_priv *priv) | |
| 1760 | +{ | |
| 1761 | + int err; | |
| 1762 | + | |
| 1763 | + if (priv->dev->driver_info->family == KVASER_USBCAN) | |
| 1764 | + return -EOPNOTSUPP; | |
| 1765 | + | |
| 1766 | + reinit_completion(&priv->get_busparams_comp); | |
| 1767 | + | |
| 1768 | + err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_GET_BUS_PARAMS, | |
| 1769 | + priv->channel); | |
| 1770 | + if (err) | |
| 1771 | + return err; | |
| 1772 | + | |
| 1773 | + if (!wait_for_completion_timeout(&priv->get_busparams_comp, | |
| 1774 | + msecs_to_jiffies(KVASER_USB_TIMEOUT))) | |
| 1775 | + return -ETIMEDOUT; | |
| 1776 | + | |
| 1777 | + return 0; | |
| 1778 | +} | |
| 1779 | + | |
| 1421 | 1780 | static int kvaser_usb_leaf_set_mode(struct net_device *netdev, |
| 1422 | 1781 | enum can_mode mode) |
| 1423 | 1782 | { |
| 1424 | 1783 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1784 | + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | |
| 1425 | 1785 | int err; |
| 1426 | 1786 | |
| 1427 | 1787 | switch (mode) { |
| 1428 | 1788 | case CAN_MODE_START: |
| 1429 | 1789 | kvaser_usb_unlink_tx_urbs(priv); |
| 1430 | 1790 | |
| 1791 | + leaf->joining_bus = true; | |
| 1792 | + | |
| 1431 | 1793 | err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP); |
| 1432 | 1794 | if (err) |
| 1433 | 1795 | return err; |
| @@ -1479,14 +1841,18 @@ static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev) · 45 unmodified lines | ||
| 1479 | 1841 | const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = { |
| 1480 | 1842 | .dev_set_mode = kvaser_usb_leaf_set_mode, |
| 1481 | 1843 | .dev_set_bittiming = kvaser_usb_leaf_set_bittiming, |
| 1844 | + .dev_get_busparams = kvaser_usb_leaf_get_busparams, | |
| 1482 | 1845 | .dev_set_data_bittiming = NULL, |
| 1846 | + .dev_get_data_busparams = NULL, | |
| 1483 | 1847 | .dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter, |
| 1484 | 1848 | .dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints, |
| 1485 | 1849 | .dev_init_card = kvaser_usb_leaf_init_card, |
| 1850 | + .dev_init_channel = kvaser_usb_leaf_init_channel, | |
| 1851 | + .dev_remove_channel = kvaser_usb_leaf_remove_channel, | |
| 1486 | 1852 | .dev_get_software_info = kvaser_usb_leaf_get_software_info, |
| 1487 | 1853 | .dev_get_software_details = NULL, |
| 1488 | 1854 | .dev_get_card_info = kvaser_usb_leaf_get_card_info, |
| 1489 | − .dev_get_capabilities = NULL, | |
| 1855 | + .dev_get_capabilities = kvaser_usb_leaf_get_capabilities, | |
| 1490 | 1856 | .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode, |
| 1491 | 1857 | .dev_start_chip = kvaser_usb_leaf_start_chip, |
| 1492 | 1858 | .dev_stop_chip = kvaser_usb_leaf_stop_chip, |
| @@ -245,7 +245,8 @@ struct ucan_message_in { · 244 unmodified lines | ||
| 245 | 245 | /* CAN transmission complete |
| 246 | 246 | * (type == UCAN_IN_TX_COMPLETE) |
| 247 | 247 | */ |
| 248 | − struct ucan_tx_complete_entry_t can_tx_complete_msg[0]; | |
| 248 | + DECLARE_FLEX_ARRAY(struct ucan_tx_complete_entry_t, | |
| 249 | + can_tx_complete_msg); | |
| 249 | 250 | } __aligned(0x4) msg; |
| 250 | 251 | } __packed __aligned(0x4); |
| 251 | 252 | |
| @@ -276,7 +277,6 @@ struct ucan_priv { · 24 unmodified lines | ||
| 276 | 277 | |
| 277 | 278 | /* linux USB device structures */ |
| 278 | 279 | struct usb_device *udev; |
| 279 | − struct usb_interface *intf; | |
| 280 | 280 | struct net_device *netdev; |
| 281 | 281 | |
| 282 | 282 | /* lock for can->echo_skb (used around |
| @@ -1500,7 +1500,6 @@ static int ucan_probe(struct usb_interface *intf, · 1217 unmodified lines | ||
| 1500 | 1500 | |
| 1501 | 1501 | /* initialize data */ |
| 1502 | 1502 | up->udev = udev; |
| 1503 | − up->intf = intf; | |
| 1504 | 1503 | up->netdev = netdev; |
| 1505 | 1504 | up->intf_index = iface_desc->desc.bInterfaceNumber; |
| 1506 | 1505 | up->in_ep_addr = in_ep_addr; |
| @@ -1533,9 +1532,8 @@ static int ucan_probe(struct usb_interface *intf, · 26 unmodified lines | ||
| 1533 | 1532 | sizeof(union ucan_ctl_payload)); |
| 1534 | 1533 | if (ret > 0) { |
| 1535 | 1534 | /* copy string while ensuring zero termination */ |
| 1536 | − strncpy(firmware_str, up->ctl_msg_buffer->raw, | |
| 1537 | − sizeof(union ucan_ctl_payload)); | |
| 1538 | − firmware_str[sizeof(union ucan_ctl_payload)] = '\0'; | |
| 1535 | + strscpy(firmware_str, up->ctl_msg_buffer->raw, | |
| 1536 | + sizeof(union ucan_ctl_payload) + 1); | |
| 1539 | 1537 | } else { |
| 1540 | 1538 | strcpy(firmware_str, "unknown"); |
| 1541 | 1539 | } |
| @@ -1581,7 +1579,7 @@ static void ucan_disconnect(struct usb_interface *intf) · 39 unmodified lines | ||
| 1581 | 1579 | usb_set_intfdata(intf, NULL); |
| 1582 | 1580 | |
| 1583 | 1581 | if (up) { |
| 1584 | − unregister_netdev(up->netdev); | |
| 1582 | + unregister_candev(up->netdev); | |
| 1585 | 1583 | free_candev(up->netdev); |
| 1586 | 1584 | } |
| 1587 | 1585 | } |
| @@ -236,7 +236,7 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, · 235 unmodified lines | ||
| 236 | 236 | |
| 237 | 237 | netif_carrier_off(peer); |
| 238 | 238 | |
| 239 | − err = rtnl_configure_link(peer, ifmp); | |
| 239 | + err = rtnl_configure_link(peer, ifmp, 0, NULL); | |
| 240 | 240 | if (err < 0) |
| 241 | 241 | goto unregister_network_device; |
| 242 | 242 | |
| @@ -18,6 +18,7 @@ config NET_DSA_BCM_SF2 · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | config NET_DSA_LOOP |
| 20 | 20 | tristate "DSA mock-up Ethernet switch chip support" |
| 21 | + select NET_DSA_TAG_NONE | |
| 21 | 22 | select FIXED_PHY |
| 22 | 23 | help |
| 23 | 24 | This enables support for a fake mock-up switch chip which |
| @@ -99,6 +100,7 @@ config NET_DSA_SMSC_LAN9303_MDIO · 75 unmodified lines | ||
| 99 | 100 | |
| 100 | 101 | config NET_DSA_VITESSE_VSC73XX |
| 101 | 102 | tristate |
| 103 | + select NET_DSA_TAG_NONE | |
| 102 | 104 | select FIXED_PHY |
| 103 | 105 | select VITESSE_PHY |
| 104 | 106 | select GPIOLIB |
| @@ -2,6 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | menuconfig B53 |
| 3 | 3 | tristate "Broadcom BCM53xx managed switch support" |
| 4 | 4 | depends on NET_DSA |
| 5 | + select NET_DSA_TAG_NONE | |
| 5 | 6 | select NET_DSA_TAG_BRCM |
| 6 | 7 | select NET_DSA_TAG_BRCM_LEGACY |
| 7 | 8 | select NET_DSA_TAG_BRCM_PREPEND |
| @@ -1176,11 +1176,6 @@ static int hellcreek_devlink_info_get(struct dsa_switch *ds, · 1175 unmodified lines | ||
| 1176 | 1176 | struct netlink_ext_ack *extack) |
| 1177 | 1177 | { |
| 1178 | 1178 | struct hellcreek *hellcreek = ds->priv; |
| 1179 | − int ret; | |
| 1180 | − | |
| 1181 | − ret = devlink_info_driver_name_put(req, "hellcreek"); | |
| 1182 | − if (ret) | |
| 1183 | − return ret; | |
| 1184 | 1179 | |
| 1185 | 1180 | return devlink_info_version_fixed_put(req, |
| 1186 | 1181 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, |
| @@ -1005,9 +1005,11 @@ static void lan9303_get_ethtool_stats(struct dsa_switch *ds, int port, · 1004 unmodified lines | ||
| 1005 | 1005 | ret = lan9303_read_switch_port( |
| 1006 | 1006 | chip, port, lan9303_mib[u].offset, ®); |
| 1007 | 1007 | |
| 1008 | − if (ret) | |
| 1008 | + if (ret) { | |
| 1009 | 1009 | dev_warn(chip->dev, "Reading status port %d reg %u failed\n", |
| 1010 | 1010 | port, lan9303_mib[u].offset); |
| 1011 | + reg = 0; | |
| 1012 | + } | |
| 1011 | 1013 | data[u] = reg; |
| 1012 | 1014 | } |
| 1013 | 1015 | } |
| @@ -29,8 +29,7 @@ static const struct regmap_config lan9303_i2c_regmap_config = { · 28 unmodified lines | ||
| 29 | 29 | .cache_type = REGCACHE_NONE, |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | −static int lan9303_i2c_probe(struct i2c_client *client, | |
| 33 | − const struct i2c_device_id *id) | |
| 32 | +static int lan9303_i2c_probe(struct i2c_client *client) | |
| 34 | 33 | { |
| 35 | 34 | struct lan9303_i2c *sw_dev; |
| 36 | 35 | int ret; |
| @@ -106,7 +105,7 @@ static struct i2c_driver lan9303_i2c_driver = { · 69 unmodified lines | ||
| 106 | 105 | .name = "LAN9303_I2C", |
| 107 | 106 | .of_match_table = of_match_ptr(lan9303_i2c_of_match), |
| 108 | 107 | }, |
| 109 | − .probe = lan9303_i2c_probe, | |
| 108 | + .probe_new = lan9303_i2c_probe, | |
| 110 | 109 | .remove = lan9303_i2c_remove, |
| 111 | 110 | .shutdown = lan9303_i2c_shutdown, |
| 112 | 111 | .id_table = lan9303_i2c_id, |
| @@ -3,6 +3,7 @@ menuconfig NET_DSA_MICROCHIP_KSZ_COMMON · 2 unmodified lines | ||
| 3 | 3 | tristate "Microchip KSZ8795/KSZ9477/LAN937x series switch support" |
| 4 | 4 | depends on NET_DSA |
| 5 | 5 | select NET_DSA_TAG_KSZ |
| 6 | + select NET_DSA_TAG_NONE | |
| 6 | 7 | help |
| 7 | 8 | This driver adds support for Microchip KSZ9477 series switch and |
| 8 | 9 | KSZ8795/KSZ88x3 switch chips. |
| @@ -57,5 +57,6 @@ int ksz8_reset_switch(struct ksz_device *dev); · 56 unmodified lines | ||
| 57 | 57 | int ksz8_switch_detect(struct ksz_device *dev); |
| 58 | 58 | int ksz8_switch_init(struct ksz_device *dev); |
| 59 | 59 | void ksz8_switch_exit(struct ksz_device *dev); |
| 60 | +int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu); | |
| 60 | 61 | |
| 61 | 62 | #endif |
| @@ -76,6 +76,57 @@ int ksz8_reset_switch(struct ksz_device *dev) · 75 unmodified lines | ||
| 76 | 76 | return 0; |
| 77 | 77 | } |
| 78 | 78 | |
| 79 | +static int ksz8863_change_mtu(struct ksz_device *dev, int frame_size) | |
| 80 | +{ | |
| 81 | + u8 ctrl2 = 0; | |
| 82 | + | |
| 83 | + if (frame_size <= KSZ8_LEGAL_PACKET_SIZE) | |
| 84 | + ctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE; | |
| 85 | + else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) | |
| 86 | + ctrl2 |= KSZ8863_HUGE_PACKET_ENABLE; | |
| 87 | + | |
| 88 | + return ksz_rmw8(dev, REG_SW_CTRL_2, KSZ8863_LEGAL_PACKET_ENABLE | | |
| 89 | + KSZ8863_HUGE_PACKET_ENABLE, ctrl2); | |
| 90 | +} | |
| 91 | + | |
| 92 | +static int ksz8795_change_mtu(struct ksz_device *dev, int frame_size) | |
| 93 | +{ | |
| 94 | + u8 ctrl1 = 0, ctrl2 = 0; | |
| 95 | + int ret; | |
| 96 | + | |
| 97 | + if (frame_size > KSZ8_LEGAL_PACKET_SIZE) | |
| 98 | + ctrl2 |= SW_LEGAL_PACKET_DISABLE; | |
| 99 | + else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) | |
| 100 | + ctrl1 |= SW_HUGE_PACKET; | |
| 101 | + | |
| 102 | + ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_HUGE_PACKET, ctrl1); | |
| 103 | + if (ret) | |
| 104 | + return ret; | |
| 105 | + | |
| 106 | + return ksz_rmw8(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, ctrl2); | |
| 107 | +} | |
| 108 | + | |
| 109 | +int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu) | |
| 110 | +{ | |
| 111 | + u16 frame_size; | |
| 112 | + | |
| 113 | + if (!dsa_is_cpu_port(dev->ds, port)) | |
| 114 | + return 0; | |
| 115 | + | |
| 116 | + frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; | |
| 117 | + | |
| 118 | + switch (dev->chip_id) { | |
| 119 | + case KSZ8795_CHIP_ID: | |
| 120 | + case KSZ8794_CHIP_ID: | |
| 121 | + case KSZ8765_CHIP_ID: | |
| 122 | + return ksz8795_change_mtu(dev, frame_size); | |
| 123 | + case KSZ8830_CHIP_ID: | |
| 124 | + return ksz8863_change_mtu(dev, frame_size); | |
| 125 | + } | |
| 126 | + | |
| 127 | + return -EOPNOTSUPP; | |
| 128 | +} | |
| 129 | + | |
| 79 | 130 | static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) |
| 80 | 131 | { |
| 81 | 132 | u8 hi, lo; |
| @@ -1233,8 +1284,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) · 1151 unmodified lines | ||
| 1233 | 1284 | masks = dev->info->masks; |
| 1234 | 1285 | regs = dev->info->regs; |
| 1235 | 1286 | |
| 1236 | − /* Switch marks the maximum frame with extra byte as oversize. */ | |
| 1237 | − ksz_cfg(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, true); | |
| 1238 | 1287 | ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true); |
| 1239 | 1288 | |
| 1240 | 1289 | p = &dev->ports[dev->cpu_port]; |
| @@ -1308,6 +1357,18 @@ int ksz8_setup(struct dsa_switch *ds) · 67 unmodified lines | ||
| 1308 | 1357 | struct ksz_device *dev = ds->priv; |
| 1309 | 1358 | int i; |
| 1310 | 1359 | |
| 1360 | + ds->mtu_enforcement_ingress = true; | |
| 1361 | + | |
| 1362 | + /* We rely on software untagging on the CPU port, so that we | |
| 1363 | + * can support both tagged and untagged VLANs | |
| 1364 | + */ | |
| 1365 | + ds->untag_bridge_pvid = true; | |
| 1366 | + | |
| 1367 | + /* VLAN filtering is partly controlled by the global VLAN | |
| 1368 | + * Enable flag | |
| 1369 | + */ | |
| 1370 | + ds->vlan_filtering_is_global = true; | |
| 1371 | + | |
| 1311 | 1372 | ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); |
| 1312 | 1373 | |
| 1313 | 1374 | /* Enable automatic fast aging when link changed detected. */ |
| @@ -1367,16 +1428,6 @@ int ksz8_switch_init(struct ksz_device *dev) · 53 unmodified lines | ||
| 1367 | 1428 | dev->phy_port_cnt = dev->info->port_cnt - 1; |
| 1368 | 1429 | dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports; |
| 1369 | 1430 | |
| 1370 | − /* We rely on software untagging on the CPU port, so that we | |
| 1371 | − * can support both tagged and untagged VLANs | |
| 1372 | − */ | |
| 1373 | − dev->ds->untag_bridge_pvid = true; | |
| 1374 | − | |
| 1375 | − /* VLAN filtering is partly controlled by the global VLAN | |
| 1376 | − * Enable flag | |
| 1377 | − */ | |
| 1378 | − dev->ds->vlan_filtering_is_global = true; | |
| 1379 | − | |
| 1380 | 1431 | return 0; |
| 1381 | 1432 | } |
| 1382 | 1433 | |
| @@ -48,6 +48,9 @@ · 47 unmodified lines | ||
| 48 | 48 | #define NO_EXC_COLLISION_DROP BIT(3) |
| 49 | 49 | #define SW_LEGAL_PACKET_DISABLE BIT(1) |
| 50 | 50 | |
| 51 | +#define KSZ8863_HUGE_PACKET_ENABLE BIT(2) | |
| 52 | +#define KSZ8863_LEGAL_PACKET_ENABLE BIT(1) | |
| 53 | + | |
| 51 | 54 | #define REG_SW_CTRL_3 0x05 |
| 52 | 55 | #define WEIGHTED_FAIR_QUEUE_ENABLE BIT(3) |
| 53 | 56 | |
| @@ -152,11 +152,10 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev) · 151 unmodified lines | ||
| 152 | 152 | ®map_smi[i], dev, |
| 153 | 153 | &rc); |
| 154 | 154 | if (IS_ERR(dev->regmap[i])) { |
| 155 | − ret = PTR_ERR(dev->regmap[i]); | |
| 156 | − dev_err(&mdiodev->dev, | |
| 157 | − "Failed to initialize regmap%i: %d\n", | |
| 158 | − ksz8863_regmap_config[i].val_bits, ret); | |
| 159 | − return ret; | |
| 155 | + return dev_err_probe(&mdiodev->dev, | |
| 156 | + PTR_ERR(dev->regmap[i]), | |
| 157 | + "Failed to initialize regmap%i\n", | |
| 158 | + ksz8863_regmap_config[i].val_bits); | |
| 160 | 159 | } |
| 161 | 160 | } |
| 162 | 161 | |
| @@ -45,24 +45,15 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) |
| 47 | 47 | { |
| 48 | − u16 frame_size, max_frame = 0; | |
| 49 | − int i; | |
| 50 | − | |
| 51 | − frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; | |
| 48 | + u16 frame_size; | |
| 52 | 49 | |
| 53 | − /* Cache the per-port MTU setting */ | |
| 54 | − dev->ports[port].max_frame = frame_size; | |
| 50 | + if (!dsa_is_cpu_port(dev->ds, port)) | |
| 51 | + return 0; | |
| 55 | 52 | |
| 56 | − for (i = 0; i < dev->info->port_cnt; i++) | |
| 57 | − max_frame = max(max_frame, dev->ports[i].max_frame); | |
| 53 | + frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; | |
| 58 | 54 | |
| 59 | 55 | return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, |
| 60 | − REG_SW_MTU_MASK, max_frame); | |
| 61 | −} | |
| 62 | − | |
| 63 | −int ksz9477_max_mtu(struct ksz_device *dev, int port) | |
| 64 | −{ | |
| 65 | − return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; | |
| 56 | + REG_SW_MTU_MASK, frame_size); | |
| 66 | 57 | } |
| 67 | 58 | |
| 68 | 59 | static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) |
| @@ -195,7 +186,8 @@ int ksz9477_reset_switch(struct ksz_device *dev) · 126 unmodified lines | ||
| 195 | 186 | |
| 196 | 187 | /* KSZ9893 compatible chips do not support refclk configuration */ |
| 197 | 188 | if (dev->chip_id == KSZ9893_CHIP_ID || |
| 198 | − dev->chip_id == KSZ8563_CHIP_ID) | |
| 189 | + dev->chip_id == KSZ8563_CHIP_ID || | |
| 190 | + dev->chip_id == KSZ9563_CHIP_ID) | |
| 199 | 191 | return 0; |
| 200 | 192 | |
| 201 | 193 | data8 = SW_ENABLE_REFCLKO; |
| @@ -1142,6 +1134,8 @@ int ksz9477_setup(struct dsa_switch *ds) · 940 unmodified lines | ||
| 1142 | 1134 | struct ksz_device *dev = ds->priv; |
| 1143 | 1135 | int ret = 0; |
| 1144 | 1136 | |
| 1137 | + ds->mtu_enforcement_ingress = true; | |
| 1138 | + | |
| 1145 | 1139 | /* Required for port partitioning. */ |
| 1146 | 1140 | ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, |
| 1147 | 1141 | true); |
| @@ -50,7 +50,6 @@ int ksz9477_mdb_add(struct ksz_device *dev, int port, · 49 unmodified lines | ||
| 50 | 50 | int ksz9477_mdb_del(struct ksz_device *dev, int port, |
| 51 | 51 | const struct switchdev_obj_port_mdb *mdb, struct dsa_db db); |
| 52 | 52 | int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu); |
| 53 | −int ksz9477_max_mtu(struct ksz_device *dev, int port); | |
| 54 | 53 | void ksz9477_config_cpu_port(struct dsa_switch *ds); |
| 55 | 54 | int ksz9477_enable_stp_addr(struct ksz_device *dev); |
| 56 | 55 | int ksz9477_reset_switch(struct ksz_device *dev); |
| @@ -14,8 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0); |
| 16 | 16 | |
| 17 | −static int ksz9477_i2c_probe(struct i2c_client *i2c, | |
| 18 | − const struct i2c_device_id *i2c_id) | |
| 17 | +static int ksz9477_i2c_probe(struct i2c_client *i2c) | |
| 19 | 18 | { |
| 20 | 19 | struct regmap_config rc; |
| 21 | 20 | struct ksz_device *dev; |
| @@ -30,17 +29,17 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c, · 8 unmodified lines | ||
| 30 | 29 | rc.lock_arg = &dev->regmap_mutex; |
| 31 | 30 | dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc); |
| 32 | 31 | if (IS_ERR(dev->regmap[i])) { |
| 33 | − ret = PTR_ERR(dev->regmap[i]); | |
| 34 | − dev_err(&i2c->dev, | |
| 35 | − "Failed to initialize regmap%i: %d\n", | |
| 36 | − ksz9477_regmap_config[i].val_bits, ret); | |
| 37 | − return ret; | |
| 32 | + return dev_err_probe(&i2c->dev, PTR_ERR(dev->regmap[i]), | |
| 33 | + "Failed to initialize regmap%i\n", | |
| 34 | + ksz9477_regmap_config[i].val_bits); | |
| 38 | 35 | } |
| 39 | 36 | } |
| 40 | 37 | |
| 41 | 38 | if (i2c->dev.platform_data) |
| 42 | 39 | dev->pdata = i2c->dev.platform_data; |
| 43 | 40 | |
| 41 | + dev->irq = i2c->irq; | |
| 42 | + | |
| 44 | 43 | ret = ksz_switch_register(dev); |
| 45 | 44 | |
| 46 | 45 | /* Main DSA driver may not be started yet. */ |
| @@ -101,7 +100,7 @@ static const struct of_device_id ksz9477_dt_ids[] = { · 54 unmodified lines | ||
| 101 | 100 | }, |
| 102 | 101 | { |
| 103 | 102 | .compatible = "microchip,ksz9563", |
| 104 | − .data = &ksz_switch_chips[KSZ9893] | |
| 103 | + .data = &ksz_switch_chips[KSZ9563] | |
| 105 | 104 | }, |
| 106 | 105 | { |
| 107 | 106 | .compatible = "microchip,ksz8563", |
| @@ -120,7 +119,7 @@ static struct i2c_driver ksz9477_i2c_driver = { · 12 unmodified lines | ||
| 120 | 119 | .name = "ksz9477-switch", |
| 121 | 120 | .of_match_table = of_match_ptr(ksz9477_dt_ids), |
| 122 | 121 | }, |
| 123 | − .probe = ksz9477_i2c_probe, | |
| 122 | + .probe_new = ksz9477_i2c_probe, | |
| 124 | 123 | .remove = ksz9477_i2c_remove, |
| 125 | 124 | .shutdown = ksz9477_i2c_shutdown, |
| 126 | 125 | .id_table = ksz9477_i2c_id, |
| @@ -1615,6 +1615,4 @@ · 1614 unmodified lines | ||
| 1615 | 1615 | #define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) |
| 1616 | 1616 | #define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) |
| 1617 | 1617 | |
| 1618 | −#define KSZ9477_MAX_FRAME_SIZE 9000 | |
| 1619 | − | |
| 1620 | 1618 | #endif /* KSZ9477_REGS_H */ |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/phy.h> |
| 15 | 15 | #include <linux/etherdevice.h> |
| 16 | 16 | #include <linux/if_bridge.h> |
| 17 | +#include <linux/if_vlan.h> | |
| 17 | 18 | #include <linux/irq.h> |
| 18 | 19 | #include <linux/irqdomain.h> |
| 19 | 20 | #include <linux/of_mdio.h> |
| @@ -69,6 +70,43 @@ struct ksz_stats_raw { · 49 unmodified lines | ||
| 69 | 70 | u64 tx_discards; |
| 70 | 71 | }; |
| 71 | 72 | |
| 73 | +struct ksz88xx_stats_raw { | |
| 74 | + u64 rx; | |
| 75 | + u64 rx_hi; | |
| 76 | + u64 rx_undersize; | |
| 77 | + u64 rx_fragments; | |
| 78 | + u64 rx_oversize; | |
| 79 | + u64 rx_jabbers; | |
| 80 | + u64 rx_symbol_err; | |
| 81 | + u64 rx_crc_err; | |
| 82 | + u64 rx_align_err; | |
| 83 | + u64 rx_mac_ctrl; | |
| 84 | + u64 rx_pause; | |
| 85 | + u64 rx_bcast; | |
| 86 | + u64 rx_mcast; | |
| 87 | + u64 rx_ucast; | |
| 88 | + u64 rx_64_or_less; | |
| 89 | + u64 rx_65_127; | |
| 90 | + u64 rx_128_255; | |
| 91 | + u64 rx_256_511; | |
| 92 | + u64 rx_512_1023; | |
| 93 | + u64 rx_1024_1522; | |
| 94 | + u64 tx; | |
| 95 | + u64 tx_hi; | |
| 96 | + u64 tx_late_col; | |
| 97 | + u64 tx_pause; | |
| 98 | + u64 tx_bcast; | |
| 99 | + u64 tx_mcast; | |
| 100 | + u64 tx_ucast; | |
| 101 | + u64 tx_deferred; | |
| 102 | + u64 tx_total_col; | |
| 103 | + u64 tx_exc_col; | |
| 104 | + u64 tx_single_col; | |
| 105 | + u64 tx_mult_col; | |
| 106 | + u64 rx_discards; | |
| 107 | + u64 tx_discards; | |
| 108 | +}; | |
| 109 | + | |
| 72 | 110 | static const struct ksz_mib_names ksz88xx_mib_names[] = { |
| 73 | 111 | { 0x00, "rx" }, |
| 74 | 112 | { 0x01, "rx_hi" }, |
| @@ -155,6 +193,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = { · 80 unmodified lines | ||
| 155 | 193 | .w_phy = ksz8_w_phy, |
| 156 | 194 | .r_mib_cnt = ksz8_r_mib_cnt, |
| 157 | 195 | .r_mib_pkt = ksz8_r_mib_pkt, |
| 196 | + .r_mib_stat64 = ksz88xx_r_mib_stats64, | |
| 158 | 197 | .freeze_mib = ksz8_freeze_mib, |
| 159 | 198 | .port_init_cnt = ksz8_port_init_cnt, |
| 160 | 199 | .fdb_dump = ksz8_fdb_dump, |
| @@ -171,6 +210,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = { · 10 unmodified lines | ||
| 171 | 210 | .reset = ksz8_reset_switch, |
| 172 | 211 | .init = ksz8_switch_init, |
| 173 | 212 | .exit = ksz8_switch_exit, |
| 213 | + .change_mtu = ksz8_change_mtu, | |
| 174 | 214 | }; |
| 175 | 215 | |
| 176 | 216 | static void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port, |
| @@ -206,7 +246,6 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { · 29 unmodified lines | ||
| 206 | 246 | .mdb_add = ksz9477_mdb_add, |
| 207 | 247 | .mdb_del = ksz9477_mdb_del, |
| 208 | 248 | .change_mtu = ksz9477_change_mtu, |
| 209 | − .max_mtu = ksz9477_max_mtu, | |
| 210 | 249 | .phylink_mac_link_up = ksz9477_phylink_mac_link_up, |
| 211 | 250 | .config_cpu_port = ksz9477_config_cpu_port, |
| 212 | 251 | .enable_stp_addr = ksz9477_enable_stp_addr, |
| @@ -243,7 +282,6 @@ static const struct ksz_dev_ops lan937x_dev_ops = { · 30 unmodified lines | ||
| 243 | 282 | .mdb_add = ksz9477_mdb_add, |
| 244 | 283 | .mdb_del = ksz9477_mdb_del, |
| 245 | 284 | .change_mtu = lan937x_change_mtu, |
| 246 | − .max_mtu = ksz9477_max_mtu, | |
| 247 | 285 | .phylink_mac_link_up = ksz9477_phylink_mac_link_up, |
| 248 | 286 | .config_cpu_port = lan937x_config_cpu_port, |
| 249 | 287 | .enable_stp_addr = ksz9477_enable_stp_addr, |
| @@ -1039,6 +1077,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { · 789 unmodified lines | ||
| 1039 | 1077 | .num_statics = 16, |
| 1040 | 1078 | .cpu_ports = 0x07, /* can be configured as cpu port */ |
| 1041 | 1079 | .port_cnt = 3, /* total port count */ |
| 1080 | + .port_nirqs = 3, | |
| 1042 | 1081 | .ops = &ksz9477_dev_ops, |
| 1043 | 1082 | .mib_names = ksz9477_mib_names, |
| 1044 | 1083 | .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), |
| @@ -1282,6 +1321,31 @@ const struct ksz_chip_data ksz_switch_chips[] = { · 237 unmodified lines | ||
| 1282 | 1321 | .gbit_capable = {true, true, true}, |
| 1283 | 1322 | }, |
| 1284 | 1323 | |
| 1324 | + [KSZ9563] = { | |
| 1325 | + .chip_id = KSZ9563_CHIP_ID, | |
| 1326 | + .dev_name = "KSZ9563", | |
| 1327 | + .num_vlans = 4096, | |
| 1328 | + .num_alus = 4096, | |
| 1329 | + .num_statics = 16, | |
| 1330 | + .cpu_ports = 0x07, /* can be configured as cpu port */ | |
| 1331 | + .port_cnt = 3, /* total port count */ | |
| 1332 | + .port_nirqs = 3, | |
| 1333 | + .ops = &ksz9477_dev_ops, | |
| 1334 | + .mib_names = ksz9477_mib_names, | |
| 1335 | + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), | |
| 1336 | + .reg_mib_cnt = MIB_COUNTER_NUM, | |
| 1337 | + .regs = ksz9477_regs, | |
| 1338 | + .masks = ksz9477_masks, | |
| 1339 | + .shifts = ksz9477_shifts, | |
| 1340 | + .xmii_ctrl0 = ksz9477_xmii_ctrl0, | |
| 1341 | + .xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */ | |
| 1342 | + .supports_mii = {false, false, true}, | |
| 1343 | + .supports_rmii = {false, false, true}, | |
| 1344 | + .supports_rgmii = {false, false, true}, | |
| 1345 | + .internal_phy = {true, true, false}, | |
| 1346 | + .gbit_capable = {true, true, true}, | |
| 1347 | + }, | |
| 1348 | + | |
| 1285 | 1349 | [KSZ9567] = { |
| 1286 | 1350 | .chip_id = KSZ9567_CHIP_ID, |
| 1287 | 1351 | .dev_name = "KSZ9567", |
| @@ -1557,6 +1621,55 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port) · 269 unmodified lines | ||
| 1557 | 1621 | spin_unlock(&mib->stats64_lock); |
| 1558 | 1622 | } |
| 1559 | 1623 | |
| 1624 | +void ksz88xx_r_mib_stats64(struct ksz_device *dev, int port) | |
| 1625 | +{ | |
| 1626 | + struct ethtool_pause_stats *pstats; | |
| 1627 | + struct rtnl_link_stats64 *stats; | |
| 1628 | + struct ksz88xx_stats_raw *raw; | |
| 1629 | + struct ksz_port_mib *mib; | |
| 1630 | + | |
| 1631 | + mib = &dev->ports[port].mib; | |
| 1632 | + stats = &mib->stats64; | |
| 1633 | + pstats = &mib->pause_stats; | |
| 1634 | + raw = (struct ksz88xx_stats_raw *)mib->counters; | |
| 1635 | + | |
| 1636 | + spin_lock(&mib->stats64_lock); | |
| 1637 | + | |
| 1638 | + stats->rx_packets = raw->rx_bcast + raw->rx_mcast + raw->rx_ucast + | |
| 1639 | + raw->rx_pause; | |
| 1640 | + stats->tx_packets = raw->tx_bcast + raw->tx_mcast + raw->tx_ucast + | |
| 1641 | + raw->tx_pause; | |
| 1642 | + | |
| 1643 | + /* HW counters are counting bytes + FCS which is not acceptable | |
| 1644 | + * for rtnl_link_stats64 interface | |
| 1645 | + */ | |
| 1646 | + stats->rx_bytes = raw->rx + raw->rx_hi - stats->rx_packets * ETH_FCS_LEN; | |
| 1647 | + stats->tx_bytes = raw->tx + raw->tx_hi - stats->tx_packets * ETH_FCS_LEN; | |
| 1648 | + | |
| 1649 | + stats->rx_length_errors = raw->rx_undersize + raw->rx_fragments + | |
| 1650 | + raw->rx_oversize; | |
| 1651 | + | |
| 1652 | + stats->rx_crc_errors = raw->rx_crc_err; | |
| 1653 | + stats->rx_frame_errors = raw->rx_align_err; | |
| 1654 | + stats->rx_dropped = raw->rx_discards; | |
| 1655 | + stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors + | |
| 1656 | + stats->rx_frame_errors + stats->rx_dropped; | |
| 1657 | + | |
| 1658 | + stats->tx_window_errors = raw->tx_late_col; | |
| 1659 | + stats->tx_fifo_errors = raw->tx_discards; | |
| 1660 | + stats->tx_aborted_errors = raw->tx_exc_col; | |
| 1661 | + stats->tx_errors = stats->tx_window_errors + stats->tx_fifo_errors + | |
| 1662 | + stats->tx_aborted_errors; | |
| 1663 | + | |
| 1664 | + stats->multicast = raw->rx_mcast; | |
| 1665 | + stats->collisions = raw->tx_total_col; | |
| 1666 | + | |
| 1667 | + pstats->tx_pause_frames = raw->tx_pause; | |
| 1668 | + pstats->rx_pause_frames = raw->rx_pause; | |
| 1669 | + | |
| 1670 | + spin_unlock(&mib->stats64_lock); | |
| 1671 | +} | |
| 1672 | + | |
| 1560 | 1673 | static void ksz_get_stats64(struct dsa_switch *ds, int port, |
| 1561 | 1674 | struct rtnl_link_stats64 *s) |
| 1562 | 1675 | { |
| @@ -2389,7 +2502,8 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, · 826 unmodified lines | ||
| 2389 | 2502 | |
| 2390 | 2503 | if (dev->chip_id == KSZ8830_CHIP_ID || |
| 2391 | 2504 | dev->chip_id == KSZ8563_CHIP_ID || |
| 2392 | − dev->chip_id == KSZ9893_CHIP_ID) | |
| 2505 | + dev->chip_id == KSZ9893_CHIP_ID || | |
| 2506 | + dev->chip_id == KSZ9563_CHIP_ID) | |
| 2393 | 2507 | proto = DSA_TAG_PROTO_KSZ9893; |
| 2394 | 2508 | |
| 2395 | 2509 | if (dev->chip_id == KSZ9477_CHIP_ID || |
| @@ -2473,10 +2587,29 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) · 77 unmodified lines | ||
| 2473 | 2587 | { |
| 2474 | 2588 | struct ksz_device *dev = ds->priv; |
| 2475 | 2589 | |
| 2476 | − if (!dev->dev_ops->max_mtu) | |
| 2477 | − return -EOPNOTSUPP; | |
| 2590 | + switch (dev->chip_id) { | |
| 2591 | + case KSZ8795_CHIP_ID: | |
| 2592 | + case KSZ8794_CHIP_ID: | |
| 2593 | + case KSZ8765_CHIP_ID: | |
| 2594 | + return KSZ8795_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; | |
| 2595 | + case KSZ8830_CHIP_ID: | |
| 2596 | + return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; | |
| 2597 | + case KSZ8563_CHIP_ID: | |
| 2598 | + case KSZ9477_CHIP_ID: | |
| 2599 | + case KSZ9563_CHIP_ID: | |
| 2600 | + case KSZ9567_CHIP_ID: | |
| 2601 | + case KSZ9893_CHIP_ID: | |
| 2602 | + case KSZ9896_CHIP_ID: | |
| 2603 | + case KSZ9897_CHIP_ID: | |
| 2604 | + case LAN9370_CHIP_ID: | |
| 2605 | + case LAN9371_CHIP_ID: | |
| 2606 | + case LAN9372_CHIP_ID: | |
| 2607 | + case LAN9373_CHIP_ID: | |
| 2608 | + case LAN9374_CHIP_ID: | |
| 2609 | + return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; | |
| 2610 | + } | |
| 2478 | 2611 | |
| 2479 | − return dev->dev_ops->max_mtu(dev, port); | |
| 2612 | + return -EOPNOTSUPP; | |
| 2480 | 2613 | } |
| 2481 | 2614 | |
| 2482 | 2615 | static void ksz_set_xmii(struct ksz_device *dev, int port, |
| @@ -2509,7 +2642,8 @@ static void ksz_set_xmii(struct ksz_device *dev, int port, · 26 unmodified lines | ||
| 2509 | 2642 | data8 |= bitval[P_RGMII_SEL]; |
| 2510 | 2643 | /* On KSZ9893, disable RGMII in-band status support */ |
| 2511 | 2644 | if (dev->chip_id == KSZ9893_CHIP_ID || |
| 2512 | − dev->chip_id == KSZ8563_CHIP_ID) | |
| 2645 | + dev->chip_id == KSZ8563_CHIP_ID || | |
| 2646 | + dev->chip_id == KSZ9563_CHIP_ID) | |
| 2513 | 2647 | data8 &= ~P_MII_MAC_MODE; |
| 2514 | 2648 | break; |
| 2515 | 2649 | default: |
| @@ -2782,6 +2916,8 @@ static int ksz_switch_detect(struct ksz_device *dev) · 266 unmodified lines | ||
| 2782 | 2916 | |
| 2783 | 2917 | if (id4 == SKU_ID_KSZ8563) |
| 2784 | 2918 | dev->chip_id = KSZ8563_CHIP_ID; |
| 2919 | + else if (id4 == SKU_ID_KSZ9563) | |
| 2920 | + dev->chip_id = KSZ9563_CHIP_ID; | |
| 2785 | 2921 | else |
| 2786 | 2922 | dev->chip_id = KSZ9893_CHIP_ID; |
| 2787 | 2923 | |
| @@ -95,7 +95,6 @@ struct ksz_port { · 94 unmodified lines | ||
| 95 | 95 | |
| 96 | 96 | struct ksz_port_mib mib; |
| 97 | 97 | phy_interface_t interface; |
| 98 | − u16 max_frame; | |
| 99 | 98 | u32 rgmii_tx_val; |
| 100 | 99 | u32 rgmii_rx_val; |
| 101 | 100 | struct ksz_device *ksz_dev; |
| @@ -154,6 +153,7 @@ enum ksz_model { · 52 unmodified lines | ||
| 154 | 153 | KSZ9896, |
| 155 | 154 | KSZ9897, |
| 156 | 155 | KSZ9893, |
| 156 | + KSZ9563, | |
| 157 | 157 | KSZ9567, |
| 158 | 158 | LAN9370, |
| 159 | 159 | LAN9371, |
| @@ -172,6 +172,7 @@ enum ksz_chip_id { · 12 unmodified lines | ||
| 172 | 172 | KSZ9896_CHIP_ID = 0x00989600, |
| 173 | 173 | KSZ9897_CHIP_ID = 0x00989700, |
| 174 | 174 | KSZ9893_CHIP_ID = 0x00989300, |
| 175 | + KSZ9563_CHIP_ID = 0x00956300, | |
| 175 | 176 | KSZ9567_CHIP_ID = 0x00956700, |
| 176 | 177 | LAN9370_CHIP_ID = 0x00937000, |
| 177 | 178 | LAN9371_CHIP_ID = 0x00937100, |
| @@ -320,7 +321,6 @@ struct ksz_dev_ops { · 142 unmodified lines | ||
| 320 | 321 | void (*get_caps)(struct ksz_device *dev, int port, |
| 321 | 322 | struct phylink_config *config); |
| 322 | 323 | int (*change_mtu)(struct ksz_device *dev, int port, int mtu); |
| 323 | − int (*max_mtu)(struct ksz_device *dev, int port); | |
| 324 | 324 | void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); |
| 325 | 325 | void (*port_init_cnt)(struct ksz_device *dev, int port); |
| 326 | 326 | void (*phylink_mac_config)(struct ksz_device *dev, int port, |
| @@ -345,6 +345,7 @@ void ksz_switch_remove(struct ksz_device *dev); · 18 unmodified lines | ||
| 345 | 345 | |
| 346 | 346 | void ksz_init_mib_timer(struct ksz_device *dev); |
| 347 | 347 | void ksz_r_mib_stats64(struct ksz_device *dev, int port); |
| 348 | +void ksz88xx_r_mib_stats64(struct ksz_device *dev, int port); | |
| 348 | 349 | void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); |
| 349 | 350 | bool ksz_get_gbit(struct ksz_device *dev, int port); |
| 350 | 351 | phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit); |
| @@ -454,6 +455,11 @@ static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) · 103 unmodified lines | ||
| 454 | 455 | return regmap_bulk_write(dev->regmap[2], reg, val, 2); |
| 455 | 456 | } |
| 456 | 457 | |
| 458 | +static inline int ksz_rmw8(struct ksz_device *dev, int offset, u8 mask, u8 val) | |
| 459 | +{ | |
| 460 | + return regmap_update_bits(dev->regmap[0], offset, mask, val); | |
| 461 | +} | |
| 462 | + | |
| 457 | 463 | static inline int ksz_pread8(struct ksz_device *dev, int port, int offset, |
| 458 | 464 | u8 *data) |
| 459 | 465 | { |
| @@ -551,6 +557,7 @@ static inline int is_lan937x(struct ksz_device *dev) · 91 unmodified lines | ||
| 551 | 557 | /* KSZ9893, KSZ9563, KSZ8563 specific register */ |
| 552 | 558 | #define REG_CHIP_ID4 0x0f |
| 553 | 559 | #define SKU_ID_KSZ8563 0x3c |
| 560 | +#define SKU_ID_KSZ9563 0x1c | |
| 554 | 561 | |
| 555 | 562 | /* Driver set switch broadcast storm protection at 10% rate. */ |
| 556 | 563 | #define BROADCAST_STORM_PROT_RATE 10 |
| @@ -585,6 +592,12 @@ static inline int is_lan937x(struct ksz_device *dev) · 28 unmodified lines | ||
| 585 | 592 | |
| 586 | 593 | #define PORT_SRC_PHY_INT 1 |
| 587 | 594 | |
| 595 | +#define KSZ8795_HUGE_PACKET_SIZE 2000 | |
| 596 | +#define KSZ8863_HUGE_PACKET_SIZE 1916 | |
| 597 | +#define KSZ8863_NORMAL_PACKET_SIZE 1536 | |
| 598 | +#define KSZ8_LEGAL_PACKET_SIZE 1518 | |
| 599 | +#define KSZ9477_MAX_FRAME_SIZE 9000 | |
| 600 | + | |
| 588 | 601 | /* Regmap tables generation */ |
| 589 | 602 | #define KSZ_SPI_OP_RD 3 |
| 590 | 603 | #define KSZ_SPI_OP_WR 2 |
| @@ -71,11 +71,9 @@ static int ksz_spi_probe(struct spi_device *spi) · 70 unmodified lines | ||
| 71 | 71 | dev->regmap[i] = devm_regmap_init_spi(spi, &rc); |
| 72 | 72 | |
| 73 | 73 | if (IS_ERR(dev->regmap[i])) { |
| 74 | − ret = PTR_ERR(dev->regmap[i]); | |
| 75 | − dev_err(&spi->dev, | |
| 76 | − "Failed to initialize regmap%i: %d\n", | |
| 77 | − regmap_config[i].val_bits, ret); | |
| 78 | − return ret; | |
| 74 | + return dev_err_probe(&spi->dev, PTR_ERR(dev->regmap[i]), | |
| 75 | + "Failed to initialize regmap%i\n", | |
| 76 | + regmap_config[i].val_bits); | |
| 79 | 77 | } |
| 80 | 78 | } |
| 81 | 79 | |
| @@ -163,7 +161,7 @@ static const struct of_device_id ksz_dt_ids[] = { · 81 unmodified lines | ||
| 163 | 161 | }, |
| 164 | 162 | { |
| 165 | 163 | .compatible = "microchip,ksz9563", |
| 166 | − .data = &ksz_switch_chips[KSZ9893] | |
| 164 | + .data = &ksz_switch_chips[KSZ9563] | |
| 167 | 165 | }, |
| 168 | 166 | { |
| 169 | 167 | .compatible = "microchip,ksz8563", |
| @@ -242,7 +242,11 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu) · 241 unmodified lines | ||
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | /* Write the frame size in PORT_MAX_FR_SIZE register */ |
| 245 | − ksz_pwrite16(dev, port, PORT_MAX_FR_SIZE, new_mtu); | |
| 245 | + ret = ksz_pwrite16(dev, port, PORT_MAX_FR_SIZE, new_mtu); | |
| 246 | + if (ret) { | |
| 247 | + dev_err(ds->dev, "failed to update mtu for port %d\n", port); | |
| 248 | + return ret; | |
| 249 | + } | |
| 246 | 250 | |
| 247 | 251 | return 0; |
| 248 | 252 | } |
| @@ -15,3 +15,7 @@ mv88e6xxx-objs += port_hidden.o · 14 unmodified lines | ||
| 15 | 15 | mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o |
| 16 | 16 | mv88e6xxx-objs += serdes.o |
| 17 | 17 | mv88e6xxx-objs += smi.o |
| 18 | +mv88e6xxx-objs += trace.o | |
| 19 | + | |
| 20 | +# for tracing framework to find trace.h | |
| 21 | +CFLAGS_trace.o := -I$(src) | |
| @@ -4077,6 +4077,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { · 4076 unmodified lines | ||
| 4077 | 4077 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 4078 | 4078 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 4079 | 4079 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 4080 | + .port_set_policy = mv88e6352_port_set_policy, | |
| 4080 | 4081 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 4081 | 4082 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 4082 | 4083 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, |
| @@ -4349,6 +4350,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { · 266 unmodified lines | ||
| 4349 | 4350 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 4350 | 4351 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 4351 | 4352 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 4353 | + .port_set_policy = mv88e6352_port_set_policy, | |
| 4352 | 4354 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 4353 | 4355 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 4354 | 4356 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, |
| @@ -5032,6 +5034,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { · 677 unmodified lines | ||
| 5032 | 5034 | .phy_write = mv88e6xxx_g2_smi_phy_write, |
| 5033 | 5035 | .port_set_link = mv88e6xxx_port_set_link, |
| 5034 | 5036 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 5037 | + .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, | |
| 5035 | 5038 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 5036 | 5039 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 5037 | 5040 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| @@ -5076,6 +5079,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { · 38 unmodified lines | ||
| 5076 | 5079 | .phy_write = mv88e6xxx_g2_smi_phy_write, |
| 5077 | 5080 | .port_set_link = mv88e6xxx_port_set_link, |
| 5078 | 5081 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 5082 | + .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, | |
| 5079 | 5083 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 5080 | 5084 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 5081 | 5085 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| @@ -821,11 +821,6 @@ int mv88e6xxx_devlink_info_get(struct dsa_switch *ds, · 820 unmodified lines | ||
| 821 | 821 | struct netlink_ext_ack *extack) |
| 822 | 822 | { |
| 823 | 823 | struct mv88e6xxx_chip *chip = ds->priv; |
| 824 | − int err; | |
| 825 | − | |
| 826 | − err = devlink_info_driver_name_put(req, "mv88e6xxx"); | |
| 827 | − if (err) | |
| 828 | − return err; | |
| 829 | 824 | |
| 830 | 825 | return devlink_info_version_fixed_put(req, |
| 831 | 826 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | #include "chip.h" |
| 14 | 14 | #include "global1.h" |
| 15 | +#include "trace.h" | |
| 15 | 16 | |
| 16 | 17 | /* Offset 0x01: ATU FID Register */ |
| 17 | 18 | |
| @@ -114,6 +115,19 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip) · 96 unmodified lines | ||
| 114 | 115 | return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0); |
| 115 | 116 | } |
| 116 | 117 | |
| 118 | +static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip) | |
| 119 | +{ | |
| 120 | + int err; | |
| 121 | + | |
| 122 | + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP, | |
| 123 | + MV88E6XXX_G1_ATU_OP_BUSY | | |
| 124 | + MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION); | |
| 125 | + if (err) | |
| 126 | + return err; | |
| 127 | + | |
| 128 | + return mv88e6xxx_g1_atu_op_wait(chip); | |
| 129 | +} | |
| 130 | + | |
| 117 | 131 | static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) |
| 118 | 132 | { |
| 119 | 133 | u16 val; |
| @@ -159,6 +173,41 @@ int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid) · 39 unmodified lines | ||
| 159 | 173 | return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); |
| 160 | 174 | } |
| 161 | 175 | |
| 176 | +static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid) | |
| 177 | +{ | |
| 178 | + u16 val = 0, upper = 0, op = 0; | |
| 179 | + int err = -EOPNOTSUPP; | |
| 180 | + | |
| 181 | + if (mv88e6xxx_num_databases(chip) > 256) { | |
| 182 | + err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val); | |
| 183 | + val &= 0xfff; | |
| 184 | + if (err) | |
| 185 | + return err; | |
| 186 | + } else { | |
| 187 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &op); | |
| 188 | + if (err) | |
| 189 | + return err; | |
| 190 | + if (mv88e6xxx_num_databases(chip) > 64) { | |
| 191 | + /* ATU DBNum[7:4] are located in ATU Control 15:12 */ | |
| 192 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, | |
| 193 | + &upper); | |
| 194 | + if (err) | |
| 195 | + return err; | |
| 196 | + | |
| 197 | + upper = (upper >> 8) & 0x00f0; | |
| 198 | + } else if (mv88e6xxx_num_databases(chip) > 16) { | |
| 199 | + /* ATU DBNum[5:4] are located in ATU Operation 9:8 */ | |
| 200 | + upper = (op >> 4) & 0x30; | |
| 201 | + } | |
| 202 | + | |
| 203 | + /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ | |
| 204 | + val = (op & 0xf) | upper; | |
| 205 | + } | |
| 206 | + *fid = val; | |
| 207 | + | |
| 208 | + return err; | |
| 209 | +} | |
| 210 | + | |
| 162 | 211 | /* Offset 0x0C: ATU Data Register */ |
| 163 | 212 | |
| 164 | 213 | static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, |
| @@ -353,14 +402,12 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) · 188 unmodified lines | ||
| 353 | 402 | { |
| 354 | 403 | struct mv88e6xxx_chip *chip = dev_id; |
| 355 | 404 | struct mv88e6xxx_atu_entry entry; |
| 356 | − int spid; | |
| 357 | − int err; | |
| 358 | − u16 val; | |
| 405 | + int err, spid; | |
| 406 | + u16 val, fid; | |
| 359 | 407 | |
| 360 | 408 | mv88e6xxx_reg_lock(chip); |
| 361 | 409 | |
| 362 | − err = mv88e6xxx_g1_atu_op(chip, 0, | |
| 363 | − MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION); | |
| 410 | + err = mv88e6xxx_g1_read_atu_violation(chip); | |
| 364 | 411 | if (err) |
| 365 | 412 | goto out; |
| 366 | 413 | |
| @@ -368,6 +415,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) · 1 unmodified line | ||
| 368 | 415 | if (err) |
| 369 | 416 | goto out; |
| 370 | 417 | |
| 418 | + err = mv88e6xxx_g1_atu_fid_read(chip, &fid); | |
| 419 | + if (err) | |
| 420 | + goto out; | |
| 421 | + | |
| 371 | 422 | err = mv88e6xxx_g1_atu_data_read(chip, &entry); |
| 372 | 423 | if (err) |
| 373 | 424 | goto out; |
| @@ -378,30 +429,24 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) · 4 unmodified lines | ||
| 378 | 429 | |
| 379 | 430 | spid = entry.state; |
| 380 | 431 | |
| 381 | − if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) { | |
| 382 | − dev_err_ratelimited(chip->dev, | |
| 383 | − "ATU age out violation for %pM\n", | |
| 384 | − entry.mac); | |
| 385 | − } | |
| 386 | − | |
| 387 | 432 | if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { |
| 388 | − dev_err_ratelimited(chip->dev, | |
| 389 | − "ATU member violation for %pM portvec %x spid %d\n", | |
| 390 | − entry.mac, entry.portvec, spid); | |
| 433 | + trace_mv88e6xxx_atu_member_violation(chip->dev, spid, | |
| 434 | + entry.portvec, entry.mac, | |
| 435 | + fid); | |
| 391 | 436 | chip->ports[spid].atu_member_violation++; |
| 392 | 437 | } |
| 393 | 438 | |
| 394 | 439 | if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { |
| 395 | − dev_err_ratelimited(chip->dev, | |
| 396 | − "ATU miss violation for %pM portvec %x spid %d\n", | |
| 397 | − entry.mac, entry.portvec, spid); | |
| 440 | + trace_mv88e6xxx_atu_miss_violation(chip->dev, spid, | |
| 441 | + entry.portvec, entry.mac, | |
| 442 | + fid); | |
| 398 | 443 | chip->ports[spid].atu_miss_violation++; |
| 399 | 444 | } |
| 400 | 445 | |
| 401 | 446 | if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { |
| 402 | − dev_err_ratelimited(chip->dev, | |
| 403 | − "ATU full violation for %pM portvec %x spid %d\n", | |
| 404 | − entry.mac, entry.portvec, spid); | |
| 447 | + trace_mv88e6xxx_atu_full_violation(chip->dev, spid, | |
| 448 | + entry.portvec, entry.mac, | |
| 449 | + fid); | |
| 405 | 450 | chip->ports[spid].atu_full_violation++; |
| 406 | 451 | } |
| 407 | 452 | mv88e6xxx_reg_unlock(chip); |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #include "chip.h" |
| 15 | 15 | #include "global1.h" |
| 16 | +#include "trace.h" | |
| 16 | 17 | |
| 17 | 18 | /* Offset 0x02: VTU FID Register */ |
| 18 | 19 | |
| @@ -628,14 +629,12 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) · 609 unmodified lines | ||
| 628 | 629 | spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK; |
| 629 | 630 | |
| 630 | 631 | if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) { |
| 631 | − dev_err_ratelimited(chip->dev, "VTU member violation for vid %d, source port %d\n", | |
| 632 | − vid, spid); | |
| 632 | + trace_mv88e6xxx_vtu_member_violation(chip->dev, spid, vid); | |
| 633 | 633 | chip->ports[spid].vtu_member_violation++; |
| 634 | 634 | } |
| 635 | 635 | |
| 636 | 636 | if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) { |
| 637 | − dev_dbg_ratelimited(chip->dev, "VTU miss violation for vid %d, source port %d\n", | |
| 638 | − vid, spid); | |
| 637 | + trace_mv88e6xxx_vtu_miss_violation(chip->dev, spid, vid); | |
| 639 | 638 | chip->ports[spid].vtu_miss_violation++; |
| 640 | 639 | } |
| 641 | 640 | |
| @@ -133,6 +133,15 @@ int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, · 132 unmodified lines | ||
| 133 | 133 | return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | +int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | |
| 137 | + phy_interface_t mode) | |
| 138 | +{ | |
| 139 | + if (port != 2 && port != 5 && port != 6) | |
| 140 | + return -EOPNOTSUPP; | |
| 141 | + | |
| 142 | + return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); | |
| 143 | +} | |
| 144 | + | |
| 136 | 145 | int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) |
| 137 | 146 | { |
| 138 | 147 | u16 reg; |
| @@ -332,6 +332,8 @@ int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg, · 331 unmodified lines | ||
| 332 | 332 | |
| 333 | 333 | int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, |
| 334 | 334 | int pause); |
| 335 | +int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | |
| 336 | + phy_interface_t mode); | |
| 335 | 337 | int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, |
| 336 | 338 | phy_interface_t mode); |
| 337 | 339 | int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, |
| @@ -0,0 +1,6 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +/* Copyright 2022 NXP | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#define CREATE_TRACE_POINTS | |
| 6 | +#include "trace.h" | |
| @@ -0,0 +1,96 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | +/* Copyright 2022 NXP | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#undef TRACE_SYSTEM | |
| 6 | +#define TRACE_SYSTEM mv88e6xxx | |
| 7 | + | |
| 8 | +#if !defined(_MV88E6XXX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) | |
| 9 | +#define _MV88E6XXX_TRACE_H | |
| 10 | + | |
| 11 | +#include <linux/device.h> | |
| 12 | +#include <linux/if_ether.h> | |
| 13 | +#include <linux/tracepoint.h> | |
| 14 | + | |
| 15 | +DECLARE_EVENT_CLASS(mv88e6xxx_atu_violation, | |
| 16 | + | |
| 17 | + TP_PROTO(const struct device *dev, int spid, u16 portvec, | |
| 18 | + const unsigned char *addr, u16 fid), | |
| 19 | + | |
| 20 | + TP_ARGS(dev, spid, portvec, addr, fid), | |
| 21 | + | |
| 22 | + TP_STRUCT__entry( | |
| 23 | + __string(name, dev_name(dev)) | |
| 24 | + __field(int, spid) | |
| 25 | + __field(u16, portvec) | |
| 26 | + __array(unsigned char, addr, ETH_ALEN) | |
| 27 | + __field(u16, fid) | |
| 28 | + ), | |
| 29 | + | |
| 30 | + TP_fast_assign( | |
| 31 | + __assign_str(name, dev_name(dev)); | |
| 32 | + __entry->spid = spid; | |
| 33 | + __entry->portvec = portvec; | |
| 34 | + memcpy(__entry->addr, addr, ETH_ALEN); | |
| 35 | + __entry->fid = fid; | |
| 36 | + ), | |
| 37 | + | |
| 38 | + TP_printk("dev %s spid %d portvec 0x%x addr %pM fid %u", | |
| 39 | + __get_str(name), __entry->spid, __entry->portvec, | |
| 40 | + __entry->addr, __entry->fid) | |
| 41 | +); | |
| 42 | + | |
| 43 | +DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_member_violation, | |
| 44 | + TP_PROTO(const struct device *dev, int spid, u16 portvec, | |
| 45 | + const unsigned char *addr, u16 fid), | |
| 46 | + TP_ARGS(dev, spid, portvec, addr, fid)); | |
| 47 | + | |
| 48 | +DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_miss_violation, | |
| 49 | + TP_PROTO(const struct device *dev, int spid, u16 portvec, | |
| 50 | + const unsigned char *addr, u16 fid), | |
| 51 | + TP_ARGS(dev, spid, portvec, addr, fid)); | |
| 52 | + | |
| 53 | +DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_full_violation, | |
| 54 | + TP_PROTO(const struct device *dev, int spid, u16 portvec, | |
| 55 | + const unsigned char *addr, u16 fid), | |
| 56 | + TP_ARGS(dev, spid, portvec, addr, fid)); | |
| 57 | + | |
| 58 | +DECLARE_EVENT_CLASS(mv88e6xxx_vtu_violation, | |
| 59 | + | |
| 60 | + TP_PROTO(const struct device *dev, int spid, u16 vid), | |
| 61 | + | |
| 62 | + TP_ARGS(dev, spid, vid), | |
| 63 | + | |
| 64 | + TP_STRUCT__entry( | |
| 65 | + __string(name, dev_name(dev)) | |
| 66 | + __field(int, spid) | |
| 67 | + __field(u16, vid) | |
| 68 | + ), | |
| 69 | + | |
| 70 | + TP_fast_assign( | |
| 71 | + __assign_str(name, dev_name(dev)); | |
| 72 | + __entry->spid = spid; | |
| 73 | + __entry->vid = vid; | |
| 74 | + ), | |
| 75 | + | |
| 76 | + TP_printk("dev %s spid %d vid %u", | |
| 77 | + __get_str(name), __entry->spid, __entry->vid) | |
| 78 | +); | |
| 79 | + | |
| 80 | +DEFINE_EVENT(mv88e6xxx_vtu_violation, mv88e6xxx_vtu_member_violation, | |
| 81 | + TP_PROTO(const struct device *dev, int spid, u16 vid), | |
| 82 | + TP_ARGS(dev, spid, vid)); | |
| 83 | + | |
| 84 | +DEFINE_EVENT(mv88e6xxx_vtu_violation, mv88e6xxx_vtu_miss_violation, | |
| 85 | + TP_PROTO(const struct device *dev, int spid, u16 vid), | |
| 86 | + TP_ARGS(dev, spid, vid)); | |
| 87 | + | |
| 88 | +#endif /* _MV88E6XXX_TRACE_H */ | |
| 89 | + | |
| 90 | +/* We don't want to use include/trace/events */ | |
| 91 | +#undef TRACE_INCLUDE_PATH | |
| 92 | +#define TRACE_INCLUDE_PATH . | |
| 93 | +#undef TRACE_INCLUDE_FILE | |
| 94 | +#define TRACE_INCLUDE_FILE trace | |
| 95 | +/* This part must be outside protection */ | |
| 96 | +#include <trace/define_trace.h> | |
| @@ -1048,21 +1048,14 @@ static void felix_phylink_get_caps(struct dsa_switch *ds, int port, · 1047 unmodified lines | ||
| 1048 | 1048 | */ |
| 1049 | 1049 | config->legacy_pre_march2020 = false; |
| 1050 | 1050 | |
| 1051 | + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | | |
| 1052 | + MAC_10 | MAC_100 | MAC_1000FD | | |
| 1053 | + MAC_2500FD; | |
| 1054 | + | |
| 1051 | 1055 | __set_bit(ocelot->ports[port]->phy_mode, |
| 1052 | 1056 | config->supported_interfaces); |
| 1053 | 1057 | } |
| 1054 | 1058 | |
| 1055 | −static void felix_phylink_validate(struct dsa_switch *ds, int port, | |
| 1056 | − unsigned long *supported, | |
| 1057 | − struct phylink_link_state *state) | |
| 1058 | −{ | |
| 1059 | − struct ocelot *ocelot = ds->priv; | |
| 1060 | − struct felix *felix = ocelot_to_felix(ocelot); | |
| 1061 | − | |
| 1062 | − if (felix->info->phylink_validate) | |
| 1063 | − felix->info->phylink_validate(ocelot, port, supported, state); | |
| 1064 | −} | |
| 1065 | − | |
| 1066 | 1059 | static struct phylink_pcs *felix_phylink_mac_select_pcs(struct dsa_switch *ds, |
| 1067 | 1060 | int port, |
| 1068 | 1061 | phy_interface_t iface) |
| @@ -1370,7 +1363,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) · 301 unmodified lines | ||
| 1370 | 1363 | return -ENOMEM; |
| 1371 | 1364 | |
| 1372 | 1365 | ocelot->map = felix->info->map; |
| 1373 | − ocelot->stats_layout = felix->info->stats_layout; | |
| 1374 | 1366 | ocelot->num_mact_rows = felix->info->num_mact_rows; |
| 1375 | 1367 | ocelot->vcap = felix->info->vcap; |
| 1376 | 1368 | ocelot->vcap_pol.base = felix->info->vcap_pol_base; |
| @@ -2050,7 +2042,6 @@ const struct dsa_switch_ops felix_switch_ops = { · 673 unmodified lines | ||
| 2050 | 2042 | .get_sset_count = felix_get_sset_count, |
| 2051 | 2043 | .get_ts_info = felix_get_ts_info, |
| 2052 | 2044 | .phylink_get_caps = felix_phylink_get_caps, |
| 2053 | − .phylink_validate = felix_phylink_validate, | |
| 2054 | 2045 | .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, |
| 2055 | 2046 | .phylink_mac_link_down = felix_phylink_mac_link_down, |
| 2056 | 2047 | .phylink_mac_link_up = felix_phylink_mac_link_up, |
| @@ -28,7 +28,6 @@ struct felix_info { · 27 unmodified lines | ||
| 28 | 28 | const struct ocelot_ops *ops; |
| 29 | 29 | const u32 *port_modes; |
| 30 | 30 | int num_mact_rows; |
| 31 | − const struct ocelot_stat_layout *stats_layout; | |
| 32 | 31 | int num_ports; |
| 33 | 32 | int num_tx_queues; |
| 34 | 33 | struct vcap_props *vcap; |
| @@ -52,9 +51,6 @@ struct felix_info { · 17 unmodified lines | ||
| 52 | 51 | |
| 53 | 52 | int (*mdio_bus_alloc)(struct ocelot *ocelot); |
| 54 | 53 | void (*mdio_bus_free)(struct ocelot *ocelot); |
| 55 | − void (*phylink_validate)(struct ocelot *ocelot, int port, | |
| 56 | − unsigned long *supported, | |
| 57 | − struct phylink_link_state *state); | |
| 58 | 54 | int (*port_setup_tc)(struct dsa_switch *ds, int port, |
| 59 | 55 | enum tc_setup_type type, void *type_data); |
| 60 | 56 | void (*tas_guard_bands_update)(struct ocelot *ocelot, int port); |
| @@ -565,10 +565,6 @@ static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { · 564 unmodified lines | ||
| 565 | 565 | [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4), |
| 566 | 566 | }; |
| 567 | 567 | |
| 568 | −static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = { | |
| 569 | − OCELOT_COMMON_STATS, | |
| 570 | −}; | |
| 571 | − | |
| 572 | 568 | static const struct vcap_field vsc9959_vcap_es0_keys[] = { |
| 573 | 569 | [VCAP_ES0_EGR_PORT] = { 0, 3}, |
| 574 | 570 | [VCAP_ES0_IGR_PORT] = { 3, 3}, |
| @@ -885,35 +881,6 @@ static int vsc9959_reset(struct ocelot *ocelot) · 310 unmodified lines | ||
| 885 | 881 | return 0; |
| 886 | 882 | } |
| 887 | 883 | |
| 888 | −static void vsc9959_phylink_validate(struct ocelot *ocelot, int port, | |
| 889 | − unsigned long *supported, | |
| 890 | − struct phylink_link_state *state) | |
| 891 | −{ | |
| 892 | − __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; | |
| 893 | − | |
| 894 | − phylink_set_port_modes(mask); | |
| 895 | − phylink_set(mask, Autoneg); | |
| 896 | − phylink_set(mask, Pause); | |
| 897 | − phylink_set(mask, Asym_Pause); | |
| 898 | − phylink_set(mask, 10baseT_Half); | |
| 899 | − phylink_set(mask, 10baseT_Full); | |
| 900 | − phylink_set(mask, 100baseT_Half); | |
| 901 | − phylink_set(mask, 100baseT_Full); | |
| 902 | − phylink_set(mask, 1000baseT_Half); | |
| 903 | − phylink_set(mask, 1000baseT_Full); | |
| 904 | − phylink_set(mask, 1000baseX_Full); | |
| 905 | − | |
| 906 | − if (state->interface == PHY_INTERFACE_MODE_INTERNAL || | |
| 907 | − state->interface == PHY_INTERFACE_MODE_2500BASEX || | |
| 908 | − state->interface == PHY_INTERFACE_MODE_USXGMII) { | |
| 909 | − phylink_set(mask, 2500baseT_Full); | |
| 910 | − phylink_set(mask, 2500baseX_Full); | |
| 911 | − } | |
| 912 | − | |
| 913 | − linkmode_and(supported, supported, mask); | |
| 914 | − linkmode_and(state->advertising, state->advertising, mask); | |
| 915 | −} | |
| 916 | − | |
| 917 | 884 | /* Watermark encode |
| 918 | 885 | * Bit 8: Unit; 0:1, 1:16 |
| 919 | 886 | * Bit 7-0: Value to be multiplied with unit |
| @@ -2575,7 +2542,6 @@ static const struct felix_info felix_info_vsc9959 = { · 1655 unmodified lines | ||
| 2575 | 2542 | .regfields = vsc9959_regfields, |
| 2576 | 2543 | .map = vsc9959_regmap, |
| 2577 | 2544 | .ops = &vsc9959_ops, |
| 2578 | − .stats_layout = vsc9959_stats_layout, | |
| 2579 | 2545 | .vcap = vsc9959_vcap_props, |
| 2580 | 2546 | .vcap_pol_base = VSC9959_VCAP_POLICER_BASE, |
| 2581 | 2547 | .vcap_pol_max = VSC9959_VCAP_POLICER_MAX, |
| @@ -2588,7 +2554,6 @@ static const struct felix_info felix_info_vsc9959 = { · 6 unmodified lines | ||
| 2588 | 2554 | .ptp_caps = &vsc9959_ptp_caps, |
| 2589 | 2555 | .mdio_bus_alloc = vsc9959_mdio_bus_alloc, |
| 2590 | 2556 | .mdio_bus_free = vsc9959_mdio_bus_free, |
| 2591 | − .phylink_validate = vsc9959_phylink_validate, | |
| 2592 | 2557 | .port_modes = vsc9959_port_modes, |
| 2593 | 2558 | .port_setup_tc = vsc9959_port_setup_tc, |
| 2594 | 2559 | .port_sched_speed_set = vsc9959_sched_speed_set, |
| @@ -543,10 +543,6 @@ static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = { · 542 unmodified lines | ||
| 543 | 543 | [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 11, 4), |
| 544 | 544 | }; |
| 545 | 545 | |
| 546 | −static const struct ocelot_stat_layout vsc9953_stats_layout[OCELOT_NUM_STATS] = { | |
| 547 | − OCELOT_COMMON_STATS, | |
| 548 | −}; | |
| 549 | − | |
| 550 | 546 | static const struct vcap_field vsc9953_vcap_es0_keys[] = { |
| 551 | 547 | [VCAP_ES0_EGR_PORT] = { 0, 4}, |
| 552 | 548 | [VCAP_ES0_IGR_PORT] = { 4, 4}, |
| @@ -840,32 +836,6 @@ static int vsc9953_reset(struct ocelot *ocelot) · 287 unmodified lines | ||
| 840 | 836 | return 0; |
| 841 | 837 | } |
| 842 | 838 | |
| 843 | −static void vsc9953_phylink_validate(struct ocelot *ocelot, int port, | |
| 844 | − unsigned long *supported, | |
| 845 | − struct phylink_link_state *state) | |
| 846 | −{ | |
| 847 | − __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; | |
| 848 | − | |
| 849 | − phylink_set_port_modes(mask); | |
| 850 | − phylink_set(mask, Autoneg); | |
| 851 | − phylink_set(mask, Pause); | |
| 852 | − phylink_set(mask, Asym_Pause); | |
| 853 | − phylink_set(mask, 10baseT_Full); | |
| 854 | − phylink_set(mask, 10baseT_Half); | |
| 855 | − phylink_set(mask, 100baseT_Full); | |
| 856 | − phylink_set(mask, 100baseT_Half); | |
| 857 | − phylink_set(mask, 1000baseT_Full); | |
| 858 | − phylink_set(mask, 1000baseX_Full); | |
| 859 | − | |
| 860 | − if (state->interface == PHY_INTERFACE_MODE_INTERNAL) { | |
| 861 | − phylink_set(mask, 2500baseT_Full); | |
| 862 | − phylink_set(mask, 2500baseX_Full); | |
| 863 | − } | |
| 864 | − | |
| 865 | − linkmode_and(supported, supported, mask); | |
| 866 | − linkmode_and(state->advertising, state->advertising, mask); | |
| 867 | −} | |
| 868 | − | |
| 869 | 839 | /* Watermark encode |
| 870 | 840 | * Bit 9: Unit; 0:1, 1:16 |
| 871 | 841 | * Bit 8-0: Value to be multiplied with unit |
| @@ -996,7 +966,6 @@ static const struct felix_info seville_info_vsc9953 = { · 124 unmodified lines | ||
| 996 | 966 | .regfields = vsc9953_regfields, |
| 997 | 967 | .map = vsc9953_regmap, |
| 998 | 968 | .ops = &vsc9953_ops, |
| 999 | − .stats_layout = vsc9953_stats_layout, | |
| 1000 | 969 | .vcap = vsc9953_vcap_props, |
| 1001 | 970 | .vcap_pol_base = VSC9953_VCAP_POLICER_BASE, |
| 1002 | 971 | .vcap_pol_max = VSC9953_VCAP_POLICER_MAX, |
| @@ -1007,7 +976,6 @@ static const struct felix_info seville_info_vsc9953 = { · 4 unmodified lines | ||
| 1007 | 976 | .num_tx_queues = OCELOT_NUM_TC, |
| 1008 | 977 | .mdio_bus_alloc = vsc9953_mdio_bus_alloc, |
| 1009 | 978 | .mdio_bus_free = vsc9953_mdio_bus_free, |
| 1010 | − .phylink_validate = vsc9953_phylink_validate, | |
| 1011 | 979 | .port_modes = vsc9953_port_modes, |
| 1012 | 980 | }; |
| 1013 | 981 | |
| @@ -122,16 +122,10 @@ int sja1105_devlink_info_get(struct dsa_switch *ds, · 121 unmodified lines | ||
| 122 | 122 | struct netlink_ext_ack *extack) |
| 123 | 123 | { |
| 124 | 124 | struct sja1105_private *priv = ds->priv; |
| 125 | − int rc; | |
| 126 | − | |
| 127 | − rc = devlink_info_driver_name_put(req, "sja1105"); | |
| 128 | − if (rc) | |
| 129 | − return rc; | |
| 130 | 125 | |
| 131 | − rc = devlink_info_version_fixed_put(req, | |
| 132 | − DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, | |
| 133 | − priv->info->name); | |
| 134 | − return rc; | |
| 126 | + return devlink_info_version_fixed_put(req, | |
| 127 | + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, | |
| 128 | + priv->info->name); | |
| 135 | 129 | } |
| 136 | 130 | |
| 137 | 131 | int sja1105_devlink_setup(struct dsa_switch *ds) |
| @@ -76,8 +76,7 @@ static const struct regmap_config xrs700x_i2c_regmap_config = { · 75 unmodified lines | ||
| 76 | 76 | .val_format_endian = REGMAP_ENDIAN_BIG |
| 77 | 77 | }; |
| 78 | 78 | |
| 79 | −static int xrs700x_i2c_probe(struct i2c_client *i2c, | |
| 80 | − const struct i2c_device_id *i2c_id) | |
| 79 | +static int xrs700x_i2c_probe(struct i2c_client *i2c) | |
| 81 | 80 | { |
| 82 | 81 | struct xrs700x *priv; |
| 83 | 82 | int ret; |
| @@ -148,7 +147,7 @@ static struct i2c_driver xrs700x_i2c_driver = { · 64 unmodified lines | ||
| 148 | 147 | .name = "xrs700x-i2c", |
| 149 | 148 | .of_match_table = of_match_ptr(xrs700x_i2c_dt_ids), |
| 150 | 149 | }, |
| 151 | − .probe = xrs700x_i2c_probe, | |
| 150 | + .probe_new = xrs700x_i2c_probe, | |
| 152 | 151 | .remove = xrs700x_i2c_remove, |
| 153 | 152 | .shutdown = xrs700x_i2c_shutdown, |
| 154 | 153 | .id_table = xrs700x_i2c_id, |
| @@ -99,14 +99,7 @@ static const struct net_device_ops dummy_netdev_ops = { · 98 unmodified lines | ||
| 99 | 99 | .ndo_change_carrier = dummy_change_carrier, |
| 100 | 100 | }; |
| 101 | 101 | |
| 102 | −static void dummy_get_drvinfo(struct net_device *dev, | |
| 103 | − struct ethtool_drvinfo *info) | |
| 104 | −{ | |
| 105 | − strscpy(info->driver, DRV_NAME, sizeof(info->driver)); | |
| 106 | −} | |
| 107 | − | |
| 108 | 102 | static const struct ethtool_ops dummy_ethtool_ops = { |
| 109 | − .get_drvinfo = dummy_get_drvinfo, | |
| 110 | 103 | .get_ts_info = ethtool_op_get_ts_info, |
| 111 | 104 | }; |
| 112 | 105 | |
| @@ -132,16 +132,6 @@ source "drivers/net/ethernet/mscc/Kconfig" · 131 unmodified lines | ||
| 132 | 132 | source "drivers/net/ethernet/microsoft/Kconfig" |
| 133 | 133 | source "drivers/net/ethernet/moxa/Kconfig" |
| 134 | 134 | source "drivers/net/ethernet/myricom/Kconfig" |
| 135 | − | |
| 136 | −config FEALNX | |
| 137 | − tristate "Myson MTD-8xx PCI Ethernet support" | |
| 138 | − depends on PCI | |
| 139 | − select CRC32 | |
| 140 | − select MII | |
| 141 | − help | |
| 142 | − Say Y here to support the Myson MTD-800 family of PCI-based Ethernet | |
| 143 | − cards. <http://www.myson.com.tw/> | |
| 144 | − | |
| 145 | 135 | source "drivers/net/ethernet/ni/Kconfig" |
| 146 | 136 | source "drivers/net/ethernet/natsemi/Kconfig" |
| 147 | 137 | source "drivers/net/ethernet/neterion/Kconfig" |
| @@ -64,7 +64,6 @@ obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/ · 63 unmodified lines | ||
| 64 | 64 | obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/ |
| 65 | 65 | obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/ |
| 66 | 66 | obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/ |
| 67 | −obj-$(CONFIG_FEALNX) += fealnx.o | |
| 68 | 67 | obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/ |
| 69 | 68 | obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/ |
| 70 | 69 | obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/ |
| @@ -196,7 +196,7 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val) · 195 unmodified lines | ||
| 196 | 196 | { |
| 197 | 197 | u32 header_len = ADIN1110_RD_HEADER_LEN; |
| 198 | 198 | u32 read_len = ADIN1110_REG_LEN; |
| 199 | − struct spi_transfer t[2] = {0}; | |
| 199 | + struct spi_transfer t = {0}; | |
| 200 | 200 | int ret; |
| 201 | 201 | |
| 202 | 202 | priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); |
| @@ -209,17 +209,15 @@ static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val) · 6 unmodified lines | ||
| 209 | 209 | header_len++; |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | − t[0].tx_buf = &priv->data[0]; | |
| 213 | − t[0].len = header_len; | |
| 214 | − | |
| 215 | 212 | if (priv->append_crc) |
| 216 | 213 | read_len++; |
| 217 | 214 | |
| 218 | 215 | memset(&priv->data[header_len], 0, read_len); |
| 219 | − t[1].rx_buf = &priv->data[header_len]; | |
| 220 | − t[1].len = read_len; | |
| 216 | + t.tx_buf = &priv->data[0]; | |
| 217 | + t.rx_buf = &priv->data[0]; | |
| 218 | + t.len = read_len + header_len; | |
| 221 | 219 | |
| 222 | − ret = spi_sync_transfer(priv->spidev, t, 2); | |
| 220 | + ret = spi_sync_transfer(priv->spidev, &t, 1); | |
| 223 | 221 | if (ret) |
| 224 | 222 | return ret; |
| 225 | 223 | |
| @@ -296,7 +294,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) · 70 unmodified lines | ||
| 296 | 294 | { |
| 297 | 295 | struct adin1110_priv *priv = port_priv->priv; |
| 298 | 296 | u32 header_len = ADIN1110_RD_HEADER_LEN; |
| 299 | − struct spi_transfer t[2] = {0}; | |
| 297 | + struct spi_transfer t; | |
| 300 | 298 | u32 frame_size_no_fcs; |
| 301 | 299 | struct sk_buff *rxb; |
| 302 | 300 | u32 frame_size; |
| @@ -327,12 +325,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) · 24 unmodified lines | ||
| 327 | 325 | return ret; |
| 328 | 326 | |
| 329 | 327 | frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; |
| 330 | − | |
| 331 | − rxb = netdev_alloc_skb(port_priv->netdev, round_len); | |
| 332 | − if (!rxb) | |
| 333 | − return -ENOMEM; | |
| 334 | − | |
| 335 | − memset(priv->data, 0, round_len + ADIN1110_RD_HEADER_LEN); | |
| 328 | + memset(priv->data, 0, ADIN1110_RD_HEADER_LEN); | |
| 336 | 329 | |
| 337 | 330 | priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); |
| 338 | 331 | priv->data[1] = FIELD_GET(GENMASK(7, 0), reg); |
| @@ -342,21 +335,23 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) · 3 unmodified lines | ||
| 342 | 335 | header_len++; |
| 343 | 336 | } |
| 344 | 337 | |
| 345 | − skb_put(rxb, frame_size_no_fcs + ADIN1110_FRAME_HEADER_LEN); | |
| 338 | + rxb = netdev_alloc_skb(port_priv->netdev, round_len + header_len); | |
| 339 | + if (!rxb) | |
| 340 | + return -ENOMEM; | |
| 346 | 341 | |
| 347 | − t[0].tx_buf = &priv->data[0]; | |
| 348 | − t[0].len = header_len; | |
| 342 | + skb_put(rxb, frame_size_no_fcs + header_len + ADIN1110_FRAME_HEADER_LEN); | |
| 349 | 343 | |
| 350 | − t[1].rx_buf = &rxb->data[0]; | |
| 351 | − t[1].len = round_len; | |
| 344 | + t.tx_buf = &priv->data[0]; | |
| 345 | + t.rx_buf = &rxb->data[0]; | |
| 346 | + t.len = header_len + round_len; | |
| 352 | 347 | |
| 353 | − ret = spi_sync_transfer(priv->spidev, t, 2); | |
| 348 | + ret = spi_sync_transfer(priv->spidev, &t, 1); | |
| 354 | 349 | if (ret) { |
| 355 | 350 | kfree_skb(rxb); |
| 356 | 351 | return ret; |
| 357 | 352 | } |
| 358 | 353 | |
| 359 | − skb_pull(rxb, ADIN1110_FRAME_HEADER_LEN); | |
| 354 | + skb_pull(rxb, header_len + ADIN1110_FRAME_HEADER_LEN); | |
| 360 | 355 | rxb->protocol = eth_type_trans(rxb, port_priv->netdev); |
| 361 | 356 | |
| 362 | 357 | if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) || |
| @@ -1087,9 +1082,30 @@ static void adin1110_adjust_link(struct net_device *dev) · 724 unmodified lines | ||
| 1087 | 1082 | */ |
| 1088 | 1083 | static int adin1110_check_spi(struct adin1110_priv *priv) |
| 1089 | 1084 | { |
| 1085 | + struct gpio_desc *reset_gpio; | |
| 1090 | 1086 | int ret; |
| 1091 | 1087 | u32 val; |
| 1092 | 1088 | |
| 1089 | + reset_gpio = devm_gpiod_get_optional(&priv->spidev->dev, "reset", | |
| 1090 | + GPIOD_OUT_LOW); | |
| 1091 | + if (reset_gpio) { | |
| 1092 | + /* MISO pin is used for internal configuration, can't have | |
| 1093 | + * anyone else disturbing the SDO line. | |
| 1094 | + */ | |
| 1095 | + spi_bus_lock(priv->spidev->controller); | |
| 1096 | + | |
| 1097 | + gpiod_set_value(reset_gpio, 1); | |
| 1098 | + fsleep(10000); | |
| 1099 | + gpiod_set_value(reset_gpio, 0); | |
| 1100 | + | |
| 1101 | + /* Need to wait 90 ms before interacting with | |
| 1102 | + * the MAC after a HW reset. | |
| 1103 | + */ | |
| 1104 | + fsleep(90000); | |
| 1105 | + | |
| 1106 | + spi_bus_unlock(priv->spidev->controller); | |
| 1107 | + } | |
| 1108 | + | |
| 1093 | 1109 | ret = adin1110_read_reg(priv, ADIN1110_PHY_ID, &val); |
| 1094 | 1110 | if (ret < 0) |
| 1095 | 1111 | return ret; |
| @@ -288,13 +288,13 @@ do { \ · 287 unmodified lines | ||
| 288 | 288 | u64_stats_update_end(&(st)->syncp); \ |
| 289 | 289 | } while (0) |
| 290 | 290 | |
| 291 | −#define SLIC_GET_STATS_COUNTER(newst, st, counter) \ | |
| 292 | −{ \ | |
| 293 | − unsigned int start; \ | |
| 291 | +#define SLIC_GET_STATS_COUNTER(newst, st, counter) \ | |
| 292 | +{ \ | |
| 293 | + unsigned int start; \ | |
| 294 | 294 | do { \ |
| 295 | − start = u64_stats_fetch_begin_irq(&(st)->syncp); \ | |
| 296 | − newst = (st)->counter; \ | |
| 297 | − } while (u64_stats_fetch_retry_irq(&(st)->syncp, start)); \ | |
| 295 | + start = u64_stats_fetch_begin(&(st)->syncp); \ | |
| 296 | + newst = (st)->counter; \ | |
| 297 | + } while (u64_stats_fetch_retry(&(st)->syncp, start)); \ | |
| 298 | 298 | } |
| 299 | 299 | |
| 300 | 300 | struct slic_upr { |
| @@ -1096,7 +1096,6 @@ static struct phylink_pcs *alt_tse_select_pcs(struct phylink_config *config, · 1095 unmodified lines | ||
| 1096 | 1096 | } |
| 1097 | 1097 | |
| 1098 | 1098 | static const struct phylink_mac_ops alt_tse_phylink_ops = { |
| 1099 | − .validate = phylink_generic_validate, | |
| 1100 | 1099 | .mac_an_restart = alt_tse_mac_an_restart, |
| 1101 | 1100 | .mac_config = alt_tse_mac_config, |
| 1102 | 1101 | .mac_link_down = alt_tse_mac_link_down, |
| @@ -118,9 +118,9 @@ static void ena_safe_update_stat(u64 *src, u64 *dst, · 117 unmodified lines | ||
| 118 | 118 | unsigned int start; |
| 119 | 119 | |
| 120 | 120 | do { |
| 121 | − start = u64_stats_fetch_begin_irq(syncp); | |
| 121 | + start = u64_stats_fetch_begin(syncp); | |
| 122 | 122 | *(dst) = *src; |
| 123 | − } while (u64_stats_fetch_retry_irq(syncp, start)); | |
| 123 | + } while (u64_stats_fetch_retry(syncp, start)); | |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | 126 | static void ena_queue_stats(struct ena_adapter *adapter, u64 **data) |
| @@ -3268,10 +3268,10 @@ static void ena_get_stats64(struct net_device *netdev, · 3267 unmodified lines | ||
| 3268 | 3268 | tx_ring = &adapter->tx_ring[i]; |
| 3269 | 3269 | |
| 3270 | 3270 | do { |
| 3271 | − start = u64_stats_fetch_begin_irq(&tx_ring->syncp); | |
| 3271 | + start = u64_stats_fetch_begin(&tx_ring->syncp); | |
| 3272 | 3272 | packets = tx_ring->tx_stats.cnt; |
| 3273 | 3273 | bytes = tx_ring->tx_stats.bytes; |
| 3274 | − } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); | |
| 3274 | + } while (u64_stats_fetch_retry(&tx_ring->syncp, start)); | |
| 3275 | 3275 | |
| 3276 | 3276 | stats->tx_packets += packets; |
| 3277 | 3277 | stats->tx_bytes += bytes; |
| @@ -3279,20 +3279,20 @@ static void ena_get_stats64(struct net_device *netdev, · 1 unmodified line | ||
| 3279 | 3279 | rx_ring = &adapter->rx_ring[i]; |
| 3280 | 3280 | |
| 3281 | 3281 | do { |
| 3282 | − start = u64_stats_fetch_begin_irq(&rx_ring->syncp); | |
| 3282 | + start = u64_stats_fetch_begin(&rx_ring->syncp); | |
| 3283 | 3283 | packets = rx_ring->rx_stats.cnt; |
| 3284 | 3284 | bytes = rx_ring->rx_stats.bytes; |
| 3285 | − } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); | |
| 3285 | + } while (u64_stats_fetch_retry(&rx_ring->syncp, start)); | |
| 3286 | 3286 | |
| 3287 | 3287 | stats->rx_packets += packets; |
| 3288 | 3288 | stats->rx_bytes += bytes; |
| 3289 | 3289 | } |
| 3290 | 3290 | |
| 3291 | 3291 | do { |
| 3292 | − start = u64_stats_fetch_begin_irq(&adapter->syncp); | |
| 3292 | + start = u64_stats_fetch_begin(&adapter->syncp); | |
| 3293 | 3293 | rx_drops = adapter->dev_stats.rx_drops; |
| 3294 | 3294 | tx_drops = adapter->dev_stats.tx_drops; |
| 3295 | − } while (u64_stats_fetch_retry_irq(&adapter->syncp, start)); | |
| 3295 | + } while (u64_stats_fetch_retry(&adapter->syncp, start)); | |
| 3296 | 3296 | |
| 3297 | 3297 | stats->rx_dropped = rx_drops; |
| 3298 | 3298 | stats->tx_dropped = tx_drops; |
| @@ -824,7 +824,7 @@ lance_start_xmit(struct sk_buff *skb, struct net_device *dev) · 823 unmodified lines | ||
| 824 | 824 | lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); |
| 825 | 825 | head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; |
| 826 | 826 | dev->stats.tx_bytes += skb->len; |
| 827 | − dev_kfree_skb( skb ); | |
| 827 | + dev_consume_skb_irq(skb); | |
| 828 | 828 | lp->cur_tx++; |
| 829 | 829 | while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { |
| 830 | 830 | lp->cur_tx -= TX_RING_SIZE; |
| @@ -1001,7 +1001,7 @@ static netdev_tx_t lance_start_xmit(struct sk_buff *skb, · 1000 unmodified lines | ||
| 1001 | 1001 | skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len); |
| 1002 | 1002 | lp->tx_ring[entry].base = |
| 1003 | 1003 | ((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000; |
| 1004 | − dev_kfree_skb(skb); | |
| 1004 | + dev_consume_skb_irq(skb); | |
| 1005 | 1005 | } else { |
| 1006 | 1006 | lp->tx_skbuff[entry] = skb; |
| 1007 | 1007 | lp->tx_ring[entry].base = ((u32)isa_virt_to_bus(skb->data) & 0xffffff) | 0x83000000; |
| @@ -189,6 +189,7 @@ enum xgbe_sfp_cable { · 188 unmodified lines | ||
| 189 | 189 | XGBE_SFP_CABLE_UNKNOWN = 0, |
| 190 | 190 | XGBE_SFP_CABLE_ACTIVE, |
| 191 | 191 | XGBE_SFP_CABLE_PASSIVE, |
| 192 | + XGBE_SFP_CABLE_FIBER, | |
| 192 | 193 | }; |
| 193 | 194 | |
| 194 | 195 | enum xgbe_sfp_base { |
| @@ -236,10 +237,7 @@ enum xgbe_sfp_speed { · 41 unmodified lines | ||
| 236 | 237 | |
| 237 | 238 | #define XGBE_SFP_BASE_BR 12 |
| 238 | 239 | #define XGBE_SFP_BASE_BR_1GBE_MIN 0x0a |
| 239 | −#define XGBE_SFP_BASE_BR_1GBE_MAX 0x0d | |
| 240 | 240 | #define XGBE_SFP_BASE_BR_10GBE_MIN 0x64 |
| 241 | −#define XGBE_SFP_BASE_BR_10GBE_MAX 0x68 | |
| 242 | −#define XGBE_MOLEX_SFP_BASE_BR_10GBE_MAX 0x78 | |
| 243 | 241 | |
| 244 | 242 | #define XGBE_SFP_BASE_CU_CABLE_LEN 18 |
| 245 | 243 | |
| @@ -826,29 +824,22 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) · 580 unmodified lines | ||
| 826 | 824 | static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, |
| 827 | 825 | enum xgbe_sfp_speed sfp_speed) |
| 828 | 826 | { |
| 829 | − u8 *sfp_base, min, max; | |
| 827 | + u8 *sfp_base, min; | |
| 830 | 828 | |
| 831 | 829 | sfp_base = sfp_eeprom->base; |
| 832 | 830 | |
| 833 | 831 | switch (sfp_speed) { |
| 834 | 832 | case XGBE_SFP_SPEED_1000: |
| 835 | 833 | min = XGBE_SFP_BASE_BR_1GBE_MIN; |
| 836 | − max = XGBE_SFP_BASE_BR_1GBE_MAX; | |
| 837 | 834 | break; |
| 838 | 835 | case XGBE_SFP_SPEED_10000: |
| 839 | 836 | min = XGBE_SFP_BASE_BR_10GBE_MIN; |
| 840 | − if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], | |
| 841 | − XGBE_MOLEX_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN) == 0) | |
| 842 | − max = XGBE_MOLEX_SFP_BASE_BR_10GBE_MAX; | |
| 843 | − else | |
| 844 | − max = XGBE_SFP_BASE_BR_10GBE_MAX; | |
| 845 | 837 | break; |
| 846 | 838 | default: |
| 847 | 839 | return false; |
| 848 | 840 | } |
| 849 | 841 | |
| 850 | − return ((sfp_base[XGBE_SFP_BASE_BR] >= min) && | |
| 851 | − (sfp_base[XGBE_SFP_BASE_BR] <= max)); | |
| 842 | + return sfp_base[XGBE_SFP_BASE_BR] >= min; | |
| 852 | 843 | } |
| 853 | 844 | |
| 854 | 845 | static void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) |
| @@ -1149,16 +1140,18 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) · 294 unmodified lines | ||
| 1149 | 1140 | phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data); |
| 1150 | 1141 | phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data); |
| 1151 | 1142 | |
| 1152 | − /* Assume ACTIVE cable unless told it is PASSIVE */ | |
| 1143 | + /* Assume FIBER cable unless told otherwise */ | |
| 1153 | 1144 | if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) { |
| 1154 | 1145 | phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE; |
| 1155 | 1146 | phy_data->sfp_cable_len = sfp_base[XGBE_SFP_BASE_CU_CABLE_LEN]; |
| 1156 | − } else { | |
| 1147 | + } else if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_ACTIVE) { | |
| 1157 | 1148 | phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE; |
| 1149 | + } else { | |
| 1150 | + phy_data->sfp_cable = XGBE_SFP_CABLE_FIBER; | |
| 1158 | 1151 | } |
| 1159 | 1152 | |
| 1160 | 1153 | /* Determine the type of SFP */ |
| 1161 | − if (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE && | |
| 1154 | + if (phy_data->sfp_cable != XGBE_SFP_CABLE_FIBER && | |
| 1162 | 1155 | xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) |
| 1163 | 1156 | phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; |
| 1164 | 1157 | else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) |
| @@ -134,27 +134,15 @@ static u64 xgbe_cc_read(const struct cyclecounter *cc) · 133 unmodified lines | ||
| 134 | 134 | return nsec; |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | −static int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta) | |
| 137 | +static int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm) | |
| 138 | 138 | { |
| 139 | 139 | struct xgbe_prv_data *pdata = container_of(info, |
| 140 | 140 | struct xgbe_prv_data, |
| 141 | 141 | ptp_clock_info); |
| 142 | 142 | unsigned long flags; |
| 143 | − u64 adjust; | |
| 144 | − u32 addend, diff; | |
| 145 | − unsigned int neg_adjust = 0; | |
| 143 | + u64 addend; | |
| 146 | 144 | |
| 147 | − if (delta < 0) { | |
| 148 | − neg_adjust = 1; | |
| 149 | − delta = -delta; | |
| 150 | − } | |
| 151 | − | |
| 152 | − adjust = pdata->tstamp_addend; | |
| 153 | − adjust *= delta; | |
| 154 | − diff = div_u64(adjust, 1000000000UL); | |
| 155 | − | |
| 156 | − addend = (neg_adjust) ? pdata->tstamp_addend - diff : | |
| 157 | − pdata->tstamp_addend + diff; | |
| 145 | + addend = adjust_by_scaled_ppm(pdata->tstamp_addend, scaled_ppm); | |
| 158 | 146 | |
| 159 | 147 | spin_lock_irqsave(&pdata->tstamp_lock, flags); |
| 160 | 148 | |
| @@ -235,7 +223,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) · 74 unmodified lines | ||
| 235 | 223 | netdev_name(pdata->netdev)); |
| 236 | 224 | info->owner = THIS_MODULE; |
| 237 | 225 | info->max_adj = pdata->ptpclk_rate; |
| 238 | − info->adjfreq = xgbe_adjfreq; | |
| 226 | + info->adjfine = xgbe_adjfine; | |
| 239 | 227 | info->adjtime = xgbe_adjtime; |
| 240 | 228 | info->gettime64 = xgbe_gettime; |
| 241 | 229 | info->settime64 = xgbe_settime; |
| @@ -1510,7 +1510,7 @@ static void bmac_tx_timeout(struct timer_list *t) · 1509 unmodified lines | ||
| 1510 | 1510 | i = bp->tx_empty; |
| 1511 | 1511 | ++dev->stats.tx_errors; |
| 1512 | 1512 | if (i != bp->tx_fill) { |
| 1513 | − dev_kfree_skb(bp->tx_bufs[i]); | |
| 1513 | + dev_kfree_skb_irq(bp->tx_bufs[i]); | |
| 1514 | 1514 | bp->tx_bufs[i] = NULL; |
| 1515 | 1515 | if (++i >= N_TX_RING) i = 0; |
| 1516 | 1516 | bp->tx_empty = i; |
| @@ -846,7 +846,7 @@ static void mace_tx_timeout(struct timer_list *t) · 845 unmodified lines | ||
| 846 | 846 | if (mp->tx_bad_runt) { |
| 847 | 847 | mp->tx_bad_runt = 0; |
| 848 | 848 | } else if (i != mp->tx_fill) { |
| 849 | − dev_kfree_skb(mp->tx_bufs[i]); | |
| 849 | + dev_kfree_skb_irq(mp->tx_bufs[i]); | |
| 850 | 850 | if (++i >= N_TX_RING) |
| 851 | 851 | i = 0; |
| 852 | 852 | mp->tx_empty = i; |
| @@ -934,7 +934,7 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data) · 933 unmodified lines | ||
| 934 | 934 | /* This data should mimic aq_ethtool_queue_rx_stat_names structure */ |
| 935 | 935 | do { |
| 936 | 936 | count = 0; |
| 937 | − start = u64_stats_fetch_begin_irq(&self->stats.rx.syncp); | |
| 937 | + start = u64_stats_fetch_begin(&self->stats.rx.syncp); | |
| 938 | 938 | data[count] = self->stats.rx.packets; |
| 939 | 939 | data[++count] = self->stats.rx.jumbo_packets; |
| 940 | 940 | data[++count] = self->stats.rx.lro_packets; |
| @@ -951,15 +951,15 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data) · 10 unmodified lines | ||
| 951 | 951 | data[++count] = self->stats.rx.xdp_tx; |
| 952 | 952 | data[++count] = self->stats.rx.xdp_invalid; |
| 953 | 953 | data[++count] = self->stats.rx.xdp_redirect; |
| 954 | − } while (u64_stats_fetch_retry_irq(&self->stats.rx.syncp, start)); | |
| 954 | + } while (u64_stats_fetch_retry(&self->stats.rx.syncp, start)); | |
| 955 | 955 | } else { |
| 956 | 956 | /* This data should mimic aq_ethtool_queue_tx_stat_names structure */ |
| 957 | 957 | do { |
| 958 | 958 | count = 0; |
| 959 | − start = u64_stats_fetch_begin_irq(&self->stats.tx.syncp); | |
| 959 | + start = u64_stats_fetch_begin(&self->stats.tx.syncp); | |
| 960 | 960 | data[count] = self->stats.tx.packets; |
| 961 | 961 | data[++count] = self->stats.tx.queue_restarts; |
| 962 | − } while (u64_stats_fetch_retry_irq(&self->stats.tx.syncp, start)); | |
| 962 | + } while (u64_stats_fetch_retry(&self->stats.tx.syncp, start)); | |
| 963 | 963 | } |
| 964 | 964 | |
| 965 | 965 | return ++count; |
| @@ -662,12 +662,12 @@ static void ax88796c_get_stats64(struct net_device *ndev, · 661 unmodified lines | ||
| 662 | 662 | s = per_cpu_ptr(ax_local->stats, cpu); |
| 663 | 663 | |
| 664 | 664 | do { |
| 665 | − start = u64_stats_fetch_begin_irq(&s->syncp); | |
| 665 | + start = u64_stats_fetch_begin(&s->syncp); | |
| 666 | 666 | rx_packets = u64_stats_read(&s->rx_packets); |
| 667 | 667 | rx_bytes = u64_stats_read(&s->rx_bytes); |
| 668 | 668 | tx_packets = u64_stats_read(&s->tx_packets); |
| 669 | 669 | tx_bytes = u64_stats_read(&s->tx_bytes); |
| 670 | − } while (u64_stats_fetch_retry_irq(&s->syncp, start)); | |
| 670 | + } while (u64_stats_fetch_retry(&s->syncp, start)); | |
| 671 | 671 | |
| 672 | 672 | stats->rx_packets += rx_packets; |
| 673 | 673 | stats->rx_bytes += rx_bytes; |
| @@ -1086,7 +1086,6 @@ static void ag71xx_mac_link_up(struct phylink_config *config, · 1085 unmodified lines | ||
| 1086 | 1086 | } |
| 1087 | 1087 | |
| 1088 | 1088 | static const struct phylink_mac_ops ag71xx_phylink_mac_ops = { |
| 1089 | − .validate = phylink_generic_validate, | |
| 1090 | 1089 | .mac_config = ag71xx_mac_config, |
| 1091 | 1090 | .mac_link_down = ag71xx_mac_link_down, |
| 1092 | 1091 | .mac_link_up = ag71xx_mac_link_up, |
| @@ -1680,7 +1680,7 @@ static void b44_get_stats64(struct net_device *dev, · 1679 unmodified lines | ||
| 1680 | 1680 | unsigned int start; |
| 1681 | 1681 | |
| 1682 | 1682 | do { |
| 1683 | − start = u64_stats_fetch_begin_irq(&hwstat->syncp); | |
| 1683 | + start = u64_stats_fetch_begin(&hwstat->syncp); | |
| 1684 | 1684 | |
| 1685 | 1685 | /* Convert HW stats into rtnl_link_stats64 stats. */ |
| 1686 | 1686 | nstat->rx_packets = hwstat->rx_pkts; |
| @@ -1714,7 +1714,7 @@ static void b44_get_stats64(struct net_device *dev, · 27 unmodified lines | ||
| 1714 | 1714 | /* Carrier lost counter seems to be broken for some devices */ |
| 1715 | 1715 | nstat->tx_carrier_errors = hwstat->tx_carrier_lost; |
| 1716 | 1716 | #endif |
| 1717 | − } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); | |
| 1717 | + } while (u64_stats_fetch_retry(&hwstat->syncp, start)); | |
| 1718 | 1718 | |
| 1719 | 1719 | } |
| 1720 | 1720 | |
| @@ -2082,12 +2082,12 @@ static void b44_get_ethtool_stats(struct net_device *dev, · 361 unmodified lines | ||
| 2082 | 2082 | do { |
| 2083 | 2083 | data_src = &hwstat->tx_good_octets; |
| 2084 | 2084 | data_dst = data; |
| 2085 | − start = u64_stats_fetch_begin_irq(&hwstat->syncp); | |
| 2085 | + start = u64_stats_fetch_begin(&hwstat->syncp); | |
| 2086 | 2086 | |
| 2087 | 2087 | for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) |
| 2088 | 2088 | *data_dst++ = *data_src++; |
| 2089 | 2089 | |
| 2090 | − } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); | |
| 2090 | + } while (u64_stats_fetch_retry(&hwstat->syncp, start)); | |
| 2091 | 2091 | } |
| 2092 | 2092 | |
| 2093 | 2093 | static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
| @@ -36,13 +36,24 @@ · 35 unmodified lines | ||
| 36 | 36 | #define ENET_MAX_ETH_OVERHEAD (ETH_HLEN + BRCM_MAX_TAG_LEN + VLAN_HLEN + \ |
| 37 | 37 | ETH_FCS_LEN + 4) /* 32 */ |
| 38 | 38 | |
| 39 | +#define ENET_RX_SKB_BUF_SIZE (NET_SKB_PAD + NET_IP_ALIGN + \ | |
| 40 | + ETH_HLEN + BRCM_MAX_TAG_LEN + VLAN_HLEN + \ | |
| 41 | + ENET_MTU_MAX + ETH_FCS_LEN + 4) | |
| 42 | +#define ENET_RX_SKB_BUF_ALLOC_SIZE (SKB_DATA_ALIGN(ENET_RX_SKB_BUF_SIZE) + \ | |
| 43 | + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) | |
| 44 | +#define ENET_RX_BUF_DMA_OFFSET (NET_SKB_PAD + NET_IP_ALIGN) | |
| 45 | +#define ENET_RX_BUF_DMA_SIZE (ENET_RX_SKB_BUF_SIZE - ENET_RX_BUF_DMA_OFFSET) | |
| 46 | + | |
| 39 | 47 | struct bcm4908_enet_dma_ring_bd { |
| 40 | 48 | __le32 ctl; |
| 41 | 49 | __le32 addr; |
| 42 | 50 | } __packed; |
| 43 | 51 | |
| 44 | 52 | struct bcm4908_enet_dma_ring_slot { |
| 45 | − struct sk_buff *skb; | |
| 53 | + union { | |
| 54 | + void *buf; /* RX */ | |
| 55 | + struct sk_buff *skb; /* TX */ | |
| 56 | + }; | |
| 46 | 57 | unsigned int len; |
| 47 | 58 | dma_addr_t dma_addr; |
| 48 | 59 | }; |
| @@ -260,22 +271,21 @@ static int bcm4908_enet_dma_alloc_rx_buf(struct bcm4908_enet *enet, unsigned int · 211 unmodified lines | ||
| 260 | 271 | u32 tmp; |
| 261 | 272 | int err; |
| 262 | 273 | |
| 263 | − slot->len = ENET_MTU_MAX + ENET_MAX_ETH_OVERHEAD; | |
| 264 | − | |
| 265 | − slot->skb = netdev_alloc_skb(enet->netdev, slot->len); | |
| 266 | − if (!slot->skb) | |
| 274 | + slot->buf = napi_alloc_frag(ENET_RX_SKB_BUF_ALLOC_SIZE); | |
| 275 | + if (!slot->buf) | |
| 267 | 276 | return -ENOMEM; |
| 268 | 277 | |
| 269 | − slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE); | |
| 278 | + slot->dma_addr = dma_map_single(dev, slot->buf + ENET_RX_BUF_DMA_OFFSET, | |
| 279 | + ENET_RX_BUF_DMA_SIZE, DMA_FROM_DEVICE); | |
| 270 | 280 | err = dma_mapping_error(dev, slot->dma_addr); |
| 271 | 281 | if (err) { |
| 272 | 282 | dev_err(dev, "Failed to map DMA buffer: %d\n", err); |
| 273 | − kfree_skb(slot->skb); | |
| 274 | − slot->skb = NULL; | |
| 283 | + skb_free_frag(slot->buf); | |
| 284 | + slot->buf = NULL; | |
| 275 | 285 | return err; |
| 276 | 286 | } |
| 277 | 287 | |
| 278 | − tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT; | |
| 288 | + tmp = ENET_RX_BUF_DMA_SIZE << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT; | |
| 279 | 289 | tmp |= DMA_CTL_STATUS_OWN; |
| 280 | 290 | if (idx == enet->rx_ring.length - 1) |
| 281 | 291 | tmp |= DMA_CTL_STATUS_WRAP; |
| @@ -315,11 +325,11 @@ static void bcm4908_enet_dma_uninit(struct bcm4908_enet *enet) · 33 unmodified lines | ||
| 315 | 325 | |
| 316 | 326 | for (i = rx_ring->length - 1; i >= 0; i--) { |
| 317 | 327 | slot = &rx_ring->slots[i]; |
| 318 | − if (!slot->skb) | |
| 328 | + if (!slot->buf) | |
| 319 | 329 | continue; |
| 320 | 330 | dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE); |
| 321 | − kfree_skb(slot->skb); | |
| 322 | − slot->skb = NULL; | |
| 331 | + skb_free_frag(slot->buf); | |
| 332 | + slot->buf = NULL; | |
| 323 | 333 | } |
| 324 | 334 | } |
| 325 | 335 | |
| @@ -495,6 +505,7 @@ static int bcm4908_enet_stop(struct net_device *netdev) · 169 unmodified lines | ||
| 495 | 505 | netif_carrier_off(netdev); |
| 496 | 506 | napi_disable(&rx_ring->napi); |
| 497 | 507 | napi_disable(&tx_ring->napi); |
| 508 | + netdev_reset_queue(netdev); | |
| 498 | 509 | |
| 499 | 510 | bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring); |
| 500 | 511 | bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring); |
| @@ -554,6 +565,8 @@ static netdev_tx_t bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_devic · 53 unmodified lines | ||
| 554 | 565 | if (ring->write_idx + 1 == ring->length - 1) |
| 555 | 566 | tmp |= DMA_CTL_STATUS_WRAP; |
| 556 | 567 | |
| 568 | + netdev_sent_queue(enet->netdev, skb->len); | |
| 569 | + | |
| 557 | 570 | buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr); |
| 558 | 571 | buf_desc->ctl = cpu_to_le32(tmp); |
| 559 | 572 | |
| @@ -575,6 +588,7 @@ static int bcm4908_enet_poll_rx(struct napi_struct *napi, int weight) · 15 unmodified lines | ||
| 575 | 588 | while (handled < weight) { |
| 576 | 589 | struct bcm4908_enet_dma_ring_bd *buf_desc; |
| 577 | 590 | struct bcm4908_enet_dma_ring_slot slot; |
| 591 | + struct sk_buff *skb; | |
| 578 | 592 | u32 ctl; |
| 579 | 593 | int len; |
| 580 | 594 | int err; |
| @@ -598,16 +612,24 @@ static int bcm4908_enet_poll_rx(struct napi_struct *napi, int weight) · 17 unmodified lines | ||
| 598 | 612 | |
| 599 | 613 | if (len < ETH_ZLEN || |
| 600 | 614 | (ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) { |
| 601 | − kfree_skb(slot.skb); | |
| 615 | + skb_free_frag(slot.buf); | |
| 602 | 616 | enet->netdev->stats.rx_dropped++; |
| 603 | 617 | break; |
| 604 | 618 | } |
| 605 | 619 | |
| 606 | − dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE); | |
| 620 | + dma_unmap_single(dev, slot.dma_addr, ENET_RX_BUF_DMA_SIZE, DMA_FROM_DEVICE); | |
| 621 | + | |
| 622 | + skb = build_skb(slot.buf, ENET_RX_SKB_BUF_ALLOC_SIZE); | |
| 623 | + if (unlikely(!skb)) { | |
| 624 | + skb_free_frag(slot.buf); | |
| 625 | + enet->netdev->stats.rx_dropped++; | |
| 626 | + break; | |
| 627 | + } | |
| 628 | + skb_reserve(skb, ENET_RX_BUF_DMA_OFFSET); | |
| 629 | + skb_put(skb, len - ETH_FCS_LEN); | |
| 630 | + skb->protocol = eth_type_trans(skb, enet->netdev); | |
| 607 | 631 | |
| 608 | − skb_put(slot.skb, len - ETH_FCS_LEN); | |
| 609 | − slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev); | |
| 610 | − netif_receive_skb(slot.skb); | |
| 632 | + netif_receive_skb(skb); | |
| 611 | 633 | |
| 612 | 634 | enet->netdev->stats.rx_packets++; |
| 613 | 635 | enet->netdev->stats.rx_bytes += len; |
| @@ -652,6 +674,7 @@ static int bcm4908_enet_poll_tx(struct napi_struct *napi, int weight) · 38 unmodified lines | ||
| 652 | 674 | tx_ring->read_idx = 0; |
| 653 | 675 | } |
| 654 | 676 | |
| 677 | + netdev_completed_queue(enet->netdev, handled, bytes); | |
| 655 | 678 | enet->netdev->stats.tx_packets += handled; |
| 656 | 679 | enet->netdev->stats.tx_bytes += bytes; |
| 657 | 680 | |
| @@ -295,6 +295,8 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { · 294 unmodified lines | ||
| 295 | 295 | /* RBUF misc statistics */ |
| 296 | 296 | STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR), |
| 297 | 297 | STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR), |
| 298 | + /* RDMA misc statistics */ | |
| 299 | + STAT_RDMA("rdma_ovflow_cnt", mib.rdma_ovflow_cnt, RDMA_OVFL_DISC_CNTR), | |
| 298 | 300 | STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), |
| 299 | 301 | STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed), |
| 300 | 302 | STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed), |
| @@ -333,6 +335,7 @@ static inline bool bcm_sysport_lite_stat_valid(enum bcm_sysport_stat_type type) · 32 unmodified lines | ||
| 333 | 335 | case BCM_SYSPORT_STAT_NETDEV64: |
| 334 | 336 | case BCM_SYSPORT_STAT_RXCHK: |
| 335 | 337 | case BCM_SYSPORT_STAT_RBUF: |
| 338 | + case BCM_SYSPORT_STAT_RDMA: | |
| 336 | 339 | case BCM_SYSPORT_STAT_SOFT: |
| 337 | 340 | return true; |
| 338 | 341 | default: |
| @@ -436,6 +439,14 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv) · 97 unmodified lines | ||
| 436 | 439 | if (val == ~0) |
| 437 | 440 | rbuf_writel(priv, 0, s->reg_offset); |
| 438 | 441 | break; |
| 442 | + case BCM_SYSPORT_STAT_RDMA: | |
| 443 | + if (!priv->is_lite) | |
| 444 | + continue; | |
| 445 | + | |
| 446 | + val = rdma_readl(priv, s->reg_offset); | |
| 447 | + if (val == ~0) | |
| 448 | + rdma_writel(priv, 0, s->reg_offset); | |
| 449 | + break; | |
| 439 | 450 | } |
| 440 | 451 | |
| 441 | 452 | j += s->stat_sizeof; |
| @@ -457,10 +468,10 @@ static void bcm_sysport_update_tx_stats(struct bcm_sysport_priv *priv, · 15 unmodified lines | ||
| 457 | 468 | for (q = 0; q < priv->netdev->num_tx_queues; q++) { |
| 458 | 469 | ring = &priv->tx_rings[q]; |
| 459 | 470 | do { |
| 460 | − start = u64_stats_fetch_begin_irq(&priv->syncp); | |
| 471 | + start = u64_stats_fetch_begin(&priv->syncp); | |
| 461 | 472 | bytes = ring->bytes; |
| 462 | 473 | packets = ring->packets; |
| 463 | − } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); | |
| 474 | + } while (u64_stats_fetch_retry(&priv->syncp, start)); | |
| 464 | 475 | |
| 465 | 476 | *tx_bytes += bytes; |
| 466 | 477 | *tx_packets += packets; |
| @@ -504,9 +515,9 @@ static void bcm_sysport_get_stats(struct net_device *dev, · 37 unmodified lines | ||
| 504 | 515 | if (s->stat_sizeof == sizeof(u64) && |
| 505 | 516 | s->type == BCM_SYSPORT_STAT_NETDEV64) { |
| 506 | 517 | do { |
| 507 | − start = u64_stats_fetch_begin_irq(syncp); | |
| 518 | + start = u64_stats_fetch_begin(syncp); | |
| 508 | 519 | data[i] = *(u64 *)p; |
| 509 | − } while (u64_stats_fetch_retry_irq(syncp, start)); | |
| 520 | + } while (u64_stats_fetch_retry(syncp, start)); | |
| 510 | 521 | } else |
| 511 | 522 | data[i] = *(u32 *)p; |
| 512 | 523 | j++; |
| @@ -1878,10 +1889,10 @@ static void bcm_sysport_get_stats64(struct net_device *dev, · 1365 unmodified lines | ||
| 1878 | 1889 | &stats->tx_packets); |
| 1879 | 1890 | |
| 1880 | 1891 | do { |
| 1881 | − start = u64_stats_fetch_begin_irq(&priv->syncp); | |
| 1892 | + start = u64_stats_fetch_begin(&priv->syncp); | |
| 1882 | 1893 | stats->rx_packets = stats64->rx_packets; |
| 1883 | 1894 | stats->rx_bytes = stats64->rx_bytes; |
| 1884 | − } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); | |
| 1895 | + } while (u64_stats_fetch_retry(&priv->syncp, start)); | |
| 1885 | 1896 | } |
| 1886 | 1897 | |
| 1887 | 1898 | static void bcm_sysport_netif_start(struct net_device *dev) |
| @@ -290,6 +290,7 @@ struct bcm_rsb { · 289 unmodified lines | ||
| 290 | 290 | |
| 291 | 291 | #define RDMA_WRITE_PTR_HI 0x1010 |
| 292 | 292 | #define RDMA_WRITE_PTR_LO 0x1014 |
| 293 | +#define RDMA_OVFL_DISC_CNTR 0x1018 | |
| 293 | 294 | #define RDMA_PROD_INDEX 0x1018 |
| 294 | 295 | #define RDMA_PROD_INDEX_MASK 0xffff |
| 295 | 296 | |
| @@ -565,6 +566,7 @@ struct bcm_sysport_mib { · 269 unmodified lines | ||
| 565 | 566 | u32 rxchk_other_pkt_disc; |
| 566 | 567 | u32 rbuf_ovflow_cnt; |
| 567 | 568 | u32 rbuf_err_cnt; |
| 569 | + u32 rdma_ovflow_cnt; | |
| 568 | 570 | u32 alloc_rx_buff_failed; |
| 569 | 571 | u32 rx_dma_failed; |
| 570 | 572 | u32 tx_dma_failed; |
| @@ -581,6 +583,7 @@ enum bcm_sysport_stat_type { · 10 unmodified lines | ||
| 581 | 583 | BCM_SYSPORT_STAT_RUNT, |
| 582 | 584 | BCM_SYSPORT_STAT_RXCHK, |
| 583 | 585 | BCM_SYSPORT_STAT_RBUF, |
| 586 | + BCM_SYSPORT_STAT_RDMA, | |
| 584 | 587 | BCM_SYSPORT_STAT_SOFT, |
| 585 | 588 | }; |
| 586 | 589 | |
| @@ -627,6 +630,14 @@ enum bcm_sysport_stat_type { · 40 unmodified lines | ||
| 627 | 630 | .reg_offset = ofs, \ |
| 628 | 631 | } |
| 629 | 632 | |
| 633 | +#define STAT_RDMA(str, m, ofs) { \ | |
| 634 | + .stat_string = str, \ | |
| 635 | + .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \ | |
| 636 | + .stat_offset = offsetof(struct bcm_sysport_priv, m), \ | |
| 637 | + .type = BCM_SYSPORT_STAT_RDMA, \ | |
| 638 | + .reg_offset = ofs, \ | |
| 639 | +} | |
| 640 | + | |
| 630 | 641 | /* TX bytes and packets */ |
| 631 | 642 | #define NUM_SYSPORT_TXQ_STAT 2 |
| 632 | 643 | |
| @@ -3045,7 +3045,7 @@ error: · 3044 unmodified lines | ||
| 3045 | 3045 | |
| 3046 | 3046 | dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, |
| 3047 | 3047 | DMA_FROM_DEVICE); |
| 3048 | − skb = build_skb(data, 0); | |
| 3048 | + skb = slab_build_skb(data); | |
| 3049 | 3049 | if (!skb) { |
| 3050 | 3050 | kfree(data); |
| 3051 | 3051 | goto error; |
| @@ -5415,8 +5415,9 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) · 2363 unmodified lines | ||
| 5415 | 5415 | |
| 5416 | 5416 | bp->rx_buf_use_size = rx_size; |
| 5417 | 5417 | /* hw alignment + build_skb() overhead*/ |
| 5418 | − bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) + | |
| 5419 | − NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); | |
| 5418 | + bp->rx_buf_size = kmalloc_size_roundup( | |
| 5419 | + SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) + | |
| 5420 | + NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); | |
| 5420 | 5421 | bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; |
| 5421 | 5422 | bp->rx_ring_size = size; |
| 5422 | 5423 | bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS); |
| @@ -13671,19 +13671,20 @@ static int bnx2x_send_update_drift_ramrod(struct bnx2x *bp, int drift_dir, · 13670 unmodified lines | ||
| 13671 | 13671 | return bnx2x_func_state_change(bp, &func_params); |
| 13672 | 13672 | } |
| 13673 | 13673 | |
| 13674 | −static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) | |
| 13674 | +static int bnx2x_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) | |
| 13675 | 13675 | { |
| 13676 | 13676 | struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info); |
| 13677 | 13677 | int rc; |
| 13678 | 13678 | int drift_dir = 1; |
| 13679 | 13679 | int val, period, period1, period2, dif, dif1, dif2; |
| 13680 | 13680 | int best_dif = BNX2X_MAX_PHC_DRIFT, best_period = 0, best_val = 0; |
| 13681 | + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); | |
| 13681 | 13682 | |
| 13682 | − DP(BNX2X_MSG_PTP, "PTP adjfreq called, ppb = %d\n", ppb); | |
| 13683 | + DP(BNX2X_MSG_PTP, "PTP adjfine called, ppb = %d\n", ppb); | |
| 13683 | 13684 | |
| 13684 | 13685 | if (!netif_running(bp->dev)) { |
| 13685 | 13686 | DP(BNX2X_MSG_PTP, |
| 13686 | − "PTP adjfreq called while the interface is down\n"); | |
| 13687 | + "PTP adjfine called while the interface is down\n"); | |
| 13687 | 13688 | return -ENETDOWN; |
| 13688 | 13689 | } |
| 13689 | 13690 | |
| @@ -13818,7 +13819,7 @@ void bnx2x_register_phc(struct bnx2x *bp) · 128 unmodified lines | ||
| 13818 | 13819 | bp->ptp_clock_info.n_ext_ts = 0; |
| 13819 | 13820 | bp->ptp_clock_info.n_per_out = 0; |
| 13820 | 13821 | bp->ptp_clock_info.pps = 0; |
| 13821 | − bp->ptp_clock_info.adjfreq = bnx2x_ptp_adjfreq; | |
| 13822 | + bp->ptp_clock_info.adjfine = bnx2x_ptp_adjfine; | |
| 13822 | 13823 | bp->ptp_clock_info.adjtime = bnx2x_ptp_adjtime; |
| 13823 | 13824 | bp->ptp_clock_info.gettime64 = bnx2x_ptp_gettime; |
| 13824 | 13825 | bp->ptp_clock_info.settime64 = bnx2x_ptp_settime; |
| @@ -389,6 +389,9 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) · 388 unmodified lines | ||
| 389 | 389 | return NETDEV_TX_BUSY; |
| 390 | 390 | } |
| 391 | 391 | |
| 392 | + if (unlikely(ipv6_hopopt_jumbo_remove(skb))) | |
| 393 | + goto tx_free; | |
| 394 | + | |
| 392 | 395 | length = skb->len; |
| 393 | 396 | len = skb_headlen(skb); |
| 394 | 397 | last_frag = skb_shinfo(skb)->nr_frags; |
| @@ -5250,7 +5253,7 @@ int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings) · 4855 unmodified lines | ||
| 5250 | 5253 | return 1; |
| 5251 | 5254 | } |
| 5252 | 5255 | |
| 5253 | −static void __bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic) | |
| 5256 | +static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic) | |
| 5254 | 5257 | { |
| 5255 | 5258 | bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG); |
| 5256 | 5259 | u16 i, j; |
| @@ -5263,8 +5266,8 @@ static void __bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic) · 6 unmodified lines | ||
| 5263 | 5266 | } |
| 5264 | 5267 | } |
| 5265 | 5268 | |
| 5266 | −static void __bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, | |
| 5267 | − struct bnxt_vnic_info *vnic) | |
| 5269 | +static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, | |
| 5270 | + struct bnxt_vnic_info *vnic) | |
| 5268 | 5271 | { |
| 5269 | 5272 | __le16 *ring_tbl = vnic->rss_table; |
| 5270 | 5273 | struct bnxt_rx_ring_info *rxr; |
| @@ -5285,12 +5288,27 @@ static void __bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, · 14 unmodified lines | ||
| 5285 | 5288 | } |
| 5286 | 5289 | } |
| 5287 | 5290 | |
| 5288 | −static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic) | |
| 5291 | +static void | |
| 5292 | +__bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req, | |
| 5293 | + struct bnxt_vnic_info *vnic) | |
| 5289 | 5294 | { |
| 5290 | 5295 | if (bp->flags & BNXT_FLAG_CHIP_P5) |
| 5291 | − __bnxt_fill_hw_rss_tbl_p5(bp, vnic); | |
| 5296 | + bnxt_fill_hw_rss_tbl_p5(bp, vnic); | |
| 5292 | 5297 | else |
| 5293 | − __bnxt_fill_hw_rss_tbl(bp, vnic); | |
| 5298 | + bnxt_fill_hw_rss_tbl(bp, vnic); | |
| 5299 | + | |
| 5300 | + if (bp->rss_hash_delta) { | |
| 5301 | + req->hash_type = cpu_to_le32(bp->rss_hash_delta); | |
| 5302 | + if (bp->rss_hash_cfg & bp->rss_hash_delta) | |
| 5303 | + req->flags |= VNIC_RSS_CFG_REQ_FLAGS_HASH_TYPE_INCLUDE; | |
| 5304 | + else | |
| 5305 | + req->flags |= VNIC_RSS_CFG_REQ_FLAGS_HASH_TYPE_EXCLUDE; | |
| 5306 | + } else { | |
| 5307 | + req->hash_type = cpu_to_le32(bp->rss_hash_cfg); | |
| 5308 | + } | |
| 5309 | + req->hash_mode_flags = VNIC_RSS_CFG_REQ_HASH_MODE_FLAGS_DEFAULT; | |
| 5310 | + req->ring_grp_tbl_addr = cpu_to_le64(vnic->rss_table_dma_addr); | |
| 5311 | + req->hash_key_tbl_addr = cpu_to_le64(vnic->rss_hash_key_dma_addr); | |
| 5294 | 5312 | } |
| 5295 | 5313 | |
| 5296 | 5314 | static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) |
| @@ -5307,14 +5325,8 @@ static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) · 10 unmodified lines | ||
| 5307 | 5325 | if (rc) |
| 5308 | 5326 | return rc; |
| 5309 | 5327 | |
| 5310 | − if (set_rss) { | |
| 5311 | − bnxt_fill_hw_rss_tbl(bp, vnic); | |
| 5312 | − req->hash_type = cpu_to_le32(bp->rss_hash_cfg); | |
| 5313 | − req->hash_mode_flags = VNIC_RSS_CFG_REQ_HASH_MODE_FLAGS_DEFAULT; | |
| 5314 | − req->ring_grp_tbl_addr = cpu_to_le64(vnic->rss_table_dma_addr); | |
| 5315 | − req->hash_key_tbl_addr = | |
| 5316 | − cpu_to_le64(vnic->rss_hash_key_dma_addr); | |
| 5317 | − } | |
| 5328 | + if (set_rss) | |
| 5329 | + __bnxt_hwrm_vnic_set_rss(bp, req, vnic); | |
| 5318 | 5330 | req->rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[0]); |
| 5319 | 5331 | return hwrm_req_send(bp, req); |
| 5320 | 5332 | } |
| @@ -5335,10 +5347,7 @@ static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp, u16 vnic_id, bool set_rss) · 14 unmodified lines | ||
| 5335 | 5347 | if (!set_rss) |
| 5336 | 5348 | return hwrm_req_send(bp, req); |
| 5337 | 5349 | |
| 5338 | − bnxt_fill_hw_rss_tbl(bp, vnic); | |
| 5339 | − req->hash_type = cpu_to_le32(bp->rss_hash_cfg); | |
| 5340 | − req->hash_mode_flags = VNIC_RSS_CFG_REQ_HASH_MODE_FLAGS_DEFAULT; | |
| 5341 | − req->hash_key_tbl_addr = cpu_to_le64(vnic->rss_hash_key_dma_addr); | |
| 5350 | + __bnxt_hwrm_vnic_set_rss(bp, req, vnic); | |
| 5342 | 5351 | ring_tbl_map = vnic->rss_table_dma_addr; |
| 5343 | 5352 | nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings); |
| 5344 | 5353 | |
| @@ -5357,6 +5366,25 @@ exit: · 12 unmodified lines | ||
| 5357 | 5366 | return rc; |
| 5358 | 5367 | } |
| 5359 | 5368 | |
| 5369 | +static void bnxt_hwrm_update_rss_hash_cfg(struct bnxt *bp) | |
| 5370 | +{ | |
| 5371 | + struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; | |
| 5372 | + struct hwrm_vnic_rss_qcfg_output *resp; | |
| 5373 | + struct hwrm_vnic_rss_qcfg_input *req; | |
| 5374 | + | |
| 5375 | + if (hwrm_req_init(bp, req, HWRM_VNIC_RSS_QCFG)) | |
| 5376 | + return; | |
| 5377 | + | |
| 5378 | + /* all contexts configured to same hash_type, zero always exists */ | |
| 5379 | + req->rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[0]); | |
| 5380 | + resp = hwrm_req_hold(bp, req); | |
| 5381 | + if (!hwrm_req_send(bp, req)) { | |
| 5382 | + bp->rss_hash_cfg = le32_to_cpu(resp->hash_type) ?: bp->rss_hash_cfg; | |
| 5383 | + bp->rss_hash_delta = 0; | |
| 5384 | + } | |
| 5385 | + hwrm_req_drop(bp, req); | |
| 5386 | +} | |
| 5387 | + | |
| 5360 | 5388 | static int bnxt_hwrm_vnic_set_hds(struct bnxt *bp, u16 vnic_id) |
| 5361 | 5389 | { |
| 5362 | 5390 | struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; |
| @@ -5614,6 +5642,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) · 251 unmodified lines | ||
| 5614 | 5642 | (BNXT_CHIP_P5_THOR(bp) && |
| 5615 | 5643 | !(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED))) |
| 5616 | 5644 | bp->fw_cap |= BNXT_FW_CAP_VLAN_RX_STRIP; |
| 5645 | + if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_HASH_TYPE_DELTA_CAP) | |
| 5646 | + bp->fw_cap |= BNXT_FW_CAP_RSS_HASH_TYPE_DELTA; | |
| 5617 | 5647 | bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported); |
| 5618 | 5648 | if (bp->max_tpa_v2) { |
| 5619 | 5649 | if (BNXT_CHIP_P5_THOR(bp)) |
| @@ -6958,8 +6988,11 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) · 1338 unmodified lines | ||
| 6958 | 6988 | if (flags & FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED) |
| 6959 | 6989 | bp->fw_cap |= BNXT_FW_CAP_DCBX_AGENT; |
| 6960 | 6990 | } |
| 6961 | − if (BNXT_PF(bp) && (flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST)) | |
| 6991 | + if (BNXT_PF(bp) && (flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST)) { | |
| 6962 | 6992 | bp->flags |= BNXT_FLAG_MULTI_HOST; |
| 6993 | + if (bp->fw_cap & BNXT_FW_CAP_PTP_RTC) | |
| 6994 | + bp->fw_cap &= ~BNXT_FW_CAP_PTP_RTC; | |
| 6995 | + } | |
| 6963 | 6996 | if (flags & FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED) |
| 6964 | 6997 | bp->fw_cap |= BNXT_FW_CAP_RING_MONITOR; |
| 6965 | 6998 | |
| @@ -8808,6 +8841,8 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) · 1842 unmodified lines | ||
| 8808 | 8841 | rc = bnxt_setup_vnic(bp, 0); |
| 8809 | 8842 | if (rc) |
| 8810 | 8843 | goto err_out; |
| 8844 | + if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) | |
| 8845 | + bnxt_hwrm_update_rss_hash_cfg(bp); | |
| 8811 | 8846 | |
| 8812 | 8847 | if (bp->flags & BNXT_FLAG_RFS) { |
| 8813 | 8848 | rc = bnxt_alloc_rfs_vnics(bp); |
| @@ -11283,6 +11318,7 @@ static bool bnxt_exthdr_check(struct bnxt *bp, struct sk_buff *skb, int nw_off, · 2469 unmodified lines | ||
| 11283 | 11318 | u8 **nextp) |
| 11284 | 11319 | { |
| 11285 | 11320 | struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + nw_off); |
| 11321 | + struct hop_jumbo_hdr *jhdr; | |
| 11286 | 11322 | int hdr_count = 0; |
| 11287 | 11323 | u8 *nexthdr; |
| 11288 | 11324 | int start; |
| @@ -11310,9 +11346,27 @@ static bool bnxt_exthdr_check(struct bnxt *bp, struct sk_buff *skb, int nw_off, · 21 unmodified lines | ||
| 11310 | 11346 | |
| 11311 | 11347 | if (hdrlen > 64) |
| 11312 | 11348 | return false; |
| 11349 | + | |
| 11350 | + /* The ext header may be a hop-by-hop header inserted for | |
| 11351 | + * big TCP purposes. This will be removed before sending | |
| 11352 | + * from NIC, so do not count it. | |
| 11353 | + */ | |
| 11354 | + if (*nexthdr == NEXTHDR_HOP) { | |
| 11355 | + if (likely(skb->len <= GRO_LEGACY_MAX_SIZE)) | |
| 11356 | + goto increment_hdr; | |
| 11357 | + | |
| 11358 | + jhdr = (struct hop_jumbo_hdr *)hp; | |
| 11359 | + if (jhdr->tlv_type != IPV6_TLV_JUMBO || jhdr->hdrlen != 0 || | |
| 11360 | + jhdr->nexthdr != IPPROTO_TCP) | |
| 11361 | + goto increment_hdr; | |
| 11362 | + | |
| 11363 | + goto next_hdr; | |
| 11364 | + } | |
| 11365 | +increment_hdr: | |
| 11366 | + hdr_count++; | |
| 11367 | +next_hdr: | |
| 11313 | 11368 | nexthdr = &hp->nexthdr; |
| 11314 | 11369 | start += hdrlen; |
| 11315 | − hdr_count++; | |
| 11316 | 11370 | } |
| 11317 | 11371 | if (nextp) { |
| 11318 | 11372 | /* Caller will check inner protocol */ |
| @@ -12252,6 +12306,8 @@ static void bnxt_set_dflt_rss_hash_type(struct bnxt *bp) · 933 unmodified lines | ||
| 12252 | 12306 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | |
| 12253 | 12307 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | |
| 12254 | 12308 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; |
| 12309 | + if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) | |
| 12310 | + bp->rss_hash_delta = bp->rss_hash_cfg; | |
| 12255 | 12311 | if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { |
| 12256 | 12312 | bp->flags |= BNXT_FLAG_UDP_RSS_CAP; |
| 12257 | 12313 | bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 | |
| @@ -13082,13 +13138,6 @@ int bnxt_get_port_parent_id(struct net_device *dev, · 824 unmodified lines | ||
| 13082 | 13138 | return 0; |
| 13083 | 13139 | } |
| 13084 | 13140 | |
| 13085 | −static struct devlink_port *bnxt_get_devlink_port(struct net_device *dev) | |
| 13086 | −{ | |
| 13087 | − struct bnxt *bp = netdev_priv(dev); | |
| 13088 | − | |
| 13089 | − return &bp->dl_port; | |
| 13090 | −} | |
| 13091 | − | |
| 13092 | 13141 | static const struct net_device_ops bnxt_netdev_ops = { |
| 13093 | 13142 | .ndo_open = bnxt_open, |
| 13094 | 13143 | .ndo_start_xmit = bnxt_start_xmit, |
| @@ -13120,7 +13169,6 @@ static const struct net_device_ops bnxt_netdev_ops = { · 25 unmodified lines | ||
| 13120 | 13169 | .ndo_xdp_xmit = bnxt_xdp_xmit, |
| 13121 | 13170 | .ndo_bridge_getlink = bnxt_bridge_getlink, |
| 13122 | 13171 | .ndo_bridge_setlink = bnxt_bridge_setlink, |
| 13123 | − .ndo_get_devlink_port = bnxt_get_devlink_port, | |
| 13124 | 13172 | }; |
| 13125 | 13173 | |
| 13126 | 13174 | static void bnxt_remove_one(struct pci_dev *pdev) |
| @@ -13131,9 +13179,6 @@ static void bnxt_remove_one(struct pci_dev *pdev) · 4 unmodified lines | ||
| 13131 | 13179 | if (BNXT_PF(bp)) |
| 13132 | 13180 | bnxt_sriov_disable(bp); |
| 13133 | 13181 | |
| 13134 | − if (BNXT_PF(bp)) | |
| 13135 | − devlink_port_type_clear(&bp->dl_port); | |
| 13136 | − | |
| 13137 | 13182 | bnxt_ptp_clear(bp); |
| 13138 | 13183 | pci_disable_pcie_error_reporting(pdev); |
| 13139 | 13184 | unregister_netdev(dev); |
| @@ -13546,6 +13591,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) · 406 unmodified lines | ||
| 13546 | 13591 | return -ENOMEM; |
| 13547 | 13592 | |
| 13548 | 13593 | bp = netdev_priv(dev); |
| 13594 | + SET_NETDEV_DEVLINK_PORT(dev, &bp->dl_port); | |
| 13549 | 13595 | bp->board_idx = ent->driver_data; |
| 13550 | 13596 | bp->msg_enable = BNXT_DEF_MSG_ENABLE; |
| 13551 | 13597 | bnxt_set_max_func_irqs(bp, max_irqs); |
| @@ -13633,6 +13679,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) · 81 unmodified lines | ||
| 13633 | 13679 | dev->features &= ~NETIF_F_LRO; |
| 13634 | 13680 | dev->priv_flags |= IFF_UNICAST_FLT; |
| 13635 | 13681 | |
| 13682 | + netif_set_tso_max_size(dev, GSO_MAX_SIZE); | |
| 13683 | + | |
| 13636 | 13684 | #ifdef CONFIG_BNXT_SRIOV |
| 13637 | 13685 | init_waitqueue_head(&bp->sriov_cfg_wait); |
| 13638 | 13686 | #endif |
| @@ -13721,8 +13769,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) · 82 unmodified lines | ||
| 13721 | 13769 | if (rc) |
| 13722 | 13770 | goto init_err_cleanup; |
| 13723 | 13771 | |
| 13724 | − if (BNXT_PF(bp)) | |
| 13725 | − devlink_port_type_eth_set(&bp->dl_port, bp->dev); | |
| 13726 | 13772 | bnxt_dl_fw_reporters_create(bp); |
| 13727 | 13773 | |
| 13728 | 13774 | bnxt_print_device_info(bp); |
| @@ -1901,6 +1901,7 @@ struct bnxt { · 1900 unmodified lines | ||
| 1901 | 1901 | u16 *rss_indir_tbl; |
| 1902 | 1902 | u16 rss_indir_tbl_entries; |
| 1903 | 1903 | u32 rss_hash_cfg; |
| 1904 | + u32 rss_hash_delta; | |
| 1904 | 1905 | |
| 1905 | 1906 | u16 max_mtu; |
| 1906 | 1907 | u8 max_tc; |
| @@ -1966,6 +1967,7 @@ struct bnxt { · 59 unmodified lines | ||
| 1966 | 1967 | #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 0x00010000 |
| 1967 | 1968 | #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED 0x00020000 |
| 1968 | 1969 | #define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000 |
| 1970 | + #define BNXT_FW_CAP_RSS_HASH_TYPE_DELTA 0x00080000 | |
| 1969 | 1971 | #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000 |
| 1970 | 1972 | #define BNXT_FW_CAP_HOT_RESET 0x00200000 |
| 1971 | 1973 | #define BNXT_FW_CAP_PTP_RTC 0x00400000 |
| @@ -2117,6 +2119,7 @@ struct bnxt { · 145 unmodified lines | ||
| 2117 | 2119 | #define BNXT_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS |
| 2118 | 2120 | #define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) |
| 2119 | 2121 | #define BNXT_PHY_FL_NO_PFC (PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED << 8) |
| 2122 | +#define BNXT_PHY_FL_BANK_SEL (PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED << 8) | |
| 2120 | 2123 | |
| 2121 | 2124 | u8 num_tests; |
| 2122 | 2125 | struct bnxt_test_info *test_info; |
| @@ -892,10 +892,6 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, · 891 unmodified lines | ||
| 892 | 892 | u32 ver = 0; |
| 893 | 893 | int rc; |
| 894 | 894 | |
| 895 | − rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME); | |
| 896 | − if (rc) | |
| 897 | − return rc; | |
| 898 | − | |
| 899 | 895 | if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) { |
| 900 | 896 | sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", |
| 901 | 897 | bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4], |
| @@ -1234,6 +1234,8 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) · 1233 unmodified lines | ||
| 1234 | 1234 | if (bp->rss_hash_cfg == rss_hash_cfg) |
| 1235 | 1235 | return 0; |
| 1236 | 1236 | |
| 1237 | + if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) | |
| 1238 | + bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg; | |
| 1237 | 1239 | bp->rss_hash_cfg = rss_hash_cfg; |
| 1238 | 1240 | if (netif_running(bp->dev)) { |
| 1239 | 1241 | bnxt_close_nic(bp, false, false); |
| @@ -2005,6 +2007,14 @@ static void bnxt_get_fec_stats(struct net_device *dev, · 765 unmodified lines | ||
| 2005 | 2007 | rx = bp->rx_port_stats_ext.sw_stats; |
| 2006 | 2008 | fec_stats->corrected_bits.total = |
| 2007 | 2009 | *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); |
| 2010 | + | |
| 2011 | + if (bp->fw_rx_stats_ext_size <= BNXT_RX_STATS_EXT_NUM_LEGACY) | |
| 2012 | + return; | |
| 2013 | + | |
| 2014 | + fec_stats->corrected_blocks.total = | |
| 2015 | + *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_corrected_blocks)); | |
| 2016 | + fec_stats->uncorrectable_blocks.total = | |
| 2017 | + *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_uncorrectable_blocks)); | |
| 2008 | 2018 | } |
| 2009 | 2019 | |
| 2010 | 2020 | static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, |
| @@ -2514,6 +2524,7 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev, · 503 unmodified lines | ||
| 2514 | 2524 | #define MSG_INTERNAL_ERR "PKG install error : Internal error" |
| 2515 | 2525 | #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" |
| 2516 | 2526 | #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" |
| 2527 | +#define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" | |
| 2517 | 2528 | #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" |
| 2518 | 2529 | #define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" |
| 2519 | 2530 | |
| @@ -2564,6 +2575,32 @@ static int nvm_update_err_to_stderr(struct net_device *dev, u8 result, · 44 unmodified lines | ||
| 2564 | 2575 | #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) |
| 2565 | 2576 | #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) |
| 2566 | 2577 | |
| 2578 | +static int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size, | |
| 2579 | + struct netlink_ext_ack *extack) | |
| 2580 | +{ | |
| 2581 | + u32 item_len; | |
| 2582 | + int rc; | |
| 2583 | + | |
| 2584 | + rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, | |
| 2585 | + BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL, | |
| 2586 | + &item_len, NULL); | |
| 2587 | + if (rc) { | |
| 2588 | + BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); | |
| 2589 | + return rc; | |
| 2590 | + } | |
| 2591 | + | |
| 2592 | + if (fw_size > item_len) { | |
| 2593 | + rc = bnxt_flash_nvram(dev, BNX_DIR_TYPE_UPDATE, | |
| 2594 | + BNX_DIR_ORDINAL_FIRST, 0, 1, | |
| 2595 | + round_up(fw_size, 4096), NULL, 0); | |
| 2596 | + if (rc) { | |
| 2597 | + BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR); | |
| 2598 | + return rc; | |
| 2599 | + } | |
| 2600 | + } | |
| 2601 | + return 0; | |
| 2602 | +} | |
| 2603 | + | |
| 2567 | 2604 | int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, |
| 2568 | 2605 | u32 install_type, struct netlink_ext_ack *extack) |
| 2569 | 2606 | { |
| @@ -2580,6 +2617,11 @@ int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware · 10 unmodified lines | ||
| 2580 | 2617 | u16 index; |
| 2581 | 2618 | int rc; |
| 2582 | 2619 | |
| 2620 | + /* resize before flashing larger image than available space */ | |
| 2621 | + rc = bnxt_resize_update_entry(dev, fw->size, extack); | |
| 2622 | + if (rc) | |
| 2623 | + return rc; | |
| 2624 | + | |
| 2583 | 2625 | bnxt_hwrm_fw_set_time(bp); |
| 2584 | 2626 | |
| 2585 | 2627 | rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); |
| @@ -3146,8 +3188,9 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) · 560 unmodified lines | ||
| 3146 | 3188 | } |
| 3147 | 3189 | |
| 3148 | 3190 | static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, |
| 3149 | − u16 page_number, u16 start_addr, | |
| 3150 | − u16 data_length, u8 *buf) | |
| 3191 | + u16 page_number, u8 bank, | |
| 3192 | + u16 start_addr, u16 data_length, | |
| 3193 | + u8 *buf) | |
| 3151 | 3194 | { |
| 3152 | 3195 | struct hwrm_port_phy_i2c_read_output *output; |
| 3153 | 3196 | struct hwrm_port_phy_i2c_read_input *req; |
| @@ -3168,8 +3211,13 @@ static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, · 14 unmodified lines | ||
| 3168 | 3211 | data_length -= xfer_size; |
| 3169 | 3212 | req->page_offset = cpu_to_le16(start_addr + byte_offset); |
| 3170 | 3213 | req->data_length = xfer_size; |
| 3171 | − req->enables = cpu_to_le32(start_addr + byte_offset ? | |
| 3172 | − PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); | |
| 3214 | + req->enables = | |
| 3215 | + cpu_to_le32((start_addr + byte_offset ? | |
| 3216 | + PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : | |
| 3217 | + 0) | | |
| 3218 | + (bank ? | |
| 3219 | + PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : | |
| 3220 | + 0)); | |
| 3173 | 3221 | rc = hwrm_req_send(bp, req); |
| 3174 | 3222 | if (!rc) |
| 3175 | 3223 | memcpy(buf + byte_offset, output->data, xfer_size); |
| @@ -3199,7 +3247,7 @@ static int bnxt_get_module_info(struct net_device *dev, · 23 unmodified lines | ||
| 3199 | 3247 | if (bp->hwrm_spec_code < 0x10202) |
| 3200 | 3248 | return -EOPNOTSUPP; |
| 3201 | 3249 | |
| 3202 | − rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, | |
| 3250 | + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0, | |
| 3203 | 3251 | SFF_DIAG_SUPPORT_OFFSET + 1, |
| 3204 | 3252 | data); |
| 3205 | 3253 | if (!rc) { |
| @@ -3244,7 +3292,7 @@ static int bnxt_get_module_eeprom(struct net_device *dev, · 38 unmodified lines | ||
| 3244 | 3292 | if (start < ETH_MODULE_SFF_8436_LEN) { |
| 3245 | 3293 | if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) |
| 3246 | 3294 | length = ETH_MODULE_SFF_8436_LEN - start; |
| 3247 | − rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, | |
| 3295 | + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, | |
| 3248 | 3296 | start, length, data); |
| 3249 | 3297 | if (rc) |
| 3250 | 3298 | return rc; |
| @@ -3256,12 +3304,68 @@ static int bnxt_get_module_eeprom(struct net_device *dev, · 5 unmodified lines | ||
| 3256 | 3304 | /* Read A2 portion of the EEPROM */ |
| 3257 | 3305 | if (length) { |
| 3258 | 3306 | start -= ETH_MODULE_SFF_8436_LEN; |
| 3259 | − rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, | |
| 3307 | + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0, | |
| 3260 | 3308 | start, length, data); |
| 3261 | 3309 | } |
| 3262 | 3310 | return rc; |
| 3263 | 3311 | } |
| 3264 | 3312 | |
| 3313 | +static int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack) | |
| 3314 | +{ | |
| 3315 | + if (bp->link_info.module_status <= | |
| 3316 | + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) | |
| 3317 | + return 0; | |
| 3318 | + | |
| 3319 | + switch (bp->link_info.module_status) { | |
| 3320 | + case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: | |
| 3321 | + NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); | |
| 3322 | + break; | |
| 3323 | + case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: | |
| 3324 | + NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); | |
| 3325 | + break; | |
| 3326 | + case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: | |
| 3327 | + NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault"); | |
| 3328 | + break; | |
| 3329 | + default: | |
| 3330 | + NL_SET_ERR_MSG_MOD(extack, "Unknown error"); | |
| 3331 | + break; | |
| 3332 | + } | |
| 3333 | + return -EINVAL; | |
| 3334 | +} | |
| 3335 | + | |
| 3336 | +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, | |
| 3337 | + const struct ethtool_module_eeprom *page_data, | |
| 3338 | + struct netlink_ext_ack *extack) | |
| 3339 | +{ | |
| 3340 | + struct bnxt *bp = netdev_priv(dev); | |
| 3341 | + int rc; | |
| 3342 | + | |
| 3343 | + rc = bnxt_get_module_status(bp, extack); | |
| 3344 | + if (rc) | |
| 3345 | + return rc; | |
| 3346 | + | |
| 3347 | + if (bp->hwrm_spec_code < 0x10202) { | |
| 3348 | + NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); | |
| 3349 | + return -EINVAL; | |
| 3350 | + } | |
| 3351 | + | |
| 3352 | + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { | |
| 3353 | + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); | |
| 3354 | + return -EINVAL; | |
| 3355 | + } | |
| 3356 | + | |
| 3357 | + rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, | |
| 3358 | + page_data->page, page_data->bank, | |
| 3359 | + page_data->offset, | |
| 3360 | + page_data->length, | |
| 3361 | + page_data->data); | |
| 3362 | + if (rc) { | |
| 3363 | + NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); | |
| 3364 | + return rc; | |
| 3365 | + } | |
| 3366 | + return page_data->length; | |
| 3367 | +} | |
| 3368 | + | |
| 3265 | 3369 | static int bnxt_nway_reset(struct net_device *dev) |
| 3266 | 3370 | { |
| 3267 | 3371 | int rc = 0; |
| @@ -4018,6 +4122,20 @@ static void bnxt_get_rmon_stats(struct net_device *dev, · 750 unmodified lines | ||
| 4018 | 4122 | *ranges = bnxt_rmon_ranges; |
| 4019 | 4123 | } |
| 4020 | 4124 | |
| 4125 | +static void bnxt_get_link_ext_stats(struct net_device *dev, | |
| 4126 | + struct ethtool_link_ext_stats *stats) | |
| 4127 | +{ | |
| 4128 | + struct bnxt *bp = netdev_priv(dev); | |
| 4129 | + u64 *rx; | |
| 4130 | + | |
| 4131 | + if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) | |
| 4132 | + return; | |
| 4133 | + | |
| 4134 | + rx = bp->rx_port_stats_ext.sw_stats; | |
| 4135 | + stats->link_down_events = | |
| 4136 | + *(rx + BNXT_RX_STATS_EXT_OFFSET(link_down_events)); | |
| 4137 | +} | |
| 4138 | + | |
| 4021 | 4139 | void bnxt_ethtool_free(struct bnxt *bp) |
| 4022 | 4140 | { |
| 4023 | 4141 | kfree(bp->test_info); |
| @@ -4067,10 +4185,12 @@ const struct ethtool_ops bnxt_ethtool_ops = { · 43 unmodified lines | ||
| 4067 | 4185 | .get_eeprom = bnxt_get_eeprom, |
| 4068 | 4186 | .set_eeprom = bnxt_set_eeprom, |
| 4069 | 4187 | .get_link = bnxt_get_link, |
| 4188 | + .get_link_ext_stats = bnxt_get_link_ext_stats, | |
| 4070 | 4189 | .get_eee = bnxt_get_eee, |
| 4071 | 4190 | .set_eee = bnxt_set_eee, |
| 4072 | 4191 | .get_module_info = bnxt_get_module_info, |
| 4073 | 4192 | .get_module_eeprom = bnxt_get_module_eeprom, |
| 4193 | + .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, | |
| 4074 | 4194 | .nway_reset = bnxt_nway_reset, |
| 4075 | 4195 | .set_phys_id = bnxt_set_phys_id, |
| 4076 | 4196 | .self_test = bnxt_self_test, |
| @@ -254,6 +254,8 @@ struct cmd_nums { · 253 unmodified lines | ||
| 254 | 254 | #define HWRM_PORT_DSC_DUMP 0xd9UL |
| 255 | 255 | #define HWRM_PORT_EP_TX_QCFG 0xdaUL |
| 256 | 256 | #define HWRM_PORT_EP_TX_CFG 0xdbUL |
| 257 | + #define HWRM_PORT_CFG 0xdcUL | |
| 258 | + #define HWRM_PORT_QCFG 0xddUL | |
| 257 | 259 | #define HWRM_TEMP_MONITOR_QUERY 0xe0UL |
| 258 | 260 | #define HWRM_REG_POWER_QUERY 0xe1UL |
| 259 | 261 | #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL |
| @@ -379,6 +381,8 @@ struct cmd_nums { · 119 unmodified lines | ||
| 379 | 381 | #define HWRM_FUNC_BACKING_STORE_QCAPS_V2 0x1a8UL |
| 380 | 382 | #define HWRM_FUNC_DBR_PACING_NQLIST_QUERY 0x1a9UL |
| 381 | 383 | #define HWRM_FUNC_DBR_RECOVERY_COMPLETED 0x1aaUL |
| 384 | + #define HWRM_FUNC_SYNCE_CFG 0x1abUL | |
| 385 | + #define HWRM_FUNC_SYNCE_QCFG 0x1acUL | |
| 382 | 386 | #define HWRM_SELFTEST_QLIST 0x200UL |
| 383 | 387 | #define HWRM_SELFTEST_EXEC 0x201UL |
| 384 | 388 | #define HWRM_SELFTEST_IRQ 0x202UL |
| @@ -417,6 +421,8 @@ struct cmd_nums { · 32 unmodified lines | ||
| 417 | 421 | #define HWRM_TF_SESSION_RESC_FREE 0x2ceUL |
| 418 | 422 | #define HWRM_TF_SESSION_RESC_FLUSH 0x2cfUL |
| 419 | 423 | #define HWRM_TF_SESSION_RESC_INFO 0x2d0UL |
| 424 | + #define HWRM_TF_SESSION_HOTUP_STATE_SET 0x2d1UL | |
| 425 | + #define HWRM_TF_SESSION_HOTUP_STATE_GET 0x2d2UL | |
| 420 | 426 | #define HWRM_TF_TBL_TYPE_GET 0x2daUL |
| 421 | 427 | #define HWRM_TF_TBL_TYPE_SET 0x2dbUL |
| 422 | 428 | #define HWRM_TF_TBL_TYPE_BULK_GET 0x2dcUL |
| @@ -440,6 +446,25 @@ struct cmd_nums { · 17 unmodified lines | ||
| 440 | 446 | #define HWRM_TF_GLOBAL_CFG_GET 0x2fdUL |
| 441 | 447 | #define HWRM_TF_IF_TBL_SET 0x2feUL |
| 442 | 448 | #define HWRM_TF_IF_TBL_GET 0x2ffUL |
| 449 | + #define HWRM_TFC_TBL_SCOPE_QCAPS 0x380UL | |
| 450 | + #define HWRM_TFC_TBL_SCOPE_ID_ALLOC 0x381UL | |
| 451 | + #define HWRM_TFC_TBL_SCOPE_CONFIG 0x382UL | |
| 452 | + #define HWRM_TFC_TBL_SCOPE_DECONFIG 0x383UL | |
| 453 | + #define HWRM_TFC_TBL_SCOPE_FID_ADD 0x384UL | |
| 454 | + #define HWRM_TFC_TBL_SCOPE_FID_REM 0x385UL | |
| 455 | + #define HWRM_TFC_TBL_SCOPE_POOL_ALLOC 0x386UL | |
| 456 | + #define HWRM_TFC_TBL_SCOPE_POOL_FREE 0x387UL | |
| 457 | + #define HWRM_TFC_SESSION_ID_ALLOC 0x388UL | |
| 458 | + #define HWRM_TFC_SESSION_FID_ADD 0x389UL | |
| 459 | + #define HWRM_TFC_SESSION_FID_REM 0x38aUL | |
| 460 | + #define HWRM_TFC_IDENT_ALLOC 0x38bUL | |
| 461 | + #define HWRM_TFC_IDENT_FREE 0x38cUL | |
| 462 | + #define HWRM_TFC_IDX_TBL_ALLOC 0x38dUL | |
| 463 | + #define HWRM_TFC_IDX_TBL_ALLOC_SET 0x38eUL | |
| 464 | + #define HWRM_TFC_IDX_TBL_SET 0x38fUL | |
| 465 | + #define HWRM_TFC_IDX_TBL_GET 0x390UL | |
| 466 | + #define HWRM_TFC_IDX_TBL_FREE 0x391UL | |
| 467 | + #define HWRM_TFC_GLOBAL_ID_ALLOC 0x392UL | |
| 443 | 468 | #define HWRM_SV 0x400UL |
| 444 | 469 | #define HWRM_DBG_READ_DIRECT 0xff10UL |
| 445 | 470 | #define HWRM_DBG_READ_INDIRECT 0xff11UL |
| @@ -546,8 +571,8 @@ struct hwrm_err_output { · 100 unmodified lines | ||
| 546 | 571 | #define HWRM_VERSION_MAJOR 1 |
| 547 | 572 | #define HWRM_VERSION_MINOR 10 |
| 548 | 573 | #define HWRM_VERSION_UPDATE 2 |
| 549 | −#define HWRM_VERSION_RSVD 95 | |
| 550 | −#define HWRM_VERSION_STR "1.10.2.95" | |
| 574 | +#define HWRM_VERSION_RSVD 118 | |
| 575 | +#define HWRM_VERSION_STR "1.10.2.118" | |
| 551 | 576 | |
| 552 | 577 | /* hwrm_ver_get_input (size:192b/24B) */ |
| 553 | 578 | struct hwrm_ver_get_input { |
| @@ -1657,6 +1682,10 @@ struct hwrm_func_qcaps_output { · 1103 unmodified lines | ||
| 1657 | 1682 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL |
| 1658 | 1683 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL |
| 1659 | 1684 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL |
| 1685 | + #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED 0x40UL | |
| 1686 | + #define FUNC_QCAPS_RESP_FLAGS_EXT2_SYNCE_SUPPORTED 0x80UL | |
| 1687 | + #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_V0_SUPPORTED 0x100UL | |
| 1688 | + #define FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED 0x200UL | |
| 1660 | 1689 | __le16 tunnel_disable_flag; |
| 1661 | 1690 | #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_VXLAN 0x1UL |
| 1662 | 1691 | #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_NGE 0x2UL |
| @@ -1804,7 +1833,20 @@ struct hwrm_func_qcfg_output { · 141 unmodified lines | ||
| 1804 | 1833 | #define FUNC_QCFG_RESP_MPC_CHNLS_TE_CFA_ENABLED 0x4UL |
| 1805 | 1834 | #define FUNC_QCFG_RESP_MPC_CHNLS_RE_CFA_ENABLED 0x8UL |
| 1806 | 1835 | #define FUNC_QCFG_RESP_MPC_CHNLS_PRIMATE_ENABLED 0x10UL |
| 1807 | − u8 unused_2[3]; | |
| 1836 | + u8 db_page_size; | |
| 1837 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_4KB 0x0UL | |
| 1838 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_8KB 0x1UL | |
| 1839 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_16KB 0x2UL | |
| 1840 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_32KB 0x3UL | |
| 1841 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_64KB 0x4UL | |
| 1842 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_128KB 0x5UL | |
| 1843 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_256KB 0x6UL | |
| 1844 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_512KB 0x7UL | |
| 1845 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_1MB 0x8UL | |
| 1846 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_2MB 0x9UL | |
| 1847 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_4MB 0xaUL | |
| 1848 | + #define FUNC_QCFG_RESP_DB_PAGE_SIZE_LAST FUNC_QCFG_RESP_DB_PAGE_SIZE_4MB | |
| 1849 | + u8 unused_2[2]; | |
| 1808 | 1850 | __le32 partition_min_bw; |
| 1809 | 1851 | #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_MASK 0xfffffffUL |
| 1810 | 1852 | #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_SFT 0 |
| @@ -1876,6 +1918,7 @@ struct hwrm_func_cfg_input { · 65 unmodified lines | ||
| 1876 | 1918 | #define FUNC_CFG_REQ_FLAGS_PPP_PUSH_MODE_DISABLE 0x10000000UL |
| 1877 | 1919 | #define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL |
| 1878 | 1920 | #define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL |
| 1921 | + #define FUNC_CFG_REQ_FLAGS_KEY_CTX_ASSETS_TEST 0x80000000UL | |
| 1879 | 1922 | __le32 enables; |
| 1880 | 1923 | #define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL |
| 1881 | 1924 | #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL |
| @@ -2021,12 +2064,26 @@ struct hwrm_func_cfg_input { · 139 unmodified lines | ||
| 2021 | 2064 | __le16 num_tx_key_ctxs; |
| 2022 | 2065 | __le16 num_rx_key_ctxs; |
| 2023 | 2066 | __le32 enables2; |
| 2024 | − #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL | |
| 2067 | + #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL | |
| 2068 | + #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL | |
| 2025 | 2069 | u8 port_kdnet_mode; |
| 2026 | 2070 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL |
| 2027 | 2071 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL |
| 2028 | 2072 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_LAST FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED |
| 2029 | − u8 unused_0[7]; | |
| 2073 | + u8 db_page_size; | |
| 2074 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_4KB 0x0UL | |
| 2075 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_8KB 0x1UL | |
| 2076 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_16KB 0x2UL | |
| 2077 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_32KB 0x3UL | |
| 2078 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_64KB 0x4UL | |
| 2079 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_128KB 0x5UL | |
| 2080 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_256KB 0x6UL | |
| 2081 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_512KB 0x7UL | |
| 2082 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_1MB 0x8UL | |
| 2083 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_2MB 0x9UL | |
| 2084 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_4MB 0xaUL | |
| 2085 | + #define FUNC_CFG_REQ_DB_PAGE_SIZE_LAST FUNC_CFG_REQ_DB_PAGE_SIZE_4MB | |
| 2086 | + u8 unused_0[6]; | |
| 2030 | 2087 | }; |
| 2031 | 2088 | |
| 2032 | 2089 | /* hwrm_func_cfg_output (size:128b/16B) */ |
| @@ -2060,10 +2117,9 @@ struct hwrm_func_qstats_input { · 27 unmodified lines | ||
| 2060 | 2117 | __le64 resp_addr; |
| 2061 | 2118 | __le16 fid; |
| 2062 | 2119 | u8 flags; |
| 2063 | − #define FUNC_QSTATS_REQ_FLAGS_UNUSED 0x0UL | |
| 2064 | − #define FUNC_QSTATS_REQ_FLAGS_ROCE_ONLY 0x1UL | |
| 2065 | − #define FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x2UL | |
| 2066 | − #define FUNC_QSTATS_REQ_FLAGS_LAST FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK | |
| 2120 | + #define FUNC_QSTATS_REQ_FLAGS_ROCE_ONLY 0x1UL | |
| 2121 | + #define FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x2UL | |
| 2122 | + #define FUNC_QSTATS_REQ_FLAGS_L2_ONLY 0x4UL | |
| 2067 | 2123 | u8 unused_0[5]; |
| 2068 | 2124 | }; |
| 2069 | 2125 | |
| @@ -2093,7 +2149,8 @@ struct hwrm_func_qstats_output { · 23 unmodified lines | ||
| 2093 | 2149 | __le64 rx_agg_bytes; |
| 2094 | 2150 | __le64 rx_agg_events; |
| 2095 | 2151 | __le64 rx_agg_aborts; |
| 2096 | − u8 unused_0[7]; | |
| 2152 | + u8 clear_seq; | |
| 2153 | + u8 unused_0[6]; | |
| 2097 | 2154 | u8 valid; |
| 2098 | 2155 | }; |
| 2099 | 2156 | |
| @@ -2106,10 +2163,8 @@ struct hwrm_func_qstats_ext_input { · 6 unmodified lines | ||
| 2106 | 2163 | __le64 resp_addr; |
| 2107 | 2164 | __le16 fid; |
| 2108 | 2165 | u8 flags; |
| 2109 | − #define FUNC_QSTATS_EXT_REQ_FLAGS_UNUSED 0x0UL | |
| 2110 | − #define FUNC_QSTATS_EXT_REQ_FLAGS_ROCE_ONLY 0x1UL | |
| 2111 | − #define FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x2UL | |
| 2112 | − #define FUNC_QSTATS_EXT_REQ_FLAGS_LAST FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK | |
| 2166 | + #define FUNC_QSTATS_EXT_REQ_FLAGS_ROCE_ONLY 0x1UL | |
| 2167 | + #define FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x2UL | |
| 2113 | 2168 | u8 unused_0[1]; |
| 2114 | 2169 | __le32 enables; |
| 2115 | 2170 | #define FUNC_QSTATS_EXT_REQ_ENABLES_SCHQ_ID 0x1UL |
| @@ -2210,6 +2265,7 @@ struct hwrm_func_drv_rgtr_input { · 94 unmodified lines | ||
| 2210 | 2265 | #define FUNC_DRV_RGTR_REQ_FLAGS_FAST_RESET_SUPPORT 0x80UL |
| 2211 | 2266 | #define FUNC_DRV_RGTR_REQ_FLAGS_RSS_STRICT_HASH_TYPE_SUPPORT 0x100UL |
| 2212 | 2267 | #define FUNC_DRV_RGTR_REQ_FLAGS_NPAR_1_2_SUPPORT 0x200UL |
| 2268 | + #define FUNC_DRV_RGTR_REQ_FLAGS_ASYM_QUEUE_CFG_SUPPORT 0x400UL | |
| 2213 | 2269 | __le32 enables; |
| 2214 | 2270 | #define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL |
| 2215 | 2271 | #define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL |
| @@ -3155,19 +3211,23 @@ struct hwrm_func_ptp_pin_qcfg_output { · 939 unmodified lines | ||
| 3155 | 3211 | #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT 0x4UL |
| 3156 | 3212 | #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT |
| 3157 | 3213 | u8 pin2_usage; |
| 3158 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL | |
| 3159 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL | |
| 3160 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL | |
| 3161 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL | |
| 3162 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT 0x4UL | |
| 3163 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT | |
| 3214 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL | |
| 3215 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL | |
| 3216 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL | |
| 3217 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL | |
| 3218 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT 0x4UL | |
| 3219 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL | |
| 3220 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL | |
| 3221 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT | |
| 3164 | 3222 | u8 pin3_usage; |
| 3165 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL | |
| 3166 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL | |
| 3167 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL | |
| 3168 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL | |
| 3169 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT 0x4UL | |
| 3170 | − #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT | |
| 3223 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL | |
| 3224 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL | |
| 3225 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL | |
| 3226 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL | |
| 3227 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT 0x4UL | |
| 3228 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL | |
| 3229 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL | |
| 3230 | + #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT | |
| 3171 | 3231 | u8 unused_0; |
| 3172 | 3232 | u8 valid; |
| 3173 | 3233 | }; |
| @@ -3215,23 +3275,27 @@ struct hwrm_func_ptp_pin_cfg_input { · 41 unmodified lines | ||
| 3215 | 3275 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED 0x1UL |
| 3216 | 3276 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED |
| 3217 | 3277 | u8 pin2_usage; |
| 3218 | − #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL | |
| 3219 | − #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL | |
| 3220 | − #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL | |
| 3221 | − #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL | |
| 3222 | − #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT 0x4UL | |
| 3223 | − #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT | |
| 3278 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL | |
| 3279 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL | |
| 3280 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL | |
| 3281 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL | |
| 3282 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT 0x4UL | |
| 3283 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL | |
| 3284 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL | |
| 3285 | + #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNCE_SECONDARY_CLOCK_OUT | |
| 3224 | 3286 | u8 pin3_state; |
| 3225 | 3287 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_DISABLED 0x0UL |
| 3226 | 3288 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED 0x1UL |
| 3227 | 3289 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED |
| 3228 | 3290 | u8 pin3_usage; |
| 3229 | − #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL | |
| 3230 | − #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL | |
| 3231 | − #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL | |
| 3232 | − #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL | |
| 3233 | − #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT 0x4UL | |
| 3234 | − #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT | |
| 3291 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL | |
| 3292 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL | |
| 3293 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL | |
| 3294 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL | |
| 3295 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT 0x4UL | |
| 3296 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNCE_PRIMARY_CLOCK_OUT 0x5UL | |
| 3297 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT 0x6UL | |
| 3298 | + #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNCE_SECONDARY_CLOCK_OUT | |
| 3235 | 3299 | u8 unused_0[4]; |
| 3236 | 3300 | }; |
| 3237 | 3301 | |
| @@ -3319,9 +3383,9 @@ struct hwrm_func_ptp_ts_query_output { · 81 unmodified lines | ||
| 3319 | 3383 | __le16 seq_id; |
| 3320 | 3384 | __le16 resp_len; |
| 3321 | 3385 | __le64 pps_event_ts; |
| 3322 | − __le64 ptm_res_local_ts; | |
| 3323 | − __le64 ptm_pmstr_ts; | |
| 3324 | − __le32 ptm_mstr_prop_dly; | |
| 3386 | + __le64 ptm_local_ts; | |
| 3387 | + __le64 ptm_system_ts; | |
| 3388 | + __le32 ptm_link_delay; | |
| 3325 | 3389 | u8 unused_0[3]; |
| 3326 | 3390 | u8 valid; |
| 3327 | 3391 | }; |
| @@ -3417,7 +3481,9 @@ struct hwrm_func_backing_store_cfg_v2_input { · 89 unmodified lines | ||
| 3417 | 3481 | #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID |
| 3418 | 3482 | __le16 instance; |
| 3419 | 3483 | __le32 flags; |
| 3420 | − #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_PREBOOT_MODE 0x1UL | |
| 3484 | + #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_PREBOOT_MODE 0x1UL | |
| 3485 | + #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_BS_CFG_ALL_DONE 0x2UL | |
| 3486 | + #define FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_BS_EXTEND 0x4UL | |
| 3421 | 3487 | __le64 page_dir; |
| 3422 | 3488 | __le32 num_entries; |
| 3423 | 3489 | __le16 entry_size; |
| @@ -3853,7 +3919,7 @@ struct hwrm_port_phy_qcfg_input { · 429 unmodified lines | ||
| 3853 | 3919 | u8 unused_0[6]; |
| 3854 | 3920 | }; |
| 3855 | 3921 | |
| 3856 | −/* hwrm_port_phy_qcfg_output (size:768b/96B) */ | |
| 3922 | +/* hwrm_port_phy_qcfg_output (size:832b/104B) */ | |
| 3857 | 3923 | struct hwrm_port_phy_qcfg_output { |
| 3858 | 3924 | __le16 error_code; |
| 3859 | 3925 | __le16 req_type; |
| @@ -4150,6 +4216,9 @@ struct hwrm_port_phy_qcfg_output { · 290 unmodified lines | ||
| 4150 | 4216 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_50GB 0x1UL |
| 4151 | 4217 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL |
| 4152 | 4218 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL |
| 4219 | + u8 link_down_reason; | |
| 4220 | + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL | |
| 4221 | + u8 unused_0[7]; | |
| 4153 | 4222 | u8 valid; |
| 4154 | 4223 | }; |
| 4155 | 4224 | |
| @@ -4422,9 +4491,7 @@ struct hwrm_port_qstats_input { · 266 unmodified lines | ||
| 4422 | 4491 | __le64 resp_addr; |
| 4423 | 4492 | __le16 port_id; |
| 4424 | 4493 | u8 flags; |
| 4425 | − #define PORT_QSTATS_REQ_FLAGS_UNUSED 0x0UL | |
| 4426 | − #define PORT_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 4427 | − #define PORT_QSTATS_REQ_FLAGS_LAST PORT_QSTATS_REQ_FLAGS_COUNTER_MASK | |
| 4494 | + #define PORT_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 4428 | 4495 | u8 unused_0[5]; |
| 4429 | 4496 | __le64 tx_stat_host_addr; |
| 4430 | 4497 | __le64 rx_stat_host_addr; |
| @@ -4552,9 +4619,7 @@ struct hwrm_port_qstats_ext_input { · 121 unmodified lines | ||
| 4552 | 4619 | __le16 tx_stat_size; |
| 4553 | 4620 | __le16 rx_stat_size; |
| 4554 | 4621 | u8 flags; |
| 4555 | − #define PORT_QSTATS_EXT_REQ_FLAGS_UNUSED 0x0UL | |
| 4556 | − #define PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 4557 | − #define PORT_QSTATS_EXT_REQ_FLAGS_LAST PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK | |
| 4622 | + #define PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 4558 | 4623 | u8 unused_0; |
| 4559 | 4624 | __le64 tx_stat_host_addr; |
| 4560 | 4625 | __le64 rx_stat_host_addr; |
| @@ -4613,9 +4678,7 @@ struct hwrm_port_ecn_qstats_input { · 52 unmodified lines | ||
| 4613 | 4678 | __le16 port_id; |
| 4614 | 4679 | __le16 ecn_stat_buf_size; |
| 4615 | 4680 | u8 flags; |
| 4616 | − #define PORT_ECN_QSTATS_REQ_FLAGS_UNUSED 0x0UL | |
| 4617 | − #define PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 4618 | − #define PORT_ECN_QSTATS_REQ_FLAGS_LAST PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK | |
| 4681 | + #define PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 4619 | 4682 | u8 unused_0[3]; |
| 4620 | 4683 | __le64 ecn_stat_host_addr; |
| 4621 | 4684 | }; |
| @@ -4814,8 +4877,9 @@ struct hwrm_port_phy_qcaps_output { · 192 unmodified lines | ||
| 4814 | 4877 | #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_100G 0x2UL |
| 4815 | 4878 | #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_200G 0x4UL |
| 4816 | 4879 | __le16 flags2; |
| 4817 | − #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL | |
| 4818 | − #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL | |
| 4880 | + #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL | |
| 4881 | + #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL | |
| 4882 | + #define PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED 0x4UL | |
| 4819 | 4883 | u8 internal_port_cnt; |
| 4820 | 4884 | u8 valid; |
| 4821 | 4885 | }; |
| @@ -4830,9 +4894,10 @@ struct hwrm_port_phy_i2c_read_input { · 8 unmodified lines | ||
| 4830 | 4894 | __le32 flags; |
| 4831 | 4895 | __le32 enables; |
| 4832 | 4896 | #define PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET 0x1UL |
| 4897 | + #define PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER 0x2UL | |
| 4833 | 4898 | __le16 port_id; |
| 4834 | 4899 | u8 i2c_slave_addr; |
| 4835 | − u8 unused_0; | |
| 4900 | + u8 bank_number; | |
| 4836 | 4901 | __le16 page_number; |
| 4837 | 4902 | __le16 page_offset; |
| 4838 | 4903 | u8 data_length; |
| @@ -6537,6 +6602,7 @@ struct hwrm_vnic_qcaps_output { · 1698 unmodified lines | ||
| 6537 | 6602 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV4_CAP 0x400000UL |
| 6538 | 6603 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV6_CAP 0x800000UL |
| 6539 | 6604 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP 0x1000000UL |
| 6605 | + #define VNIC_QCAPS_RESP_FLAGS_OUTERMOST_RSS_TRUSTED_VF_CAP 0x2000000UL | |
| 6540 | 6606 | __le16 max_aggs_supported; |
| 6541 | 6607 | u8 unused_1[5]; |
| 6542 | 6608 | u8 valid; |
| @@ -6702,6 +6768,53 @@ struct hwrm_vnic_rss_cfg_cmd_err { · 159 unmodified lines | ||
| 6702 | 6768 | u8 unused_0[7]; |
| 6703 | 6769 | }; |
| 6704 | 6770 | |
| 6771 | +/* hwrm_vnic_rss_qcfg_input (size:192b/24B) */ | |
| 6772 | +struct hwrm_vnic_rss_qcfg_input { | |
| 6773 | + __le16 req_type; | |
| 6774 | + __le16 cmpl_ring; | |
| 6775 | + __le16 seq_id; | |
| 6776 | + __le16 target_id; | |
| 6777 | + __le64 resp_addr; | |
| 6778 | + __le16 rss_ctx_idx; | |
| 6779 | + __le16 vnic_id; | |
| 6780 | + u8 unused_0[4]; | |
| 6781 | +}; | |
| 6782 | + | |
| 6783 | +/* hwrm_vnic_rss_qcfg_output (size:512b/64B) */ | |
| 6784 | +struct hwrm_vnic_rss_qcfg_output { | |
| 6785 | + __le16 error_code; | |
| 6786 | + __le16 req_type; | |
| 6787 | + __le16 seq_id; | |
| 6788 | + __le16 resp_len; | |
| 6789 | + __le32 hash_type; | |
| 6790 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_IPV4 0x1UL | |
| 6791 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_TCP_IPV4 0x2UL | |
| 6792 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_UDP_IPV4 0x4UL | |
| 6793 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_IPV6 0x8UL | |
| 6794 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_TCP_IPV6 0x10UL | |
| 6795 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_UDP_IPV6 0x20UL | |
| 6796 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_IPV6_FLOW_LABEL 0x40UL | |
| 6797 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_AH_SPI_IPV4 0x80UL | |
| 6798 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_ESP_SPI_IPV4 0x100UL | |
| 6799 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_AH_SPI_IPV6 0x200UL | |
| 6800 | + #define VNIC_RSS_QCFG_RESP_HASH_TYPE_ESP_SPI_IPV6 0x400UL | |
| 6801 | + u8 unused_0[4]; | |
| 6802 | + __le32 hash_key[10]; | |
| 6803 | + u8 hash_mode_flags; | |
| 6804 | + #define VNIC_RSS_QCFG_RESP_HASH_MODE_FLAGS_DEFAULT 0x1UL | |
| 6805 | + #define VNIC_RSS_QCFG_RESP_HASH_MODE_FLAGS_INNERMOST_4 0x2UL | |
| 6806 | + #define VNIC_RSS_QCFG_RESP_HASH_MODE_FLAGS_INNERMOST_2 0x4UL | |
| 6807 | + #define VNIC_RSS_QCFG_RESP_HASH_MODE_FLAGS_OUTERMOST_4 0x8UL | |
| 6808 | + #define VNIC_RSS_QCFG_RESP_HASH_MODE_FLAGS_OUTERMOST_2 0x10UL | |
| 6809 | + u8 ring_select_mode; | |
| 6810 | + #define VNIC_RSS_QCFG_RESP_RING_SELECT_MODE_TOEPLITZ 0x0UL | |
| 6811 | + #define VNIC_RSS_QCFG_RESP_RING_SELECT_MODE_XOR 0x1UL | |
| 6812 | + #define VNIC_RSS_QCFG_RESP_RING_SELECT_MODE_TOEPLITZ_CHECKSUM 0x2UL | |
| 6813 | + #define VNIC_RSS_QCFG_RESP_RING_SELECT_MODE_LAST VNIC_RSS_QCFG_RESP_RING_SELECT_MODE_TOEPLITZ_CHECKSUM | |
| 6814 | + u8 unused_1[5]; | |
| 6815 | + u8 valid; | |
| 6816 | +}; | |
| 6817 | + | |
| 6705 | 6818 | /* hwrm_vnic_plcmodes_cfg_input (size:320b/40B) */ |
| 6706 | 6819 | struct hwrm_vnic_plcmodes_cfg_input { |
| 6707 | 6820 | __le16 req_type; |
| @@ -6827,6 +6940,7 @@ struct hwrm_ring_alloc_input { · 119 unmodified lines | ||
| 6827 | 6940 | #define RING_ALLOC_REQ_FLAGS_RX_SOP_PAD 0x1UL |
| 6828 | 6941 | #define RING_ALLOC_REQ_FLAGS_DISABLE_CQ_OVERFLOW_DETECTION 0x2UL |
| 6829 | 6942 | #define RING_ALLOC_REQ_FLAGS_NQ_DBR_PACING 0x4UL |
| 6943 | + #define RING_ALLOC_REQ_FLAGS_TX_PKT_TS_CMPL_ENABLE 0x8UL | |
| 6830 | 6944 | __le64 page_tbl_addr; |
| 6831 | 6945 | __le32 fbo; |
| 6832 | 6946 | u8 page_size; |
| @@ -7626,7 +7740,10 @@ struct hwrm_cfa_ntuple_filter_alloc_input { · 793 unmodified lines | ||
| 7626 | 7740 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UNKNOWN 0x0UL |
| 7627 | 7741 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_TCP 0x6UL |
| 7628 | 7742 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP 0x11UL |
| 7629 | − #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP | |
| 7743 | + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_ICMP 0x1UL | |
| 7744 | + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_ICMPV6 0x3aUL | |
| 7745 | + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD 0xffUL | |
| 7746 | + #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD | |
| 7630 | 7747 | __le16 dst_id; |
| 7631 | 7748 | __le16 mirror_vnic_id; |
| 7632 | 7749 | u8 tunnel_type; |
| @@ -8337,6 +8454,7 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output { · 704 unmodified lines | ||
| 8337 | 8454 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_LAG_SUPPORTED 0x20000UL |
| 8338 | 8455 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_NO_L2CTX_SUPPORTED 0x40000UL |
| 8339 | 8456 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NIC_FLOW_STATS_SUPPORTED 0x80000UL |
| 8457 | + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED 0x100000UL | |
| 8340 | 8458 | u8 unused_0[3]; |
| 8341 | 8459 | u8 valid; |
| 8342 | 8460 | }; |
| @@ -8355,7 +8473,9 @@ struct hwrm_tunnel_dst_port_query_input { · 12 unmodified lines | ||
| 8355 | 8473 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL |
| 8356 | 8474 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL |
| 8357 | 8475 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL |
| 8358 | − #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 | |
| 8476 | + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_CUSTOM_GRE 0xdUL | |
| 8477 | + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_ECPRI 0xeUL | |
| 8478 | + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_ECPRI | |
| 8359 | 8479 | u8 unused_0[7]; |
| 8360 | 8480 | }; |
| 8361 | 8481 | |
| @@ -8367,7 +8487,16 @@ struct hwrm_tunnel_dst_port_query_output { · 5 unmodified lines | ||
| 8367 | 8487 | __le16 resp_len; |
| 8368 | 8488 | __le16 tunnel_dst_port_id; |
| 8369 | 8489 | __be16 tunnel_dst_port_val; |
| 8370 | − u8 unused_0[3]; | |
| 8490 | + u8 upar_in_use; | |
| 8491 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR0 0x1UL | |
| 8492 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR1 0x2UL | |
| 8493 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR2 0x4UL | |
| 8494 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR3 0x8UL | |
| 8495 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR4 0x10UL | |
| 8496 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR5 0x20UL | |
| 8497 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR6 0x40UL | |
| 8498 | + #define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR7 0x80UL | |
| 8499 | + u8 unused_0[2]; | |
| 8371 | 8500 | u8 valid; |
| 8372 | 8501 | }; |
| 8373 | 8502 | |
| @@ -8385,7 +8514,9 @@ struct hwrm_tunnel_dst_port_alloc_input { · 11 unmodified lines | ||
| 8385 | 8514 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL |
| 8386 | 8515 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL |
| 8387 | 8516 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL |
| 8388 | − #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 | |
| 8517 | + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_CUSTOM_GRE 0xdUL | |
| 8518 | + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_ECPRI 0xeUL | |
| 8519 | + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_ECPRI | |
| 8389 | 8520 | u8 unused_0; |
| 8390 | 8521 | __be16 tunnel_dst_port_val; |
| 8391 | 8522 | u8 unused_1[4]; |
| @@ -8398,7 +8529,21 @@ struct hwrm_tunnel_dst_port_alloc_output { · 6 unmodified lines | ||
| 8398 | 8529 | __le16 seq_id; |
| 8399 | 8530 | __le16 resp_len; |
| 8400 | 8531 | __le16 tunnel_dst_port_id; |
| 8401 | − u8 unused_0[5]; | |
| 8532 | + u8 error_info; | |
| 8533 | + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_SUCCESS 0x0UL | |
| 8534 | + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ALLOCATED 0x1UL | |
| 8535 | + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE 0x2UL | |
| 8536 | + #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE | |
| 8537 | + u8 upar_in_use; | |
| 8538 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR0 0x1UL | |
| 8539 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR1 0x2UL | |
| 8540 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR2 0x4UL | |
| 8541 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR3 0x8UL | |
| 8542 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR4 0x10UL | |
| 8543 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR5 0x20UL | |
| 8544 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR6 0x40UL | |
| 8545 | + #define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR7 0x80UL | |
| 8546 | + u8 unused_0[3]; | |
| 8402 | 8547 | u8 valid; |
| 8403 | 8548 | }; |
| 8404 | 8549 | |
| @@ -8416,7 +8561,9 @@ struct hwrm_tunnel_dst_port_free_input { · 11 unmodified lines | ||
| 8416 | 8561 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL |
| 8417 | 8562 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL |
| 8418 | 8563 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL |
| 8419 | − #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 | |
| 8564 | + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_CUSTOM_GRE 0xdUL | |
| 8565 | + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_ECPRI 0xeUL | |
| 8566 | + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_ECPRI | |
| 8420 | 8567 | u8 unused_0; |
| 8421 | 8568 | __le16 tunnel_dst_port_id; |
| 8422 | 8569 | u8 unused_1[4]; |
| @@ -8428,7 +8575,12 @@ struct hwrm_tunnel_dst_port_free_output { · 5 unmodified lines | ||
| 8428 | 8575 | __le16 req_type; |
| 8429 | 8576 | __le16 seq_id; |
| 8430 | 8577 | __le16 resp_len; |
| 8431 | − u8 unused_1[7]; | |
| 8578 | + u8 error_info; | |
| 8579 | + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_SUCCESS 0x0UL | |
| 8580 | + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_ERR_NOT_OWNER 0x1UL | |
| 8581 | + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_ERR_NOT_ALLOCATED 0x2UL | |
| 8582 | + #define TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_FREE_RESP_ERROR_INFO_ERR_NOT_ALLOCATED | |
| 8583 | + u8 unused_1[6]; | |
| 8432 | 8584 | u8 valid; |
| 8433 | 8585 | }; |
| 8434 | 8586 | |
| @@ -8686,9 +8838,7 @@ struct hwrm_stat_generic_qstats_input { · 251 unmodified lines | ||
| 8686 | 8838 | __le64 resp_addr; |
| 8687 | 8839 | __le16 generic_stat_size; |
| 8688 | 8840 | u8 flags; |
| 8689 | − #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER 0x0UL | |
| 8690 | − #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 8691 | − #define STAT_GENERIC_QSTATS_REQ_FLAGS_LAST STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK | |
| 8841 | + #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | |
| 8692 | 8842 | u8 unused_0[5]; |
| 8693 | 8843 | __le64 generic_stat_host_addr; |
| 8694 | 8844 | }; |
| @@ -10202,6 +10352,7 @@ struct fw_status_reg { · 1507 unmodified lines | ||
| 10202 | 10352 | #define FW_STATUS_REG_SHUTDOWN 0x100000UL |
| 10203 | 10353 | #define FW_STATUS_REG_CRASHED_NO_MASTER 0x200000UL |
| 10204 | 10354 | #define FW_STATUS_REG_RECOVERING 0x400000UL |
| 10355 | + #define FW_STATUS_REG_MANU_DEBUG_STATUS 0x800000UL | |
| 10205 | 10356 | }; |
| 10206 | 10357 | |
| 10207 | 10358 | /* hcomm_status (size:64b/8B) */ |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/net_tstamp.h> |
| 15 | 15 | #include <linux/timekeeping.h> |
| 16 | 16 | #include <linux/ptp_classify.h> |
| 17 | +#include <linux/clocksource.h> | |
| 17 | 18 | #include "bnxt_hsi.h" |
| 18 | 19 | #include "bnxt.h" |
| 19 | 20 | #include "bnxt_hwrm.h" |
| @@ -204,24 +205,33 @@ static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) · 184 unmodified lines | ||
| 204 | 205 | return 0; |
| 205 | 206 | } |
| 206 | 207 | |
| 207 | −static int bnxt_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb) | |
| 208 | +static int bnxt_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) | |
| 208 | 209 | { |
| 209 | 210 | struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg, |
| 210 | 211 | ptp_info); |
| 211 | 212 | struct hwrm_port_mac_cfg_input *req; |
| 212 | 213 | struct bnxt *bp = ptp->bp; |
| 213 | − int rc; | |
| 214 | + int rc = 0; | |
| 214 | 215 | |
| 215 | − rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); | |
| 216 | − if (rc) | |
| 217 | − return rc; | |
| 216 | + if (!(ptp->bp->fw_cap & BNXT_FW_CAP_PTP_RTC)) { | |
| 217 | + spin_lock_bh(&ptp->ptp_lock); | |
| 218 | + timecounter_read(&ptp->tc); | |
| 219 | + ptp->cc.mult = adjust_by_scaled_ppm(ptp->cmult, scaled_ppm); | |
| 220 | + spin_unlock_bh(&ptp->ptp_lock); | |
| 221 | + } else { | |
| 222 | + s32 ppb = scaled_ppm_to_ppb(scaled_ppm); | |
| 218 | 223 | |
| 219 | − req->ptp_freq_adj_ppb = cpu_to_le32(ppb); | |
| 220 | − req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB); | |
| 221 | − rc = hwrm_req_send(ptp->bp, req); | |
| 222 | − if (rc) | |
| 223 | − netdev_err(ptp->bp->dev, | |
| 224 | − "ptp adjfreq failed. rc = %d\n", rc); | |
| 224 | + rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); | |
| 225 | + if (rc) | |
| 226 | + return rc; | |
| 227 | + | |
| 228 | + req->ptp_freq_adj_ppb = cpu_to_le32(ppb); | |
| 229 | + req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB); | |
| 230 | + rc = hwrm_req_send(ptp->bp, req); | |
| 231 | + if (rc) | |
| 232 | + netdev_err(ptp->bp->dev, | |
| 233 | + "ptp adjfine failed. rc = %d\n", rc); | |
| 234 | + } | |
| 225 | 235 | return rc; |
| 226 | 236 | } |
| 227 | 237 | |
| @@ -749,7 +759,7 @@ static const struct ptp_clock_info bnxt_ptp_caps = { · 521 unmodified lines | ||
| 749 | 759 | .n_per_out = 0, |
| 750 | 760 | .n_pins = 0, |
| 751 | 761 | .pps = 0, |
| 752 | − .adjfreq = bnxt_ptp_adjfreq, | |
| 762 | + .adjfine = bnxt_ptp_adjfine, | |
| 753 | 763 | .adjtime = bnxt_ptp_adjtime, |
| 754 | 764 | .do_aux_work = bnxt_ptp_ts_aux_work, |
| 755 | 765 | .gettimex64 = bnxt_ptp_gettimex, |
| @@ -846,8 +856,9 @@ static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc) · 90 unmodified lines | ||
| 846 | 856 | memset(&ptp->cc, 0, sizeof(ptp->cc)); |
| 847 | 857 | ptp->cc.read = bnxt_cc_read; |
| 848 | 858 | ptp->cc.mask = CYCLECOUNTER_MASK(48); |
| 849 | − ptp->cc.shift = 0; | |
| 850 | − ptp->cc.mult = 1; | |
| 859 | + ptp->cc.shift = BNXT_CYCLES_SHIFT; | |
| 860 | + ptp->cc.mult = clocksource_khz2mult(BNXT_DEVCLK_FREQ, ptp->cc.shift); | |
| 861 | + ptp->cmult = ptp->cc.mult; | |
| 851 | 862 | ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD; |
| 852 | 863 | } |
| 853 | 864 | if (init_tc) |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | ||
| 17 | 17 | #define BNXT_PTP_GRC_WIN_BASE 0x6000 |
| 18 | 18 | |
| 19 | 19 | #define BNXT_MAX_PHC_DRIFT 31000000 |
| 20 | +#define BNXT_CYCLES_SHIFT 23 | |
| 21 | +#define BNXT_DEVCLK_FREQ 1000000 | |
| 20 | 22 | #define BNXT_LO_TIMER_MASK 0x0000ffffffffUL |
| 21 | 23 | #define BNXT_HI_TIMER_MASK 0xffff00000000UL |
| 22 | 24 | |
| @@ -88,8 +90,9 @@ struct bnxt_ptp_cfg { · 65 unmodified lines | ||
| 88 | 90 | u64 old_time; |
| 89 | 91 | unsigned long next_period; |
| 90 | 92 | unsigned long next_overflow_check; |
| 91 | − /* 48-bit PHC overflows in 78 hours. Check overflow every 19 hours. */ | |
| 92 | − #define BNXT_PHC_OVERFLOW_PERIOD (19 * 3600 * HZ) | |
| 93 | + u32 cmult; | |
| 94 | + /* a 23b shift cyclecounter will overflow in ~36 mins. Check overflow every 18 mins. */ | |
| 95 | + #define BNXT_PHC_OVERFLOW_PERIOD (18 * 60 * HZ) | |
| 93 | 96 | |
| 94 | 97 | u16 tx_seqid; |
| 95 | 98 | u16 tx_hdr_off; |
| @@ -117,24 +117,6 @@ static inline void dmadesc_set(struct bcmgenet_priv *priv, · 116 unmodified lines | ||
| 117 | 117 | dmadesc_set_length_status(priv, d, val); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | −static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv, | |
| 121 | − void __iomem *d) | |
| 122 | −{ | |
| 123 | − dma_addr_t addr; | |
| 124 | − | |
| 125 | − addr = bcmgenet_readl(d + DMA_DESC_ADDRESS_LO); | |
| 126 | − | |
| 127 | − /* Register writes to GISB bus can take couple hundred nanoseconds | |
| 128 | − * and are done for each packet, save these expensive writes unless | |
| 129 | − * the platform is explicitly configured for 64-bits/LPAE. | |
| 130 | − */ | |
| 131 | −#ifdef CONFIG_PHYS_ADDR_T_64BIT | |
| 132 | − if (priv->hw_params->flags & GENET_HAS_40BITS) | |
| 133 | − addr |= (u64)bcmgenet_readl(d + DMA_DESC_ADDRESS_HI) << 32; | |
| 134 | −#endif | |
| 135 | − return addr; | |
| 136 | −} | |
| 137 | − | |
| 138 | 120 | #define GENET_VER_FMT "%1d.%1d EPHY: 0x%04x" |
| 139 | 121 | |
| 140 | 122 | #define GENET_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ |
| @@ -1387,7 +1369,8 @@ static int bcmgenet_validate_flow(struct net_device *dev, · 1246 unmodified lines | ||
| 1387 | 1369 | struct ethtool_usrip4_spec *l4_mask; |
| 1388 | 1370 | struct ethhdr *eth_mask; |
| 1389 | 1371 | |
| 1390 | − if (cmd->fs.location >= MAX_NUM_OF_FS_RULES) { | |
| 1372 | + if (cmd->fs.location >= MAX_NUM_OF_FS_RULES && | |
| 1373 | + cmd->fs.location != RX_CLS_LOC_ANY) { | |
| 1391 | 1374 | netdev_err(dev, "rxnfc: Invalid location (%d)\n", |
| 1392 | 1375 | cmd->fs.location); |
| 1393 | 1376 | return -EINVAL; |
| @@ -1452,7 +1435,7 @@ static int bcmgenet_insert_flow(struct net_device *dev, · 58 unmodified lines | ||
| 1452 | 1435 | { |
| 1453 | 1436 | struct bcmgenet_priv *priv = netdev_priv(dev); |
| 1454 | 1437 | struct bcmgenet_rxnfc_rule *loc_rule; |
| 1455 | − int err; | |
| 1438 | + int err, i; | |
| 1456 | 1439 | |
| 1457 | 1440 | if (priv->hw_params->hfb_filter_size < 128) { |
| 1458 | 1441 | netdev_err(dev, "rxnfc: Not supported by this device\n"); |
| @@ -1470,7 +1453,29 @@ static int bcmgenet_insert_flow(struct net_device *dev, · 11 unmodified lines | ||
| 1470 | 1453 | if (err) |
| 1471 | 1454 | return err; |
| 1472 | 1455 | |
| 1473 | − loc_rule = &priv->rxnfc_rules[cmd->fs.location]; | |
| 1456 | + if (cmd->fs.location == RX_CLS_LOC_ANY) { | |
| 1457 | + list_for_each_entry(loc_rule, &priv->rxnfc_list, list) { | |
| 1458 | + cmd->fs.location = loc_rule->fs.location; | |
| 1459 | + err = memcmp(&loc_rule->fs, &cmd->fs, | |
| 1460 | + sizeof(struct ethtool_rx_flow_spec)); | |
| 1461 | + if (!err) | |
| 1462 | + /* rule exists so return current location */ | |
| 1463 | + return 0; | |
| 1464 | + } | |
| 1465 | + for (i = 0; i < MAX_NUM_OF_FS_RULES; i++) { | |
| 1466 | + loc_rule = &priv->rxnfc_rules[i]; | |
| 1467 | + if (loc_rule->state == BCMGENET_RXNFC_STATE_UNUSED) { | |
| 1468 | + cmd->fs.location = i; | |
| 1469 | + break; | |
| 1470 | + } | |
| 1471 | + } | |
| 1472 | + if (i == MAX_NUM_OF_FS_RULES) { | |
| 1473 | + cmd->fs.location = RX_CLS_LOC_ANY; | |
| 1474 | + return -ENOSPC; | |
| 1475 | + } | |
| 1476 | + } else { | |
| 1477 | + loc_rule = &priv->rxnfc_rules[cmd->fs.location]; | |
| 1478 | + } | |
| 1474 | 1479 | if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) |
| 1475 | 1480 | bcmgenet_hfb_disable_filter(priv, cmd->fs.location); |
| 1476 | 1481 | if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { |
| @@ -1583,7 +1588,7 @@ static int bcmgenet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, · 106 unmodified lines | ||
| 1583 | 1588 | break; |
| 1584 | 1589 | case ETHTOOL_GRXCLSRLCNT: |
| 1585 | 1590 | cmd->rule_cnt = bcmgenet_get_num_flows(priv); |
| 1586 | − cmd->data = MAX_NUM_OF_FS_RULES; | |
| 1591 | + cmd->data = MAX_NUM_OF_FS_RULES | RX_CLS_LOC_SPECIAL; | |
| 1587 | 1592 | break; |
| 1588 | 1593 | case ETHTOOL_GRXCLSRULE: |
| 1589 | 1594 | err = bcmgenet_get_flow(dev, cmd, cmd->fs.location); |
| @@ -72,7 +72,6 @@ static void bcmgenet_mac_config(struct net_device *dev) · 71 unmodified lines | ||
| 72 | 72 | * Receive clock is provided by the PHY. |
| 73 | 73 | */ |
| 74 | 74 | reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); |
| 75 | − reg &= ~OOB_DISABLE; | |
| 76 | 75 | reg |= RGMII_LINK; |
| 77 | 76 | bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); |
| 78 | 77 | |
| @@ -95,10 +94,18 @@ static void bcmgenet_mac_config(struct net_device *dev) · 16 unmodified lines | ||
| 95 | 94 | */ |
| 96 | 95 | void bcmgenet_mii_setup(struct net_device *dev) |
| 97 | 96 | { |
| 97 | + struct bcmgenet_priv *priv = netdev_priv(dev); | |
| 98 | 98 | struct phy_device *phydev = dev->phydev; |
| 99 | + u32 reg; | |
| 99 | 100 | |
| 100 | − if (phydev->link) | |
| 101 | + if (phydev->link) { | |
| 101 | 102 | bcmgenet_mac_config(dev); |
| 103 | + } else { | |
| 104 | + reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); | |
| 105 | + reg &= ~RGMII_LINK; | |
| 106 | + bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); | |
| 107 | + } | |
| 108 | + | |
| 102 | 109 | phy_print_status(phydev); |
| 103 | 110 | } |
| 104 | 111 | |
| @@ -266,18 +273,20 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) · 161 unmodified lines | ||
| 266 | 273 | (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); |
| 267 | 274 | |
| 268 | 275 | /* This is an external PHY (xMII), so we need to enable the RGMII |
| 269 | − * block for the interface to work | |
| 276 | + * block for the interface to work, unconditionally clear the | |
| 277 | + * Out-of-band disable since we do not need it. | |
| 270 | 278 | */ |
| 279 | + reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); | |
| 280 | + reg &= ~OOB_DISABLE; | |
| 271 | 281 | if (priv->ext_phy) { |
| 272 | − reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); | |
| 273 | 282 | reg &= ~ID_MODE_DIS; |
| 274 | 283 | reg |= id_mode_dis; |
| 275 | 284 | if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) |
| 276 | 285 | reg |= RGMII_MODE_EN_V123; |
| 277 | 286 | else |
| 278 | 287 | reg |= RGMII_MODE_EN; |
| 279 | − bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); | |
| 280 | 288 | } |
| 289 | + bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); | |
| 281 | 290 | |
| 282 | 291 | if (init) |
| 283 | 292 | dev_info(kdev, "configuring instance for %s\n", phy_name); |
| @@ -6179,34 +6179,26 @@ static int tg3_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) · 6178 unmodified lines | ||
| 6179 | 6179 | return 0; |
| 6180 | 6180 | } |
| 6181 | 6181 | |
| 6182 | −static int tg3_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) | |
| 6182 | +static int tg3_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) | |
| 6183 | 6183 | { |
| 6184 | 6184 | struct tg3 *tp = container_of(ptp, struct tg3, ptp_info); |
| 6185 | − bool neg_adj = false; | |
| 6186 | − u32 correction = 0; | |
| 6187 | − | |
| 6188 | − if (ppb < 0) { | |
| 6189 | − neg_adj = true; | |
| 6190 | − ppb = -ppb; | |
| 6191 | − } | |
| 6185 | + u64 correction; | |
| 6186 | + bool neg_adj; | |
| 6192 | 6187 | |
| 6193 | 6188 | /* Frequency adjustment is performed using hardware with a 24 bit |
| 6194 | 6189 | * accumulator and a programmable correction value. On each clk, the |
| 6195 | 6190 | * correction value gets added to the accumulator and when it |
| 6196 | 6191 | * overflows, the time counter is incremented/decremented. |
| 6197 | − * | |
| 6198 | − * So conversion from ppb to correction value is | |
| 6199 | − * ppb * (1 << 24) / 1000000000 | |
| 6200 | 6192 | */ |
| 6201 | − correction = div_u64((u64)ppb * (1 << 24), 1000000000ULL) & | |
| 6202 | − TG3_EAV_REF_CLK_CORRECT_MASK; | |
| 6193 | + neg_adj = diff_by_scaled_ppm(1 << 24, scaled_ppm, &correction); | |
| 6203 | 6194 | |
| 6204 | 6195 | tg3_full_lock(tp, 0); |
| 6205 | 6196 | |
| 6206 | 6197 | if (correction) |
| 6207 | 6198 | tw32(TG3_EAV_REF_CLK_CORRECT_CTL, |
| 6208 | 6199 | TG3_EAV_REF_CLK_CORRECT_EN | |
| 6209 | − (neg_adj ? TG3_EAV_REF_CLK_CORRECT_NEG : 0) | correction); | |
| 6200 | + (neg_adj ? TG3_EAV_REF_CLK_CORRECT_NEG : 0) | | |
| 6201 | + ((u32)correction & TG3_EAV_REF_CLK_CORRECT_MASK)); | |
| 6210 | 6202 | else |
| 6211 | 6203 | tw32(TG3_EAV_REF_CLK_CORRECT_CTL, 0); |
| 6212 | 6204 | |
| @@ -6330,7 +6322,7 @@ static const struct ptp_clock_info tg3_ptp_caps = { · 117 unmodified lines | ||
| 6330 | 6322 | .n_per_out = 1, |
| 6331 | 6323 | .n_pins = 0, |
| 6332 | 6324 | .pps = 0, |
| 6333 | − .adjfreq = tg3_ptp_adjfreq, | |
| 6325 | + .adjfine = tg3_ptp_adjfine, | |
| 6334 | 6326 | .adjtime = tg3_ptp_adjtime, |
| 6335 | 6327 | .gettimex64 = tg3_ptp_gettimex, |
| 6336 | 6328 | .settime64 = tg3_ptp_settime, |
| @@ -18,15 +18,43 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | /* BFA state machine interfaces */ |
| 20 | 20 | |
| 21 | −typedef void (*bfa_sm_t)(void *sm, int event); | |
| 22 | − | |
| 23 | 21 | /* For converting from state machine function to state encoding. */ |
| 24 | −struct bfa_sm_table { | |
| 25 | − bfa_sm_t sm; /*!< state machine function */ | |
| 26 | − int state; /*!< state machine encoding */ | |
| 27 | − char *name; /*!< state name for display */ | |
| 28 | −}; | |
| 29 | −#define BFA_SM(_sm) ((bfa_sm_t)(_sm)) | |
| 22 | +#define BFA_SM_TABLE(n, s, e, t) \ | |
| 23 | +struct s; \ | |
| 24 | +enum e; \ | |
| 25 | +typedef void (*t)(struct s *, enum e); \ | |
| 26 | + \ | |
| 27 | +struct n ## _sm_table_s { \ | |
| 28 | + t sm; /* state machine function */ \ | |
| 29 | + int state; /* state machine encoding */ \ | |
| 30 | + char *name; /* state name for display */ \ | |
| 31 | +}; \ | |
| 32 | + \ | |
| 33 | +static inline int \ | |
| 34 | +n ## _sm_to_state(struct n ## _sm_table_s *smt, t sm) \ | |
| 35 | +{ \ | |
| 36 | + int i = 0; \ | |
| 37 | + \ | |
| 38 | + while (smt[i].sm && smt[i].sm != sm) \ | |
| 39 | + i++; \ | |
| 40 | + return smt[i].state; \ | |
| 41 | +} | |
| 42 | + | |
| 43 | +BFA_SM_TABLE(iocpf, bfa_iocpf, iocpf_event, bfa_fsm_iocpf_t) | |
| 44 | +BFA_SM_TABLE(ioc, bfa_ioc, ioc_event, bfa_fsm_ioc_t) | |
| 45 | +BFA_SM_TABLE(cmdq, bfa_msgq_cmdq, cmdq_event, bfa_fsm_msgq_cmdq_t) | |
| 46 | +BFA_SM_TABLE(rspq, bfa_msgq_rspq, rspq_event, bfa_fsm_msgq_rspq_t) | |
| 47 | + | |
| 48 | +BFA_SM_TABLE(ioceth, bna_ioceth, bna_ioceth_event, bna_fsm_ioceth_t) | |
| 49 | +BFA_SM_TABLE(enet, bna_enet, bna_enet_event, bna_fsm_enet_t) | |
| 50 | +BFA_SM_TABLE(ethport, bna_ethport, bna_ethport_event, bna_fsm_ethport_t) | |
| 51 | +BFA_SM_TABLE(tx, bna_tx, bna_tx_event, bna_fsm_tx_t) | |
| 52 | +BFA_SM_TABLE(rxf, bna_rxf, bna_rxf_event, bna_fsm_rxf_t) | |
| 53 | +BFA_SM_TABLE(rx, bna_rx, bna_rx_event, bna_fsm_rx_t) | |
| 54 | + | |
| 55 | +#undef BFA_SM_TABLE | |
| 56 | + | |
| 57 | +#define BFA_SM(_sm) (_sm) | |
| 30 | 58 | |
| 31 | 59 | /* State machine with entry actions. */ |
| 32 | 60 | typedef void (*bfa_fsm_t)(void *fsm, int event); |
| @@ -41,24 +69,12 @@ typedef void (*bfa_fsm_t)(void *fsm, int event); · 8 unmodified lines | ||
| 41 | 69 | static void oc ## _sm_ ## st ## _entry(otype * fsm) |
| 42 | 70 | |
| 43 | 71 | #define bfa_fsm_set_state(_fsm, _state) do { \ |
| 44 | − (_fsm)->fsm = (bfa_fsm_t)(_state); \ | |
| 72 | + (_fsm)->fsm = (_state); \ | |
| 45 | 73 | _state ## _entry(_fsm); \ |
| 46 | 74 | } while (0) |
| 47 | 75 | |
| 48 | 76 | #define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event))) |
| 49 | −#define bfa_fsm_cmp_state(_fsm, _state) \ | |
| 50 | − ((_fsm)->fsm == (bfa_fsm_t)(_state)) | |
| 51 | − | |
| 52 | −static inline int | |
| 53 | −bfa_sm_to_state(const struct bfa_sm_table *smt, bfa_sm_t sm) | |
| 54 | −{ | |
| 55 | − int i = 0; | |
| 56 | − | |
| 57 | − while (smt[i].sm && smt[i].sm != sm) | |
| 58 | − i++; | |
| 59 | − return smt[i].state; | |
| 60 | −} | |
| 61 | − | |
| 77 | +#define bfa_fsm_cmp_state(_fsm, _state) ((_fsm)->fsm == (_state)) | |
| 62 | 78 | /* Generic wait counter. */ |
| 63 | 79 | |
| 64 | 80 | typedef void (*bfa_wc_resume_t) (void *cbarg); |
| @@ -114,7 +114,7 @@ bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event); · 113 unmodified lines | ||
| 114 | 114 | bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event); |
| 115 | 115 | bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc, enum ioc_event); |
| 116 | 116 | |
| 117 | −static struct bfa_sm_table ioc_sm_table[] = { | |
| 117 | +static struct ioc_sm_table_s ioc_sm_table[] = { | |
| 118 | 118 | {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, |
| 119 | 119 | {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, |
| 120 | 120 | {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING}, |
| @@ -183,7 +183,7 @@ bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf, · 62 unmodified lines | ||
| 183 | 183 | enum iocpf_event); |
| 184 | 184 | bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf, enum iocpf_event); |
| 185 | 185 | |
| 186 | −static struct bfa_sm_table iocpf_sm_table[] = { | |
| 186 | +static struct iocpf_sm_table_s iocpf_sm_table[] = { | |
| 187 | 187 | {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET}, |
| 188 | 188 | {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH}, |
| 189 | 189 | {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH}, |
| @@ -2860,12 +2860,12 @@ static enum bfa_ioc_state · 2670 unmodified lines | ||
| 2860 | 2860 | bfa_ioc_get_state(struct bfa_ioc *ioc) |
| 2861 | 2861 | { |
| 2862 | 2862 | enum bfa_iocpf_state iocpf_st; |
| 2863 | − enum bfa_ioc_state ioc_st = bfa_sm_to_state(ioc_sm_table, ioc->fsm); | |
| 2863 | + enum bfa_ioc_state ioc_st = ioc_sm_to_state(ioc_sm_table, ioc->fsm); | |
| 2864 | 2864 | |
| 2865 | 2865 | if (ioc_st == BFA_IOC_ENABLING || |
| 2866 | 2866 | ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) { |
| 2867 | 2867 | |
| 2868 | − iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); | |
| 2868 | + iocpf_st = iocpf_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); | |
| 2869 | 2869 | |
| 2870 | 2870 | switch (iocpf_st) { |
| 2871 | 2871 | case BFA_IOCPF_SEMWAIT: |
| @@ -2983,7 +2983,7 @@ bfa_nw_iocpf_timeout(struct bfa_ioc *ioc) · 111 unmodified lines | ||
| 2983 | 2983 | { |
| 2984 | 2984 | enum bfa_iocpf_state iocpf_st; |
| 2985 | 2985 | |
| 2986 | − iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); | |
| 2986 | + iocpf_st = iocpf_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); | |
| 2987 | 2987 | |
| 2988 | 2988 | if (iocpf_st == BFA_IOCPF_HWINIT) |
| 2989 | 2989 | bfa_ioc_poll_fwinit(ioc); |
| @@ -147,16 +147,20 @@ struct bfa_ioc_notify { · 146 unmodified lines | ||
| 147 | 147 | (__notify)->cbarg = (__cbarg); \ |
| 148 | 148 | } while (0) |
| 149 | 149 | |
| 150 | +enum iocpf_event; | |
| 151 | + | |
| 150 | 152 | struct bfa_iocpf { |
| 151 | − bfa_fsm_t fsm; | |
| 153 | + void (*fsm)(struct bfa_iocpf *s, enum iocpf_event e); | |
| 152 | 154 | struct bfa_ioc *ioc; |
| 153 | 155 | bool fw_mismatch_notified; |
| 154 | 156 | bool auto_recover; |
| 155 | 157 | u32 poll_time; |
| 156 | 158 | }; |
| 157 | 159 | |
| 160 | +enum ioc_event; | |
| 161 | + | |
| 158 | 162 | struct bfa_ioc { |
| 159 | − bfa_fsm_t fsm; | |
| 163 | + void (*fsm)(struct bfa_ioc *s, enum ioc_event e); | |
| 160 | 164 | struct bfa *bfa; |
| 161 | 165 | struct bfa_pcidev pcidev; |
| 162 | 166 | struct timer_list ioc_timer; |
| @@ -202,7 +202,6 @@ static void · 201 unmodified lines | ||
| 202 | 202 | __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd) |
| 203 | 203 | { |
| 204 | 204 | size_t len = cmd->msg_size; |
| 205 | − int num_entries = 0; | |
| 206 | 205 | size_t to_copy; |
| 207 | 206 | u8 *src, *dst; |
| 208 | 207 | |
| @@ -219,7 +218,6 @@ __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd) · 10 unmodified lines | ||
| 219 | 218 | BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth); |
| 220 | 219 | dst = (u8 *)cmdq->addr.kva; |
| 221 | 220 | dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE); |
| 222 | − num_entries++; | |
| 223 | 221 | } |
| 224 | 222 | |
| 225 | 223 | } |
| @@ -55,8 +55,10 @@ enum bfa_msgq_cmdq_flags { · 54 unmodified lines | ||
| 55 | 55 | BFA_MSGQ_CMDQ_F_DB_UPDATE = 1, |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | +enum cmdq_event; | |
| 59 | + | |
| 58 | 60 | struct bfa_msgq_cmdq { |
| 59 | − bfa_fsm_t fsm; | |
| 61 | + void (*fsm)(struct bfa_msgq_cmdq *s, enum cmdq_event e); | |
| 60 | 62 | enum bfa_msgq_cmdq_flags flags; |
| 61 | 63 | |
| 62 | 64 | u16 producer_index; |
| @@ -81,8 +83,10 @@ enum bfa_msgq_rspq_flags { · 18 unmodified lines | ||
| 81 | 83 | |
| 82 | 84 | typedef void (*bfa_msgq_mcfunc_t)(void *cbarg, struct bfi_msgq_mhdr *mhdr); |
| 83 | 85 | |
| 86 | +enum rspq_event; | |
| 87 | + | |
| 84 | 88 | struct bfa_msgq_rspq { |
| 85 | − bfa_fsm_t fsm; | |
| 89 | + void (*fsm)(struct bfa_msgq_rspq *s, enum rspq_event e); | |
| 86 | 90 | enum bfa_msgq_rspq_flags flags; |
| 87 | 91 | |
| 88 | 92 | u16 producer_index; |
| @@ -1257,7 +1257,7 @@ bna_enet_mtu_get(struct bna_enet *enet) · 1256 unmodified lines | ||
| 1257 | 1257 | void |
| 1258 | 1258 | bna_enet_enable(struct bna_enet *enet) |
| 1259 | 1259 | { |
| 1260 | − if (enet->fsm != (bfa_sm_t)bna_enet_sm_stopped) | |
| 1260 | + if (enet->fsm != bna_enet_sm_stopped) | |
| 1261 | 1261 | return; |
| 1262 | 1262 | |
| 1263 | 1263 | enet->flags |= BNA_ENET_F_ENABLED; |
| @@ -1751,12 +1751,12 @@ bna_ioceth_uninit(struct bna_ioceth *ioceth) · 487 unmodified lines | ||
| 1751 | 1751 | void |
| 1752 | 1752 | bna_ioceth_enable(struct bna_ioceth *ioceth) |
| 1753 | 1753 | { |
| 1754 | − if (ioceth->fsm == (bfa_fsm_t)bna_ioceth_sm_ready) { | |
| 1754 | + if (ioceth->fsm == bna_ioceth_sm_ready) { | |
| 1755 | 1755 | bnad_cb_ioceth_ready(ioceth->bna->bnad); |
| 1756 | 1756 | return; |
| 1757 | 1757 | } |
| 1758 | 1758 | |
| 1759 | − if (ioceth->fsm == (bfa_fsm_t)bna_ioceth_sm_stopped) | |
| 1759 | + if (ioceth->fsm == bna_ioceth_sm_stopped) | |
| 1760 | 1760 | bfa_fsm_send_event(ioceth, IOCETH_E_ENABLE); |
| 1761 | 1761 | } |
| 1762 | 1762 | |
| @@ -1956,7 +1956,7 @@ static void · 1955 unmodified lines | ||
| 1956 | 1956 | bna_rx_stop(struct bna_rx *rx) |
| 1957 | 1957 | { |
| 1958 | 1958 | rx->rx_flags &= ~BNA_RX_F_ENET_STARTED; |
| 1959 | − if (rx->fsm == (bfa_fsm_t) bna_rx_sm_stopped) | |
| 1959 | + if (rx->fsm == bna_rx_sm_stopped) | |
| 1960 | 1960 | bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx); |
| 1961 | 1961 | else { |
| 1962 | 1962 | rx->stop_cbfn = bna_rx_mod_cb_rx_stopped; |
| @@ -2535,7 +2535,7 @@ bna_rx_destroy(struct bna_rx *rx) · 572 unmodified lines | ||
| 2535 | 2535 | void |
| 2536 | 2536 | bna_rx_enable(struct bna_rx *rx) |
| 2537 | 2537 | { |
| 2538 | − if (rx->fsm != (bfa_sm_t)bna_rx_sm_stopped) | |
| 2538 | + if (rx->fsm != bna_rx_sm_stopped) | |
| 2539 | 2539 | return; |
| 2540 | 2540 | |
| 2541 | 2541 | rx->rx_flags |= BNA_RX_F_ENABLED; |
| @@ -3523,7 +3523,7 @@ bna_tx_destroy(struct bna_tx *tx) · 981 unmodified lines | ||
| 3523 | 3523 | void |
| 3524 | 3524 | bna_tx_enable(struct bna_tx *tx) |
| 3525 | 3525 | { |
| 3526 | − if (tx->fsm != (bfa_sm_t)bna_tx_sm_stopped) | |
| 3526 | + if (tx->fsm != bna_tx_sm_stopped) | |
| 3527 | 3527 | return; |
| 3528 | 3528 | |
| 3529 | 3529 | tx->flags |= BNA_TX_F_ENABLED; |
| @@ -312,8 +312,10 @@ struct bna_attr { · 311 unmodified lines | ||
| 312 | 312 | |
| 313 | 313 | /* IOCEth */ |
| 314 | 314 | |
| 315 | +enum bna_ioceth_event; | |
| 316 | + | |
| 315 | 317 | struct bna_ioceth { |
| 316 | − bfa_fsm_t fsm; | |
| 318 | + void (*fsm)(struct bna_ioceth *s, enum bna_ioceth_event e); | |
| 317 | 319 | struct bfa_ioc ioc; |
| 318 | 320 | |
| 319 | 321 | struct bna_attr attr; |
| @@ -334,8 +336,10 @@ struct bna_pause_config { · 14 unmodified lines | ||
| 334 | 336 | enum bna_status rx_pause; |
| 335 | 337 | }; |
| 336 | 338 | |
| 339 | +enum bna_enet_event; | |
| 340 | + | |
| 337 | 341 | struct bna_enet { |
| 338 | − bfa_fsm_t fsm; | |
| 342 | + void (*fsm)(struct bna_enet *s, enum bna_enet_event e); | |
| 339 | 343 | enum bna_enet_flags flags; |
| 340 | 344 | |
| 341 | 345 | enum bna_enet_type type; |
| @@ -360,8 +364,10 @@ struct bna_enet { · 18 unmodified lines | ||
| 360 | 364 | |
| 361 | 365 | /* Ethport */ |
| 362 | 366 | |
| 367 | +enum bna_ethport_event; | |
| 368 | + | |
| 363 | 369 | struct bna_ethport { |
| 364 | − bfa_fsm_t fsm; | |
| 370 | + void (*fsm)(struct bna_ethport *s, enum bna_ethport_event e); | |
| 365 | 371 | enum bna_ethport_flags flags; |
| 366 | 372 | |
| 367 | 373 | enum bna_link_status link_status; |
| @@ -454,13 +460,16 @@ struct bna_txq { · 86 unmodified lines | ||
| 454 | 460 | }; |
| 455 | 461 | |
| 456 | 462 | /* Tx object */ |
| 463 | + | |
| 464 | +enum bna_tx_event; | |
| 465 | + | |
| 457 | 466 | struct bna_tx { |
| 458 | 467 | /* This should be the first one */ |
| 459 | 468 | struct list_head qe; |
| 460 | 469 | int rid; |
| 461 | 470 | int hw_id; |
| 462 | 471 | |
| 463 | − bfa_fsm_t fsm; | |
| 472 | + void (*fsm)(struct bna_tx *s, enum bna_tx_event e); | |
| 464 | 473 | enum bna_tx_flags flags; |
| 465 | 474 | |
| 466 | 475 | enum bna_tx_type type; |
| @@ -698,8 +707,11 @@ struct bna_rxp { · 231 unmodified lines | ||
| 698 | 707 | }; |
| 699 | 708 | |
| 700 | 709 | /* RxF structure (hardware Rx Function) */ |
| 710 | + | |
| 711 | +enum bna_rxf_event; | |
| 712 | + | |
| 701 | 713 | struct bna_rxf { |
| 702 | − bfa_fsm_t fsm; | |
| 714 | + void (*fsm)(struct bna_rxf *s, enum bna_rxf_event e); | |
| 703 | 715 | |
| 704 | 716 | struct bfa_msgq_cmd_entry msgq_cmd; |
| 705 | 717 | union { |
| @@ -769,13 +781,16 @@ struct bna_rxf { · 63 unmodified lines | ||
| 769 | 781 | }; |
| 770 | 782 | |
| 771 | 783 | /* Rx object */ |
| 784 | + | |
| 785 | +enum bna_rx_event; | |
| 786 | + | |
| 772 | 787 | struct bna_rx { |
| 773 | 788 | /* This should be the first one */ |
| 774 | 789 | struct list_head qe; |
| 775 | 790 | int rid; |
| 776 | 791 | int hw_id; |
| 777 | 792 | |
| 778 | − bfa_fsm_t fsm; | |
| 793 | + void (*fsm)(struct bna_rx *s, enum bna_rx_event e); | |
| 779 | 794 | |
| 780 | 795 | enum bna_rx_type type; |
| 781 | 796 | |
| @@ -742,7 +742,6 @@ static struct phylink_pcs *macb_mac_select_pcs(struct phylink_config *config, · 741 unmodified lines | ||
| 742 | 742 | } |
| 743 | 743 | |
42 more lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 356 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 1954 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 179 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 1198 lines aren’t shown here.
This diff is large: its 224 lines aren’t shown here.
This diff is large: its 240 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 455 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 554 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 712 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 982 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 718 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 223 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 328 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 751 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 407 lines aren’t shown here.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 852 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 477 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 467 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 244 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 382 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 320 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 995 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 211 lines aren’t shown here.
This diff is large: its 1279 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 391 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 513 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 514 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 533 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 1337 lines aren’t shown here.
This diff is large: its 368 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 277 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 672 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 398 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 573 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 306 lines aren’t shown here.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 225 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 263 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 681 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 178 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 261 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 255 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 1609 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 550 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 625 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 1017 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 1352 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 724 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 736 lines aren’t shown here.
This diff is large: its 2884 lines aren’t shown here.
This diff is large: its 281 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 432 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 556 lines aren’t shown here.
This diff is large: its 2246 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 5571 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 353 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 303 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 593 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 236 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 1842 lines aren’t shown here.
This diff is large: its 974 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 347 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 471 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 504 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 2199 lines aren’t shown here.
This diff is large: its 902 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 389 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 448 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 937 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 353 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 442 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 313 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 532 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 254 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 406 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 535 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 594 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 508 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 1722 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 539 lines aren’t shown here.
This diff is large: its 427 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 399 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 382 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 395 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 766 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 332 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 518 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 560 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 619 lines aren’t shown here.
This diff is large: its 340 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 431 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 309 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 411 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 432 lines aren’t shown here.
This diff is large: its 292 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 1074 lines aren’t shown here.
This diff is large: its 329 lines aren’t shown here.
This diff is large: its 830 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 471 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 181 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 237 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 295 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 852 lines aren’t shown here.
This diff is large: its 361 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 824 lines aren’t shown here.
This diff is large: its 2499 lines aren’t shown here.
This diff is large: its 399 lines aren’t shown here.
This diff is large: its 1335 lines aren’t shown here.
This diff is large: its 3608 lines aren’t shown here.
This diff is large: its 670 lines aren’t shown here.
This diff is large: its 387 lines aren’t shown here.
This diff is large: its 524 lines aren’t shown here.
This diff is large: its 223 lines aren’t shown here.
This diff is large: its 543 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 1767 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 342 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 1081 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 912 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 277 lines aren’t shown here.
This diff is large: its 511 lines aren’t shown here.
This diff is large: its 1227 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 970 lines aren’t shown here.
This diff is large: its 824 lines aren’t shown here.
This diff is large: its 1007 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 520 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 993 lines aren’t shown here.
This diff is large: its 244 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 2475 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 4175 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 795 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 22878 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 345 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 1424 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 860 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 194 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 419 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 348 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 998 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 779 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 637 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 192 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 225 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 251 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 267 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 265 lines aren’t shown here.
File renamed without changes.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
File renamed without changes.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 1228 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 620 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 247 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 272 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 267 lines aren’t shown here.
This diff is large: its 1747 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 592 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 758 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 3972 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 963 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 442 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 1384 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 310 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 263 lines aren’t shown here.
This diff is large: its 366 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 392 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 1873 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 1830 lines aren’t shown here.
This diff is large: its 589 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 244 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 475 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 436 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 535 lines aren’t shown here.
This diff is large: its 310 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 388 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 192 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 265 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 345 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 773 lines aren’t shown here.
This diff is large: its 940 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 386 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 797 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 295 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 815 lines aren’t shown here.
This diff is large: its 344 lines aren’t shown here.
This diff is large: its 717 lines aren’t shown here.
This diff is large: its 695 lines aren’t shown here.
This diff is large: its 405 lines aren’t shown here.
This diff is large: its 265 lines aren’t shown here.
This diff is large: its 487 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 1577 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 497 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 323 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 748 lines aren’t shown here.
This diff is large: its 574 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 269 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 524 lines aren’t shown here.
This diff is large: its 725 lines aren’t shown here.
This diff is large: its 620 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 419 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 425 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 309 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 392 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 183 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 280 lines aren’t shown here.
This diff is large: its 384 lines aren’t shown here.
This diff is large: its 280 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 149 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 620 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 503 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 554 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 306 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is larger than a page shows: the files after these aren’t listed. Clone the repository to see all of it.