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 | The BTF_ID macro does not cause a function to become part of the ABI | 299 | The BTF_ID macro does not cause a function to become part of the ABI |
| 300 | any more than does the EXPORT_SYMBOL_GPL macro. | 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 | Submitting patches | 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 | Q: To which mailing list do I need to submit my BPF patches? | 74 | Q: To which mailing list do I need to submit my BPF patches? |
| 48 | ------------------------------------------------------------ | 75 | ------------------------------------------------------------ |
| 49 | A: Please submit your BPF patches to the bpf kernel mailing list: | 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 | 7. Testing | 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 | maps | 24 | maps |
| 25 | bpf_prog_run | 25 | bpf_prog_run |
| 26 | classic_vs_extended.rst | 26 | classic_vs_extended.rst |
| 27 | bpf_iterators | ||
| 27 | bpf_licensing | 28 | bpf_licensing |
| 28 | test_debug | 29 | test_debug |
| 29 | clang-notes | 30 | clang-notes |
| 30 | linux-notes | 31 | linux-notes |
| 31 | other | 32 | other |
| 33 | redirect | ||
| 32 | 34 | ||
| 33 | .. only:: subproject and html | 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 | ``BPF_XOR | BPF_K | BPF_ALU`` means:: | 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 | ``BPF_XOR | BPF_K | BPF_ALU64`` means:: | 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 | Byte swap instructions | 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 | of the pointer is used. Without __sz annotation, a kfunc cannot accept a void | 72 | of the pointer is used. Without __sz annotation, a kfunc cannot accept a void |
| 73 | pointer. | 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 | .. _BPF_kfunc_nodef: | 99 | .. _BPF_kfunc_nodef: |
| 76 | 100 | ||
| 77 | 2.3 Using an existing kernel function | 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 | The KF_TRUSTED_ARGS flag is used for kfuncs taking pointer arguments. It | 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, | 164 | indicates that the all pointer arguments are valid, and that all pointers to |
| 141 | and pointers to kernel objects are always passed to helpers in their unmodified | 165 | BTF objects have been passed in their unmodified form (that is, at a zero |
| 142 | form (as obtained from acquire kfuncs). | 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 | 168 | There are two types of pointers to kernel objects which are considered "valid": |
| 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. | ||
| 148 | 169 | ||
| 149 | Meanwhile, it is also allowed pass pointers to normal memory to such kfuncs, | 170 | 1. Pointers which are passed as tracepoint or struct_ops callback arguments. |
| 150 | but those can have a non-zero offset. | 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 | 173 | Pointers to non-BTF objects (e.g. scalar pointers) may also be passed to |
| 153 | some operation) on an object that was obtained using an acquire kfunc. Such | 174 | KF_TRUSTED_ARGS kfuncs, and may have a non-zero offset. |
| 154 | kfuncs need an unchanged pointer to ensure the integrity of the operation being | 175 | |
| 155 | performed on the expected object. | 176 | The definition of "valid" pointers is subject to change at any time, and has |
| 177 | absolutely no ABI stability guarantees. | ||
| 156 | 178 | ||
| 157 | 2.4.6 KF_SLEEPABLE flag | 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 | calls. At the moment they only require CAP_SYS_BOOT capability, but more can be | 191 | calls. At the moment they only require CAP_SYS_BOOT capability, but more can be |
| 170 | added later. | 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 | 2.5 Registering the kfuncs | 203 | 2.5 Registering the kfuncs |
| 173 | -------------------------- | 204 | -------------------------- |
| 174 | 205 | ||
| @@ -191,3 +222,201 @@ type. An example is shown below:: · 16 unmodified lines | |||
| 191 | return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_task_kfunc_set); | 222 | return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_task_kfunc_set); |
| 192 | } | 223 | } |
| 193 | late_initcall(init_subsystem); | 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 | .. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | 1 | .. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
| 2 | 2 | ||
| 3 | .. _libbpf: | ||
| 4 | |||
| 3 | libbpf | 5 | libbpf |
| 4 | ====== | 6 | ====== |
| 5 | 7 | ||
| @@ -7,6 +9,7 @@ libbpf · 1 unmodified line | |||
| 7 | :maxdepth: 1 | 9 | :maxdepth: 1 |
| 8 | 10 | ||
| 9 | API Documentation <https://libbpf.readthedocs.io/en/latest/api.html> | 11 | API Documentation <https://libbpf.readthedocs.io/en/latest/api.html> |
| 12 | program_types | ||
| 10 | libbpf_naming_convention | 13 | libbpf_naming_convention |
| 11 | libbpf_build | 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 | Usage | 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 | long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) | 45 | long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) |
| 39 | 46 | ||
| 40 | Hash entries can be added or updated using the ``bpf_map_update_elem()`` | 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 | ``bpf_map_update_elem()`` returns 0 on success, or negative error in | 56 | ``bpf_map_update_elem()`` returns 0 on success, or negative error in |
| 50 | case of failure. | 57 | case of failure. |
| 51 | 58 | ||
| 52 | .. c:function:: | 59 | bpf_map_lookup_elem() |
| 60 | ~~~~~~~~~~~~~~~~~~~~~ | ||
| 61 | |||
| 62 | .. code-block:: c | ||
| 63 | |||
| 53 | void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) | 64 | void *bpf_map_lookup_elem(struct bpf_map *map, const void *key) |
| 54 | 65 | ||
| 55 | Hash entries can be retrieved using the ``bpf_map_lookup_elem()`` | 66 | Hash entries can be retrieved using the ``bpf_map_lookup_elem()`` |
| 56 | helper. This helper returns a pointer to the value associated with | 67 | helper. This helper returns a pointer to the value associated with |
| 57 | ``key``, or ``NULL`` if no entry was found. | 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 | long bpf_map_delete_elem(struct bpf_map *map, const void *key) | 75 | long bpf_map_delete_elem(struct bpf_map *map, const void *key) |
| 61 | 76 | ||
| 62 | Hash entries can be deleted using the ``bpf_map_delete_elem()`` | 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 | the ``bpf_map_update_elem()`` and ``bpf_map_lookup_elem()`` helpers | 85 | the ``bpf_map_update_elem()`` and ``bpf_map_lookup_elem()`` helpers |
| 71 | automatically access the hash slot for the current CPU. | 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 | void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) | 93 | void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu) |
| 75 | 94 | ||
| 76 | The ``bpf_map_lookup_percpu_elem()`` helper can be used to lookup the | 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 | Userspace | 108 | Userspace |
| 90 | --------- | 109 | --------- |
| 91 | 110 | ||
| 92 | .. c:function:: | 111 | bpf_map_get_next_key() |
| 112 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
| 113 | |||
| 114 | .. code-block:: c | ||
| 115 | |||
| 93 | int bpf_map_get_next_key(int fd, const void *cur_key, void *next_key) | 116 | int bpf_map_get_next_key(int fd, const void *cur_key, void *next_key) |
| 94 | 117 | ||
| 95 | In userspace, it is possible to iterate through the keys of a hash using | 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 | ========= | 2 | ======== |
| 3 | eBPF maps | 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 | 21 | .. toctree:: |
| 7 | and userspace. | 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 | 27 | Usage Notes |
| 12 | ``map_fd = bpf(BPF_MAP_CREATE, union bpf_attr *attr, u32 size)`` | 28 | =========== |
| 13 | using attr->map_type, attr->key_size, attr->value_size, attr->max_entries | ||
| 14 | returns process-local file descriptor or negative error | ||
| 15 | 29 | ||
| 16 | - lookup key in a given map | 30 | .. c:function:: |
| 17 | ``err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)`` | 31 | int bpf(int command, 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 | ||
| 20 | 32 | ||
| 21 | - create or update key/value pair in a given map | 33 | Use the ``bpf()`` system call to perform the operation specified by |
| 22 | ``err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)`` | 34 | ``command``. The operation takes parameters provided in ``attr``. The ``size`` |
| 23 | using attr->map_fd, attr->key, attr->value | 35 | argument is the size of the ``union bpf_attr`` in ``attr``. |
| 24 | returns zero or negative error | ||
| 25 | 36 | ||
| 26 | - find and delete element by key in a given map | 37 | **BPF_MAP_CREATE** |
| 27 | ``err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)`` | ||
| 28 | using attr->map_fd, attr->key | ||
| 29 | 38 | ||
| 30 | - to delete map: close(fd) | 39 | Create a map with the desired type and attributes in ``attr``: |
| 31 | Exiting process will delete maps automatically | ||
| 32 | 40 | ||
| 33 | userspace programs use this syscall to create/access maps that eBPF programs | 41 | .. code-block:: c |
| 34 | are concurrently updating. | ||
| 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 | 55 | Returns a process-local file descriptor on success, or negative error in case of |
| 41 | - max number of elements | 56 | failure. The map can be deleted by calling ``close(fd)``. Maps held by open |
| 42 | - key size in bytes | 57 | file descriptors will be deleted automatically when a process exits. |
| 43 | - value size in bytes | ||
| 44 | 58 | ||
| 45 | Map Types | 59 | .. note:: Valid characters for ``map_name`` are ``A-Z``, ``a-z``, ``0-9``, |
| 46 | ========= | 60 | ``'_'`` and ``'.'``. |
| 47 | 61 | ||
| 48 | .. toctree:: | 62 | **BPF_MAP_LOOKUP_ELEM** |
| 49 | :maxdepth: 1 | 63 | |
| 50 | :glob: | 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 | :glob: | 7 | :glob: |
| 8 | 8 | ||
| 9 | prog_* | 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 | interrupts: | 29 | interrupts: |
| 30 | maxItems: 1 | 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 | required: | 64 | required: |
| 33 | - compatible | 65 | - compatible |
| 34 | - reg | 66 | - reg |
| @@ -49,3 +81,23 @@ examples: · 14 unmodified lines | |||
| 49 | interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_LOW>; | 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 | title: Freescale INTMUX interrupt multiplexer | 7 | title: Freescale INTMUX interrupt multiplexer |
| 8 | 8 | ||
| 9 | maintainers: | 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 | properties: | 13 | properties: |
| 13 | compatible: | 14 | compatible: |
| @@ -46,6 +46,10 @@ properties: · 45 unmodified lines | |||
| 46 | interrupts: | 46 | interrupts: |
| 47 | maxItems: 1 | 47 | maxItems: 1 |
| 48 | 48 | ||
| 49 | reset-gpios: | ||
| 50 | maxItems: 1 | ||
| 51 | description: GPIO connected to active low reset | ||
| 52 | |||
| 49 | required: | 53 | required: |
| 50 | - compatible | 54 | - compatible |
| 51 | - reg | 55 | - reg |
| @@ -27,7 +27,9 @@ properties: · 26 unmodified lines | |||
| 27 | - usbb95,772b # ASIX AX88772B | 27 | - usbb95,772b # ASIX AX88772B |
| 28 | - usbb95,7e2b # ASIX AX88772B | 28 | - usbb95,7e2b # ASIX AX88772B |
| 29 | 29 | ||
| 30 | reg: true | 30 | reg: |
| 31 | maxItems: 1 | ||
| 32 | |||
| 31 | local-mac-address: true | 33 | local-mac-address: true |
| 32 | mac-address: true | 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 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | %YAML 1.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 | $schema: http://devicetree.org/meta-schemas/core.yaml# | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | ||
| 7 | title: Qualcomm Bluetooth Chips | 7 | title: Qualcomm Bluetooth Chips |
| @@ -79,8 +79,7 @@ properties: · 71 unmodified lines | |||
| 79 | firmware-name: | 79 | firmware-name: |
| 80 | description: specify the name of nvm firmware to load | 80 | description: specify the name of nvm firmware to load |
| 81 | 81 | ||
| 82 | local-bd-address: | 82 | local-bd-address: true |
| 83 | description: see Documentation/devicetree/bindings/net/bluetooth.txt | ||
| 84 | 83 | ||
| 85 | 84 | ||
| 86 | required: | 85 | required: |
| @@ -89,6 +88,7 @@ required: · 2 unmodified lines | |||
| 89 | additionalProperties: false | 88 | additionalProperties: false |
| 90 | 89 | ||
| 91 | allOf: | 90 | allOf: |
| 91 | - $ref: bluetooth-controller.yaml# | ||
| 92 | - if: | 92 | - if: |
| 93 | properties: | 93 | properties: |
| 94 | compatible: | 94 | compatible: |
| @@ -19,11 +19,14 @@ properties: · 18 unmodified lines | |||
| 19 | - brcm,bcm4329-bt | 19 | - brcm,bcm4329-bt |
| 20 | - brcm,bcm4330-bt | 20 | - brcm,bcm4330-bt |
| 21 | - brcm,bcm4334-bt | 21 | - brcm,bcm4334-bt |
| 22 | - brcm,bcm43430a0-bt | ||
| 23 | - brcm,bcm43430a1-bt | ||
| 22 | - brcm,bcm43438-bt | 24 | - brcm,bcm43438-bt |
| 23 | - brcm,bcm4345c5 | 25 | - brcm,bcm4345c5 |
| 24 | - brcm,bcm43540-bt | 26 | - brcm,bcm43540-bt |
| 25 | - brcm,bcm4335a0 | 27 | - brcm,bcm4335a0 |
| 26 | - brcm,bcm4349-bt | 28 | - brcm,bcm4349-bt |
| 29 | - cypress,cyw4373a0-bt | ||
| 27 | - infineon,cyw55572-bt | 30 | - infineon,cyw55572-bt |
| 28 | 31 | ||
| 29 | shutdown-gpios: | 32 | shutdown-gpios: |
| @@ -17,6 +17,7 @@ properties: · 16 unmodified lines | |||
| 17 | compatible: | 17 | compatible: |
| 18 | oneOf: | 18 | oneOf: |
| 19 | - enum: | 19 | - enum: |
| 20 | - fsl,imx93-flexcan | ||
| 20 | - fsl,imx8qm-flexcan | 21 | - fsl,imx8qm-flexcan |
| 21 | - fsl,imx8mp-flexcan | 22 | - fsl,imx8mp-flexcan |
| 22 | - fsl,imx6q-flexcan | 23 | - fsl,imx6q-flexcan |
| @@ -9,9 +9,6 @@ title: Renesas R-Car CAN FD Controller · 8 unmodified lines | |||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Fabrizio Castro <fabrizio.castro.jz@renesas.com> | 10 | - Fabrizio Castro <fabrizio.castro.jz@renesas.com> |
| 11 | 11 | ||
| 12 | allOf: | ||
| 13 | - $ref: can-controller.yaml# | ||
| 14 | |||
| 15 | properties: | 12 | properties: |
| 16 | compatible: | 13 | compatible: |
| 17 | oneOf: | 14 | oneOf: |
| @@ -33,7 +30,7 @@ properties: · 15 unmodified lines | |||
| 33 | 30 | ||
| 34 | - items: | 31 | - items: |
| 35 | - enum: | 32 | - enum: |
| 36 | - renesas,r9a07g043-canfd # RZ/G2UL | 33 | - renesas,r9a07g043-canfd # RZ/G2UL and RZ/Five |
| 37 | - renesas,r9a07g044-canfd # RZ/G2{L,LC} | 34 | - renesas,r9a07g044-canfd # RZ/G2{L,LC} |
| 38 | - renesas,r9a07g054-canfd # RZ/V2L | 35 | - renesas,r9a07g054-canfd # RZ/V2L |
| 39 | - const: renesas,rzg2l-canfd # RZ/G2L family | 36 | - const: renesas,rzg2l-canfd # RZ/G2L family |
| @@ -77,12 +74,13 @@ properties: · 37 unmodified lines | |||
| 77 | description: Maximum frequency of the CANFD clock. | 74 | description: Maximum frequency of the CANFD clock. |
| 78 | 75 | ||
| 79 | patternProperties: | 76 | patternProperties: |
| 80 | "^channel[01]$": | 77 | "^channel[0-7]$": |
| 81 | type: object | 78 | type: object |
| 82 | description: | 79 | description: |
| 83 | The controller supports two channels and each is represented as a child | 80 | The controller supports multiple channels and each is represented as a |
| 84 | node. Each child node supports the "status" property only, which | 81 | child node. Each channel can be enabled/disabled individually. |
| 85 | is used to enable/disable the respective channel. | 82 | |
| 83 | additionalProperties: false | ||
| 86 | 84 | ||
| 87 | required: | 85 | required: |
| 88 | - compatible | 86 | - compatible |
| @@ -98,60 +96,73 @@ required: · 9 unmodified lines | |||
| 98 | - channel0 | 96 | - channel0 |
| 99 | - channel1 | 97 | - channel1 |
| 100 | 98 | ||
| 101 | if: | 99 | allOf: |
| 102 | properties: | 100 | - $ref: can-controller.yaml# |
| 103 | compatible: | 101 | |
| 104 | contains: | 102 | - if: |
| 105 | enum: | 103 | properties: |
| 106 | - renesas,rzg2l-canfd | 104 | compatible: |
| 107 | then: | 105 | contains: |
| 108 | properties: | 106 | enum: |
| 109 | interrupts: | 107 | - renesas,rzg2l-canfd |
| 110 | items: | 108 | then: |
| 111 | - description: CAN global error interrupt | 109 | properties: |
| 112 | - description: CAN receive FIFO interrupt | 110 | interrupts: |
| 113 | - description: CAN0 error interrupt | 111 | items: |
| 114 | - description: CAN0 transmit interrupt | 112 | - description: CAN global error interrupt |
| 115 | - description: CAN0 transmit/receive FIFO receive completion interrupt | 113 | - description: CAN receive FIFO interrupt |
| 116 | - description: CAN1 error interrupt | 114 | - description: CAN0 error interrupt |
| 117 | - description: CAN1 transmit interrupt | 115 | - description: CAN0 transmit interrupt |
| 118 | - description: CAN1 transmit/receive FIFO receive completion interrupt | 116 | - description: CAN0 transmit/receive FIFO receive completion interrupt |
| 119 | 117 | - description: CAN1 error interrupt | |
| 120 | interrupt-names: | 118 | - description: CAN1 transmit interrupt |
| 121 | items: | 119 | - description: CAN1 transmit/receive FIFO receive completion interrupt |
| 122 | - const: g_err | 120 | |
| 123 | - const: g_recc | 121 | interrupt-names: |
| 124 | - const: ch0_err | 122 | items: |
| 125 | - const: ch0_rec | 123 | - const: g_err |
| 126 | - const: ch0_trx | 124 | - const: g_recc |
| 127 | - const: ch1_err | 125 | - const: ch0_err |
| 128 | - const: ch1_rec | 126 | - const: ch0_rec |
| 129 | - const: ch1_trx | 127 | - const: ch0_trx |
| 130 | 128 | - const: ch1_err | |
| 131 | resets: | 129 | - const: ch1_rec |
| 132 | maxItems: 2 | 130 | - const: ch1_trx |
| 133 | 131 | ||
| 134 | reset-names: | 132 | resets: |
| 135 | items: | 133 | maxItems: 2 |
| 136 | - const: rstp_n | 134 | |
| 137 | - const: rstc_n | 135 | reset-names: |
| 138 | 136 | items: | |
| 139 | required: | 137 | - const: rstp_n |
| 140 | - reset-names | 138 | - const: rstc_n |
| 141 | else: | 139 | |
| 142 | properties: | 140 | required: |
| 143 | interrupts: | 141 | - reset-names |
| 144 | items: | 142 | else: |
| 145 | - description: Channel interrupt | 143 | properties: |
| 146 | - description: Global interrupt | 144 | interrupts: |
| 147 | 145 | items: | |
| 148 | interrupt-names: | 146 | - description: Channel interrupt |
| 149 | items: | 147 | - description: Global interrupt |
| 150 | - const: ch_int | 148 | |
| 151 | - const: g_int | 149 | interrupt-names: |
| 152 | 150 | items: | |
| 153 | resets: | 151 | - const: ch_int |
| 154 | maxItems: 1 | 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 | unevaluatedProperties: false | 167 | unevaluatedProperties: false |
| 157 | 168 | ||
| @@ -19,7 +19,8 @@ allOf: · 18 unmodified lines | |||
| 19 | 19 | ||
| 20 | properties: | 20 | properties: |
| 21 | reg: | 21 | reg: |
| 22 | description: Port number | 22 | items: |
| 23 | - description: Port number | ||
| 23 | 24 | ||
| 24 | label: | 25 | label: |
| 25 | description: | 26 | description: |
| @@ -12,7 +12,7 @@ allOf: · 11 unmodified lines | |||
| 12 | maintainers: | 12 | maintainers: |
| 13 | - Andrew Lunn <andrew@lunn.ch> | 13 | - Andrew Lunn <andrew@lunn.ch> |
| 14 | - Florian Fainelli <f.fainelli@gmail.com> | 14 | - Florian Fainelli <f.fainelli@gmail.com> |
| 15 | - Vivien Didelot <vivien.didelot@gmail.com> | 15 | - Vladimir Oltean <olteanv@gmail.com> |
| 16 | - Kurt Kanzenbach <kurt@linutronix.de> | 16 | - Kurt Kanzenbach <kurt@linutronix.de> |
| 17 | 17 | ||
| 18 | description: | 18 | description: |
| @@ -74,10 +74,10 @@ properties: · 73 unmodified lines | |||
| 74 | 74 | ||
| 75 | properties: | 75 | properties: |
| 76 | pcs-handle: | 76 | pcs-handle: |
| 77 | maxItems: 1 | ||
| 77 | description: | 78 | description: |
| 78 | phandle pointing to a PCS sub-node compatible with | 79 | phandle pointing to a PCS sub-node compatible with |
| 79 | renesas,rzn1-miic.yaml# | 80 | renesas,rzn1-miic.yaml# |
| 80 | $ref: /schemas/types.yaml#/definitions/phandle | ||
| 81 | 81 | ||
| 82 | unevaluatedProperties: false | 82 | unevaluatedProperties: false |
| 83 | 83 | ||
| @@ -108,11 +108,17 @@ properties: · 107 unmodified lines | |||
| 108 | $ref: "#/properties/phy-connection-type" | 108 | $ref: "#/properties/phy-connection-type" |
| 109 | 109 | ||
| 110 | pcs-handle: | 110 | pcs-handle: |
| 111 | $ref: /schemas/types.yaml#/definitions/phandle | 111 | $ref: /schemas/types.yaml#/definitions/phandle-array |
| 112 | items: | ||
| 113 | maxItems: 1 | ||
| 112 | description: | 114 | description: |
| 113 | Specifies a reference to a node representing a PCS PHY device on a MDIO | 115 | Specifies a reference to a node representing a PCS PHY device on a MDIO |
| 114 | bus to link with an external PHY (phy-handle) if exists. | 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 | phy-handle: | 122 | phy-handle: |
| 117 | $ref: /schemas/types.yaml#/definitions/phandle | 123 | $ref: /schemas/types.yaml#/definitions/phandle |
| 118 | description: | 124 | description: |
| @@ -216,6 +222,9 @@ properties: · 97 unmodified lines | |||
| 216 | required: | 222 | required: |
| 217 | - speed | 223 | - speed |
| 218 | 224 | ||
| 225 | dependencies: | ||
| 226 | pcs-handle-names: [pcs-handle] | ||
| 227 | |||
| 219 | allOf: | 228 | allOf: |
| 220 | - if: | 229 | - if: |
| 221 | properties: | 230 | properties: |
| @@ -7,7 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 6 unmodified lines | |||
| 7 | title: Freescale Fast Ethernet Controller (FEC) | 7 | title: Freescale Fast Ethernet Controller (FEC) |
| 8 | 8 | ||
| 9 | maintainers: | 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 | allOf: | 14 | allOf: |
| 13 | - $ref: ethernet-controller.yaml# | 15 | - $ref: ethernet-controller.yaml# |
| @@ -85,9 +85,39 @@ properties: · 84 unmodified lines | |||
| 85 | $ref: /schemas/types.yaml#/definitions/phandle | 85 | $ref: /schemas/types.yaml#/definitions/phandle |
| 86 | description: A reference to the IEEE1588 timer | 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 | pcsphy-handle: | 96 | pcsphy-handle: |
| 89 | $ref: /schemas/types.yaml#/definitions/phandle | 97 | $ref: /schemas/types.yaml#/definitions/phandle-array |
| 90 | description: A reference to the PCS (typically found on the SerDes) | 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 | tbi-handle: | 122 | tbi-handle: |
| 93 | $ref: /schemas/types.yaml#/definitions/phandle | 123 | $ref: /schemas/types.yaml#/definitions/phandle |
| @@ -100,6 +130,10 @@ required: · 6 unmodified lines | |||
| 100 | - fsl,fman-ports | 130 | - fsl,fman-ports |
| 101 | - ptp-timer | 131 | - ptp-timer |
| 102 | 132 | ||
| 133 | dependencies: | ||
| 134 | pcs-handle-names: | ||
| 135 | - pcs-handle | ||
| 136 | |||
| 103 | allOf: | 137 | allOf: |
| 104 | - $ref: ethernet-controller.yaml# | 138 | - $ref: ethernet-controller.yaml# |
| 105 | - if: | 139 | - if: |
| @@ -110,14 +144,6 @@ allOf: · 4 unmodified lines | |||
| 110 | then: | 144 | then: |
| 111 | required: | 145 | required: |
| 112 | - tbi-handle | 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 | unevaluatedProperties: false | 148 | unevaluatedProperties: false |
| 123 | 149 | ||
| @@ -138,8 +164,9 @@ examples: · 14 unmodified lines | |||
| 138 | reg = <0xe8000 0x1000>; | 164 | reg = <0xe8000 0x1000>; |
| 139 | fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; | 165 | fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; |
| 140 | ptp-timer = <&ptp_timer0>; | 166 | ptp-timer = <&ptp_timer0>; |
| 141 | pcsphy-handle = <&pcsphy4>; | 167 | pcs-handle = <&pcsphy4>, <&qsgmiib_pcs1>; |
| 142 | phy-handle = <&sgmii_phy1>; | 168 | pcs-handle-names = "sgmii", "qsgmii"; |
| 143 | phy-connection-type = "sgmii"; | 169 | phys = <&serdes1 1>; |
| 170 | phy-names = "serdes"; | ||
| 144 | }; | 171 | }; |
| 145 | ... | 172 | ... |
| @@ -31,7 +31,7 @@ properties: · 30 unmodified lines | |||
| 31 | phy-mode: true | 31 | phy-mode: true |
| 32 | 32 | ||
| 33 | pcs-handle: | 33 | pcs-handle: |
| 34 | $ref: /schemas/types.yaml#/definitions/phandle | 34 | maxItems: 1 |
| 35 | description: | 35 | description: |
| 36 | A reference to a node representing a PCS PHY device found on | 36 | A reference to a node representing a PCS PHY device found on |
| 37 | the internal MDIO bus. | 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 | See the definition of the PHY node in booting-without-of.txt for an | 320 | See the definition of the PHY node in booting-without-of.txt for an |
| 321 | example of how to define a PHY (Internal PHY has no interrupt line). | 321 | example of how to define a PHY (Internal PHY has no interrupt line). |
| 322 | - For "fsl,fman-mdio" compatible internal mdio bus, the PHY is TBI PHY. | 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, | 323 | - For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY. |
| 324 | PCS PHY addr must be '0'. | 324 | The PCS PHY address should correspond to the value of the appropriate |
| 325 | MDEV_PORT. | ||
| 325 | 326 | ||
| 326 | EXAMPLE | 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 | - usb424,9e08 # SMSC LAN89530 USB Ethernet Device | 39 | - usb424,9e08 # SMSC LAN89530 USB Ethernet Device |
| 40 | - usb424,ec00 # SMSC9512/9514 USB Hub & Ethernet Device | 40 | - usb424,ec00 # SMSC9512/9514 USB Hub & Ethernet Device |
| 41 | 41 | ||
| 42 | reg: true | 42 | reg: |
| 43 | maxItems: 1 | ||
| 44 | |||
| 43 | local-mac-address: true | 45 | local-mac-address: true |
| 44 | mac-address: true | 46 | mac-address: true |
| 45 | 47 | ||
| @@ -14,7 +14,9 @@ properties: · 13 unmodified lines | |||
| 14 | oneOf: | 14 | oneOf: |
| 15 | - const: nxp,nxp-nci-i2c | 15 | - const: nxp,nxp-nci-i2c |
| 16 | - items: | 16 | - items: |
| 17 | - const: nxp,pn547 | 17 | - enum: |
| 18 | - nxp,nq310 | ||
| 19 | - nxp,pn547 | ||
| 18 | - const: nxp,nxp-nci-i2c | 20 | - const: nxp,nxp-nci-i2c |
| 19 | 21 | ||
| 20 | enable-gpios: | 22 | enable-gpios: |
| @@ -7,7 +7,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 6 unmodified lines | |||
| 7 | title: NXP i.MX8 DWMAC glue layer | 7 | title: NXP i.MX8 DWMAC glue layer |
| 8 | 8 | ||
| 9 | maintainers: | 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 | # We need a select here so we don't match all nodes with 'snps,dwmac' | 14 | # We need a select here so we don't match all nodes with 'snps,dwmac' |
| 13 | select: | 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 | switch_port0: port@0 { | 124 | switch_port0: port@0 { |
| 125 | reg = <0x0>; | 125 | reg = <0x0>; |
| 126 | label = "cpu"; | ||
| 127 | ethernet = <ð1>; | 126 | ethernet = <ð1>; |
| 128 | 127 | ||
| 129 | phy-mode = "gmii"; | 128 | phy-mode = "gmii"; |
| @@ -49,6 +49,7 @@ properties: · 48 unmodified lines | |||
| 49 | - qcom,sc7280-ipa | 49 | - qcom,sc7280-ipa |
| 50 | - qcom,sdm845-ipa | 50 | - qcom,sdm845-ipa |
| 51 | - qcom,sdx55-ipa | 51 | - qcom,sdx55-ipa |
| 52 | - qcom,sm6350-ipa | ||
| 52 | - qcom,sm8350-ipa | 53 | - qcom,sm8350-ipa |
| 53 | 54 | ||
| 54 | reg: | 55 | reg: |
| @@ -124,19 +125,31 @@ properties: · 69 unmodified lines | |||
| 124 | - const: ipa-clock-enabled-valid | 125 | - const: ipa-clock-enabled-valid |
| 125 | - const: ipa-clock-enabled | 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 | modem-init: | 139 | modem-init: |
| 140 | deprecated: true | ||
| 128 | type: boolean | 141 | type: boolean |
| 129 | description: | 142 | description: |
| 130 | If present, it indicates that the modem is responsible for | 143 | This is the older (deprecated) way of indicating how GSI firmware |
| 131 | performing early IPA initialization, including loading and | 144 | should be loaded. If present, the modem loads GSI firmware; if |
| 132 | validating firwmare used by the GSI. | 145 | absent, the AP loads GSI firmware. |
| 133 | 146 | ||
| 134 | memory-region: | 147 | memory-region: |
| 135 | maxItems: 1 | 148 | maxItems: 1 |
| 136 | description: | 149 | description: |
| 137 | If present, a phandle for a reserved memory area that holds | 150 | If present, a phandle for a reserved memory area that holds |
| 138 | the firmware passed to Trust Zone for authentication. Required | 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 | firmware-name: | 154 | firmware-name: |
| 142 | $ref: /schemas/types.yaml#/definitions/string | 155 | $ref: /schemas/types.yaml#/definitions/string |
| @@ -155,22 +168,36 @@ required: · 12 unmodified lines | |||
| 155 | - interconnects | 168 | - interconnects |
| 156 | - qcom,smem-states | 169 | - qcom,smem-states |
| 157 | 170 | ||
| 158 | # Either modem-init is present, or memory-region must be present. | 171 | allOf: |
| 159 | oneOf: | 172 | # If qcom,gsi-loader is present, modem-init must not be present |
| 160 | - required: | 173 | - if: |
| 161 | - modem-init | 174 | required: |
| 162 | - required: | 175 | - qcom,gsi-loader |
| 163 | - memory-region | 176 | then: |
| 164 | 177 | properties: | |
| 165 | # If memory-region is present, firmware-name may optionally be present. | 178 | modem-init: false |
| 166 | # But if modem-init is present, firmware-name must not be present. | 179 | |
| 167 | if: | 180 | # If qcom,gsi-loader is "self", the AP loads GSI firmware, and |
| 168 | required: | 181 | # memory-region must be specified |
| 169 | - modem-init | 182 | if: |
| 170 | then: | 183 | properties: |
| 171 | not: | 184 | qcom,gsi-loader: |
| 172 | required: | 185 | contains: |
| 173 | - firmware-name | 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 | additionalProperties: false | 202 | additionalProperties: false |
| 176 | 203 | ||
| @@ -201,14 +228,17 @@ examples: · 24 unmodified lines | |||
| 201 | }; | 228 | }; |
| 202 | 229 | ||
| 203 | ipa@1e40000 { | 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 | reg = <0x1e40000 0x7000>, | 239 | reg = <0x1e40000 0x7000>, |
| 210 | <0x1e47000 0x2000>, | 240 | <0x1e47000 0x2000>, |
| 211 | <0x1e04000 0x2c000>; | 241 | <0x1e04000 0x2c000>; |
| 212 | reg-names = "ipa-reg", | 242 | reg-names = "ipa-reg", |
| 213 | "ipa-shared", | 243 | "ipa-shared", |
| 214 | "gsi"; | 244 | "gsi"; |
| @@ -226,9 +256,9 @@ examples: · 11 unmodified lines | |||
| 226 | clock-names = "core"; | 256 | clock-names = "core"; |
| 227 | 257 | ||
| 228 | interconnects = | 258 | interconnects = |
| 229 | <&rsc_hlos MASTER_IPA &rsc_hlos SLAVE_EBI1>, | 259 | <&aggre2_noc MASTER_IPA 0 &mc_virt SLAVE_EBI1 0>, |
| 230 | <&rsc_hlos MASTER_IPA &rsc_hlos SLAVE_IMEM>, | 260 | <&aggre2_noc MASTER_IPA 0 &system_noc SLAVE_IMEM 0>, |
| 231 | <&rsc_hlos MASTER_APPSS_PROC &rsc_hlos SLAVE_IPA_CFG>; | 261 | <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_IPA_CFG 0>; |
| 232 | interconnect-names = "memory", | 262 | interconnect-names = "memory", |
| 233 | "imem", | 263 | "imem", |
| 234 | "config"; | 264 | "config"; |
| @@ -9,14 +9,18 @@ title: Qualcomm IPQ40xx MDIO Controller · 8 unmodified lines | |||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Robert Marko <robert.marko@sartura.hr> | 10 | - Robert Marko <robert.marko@sartura.hr> |
| 11 | 11 | ||
| 12 | allOf: | ||
| 13 | - $ref: "mdio.yaml#" | ||
| 14 | |||
| 15 | properties: | 12 | properties: |
| 16 | compatible: | 13 | compatible: |
| 17 | enum: | 14 | oneOf: |
| 18 | - qcom,ipq4019-mdio | 15 | - enum: |
| 19 | - qcom,ipq5018-mdio | 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 | "#address-cells": | 25 | "#address-cells": |
| 22 | const: 1 | 26 | const: 1 |
| @@ -33,10 +37,12 @@ properties: · 10 unmodified lines | |||
| 33 | address range is only required by the platform IPQ50xx. | 37 | address range is only required by the platform IPQ50xx. |
| 34 | 38 | ||
| 35 | clocks: | 39 | clocks: |
| 36 | maxItems: 1 | 40 | items: |
| 37 | description: | | 41 | - description: MDIO clock source frequency fixed to 100MHZ |
| 38 | MDIO clock source frequency fixed to 100MHZ, this clock should be specified | 42 | |
| 39 | by the platform IPQ807x, IPQ60xx and IPQ50xx. | 43 | clock-names: |
| 44 | items: | ||
| 45 | - const: gcc_mdio_ahb_clk | ||
| 40 | 46 | ||
| 41 | required: | 47 | required: |
| 42 | - compatible | 48 | - compatible |
| @@ -44,6 +50,26 @@ required: · 1 unmodified line | |||
| 44 | - "#address-cells" | 50 | - "#address-cells" |
| 45 | - "#size-cells" | 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 | unevaluatedProperties: false | 73 | unevaluatedProperties: false |
| 48 | 74 | ||
| 49 | examples: | 75 | examples: |
| @@ -20,6 +20,7 @@ properties: · 19 unmodified lines | |||
| 20 | enum: | 20 | enum: |
| 21 | - realtek,rtl8723bs-bt | 21 | - realtek,rtl8723bs-bt |
| 22 | - realtek,rtl8723cs-bt | 22 | - realtek,rtl8723cs-bt |
| 23 | - realtek,rtl8723ds-bt | ||
| 23 | - realtek,rtl8822cs-bt | 24 | - realtek,rtl8822cs-bt |
| 24 | 25 | ||
| 25 | device-wake-gpios: | 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 | phandle of an I2C bus controller for the SFP two wire serial | 22 | phandle of an I2C bus controller for the SFP two wire serial |
| 23 | 23 | ||
| 24 | maximum-power-milliwatt: | 24 | maximum-power-milliwatt: |
| 25 | maxItems: 1 | 25 | minimum: 1000 |
| 26 | default: 1000 | ||
| 26 | description: | 27 | description: |
| 27 | Maximum module power consumption Specifies the maximum power consumption | 28 | Maximum module power consumption Specifies the maximum power consumption |
| 28 | allowable by a module in the slot, in milli-Watts. Presently, modules can | 29 | allowable by a module in the slot, in milli-Watts. Presently, modules can |
| @@ -167,56 +167,238 @@ properties: · 166 unmodified lines | |||
| 167 | snps,mtl-rx-config: | 167 | snps,mtl-rx-config: |
| 168 | $ref: /schemas/types.yaml#/definitions/phandle | 168 | $ref: /schemas/types.yaml#/definitions/phandle |
| 169 | description: | 169 | description: |
| 170 | Multiple RX Queues parameters. Phandle to a node that can | 170 | Multiple RX Queues parameters. Phandle to a node that |
| 171 | contain the following properties | 171 | implements the 'rx-queues-config' object described in |
| 172 | * snps,rx-queues-to-use, number of RX queues to be used in the | 172 | this binding. |
| 173 | driver | 173 | |
| 174 | * Choose one of these RX scheduling algorithms | 174 | rx-queues-config: |
| 175 | * snps,rx-sched-sp, Strict priority | 175 | type: object |
| 176 | * snps,rx-sched-wsp, Weighted Strict priority | 176 | properties: |
| 177 | * For each RX queue | 177 | snps,rx-queues-to-use: |
| 178 | * Choose one of these modes | 178 | $ref: /schemas/types.yaml#/definitions/uint32 |
| 179 | * snps,dcb-algorithm, Queue to be enabled as DCB | 179 | description: number of RX queues to be used in the driver |
| 180 | * snps,avb-algorithm, Queue to be enabled as AVB | 180 | snps,rx-sched-sp: |
| 181 | * snps,map-to-dma-channel, Channel to map | 181 | type: boolean |
| 182 | * Specifiy specific packet routing | 182 | description: Strict priority |
| 183 | * snps,route-avcp, AV Untagged Control packets | 183 | snps,rx-sched-wsp: |
| 184 | * snps,route-ptp, PTP Packets | 184 | type: boolean |
| 185 | * snps,route-dcbcp, DCB Control Packets | 185 | description: Weighted Strict priority |
| 186 | * snps,route-up, Untagged Packets | 186 | allOf: |
| 187 | * snps,route-multi-broad, Multicast & Broadcast Packets | 187 | - if: |
| 188 | * snps,priority, bitmask of the tagged frames priorities assigned to | 188 | required: |
| 189 | the queue | 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 | snps,mtl-tx-config: | 292 | snps,mtl-tx-config: |
| 192 | $ref: /schemas/types.yaml#/definitions/phandle | 293 | $ref: /schemas/types.yaml#/definitions/phandle |
| 193 | description: | 294 | description: |
| 194 | Multiple TX Queues parameters. Phandle to a node that can | 295 | Multiple TX Queues parameters. Phandle to a node that |
| 195 | contain the following properties | 296 | implements the 'tx-queues-config' object described in |
| 196 | * snps,tx-queues-to-use, number of TX queues to be used in the | 297 | this binding. |
| 197 | driver | 298 | |
| 198 | * Choose one of these TX scheduling algorithms | 299 | tx-queues-config: |
| 199 | * snps,tx-sched-wrr, Weighted Round Robin | 300 | type: object |
| 200 | * snps,tx-sched-wfq, Weighted Fair Queuing | 301 | properties: |
| 201 | * snps,tx-sched-dwrr, Deficit Weighted Round Robin | 302 | snps,tx-queues-to-use: |
| 202 | * snps,tx-sched-sp, Strict priority | 303 | $ref: /schemas/types.yaml#/definitions/uint32 |
| 203 | * For each TX queue | 304 | description: number of TX queues to be used in the driver |
| 204 | * snps,weight, TX queue weight (if using a DCB weight | 305 | snps,tx-sched-wrr: |
| 205 | algorithm) | 306 | type: boolean |
| 206 | * Choose one of these modes | 307 | description: Weighted Round Robin |
| 207 | * snps,dcb-algorithm, TX queue will be working in DCB | 308 | snps,tx-sched-wfq: |
| 208 | * snps,avb-algorithm, TX queue will be working in AVB | 309 | type: boolean |
| 209 | [Attention] Queue 0 is reserved for legacy traffic | 310 | description: Weighted Fair Queuing |
| 210 | and so no AVB is available in this queue. | 311 | snps,tx-sched-dwrr: |
| 211 | * Configure Credit Base Shaper (if AVB Mode selected) | 312 | type: boolean |
| 212 | * snps,send_slope, enable Low Power Interface | 313 | description: Deficit Weighted Round Robin |
| 213 | * snps,idle_slope, unlock on WoL | 314 | snps,tx-sched-sp: |
| 214 | * snps,high_credit, max write outstanding req. limit | 315 | type: boolean |
| 215 | * snps,low_credit, max read outstanding req. limit | 316 | description: Strict priority |
| 216 | * snps,priority, bitmask of the priorities assigned to the queue. | 317 | allOf: |
| 217 | When a PFC frame is received with priorities matching the bitmask, | 318 | - if: |
| 218 | the queue is blocked from transmitting for the pause time specified | 319 | required: |
| 219 | in the PFC frame. | 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 | snps,reset-gpio: | 403 | snps,reset-gpio: |
| 222 | deprecated: true | 404 | deprecated: true |
| @@ -463,41 +645,6 @@ additionalProperties: true · 240 unmodified lines | |||
| 463 | 645 | ||
| 464 | examples: | 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 | gmac0: ethernet@e0800000 { | 648 | gmac0: ethernet@e0800000 { |
| 502 | compatible = "snps,dwxgmac-2.10", "snps,dwxgmac"; | 649 | compatible = "snps,dwxgmac-2.10", "snps,dwxgmac"; |
| 503 | reg = <0xe0800000 0x8000>; | 650 | reg = <0xe0800000 0x8000>; |
| @@ -516,6 +663,42 @@ examples: · 12 unmodified lines | |||
| 516 | snps,axi-config = <&stmmac_axi_setup>; | 663 | snps,axi-config = <&stmmac_axi_setup>; |
| 517 | snps,mtl-rx-config = <&mtl_rx_setup>; | 664 | snps,mtl-rx-config = <&mtl_rx_setup>; |
| 518 | snps,mtl-tx-config = <&mtl_tx_setup>; | 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 | mdio0 { | 702 | mdio0 { |
| 520 | #address-cells = <1>; | 703 | #address-cells = <1>; |
| 521 | #size-cells = <0>; | 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 | - mdio : Child node for MDIO bus. Must be defined if PHY access is | 68 | - mdio : Child node for MDIO bus. Must be defined if PHY access is |
| 69 | required through the core's MDIO interface (i.e. always, | 69 | required through the core's MDIO interface (i.e. always, |
| 70 | unless the PHY is accessed through a different bus). | 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 | - pcs-handle: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X | 74 | - pcs-handle: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X |
| 73 | modes, where "pcs-handle" should be used to point | 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 | bluetooth: | 42 | bluetooth: |
| 43 | type: object | 43 | type: object |
| 44 | additionalProperties: false | 44 | additionalProperties: false |
| 45 | allOf: | ||
| 46 | - $ref: /schemas/net/bluetooth/bluetooth-controller.yaml# | ||
| 45 | properties: | 47 | properties: |
| 46 | compatible: | 48 | compatible: |
| 47 | const: qcom,wcnss-bt | 49 | const: qcom,wcnss-bt |
| 48 | 50 | ||
| 49 | local-bd-address: | 51 | local-bd-address: true |
| 50 | $ref: /schemas/types.yaml#/definitions/uint8-array | ||
| 51 | maxItems: 6 | ||
| 52 | description: | ||
| 53 | See Documentation/devicetree/bindings/net/bluetooth.txt | ||
| 54 | 52 | ||
| 55 | required: | 53 | required: |
| 56 | - compatible | 54 | - compatible |
| @@ -566,7 +566,8 @@ miimon · 565 unmodified lines | |||
| 566 | link monitoring. A value of 100 is a good starting point. | 566 | link monitoring. A value of 100 is a good starting point. |
| 567 | The use_carrier option, below, affects how the link state is | 567 | The use_carrier option, below, affects how the link state is |
| 568 | determined. See the High Availability section for additional | 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 | min_links | 572 | min_links |
| 572 | 573 | ||
| @@ -956,6 +957,7 @@ xmit_hash_policy · 383 unmodified lines | |||
| 956 | hash = hash XOR source IP XOR destination IP | 957 | hash = hash XOR source IP XOR destination IP |
| 957 | hash = hash XOR (hash RSHIFT 16) | 958 | hash = hash XOR (hash RSHIFT 16) |
| 958 | hash = hash XOR (hash RSHIFT 8) | 959 | hash = hash XOR (hash RSHIFT 8) |
| 960 | hash = hash RSHIFT 1 | ||
| 959 | And then hash is reduced modulo slave count. | 961 | And then hash is reduced modulo slave count. |
| 960 | 962 | ||
| 961 | If the protocol is IPv6 then the source and destination | 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 | load without any problems ... | 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 | The Virtual CAN Driver (vcan) | 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 | - int dpaa2_mac_connect(struct dpaa2_mac *mac); | 181 | - int dpaa2_mac_connect(struct dpaa2_mac *mac); |
| 182 | - void dpaa2_mac_disconnect(struct dpaa2_mac *mac); | 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. | 184 | A phylink integration is necessary only when the partner DPMAC is not of |
| 185 | One can check for this condition using the below API:: | 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 | Before connection to a MAC, the caller must allocate and populate the | 192 | Before connection to a MAC, the caller must allocate and populate the |
| 190 | dpaa2_mac structure with the associated net_device, a pointer to the MC portal | 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 | Currently, this driver support following devices: | 24 | Currently, this driver support following devices: |
| 25 | * Network controller: Cavium, Inc. Device b200 | 25 | * Network controller: Cavium, Inc. Device b200 |
| 26 | * Network controller: Cavium, Inc. Device b400 | ||
| 26 | 27 | ||
| 27 | Interface Control | 28 | Interface Control |
| 28 | ================= | 29 | ================= |
| @@ -25,7 +25,7 @@ Enabling the driver and kconfig options · 24 unmodified lines | |||
| 25 | | at build time via kernel Kconfig flags. | 25 | | at build time via kernel Kconfig flags. |
| 26 | | Basic features, ethernet net device rx/tx offloads and XDP, are available with the most basic flags | 26 | | Basic features, ethernet net device rx/tx offloads and XDP, are available with the most basic flags |
| 27 | | CONFIG_MLX5_CORE=y/m and CONFIG_MLX5_CORE_EN=y. | 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 | **CONFIG_MLX5_CORE=(y/m/n)** (module mlx5_core.ko) | 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 | **CONFIG_MLX5_EN_IPSEC=(y/n)** | 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 | **CONFIG_MLX5_EN_TLS=(y/n)** | 94 | **CONFIG_MLX5_EN_TLS=(y/n)** |
| 95 | 95 | ||
| 96 | | TLS cryptography-offload accelaration. | 96 | | TLS cryptography-offload acceleration. |
| 97 | 97 | ||
| 98 | 98 | ||
| 99 | **CONFIG_MLX5_INFINIBAND=(y/n/m)** (module mlx5_ib.ko) | 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 | The flow steering mode parameter controls the flow steering mode of the driver. | 139 | The flow steering mode parameter controls the flow steering mode of the driver. |
| 140 | Two modes are supported: | 140 | Two modes are supported: |
| 141 | 1. 'dmfs' - Device managed flow steering. | 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 | In DMFS mode, the HW steering entities are created and managed through the | 144 | In DMFS mode, the HW steering entities are created and managed through the |
| 145 | Firmware. | 145 | Firmware. |
| 146 | In SMFS mode, the HW steering entities are created and managed though by | 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 | User command examples: | 151 | User command examples: |
| 152 | 152 | ||
| @@ -165,9 +165,9 @@ User command examples: · 12 unmodified lines | |||
| 165 | enable_roce: RoCE enablement state | 165 | enable_roce: RoCE enablement state |
| 166 | ---------------------------------- | 166 | ---------------------------------- |
| 167 | RoCE enablement state controls driver support for RoCE traffic. | 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 | User command examples: | 172 | User command examples: |
| 173 | 173 | ||
| @@ -186,7 +186,7 @@ User command examples: · 12 unmodified lines | |||
| 186 | 186 | ||
| 187 | esw_port_metadata: Eswitch port metadata state | 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 | up to 20% depending on the use case and packet sizes. | 190 | up to 20% depending on the use case and packet sizes. |
| 191 | 191 | ||
| 192 | Eswitch port metadata state controls whether to internally tag packets with | 192 | Eswitch port metadata state controls whether to internally tag packets with |
| @@ -253,26 +253,26 @@ mlx5 subfunction · 60 unmodified lines | |||
| 253 | ================ | 253 | ================ |
| 254 | mlx5 supports subfunction management using devlink port (see :ref:`Documentation/networking/devlink/devlink-port.rst <devlink_port>`) interface. | 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 | means a subfunction has its own dedicated queues (txq, rxq, cq, eq). These | 257 | means a subfunction has its own dedicated queues (txq, rxq, cq, eq). These |
| 258 | queues are neither shared nor stolen from the parent PCI function. | 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 | resources neither shared nor stolen from the parent PCI function. | 261 | resources neither shared nor stolen from the parent PCI function. |
| 262 | 262 | ||
| 263 | A subfunction has a dedicated window in PCI BAR space that is not shared | 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 | 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 | 265 | devices (netdev, rdma, vdpa, etc.) of the subfunction accesses only assigned |
| 266 | PCI BAR space. | 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 | offloads. The user configures eswitch to send/receive packets from/to | 269 | offloads. The user configures eswitch to send/receive packets from/to |
| 270 | the subfunction port. | 270 | the subfunction port. |
| 271 | 271 | ||
| 272 | Subfunctions share PCI level resources such as PCI MSI-X IRQs with | 272 | Subfunctions share PCI level resources such as PCI MSI-X IRQs with |
| 273 | other subfunctions and/or with its parent PCI function. | 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 | | admin | | 278 | | admin | |
| @@ -310,7 +310,7 @@ Example mlx5 software, system and device view:: · 31 unmodified lines | |||
| 310 | | (device add/del) | 310 | | (device add/del) |
| 311 | _____|____ ____|________ | 311 | _____|____ ____|________ |
| 312 | | | | subfunction | | 312 | | | | subfunction | |
| 313 | | PCI NIC |---- activate/deactive events---->| host driver | | 313 | | PCI NIC |--- activate/deactivate events--->| host driver | |
| 314 | |__________| | (mlx5_core) | | 314 | |__________| | (mlx5_core) | |
| 315 | |_____________| | 315 | |_____________| |
| 316 | 316 | ||
| @@ -320,7 +320,7 @@ Subfunction is created using devlink port interface. · 3 unmodified lines | |||
| 320 | 320 | ||
| 321 | $ devlink dev eswitch set pci/0000:06:00.0 mode switchdev | 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 | $ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88 | 325 | $ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88 |
| 326 | pci/0000:06:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false | 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 | MAC address setup | 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 | RoCE capability setup |
| 357 | device created for the PCI VF/SF. | 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 | 364 | mlx5 driver support devlink port function attr mechanism to setup RoCE |
| 362 | pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 | 365 | capability. (refer to Documentation/networking/devlink/devlink-port.rst) |
| 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 | ||
| 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 | 372 | mlx5 driver support devlink port function attr mechanism to setup migratable |
| 378 | pci/0000:06:00.0/32768: type eth netdev enp6s0pf0sf88 flavour pcisf pfnum 0 sfnum 88 | 373 | capability. (refer to Documentation/networking/devlink/devlink-port.rst) |
| 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 | ||
| 390 | 374 | ||
| 391 | SF state setup | 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 | attribute. | 378 | attribute. |
| 395 | 379 | ||
| 396 | - Get the state of the SF identified by its unique devlink port index:: | 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 | Additionally, the SF port also gets the event when the driver attaches to the | 432 | Additionally, the SF port also gets the event when the driver attaches to the |
| 449 | auxiliary device of the subfunction. This results in changing the operational | 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 | safe to delete the SF port for graceful termination of the subfunction. | 435 | safe to delete the SF port for graceful termination of the subfunction. |
| 452 | 436 | ||
| 453 | - Show the SF port operational state:: | 437 | - Show the SF port operational state:: |
| @@ -464,14 +448,14 @@ tx reporter · 10 unmodified lines | |||
| 464 | ----------- | 448 | ----------- |
| 465 | The tx reporter is responsible for reporting and recovering of the following two error scenarios: | 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 | Report on kernel tx timeout detection. | 452 | Report on kernel tx timeout detection. |
| 469 | Recover by searching lost interrupts. | 453 | Recover by searching lost interrupts. |
| 470 | - TX error completion | 454 | - tx error completion |
| 471 | Report on error tx completion. | 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 | real time information of its send queues status. | 459 | real time information of its send queues status. |
| 476 | 460 | ||
| 477 | User commands examples: | 461 | User commands examples: |
| @@ -491,32 +475,32 @@ rx reporter · 13 unmodified lines | |||
| 491 | ----------- | 475 | ----------- |
| 492 | The rx reporter is responsible for reporting and recovering of the following two error scenarios: | 476 | The rx reporter is responsible for reporting and recovering of the following two error scenarios: |
| 493 | 477 | ||
| 494 | - RX queues initialization (population) timeout | 478 | - rx queues' initialization (population) timeout |
| 495 | RX queues descriptors population on ring initialization is done in | 479 | Population of rx queues' descriptors on ring initialization is done |
| 496 | napi context via triggering an irq, in case of a failure to get | 480 | in 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 | 481 | the minimum amount of descriptors, a timeout would occur, and |
| 498 | could be recoverable by polling the EQ (Event Queue). | 482 | descriptors could be recovered by polling the EQ (Event Queue). |
| 499 | - RX completions with errors (reported by HW on interrupt context) | 483 | - rx completions with errors (reported by HW on interrupt context) |
| 500 | Report on rx completion error. | 484 | Report on rx completion error. |
| 501 | Recover (if needed) by flushing the related queue and reset it. | 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 | 487 | rx reporter also supports on demand diagnose callback, on which it |
| 504 | provides real time information of its receive queues status. | 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 | $ devlink health diagnose pci/0000:82:00.0 reporter rx | 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 | - Show number of rx errors indicated, number of recover flows ended successfully, | 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 | $ devlink health show pci/0000:82:00.0 reporter rx | 499 | $ devlink health show pci/0000:82:00.0 reporter rx |
| 516 | 500 | ||
| 517 | fw reporter | 501 | fw reporter |
| 518 | ----------- | 502 | ----------- |
| 519 | The fw reporter implements diagnose and dump callbacks. | 503 | The fw reporter implements `diagnose` and `dump` callbacks. |
| 520 | It follows symptoms of fw error such as fw syndrome by triggering | 504 | It follows symptoms of fw error such as fw syndrome by triggering |
| 521 | fw core dump and storing it into the dump buffer. | 505 | fw core dump and storing it into the dump buffer. |
| 522 | The fw reporter diagnose command can be triggered any time by the user to check | 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 | fw fatal reporter | 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 | It follows fatal errors indications by CR-space dump and recover flow. | 525 | It follows fatal errors indications by CR-space dump and recover flow. |
| 542 | The CR-space dump uses vsc interface which is valid even if the FW command | 526 | The CR-space dump uses vsc interface which is valid even if the FW command |
| 543 | interface is not functional, which is the case in most FW fatal errors. | 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 | $ devlink health recover pci/0000:82:00.0 reporter fw_fatal | 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 | $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal | 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 | mlx5 tracepoints | 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 | kernel tracepoints interfaces (refer to Documentation/trace/ftrace.rst). | 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 | tc and eswitch offloads tracepoints: | 553 | tc and eswitch offloads tracepoints: |
| 570 | 554 | ||
| @@ -1,50 +1,57 @@ | |||
| 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
| 2 | .. include:: <isonum.txt> | ||
| 2 | 3 | ||
| 3 | ============================================= | 4 | =========================================== |
| 4 | Netronome Flow Processor (NFP) Kernel Drivers | 5 | Network Flow Processor (NFP) Kernel Drivers |
| 5 | ============================================= | 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 | Contents | 11 | Contents |
| 10 | ======== | 12 | ======== |
| 11 | 13 | ||
| 12 | - `Overview`_ | 14 | - `Overview`_ |
| 13 | - `Acquiring Firmware`_ | 15 | - `Acquiring Firmware`_ |
| 16 | - `Devlink Info`_ | ||
| 17 | - `Configure Device`_ | ||
| 18 | - `Statistics`_ | ||
| 14 | 19 | ||
| 15 | Overview | 20 | Overview |
| 16 | ======== | 21 | ======== |
| 17 | 22 | ||
| 18 | This driver supports Netronome's line of Flow Processor devices, | 23 | This driver supports Netronome and Corigine's line of Network Flow Processor |
| 19 | including the NFP4000, NFP5000, and NFP6000 models, which are also | 24 | devices, including the NFP3800, NFP4000, NFP5000, and NFP6000 models, which |
| 20 | incorporated in the company's family of Agilio SmartNICs. The SR-IOV | 25 | are also incorporated in the companies' family of Agilio SmartNICs. The SR-IOV |
| 21 | physical and virtual functions for these devices are supported by | 26 | physical and virtual functions for these devices are supported by the driver. |
| 22 | the driver. | ||
| 23 | 27 | ||
| 24 | Acquiring Firmware | 28 | Acquiring Firmware |
| 25 | ================== | 29 | ================== |
| 26 | 30 | ||
| 27 | The NFP4000 and NFP6000 devices require application specific firmware | 31 | The NFP3800, NFP4000 and NFP6000 devices require application specific firmware |
| 28 | to function. Application firmware can be located either on the host file system | 32 | to function. Application firmware can be located either on the host file system |
| 29 | or in the device flash (if supported by management firmware). | 33 | or in the device flash (if supported by management firmware). |
| 30 | 34 | ||
| 31 | Firmware files on the host filesystem contain card type (`AMDA-*` string), media | 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 | load firmware from the host file system. | 37 | load firmware from the host file system. |
| 34 | 38 | ||
| 35 | Firmware for basic NIC operation is available in the upstream | 39 | Firmware for basic NIC operation is available in the upstream |
| 36 | `linux-firmware.git` repository. | 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 | Firmware in NVRAM | 45 | Firmware in NVRAM |
| 39 | ----------------- | 46 | ----------------- |
| 40 | 47 | ||
| 41 | Recent versions of management firmware supports loading application | 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 | policy configuration may be used to configure this feature appropriately. | 50 | policy configuration may be used to configure this feature appropriately. |
| 44 | 51 | ||
| 45 | Devlink or ethtool can be used to update the application firmware on the device | 52 | Devlink or ethtool can be used to update the application firmware on the device |
| 46 | flash by providing the appropriate `nic_AMDA*.nffw` file to the respective | 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 | card and media configuration to flash. | 55 | card and media configuration to flash. |
| 49 | 56 | ||
| 50 | Available storage space in flash depends on the card being used. | 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 | which use old `mkinitrd` command instead of `dracut` (e.g. Ubuntu). | 86 | which use old `mkinitrd` command instead of `dracut` (e.g. Ubuntu). |
| 80 | 87 | ||
| 81 | After changing firmware files you may need to regenerate the initramfs | 88 | After changing firmware files you may need to regenerate the initramfs |
| 82 | image. Initramfs contains drivers and firmware files your system may | 89 | image. Initramfs contains drivers and firmware files your system may |
| 83 | need to boot. Refer to the documentation of your distribution to find | 90 | need to boot. Refer to the documentation of your distribution to find |
| 84 | out how to update initramfs. Good indication of stale initramfs | 91 | out how to update initramfs. Good indication of stale initramfs |
| 85 | is system loading wrong driver or firmware on boot, but when driver is | 92 | is system loading wrong driver or firmware on boot, but when driver is |
| 86 | later reloaded manually everything works correctly. | 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 | Most commonly all cards on the system use the same type of firmware. | 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 | 99 | If you want to load a specific firmware image for a specific card, you |
| 93 | can use either the PCI bus address or serial number. Driver will print | 100 | can use either the PCI bus address or serial number. The driver will |
| 94 | which files it's looking for when it recognizes a NFP device:: | 101 | print which files it's looking for when it recognizes a NFP device:: |
| 95 | 102 | ||
| 96 | nfp: Looking for firmware file in order of priority: | 103 | nfp: Looking for firmware file in order of priority: |
| 97 | nfp: netronome/serial-00-12-34-aa-bb-cc-10-ff.nffw: not found | 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 | in initramfs, you will have to refer to documentation of appropriate tools | 113 | in initramfs, you will have to refer to documentation of appropriate tools |
| 107 | to find out how to include them. | 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 | Firmware loading policy | 125 | Firmware loading policy |
| 110 | ----------------------- | 126 | ----------------------- |
| 111 | 127 | ||
| @@ -132,6 +148,115 @@ abi_drv_load_ifc · 20 unmodified lines | |||
| 132 | Defines a list of PF devices allowed to load FW on the device. | 148 | Defines a list of PF devices allowed to load FW on the device. |
| 133 | This variable is not currently user configurable. | 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 | Statistics | 260 | Statistics |
| 136 | ========== | 261 | ========== |
| 137 | 262 | ||
| @@ -198,6 +198,11 @@ fw.bundle_id · 197 unmodified lines | |||
| 198 | 198 | ||
| 199 | Unique identifier of the entire firmware bundle. | 199 | Unique identifier of the entire firmware bundle. |
| 200 | 200 | ||
| 201 | fw.bootloader | ||
| 202 | ------------- | ||
| 203 | |||
| 204 | Version of the bootloader. | ||
| 205 | |||
| 201 | Future work | 206 | Future work |
| 202 | =========== | 207 | =========== |
| 203 | 208 | ||
| @@ -110,7 +110,7 @@ devlink ports for both the controllers. · 109 unmodified lines | |||
| 110 | Function configuration | 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 | function. Usually it means, user should configure function attribute | 114 | function. Usually it means, user should configure function attribute |
| 115 | before a bus specific device for the function is created. However, when | 115 | before a bus specific device for the function is created. However, when |
| 116 | SRIOV is enabled, virtual function devices are created on the PCI bus. | 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 | configure port function attribute before activating the port function. | 119 | configure port function attribute before activating the port function. |
| 120 | 120 | ||
| 121 | A user may set the hardware address of the function using | 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 | this means a MAC address. | 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 | Subfunction | 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 | SRIOV VFs, a subfunction doesn't require its own PCI virtual function. | 248 | SRIOV VFs, a subfunction doesn't require its own PCI virtual function. |
| 131 | A subfunction communicates with the hardware through the parent PCI function. | 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. | 251 | To use a subfunction, 3 steps setup sequence is followed: |
| 134 | (1) create - create a subfunction; | 252 | |
| 135 | (2) configure - configure subfunction attributes; | 253 | 1) create - create a subfunction; |
| 136 | (3) deploy - deploy the subfunction; | 254 | 2) configure - configure subfunction attributes; |
| 255 | 3) deploy - deploy the subfunction; | ||
| 137 | 256 | ||
| 138 | Subfunction management is done using devlink port user interface. | 257 | Subfunction management is done using devlink port user interface. |
| 139 | User performs setup on the subfunction management device. | 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 | ``tx_max`` | 310 | ``tx_max`` |
| 192 | Maximum TX rate value. | 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 | ``parent`` | 328 | ``parent`` |
| 195 | Parent node name. Parent node rate limits are considered as additional limits | 329 | Parent node name. Parent node rate limits are considered as additional limits |
| 196 | to all node children limits. ``tx_max`` is an upper limit for children. | 330 | to all node children limits. ``tx_max`` is an upper limit for children. |
| 197 | ``tx_share`` is a total bandwidth distributed among children. | 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 | Driver implementations are allowed to support both or either rate object types | 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 | Terms and Definitions | 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 | the ``DEVLINK_CMD_REGION_NEW`` request kernel will allocate one and send | 31 | the ``DEVLINK_CMD_REGION_NEW`` request kernel will allocate one and send |
| 32 | the snapshot information to user space. | 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 | example usage | 43 | example usage |
| 35 | ------------- | 44 | ------------- |
| 36 | 45 | ||
| @@ -65,6 +74,10 @@ example usage · 28 unmodified lines | |||
| 65 | $ devlink region read pci/0000:00:05.0/fw-health snapshot 1 address 0 length 16 | 74 | $ devlink region read pci/0000:00:05.0/fw-health snapshot 1 address 0 length 16 |
| 66 | 0000000000000000 0014 95dc 0014 9514 0035 1670 0034 db30 | 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 | As regions are likely very device or driver specific, no generic regions are | 81 | As regions are likely very device or driver specific, no generic regions are |
| 69 | defined. See the driver-specific documentation files for information on the | 82 | defined. See the driver-specific documentation files for information on the |
| 70 | specific regions a driver supports. | 83 | specific regions a driver supports. |
| @@ -485,6 +485,16 @@ be added to the following table: · 484 unmodified lines | |||
| 485 | - Traps incoming packets that the device decided to drop because | 485 | - Traps incoming packets that the device decided to drop because |
| 486 | the destination MAC is not configured in the MAC table and | 486 | the destination MAC is not configured in the MAC table and |
| 487 | the interface is not in promiscuous mode | 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 | Driver-specific Packet Traps | 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 | * - ``parser_error_drops`` | 599 | * - ``parser_error_drops`` |
| 590 | - Contains packet traps for packets that were marked by the device during | 600 | - Contains packet traps for packets that were marked by the device during |
| 591 | parsing as erroneous | 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 | Packet Trap Policers | 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 | * - ``nvm-flash`` | 189 | * - ``nvm-flash`` |
| 190 | - The contents of the entire flash chip, sometimes referred to as | 190 | - The contents of the entire flash chip, sometimes referred to as |
| 191 | the device's Non Volatile Memory. | 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 | * - ``device-caps`` | 197 | * - ``device-caps`` |
| 193 | - The contents of the device firmware's capabilities buffer. Useful to | 198 | - The contents of the device firmware's capabilities buffer. Useful to |
| 194 | determine the current state and configuration of the device. | 199 | determine the current state and configuration of the device. |
| 195 | 200 | ||
| 196 | Users can request an immediate capture of a snapshot via the | 201 | Both the ``nvm-flash`` and ``shadow-ram`` regions can be accessed without a |
| 197 | ``DEVLINK_CMD_REGION_NEW`` | 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 | .. code:: shell | 208 | .. code:: shell |
| 200 | 209 | ||
| @@ -254,3 +263,118 @@ Users can request an immediate capture of a snapshot via the · 53 unmodified lines | |||
| 254 | 0000000000000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 263 | 0000000000000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
| 255 | 264 | ||
| 256 | $ devlink region delete pci/0000:01:00.0/device-caps snapshot 1 | 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 | ``ETHTOOL_MSG_MODULE_GET`` get transceiver module parameters | 222 | ``ETHTOOL_MSG_MODULE_GET`` get transceiver module parameters |
| 223 | ``ETHTOOL_MSG_PSE_SET`` set PSE parameters | 223 | ``ETHTOOL_MSG_PSE_SET`` set PSE parameters |
| 224 | ``ETHTOOL_MSG_PSE_GET`` get PSE parameters | 224 | ``ETHTOOL_MSG_PSE_GET`` get PSE parameters |
| 225 | ``ETHTOOL_MSG_RSS_GET`` get RSS settings | ||
| 225 | ===================================== ================================= | 226 | ===================================== ================================= |
| 226 | 227 | ||
| 227 | Kernel to userspace: | 228 | Kernel to userspace: |
| @@ -263,6 +264,7 @@ Kernel to userspace: · 35 unmodified lines | |||
| 263 | ``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info | 264 | ``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info |
| 264 | ``ETHTOOL_MSG_MODULE_GET_REPLY`` transceiver module parameters | 265 | ``ETHTOOL_MSG_MODULE_GET_REPLY`` transceiver module parameters |
| 265 | ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters | 266 | ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters |
| 267 | ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings | ||
| 266 | ======================================== ================================= | 268 | ======================================== ================================= |
| 267 | 269 | ||
| 268 | ``GET`` requests are sent by userspace applications to retrieve device | 270 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -491,6 +493,7 @@ Kernel response contents: · 222 unmodified lines | |||
| 491 | ``ETHTOOL_A_LINKSTATE_SQI_MAX`` u32 Max support SQI value | 493 | ``ETHTOOL_A_LINKSTATE_SQI_MAX`` u32 Max support SQI value |
| 492 | ``ETHTOOL_A_LINKSTATE_EXT_STATE`` u8 link extended state | 494 | ``ETHTOOL_A_LINKSTATE_EXT_STATE`` u8 link extended state |
| 493 | ``ETHTOOL_A_LINKSTATE_EXT_SUBSTATE`` u8 link extended substate | 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 | For most NIC drivers, the value of ``ETHTOOL_A_LINKSTATE_LINK`` returns | 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 | ``IEEE 802.3-2018`` 30.15.1.2.1 acPoDLPSEAdminControl. See | 1689 | ``IEEE 802.3-2018`` 30.15.1.2.1 acPoDLPSEAdminControl. See |
| 1687 | ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` for supported values. | 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 | Request translation | 1719 | Request translation |
| 1690 | =================== | 1720 | =================== |
| 1691 | 1721 | ||
| @@ -1767,7 +1797,7 @@ are netlink only. · 75 unmodified lines | |||
| 1767 | ``ETHTOOL_GMODULEEEPROM`` ``ETHTOOL_MSG_MODULE_EEPROM_GET`` | 1797 | ``ETHTOOL_GMODULEEEPROM`` ``ETHTOOL_MSG_MODULE_EEPROM_GET`` |
| 1768 | ``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET`` | 1798 | ``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET`` |
| 1769 | ``ETHTOOL_SEEE`` ``ETHTOOL_MSG_EEE_SET`` | 1799 | ``ETHTOOL_SEEE`` ``ETHTOOL_MSG_EEE_SET`` |
| 1770 | ``ETHTOOL_GRSSH`` n/a | 1800 | ``ETHTOOL_GRSSH`` ``ETHTOOL_MSG_RSS_GET`` |
| 1771 | ``ETHTOOL_SRSSH`` n/a | 1801 | ``ETHTOOL_SRSSH`` n/a |
| 1772 | ``ETHTOOL_GTUNABLE`` n/a | 1802 | ``ETHTOOL_GTUNABLE`` n/a |
| 1773 | ``ETHTOOL_STUNABLE`` n/a | 1803 | ``ETHTOOL_STUNABLE`` n/a |
| @@ -104,6 +104,7 @@ Contents: · 103 unmodified lines | |||
| 104 | switchdev | 104 | switchdev |
| 105 | sysfs-tagging | 105 | sysfs-tagging |
| 106 | tc-actions-env-rules | 106 | tc-actions-env-rules |
| 107 | tc-queue-filters | ||
| 107 | tcp-thin | 108 | tcp-thin |
| 108 | team | 109 | team |
| 109 | timestamping | 110 | timestamping |
| @@ -1069,6 +1069,81 @@ tcp_child_ehash_entries - INTEGER · 1068 unmodified lines | |||
| 1069 | 1069 | ||
| 1070 | Default: 0 | 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 | UDP variables | 1147 | UDP variables |
| 1073 | ============= | 1148 | ============= |
| 1074 | 1149 | ||
| @@ -1102,6 +1177,33 @@ udp_rmem_min - INTEGER · 27 unmodified lines | |||
| 1102 | udp_wmem_min - INTEGER | 1177 | udp_wmem_min - INTEGER |
| 1103 | UDP does not have tx memory accounting and this tunable has no effect. | 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 | RAW variables | 1207 | RAW variables |
| 1106 | ============= | 1208 | ============= |
| 1107 | 1209 | ||
| @@ -3025,6 +3127,15 @@ ecn_enable - BOOLEAN · 1917 unmodified lines | |||
| 3025 | 3127 | ||
| 3026 | Default: 1 | 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 | ``/proc/sys/net/core/*`` | 3140 | ``/proc/sys/net/core/*`` |
| 3030 | ======================== | 3141 | ======================== |
| @@ -129,6 +129,26 @@ drop_packet - INTEGER · 128 unmodified lines | |||
| 129 | threshold. When the mode 3 is set, the always mode drop rate | 129 | threshold. When the mode 3 is set, the always mode drop rate |
| 130 | is controlled by the /proc/sys/net/ipv4/vs/am_droprate. | 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 | expire_nodest_conn - BOOLEAN | 152 | expire_nodest_conn - BOOLEAN |
| 133 | - 0 - disabled (default) | 153 | - 0 - disabled (default) |
| 134 | - not 0 - enabled | 154 | - not 0 - enabled |
| @@ -304,8 +324,8 @@ run_estimation - BOOLEAN · 169 unmodified lines | |||
| 304 | 0 - disabled | 324 | 0 - disabled |
| 305 | not 0 - enabled (default) | 325 | not 0 - enabled (default) |
| 306 | 326 | ||
| 307 | If disabled, the estimation will be stop, and you can't see | 327 | If disabled, the estimation will be suspended and kthread tasks |
| 308 | any update on speed estimation data. | 328 | stopped. |
| 309 | 329 | ||
| 310 | You can always re-enable estimation by setting this value to 1. | 330 | You can always re-enable estimation by setting this value to 1. |
| 311 | But be careful, the first estimation after re-enable is not | 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 | identifier and returns that along with the timestamp. The identifier | 179 | identifier and returns that along with the timestamp. The identifier |
| 180 | is derived from a per-socket u32 counter (that wraps). For datagram | 180 | is derived from a per-socket u32 counter (that wraps). For datagram |
| 181 | sockets, the counter increments with each sent packet. For stream | 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 | The counter starts at zero. It is initialized the first time that | 185 | The counter starts at zero. It is initialized the first time that |
| 185 | the socket option is enabled. It is reset each time the option is | 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 | among all possibly concurrently outstanding timestamp requests for | 193 | among all possibly concurrently outstanding timestamp requests for |
| 193 | that socket. | 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 | SOF_TIMESTAMPING_OPT_CMSG: | 226 | SOF_TIMESTAMPING_OPT_CMSG: |
| 197 | Support recv() cmsg for all timestamped packets. Control messages | 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 | Shannon Nelson <shannon.nelson@oracle.com> | 7 | Shannon Nelson <shannon.nelson@oracle.com> |
| 8 | Leon Romanovsky <leonro@nvidia.com> | ||
| 8 | 9 | ||
| 9 | 10 | ||
| 10 | Overview | 11 | Overview |
| @@ -18,10 +19,21 @@ can radically increase throughput and decrease CPU utilization. The XFRM · 7 unmodified lines | |||
| 18 | Device interface allows NIC drivers to offer to the stack access to the | 19 | Device interface allows NIC drivers to offer to the stack access to the |
| 19 | hardware offload. | 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 | Userland access to the offload is typically through a system such as | 33 | Userland access to the offload is typically through a system such as |
| 22 | libreswan or KAME/raccoon, but the iproute2 'ip xfrm' command set can | 34 | libreswan or KAME/raccoon, but the iproute2 'ip xfrm' command set can |
| 23 | be handy when experimenting. An example command might look something | 35 | be handy when experimenting. An example command might look something |
| 24 | like this:: | 36 | like this for crypto offload: |
| 25 | 37 | ||
| 26 | ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport \ | 38 | ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport \ |
| 27 | reqid 0x07 replay-window 32 \ | 39 | reqid 0x07 replay-window 32 \ |
| @@ -29,6 +41,17 @@ like this:: · 1 unmodified line | |||
| 29 | sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp \ | 41 | sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp \ |
| 30 | offload dev eth4 dir in | 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 | Yes, that's ugly, but that's what shell scripts and/or libreswan are for. | 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 | /* from include/linux/netdevice.h */ | 64 | /* from include/linux/netdevice.h */ |
| 42 | struct xfrmdev_ops { | 65 | struct xfrmdev_ops { |
| 66 | /* Crypto and Packet offload callbacks */ | ||
| 43 | int (*xdo_dev_state_add) (struct xfrm_state *x); | 67 | int (*xdo_dev_state_add) (struct xfrm_state *x); |
| 44 | void (*xdo_dev_state_delete) (struct xfrm_state *x); | 68 | void (*xdo_dev_state_delete) (struct xfrm_state *x); |
| 45 | void (*xdo_dev_state_free) (struct xfrm_state *x); | 69 | void (*xdo_dev_state_free) (struct xfrm_state *x); |
| 46 | bool (*xdo_dev_offload_ok) (struct sk_buff *skb, | 70 | bool (*xdo_dev_offload_ok) (struct sk_buff *skb, |
| 47 | struct xfrm_state *x); | 71 | struct xfrm_state *x); |
| 48 | void (*xdo_dev_state_advance_esn) (struct xfrm_state *x); | 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 | 81 | The NIC driver offering ipsec offload will need to implement callbacks |
| 52 | callbacks to make the offload available to the network stack's | 82 | relevant to supported offload to make the offload available to the network |
| 53 | XFRM subsystem. Additionally, the feature bits NETIF_F_HW_ESP and | 83 | stack's XFRM subsystem. Additionally, the feature bits NETIF_F_HW_ESP and |
| 54 | NETIF_F_HW_ESP_TX_CSUM will signal the availability of the offload. | 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 | 0 success | 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 | other fail the request | 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 | offload can be supported (e.g. IPv4 or IPv6, no IPv4 options, etc) and | 127 | offload can be supported (e.g. IPv4 or IPv6, no IPv4 options, etc) and |
| 97 | return true of false to signify its support. | 128 | return true of false to signify its support. |
| 98 | 129 | ||
| 130 | Crypto offload mode: | ||
| 99 | When ready to send, the driver needs to inspect the Tx packet for the | 131 | When ready to send, the driver needs to inspect the Tx packet for the |
| 100 | offload information, including the opaque context, and set up the packet | 132 | offload information, including the opaque context, and set up the packet |
| 101 | send accordingly:: | 133 | send accordingly:: |
| @@ -139,13 +171,25 @@ the stack in xfrm_input(). · 37 unmodified lines | |||
| 139 | In ESN mode, xdo_dev_state_advance_esn() is called from xfrm_replay_advance_esn(). | 171 | In ESN mode, xdo_dev_state_advance_esn() is called from xfrm_replay_advance_esn(). |
| 140 | Driver will check packet seq number and update HW ESN state machine if needed. | 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 | When the SA is removed by the user, the driver's xdo_dev_state_delete() | 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 | 180 | and xdo_dev_policy_delete() are asked to disable the offload. Later, |
| 144 | from a garbage collection routine after all reference counts to the state | 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 | have been removed and any remaining resources can be cleared for the | 183 | have been removed and any remaining resources can be cleared for the |
| 146 | offload state. How these are used by the driver will depend on specific | 184 | offload state. How these are used by the driver will depend on specific |
| 147 | hardware needs. | 185 | hardware needs. |
| 148 | 186 | ||
| 149 | As a netdev is set to DOWN the XFRM stack's netdev listener will call | 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 | 188 | xdo_dev_state_delete(), xdo_dev_policy_delete(), xdo_dev_state_free() and |
| 151 | states. | 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 | F: Documentation/devicetree/bindings/iommu/apple,dart.yaml | 1932 | F: Documentation/devicetree/bindings/iommu/apple,dart.yaml |
| 1933 | F: Documentation/devicetree/bindings/iommu/apple,sart.yaml | 1933 | F: Documentation/devicetree/bindings/iommu/apple,sart.yaml |
| 1934 | F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml | 1934 | F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml |
| 1935 | F: Documentation/devicetree/bindings/net/bluetooth/brcm,bcm4377-bluetooth.yaml | ||
| 1935 | F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml | 1936 | F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml |
| 1936 | F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml | 1937 | F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml |
| 1937 | F: Documentation/devicetree/bindings/pci/apple,pcie.yaml | 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 | F: Documentation/devicetree/bindings/power/apple* | 1940 | F: Documentation/devicetree/bindings/power/apple* |
| 1940 | F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml | 1941 | F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml |
| 1941 | F: arch/arm64/boot/dts/apple/ | 1942 | F: arch/arm64/boot/dts/apple/ |
| 1943 | F: drivers/bluetooth/hci_bcm4377.c | ||
| 1942 | F: drivers/clk/clk-apple-nco.c | 1944 | F: drivers/clk/clk-apple-nco.c |
| 1943 | F: drivers/cpufreq/apple-soc-cpufreq.c | 1945 | F: drivers/cpufreq/apple-soc-cpufreq.c |
| 1944 | F: drivers/dma/apple-admac.c | 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 | S: Supported | 2472 | S: Supported |
| 2471 | T: git git://github.com/microchip-ung/linux-upstream.git | 2473 | T: git git://github.com/microchip-ung/linux-upstream.git |
| 2472 | F: arch/arm64/boot/dts/microchip/ | 2474 | F: arch/arm64/boot/dts/microchip/ |
| 2475 | F: drivers/net/ethernet/microchip/vcap/ | ||
| 2473 | F: drivers/pinctrl/pinctrl-microchip-sgpio.c | 2476 | F: drivers/pinctrl/pinctrl-microchip-sgpio.c |
| 2474 | N: sparx5 | 2477 | N: sparx5 |
| 2475 | 2478 | ||
| @@ -6362,6 +6365,7 @@ F: drivers/net/ethernet/freescale/dpaa2/Kconfig · 3886 unmodified lines | |||
| 6362 | F: drivers/net/ethernet/freescale/dpaa2/Makefile | 6365 | F: drivers/net/ethernet/freescale/dpaa2/Makefile |
| 6363 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth* | 6366 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth* |
| 6364 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-mac* | 6367 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-mac* |
| 6368 | F: drivers/net/ethernet/freescale/dpaa2/dpaa2-xsk* | ||
| 6365 | F: drivers/net/ethernet/freescale/dpaa2/dpkg.h | 6369 | F: drivers/net/ethernet/freescale/dpaa2/dpkg.h |
| 6366 | F: drivers/net/ethernet/freescale/dpaa2/dpmac* | 6370 | F: drivers/net/ethernet/freescale/dpaa2/dpmac* |
| 6367 | F: drivers/net/ethernet/freescale/dpaa2/dpni* | 6371 | F: drivers/net/ethernet/freescale/dpaa2/dpni* |
| @@ -7734,6 +7738,7 @@ ETAS ES58X CAN/USB DRIVER · 1366 unmodified lines | |||
| 7734 | M: Vincent Mailhol <mailhol.vincent@wanadoo.fr> | 7738 | M: Vincent Mailhol <mailhol.vincent@wanadoo.fr> |
| 7735 | L: linux-can@vger.kernel.org | 7739 | L: linux-can@vger.kernel.org |
| 7736 | S: Maintained | 7740 | S: Maintained |
| 7741 | F: Documentation/networking/devlink/etas_es58x.rst | ||
| 7737 | F: drivers/net/can/usb/etas_es58x/ | 7742 | F: drivers/net/can/usb/etas_es58x/ |
| 7738 | 7743 | ||
| 7739 | ETHERNET BRIDGE | 7744 | ETHERNET BRIDGE |
| @@ -8236,7 +8241,10 @@ S: Maintained · 496 unmodified lines | |||
| 8236 | F: drivers/i2c/busses/i2c-cpm.c | 8241 | F: drivers/i2c/busses/i2c-cpm.c |
| 8237 | 8242 | ||
| 8238 | FREESCALE IMX / MXC FEC DRIVER | 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 | L: netdev@vger.kernel.org | 8248 | L: netdev@vger.kernel.org |
| 8241 | S: Maintained | 8249 | S: Maintained |
| 8242 | F: Documentation/devicetree/bindings/net/fsl,fec.yaml | 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 | F: drivers/iio/humidity/hts221* | 9501 | F: drivers/iio/humidity/hts221* |
| 9494 | 9502 | ||
| 9495 | HUAWEI ETHERNET DRIVER | 9503 | HUAWEI ETHERNET DRIVER |
| 9504 | M: Cai Huoqing <cai.huoqing@linux.dev> | ||
| 9496 | L: netdev@vger.kernel.org | 9505 | L: netdev@vger.kernel.org |
| 9497 | S: Orphan | 9506 | S: Maintained |
| 9498 | F: Documentation/networking/device_drivers/ethernet/huawei/hinic.rst | 9507 | F: Documentation/networking/device_drivers/ethernet/huawei/hinic.rst |
| 9499 | F: drivers/net/ethernet/huawei/hinic/ | 9508 | F: drivers/net/ethernet/huawei/hinic/ |
| 9500 | 9509 | ||
| @@ -9597,6 +9606,7 @@ F: include/asm-generic/hyperv-tlfs.h · 96 unmodified lines | |||
| 9597 | F: include/asm-generic/mshyperv.h | 9606 | F: include/asm-generic/mshyperv.h |
| 9598 | F: include/clocksource/hyperv_timer.h | 9607 | F: include/clocksource/hyperv_timer.h |
| 9599 | F: include/linux/hyperv.h | 9608 | F: include/linux/hyperv.h |
| 9609 | F: include/net/mana | ||
| 9600 | F: include/uapi/linux/hyperv.h | 9610 | F: include/uapi/linux/hyperv.h |
| 9601 | F: net/vmw_vsock/hyperv_transport.c | 9611 | F: net/vmw_vsock/hyperv_transport.c |
| 9602 | F: tools/hv/ | 9612 | F: tools/hv/ |
| @@ -12410,7 +12420,7 @@ M: Marcin Wojtas <mw@semihalf.com> · 2807 unmodified lines | |||
| 12410 | M: Russell King <linux@armlinux.org.uk> | 12420 | M: Russell King <linux@armlinux.org.uk> |
| 12411 | L: netdev@vger.kernel.org | 12421 | L: netdev@vger.kernel.org |
| 12412 | S: Maintained | 12422 | S: Maintained |
| 12413 | F: Documentation/devicetree/bindings/net/marvell-pp2.txt | 12423 | F: Documentation/devicetree/bindings/net/marvell,pp2.yaml |
| 12414 | F: drivers/net/ethernet/marvell/mvpp2/ | 12424 | F: drivers/net/ethernet/marvell/mvpp2/ |
| 12415 | 12425 | ||
| 12416 | MARVELL MWIFIEX WIRELESS DRIVER | 12426 | MARVELL MWIFIEX WIRELESS DRIVER |
| @@ -12458,7 +12468,7 @@ F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst · 41 unmodified lines | |||
| 12458 | F: drivers/net/ethernet/marvell/octeontx2/af/ | 12468 | F: drivers/net/ethernet/marvell/octeontx2/af/ |
| 12459 | 12469 | ||
| 12460 | MARVELL PRESTERA ETHERNET SWITCH DRIVER | 12470 | MARVELL PRESTERA ETHERNET SWITCH DRIVER |
| 12461 | M: Taras Chornyi <tchornyi@marvell.com> | 12471 | M: Taras Chornyi <taras.chornyi@plvision.eu> |
| 12462 | S: Supported | 12472 | S: Supported |
| 12463 | W: https://github.com/Marvell-switching/switchdev-prestera | 12473 | W: https://github.com/Marvell-switching/switchdev-prestera |
| 12464 | F: drivers/net/ethernet/marvell/prestera/ | 12474 | F: drivers/net/ethernet/marvell/prestera/ |
| @@ -13017,6 +13027,7 @@ M: Felix Fietkau <nbd@nbd.name> · 552 unmodified lines | |||
| 13017 | M: John Crispin <john@phrozen.org> | 13027 | M: John Crispin <john@phrozen.org> |
| 13018 | M: Sean Wang <sean.wang@mediatek.com> | 13028 | M: Sean Wang <sean.wang@mediatek.com> |
| 13019 | M: Mark Lee <Mark-MC.Lee@mediatek.com> | 13029 | M: Mark Lee <Mark-MC.Lee@mediatek.com> |
| 13030 | M: Lorenzo Bianconi <lorenzo@kernel.org> | ||
| 13020 | L: netdev@vger.kernel.org | 13031 | L: netdev@vger.kernel.org |
| 13021 | S: Maintained | 13032 | S: Maintained |
| 13022 | F: drivers/net/ethernet/mediatek/ | 13033 | F: drivers/net/ethernet/mediatek/ |
| @@ -14048,6 +14059,7 @@ F: include/uapi/linux/meye.h · 1025 unmodified lines | |||
| 14048 | 14059 | ||
| 14049 | MOTORCOMM PHY DRIVER | 14060 | MOTORCOMM PHY DRIVER |
| 14050 | M: Peter Geis <pgwipeout@gmail.com> | 14061 | M: Peter Geis <pgwipeout@gmail.com> |
| 14062 | M: Frank <Frank.Sae@motor-comm.com> | ||
| 14051 | L: netdev@vger.kernel.org | 14063 | L: netdev@vger.kernel.org |
| 14052 | S: Maintained | 14064 | S: Maintained |
| 14053 | F: drivers/net/phy/motorcomm.c | 14065 | F: drivers/net/phy/motorcomm.c |
| @@ -19175,7 +19187,7 @@ M: Jassi Brar <jaswinder.singh@linaro.org> · 5121 unmodified lines | |||
| 19175 | M: Ilias Apalodimas <ilias.apalodimas@linaro.org> | 19187 | M: Ilias Apalodimas <ilias.apalodimas@linaro.org> |
| 19176 | L: netdev@vger.kernel.org | 19188 | L: netdev@vger.kernel.org |
| 19177 | S: Maintained | 19189 | S: Maintained |
| 19178 | F: Documentation/devicetree/bindings/net/socionext-netsec.txt | 19190 | F: Documentation/devicetree/bindings/net/socionext,synquacer-netsec.yaml |
| 19179 | F: drivers/net/ethernet/socionext/netsec.c | 19191 | F: drivers/net/ethernet/socionext/netsec.c |
| 19180 | 19192 | ||
| 19181 | SOCIONEXT (SNI) Synquacer SPI DRIVER | 19193 | SOCIONEXT (SNI) Synquacer SPI DRIVER |
| @@ -20828,7 +20840,6 @@ W: https://wireless.wiki.kernel.org/en/users/Drivers/wl12xx · 1646 unmodified lines | |||
| 20828 | W: https://wireless.wiki.kernel.org/en/users/Drivers/wl1251 | 20840 | W: https://wireless.wiki.kernel.org/en/users/Drivers/wl1251 |
| 20829 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git | 20841 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git |
| 20830 | F: drivers/net/wireless/ti/ | 20842 | F: drivers/net/wireless/ti/ |
| 20831 | F: include/linux/wl12xx.h | ||
| 20832 | 20843 | ||
| 20833 | TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER | 20844 | TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER |
| 20834 | M: John Stultz <jstultz@google.com> | 20845 | M: John Stultz <jstultz@google.com> |
| @@ -178,6 +178,8 @@ · 177 unmodified lines | |||
| 178 | 178 | ||
| 179 | /* Network controller */ | 179 | /* Network controller */ |
| 180 | ethernet: ethernet@f0000 { | 180 | ethernet: ethernet@f0000 { |
| 181 | #address-cells = <1>; | ||
| 182 | #size-cells = <0>; | ||
| 181 | compatible = "marvell,armada-375-pp2"; | 183 | compatible = "marvell,armada-375-pp2"; |
| 182 | reg = <0xf0000 0xa000>, /* Packet Processor regs */ | 184 | reg = <0xf0000 0xa000>, /* Packet Processor regs */ |
| 183 | <0xc0000 0x3060>, /* LMS regs */ | 185 | <0xc0000 0x3060>, /* LMS regs */ |
| @@ -187,15 +189,17 @@ · 3 unmodified lines | |||
| 187 | clock-names = "pp_clk", "gop_clk"; | 189 | clock-names = "pp_clk", "gop_clk"; |
| 188 | status = "disabled"; | 190 | status = "disabled"; |
| 189 | 191 | ||
| 190 | eth0: eth0 { | 192 | eth0: ethernet-port@0 { |
| 191 | interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; | 193 | interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; |
| 192 | port-id = <0>; | 194 | reg = <0>; |
| 195 | port-id = <0>; /* For backward compatibility. */ | ||
| 193 | status = "disabled"; | 196 | status = "disabled"; |
| 194 | }; | 197 | }; |
| 195 | 198 | ||
| 196 | eth1: eth1 { | 199 | eth1: ethernet-port@1 { |
| 197 | interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; | 200 | interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; |
| 198 | port-id = <1>; | 201 | reg = <1>; |
| 202 | port-id = <1>; /* For backward compatibility. */ | ||
| 199 | status = "disabled"; | 203 | status = "disabled"; |
| 200 | }; | 204 | }; |
| 201 | }; | 205 | }; |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | |||
| 10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/of_platform.h> | 12 | #include <linux/of_platform.h> |
| 13 | #include <linux/wl12xx.h> | ||
| 14 | #include <linux/mmc/card.h> | 13 | #include <linux/mmc/card.h> |
| 15 | #include <linux/mmc/host.h> | 14 | #include <linux/mmc/host.h> |
| 16 | #include <linux/power/smartreflex.h> | 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 | &wifi0 { | 28 | &wifi0 { |
| 25 | brcm,board-type = "apple,atlantisb"; | 29 | brcm,board-type = "apple,atlantisb"; |
| 26 | }; | 30 | }; |
| @@ -17,6 +17,10 @@ · 16 unmodified lines | |||
| 17 | model = "Apple MacBook Pro (13-inch, M1, 2020)"; | 17 | model = "Apple MacBook Pro (13-inch, M1, 2020)"; |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | &bluetooth0 { | ||
| 21 | brcm,board-type = "apple,honshu"; | ||
| 22 | }; | ||
| 23 | |||
| 20 | &wifi0 { | 24 | &wifi0 { |
| 21 | brcm,board-type = "apple,honshu"; | 25 | brcm,board-type = "apple,honshu"; |
| 22 | }; | 26 | }; |
| @@ -17,6 +17,10 @@ · 16 unmodified lines | |||
| 17 | model = "Apple MacBook Air (M1, 2020)"; | 17 | model = "Apple MacBook Air (M1, 2020)"; |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | &bluetooth0 { | ||
| 21 | brcm,board-type = "apple,shikoku"; | ||
| 22 | }; | ||
| 23 | |||
| 20 | &wifi0 { | 24 | &wifi0 { |
| 21 | brcm,board-type = "apple,shikoku"; | 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 | &wifi0 { | 28 | &wifi0 { |
| 25 | brcm,board-type = "apple,capri"; | 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 | &wifi0 { | 28 | &wifi0 { |
| 25 | brcm,board-type = "apple,santorini"; | 29 | brcm,board-type = "apple,santorini"; |
| 26 | }; | 30 | }; |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | / { | 12 | / { |
| 13 | aliases { | 13 | aliases { |
| 14 | bluetooth0 = &bluetooth0; | ||
| 14 | serial0 = &serial0; | 15 | serial0 = &serial0; |
| 15 | serial2 = &serial2; | 16 | serial2 = &serial2; |
| 16 | wifi0 = &wifi0; | 17 | wifi0 = &wifi0; |
| @@ -77,6 +78,13 @@ · 60 unmodified lines | |||
| 77 | local-mac-address = [00 00 00 00 00 00]; | 78 | local-mac-address = [00 00 00 00 00 00]; |
| 78 | apple,antenna-sku = "XX"; | 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 | &nco_clkref { | 90 | &nco_clkref { |
| @@ -24,9 +24,12 @@ · 23 unmodified lines | |||
| 24 | 24 | ||
| 25 | /* these aliases provide the FMan ports mapping */ | 25 | /* these aliases provide the FMan ports mapping */ |
| 26 | enet0: ethernet@e0000 { | 26 | enet0: ethernet@e0000 { |
| 27 | pcs-handle-names = "qsgmii"; | ||
| 27 | }; | 28 | }; |
| 28 | 29 | ||
| 29 | enet1: ethernet@e2000 { | 30 | enet1: ethernet@e2000 { |
| 31 | pcsphy-handle = <&pcsphy1>, <&qsgmiib_pcs1>; | ||
| 32 | pcs-handle-names = "sgmii", "qsgmii"; | ||
| 30 | }; | 33 | }; |
| 31 | 34 | ||
| 32 | enet2: ethernet@e4000 { | 35 | enet2: ethernet@e4000 { |
| @@ -36,11 +39,32 @@ · 3 unmodified lines | |||
| 36 | }; | 39 | }; |
| 37 | 40 | ||
| 38 | enet4: ethernet@e8000 { | 41 | enet4: ethernet@e8000 { |
| 42 | pcsphy-handle = <&pcsphy4>, <&qsgmiib_pcs2>; | ||
| 43 | pcs-handle-names = "sgmii", "qsgmii"; | ||
| 39 | }; | 44 | }; |
| 40 | 45 | ||
| 41 | enet5: ethernet@ea000 { | 46 | enet5: ethernet@ea000 { |
| 47 | pcsphy-handle = <&pcsphy5>, <&qsgmiib_pcs3>; | ||
| 48 | pcs-handle-names = "sgmii", "qsgmii"; | ||
| 42 | }; | 49 | }; |
| 43 | 50 | ||
| 44 | enet6: ethernet@f0000 { | 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 | &fman0 { | 23 | &fman0 { |
| 24 | /* these aliases provide the FMan ports mapping */ | 24 | /* these aliases provide the FMan ports mapping */ |
| 25 | enet0: ethernet@e0000 { | 25 | enet0: ethernet@e0000 { |
| 26 | pcsphy-handle = <&qsgmiib_pcs3>; | ||
| 27 | pcs-handle-names = "qsgmii"; | ||
| 26 | }; | 28 | }; |
| 27 | 29 | ||
| 28 | enet1: ethernet@e2000 { | 30 | enet1: ethernet@e2000 { |
| @@ -35,14 +37,37 @@ · 6 unmodified lines | |||
| 35 | }; | 37 | }; |
| 36 | 38 | ||
| 37 | enet4: ethernet@e8000 { | 39 | enet4: ethernet@e8000 { |
| 40 | pcsphy-handle = <&pcsphy4>, <&qsgmiib_pcs1>; | ||
| 41 | pcs-handle-names = "sgmii", "qsgmii"; | ||
| 38 | }; | 42 | }; |
| 39 | 43 | ||
| 40 | enet5: ethernet@ea000 { | 44 | enet5: ethernet@ea000 { |
| 45 | pcsphy-handle = <&pcsphy5>, <&pcsphy5>; | ||
| 46 | pcs-handle-names = "sgmii", "qsgmii"; | ||
| 41 | }; | 47 | }; |
| 42 | 48 | ||
| 43 | enet6: ethernet@f0000 { | 49 | enet6: ethernet@f0000 { |
| 44 | }; | 50 | }; |
| 45 | 51 | ||
| 46 | enet7: ethernet@f2000 { | 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 | ranges = <0x0 0x0 ADDRESSIFY(CP11X_BASE) 0x2000000>; | 58 | ranges = <0x0 0x0 ADDRESSIFY(CP11X_BASE) 0x2000000>; |
| 59 | 59 | ||
| 60 | CP11X_LABEL(ethernet): ethernet@0 { | 60 | CP11X_LABEL(ethernet): ethernet@0 { |
| 61 | #address-cells = <1>; | ||
| 62 | #size-cells = <0>; | ||
| 61 | compatible = "marvell,armada-7k-pp22"; | 63 | compatible = "marvell,armada-7k-pp22"; |
| 62 | reg = <0x0 0x100000>, <0x129000 0xb000>, <0x220000 0x800>; | 64 | reg = <0x0 0x100000>, <0x129000 0xb000>, <0x220000 0x800>; |
| 63 | clocks = <&CP11X_LABEL(clk) 1 3>, <&CP11X_LABEL(clk) 1 9>, | 65 | clocks = <&CP11X_LABEL(clk) 1 3>, <&CP11X_LABEL(clk) 1 9>, |
| @@ -69,7 +71,7 @@ · 5 unmodified lines | |||
| 69 | status = "disabled"; | 71 | status = "disabled"; |
| 70 | dma-coherent; | 72 | dma-coherent; |
| 71 | 73 | ||
| 72 | CP11X_LABEL(eth0): eth0 { | 74 | CP11X_LABEL(eth0): ethernet-port@0 { |
| 73 | interrupts = <39 IRQ_TYPE_LEVEL_HIGH>, | 75 | interrupts = <39 IRQ_TYPE_LEVEL_HIGH>, |
| 74 | <43 IRQ_TYPE_LEVEL_HIGH>, | 76 | <43 IRQ_TYPE_LEVEL_HIGH>, |
| 75 | <47 IRQ_TYPE_LEVEL_HIGH>, | 77 | <47 IRQ_TYPE_LEVEL_HIGH>, |
| @@ -83,12 +85,13 @@ · 7 unmodified lines | |||
| 83 | interrupt-names = "hif0", "hif1", "hif2", | 85 | interrupt-names = "hif0", "hif1", "hif2", |
| 84 | "hif3", "hif4", "hif5", "hif6", "hif7", | 86 | "hif3", "hif4", "hif5", "hif6", "hif7", |
| 85 | "hif8", "link"; | 87 | "hif8", "link"; |
| 86 | port-id = <0>; | 88 | reg = <0>; |
| 89 | port-id = <0>; /* For backward compatibility. */ | ||
| 87 | gop-port-id = <0>; | 90 | gop-port-id = <0>; |
| 88 | status = "disabled"; | 91 | status = "disabled"; |
| 89 | }; | 92 | }; |
| 90 | 93 | ||
| 91 | CP11X_LABEL(eth1): eth1 { | 94 | CP11X_LABEL(eth1): ethernet-port@1 { |
| 92 | interrupts = <40 IRQ_TYPE_LEVEL_HIGH>, | 95 | interrupts = <40 IRQ_TYPE_LEVEL_HIGH>, |
| 93 | <44 IRQ_TYPE_LEVEL_HIGH>, | 96 | <44 IRQ_TYPE_LEVEL_HIGH>, |
| 94 | <48 IRQ_TYPE_LEVEL_HIGH>, | 97 | <48 IRQ_TYPE_LEVEL_HIGH>, |
| @@ -102,12 +105,13 @@ · 7 unmodified lines | |||
| 102 | interrupt-names = "hif0", "hif1", "hif2", | 105 | interrupt-names = "hif0", "hif1", "hif2", |
| 103 | "hif3", "hif4", "hif5", "hif6", "hif7", | 106 | "hif3", "hif4", "hif5", "hif6", "hif7", |
| 104 | "hif8", "link"; | 107 | "hif8", "link"; |
| 105 | port-id = <1>; | 108 | reg = <1>; |
| 109 | port-id = <1>; /* For backward compatibility. */ | ||
| 106 | gop-port-id = <2>; | 110 | gop-port-id = <2>; |
| 107 | status = "disabled"; | 111 | status = "disabled"; |
| 108 | }; | 112 | }; |
| 109 | 113 | ||
| 110 | CP11X_LABEL(eth2): eth2 { | 114 | CP11X_LABEL(eth2): ethernet-port@2 { |
| 111 | interrupts = <41 IRQ_TYPE_LEVEL_HIGH>, | 115 | interrupts = <41 IRQ_TYPE_LEVEL_HIGH>, |
| 112 | <45 IRQ_TYPE_LEVEL_HIGH>, | 116 | <45 IRQ_TYPE_LEVEL_HIGH>, |
| 113 | <49 IRQ_TYPE_LEVEL_HIGH>, | 117 | <49 IRQ_TYPE_LEVEL_HIGH>, |
| @@ -121,7 +125,8 @@ · 7 unmodified lines | |||
| 121 | interrupt-names = "hif0", "hif1", "hif2", | 125 | interrupt-names = "hif0", "hif1", "hif2", |
| 122 | "hif3", "hif4", "hif5", "hif6", "hif7", | 126 | "hif3", "hif4", "hif5", "hif6", "hif7", |
| 123 | "hif8", "link"; | 127 | "hif8", "link"; |
| 124 | port-id = <2>; | 128 | reg = <2>; |
| 129 | port-id = <2>; /* For backward compatibility. */ | ||
| 125 | gop-port-id = <3>; | 130 | gop-port-id = <3>; |
| 126 | status = "disabled"; | 131 | status = "disabled"; |
| 127 | }; | 132 | }; |
| @@ -77,6 +77,47 @@ · 76 unmodified lines | |||
| 77 | no-map; | 77 | no-map; |
| 78 | reg = <0 0x4fc00000 0 0x00100000>; | 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 | timer { | 123 | timer { |
| @@ -298,6 +339,11 @@ · 215 unmodified lines | |||
| 298 | reg = <0 0x15010000 0 0x1000>; | 339 | reg = <0 0x15010000 0 0x1000>; |
| 299 | interrupt-parent = <&gic>; | 340 | interrupt-parent = <&gic>; |
| 300 | interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>; | 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 | wed1: wed@15011000 { | 349 | wed1: wed@15011000 { |
| @@ -306,6 +352,25 @@ · 2 unmodified lines | |||
| 306 | reg = <0 0x15011000 0 0x1000>; | 352 | reg = <0 0x15011000 0 0x1000>; |
| 307 | interrupt-parent = <&gic>; | 353 | interrupt-parent = <&gic>; |
| 308 | interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>; | 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 | eth: ethernet@15100000 { | 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 | struct bpf_prog *p = l->link.prog; | 1649 | struct bpf_prog *p = l->link.prog; |
| 1650 | int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); | 1650 | int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); |
| 1651 | 1651 | ||
| 1652 | if (p->aux->sleepable) { | 1652 | enter_prog = (u64)bpf_trampoline_enter(p); |
| 1653 | enter_prog = (u64)__bpf_prog_enter_sleepable; | 1653 | exit_prog = (u64)bpf_trampoline_exit(p); |
| 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 | } | ||
| 1659 | 1654 | ||
| 1660 | if (l->cookie == 0) { | 1655 | if (l->cookie == 0) { |
| 1661 | /* if cookie is zero, one instruction is enough to store it */ | 1656 | /* if cookie is zero, one instruction is enough to store it */ |
| @@ -284,7 +284,6 @@ CONFIG_IXGB=m · 283 unmodified lines | |||
| 284 | CONFIG_SKGE=m | 284 | CONFIG_SKGE=m |
| 285 | CONFIG_SKY2=m | 285 | CONFIG_SKY2=m |
| 286 | CONFIG_MYRI10GE=m | 286 | CONFIG_MYRI10GE=m |
| 287 | CONFIG_FEALNX=m | ||
| 288 | CONFIG_NATSEMI=m | 287 | CONFIG_NATSEMI=m |
| 289 | CONFIG_NS83820=m | 288 | CONFIG_NS83820=m |
| 290 | CONFIG_S2IO=m | 289 | CONFIG_S2IO=m |
| @@ -55,7 +55,8 @@ fman@400000 { · 54 unmodified lines | |||
| 55 | reg = <0xe0000 0x1000>; | 55 | reg = <0xe0000 0x1000>; |
| 56 | fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; | 56 | fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; |
| 57 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e1000 { | 62 | mdio@e1000 { |
| @@ -52,7 +52,15 @@ fman@400000 { · 51 unmodified lines | |||
| 52 | compatible = "fsl,fman-memac"; | 52 | compatible = "fsl,fman-memac"; |
| 53 | reg = <0xf0000 0x1000>; | 53 | reg = <0xf0000 0x1000>; |
| 54 | fsl,fman-ports = <&fman0_rx_0x10 &fman0_tx_0x30>; | 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 | mdio@f1000 { | 66 | mdio@f1000 { |
| @@ -55,7 +55,15 @@ fman@400000 { · 54 unmodified lines | |||
| 55 | reg = <0xe2000 0x1000>; | 55 | reg = <0xe2000 0x1000>; |
| 56 | fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; | 56 | fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; |
| 57 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e3000 { | 69 | mdio@e3000 { |
| @@ -52,7 +52,15 @@ fman@400000 { · 51 unmodified lines | |||
| 52 | compatible = "fsl,fman-memac"; | 52 | compatible = "fsl,fman-memac"; |
| 53 | reg = <0xf2000 0x1000>; | 53 | reg = <0xf2000 0x1000>; |
| 54 | fsl,fman-ports = <&fman0_rx_0x11 &fman0_tx_0x31>; | 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 | mdio@f3000 { | 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 | reg = <0xe0000 0x1000>; | 51 | reg = <0xe0000 0x1000>; |
| 52 | fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; | 52 | fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; |
| 53 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e1000 { | 58 | mdio@e1000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | |||
| 51 | reg = <0xe2000 0x1000>; | 51 | reg = <0xe2000 0x1000>; |
| 52 | fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; | 52 | fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; |
| 53 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e3000 { | 65 | mdio@e3000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | |||
| 51 | reg = <0xe4000 0x1000>; | 51 | reg = <0xe4000 0x1000>; |
| 52 | fsl,fman-ports = <&fman0_rx_0x0a &fman0_tx_0x2a>; | 52 | fsl,fman-ports = <&fman0_rx_0x0a &fman0_tx_0x2a>; |
| 53 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e5000 { | 65 | mdio@e5000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | |||
| 51 | reg = <0xe6000 0x1000>; | 51 | reg = <0xe6000 0x1000>; |
| 52 | fsl,fman-ports = <&fman0_rx_0x0b &fman0_tx_0x2b>; | 52 | fsl,fman-ports = <&fman0_rx_0x0b &fman0_tx_0x2b>; |
| 53 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e7000 { | 65 | mdio@e7000 { |
| @@ -51,7 +51,8 @@ fman@400000 { · 50 unmodified lines | |||
| 51 | reg = <0xe8000 0x1000>; | 51 | reg = <0xe8000 0x1000>; |
| 52 | fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; | 52 | fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; |
| 53 | ptp-timer = <&ptp_timer0>; | 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 | mdio@e9000 { | 58 | mdio@e9000 { |
| @@ -51,7 +51,15 @@ fman@400000 { · 50 unmodified lines | |||
| 51 | reg = <0xea000 0x1000>; | 51 | reg = <0xea000 0x1000>; |
| 52 | fsl,fman-ports = <&fman0_rx_0x0d &fman0_tx_0x2d>; | 52 | fsl,fman-ports = <&fman0_rx_0x0d &fman0_tx_0x2d>; |
| 53 | ptp-timer = <&ptp_timer0>; | 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 | mdio@eb000 { | 65 | mdio@eb000 { |
| @@ -52,7 +52,15 @@ fman@500000 { · 51 unmodified lines | |||
| 52 | compatible = "fsl,fman-memac"; | 52 | compatible = "fsl,fman-memac"; |
| 53 | reg = <0xf0000 0x1000>; | 53 | reg = <0xf0000 0x1000>; |
| 54 | fsl,fman-ports = <&fman1_rx_0x10 &fman1_tx_0x30>; | 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 | mdio@f1000 { | 66 | mdio@f1000 { |
| @@ -52,7 +52,15 @@ fman@500000 { · 51 unmodified lines | |||
| 52 | compatible = "fsl,fman-memac"; | 52 | compatible = "fsl,fman-memac"; |
| 53 | reg = <0xf2000 0x1000>; | 53 | reg = <0xf2000 0x1000>; |
| 54 | fsl,fman-ports = <&fman1_rx_0x11 &fman1_tx_0x31>; | 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 | mdio@f3000 { | 66 | mdio@f3000 { |
| @@ -51,7 +51,8 @@ fman@500000 { · 50 unmodified lines | |||
| 51 | reg = <0xe0000 0x1000>; | 51 | reg = <0xe0000 0x1000>; |
| 52 | fsl,fman-ports = <&fman1_rx_0x08 &fman1_tx_0x28>; | 52 | fsl,fman-ports = <&fman1_rx_0x08 &fman1_tx_0x28>; |
| 53 | ptp-timer = <&ptp_timer1>; | 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 | mdio@e1000 { | 58 | mdio@e1000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | |||
| 51 | reg = <0xe2000 0x1000>; | 51 | reg = <0xe2000 0x1000>; |
| 52 | fsl,fman-ports = <&fman1_rx_0x09 &fman1_tx_0x29>; | 52 | fsl,fman-ports = <&fman1_rx_0x09 &fman1_tx_0x29>; |
| 53 | ptp-timer = <&ptp_timer1>; | 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 | mdio@e3000 { | 65 | mdio@e3000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | |||
| 51 | reg = <0xe4000 0x1000>; | 51 | reg = <0xe4000 0x1000>; |
| 52 | fsl,fman-ports = <&fman1_rx_0x0a &fman1_tx_0x2a>; | 52 | fsl,fman-ports = <&fman1_rx_0x0a &fman1_tx_0x2a>; |
| 53 | ptp-timer = <&ptp_timer1>; | 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 | mdio@e5000 { | 65 | mdio@e5000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | |||
| 51 | reg = <0xe6000 0x1000>; | 51 | reg = <0xe6000 0x1000>; |
| 52 | fsl,fman-ports = <&fman1_rx_0x0b &fman1_tx_0x2b>; | 52 | fsl,fman-ports = <&fman1_rx_0x0b &fman1_tx_0x2b>; |
| 53 | ptp-timer = <&ptp_timer1>; | 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 | mdio@e7000 { | 65 | mdio@e7000 { |
| @@ -51,7 +51,8 @@ fman@500000 { · 50 unmodified lines | |||
| 51 | reg = <0xe8000 0x1000>; | 51 | reg = <0xe8000 0x1000>; |
| 52 | fsl,fman-ports = <&fman1_rx_0x0c &fman1_tx_0x2c>; | 52 | fsl,fman-ports = <&fman1_rx_0x0c &fman1_tx_0x2c>; |
| 53 | ptp-timer = <&ptp_timer1>; | 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 | mdio@e9000 { | 58 | mdio@e9000 { |
| @@ -51,7 +51,15 @@ fman@500000 { · 50 unmodified lines | |||
| 51 | reg = <0xea000 0x1000>; | 51 | reg = <0xea000 0x1000>; |
| 52 | fsl,fman-ports = <&fman1_rx_0x0d &fman1_tx_0x2d>; | 52 | fsl,fman-ports = <&fman1_rx_0x0d &fman1_tx_0x2d>; |
| 53 | ptp-timer = <&ptp_timer1>; | 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 | mdio@eb000 { | 65 | mdio@eb000 { |
| @@ -609,8 +609,8 @@ · 608 unmodified lines | |||
| 609 | /include/ "qoriq-bman1.dtsi" | 609 | /include/ "qoriq-bman1.dtsi" |
| 610 | 610 | ||
| 611 | /include/ "qoriq-fman3-0.dtsi" | 611 | /include/ "qoriq-fman3-0.dtsi" |
| 612 | /include/ "qoriq-fman3-0-1g-0.dtsi" | 612 | /include/ "qoriq-fman3-0-10g-2.dtsi" |
| 613 | /include/ "qoriq-fman3-0-1g-1.dtsi" | 613 | /include/ "qoriq-fman3-0-10g-3.dtsi" |
| 614 | /include/ "qoriq-fman3-0-1g-2.dtsi" | 614 | /include/ "qoriq-fman3-0-1g-2.dtsi" |
| 615 | /include/ "qoriq-fman3-0-1g-3.dtsi" | 615 | /include/ "qoriq-fman3-0-1g-3.dtsi" |
| 616 | /include/ "qoriq-fman3-0-1g-4.dtsi" | 616 | /include/ "qoriq-fman3-0-1g-4.dtsi" |
| @@ -461,7 +461,6 @@ CONFIG_MV643XX_ETH=m · 460 unmodified lines | |||
| 461 | CONFIG_SKGE=m | 461 | CONFIG_SKGE=m |
| 462 | CONFIG_SKY2=m | 462 | CONFIG_SKY2=m |
| 463 | CONFIG_MYRI10GE=m | 463 | CONFIG_MYRI10GE=m |
| 464 | CONFIG_FEALNX=m | ||
| 465 | CONFIG_NATSEMI=m | 464 | CONFIG_NATSEMI=m |
| 466 | CONFIG_NS83820=m | 465 | CONFIG_NS83820=m |
| 467 | CONFIG_PCMCIA_AXNET=m | 466 | CONFIG_PCMCIA_AXNET=m |
| @@ -136,6 +136,25 @@ static bool in_auipc_jalr_range(s64 val) · 135 unmodified lines | |||
| 136 | val < ((1L << 31) - (1L << 11)); | 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 | static void emit_imm(u8 rd, s64 val, struct rv_jit_context *ctx) | 158 | static void emit_imm(u8 rd, s64 val, struct rv_jit_context *ctx) |
| 140 | { | 159 | { |
| 141 | /* Note that the immediate from the add is sign-extended, | 160 | /* Note that the immediate from the add is sign-extended, |
| @@ -1050,7 +1069,15 @@ out_be: · 908 unmodified lines | |||
| 1050 | u64 imm64; | 1069 | u64 imm64; |
| 1051 | 1070 | ||
| 1052 | imm64 = (u64)insn1.imm << 32 | (u32)imm; | 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 | return 1; | 1081 | return 1; |
| 1055 | } | 1082 | } |
| 1056 | 1083 | ||
| @@ -555,11 +555,11 @@ void bpf_jit_compile(struct bpf_prog *fp) · 554 unmodified lines | |||
| 555 | emit_skb_load16(vlan_tci, r_A); | 555 | emit_skb_load16(vlan_tci, r_A); |
| 556 | break; | 556 | break; |
| 557 | case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT: | 557 | case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT: |
| 558 | __emit_skb_load8(__pkt_vlan_present_offset, r_A); | 558 | emit_skb_load32(vlan_all, r_A); |
| 559 | if (PKT_VLAN_PRESENT_BIT) | 559 | emit_cmpi(r_A, 0); |
| 560 | emit_alu_K(SRL, PKT_VLAN_PRESENT_BIT); | 560 | emit_branch_off(BE, 12); |
| 561 | if (PKT_VLAN_PRESENT_BIT < 7) | 561 | emit_nop(); |
| 562 | emit_andi(r_A, 1, r_A); | 562 | emit_loadimm(1, r_A); |
| 563 | break; | 563 | break; |
| 564 | case BPF_LD | BPF_W | BPF_LEN: | 564 | case BPF_LD | BPF_W | BPF_LEN: |
| 565 | emit_skb_load32(len, r_A); | 565 | emit_skb_load32(len, r_A); |
| @@ -891,6 +891,65 @@ static void emit_nops(u8 **pprog, int len) · 890 unmodified lines | |||
| 891 | *pprog = prog; | 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 | #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp))) | 953 | #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp))) |
| 895 | 954 | ||
| 896 | static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image, | 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 | case BPF_ALU64 | BPF_LSH | BPF_X: | 1196 | case BPF_ALU64 | BPF_LSH | BPF_X: |
| 1138 | case BPF_ALU64 | BPF_RSH | BPF_X: | 1197 | case BPF_ALU64 | BPF_RSH | BPF_X: |
| 1139 | case BPF_ALU64 | BPF_ARSH | BPF_X: | 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 */ | 1217 | emit_shiftx(&prog, dst_reg, src_reg, w, op); |
| 1142 | if (dst_reg == BPF_REG_4) { | 1218 | |
| 1143 | /* mov r11, dst_reg */ | 1219 | break; |
| 1144 | EMIT_mov(AUX_REG, dst_reg); | ||
| 1145 | dst_reg = AUX_REG; | ||
| 1146 | } | 1220 | } |
| 1147 | 1221 | ||
| 1148 | if (src_reg != BPF_REG_4) { /* common case */ | 1222 | if (src_reg != BPF_REG_4) { /* common case */ |
| 1149 | EMIT1(0x51); /* push rcx */ | 1223 | /* Check for bad case when dst_reg == rcx */ |
| 1150 | 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 | /* mov rcx, src_reg */ | 1231 | /* mov rcx, src_reg */ |
| 1152 | EMIT_mov(BPF_REG_4, src_reg); | 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 | b3 = simple_alu_opcodes[BPF_OP(insn->code)]; | 1239 | b3 = simple_alu_opcodes[BPF_OP(insn->code)]; |
| 1160 | EMIT2(0xD3, add_1reg(b3, dst_reg)); | 1240 | EMIT2(0xD3, add_1reg(b3, dst_reg)); |
| 1161 | 1241 | ||
| 1162 | if (src_reg != BPF_REG_4) | 1242 | if (src_reg != BPF_REG_4) { |
| 1163 | EMIT1(0x59); /* pop rcx */ | 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 | break; | 1250 | break; |
| 1169 | 1251 | ||
| 1170 | case BPF_ALU | BPF_END | BPF_FROM_BE: | 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 | /* speculation barrier */ | 1309 | /* speculation barrier */ |
| 1228 | case BPF_ST | BPF_NOSPEC: | 1310 | case BPF_ST | BPF_NOSPEC: |
| 1229 | if (boot_cpu_has(X86_FEATURE_XMM2)) | 1311 | EMIT_LFENCE(); |
| 1230 | EMIT_LFENCE(); | ||
| 1231 | break; | 1312 | break; |
| 1232 | 1313 | ||
| 1233 | /* ST: *(u8*)(dst_reg + off) = imm */ | 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 | struct bpf_tramp_link *l, int stack_size, | 1894 | struct bpf_tramp_link *l, int stack_size, |
| 1814 | int run_ctx_off, bool save_ret) | 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 | u8 *prog = *pprog; | 1897 | u8 *prog = *pprog; |
| 1821 | u8 *jmp_insn; | 1898 | u8 *jmp_insn; |
| 1822 | int ctx_cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); | 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 | emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_1, -run_ctx_off + ctx_cookie_off); | 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 | /* arg1: mov rdi, progs[i] */ | 1915 | /* arg1: mov rdi, progs[i] */ |
| 1850 | emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, (u32) (long) p); | 1916 | emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, (u32) (long) p); |
| 1851 | /* arg2: lea rsi, [rbp - ctx_cookie_off] */ | 1917 | /* arg2: lea rsi, [rbp - ctx_cookie_off] */ |
| 1852 | EMIT4(0x48, 0x8D, 0x75, -run_ctx_off); | 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 | return -EINVAL; | 1921 | return -EINVAL; |
| 1856 | /* remember prog start time returned by __bpf_prog_enter */ | 1922 | /* remember prog start time returned by __bpf_prog_enter */ |
| 1857 | emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0); | 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 | emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6); | 1962 | emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6); |
| 1897 | /* arg3: lea rdx, [rbp - run_ctx_off] */ | 1963 | /* arg3: lea rdx, [rbp - run_ctx_off] */ |
| 1898 | EMIT4(0x48, 0x8D, 0x55, -run_ctx_off); | 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 | return -EINVAL; | 1966 | return -EINVAL; |
| 1901 | 1967 | ||
| 1902 | *pprog = prog; | 1968 | *pprog = prog; |
| @@ -82,6 +82,7 @@ static void bcma_gpio_irq_unmask(struct irq_data *d) · 81 unmodified lines | |||
| 82 | int gpio = irqd_to_hwirq(d); | 82 | int gpio = irqd_to_hwirq(d); |
| 83 | u32 val = bcma_chipco_gpio_in(cc, BIT(gpio)); | 83 | u32 val = bcma_chipco_gpio_in(cc, BIT(gpio)); |
| 84 | 84 | ||
| 85 | gpiochip_enable_irq(gc, gpio); | ||
| 85 | bcma_chipco_gpio_polarity(cc, BIT(gpio), val); | 86 | bcma_chipco_gpio_polarity(cc, BIT(gpio), val); |
| 86 | bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio)); | 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 | int gpio = irqd_to_hwirq(d); | 94 | int gpio = irqd_to_hwirq(d); |
| 94 | 95 | ||
| 95 | bcma_chipco_gpio_intmask(cc, BIT(gpio), 0); | 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 | .name = "BCMA-GPIO", | 101 | .name = "BCMA-GPIO", |
| 100 | .irq_mask = bcma_gpio_irq_mask, | 102 | .irq_mask = bcma_gpio_irq_mask, |
| 101 | .irq_unmask = bcma_gpio_irq_unmask, | 103 | .irq_unmask = bcma_gpio_irq_unmask, |
| 104 | .flags = IRQCHIP_IMMUTABLE, | ||
| 105 | GPIOCHIP_IRQ_RESOURCE_HELPERS, | ||
| 102 | }; | 106 | }; |
| 103 | 107 | ||
| 104 | static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id) | 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 | bcma_chipco_gpio_intmask(cc, ~0, 0); | 143 | bcma_chipco_gpio_intmask(cc, ~0, 0); |
| 140 | bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO); | 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 | /* This will let us handle the parent IRQ in the driver */ | 147 | /* This will let us handle the parent IRQ in the driver */ |
| 144 | girq->parent_handler = NULL; | 148 | girq->parent_handler = NULL; |
| 145 | girq->num_parents = 0; | 149 | girq->num_parents = 0; |
| @@ -344,8 +344,10 @@ static int bcma_register_devices(struct bcma_bus *bus) · 343 unmodified lines | |||
| 344 | err = bcma_gpio_init(&bus->drv_cc); | 344 | err = bcma_gpio_init(&bus->drv_cc); |
| 345 | if (err == -ENOTSUPP) | 345 | if (err == -ENOTSUPP) |
| 346 | bcma_debug(bus, "GPIO driver not activated\n"); | 346 | bcma_debug(bus, "GPIO driver not activated\n"); |
| 347 | else if (err) | 347 | else if (err) { |
| 348 | bcma_err(bus, "Error registering GPIO driver: %i\n", err); | 348 | bcma_err(bus, "Error registering GPIO driver: %i\n", err); |
| 349 | return err; | ||
| 350 | } | ||
| 349 | 351 | ||
| 350 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { | 352 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
| 351 | err = bcma_chipco_watchdog_register(&bus->drv_cc); | 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 | return err; | 165 | return err; |
| 166 | 166 | ||
| 167 | revision = sprom[words - 1] & SSB_SPROM_REVISION_REV; | 167 | revision = sprom[words - 1] & SSB_SPROM_REVISION_REV; |
| 168 | if (revision != 8 && revision != 9 && revision != 10) { | 168 | if (revision < 8 || revision > 11) { |
| 169 | pr_err("Unsupported SPROM revision: %d\n", revision); | 169 | pr_err("Unsupported SPROM revision: %d\n", revision); |
| 170 | return -ENOENT; | 170 | return -ENOENT; |
| 171 | } | 171 | } |
| @@ -45,6 +45,17 @@ config BT_HCIBTUSB_AUTOSUSPEND · 44 unmodified lines | |||
| 45 | This can be overridden by passing btusb.enable_autosuspend=[y|n] | 45 | This can be overridden by passing btusb.enable_autosuspend=[y|n] |
| 46 | on the kernel commandline. | 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 | config BT_HCIBTUSB_BCM | 59 | config BT_HCIBTUSB_BCM |
| 49 | bool "Broadcom protocol support" | 60 | bool "Broadcom protocol support" |
| 50 | depends on BT_HCIBTUSB | 61 | depends on BT_HCIBTUSB |
| @@ -274,6 +285,18 @@ config BT_HCIBCM203X · 223 unmodified lines | |||
| 274 | Say Y here to compile support for HCI BCM203x devices into the | 285 | Say Y here to compile support for HCI BCM203x devices into the |
| 275 | kernel or say M to compile it as module (bcm203x). | 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 | config BT_HCIBPA10X | 300 | config BT_HCIBPA10X |
| 278 | tristate "HCI BPA10x USB driver" | 301 | tristate "HCI BPA10x USB driver" |
| 279 | depends on USB | 302 | depends on USB |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o | 6 | obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o |
| 7 | obj-$(CONFIG_BT_HCIUART) += hci_uart.o | 7 | obj-$(CONFIG_BT_HCIUART) += hci_uart.o |
| 8 | obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o | 8 | obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o |
| 9 | obj-$(CONFIG_BT_HCIBCM4377) += hci_bcm4377.o | ||
| 9 | obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o | 10 | obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o |
| 10 | obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o | 11 | obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o |
| 11 | obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o | 12 | obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | #define CMD_WRITE_BOOT_PARAMS 0xfc0e | 27 | #define CMD_WRITE_BOOT_PARAMS 0xfc0e |
| 28 | struct cmd_write_boot_params { | 28 | struct cmd_write_boot_params { |
| 29 | u32 boot_addr; | 29 | __le32 boot_addr; |
| 30 | u8 fw_build_num; | 30 | u8 fw_build_num; |
| 31 | u8 fw_build_ww; | 31 | u8 fw_build_ww; |
| 32 | u8 fw_build_yy; | 32 | u8 fw_build_yy; |
| @@ -1783,19 +1783,19 @@ static int btintel_get_fw_name(struct intel_version *ver, · 1750 unmodified lines | |||
| 1783 | case 0x0b: /* SfP */ | 1783 | case 0x0b: /* SfP */ |
| 1784 | case 0x0c: /* WsP */ | 1784 | case 0x0c: /* WsP */ |
| 1785 | snprintf(fw_name, len, "intel/ibt-%u-%u.%s", | 1785 | snprintf(fw_name, len, "intel/ibt-%u-%u.%s", |
| 1786 | le16_to_cpu(ver->hw_variant), | 1786 | ver->hw_variant, |
| 1787 | le16_to_cpu(params->dev_revid), | 1787 | le16_to_cpu(params->dev_revid), |
| 1788 | suffix); | 1788 | suffix); |
| 1789 | break; | 1789 | break; |
| 1790 | case 0x11: /* JfP */ | 1790 | case 0x11: /* JfP */ |
| 1791 | case 0x12: /* ThP */ | 1791 | case 0x12: /* ThP */ |
| 1792 | case 0x13: /* HrP */ | 1792 | case 0x13: /* HrP */ |
| 1793 | case 0x14: /* CcP */ | 1793 | case 0x14: /* CcP */ |
| 1794 | snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s", | 1794 | snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s", |
| 1795 | le16_to_cpu(ver->hw_variant), | 1795 | ver->hw_variant, |
| 1796 | le16_to_cpu(ver->hw_revision), | 1796 | ver->hw_revision, |
| 1797 | le16_to_cpu(ver->fw_revision), | 1797 | ver->fw_revision, |
| 1798 | suffix); | 1798 | suffix); |
| 1799 | break; | 1799 | break; |
| 1800 | default: | 1800 | default: |
| 1801 | return -EINVAL; | 1801 | return -EINVAL; |
| @@ -2524,7 +2524,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) · 722 unmodified lines | |||
| 2524 | */ | 2524 | */ |
| 2525 | err = btintel_read_version(hdev, &ver); | 2525 | err = btintel_read_version(hdev, &ver); |
| 2526 | if (err) | 2526 | if (err) |
| 2527 | return err; | 2527 | break; |
| 2528 | 2528 | ||
| 2529 | /* Apply the device specific HCI quirks | 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 | default: | 2566 | default: |
| 2567 | bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", | 2567 | bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", |
| 2568 | INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); | 2568 | INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); |
| 2569 | return -EINVAL; | 2569 | err = -EINVAL; |
| 2570 | break; | ||
| 2570 | } | 2571 | } |
| 2571 | 2572 | ||
| 2572 | exit_error: | 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 | case CHIP_ID_8852C: | 781 | case CHIP_ID_8852C: |
| 782 | set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); | 782 | set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); |
| 783 | set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); | 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 | hci_set_aosp_capable(hdev); | 791 | hci_set_aosp_capable(hdev); |
| 785 | break; | 792 | break; |
| 786 | default: | 793 | default: |
| @@ -47,6 +47,27 @@ struct rtl_vendor_config { · 46 unmodified lines | |||
| 47 | struct rtl_vendor_config_entry entry[]; | 47 | struct rtl_vendor_config_entry entry[]; |
| 48 | } __packed; | 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 | #if IS_ENABLED(CONFIG_BT_RTL) | 71 | #if IS_ENABLED(CONFIG_BT_RTL) |
| 51 | 72 | ||
| 52 | struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, | 73 | struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | |||
| 32 | static bool disable_scofix; | 32 | static bool disable_scofix; |
| 33 | static bool force_scofix; | 33 | static bool force_scofix; |
| 34 | static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND); | 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 | static bool reset = true; | 36 | static bool reset = true; |
| 36 | 37 | ||
| 37 | static struct usb_driver btusb_driver; | 38 | static struct usb_driver btusb_driver; |
| @@ -316,6 +317,90 @@ static const struct usb_device_id blacklist_table[] = { · 278 unmodified lines | |||
| 316 | { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 | | 317 | { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 | |
| 317 | BTUSB_WIDEBAND_SPEECH | | 318 | BTUSB_WIDEBAND_SPEECH | |
| 318 | BTUSB_VALID_LE_STATES }, | 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 | /* QCA WCN785x chipset */ | 405 | /* QCA WCN785x chipset */ |
| 321 | { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 | | 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 | { USB_DEVICE(0x0bda, 0xc822), .driver_info = BTUSB_REALTEK | | 498 | { USB_DEVICE(0x0bda, 0xc822), .driver_info = BTUSB_REALTEK | |
| 414 | BTUSB_WIDEBAND_SPEECH }, | 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 | /* Realtek 8852AE Bluetooth devices */ | 505 | /* Realtek 8852AE Bluetooth devices */ |
| 417 | { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | | 506 | { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | |
| 418 | BTUSB_WIDEBAND_SPEECH }, | 507 | BTUSB_WIDEBAND_SPEECH }, |
| @@ -443,6 +532,10 @@ static const struct usb_device_id blacklist_table[] = { · 24 unmodified lines | |||
| 443 | { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | | 532 | { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | |
| 444 | BTUSB_WIDEBAND_SPEECH }, | 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 | /* Realtek Bluetooth devices */ | 539 | /* Realtek Bluetooth devices */ |
| 447 | { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), | 540 | { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), |
| 448 | .driver_info = BTUSB_REALTEK }, | 541 | .driver_info = BTUSB_REALTEK }, |
| @@ -511,6 +604,9 @@ static const struct usb_device_id blacklist_table[] = { · 62 unmodified lines | |||
| 511 | { USB_DEVICE(0x0489, 0xe0e2), .driver_info = BTUSB_MEDIATEK | | 604 | { USB_DEVICE(0x0489, 0xe0e2), .driver_info = BTUSB_MEDIATEK | |
| 512 | BTUSB_WIDEBAND_SPEECH | | 605 | BTUSB_WIDEBAND_SPEECH | |
| 513 | BTUSB_VALID_LE_STATES }, | 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 | /* Additional Realtek 8723AE Bluetooth devices */ | 611 | /* Additional Realtek 8723AE Bluetooth devices */ |
| 516 | { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, | 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 | BTUSB_WIDEBAND_SPEECH }, | 639 | BTUSB_WIDEBAND_SPEECH }, |
| 544 | { USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK | | 640 | { USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK | |
| 545 | BTUSB_WIDEBAND_SPEECH }, | 641 | BTUSB_WIDEBAND_SPEECH }, |
| 642 | { USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK | | ||
| 643 | BTUSB_WIDEBAND_SPEECH }, | ||
| 546 | 644 | ||
| 547 | /* Additional Realtek 8821AE Bluetooth devices */ | 645 | /* Additional Realtek 8821AE Bluetooth devices */ |
| 548 | { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, | 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 | #define BTUSB_TX_WAIT_VND_EVT 13 | 730 | #define BTUSB_TX_WAIT_VND_EVT 13 |
| 633 | #define BTUSB_WAKEUP_AUTOSUSPEND 14 | 731 | #define BTUSB_WAKEUP_AUTOSUSPEND 14 |
| 634 | #define BTUSB_USE_ALT3_FOR_WBS 15 | 732 | #define BTUSB_USE_ALT3_FOR_WBS 15 |
| 733 | #define BTUSB_ALT6_CONTINUOUS_TX 16 | ||
| 635 | 734 | ||
| 636 | struct btusb_data { | 735 | struct btusb_data { |
| 637 | struct hci_dev *hdev; | 736 | struct hci_dev *hdev; |
| @@ -696,6 +795,28 @@ struct btusb_data { · 58 unmodified lines | |||
| 696 | unsigned cmd_timeout_cnt; | 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 | static void btusb_intel_cmd_timeout(struct hci_dev *hdev) | 820 | static void btusb_intel_cmd_timeout(struct hci_dev *hdev) |
| 700 | { | 821 | { |
| 701 | struct btusb_data *data = hci_get_drvdata(hdev); | 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 | return; | 826 | return; |
| 706 | 827 | ||
| 707 | if (!reset_gpio) { | 828 | if (!reset_gpio) { |
| 708 | bt_dev_err(hdev, "No way to reset. Ignoring and continuing"); | 829 | btusb_reset(hdev); |
| 709 | return; | 830 | return; |
| 710 | } | 831 | } |
| 711 | 832 | ||
| @@ -736,7 +857,7 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev) · 24 unmodified lines | |||
| 736 | return; | 857 | return; |
| 737 | 858 | ||
| 738 | if (!reset_gpio) { | 859 | if (!reset_gpio) { |
| 739 | bt_dev_err(hdev, "No gpio to reset Realtek device, ignoring"); | 860 | btusb_reset(hdev); |
| 740 | return; | 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 | struct btusb_data *data = hci_get_drvdata(hdev); | 883 | struct btusb_data *data = hci_get_drvdata(hdev); |
| 763 | struct gpio_desc *reset_gpio = data->reset_gpio; | 884 | struct gpio_desc *reset_gpio = data->reset_gpio; |
| 764 | int err; | ||
| 765 | 885 | ||
| 766 | if (++data->cmd_timeout_cnt < 5) | 886 | if (++data->cmd_timeout_cnt < 5) |
| 767 | return; | 887 | return; |
| @@ -787,13 +907,7 @@ static void btusb_qca_cmd_timeout(struct hci_dev *hdev) · 19 unmodified lines | |||
| 787 | return; | 907 | return; |
| 788 | } | 908 | } |
| 789 | 909 | ||
| 790 | bt_dev_err(hdev, "Multiple cmd timeouts seen. Resetting usb device."); | 910 | btusb_reset(hdev); |
| 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); | ||
| 797 | } | 911 | } |
| 798 | 912 | ||
| 799 | static inline void btusb_free_frags(struct btusb_data *data) | 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 | spin_lock_irqsave(&data->rxlock, flags); | 917 | spin_lock_irqsave(&data->rxlock, flags); |
| 804 | 918 | ||
| 805 | kfree_skb(data->evt_skb); | 919 | dev_kfree_skb_irq(data->evt_skb); |
| 806 | data->evt_skb = NULL; | 920 | data->evt_skb = NULL; |
| 807 | 921 | ||
| 808 | kfree_skb(data->acl_skb); | 922 | dev_kfree_skb_irq(data->acl_skb); |
| 809 | data->acl_skb = NULL; | 923 | data->acl_skb = NULL; |
| 810 | 924 | ||
| 811 | kfree_skb(data->sco_skb); | 925 | dev_kfree_skb_irq(data->sco_skb); |
| 812 | data->sco_skb = NULL; | 926 | data->sco_skb = NULL; |
| 813 | 927 | ||
| 814 | spin_unlock_irqrestore(&data->rxlock, flags); | 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 | return err; | 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 | static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) | 1107 | static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) |
| 966 | { | 1108 | { |
| 967 | struct sk_buff *skb; | 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 | if (skb->len == HCI_SCO_HDR_SIZE) { | 1137 | if (skb->len == HCI_SCO_HDR_SIZE) { |
| 996 | /* Complete SCO header */ | 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 | kfree_skb(skb); | 1145 | kfree_skb(skb); |
| 1001 | skb = NULL; | 1146 | skb = NULL; |
| 1002 | 1147 | ||
| @@ -1276,11 +1421,17 @@ static void btusb_isoc_complete(struct urb *urb) · 273 unmodified lines | |||
| 1276 | static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len, | 1421 | static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len, |
| 1277 | int mtu, struct btusb_data *data) | 1422 | int mtu, struct btusb_data *data) |
| 1278 | { | 1423 | { |
| 1279 | int i, offset = 0; | 1424 | int i = 0, offset = 0; |
| 1280 | unsigned int interval; | 1425 | unsigned int interval; |
| 1281 | 1426 | ||
| 1282 | BT_DBG("len %d mtu %d", len, mtu); | 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 | /* For mSBC ALT 6 setting the host will send the packet at continuous | 1435 | /* For mSBC ALT 6 setting the host will send the packet at continuous |
| 1285 | * flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting | 1436 | * flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting |
| 1286 | * 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets. | 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 | urb->iso_frame_desc[i].length = offset; | 1451 | urb->iso_frame_desc[i].length = offset; |
| 1301 | } | 1452 | } |
| 1302 | 1453 | ||
| 1454 | ignore_usb_alt6_packet_flow: | ||
| 1303 | if (len && i < BTUSB_MAX_ISOC_FRAMES) { | 1455 | if (len && i < BTUSB_MAX_ISOC_FRAMES) { |
| 1304 | urb->iso_frame_desc[i].offset = offset; | 1456 | urb->iso_frame_desc[i].offset = offset; |
| 1305 | urb->iso_frame_desc[i].length = len; | 1457 | urb->iso_frame_desc[i].length = len; |
| @@ -1981,10 +2133,11 @@ static void btusb_work(struct work_struct *work) · 675 unmodified lines | |||
| 1981 | if (btusb_switch_alt_setting(hdev, new_alts) < 0) | 2133 | if (btusb_switch_alt_setting(hdev, new_alts) < 0) |
| 1982 | bt_dev_err(hdev, "set USB alt:(%d) failed!", new_alts); | 2134 | bt_dev_err(hdev, "set USB alt:(%d) failed!", new_alts); |
| 1983 | } else { | 2135 | } else { |
| 1984 | clear_bit(BTUSB_ISOC_RUNNING, &data->flags); | ||
| 1985 | usb_kill_anchored_urbs(&data->isoc_anchor); | 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 | if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags)) | 2141 | if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags)) |
| 1989 | usb_autopm_put_interface(data->isoc ? data->isoc : data->intf); | 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 | return err; | 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 | bt_dev_err(hdev, "CSR: Local version length mismatch"); | 2206 | bt_dev_err(hdev, "CSR: Local version length mismatch"); |
| 2053 | kfree_skb(skb); | 2207 | kfree_skb(skb); |
| 2054 | return -EIO; | 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", | 2214 | bt_dev_info(hdev, "LMP ver=%u subver=%04x; manufacturer=%u", |
| 2060 | le16_to_cpu(rp->hci_ver), le16_to_cpu(rp->hci_rev), | 2215 | rp->lmp_ver, le16_to_cpu(rp->lmp_subver), |
| 2061 | le16_to_cpu(rp->lmp_ver), le16_to_cpu(rp->lmp_subver), | 2216 | le16_to_cpu(rp->manufacturer)); |
| 2062 | le16_to_cpu(rp->manufacturer)); | ||
| 2063 | 2217 | ||
| 2064 | /* Detect a wide host of Chinese controllers that aren't CSR. | 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 | * third-party BT 4.0 dongle reuses it. | 2243 | * third-party BT 4.0 dongle reuses it. |
| 2090 | */ | 2244 | */ |
| 2091 | else if (le16_to_cpu(rp->lmp_subver) <= 0x034e && | 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 | is_fake = true; | 2247 | is_fake = true; |
| 2094 | 2248 | ||
| 2095 | else if (le16_to_cpu(rp->lmp_subver) <= 0x0529 && | 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 | is_fake = true; | 2251 | is_fake = true; |
| 2098 | 2252 | ||
| 2099 | else if (le16_to_cpu(rp->lmp_subver) <= 0x0c5c && | 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 | is_fake = true; | 2255 | is_fake = true; |
| 2102 | 2256 | ||
| 2103 | else if (le16_to_cpu(rp->lmp_subver) <= 0x1899 && | 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 | is_fake = true; | 2259 | is_fake = true; |
| 2106 | 2260 | ||
| 2107 | else if (le16_to_cpu(rp->lmp_subver) <= 0x22bb && | 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 | is_fake = true; | 2263 | is_fake = true; |
| 2110 | 2264 | ||
| 2111 | /* Other clones which beat all the above checks */ | 2265 | /* Other clones which beat all the above checks */ |
| 2112 | else if (bcdDevice == 0x0134 && | 2266 | else if (bcdDevice == 0x0134 && |
| 2113 | le16_to_cpu(rp->lmp_subver) == 0x0c5c && | 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 | is_fake = true; | 2269 | is_fake = true; |
| 2116 | 2270 | ||
| 2117 | if (is_fake) { | 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 | return -EILSEQ; | 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 | /* UHW CR mapping */ | 2491 | /* UHW CR mapping */ |
| 2325 | #define MTK_BT_MISC 0x70002510 | 2492 | #define MTK_BT_MISC 0x70002510 |
| 2326 | #define MTK_BT_SUBSYS_RST 0x70002610 | 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 | if (ver_rom & ~0xffffU) { | 3424 | if (ver_rom & ~0xffffU) { |
| 3258 | rver_rom_high = le16_to_cpu(rver->rom_version_high); | 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 | } else { | 3427 | } else { |
| 3261 | rver_rom = rver_rom_low; | 3428 | rver_rom = rver_rom_low; |
| 3262 | } | 3429 | } |
| @@ -3761,6 +3928,9 @@ static int btusb_probe(struct usb_interface *intf, · 498 unmodified lines | |||
| 3761 | /* Override the rx handlers */ | 3928 | /* Override the rx handlers */ |
| 3762 | data->recv_event = btusb_recv_event_intel; | 3929 | data->recv_event = btusb_recv_event_intel; |
| 3763 | data->recv_bulk = btusb_recv_bulk_intel; | 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 | data->recv_acl = hci_recv_frame; | 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 | if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) && | 4090 | if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) && |
| 3921 | (id->driver_info & BTUSB_REALTEK)) { | 4091 | (id->driver_info & BTUSB_REALTEK)) { |
| 3922 | hdev->setup = btrtl_setup_realtek; | 4092 | hdev->setup = btusb_setup_realtek; |
| 3923 | hdev->shutdown = btrtl_shutdown_realtek; | 4093 | hdev->shutdown = btrtl_shutdown_realtek; |
| 3924 | hdev->cmd_timeout = btusb_rtl_cmd_timeout; | 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 | if (enable_autosuspend) | 4174 | if (enable_autosuspend) |
| 4005 | usb_enable_autosuspend(data->udev); | 4175 | usb_enable_autosuspend(data->udev); |
| 4006 | 4176 | ||
| 4177 | data->poll_sync = enable_poll_sync; | ||
| 4178 | |||
| 4007 | err = hci_register_dev(hdev); | 4179 | err = hci_register_dev(hdev); |
| 4008 | if (err < 0) | 4180 | if (err < 0) |
| 4009 | goto out_free_dev; | 4181 | goto out_free_dev; |
| @@ -53,11 +53,13 @@ · 52 unmodified lines | |||
| 53 | * struct bcm_device_data - device specific data | 53 | * struct bcm_device_data - device specific data |
| 54 | * @no_early_set_baudrate: Disallow set baudrate before driver setup() | 54 | * @no_early_set_baudrate: Disallow set baudrate before driver setup() |
| 55 | * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it | 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 | * @max_autobaud_speed: max baudrate supported by device in autobaud mode | 57 | * @max_autobaud_speed: max baudrate supported by device in autobaud mode |
| 57 | */ | 58 | */ |
| 58 | struct bcm_device_data { | 59 | struct bcm_device_data { |
| 59 | bool no_early_set_baudrate; | 60 | bool no_early_set_baudrate; |
| 60 | bool drive_rts_on_open; | 61 | bool drive_rts_on_open; |
| 62 | bool no_uart_clock_set; | ||
| 61 | u32 max_autobaud_speed; | 63 | u32 max_autobaud_speed; |
| 62 | }; | 64 | }; |
| 63 | 65 | ||
| @@ -100,6 +102,7 @@ struct bcm_device_data { · 36 unmodified lines | |||
| 100 | * @is_suspended: whether flow control is currently disabled | 102 | * @is_suspended: whether flow control is currently disabled |
| 101 | * @no_early_set_baudrate: don't set_baudrate before setup() | 103 | * @no_early_set_baudrate: don't set_baudrate before setup() |
| 102 | * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it | 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 | * @pcm_int_params: keep the initial PCM configuration | 106 | * @pcm_int_params: keep the initial PCM configuration |
| 104 | * @use_autobaud_mode: start Bluetooth device in autobaud mode | 107 | * @use_autobaud_mode: start Bluetooth device in autobaud mode |
| 105 | * @max_autobaud_speed: max baudrate supported by device in autobaud mode | 108 | * @max_autobaud_speed: max baudrate supported by device in autobaud mode |
| @@ -140,6 +143,7 @@ struct bcm_device { · 34 unmodified lines | |||
| 140 | #endif | 143 | #endif |
| 141 | bool no_early_set_baudrate; | 144 | bool no_early_set_baudrate; |
| 142 | bool drive_rts_on_open; | 145 | bool drive_rts_on_open; |
| 146 | bool no_uart_clock_set; | ||
| 143 | bool use_autobaud_mode; | 147 | bool use_autobaud_mode; |
| 144 | u8 pcm_int_params[5]; | 148 | u8 pcm_int_params[5]; |
| 145 | u32 max_autobaud_speed; | 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 | static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) | 176 | static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) |
| 173 | { | 177 | { |
| 174 | struct hci_dev *hdev = hu->hdev; | 178 | struct hci_dev *hdev = hu->hdev; |
| 179 | struct bcm_data *bcm = hu->priv; | ||
| 175 | struct sk_buff *skb; | 180 | struct sk_buff *skb; |
| 176 | struct bcm_update_uart_baud_rate param; | 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 | struct bcm_write_uart_clock_setting clock; | 184 | struct bcm_write_uart_clock_setting clock; |
| 180 | 185 | ||
| 181 | clock.type = BCM_UART_CLOCK_48MHZ; | 186 | clock.type = BCM_UART_CLOCK_48MHZ; |
| @@ -1529,6 +1534,7 @@ static int bcm_serdev_probe(struct serdev_device *serdev) · 1347 unmodified lines | |||
| 1529 | bcmdev->max_autobaud_speed = data->max_autobaud_speed; | 1534 | bcmdev->max_autobaud_speed = data->max_autobaud_speed; |
| 1530 | bcmdev->no_early_set_baudrate = data->no_early_set_baudrate; | 1535 | bcmdev->no_early_set_baudrate = data->no_early_set_baudrate; |
| 1531 | bcmdev->drive_rts_on_open = data->drive_rts_on_open; | 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 | return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto); | 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 | .drive_rts_on_open = true, | 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 | static struct bcm_device_data cyw55572_device_data = { | 1563 | static struct bcm_device_data cyw55572_device_data = { |
| 1554 | .max_autobaud_speed = 921600, | 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 | { .compatible = "brcm,bcm4349-bt", .data = &bcm43438_device_data }, | 1576 | { .compatible = "brcm,bcm4349-bt", .data = &bcm43438_device_data }, |
| 1567 | { .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data }, | 1577 | { .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data }, |
| 1568 | { .compatible = "brcm,bcm4335a0" }, | 1578 | { .compatible = "brcm,bcm4335a0" }, |
| 1579 | { .compatible = "cypress,cyw4373a0-bt", .data = &cyw4373a0_device_data }, | ||
| 1569 | { .compatible = "infineon,cyw55572-bt", .data = &cyw55572_device_data }, | 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 | i++; | 378 | i++; |
| 379 | 379 | ||
| 380 | __skb_unlink(skb, &bcsp->unack); | 380 | __skb_unlink(skb, &bcsp->unack); |
| 381 | kfree_skb(skb); | 381 | dev_kfree_skb_irq(skb); |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | if (skb_queue_empty(&bcsp->unack)) | 384 | if (skb_queue_empty(&bcsp->unack)) |
| @@ -313,7 +313,7 @@ static void h5_pkt_cull(struct h5 *h5) · 312 unmodified lines | |||
| 313 | break; | 313 | break; |
| 314 | 314 | ||
| 315 | __skb_unlink(skb, &h5->unack); | 315 | __skb_unlink(skb, &h5->unack); |
| 316 | kfree_skb(skb); | 316 | dev_kfree_skb_irq(skb); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | if (skb_queue_empty(&h5->unack)) | 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 | default: | 345 | default: |
| 346 | BT_ERR("illegal hcill state: %ld (losing packet)", | 346 | BT_ERR("illegal hcill state: %ld (losing packet)", |
| 347 | ll->hcill_state); | 347 | ll->hcill_state); |
| 348 | kfree_skb(skb); | 348 | dev_kfree_skb_irq(skb); |
| 349 | break; | 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 | default: | 918 | default: |
| 919 | BT_ERR("Illegal tx state: %d (losing packet)", | 919 | BT_ERR("Illegal tx state: %d (losing packet)", |
| 920 | qca->tx_ibs_state); | 920 | qca->tx_ibs_state); |
| 921 | kfree_skb(skb); | 921 | dev_kfree_skb_irq(skb); |
| 922 | break; | 922 | break; |
| 923 | } | 923 | } |
| 924 | 924 | ||
| @@ -1771,7 +1771,8 @@ retry: · 846 unmodified lines | |||
| 1771 | qca_debugfs_init(hdev); | 1771 | qca_debugfs_init(hdev); |
| 1772 | hu->hdev->hw_error = qca_hw_error; | 1772 | hu->hdev->hw_error = qca_hw_error; |
| 1773 | hu->hdev->cmd_timeout = qca_cmd_timeout; | 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 | } else if (ret == -ENOENT) { | 1776 | } else if (ret == -ENOENT) { |
| 1776 | /* No patch/nvm-config found, run with original fw/config */ | 1777 | /* No patch/nvm-config found, run with original fw/config */ |
| 1777 | set_bit(QCA_ROM_FW, &qca->flags); | 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 | static int virtbt_open(struct hci_dev *hdev) | 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 | if (virtbt_add_inbuf(vbt) < 0) | 58 | if (virtbt_add_inbuf(vbt) < 0) |
| 56 | return -EIO; | 59 | return -EIO; |
| 57 | 60 | ||
| @@ -61,7 +64,11 @@ static int virtbt_open(struct hci_dev *hdev) · 3 unmodified lines | |||
| 61 | 64 | ||
| 62 | static int virtbt_close(struct hci_dev *hdev) | 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 | int i; | 72 | int i; |
| 66 | 73 | ||
| 67 | cancel_work_sync(&vbt->rx); | 74 | cancel_work_sync(&vbt->rx); |
| @@ -306,7 +313,12 @@ static int virtbt_probe(struct virtio_device *vdev) · 238 unmodified lines | |||
| 306 | if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) { | 313 | if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) { |
| 307 | __u16 vendor; | 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 | switch (vendor) { | 323 | switch (vendor) { |
| 312 | case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR: | 324 | case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR: |
| @@ -339,8 +351,12 @@ static int virtbt_probe(struct virtio_device *vdev) · 26 unmodified lines | |||
| 339 | if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) { | 351 | if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) { |
| 340 | __u16 msft_opcode; | 352 | __u16 msft_opcode; |
| 341 | 353 | ||
| 342 | virtio_cread(vdev, struct virtio_bt_config, | 354 | if (virtio_has_feature(vdev, VIRTIO_BT_F_CONFIG_V2)) |
| 343 | msft_opcode, &msft_opcode); | 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 | hci_set_msft_opcode(hdev, msft_opcode); | 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 | goto failed; | 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 | return 0; | 378 | return 0; |
| 358 | 379 | ||
| 380 | open_failed: | ||
| 381 | hci_free_dev(hdev); | ||
| 359 | failed: | 382 | failed: |
| 360 | vdev->config->del_vqs(vdev); | 383 | vdev->config->del_vqs(vdev); |
| 361 | return err; | 384 | return err; |
| @@ -368,6 +391,7 @@ static void virtbt_remove(struct virtio_device *vdev) · 6 unmodified lines | |||
| 368 | 391 | ||
| 369 | hci_unregister_dev(hdev); | 392 | hci_unregister_dev(hdev); |
| 370 | virtio_reset_device(vdev); | 393 | virtio_reset_device(vdev); |
| 394 | virtbt_close_vdev(vbt); | ||
| 371 | 395 | ||
| 372 | hci_free_dev(hdev); | 396 | hci_free_dev(hdev); |
| 373 | vbt->hdev = NULL; | 397 | vbt->hdev = NULL; |
| @@ -387,6 +411,7 @@ static const unsigned int virtbt_features[] = { · 13 unmodified lines | |||
| 387 | VIRTIO_BT_F_VND_HCI, | 411 | VIRTIO_BT_F_VND_HCI, |
| 388 | VIRTIO_BT_F_MSFT_EXT, | 412 | VIRTIO_BT_F_MSFT_EXT, |
| 389 | VIRTIO_BT_F_AOSP_EXT, | 413 | VIRTIO_BT_F_AOSP_EXT, |
| 414 | VIRTIO_BT_F_CONFIG_V2, | ||
| 390 | }; | 415 | }; |
| 391 | 416 | ||
| 392 | static struct virtio_driver virtbt_driver = { | 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 | struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf; | 76 | struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf; |
| 77 | int err; | 77 | int err; |
| 78 | 78 | ||
| 79 | err = devlink_info_driver_name_put(req, "rvu_cptpf"); | ||
| 80 | if (err) | ||
| 81 | return err; | ||
| 82 | |||
| 83 | err = otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp, | 79 | err = otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp, |
| 84 | "fw.ae", OTX2_CPT_AE_TYPES); | 80 | "fw.ae", OTX2_CPT_AE_TYPES); |
| 85 | if (err) | 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 | return -EOPNOTSUPP; | 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 | return -EOPNOTSUPP; | 711 | return -EOPNOTSUPP; |
| 712 | } | 712 | } |
| @@ -724,7 +724,7 @@ static struct ptp_clock_info ptp_hyperv_info = { · 11 unmodified lines | |||
| 724 | .name = "hyperv", | 724 | .name = "hyperv", |
| 725 | .enable = hv_ptp_enable, | 725 | .enable = hv_ptp_enable, |
| 726 | .adjtime = hv_ptp_adjtime, | 726 | .adjtime = hv_ptp_adjtime, |
| 727 | .adjfreq = hv_ptp_adjfreq, | 727 | .adjfine = hv_ptp_adjfine, |
| 728 | .gettime64 = hv_ptp_gettime, | 728 | .gettime64 = hv_ptp_gettime, |
| 729 | .settime64 = hv_ptp_settime, | 729 | .settime64 = hv_ptp_settime, |
| 730 | .owner = THIS_MODULE, | 730 | .owner = THIS_MODULE, |
| @@ -230,8 +230,7 @@ static bool mlx5_ib_invalidate_range(struct mmu_interval_notifier *mni, · 229 unmodified lines | |||
| 230 | struct ib_umem_odp *umem_odp = | 230 | struct ib_umem_odp *umem_odp = |
| 231 | container_of(mni, struct ib_umem_odp, notifier); | 231 | container_of(mni, struct ib_umem_odp, notifier); |
| 232 | struct mlx5_ib_mr *mr; | 232 | struct mlx5_ib_mr *mr; |
| 233 | const u64 umr_block_mask = (MLX5_UMR_MTT_ALIGNMENT / | 233 | const u64 umr_block_mask = MLX5_UMR_MTT_NUM_ENTRIES_ALIGNMENT - 1; |
| 234 | sizeof(struct mlx5_mtt)) - 1; | ||
| 235 | u64 idx = 0, blk_start_idx = 0; | 234 | u64 idx = 0, blk_start_idx = 0; |
| 236 | u64 invalidations = 0; | 235 | u64 invalidations = 0; |
| 237 | unsigned long start; | 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 | #define MLX5_MAX_UMR_CHUNK \ | 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 | #define MLX5_SPARE_UMR_CHUNK 0x10000 | 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 | static void *mlx5r_umr_alloc_xlt(size_t *nents, size_t ent_size, gfp_t gfp_mask) | 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 | size_t size; | 432 | size_t size; |
| 433 | void *res = NULL; | 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 | * MLX5_IB_UPD_XLT_ATOMIC doesn't signal an atomic context just that the | 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 | final_size = (void *)cur_mtt - (void *)mtt; | 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 | memset(cur_mtt, 0, sg.length - final_size); | 670 | memset(cur_mtt, 0, sg.length - final_size); |
| 671 | mlx5r_umr_final_update_xlt(dev, &wqe, mr, &sg, flags); | 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 | int desc_size = (flags & MLX5_IB_UPD_XLT_INDIRECT) | 690 | int desc_size = (flags & MLX5_IB_UPD_XLT_INDIRECT) |
| 691 | ? sizeof(struct mlx5_klm) | 691 | ? sizeof(struct mlx5_klm) |
| 692 | : sizeof(struct mlx5_mtt); | 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 | struct mlx5_ib_dev *dev = mr_to_mdev(mr); | 694 | struct mlx5_ib_dev *dev = mr_to_mdev(mr); |
| 695 | struct device *ddev = &dev->mdev->pdev->dev; | 695 | struct device *ddev = &dev->mdev->pdev->dev; |
| 696 | const int page_mask = page_align - 1; | 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 | if (WARN_ON(!mr->umem->is_odp)) | 711 | if (WARN_ON(!mr->umem->is_odp)) |
| 712 | return -EINVAL; | 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 | * so we need to align the offset and length accordingly | 715 | * so we need to align the offset and length accordingly |
| 716 | */ | 716 | */ |
| 717 | if (idx & page_mask) { | 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 | mlx5_odp_populate_xlt(xlt, idx, npages, mr, flags); | 748 | mlx5_odp_populate_xlt(xlt, idx, npages, mr, flags); |
| 749 | dma_sync_single_for_device(ddev, sg.addr, sg.length, | 749 | dma_sync_single_for_device(ddev, sg.addr, sg.length, |
| 750 | DMA_TO_DEVICE); | 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 | if (pages_mapped + pages_iter >= pages_to_map) | 753 | if (pages_mapped + pages_iter >= pages_to_map) |
| 754 | mlx5r_umr_final_update_xlt(dev, &wqe, mr, &sg, flags); | 754 | mlx5r_umr_final_update_xlt(dev, &wqe, mr, &sg, flags); |
| @@ -75,6 +75,7 @@ enum ad_link_speed_type { · 74 unmodified lines | |||
| 75 | AD_LINK_SPEED_100000MBPS, | 75 | AD_LINK_SPEED_100000MBPS, |
| 76 | AD_LINK_SPEED_200000MBPS, | 76 | AD_LINK_SPEED_200000MBPS, |
| 77 | AD_LINK_SPEED_400000MBPS, | 77 | AD_LINK_SPEED_400000MBPS, |
| 78 | AD_LINK_SPEED_800000MBPS, | ||
| 78 | }; | 79 | }; |
| 79 | 80 | ||
| 80 | /* compare MAC addresses */ | 81 | /* compare MAC addresses */ |
| @@ -251,6 +252,7 @@ static inline int __check_agg_selection_timer(struct port *port) · 170 unmodified lines | |||
| 251 | * %AD_LINK_SPEED_100000MBPS | 252 | * %AD_LINK_SPEED_100000MBPS |
| 252 | * %AD_LINK_SPEED_200000MBPS | 253 | * %AD_LINK_SPEED_200000MBPS |
| 253 | * %AD_LINK_SPEED_400000MBPS | 254 | * %AD_LINK_SPEED_400000MBPS |
| 255 | * %AD_LINK_SPEED_800000MBPS | ||
| 254 | */ | 256 | */ |
| 255 | static u16 __get_link_speed(struct port *port) | 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 | speed = AD_LINK_SPEED_400000MBPS; | 328 | speed = AD_LINK_SPEED_400000MBPS; |
| 327 | break; | 329 | break; |
| 328 | 330 | ||
| 331 | case SPEED_800000: | ||
| 332 | speed = AD_LINK_SPEED_800000MBPS; | ||
| 333 | break; | ||
| 334 | |||
| 329 | default: | 335 | default: |
| 330 | /* unknown speed value from ethtool. shouldn't happen */ | 336 | /* unknown speed value from ethtool. shouldn't happen */ |
| 331 | if (slave->speed != SPEED_UNKNOWN) | 337 | if (slave->speed != SPEED_UNKNOWN) |
| @@ -753,6 +759,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) · 421 unmodified lines | |||
| 753 | case AD_LINK_SPEED_400000MBPS: | 759 | case AD_LINK_SPEED_400000MBPS: |
| 754 | bandwidth = nports * 400000; | 760 | bandwidth = nports * 400000; |
| 755 | break; | 761 | break; |
| 762 | case AD_LINK_SPEED_800000MBPS: | ||
| 763 | bandwidth = nports * 800000; | ||
| 764 | break; | ||
| 756 | default: | 765 | default: |
| 757 | bandwidth = 0; /* to silence the compiler */ | 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 | return dev_queue_xmit(skb); | 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 | switch (BOND_MODE(bond)) { | 312 | switch (BOND_MODE(bond)) { |
| 313 | case BOND_MODE_8023AD: | 313 | case BOND_MODE_8023AD: |
| @@ -1398,13 +1398,6 @@ static netdev_features_t bond_fix_features(struct net_device *dev, · 1084 unmodified lines | |||
| 1398 | netdev_features_t mask; | 1398 | netdev_features_t mask; |
| 1399 | struct slave *slave; | 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 | mask = features; | 1401 | mask = features; |
| 1409 | 1402 | ||
| 1410 | features &= ~NETIF_F_ONE_FOR_ALL; | 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 | struct netdev_lag_upper_info lag_upper_info; | 1633 | struct netdev_lag_upper_info lag_upper_info; |
| 1641 | enum netdev_lag_tx_type type; | 1634 | enum netdev_lag_tx_type type; |
| 1635 | int err; | ||
| 1642 | 1636 | ||
| 1643 | type = bond_lag_tx_type(bond); | 1637 | type = bond_lag_tx_type(bond); |
| 1644 | lag_upper_info.tx_type = type; | 1638 | lag_upper_info.tx_type = type; |
| 1645 | lag_upper_info.hash_type = bond_lag_hash_type(bond, type); | 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, | 1641 | err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave, |
| 1648 | &lag_upper_info, extack); | 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 | static void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave) | 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 */ | 1959 | /* set no_addrconf flag before open to prevent IPv6 addrconf */ |
| 1961 | slave_dev->flags |= IFF_SLAVE; | 1960 | slave_dev->priv_flags |= IFF_NO_ADDRCONF; |
| 1962 | 1961 | ||
| 1963 | /* open the slave since the application closed it */ | 1962 | /* open the slave since the application closed it */ |
| 1964 | res = dev_open(slave_dev, extack); | 1963 | res = dev_open(slave_dev, extack); |
| @@ -2261,7 +2260,7 @@ err_close: · 296 unmodified lines | |||
| 2261 | dev_close(slave_dev); | 2260 | dev_close(slave_dev); |
| 2262 | 2261 | ||
| 2263 | err_restore_mac: | 2262 | err_restore_mac: |
| 2264 | slave_dev->flags &= ~IFF_SLAVE; | 2263 | slave_dev->priv_flags &= ~IFF_NO_ADDRCONF; |
| 2265 | if (!bond->params.fail_over_mac || | 2264 | if (!bond->params.fail_over_mac || |
| 2266 | BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { | 2265 | BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { |
| 2267 | /* XXX TODO - fom follow mode needs to change master's | 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 | /* close slave before restoring its mac address */ | 2452 | /* close slave before restoring its mac address */ |
| 2454 | dev_close(slave_dev); | 2453 | dev_close(slave_dev); |
| 2455 | 2454 | ||
| 2455 | slave_dev->priv_flags &= ~IFF_NO_ADDRCONF; | ||
| 2456 | |||
| 2456 | if (bond->params.fail_over_mac != BOND_FOM_ACTIVE || | 2457 | if (bond->params.fail_over_mac != BOND_FOM_ACTIVE || |
| 2457 | BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { | 2458 | BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { |
| 2458 | /* restore original ("permanent") mac address */ | 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 | /* called with rcu_read_lock() */ | 2532 | /* called with rcu_read_lock() */ |
| 2532 | static int bond_miimon_inspect(struct bonding *bond) | 2533 | static int bond_miimon_inspect(struct bonding *bond) |
| 2533 | { | 2534 | { |
| 2535 | bool ignore_updelay = false; | ||
| 2534 | int link_state, commit = 0; | 2536 | int link_state, commit = 0; |
| 2535 | struct list_head *iter; | 2537 | struct list_head *iter; |
| 2536 | struct slave *slave; | 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 | bond_for_each_slave_rcu(bond, slave, iter) { | 2551 | bond_for_each_slave_rcu(bond, slave, iter) { |
| 2542 | bond_propose_link_state(slave, BOND_LINK_NOCHANGE); | 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 | if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) | 5823 | if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) |
| 5814 | bond_dev->features |= BOND_XFRM_FEATURES; | 5824 | bond_dev->features |= BOND_XFRM_FEATURES; |
| 5815 | #endif /* CONFIG_XFRM_OFFLOAD */ | 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 | /* Destroy a bonding device. | 5828 | /* Destroy a bonding device. |
| @@ -842,19 +842,6 @@ static bool bond_set_xfrm_features(struct bonding *bond) · 841 unmodified lines | |||
| 842 | return true; | 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 | static int bond_option_mode_set(struct bonding *bond, | 845 | static int bond_option_mode_set(struct bonding *bond, |
| 859 | const struct bond_opt_value *newval) | 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 | bool update = false; | 872 | bool update = false; |
| 886 | 873 | ||
| 887 | update |= bond_set_xfrm_features(bond); | 874 | update |= bond_set_xfrm_features(bond); |
| 888 | update |= bond_set_tls_features(bond); | ||
| 889 | 875 | ||
| 890 | if (update) | 876 | if (update) |
| 891 | netdev_update_features(bond->dev); | 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 | newval->string, newval->value); | 1404 | newval->string, newval->value); |
| 1419 | bond->params.xmit_policy = newval->value; | 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 | return 0; | 1407 | return 0; |
| 1426 | } | 1408 | } |
| 1427 | 1409 | ||
| @@ -198,14 +198,6 @@ config CAN_XILINXCAN · 197 unmodified lines | |||
| 198 | Xilinx CAN driver. This driver supports both soft AXI CAN IP and | 198 | Xilinx CAN driver. This driver supports both soft AXI CAN IP and |
| 199 | Zynq CANPS IP. | 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 | source "drivers/net/can/c_can/Kconfig" | 201 | source "drivers/net/can/c_can/Kconfig" |
| 210 | source "drivers/net/can/cc770/Kconfig" | 202 | source "drivers/net/can/cc770/Kconfig" |
| 211 | source "drivers/net/can/ctucanfd/Kconfig" | 203 | source "drivers/net/can/ctucanfd/Kconfig" |
| @@ -30,6 +30,5 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ · 29 unmodified lines | |||
| 30 | obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o | 30 | obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o |
| 31 | obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o | 31 | obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o |
| 32 | obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o | 32 | obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o |
| 33 | obj-$(CONFIG_PCH_CAN) += pch_can.o | ||
| 34 | 33 | ||
| 35 | subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG | 34 | subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG |
| @@ -20,5 +20,6 @@ config CAN_C_CAN_PCI · 19 unmodified lines | |||
| 20 | depends on PCI | 20 | depends on PCI |
| 21 | help | 21 | help |
| 22 | This driver adds support for the C_CAN/D_CAN chips connected | 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 | endif | 25 | endif |
| @@ -290,8 +290,7 @@ static int c_can_plat_probe(struct platform_device *pdev) · 289 unmodified lines | |||
| 290 | goto exit; | 290 | goto exit; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 293 | addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); |
| 294 | addr = devm_ioremap_resource(&pdev->dev, mem); | ||
| 295 | if (IS_ERR(addr)) { | 294 | if (IS_ERR(addr)) { |
| 296 | ret = PTR_ERR(addr); | 295 | ret = PTR_ERR(addr); |
| 297 | goto exit; | 296 | goto exit; |
| @@ -23,7 +23,7 @@ config CAN_CTUCANFD_PCI · 22 unmodified lines | |||
| 23 | 23 | ||
| 24 | config CAN_CTUCANFD_PLATFORM | 24 | config CAN_CTUCANFD_PLATFORM |
| 25 | tristate "CTU CAN-FD IP core platform (FPGA, SoC) driver" | 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 | select CAN_CTUCANFD | 27 | select CAN_CTUCANFD |
| 28 | help | 28 | help |
| 29 | The core has been tested together with OpenCores SJA1000 | 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 | FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR, | 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 | static const struct flexcan_devtype_data fsl_vf610_devtype_data = { | 357 | static const struct flexcan_devtype_data fsl_vf610_devtype_data = { |
| 349 | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | | 358 | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | |
| 350 | FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX | | 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 | ret = flexcan_stop_mode_enable_scfw(priv, true); | 541 | ret = flexcan_stop_mode_enable_scfw(priv, true); |
| 533 | if (ret < 0) | 542 | if (ret < 0) |
| 534 | return ret; | 543 | return ret; |
| 535 | } else { | 544 | } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) { |
| 536 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, | 545 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
| 537 | 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); | 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 | return flexcan_low_power_enter_ack(priv); | 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 | ret = flexcan_stop_mode_enable_scfw(priv, false); | 565 | ret = flexcan_stop_mode_enable_scfw(priv, false); |
| 552 | if (ret < 0) | 566 | if (ret < 0) |
| 553 | return ret; | 567 | return ret; |
| 554 | } else { | 568 | } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) { |
| 555 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, | 569 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
| 556 | 1 << priv->stm.req_bit, 0); | 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 | reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; | 574 | reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; |
| 561 | priv->write(reg_mcr, ®s->mcr); | 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 | return flexcan_low_power_exit_ack(priv); | 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 | ret = flexcan_setup_stop_mode_scfw(pdev); | 1994 | ret = flexcan_setup_stop_mode_scfw(pdev); |
| 1975 | else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) | 1995 | else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) |
| 1976 | ret = flexcan_setup_stop_mode_gpr(pdev); | 1996 | ret = flexcan_setup_stop_mode_gpr(pdev); |
| 1997 | else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) | ||
| 1998 | ret = 0; | ||
| 1977 | else | 1999 | else |
| 1978 | /* return 0 directly if doesn't support stop mode feature */ | 2000 | /* return 0 directly if doesn't support stop mode feature */ |
| 1979 | return 0; | 2001 | return 0; |
| @@ -1992,6 +2014,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) · 12 unmodified lines | |||
| 1992 | static const struct of_device_id flexcan_of_match[] = { | 2014 | static const struct of_device_id flexcan_of_match[] = { |
| 1993 | { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, | 2015 | { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, |
| 1994 | { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, | 2016 | { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, |
| 2017 | { .compatible = "fsl,imx93-flexcan", .data = &fsl_imx93_devtype_data, }, | ||
| 1995 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, | 2018 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, |
| 1996 | { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, | 2019 | { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, |
| 1997 | { .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, }, | 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 | if (netif_running(dev)) { | 2322 | if (netif_running(dev)) { |
| 2300 | int err; | 2323 | int err; |
| 2301 | 2324 | ||
| 2302 | if (device_may_wakeup(device)) | 2325 | if (device_may_wakeup(device)) { |
| 2303 | flexcan_enable_wakeup_irq(priv, true); | 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 | err = pm_runtime_force_suspend(device); | 2336 | err = pm_runtime_force_suspend(device); |
| 2306 | if (err) | 2337 | if (err) |
| @@ -68,6 +68,8 @@ · 67 unmodified lines | |||
| 68 | #define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15) | 68 | #define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15) |
| 69 | /* Device supports RX via FIFO */ | 69 | /* Device supports RX via FIFO */ |
| 70 | #define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16) | 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 | struct flexcan_devtype_data { | 74 | struct flexcan_devtype_data { |
| 73 | u32 quirks; /* quirks needed for different IP cores */ | 75 | u32 quirks; /* quirks needed for different IP cores */ |
| @@ -9,20 +9,20 @@ · 8 unmodified lines | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/bitfield.h> | 11 | #include <linux/bitfield.h> |
| 12 | #include <linux/can/dev.h> | ||
| 12 | #include <linux/ethtool.h> | 13 | #include <linux/ethtool.h> |
| 13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 14 | #include <linux/io.h> | 15 | #include <linux/io.h> |
| 16 | #include <linux/iopoll.h> | ||
| 15 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 16 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 17 | #include <linux/netdevice.h> | 19 | #include <linux/netdevice.h> |
| 18 | #include <linux/of.h> | 20 | #include <linux/of.h> |
| 19 | #include <linux/of_device.h> | 21 | #include <linux/of_device.h> |
| 22 | #include <linux/phy/phy.h> | ||
| 23 | #include <linux/pinctrl/consumer.h> | ||
| 20 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 21 | #include <linux/pm_runtime.h> | 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 | #include "m_can.h" | 27 | #include "m_can.h" |
| 28 | 28 | ||
| @@ -156,6 +156,7 @@ enum m_can_reg { · 127 unmodified lines | |||
| 156 | #define PSR_EW BIT(6) | 156 | #define PSR_EW BIT(6) |
| 157 | #define PSR_EP BIT(5) | 157 | #define PSR_EP BIT(5) |
| 158 | #define PSR_LEC_MASK GENMASK(2, 0) | 158 | #define PSR_LEC_MASK GENMASK(2, 0) |
| 159 | #define PSR_DLEC_MASK GENMASK(10, 8) | ||
| 159 | 160 | ||
| 160 | /* Interrupt Register (IR) */ | 161 | /* Interrupt Register (IR) */ |
| 161 | #define IR_ALL_INT 0xffffffff | 162 | #define IR_ALL_INT 0xffffffff |
| @@ -209,7 +210,7 @@ enum m_can_reg { · 47 unmodified lines | |||
| 209 | 210 | ||
| 210 | /* Interrupts for version >= 3.1.x */ | 211 | /* Interrupts for version >= 3.1.x */ |
| 211 | #define IR_ERR_LEC_31X (IR_PED | IR_PEA) | 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 | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \ | 214 | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \ |
| 214 | IR_RF0L) | 215 | IR_RF0L) |
| 215 | #define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X) | 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 | return cdev->ops->read_fifo(cdev, addr_offset, val, 1); | 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 | static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev) | 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 | static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) | 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 | struct net_device_stats *stats = &dev->stats; | 482 | struct net_device_stats *stats = &dev->stats; |
| 477 | struct m_can_classdev *cdev = netdev_priv(dev); | 483 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 478 | struct canfd_frame *cf; | 484 | struct canfd_frame *cf; |
| 479 | struct sk_buff *skb; | 485 | struct sk_buff *skb; |
| 480 | struct id_and_dlc fifo_header; | 486 | struct id_and_dlc fifo_header; |
| 481 | u32 fgi; | ||
| 482 | u32 timestamp = 0; | 487 | u32 timestamp = 0; |
| 483 | int err; | 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 | err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID, &fifo_header, 2); | 490 | err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID, &fifo_header, 2); |
| 488 | if (err) | 491 | if (err) |
| 489 | goto out_fail; | 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 | stats->rx_packets++; | 531 | stats->rx_packets++; |
| 529 | 532 | ||
| 530 | /* acknowledge rx fifo 0 */ | ||
| 531 | m_can_write(cdev, M_CAN_RXF0A, fgi); | ||
| 532 | |||
| 533 | timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16; | 533 | timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16; |
| 534 | 534 | ||
| 535 | m_can_receive_skb(cdev, skb, timestamp); | 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 | struct m_can_classdev *cdev = netdev_priv(dev); | 548 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 549 | u32 pkts = 0; | 549 | u32 pkts = 0; |
| 550 | u32 rxfs; | 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 | rxfs = m_can_read(cdev, M_CAN_RXF0S); | 557 | rxfs = m_can_read(cdev, M_CAN_RXF0S); |
| 554 | if (!(rxfs & RXFS_FFL_MASK)) { | 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 | return 0; | 560 | return 0; |
| 557 | } | 561 | } |
| 558 | 562 | ||
| 559 | while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) { | 563 | rx_count = FIELD_GET(RXFS_FFL_MASK, rxfs); |
| 560 | err = m_can_read_fifo(dev, 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 | if (err) | 568 | if (err) |
| 562 | return err; | 569 | break; |
| 563 | 570 | ||
| 564 | quota--; | 571 | quota--; |
| 565 | pkts++; | 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 | return pkts; | 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 | netdev_err(dev, "Message RAM access failure occurred\n"); | 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; | 835 | return lec != LEC_NO_ERROR && lec != LEC_NO_CHANGE; |
| 822 | |||
| 823 | return psr && (psr != LEC_UNUSED); | ||
| 824 | } | 836 | } |
| 825 | 837 | ||
| 826 | static inline bool m_can_is_protocol_err(u32 irqstatus) | 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 | work_done += m_can_handle_lost_msg(dev); | 887 | work_done += m_can_handle_lost_msg(dev); |
| 876 | 888 | ||
| 877 | /* handle lec errors on the bus */ | 889 | /* handle lec errors on the bus */ |
| 878 | if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && | 890 | if (cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { |
| 879 | is_lec_err(psr)) | 891 | u8 lec = FIELD_GET(PSR_LEC_MASK, psr); |
| 880 | work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED); | 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 | /* handle protocol errors in arbitration phase */ | 905 | /* handle protocol errors in arbitration phase */ |
| 883 | if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && | 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 | return work_done; | 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 | struct m_can_classdev *cdev = netdev_priv(dev); | 918 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 896 | int rx_work_or_err; | 919 | int rx_work_or_err; |
| 897 | int work_done = 0; | 920 | int work_done = 0; |
| 898 | u32 irqstatus, psr; | ||
| 899 | 921 | ||
| 900 | irqstatus = cdev->irqstatus | m_can_read(cdev, M_CAN_IR); | ||
| 901 | if (!irqstatus) | 922 | if (!irqstatus) |
| 902 | goto end; | 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 | if (irqstatus & IR_ERR_STATE) | 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 | if (irqstatus & IR_ERR_BUS_30X) | 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 | if (irqstatus & IR_RF0N) { | 954 | if (irqstatus & IR_RF0N) { |
| 934 | rx_work_or_err = m_can_do_rx_poll(dev, (quota - work_done)); | 955 | rx_work_or_err = m_can_do_rx_poll(dev, (quota - work_done)); |
| @@ -941,12 +962,12 @@ end: · 6 unmodified lines | |||
| 941 | return work_done; | 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 | struct m_can_classdev *cdev = netdev_priv(dev); | 967 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 947 | int work_done; | 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 | /* Don't re-enable interrupts if the driver had a fatal error | 972 | /* Don't re-enable interrupts if the driver had a fatal error |
| 952 | * (e.g., FIFO read failure). | 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 | struct net_device *dev = napi->dev; | 983 | struct net_device *dev = napi->dev; |
| 963 | struct m_can_classdev *cdev = netdev_priv(dev); | 984 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 964 | int work_done; | 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 | /* Don't re-enable interrupts if the driver had a fatal error | 992 | /* Don't re-enable interrupts if the driver had a fatal error |
| 969 | * (e.g., FIFO read failure). | 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 | u32 txe_count = 0; | 1028 | u32 txe_count = 0; |
| 1005 | u32 m_can_txefs; | 1029 | u32 m_can_txefs; |
| 1006 | u32 fgi = 0; | 1030 | u32 fgi = 0; |
| 1031 | int ack_fgi = -1; | ||
| 1007 | int i = 0; | 1032 | int i = 0; |
| 1033 | int err = 0; | ||
| 1008 | unsigned int msg_mark; | 1034 | unsigned int msg_mark; |
| 1009 | 1035 | ||
| 1010 | struct m_can_classdev *cdev = netdev_priv(dev); | 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 | /* Get Tx Event fifo element count */ | 1041 | /* Get Tx Event fifo element count */ |
| 1016 | txe_count = FIELD_GET(TXEFS_EFFL_MASK, m_can_txefs); | 1042 | txe_count = FIELD_GET(TXEFS_EFFL_MASK, m_can_txefs); |
| 1043 | fgi = FIELD_GET(TXEFS_EFGI_MASK, m_can_txefs); | ||
| 1017 | 1044 | ||
| 1018 | /* Get and process all sent elements */ | 1045 | /* Get and process all sent elements */ |
| 1019 | for (i = 0; i < txe_count; i++) { | 1046 | for (i = 0; i < txe_count; i++) { |
| 1020 | u32 txe, timestamp = 0; | 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 | /* get message marker, timestamp */ | 1049 | /* get message marker, timestamp */ |
| 1027 | err = m_can_txe_fifo_read(cdev, fgi, 4, &txe); | 1050 | err = m_can_txe_fifo_read(cdev, fgi, 4, &txe); |
| 1028 | if (err) { | 1051 | if (err) { |
| 1029 | netdev_err(dev, "TXE FIFO read returned %d\n", err); | 1052 | netdev_err(dev, "TXE FIFO read returned %d\n", err); |
| 1030 | return err; | 1053 | break; |
| 1031 | } | 1054 | } |
| 1032 | 1055 | ||
| 1033 | msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe); | 1056 | msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe); |
| 1034 | timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16; | 1057 | timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16; |
| 1035 | 1058 | ||
| 1036 | /* ack txe element */ | 1059 | ack_fgi = fgi; |
| 1037 | m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK, | 1060 | fgi = (++fgi >= cdev->mcfg[MRAM_TXE].num ? 0 : fgi); |
| 1038 | fgi)); | ||
| 1039 | 1061 | ||
| 1040 | /* update stats */ | 1062 | /* update stats */ |
| 1041 | m_can_tx_update_stats(cdev, msg_mark, timestamp); | 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 | static irqreturn_t m_can_isr(int irq, void *dev_id) | 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 | m_can_disable_all_interrupts(cdev); | 1099 | m_can_disable_all_interrupts(cdev); |
| 1074 | if (!cdev->is_peripheral) | 1100 | if (!cdev->is_peripheral) |
| 1075 | napi_schedule(&cdev->napi); | 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 | goto out_fail; | 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 | * - setup bittiming | 1259 | * - setup bittiming |
| 1234 | * - configure timestamp generation | 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 | struct m_can_classdev *cdev = netdev_priv(dev); | 1264 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 1239 | u32 cccr, test; | 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 | m_can_config_endisable(cdev, true); | 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 | if (cdev->ops->init) | 1394 | if (cdev->ops->init) |
| 1362 | cdev->ops->init(cdev); | 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 | struct m_can_classdev *cdev = netdev_priv(dev); | 1402 | struct m_can_classdev *cdev = netdev_priv(dev); |
| 1403 | int ret; | ||
| 1368 | 1404 | ||
| 1369 | /* basic m_can configuration */ | 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 | cdev->can.state = CAN_STATE_ERROR_ACTIVE; | 1410 | cdev->can.state = CAN_STATE_ERROR_ACTIVE; |
| 1373 | 1411 | ||
| 1374 | m_can_enable_all_interrupts(cdev); | 1412 | m_can_enable_all_interrupts(cdev); |
| 1413 | |||
| 1414 | return 0; | ||
| 1375 | } | 1415 | } |
| 1376 | 1416 | ||
| 1377 | static int m_can_set_mode(struct net_device *dev, enum can_mode mode) | 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 | struct sk_buff *skb = cdev->tx_skb; | 1625 | struct sk_buff *skb = cdev->tx_skb; |
| 1586 | struct id_and_dlc fifo_header; | 1626 | struct id_and_dlc fifo_header; |
| 1587 | u32 cccr, fdflags; | 1627 | u32 cccr, fdflags; |
| 1628 | u32 txfqs; | ||
| 1588 | int err; | 1629 | int err; |
| 1589 | int putidx; | 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 | } else { | 1682 | } else { |
| 1642 | /* Transmit routine for version >= v3.1.x */ | 1683 | /* Transmit routine for version >= v3.1.x */ |
| 1643 | 1684 | ||
| 1685 | txfqs = m_can_read(cdev, M_CAN_TXFQS); | ||
| 1686 | |||
| 1644 | /* Check if FIFO full */ | 1687 | /* Check if FIFO full */ |
| 1645 | if (m_can_tx_fifo_full(cdev)) { | 1688 | if (_m_can_tx_fifo_full(txfqs)) { |
| 1646 | /* This shouldn't happen */ | 1689 | /* This shouldn't happen */ |
| 1647 | netif_stop_queue(dev); | 1690 | netif_stop_queue(dev); |
| 1648 | netdev_warn(dev, | 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 | /* get put index for frame */ | 1703 | /* get put index for frame */ |
| 1661 | putidx = FIELD_GET(TXFQS_TFQPI_MASK, | 1704 | putidx = FIELD_GET(TXFQS_TFQPI_MASK, txfqs); |
| 1662 | m_can_read(cdev, M_CAN_TXFQS)); | ||
| 1663 | 1705 | ||
| 1664 | /* Construct DLC Field, with CAN-FD configuration. | 1706 | /* Construct DLC Field, with CAN-FD configuration. |
| 1665 | * Use the put index of the fifo as the message marker, | 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 | /* start the m_can controller */ | 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 | if (!cdev->is_peripheral) | 1848 | if (!cdev->is_peripheral) |
| 1805 | napi_enable(&cdev->napi); | 1849 | napi_enable(&cdev->napi); |
| @@ -2058,9 +2102,13 @@ int m_can_class_resume(struct device *dev) · 252 unmodified lines | |||
| 2058 | ret = m_can_clk_start(cdev); | 2102 | ret = m_can_clk_start(cdev); |
| 2059 | if (ret) | 2103 | if (ret) |
| 2060 | return ret; | 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 | netif_device_attach(ndev); | 2112 | netif_device_attach(ndev); |
| 2065 | netif_start_queue(ndev); | 2113 | netif_start_queue(ndev); |
| 2066 | } | 2114 | } |
| @@ -7,27 +7,27 @@ · 6 unmodified lines | |||
| 7 | #define _CAN_M_CAN_H_ | 7 | #define _CAN_M_CAN_H_ |
| 8 | 8 | ||
| 9 | #include <linux/can/core.h> | 9 | #include <linux/can/core.h> |
| 10 | #include <linux/can/dev.h> | ||
| 10 | #include <linux/can/rx-offload.h> | 11 | #include <linux/can/rx-offload.h> |
| 12 | #include <linux/clk.h> | ||
| 11 | #include <linux/completion.h> | 13 | #include <linux/completion.h> |
| 14 | #include <linux/delay.h> | ||
| 12 | #include <linux/device.h> | 15 | #include <linux/device.h> |
| 13 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
| 14 | #include <linux/freezer.h> | 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 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 20 | #include <linux/io.h> | 19 | #include <linux/io.h> |
| 20 | #include <linux/iopoll.h> | ||
| 21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
| 24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
| 25 | #include <linux/of_device.h> | 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 | #include <linux/phy/phy.h> | 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 | /* m_can lec values */ | 32 | /* m_can lec values */ |
| 33 | enum m_can_lec_type { | 33 | enum m_can_lec_type { |
| @@ -38,7 +38,7 @@ enum m_can_lec_type { · 4 unmodified lines | |||
| 38 | LEC_BIT1_ERROR, | 38 | LEC_BIT1_ERROR, |
| 39 | LEC_BIT0_ERROR, | 39 | LEC_BIT0_ERROR, |
| 40 | LEC_CRC_ERROR, | 40 | LEC_CRC_ERROR, |
| 41 | LEC_UNUSED, | 41 | LEC_NO_CHANGE, |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | enum m_can_mram_cfg { | 44 | enum m_can_mram_cfg { |
| @@ -5,8 +5,8 @@ · 4 unmodified lines | |||
| 5 | // | 5 | // |
| 6 | // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ | 6 | // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ |
| 7 | 7 | ||
| 8 | #include <linux/platform_device.h> | ||
| 9 | #include <linux/phy/phy.h> | 8 | #include <linux/phy/phy.h> |
| 9 | #include <linux/platform_device.h> | ||
| 10 | 10 | ||
| 11 | #include "m_can.h" | 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 | platform_set_drvdata(pdev, mcan_class); | 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 | pm_runtime_enable(mcan_class->dev); | 143 | pm_runtime_enable(mcan_class->dev); |
| 148 | ret = m_can_class_register(mcan_class); | 144 | ret = m_can_class_register(mcan_class); |
| 149 | if (ret) | 145 | if (ret) |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #define TCAN4X5X_DEV_ID1 0x04 | 10 | #define TCAN4X5X_DEV_ID1 0x04 |
| 11 | #define TCAN4X5X_REV 0x08 | 11 | #define TCAN4X5X_REV 0x08 |
| 12 | #define TCAN4X5X_STATUS 0x0C | 12 | #define TCAN4X5X_STATUS 0x0C |
| 13 | #define TCAN4X5X_ERROR_STATUS 0x10 | 13 | #define TCAN4X5X_ERROR_STATUS_MASK 0x10 |
| 14 | #define TCAN4X5X_CONTROL 0x14 | 14 | #define TCAN4X5X_CONTROL 0x14 |
| 15 | 15 | ||
| 16 | #define TCAN4X5X_CONFIG 0x800 | 16 | #define TCAN4X5X_CONFIG 0x800 |
| @@ -204,17 +204,7 @@ static int tcan4x5x_clear_interrupts(struct m_can_classdev *cdev) · 187 unmodified lines | |||
| 204 | if (ret) | 204 | if (ret) |
| 205 | return ret; | 205 | return ret; |
| 206 | 206 | ||
| 207 | ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_MCAN_INT_REG, | 207 | return tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_FLAGS, |
| 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, | ||
| 218 | TCAN4X5X_CLEAR_ALL_INT); | 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 | if (ret) | 224 | if (ret) |
| 235 | return ret; | 225 | return ret; |
| 236 | 226 | ||
| 237 | /* Zero out the MCAN buffers */ | 227 | ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS_MASK, |
| 238 | ret = m_can_init_ram(cdev); | 228 | TCAN4X5X_CLEAR_ALL_INT); |
| 239 | if (ret) | 229 | if (ret) |
| 240 | return ret; | 230 | return ret; |
| 241 | 231 | ||
| @@ -90,16 +90,47 @@ static int tcan4x5x_regmap_read(void *context, · 89 unmodified lines | |||
| 90 | return 0; | 90 | return 0; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static const struct regmap_range tcan4x5x_reg_table_yes_range[] = { | 93 | static const struct regmap_range tcan4x5x_reg_table_wr_range[] = { |
| 94 | regmap_reg_range(0x0000, 0x002c), /* Device ID and SPI Registers */ | 94 | /* Device ID and SPI Registers */ |
| 95 | regmap_reg_range(0x0800, 0x083c), /* Device configuration registers and Interrupt Flags*/ | 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 | regmap_reg_range(0x1000, 0x10fc), /* M_CAN */ | 122 | regmap_reg_range(0x1000, 0x10fc), /* M_CAN */ |
| 97 | regmap_reg_range(0x8000, 0x87fc), /* MRAM */ | 123 | regmap_reg_range(0x8000, 0x87fc), /* MRAM */ |
| 98 | }; | 124 | }; |
| 99 | 125 | ||
| 100 | static const struct regmap_access_table tcan4x5x_reg_table = { | 126 | static const struct regmap_access_table tcan4x5x_reg_table_wr = { |
| 101 | .yes_ranges = tcan4x5x_reg_table_yes_range, | 127 | .yes_ranges = tcan4x5x_reg_table_wr_range, |
| 102 | .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_yes_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 | static const struct regmap_config tcan4x5x_regmap = { | 136 | static const struct regmap_config tcan4x5x_regmap = { |
| @@ -107,8 +138,8 @@ static const struct regmap_config tcan4x5x_regmap = { · 1 unmodified line | |||
| 107 | .reg_stride = 4, | 138 | .reg_stride = 4, |
| 108 | .pad_bits = 8, | 139 | .pad_bits = 8, |
| 109 | .val_bits = 32, | 140 | .val_bits = 32, |
| 110 | .wr_table = &tcan4x5x_reg_table, | 141 | .wr_table = &tcan4x5x_reg_table_wr, |
| 111 | .rd_table = &tcan4x5x_reg_table, | 142 | .rd_table = &tcan4x5x_reg_table_rd, |
| 112 | .max_register = TCAN4X5X_MAX_REGISTER, | 143 | .max_register = TCAN4X5X_MAX_REGISTER, |
| 113 | .cache_type = REGCACHE_NONE, | 144 | .cache_type = REGCACHE_NONE, |
| 114 | .read_flag_mask = (__force unsigned long) | 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 | #define RCANFD_DRV_NAME "rcar_canfd" | 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 | /* Global register bits */ | 44 | /* Global register bits */ |
| 51 | 45 | ||
| 52 | /* RSCFDnCFDGRMCFG */ | 46 | /* RSCFDnCFDGRMCFG */ |
| @@ -522,6 +516,14 @@ enum rcar_canfd_fcanclk { · 469 unmodified lines | |||
| 522 | 516 | ||
| 523 | struct rcar_canfd_global; | 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 | /* Channel priv data */ | 527 | /* Channel priv data */ |
| 526 | struct rcar_canfd_channel { | 528 | struct rcar_canfd_channel { |
| 527 | struct can_priv can; /* Must be the first member */ | 529 | struct can_priv can; /* Must be the first member */ |
| @@ -547,8 +549,7 @@ struct rcar_canfd_global { · 19 unmodified lines | |||
| 547 | bool fdmode; /* CAN FD or Classical CAN only mode */ | 549 | bool fdmode; /* CAN FD or Classical CAN only mode */ |
| 548 | struct reset_control *rstc1; | 550 | struct reset_control *rstc1; |
| 549 | struct reset_control *rstc2; | 551 | struct reset_control *rstc2; |
| 550 | enum rcanfd_chip_id chip_id; | 552 | const struct rcar_canfd_hw_info *info; |
| 551 | u32 max_channels; | ||
| 552 | }; | 553 | }; |
| 553 | 554 | ||
| 554 | /* CAN FD mode nominal rate constants */ | 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 | .brp_inc = 1, | 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 | /* Helper functions */ | 612 | /* Helper functions */ |
| 594 | static inline bool is_v3u(struct rcar_canfd_global *gpriv) | 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 | static inline u32 reg_v3u(struct rcar_canfd_global *gpriv, | 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 | rcar_canfd_set_mode(gpriv); | 740 | rcar_canfd_set_mode(gpriv); |
| 722 | 741 | ||
| 723 | /* Transition all Channels to reset mode */ | 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 | rcar_canfd_clear_bit(gpriv->base, | 744 | rcar_canfd_clear_bit(gpriv->base, |
| 726 | RCANFD_CCTR(ch), RCANFD_CCTR_CSLPR); | 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 | rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg); | 781 | rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg); |
| 763 | 782 | ||
| 764 | /* Channel configuration settings */ | 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 | rcar_canfd_set_bit(gpriv->base, RCANFD_CCTR(ch), | 785 | rcar_canfd_set_bit(gpriv->base, RCANFD_CCTR(ch), |
| 767 | RCANFD_CCTR_ERRD); | 786 | RCANFD_CCTR_ERRD); |
| 768 | rcar_canfd_update_bit(gpriv->base, RCANFD_CCTR(ch), | 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 | struct rcar_canfd_global *gpriv = dev_id; | 1161 | struct rcar_canfd_global *gpriv = dev_id; |
| 1143 | u32 ch; | 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 | rcar_canfd_handle_global_err(gpriv, ch); | 1165 | rcar_canfd_handle_global_err(gpriv, ch); |
| 1147 | 1166 | ||
| 1148 | return IRQ_HANDLED; | 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 | struct rcar_canfd_global *gpriv = dev_id; | 1193 | struct rcar_canfd_global *gpriv = dev_id; |
| 1175 | u32 ch; | 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 | rcar_canfd_handle_global_receive(gpriv, ch); | 1197 | rcar_canfd_handle_global_receive(gpriv, ch); |
| 1179 | 1198 | ||
| 1180 | return IRQ_HANDLED; | 1199 | return IRQ_HANDLED; |
| @@ -1188,7 +1207,7 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id) · 7 unmodified lines | |||
| 1188 | /* Global error interrupts still indicate a condition specific | 1207 | /* Global error interrupts still indicate a condition specific |
| 1189 | * to a channel. RxFIFO interrupt is a global interrupt. | 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 | rcar_canfd_handle_global_err(gpriv, ch); | 1211 | rcar_canfd_handle_global_err(gpriv, ch); |
| 1193 | rcar_canfd_handle_global_receive(gpriv, ch); | 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 | u32 ch; | 1303 | u32 ch; |
| 1285 | 1304 | ||
| 1286 | /* Common FIFO is a per channel resource */ | 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 | rcar_canfd_handle_channel_err(gpriv, ch); | 1307 | rcar_canfd_handle_channel_err(gpriv, ch); |
| 1289 | rcar_canfd_handle_channel_tx(gpriv, ch); | 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 | static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, | 1715 | static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, |
| 1697 | u32 fcan_freq) | 1716 | u32 fcan_freq) |
| 1698 | { | 1717 | { |
| 1718 | const struct rcar_canfd_hw_info *info = gpriv->info; | ||
| 1699 | struct platform_device *pdev = gpriv->pdev; | 1719 | struct platform_device *pdev = gpriv->pdev; |
| 1700 | struct rcar_canfd_channel *priv; | 1720 | struct rcar_canfd_channel *priv; |
| 1701 | struct net_device *ndev; | 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 | priv->can.clock.freq = fcan_freq; | 1738 | priv->can.clock.freq = fcan_freq; |
| 1719 | dev_info(&pdev->dev, "can_clk rate is %u\n", priv->can.clock.freq); | 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 | char *irq_name; | 1742 | char *irq_name; |
| 1723 | int err_irq; | 1743 | int err_irq; |
| 1724 | int tx_irq; | 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 | static int rcar_canfd_probe(struct platform_device *pdev) | 1839 | static int rcar_canfd_probe(struct platform_device *pdev) |
| 1820 | { | 1840 | { |
| 1841 | const struct rcar_canfd_hw_info *info; | ||
| 1821 | void __iomem *addr; | 1842 | void __iomem *addr; |
| 1822 | u32 sts, ch, fcan_freq; | 1843 | u32 sts, ch, fcan_freq; |
| 1823 | struct rcar_canfd_global *gpriv; | 1844 | struct rcar_canfd_global *gpriv; |
| @@ -1826,18 +1847,15 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 1826 | int err, ch_irq, g_irq; | 1847 | int err, ch_irq, g_irq; |
| 1827 | int g_err_irq, g_recc_irq; | 1848 | int g_err_irq, g_recc_irq; |
| 1828 | bool fdmode = true; /* CAN FD only mode - default */ | 1849 | bool fdmode = true; /* CAN FD only mode - default */ |
| 1829 | enum rcanfd_chip_id chip_id; | ||
| 1830 | int max_channels; | ||
| 1831 | char name[9] = "channelX"; | 1850 | char name[9] = "channelX"; |
| 1832 | int i; | 1851 | int i; |
| 1833 | 1852 | ||
| 1834 | chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev); | 1853 | info = of_device_get_match_data(&pdev->dev); |
| 1835 | max_channels = chip_id == RENESAS_R8A779A0 ? 8 : 2; | ||
| 1836 | 1854 | ||
| 1837 | if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd")) | 1855 | if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd")) |
| 1838 | fdmode = false; /* Classical CAN only mode */ | 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 | name[7] = '0' + i; | 1859 | name[7] = '0' + i; |
| 1842 | of_child = of_get_child_by_name(pdev->dev.of_node, name); | 1860 | of_child = of_get_child_by_name(pdev->dev.of_node, name); |
| 1843 | if (of_child && of_device_is_available(of_child)) | 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 | of_node_put(of_child); | 1863 | of_node_put(of_child); |
| 1846 | } | 1864 | } |
| 1847 | 1865 | ||
| 1848 | if (chip_id != RENESAS_RZG2L) { | 1866 | if (info->shared_global_irqs) { |
| 1849 | ch_irq = platform_get_irq_byname_optional(pdev, "ch_int"); | 1867 | ch_irq = platform_get_irq_byname_optional(pdev, "ch_int"); |
| 1850 | if (ch_irq < 0) { | 1868 | if (ch_irq < 0) { |
| 1851 | /* For backward compatibility get irq by index */ | 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 | gpriv->pdev = pdev; | 1897 | gpriv->pdev = pdev; |
| 1880 | gpriv->channels_mask = channels_mask; | 1898 | gpriv->channels_mask = channels_mask; |
| 1881 | gpriv->fdmode = fdmode; | 1899 | gpriv->fdmode = fdmode; |
| 1882 | gpriv->chip_id = chip_id; | 1900 | gpriv->info = info; |
| 1883 | gpriv->max_channels = max_channels; | 1901 | |
| 1884 | 1902 | gpriv->rstc1 = devm_reset_control_get_optional_exclusive(&pdev->dev, | |
| 1885 | if (gpriv->chip_id == RENESAS_RZG2L) { | 1903 | "rstp_n"); |
| 1886 | gpriv->rstc1 = devm_reset_control_get_exclusive(&pdev->dev, "rstp_n"); | 1904 | if (IS_ERR(gpriv->rstc1)) |
| 1887 | if (IS_ERR(gpriv->rstc1)) | 1905 | return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1), |
| 1888 | return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1), | 1906 | "failed to get rstp_n\n"); |
| 1889 | "failed to get rstp_n\n"); | 1907 | |
| 1890 | 1908 | gpriv->rstc2 = devm_reset_control_get_optional_exclusive(&pdev->dev, | |
| 1891 | gpriv->rstc2 = devm_reset_control_get_exclusive(&pdev->dev, "rstc_n"); | 1909 | "rstc_n"); |
| 1892 | if (IS_ERR(gpriv->rstc2)) | 1910 | if (IS_ERR(gpriv->rstc2)) |
| 1893 | return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2), | 1911 | return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2), |
| 1894 | "failed to get rstc_n\n"); | 1912 | "failed to get rstc_n\n"); |
| 1895 | } | ||
| 1896 | 1913 | ||
| 1897 | /* Peripheral clock */ | 1914 | /* Peripheral clock */ |
| 1898 | gpriv->clkp = devm_clk_get(&pdev->dev, "fck"); | 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 | fcan_freq = clk_get_rate(gpriv->can_clk); | 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 | /* CANFD clock is further divided by (1/2) within the IP */ | 1938 | /* CANFD clock is further divided by (1/2) within the IP */ |
| 1922 | fcan_freq /= 2; | 1939 | fcan_freq /= info->postdiv; |
| 1923 | 1940 | ||
| 1924 | addr = devm_platform_ioremap_resource(pdev, 0); | 1941 | addr = devm_platform_ioremap_resource(pdev, 0); |
| 1925 | if (IS_ERR(addr)) { | 1942 | if (IS_ERR(addr)) { |
| @@ -1929,7 +1946,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 3 unmodified lines | |||
| 1929 | gpriv->base = addr; | 1946 | gpriv->base = addr; |
| 1930 | 1947 | ||
| 1931 | /* Request IRQ that's common for both channels */ | 1948 | /* Request IRQ that's common for both channels */ |
| 1932 | if (gpriv->chip_id != RENESAS_RZG2L) { | 1949 | if (info->shared_global_irqs) { |
| 1933 | err = devm_request_irq(&pdev->dev, ch_irq, | 1950 | err = devm_request_irq(&pdev->dev, ch_irq, |
| 1934 | rcar_canfd_channel_interrupt, 0, | 1951 | rcar_canfd_channel_interrupt, 0, |
| 1935 | "canfd.ch_int", gpriv); | 1952 | "canfd.ch_int", gpriv); |
| @@ -1995,7 +2012,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 59 unmodified lines | |||
| 1995 | rcar_canfd_configure_controller(gpriv); | 2012 | rcar_canfd_configure_controller(gpriv); |
| 1996 | 2013 | ||
| 1997 | /* Configure per channel attributes */ | 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 | /* Configure Channel's Rx fifo */ | 2016 | /* Configure Channel's Rx fifo */ |
| 2000 | rcar_canfd_configure_rx(gpriv, ch); | 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 | goto fail_mode; | 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 | err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq); | 2042 | err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq); |
| 2026 | if (err) | 2043 | if (err) |
| 2027 | goto fail_channel; | 2044 | goto fail_channel; |
| @@ -2033,7 +2050,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 2033 | return 0; | 2050 | return 0; |
| 2034 | 2051 | ||
| 2035 | fail_channel: | 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 | rcar_canfd_channel_remove(gpriv, ch); | 2054 | rcar_canfd_channel_remove(gpriv, ch); |
| 2038 | fail_mode: | 2055 | fail_mode: |
| 2039 | rcar_canfd_disable_global_interrupts(gpriv); | 2056 | rcar_canfd_disable_global_interrupts(gpriv); |
| @@ -2054,7 +2071,7 @@ static int rcar_canfd_remove(struct platform_device *pdev) · 14 unmodified lines | |||
| 2054 | rcar_canfd_reset_controller(gpriv); | 2071 | rcar_canfd_reset_controller(gpriv); |
| 2055 | rcar_canfd_disable_global_interrupts(gpriv); | 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 | rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]); | 2075 | rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]); |
| 2059 | rcar_canfd_channel_remove(gpriv, ch); | 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 | rcar_canfd_resume); | 2099 | rcar_canfd_resume); |
| 2083 | 2100 | ||
| 2084 | static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = { | 2101 | static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = { |
| 2085 | { .compatible = "renesas,rcar-gen3-canfd", .data = (void *)RENESAS_RCAR_GEN3 }, | 2102 | { .compatible = "renesas,rcar-gen3-canfd", .data = &rcar_gen3_hw_info }, |
| 2086 | { .compatible = "renesas,rzg2l-canfd", .data = (void *)RENESAS_RZG2L }, | 2103 | { .compatible = "renesas,rzg2l-canfd", .data = &rzg2l_hw_info }, |
| 2087 | { .compatible = "renesas,r8a779a0-canfd", .data = (void *)RENESAS_R8A779A0 }, | 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 | config CAN_ETAS_ES58X | 30 | config CAN_ETAS_ES58X |
| 31 | tristate "ETAS ES58X CAN/USB interfaces" | 31 | tristate "ETAS ES58X CAN/USB interfaces" |
| 32 | select CRC16 | 32 | select CRC16 |
| 33 | select NET_DEVLINK | ||
| 33 | help | 34 | help |
| 34 | This driver supports the ES581.4, ES582.1 and ES584.1 interfaces | 35 | This driver supports the ES581.4, ES582.1 and ES584.1 interfaces |
| 35 | from ETAS GmbH (https://www.etas.com/en/products/es58x.php). | 36 | from ETAS GmbH (https://www.etas.com/en/products/es58x.php). |
| @@ -38,10 +39,13 @@ config CAN_ETAS_ES58X · 2 unmodified lines | |||
| 38 | will be called etas_es58x. | 39 | will be called etas_es58x. |
| 39 | 40 | ||
| 40 | config CAN_GS_USB | 41 | config CAN_GS_USB |
| 41 | tristate "Geschwister Schneider UG interfaces" | 42 | tristate "Geschwister Schneider UG and candleLight compatible interfaces" |
| 42 | help | 43 | help |
| 43 | This driver supports the Geschwister Schneider and bytewerk.org | 44 | This driver supports the Geschwister Schneider and |
| 44 | candleLight USB CAN interfaces USB/CAN devices | 45 | bytewerk.org candleLight compatible |
| 46 | (https://github.com/candle-usb/candleLight_fw) USB/CAN | ||
| 47 | interfaces. | ||
| 48 | |||
| 45 | If unsure choose N, | 49 | If unsure choose N, |
| 46 | choose Y for built in support, | 50 | choose Y for built in support, |
| 47 | M to compile as module (module will be named: gs_usb). | 51 | M to compile as module (module will be named: gs_usb). |
| @@ -1,3 +1,3 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x.o | 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 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. | 7 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 8 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. | 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 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 13 | #include <linux/units.h> | 14 | #include <linux/units.h> |
| 14 | #include <asm/unaligned.h> | ||
| 15 | 15 | ||
| 16 | #include "es58x_core.h" | 16 | #include "es58x_core.h" |
| 17 | #include "es581_4.h" | 17 | #include "es581_4.h" |
| @@ -7,15 +7,16 @@ · 6 unmodified lines | |||
| 7 | * | 7 | * |
| 8 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. | 8 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 9 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. | 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 | #include <linux/ethtool.h> | 15 | #include <linux/ethtool.h> |
| 14 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 15 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 16 | #include <linux/usb.h> | 18 | #include <linux/usb.h> |
| 17 | #include <linux/crc16.h> | 19 | #include <net/devlink.h> |
| 18 | #include <asm/unaligned.h> | ||
| 19 | 20 | ||
| 20 | #include "es58x_core.h" | 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 | * @es58x_dev: ES58X device. | 2039 | * @es58x_dev: ES58X device. |
| 2039 | * @priv: ES58X private parameters related to the network device. | 2040 | * @priv: ES58X private parameters related to the network device. |
| 2040 | * @channel_idx: Index of the network device. | 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, | 2046 | static int es58x_init_priv(struct es58x_device *es58x_dev, |
| 2043 | struct es58x_priv *priv, int channel_idx) | 2047 | struct es58x_priv *priv, int channel_idx) |
| 2044 | { | 2048 | { |
| 2049 | struct devlink_port_attrs attrs = { | ||
| 2050 | .flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL, | ||
| 2051 | }; | ||
| 2045 | const struct es58x_parameters *param = es58x_dev->param; | 2052 | const struct es58x_parameters *param = es58x_dev->param; |
| 2046 | struct can_priv *can = &priv->can; | 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 | can->state = CAN_STATE_STOPPED; | 2067 | can->state = CAN_STATE_STOPPED; |
| 2061 | can->ctrlmode_supported = param->ctrlmode_supported; | 2068 | can->ctrlmode_supported = param->ctrlmode_supported; |
| 2062 | can->do_set_mode = es58x_set_mode; | 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 | SET_NETDEV_DEV(netdev, dev); | 2095 | SET_NETDEV_DEV(netdev, dev); |
| 2085 | es58x_dev->netdev[channel_idx] = netdev; | 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 | netdev->netdev_ops = &es58x_netdev_ops; | 2102 | netdev->netdev_ops = &es58x_netdev_ops; |
| 2089 | netdev->ethtool_ops = &es58x_ethtool_ops; | 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 | netdev->dev_port = channel_idx; | 2105 | netdev->dev_port = channel_idx; |
| 2092 | 2106 | ||
| 2093 | ret = register_candev(netdev); | 2107 | ret = register_candev(netdev); |
| 2094 | if (ret) { | 2108 | if (ret) |
| 2095 | es58x_dev->netdev[channel_idx] = NULL; | 2109 | goto devlink_port_unregister; |
| 2096 | free_candev(netdev); | ||
| 2097 | return ret; | ||
| 2098 | } | ||
| 2099 | 2110 | ||
| 2100 | netdev_queue_set_dql_min_limit(netdev_get_tx_queue(netdev, 0), | 2111 | netdev_queue_set_dql_min_limit(netdev_get_tx_queue(netdev, 0), |
| 2101 | es58x_dev->param->dql_min_limit); | 2112 | es58x_dev->param->dql_min_limit); |
| 2102 | 2113 | ||
| 2103 | return ret; | 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 | if (!netdev) | 2135 | if (!netdev) |
| 2118 | continue; | 2136 | continue; |
| 2119 | unregister_candev(netdev); | 2137 | unregister_candev(netdev); |
| 2138 | devlink_port_unregister(&es58x_priv(netdev)->devlink_port); | ||
| 2120 | es58x_dev->netdev[i] = NULL; | 2139 | es58x_dev->netdev[i] = NULL; |
| 2121 | free_candev(netdev); | 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 | * es58x_init_es58x_dev() - Initialize the ES58X device. | 2145 | * es58x_init_es58x_dev() - Initialize the ES58X device. |
| 2169 | * @intf: USB interface. | 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 | struct device *dev = &intf->dev; | 2155 | struct device *dev = &intf->dev; |
| 2179 | struct es58x_device *es58x_dev; | 2156 | struct es58x_device *es58x_dev; |
| 2157 | struct devlink *devlink; | ||
| 2180 | const struct es58x_parameters *param; | 2158 | const struct es58x_parameters *param; |
| 2181 | const struct es58x_operators *ops; | 2159 | const struct es58x_operators *ops; |
| 2182 | struct usb_device *udev = interface_to_usbdev(intf); | 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 | ops = &es581_4_ops; | 2177 | ops = &es581_4_ops; |
| 2200 | } | 2178 | } |
| 2201 | 2179 | ||
| 2202 | es58x_dev = devm_kzalloc(dev, es58x_sizeof_es58x_device(param), | 2180 | devlink = devlink_alloc(&es58x_dl_ops, es58x_sizeof_es58x_device(param), |
| 2203 | GFP_KERNEL); | 2181 | dev); |
| 2204 | if (!es58x_dev) | 2182 | if (!devlink) |
| 2205 | return ERR_PTR(-ENOMEM); | 2183 | return ERR_PTR(-ENOMEM); |
| 2206 | 2184 | ||
| 2185 | es58x_dev = devlink_priv(devlink); | ||
| 2207 | es58x_dev->param = param; | 2186 | es58x_dev->param = param; |
| 2208 | es58x_dev->ops = ops; | 2187 | es58x_dev->ops = ops; |
| 2209 | es58x_dev->dev = dev; | 2188 | es58x_dev->dev = dev; |
| @@ -2240,25 +2219,24 @@ static int es58x_probe(struct usb_interface *intf, · 30 unmodified lines | |||
| 2240 | const struct usb_device_id *id) | 2219 | const struct usb_device_id *id) |
| 2241 | { | 2220 | { |
| 2242 | struct es58x_device *es58x_dev; | 2221 | struct es58x_device *es58x_dev; |
| 2243 | int ch_idx, ret; | 2222 | int ch_idx; |
| 2244 | 2223 | ||
| 2245 | es58x_dev = es58x_init_es58x_dev(intf, id->driver_info); | 2224 | es58x_dev = es58x_init_es58x_dev(intf, id->driver_info); |
| 2246 | if (IS_ERR(es58x_dev)) | 2225 | if (IS_ERR(es58x_dev)) |
| 2247 | return PTR_ERR(es58x_dev); | 2226 | return PTR_ERR(es58x_dev); |
| 2248 | 2227 | ||
| 2249 | ret = es58x_get_product_info(es58x_dev); | 2228 | es58x_parse_product_info(es58x_dev); |
| 2250 | if (ret) | 2229 | devlink_register(priv_to_devlink(es58x_dev)); |
| 2251 | return ret; | ||
| 2252 | 2230 | ||
| 2253 | for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++) { | 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 | if (ret) { | 2233 | if (ret) { |
| 2256 | es58x_free_netdevs(es58x_dev); | 2234 | es58x_free_netdevs(es58x_dev); |
| 2257 | return ret; | 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 | dev_info(&intf->dev, "Disconnecting %s %s\n", | 2253 | dev_info(&intf->dev, "Disconnecting %s %s\n", |
| 2276 | es58x_dev->udev->manufacturer, es58x_dev->udev->product); | 2254 | es58x_dev->udev->manufacturer, es58x_dev->udev->product); |
| 2277 | 2255 | ||
| 2256 | devlink_unregister(priv_to_devlink(es58x_dev)); | ||
| 2278 | es58x_free_netdevs(es58x_dev); | 2257 | es58x_free_netdevs(es58x_dev); |
| 2279 | es58x_free_urbs(es58x_dev); | 2258 | es58x_free_urbs(es58x_dev); |
| 2259 | devlink_free(priv_to_devlink(es58x_dev)); | ||
| 2280 | usb_set_intfdata(intf, NULL); | 2260 | usb_set_intfdata(intf, NULL); |
| 2281 | } | 2261 | } |
| 2282 | 2262 | ||
| @@ -6,17 +6,18 @@ · 5 unmodified lines | |||
| 6 | * | 6 | * |
| 7 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. | 7 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 8 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. | 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 | #ifndef __ES58X_COMMON_H__ | 12 | #ifndef __ES58X_COMMON_H__ |
| 13 | #define __ES58X_COMMON_H__ | 13 | #define __ES58X_COMMON_H__ |
| 14 | 14 | ||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/usb.h> | ||
| 17 | #include <linux/netdevice.h> | ||
| 18 | #include <linux/can.h> | 15 | #include <linux/can.h> |
| 19 | #include <linux/can/dev.h> | 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 | #include "es581_4.h" | 22 | #include "es581_4.h" |
| 22 | #include "es58x_fd.h" | 23 | #include "es58x_fd.h" |
| @@ -230,6 +231,7 @@ union es58x_urb_cmd { · 207 unmodified lines | |||
| 230 | * @can: struct can_priv must be the first member (Socket CAN relies | 231 | * @can: struct can_priv must be the first member (Socket CAN relies |
| 231 | * on the fact that function netdev_priv() returns a pointer to | 232 | * on the fact that function netdev_priv() returns a pointer to |
| 232 | * a struct can_priv). | 233 | * a struct can_priv). |
| 234 | * @devlink_port: devlink instance for the network interface. | ||
| 233 | * @es58x_dev: pointer to the corresponding ES58X device. | 235 | * @es58x_dev: pointer to the corresponding ES58X device. |
| 234 | * @tx_urb: Used as a buffer to concatenate the TX messages and to do | 236 | * @tx_urb: Used as a buffer to concatenate the TX messages and to do |
| 235 | * a bulk send. Please refer to es58x_start_xmit() for more | 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 | struct es58x_priv { | 258 | struct es58x_priv { |
| 257 | struct can_priv can; | 259 | struct can_priv can; |
| 260 | struct devlink_port devlink_port; | ||
| 258 | struct es58x_device *es58x_dev; | 261 | struct es58x_device *es58x_dev; |
| 259 | struct urb *tx_urb; | 262 | struct urb *tx_urb; |
| 260 | 263 | ||
| @@ -356,6 +359,39 @@ struct es58x_operators { · 95 unmodified lines | |||
| 356 | int (*get_timestamp)(struct es58x_device *es58x_dev); | 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 | * struct es58x_device - All information specific to an ES58X device. | 396 | * struct es58x_device - All information specific to an ES58X device. |
| 361 | * @dev: Device information. | 397 | * @dev: Device information. |
| @@ -373,6 +409,9 @@ struct es58x_operators { · 11 unmodified lines | |||
| 373 | * queue wake/stop logic should prevent this URB from getting | 409 | * queue wake/stop logic should prevent this URB from getting |
| 374 | * empty. Please refer to es58x_get_tx_urb() for more details. | 410 | * empty. Please refer to es58x_get_tx_urb() for more details. |
| 375 | * @tx_urbs_idle_cnt: number of urbs in @tx_urbs_idle. | 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 | * @ktime_req_ns: kernel timestamp when es58x_set_realtime_diff_ns() | 415 | * @ktime_req_ns: kernel timestamp when es58x_set_realtime_diff_ns() |
| 377 | * was called. | 416 | * was called. |
| 378 | * @realtime_diff_ns: difference in nanoseconds between the clocks of | 417 | * @realtime_diff_ns: difference in nanoseconds between the clocks of |
| @@ -408,6 +447,10 @@ struct es58x_device { · 29 unmodified lines | |||
| 408 | struct usb_anchor tx_urbs_idle; | 447 | struct usb_anchor tx_urbs_idle; |
| 409 | atomic_t tx_urbs_idle_cnt; | 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 | u64 ktime_req_ns; | 454 | u64 ktime_req_ns; |
| 412 | s64 realtime_diff_ns; | 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 | return es58x_flags; | 717 | return es58x_flags; |
| 675 | } | 718 | } |
| 676 | 719 | ||
| 720 | /* es58x_core.c. */ | ||
| 677 | int es58x_can_get_echo_skb(struct net_device *netdev, u32 packet_idx, | 721 | int es58x_can_get_echo_skb(struct net_device *netdev, u32 packet_idx, |
| 678 | u64 *tstamps, unsigned int pkts); | 722 | u64 *tstamps, unsigned int pkts); |
| 679 | int es58x_tx_ack_msg(struct net_device *netdev, u16 tx_free_entries, | 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 | int es58x_send_msg(struct es58x_device *es58x_dev, u8 cmd_type, u8 cmd_id, | 735 | int es58x_send_msg(struct es58x_device *es58x_dev, u8 cmd_type, u8 cmd_id, |
| 692 | const void *msg, u16 cmd_len, int channel_idx); | 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 | extern const struct es58x_parameters es581_4_param; | 743 | extern const struct es58x_parameters es581_4_param; |
| 695 | extern const struct es58x_operators es581_4_ops; | 744 | extern const struct es58x_operators es581_4_ops; |
| 696 | 745 | ||
| 746 | /* es58x_fd.c. */ | ||
| 697 | extern const struct es58x_parameters es58x_fd_param; | 747 | extern const struct es58x_parameters es58x_fd_param; |
| 698 | extern const struct es58x_operators es58x_fd_ops; | 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 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. | 9 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 10 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. | 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 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/units.h> | 16 | #include <linux/units.h> |
| 16 | #include <asm/unaligned.h> | ||
| 17 | 17 | ||
| 18 | #include "es58x_core.h" | 18 | #include "es58x_core.h" |
| 19 | #include "es58x_fd.h" | 19 | #include "es58x_fd.h" |
| @@ -66,6 +66,7 @@ enum gs_usb_breq { · 65 unmodified lines | |||
| 66 | GS_USB_BREQ_BT_CONST_EXT, | 66 | GS_USB_BREQ_BT_CONST_EXT, |
| 67 | GS_USB_BREQ_SET_TERMINATION, | 67 | GS_USB_BREQ_SET_TERMINATION, |
| 68 | GS_USB_BREQ_GET_TERMINATION, | 68 | GS_USB_BREQ_GET_TERMINATION, |
| 69 | GS_USB_BREQ_GET_STATE, | ||
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 71 | enum gs_can_mode { | 72 | enum gs_can_mode { |
| @@ -134,6 +135,8 @@ struct gs_device_config { · 62 unmodified lines | |||
| 134 | /* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */ | 135 | /* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */ |
| 135 | /* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */ | 136 | /* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */ |
| 136 | /* GS_CAN_FEATURE_TERMINATION BIT(11) */ | 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 | struct gs_device_mode { | 141 | struct gs_device_mode { |
| 139 | __le32 mode; | 142 | __le32 mode; |
| @@ -174,7 +177,9 @@ struct gs_device_termination_state { · 34 unmodified lines | |||
| 174 | #define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) | 177 | #define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) |
| 175 | #define GS_CAN_FEATURE_BT_CONST_EXT BIT(10) | 178 | #define GS_CAN_FEATURE_BT_CONST_EXT BIT(10) |
| 176 | #define GS_CAN_FEATURE_TERMINATION BIT(11) | 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 | /* internal quirks - keep in GS_CAN_FEATURE space for now */ | 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 | struct net_device *netdev; | 300 | struct net_device *netdev; |
| 296 | struct usb_device *udev; | 301 | struct usb_device *udev; |
| 297 | struct usb_interface *iface; | ||
| 298 | 302 | ||
| 299 | struct can_bittiming_const bt_const, data_bt_const; | 303 | struct can_bittiming_const bt_const, data_bt_const; |
| 300 | unsigned int channel; /* channel number */ | 304 | unsigned int channel; /* channel number */ |
| @@ -378,8 +382,7 @@ static int gs_cmd_reset(struct gs_can *dev) · 77 unmodified lines | |||
| 378 | .mode = GS_CAN_MODE_RESET, | 382 | .mode = GS_CAN_MODE_RESET, |
| 379 | }; | 383 | }; |
| 380 | 384 | ||
| 381 | return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | 385 | return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_MODE, |
| 382 | GS_USB_BREQ_MODE, | ||
| 383 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 386 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 384 | dev->channel, 0, &dm, sizeof(dm), 1000, | 387 | dev->channel, 0, &dm, sizeof(dm), 1000, |
| 385 | GFP_KERNEL); | 388 | GFP_KERNEL); |
| @@ -391,8 +394,7 @@ static inline int gs_usb_get_timestamp(const struct gs_can *dev, · 5 unmodified lines | |||
| 391 | __le32 timestamp; | 394 | __le32 timestamp; |
| 392 | int rc; | 395 | int rc; |
| 393 | 396 | ||
| 394 | rc = usb_control_msg_recv(interface_to_usbdev(dev->iface), 0, | 397 | rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_TIMESTAMP, |
| 395 | GS_USB_BREQ_TIMESTAMP, | ||
| 396 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 398 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 397 | dev->channel, 0, | 399 | dev->channel, 0, |
| 398 | ×tamp, sizeof(timestamp), | 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 | /* request bit timings */ | 673 | /* request bit timings */ |
| 672 | return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | 674 | return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_BITTIMING, |
| 673 | GS_USB_BREQ_BITTIMING, | ||
| 674 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 675 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 675 | dev->channel, 0, &dbt, sizeof(dbt), 1000, | 676 | dev->channel, 0, &dbt, sizeof(dbt), 1000, |
| 676 | GFP_KERNEL); | 677 | GFP_KERNEL); |
| @@ -693,8 +694,7 @@ static int gs_usb_set_data_bittiming(struct net_device *netdev) · 16 unmodified lines | |||
| 693 | request = GS_USB_BREQ_QUIRK_CANTACT_PRO_DATA_BITTIMING; | 694 | request = GS_USB_BREQ_QUIRK_CANTACT_PRO_DATA_BITTIMING; |
| 694 | 695 | ||
| 695 | /* request data bit timings */ | 696 | /* request data bit timings */ |
| 696 | return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | 697 | return usb_control_msg_send(dev->udev, 0, request, |
| 697 | request, | ||
| 698 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 698 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 699 | dev->channel, 0, &dbt, sizeof(dbt), 1000, | 699 | dev->channel, 0, &dbt, sizeof(dbt), 1000, |
| 700 | GFP_KERNEL); | 700 | GFP_KERNEL); |
| @@ -843,8 +843,6 @@ static int gs_can_open(struct net_device *netdev) · 142 unmodified lines | |||
| 843 | 843 | ||
| 844 | ctrlmode = dev->can.ctrlmode; | 844 | ctrlmode = dev->can.ctrlmode; |
| 845 | if (ctrlmode & CAN_CTRLMODE_FD) { | 845 | if (ctrlmode & CAN_CTRLMODE_FD) { |
| 846 | flags |= GS_CAN_MODE_FD; | ||
| 847 | |||
| 848 | if (dev->feature & GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX) | 846 | if (dev->feature & GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX) |
| 849 | dev->hf_size_tx = struct_size(hf, canfd_quirk, 1); | 847 | dev->hf_size_tx = struct_size(hf, canfd_quirk, 1); |
| 850 | else | 848 | else |
| @@ -911,31 +909,34 @@ static int gs_can_open(struct net_device *netdev) · 60 unmodified lines | |||
| 911 | /* flags */ | 909 | /* flags */ |
| 912 | if (ctrlmode & CAN_CTRLMODE_LOOPBACK) | 910 | if (ctrlmode & CAN_CTRLMODE_LOOPBACK) |
| 913 | flags |= GS_CAN_MODE_LOOP_BACK; | 911 | flags |= GS_CAN_MODE_LOOP_BACK; |
| 914 | else if (ctrlmode & CAN_CTRLMODE_LISTENONLY) | 912 | |
| 913 | if (ctrlmode & CAN_CTRLMODE_LISTENONLY) | ||
| 915 | flags |= GS_CAN_MODE_LISTEN_ONLY; | 914 | flags |= GS_CAN_MODE_LISTEN_ONLY; |
| 916 | 915 | ||
| 917 | /* Controller is not allowed to retry TX | 916 | if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) |
| 918 | * this mode is unavailable on atmels uc3c hardware | 917 | flags |= GS_CAN_MODE_TRIPLE_SAMPLE; |
| 919 | */ | 918 | |
| 920 | if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) | 919 | if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) |
| 921 | flags |= GS_CAN_MODE_ONE_SHOT; | 920 | flags |= GS_CAN_MODE_ONE_SHOT; |
| 922 | 921 | ||
| 923 | if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) | 922 | if (ctrlmode & CAN_CTRLMODE_BERR_REPORTING) |
| 924 | flags |= GS_CAN_MODE_TRIPLE_SAMPLE; | 923 | flags |= GS_CAN_MODE_BERR_REPORTING; |
| 924 | |||
| 925 | if (ctrlmode & CAN_CTRLMODE_FD) | ||
| 926 | flags |= GS_CAN_MODE_FD; | ||
| 925 | 927 | ||
| 926 | /* if hardware supports timestamps, enable it */ | 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 | flags |= GS_CAN_MODE_HW_TIMESTAMP; | 930 | flags |= GS_CAN_MODE_HW_TIMESTAMP; |
| 929 | 931 | ||
| 930 | /* start polling timestamp */ | 932 | /* start polling timestamp */ |
| 931 | if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) | ||
| 932 | gs_usb_timestamp_init(dev); | 933 | gs_usb_timestamp_init(dev); |
| 934 | } | ||
| 933 | 935 | ||
| 934 | /* finally start device */ | 936 | /* finally start device */ |
| 935 | dev->can.state = CAN_STATE_ERROR_ACTIVE; | 937 | dev->can.state = CAN_STATE_ERROR_ACTIVE; |
| 936 | dm.flags = cpu_to_le32(flags); | 938 | dm.flags = cpu_to_le32(flags); |
| 937 | rc = usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | 939 | rc = usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_MODE, |
| 938 | GS_USB_BREQ_MODE, | ||
| 939 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 940 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 940 | dev->channel, 0, &dm, sizeof(dm), 1000, | 941 | dev->channel, 0, &dm, sizeof(dm), 1000, |
| 941 | GFP_KERNEL); | 942 | GFP_KERNEL); |
| @@ -954,6 +955,41 @@ static int gs_can_open(struct net_device *netdev) · 12 unmodified lines | |||
| 954 | return 0; | 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 | static int gs_can_close(struct net_device *netdev) | 993 | static int gs_can_close(struct net_device *netdev) |
| 958 | { | 994 | { |
| 959 | int rc; | 995 | int rc; |
| @@ -1021,8 +1057,7 @@ static int gs_usb_set_identify(struct net_device *netdev, bool do_identify) · 61 unmodified lines | |||
| 1021 | else | 1057 | else |
| 1022 | imode.mode = cpu_to_le32(GS_CAN_IDENTIFY_OFF); | 1058 | imode.mode = cpu_to_le32(GS_CAN_IDENTIFY_OFF); |
| 1023 | 1059 | ||
| 1024 | return usb_control_msg_send(interface_to_usbdev(dev->iface), 0, | 1060 | return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_IDENTIFY, |
| 1025 | GS_USB_BREQ_IDENTIFY, | ||
| 1026 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 1061 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 1027 | dev->channel, 0, &imode, sizeof(imode), 100, | 1062 | dev->channel, 0, &imode, sizeof(imode), 100, |
| 1028 | GFP_KERNEL); | 1063 | GFP_KERNEL); |
| @@ -1075,8 +1110,7 @@ static int gs_usb_get_termination(struct net_device *netdev, u16 *term) · 46 unmodified lines | |||
| 1075 | struct gs_device_termination_state term_state; | 1110 | struct gs_device_termination_state term_state; |
| 1076 | int rc; | 1111 | int rc; |
| 1077 | 1112 | ||
| 1078 | rc = usb_control_msg_recv(interface_to_usbdev(dev->iface), 0, | 1113 | rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_GET_TERMINATION, |
| 1079 | GS_USB_BREQ_GET_TERMINATION, | ||
| 1080 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 1114 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 1081 | dev->channel, 0, | 1115 | dev->channel, 0, |
| 1082 | &term_state, sizeof(term_state), 1000, | 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 | else | 1136 | else |
| 1103 | term_state.state = cpu_to_le32(GS_CAN_TERMINATION_STATE_OFF); | 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, | 1139 | return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_SET_TERMINATION, |
| 1106 | GS_USB_BREQ_SET_TERMINATION, | ||
| 1107 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | 1140 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
| 1108 | dev->channel, 0, | 1141 | dev->channel, 0, |
| 1109 | &term_state, sizeof(term_state), 1000, | 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 | netdev->ethtool_ops = &gs_usb_ethtool_ops; | 1186 | netdev->ethtool_ops = &gs_usb_ethtool_ops; |
| 1154 | 1187 | ||
| 1155 | netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ | 1188 | netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ |
| 1189 | netdev->dev_id = channel; | ||
| 1156 | 1190 | ||
| 1157 | /* dev setup */ | 1191 | /* dev setup */ |
| 1158 | strcpy(dev->bt_const.name, KBUILD_MODNAME); | 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 | dev->bt_const.brp_inc = le32_to_cpu(bt_const.brp_inc); | 1200 | dev->bt_const.brp_inc = le32_to_cpu(bt_const.brp_inc); |
| 1167 | 1201 | ||
| 1168 | dev->udev = interface_to_usbdev(intf); | 1202 | dev->udev = interface_to_usbdev(intf); |
| 1169 | dev->iface = intf; | ||
| 1170 | dev->netdev = netdev; | 1203 | dev->netdev = netdev; |
| 1171 | dev->channel = channel; | 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 | /* The CANtact Pro from LinkLayer Labs is based on the | 1266 | /* The CANtact Pro from LinkLayer Labs is based on the |
| 1228 | * LPC54616 µC, which is affected by the NXP LPC USB transfer | 1267 | * LPC54616 µC, which is affected by the NXP LPC USB transfer |
| 1229 | * erratum. However, the current firmware (version 2) doesn't | 1268 | * erratum. However, the current firmware (version 2) doesn't |
| @@ -1,8 +1,3 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o | 2 | obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o |
| 3 | kvaser_usb-y = kvaser_usb_core.o kvaser_usb_leaf.o kvaser_usb_hydra.o | 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 | u32 echo_index; | 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 | struct kvaser_usb { | 87 | struct kvaser_usb { |
| 80 | struct usb_device *udev; | 88 | struct usb_device *udev; |
| 81 | struct usb_interface *intf; | 89 | struct usb_interface *intf; |
| @@ -104,13 +112,19 @@ struct kvaser_usb_net_priv { · 22 unmodified lines | |||
| 104 | struct can_priv can; | 112 | struct can_priv can; |
| 105 | struct can_berr_counter bec; | 113 | struct can_berr_counter bec; |
| 106 | 114 | ||
| 115 | /* subdriver-specific data */ | ||
| 116 | void *sub_priv; | ||
| 117 | |||
| 107 | struct kvaser_usb *dev; | 118 | struct kvaser_usb *dev; |
| 108 | struct net_device *netdev; | 119 | struct net_device *netdev; |
| 109 | int channel; | 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 | struct usb_anchor tx_submitted; | 124 | struct usb_anchor tx_submitted; |
| 113 | 125 | ||
| 126 | struct kvaser_usb_busparams busparams_nominal, busparams_data; | ||
| 127 | |||
| 114 | spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */ | 128 | spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */ |
| 115 | int active_tx_contexts; | 129 | int active_tx_contexts; |
| 116 | struct kvaser_usb_tx_urb_context tx_contexts[]; | 130 | struct kvaser_usb_tx_urb_context tx_contexts[]; |
| @@ -120,11 +134,15 @@ struct kvaser_usb_net_priv { · 3 unmodified lines | |||
| 120 | * struct kvaser_usb_dev_ops - Device specific functions | 134 | * struct kvaser_usb_dev_ops - Device specific functions |
| 121 | * @dev_set_mode: used for can.do_set_mode | 135 | * @dev_set_mode: used for can.do_set_mode |
| 122 | * @dev_set_bittiming: used for can.do_set_bittiming | 136 | * @dev_set_bittiming: used for can.do_set_bittiming |
| 137 | * @dev_get_busparams: readback arbitration busparams | ||
| 123 | * @dev_set_data_bittiming: used for can.do_set_data_bittiming | 138 | * @dev_set_data_bittiming: used for can.do_set_data_bittiming |
| 139 | * @dev_get_data_busparams: readback data busparams | ||
| 124 | * @dev_get_berr_counter: used for can.do_get_berr_counter | 140 | * @dev_get_berr_counter: used for can.do_get_berr_counter |
| 125 | * | 141 | * |
| 126 | * @dev_setup_endpoints: setup USB in and out endpoints | 142 | * @dev_setup_endpoints: setup USB in and out endpoints |
| 127 | * @dev_init_card: initialize card | 143 | * @dev_init_card: initialize card |
| 144 | * @dev_init_channel: initialize channel | ||
| 145 | * @dev_remove_channel: uninitialize channel | ||
| 128 | * @dev_get_software_info: get software info | 146 | * @dev_get_software_info: get software info |
| 129 | * @dev_get_software_details: get software details | 147 | * @dev_get_software_details: get software details |
| 130 | * @dev_get_card_info: get card info | 148 | * @dev_get_card_info: get card info |
| @@ -140,12 +158,18 @@ struct kvaser_usb_net_priv { · 9 unmodified lines | |||
| 140 | */ | 158 | */ |
| 141 | struct kvaser_usb_dev_ops { | 159 | struct kvaser_usb_dev_ops { |
| 142 | int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode); | 160 | int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode); |
| 143 | int (*dev_set_bittiming)(struct net_device *netdev); | 161 | int (*dev_set_bittiming)(const struct net_device *netdev, |
| 144 | int (*dev_set_data_bittiming)(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 | int (*dev_get_berr_counter)(const struct net_device *netdev, | 167 | int (*dev_get_berr_counter)(const struct net_device *netdev, |
| 146 | struct can_berr_counter *bec); | 168 | struct can_berr_counter *bec); |
| 147 | int (*dev_setup_endpoints)(struct kvaser_usb *dev); | 169 | int (*dev_setup_endpoints)(struct kvaser_usb *dev); |
| 148 | int (*dev_init_card)(struct kvaser_usb *dev); | 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 | int (*dev_get_software_info)(struct kvaser_usb *dev); | 173 | int (*dev_get_software_info)(struct kvaser_usb *dev); |
| 150 | int (*dev_get_software_details)(struct kvaser_usb *dev); | 174 | int (*dev_get_software_details)(struct kvaser_usb *dev); |
| 151 | int (*dev_get_card_info)(struct kvaser_usb *dev); | 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 | if (err) | 440 | if (err) |
| 441 | return err; | 441 | return err; |
| 442 | 442 | ||
| 443 | err = kvaser_usb_setup_rx_urbs(dev); | ||
| 444 | if (err) | ||
| 445 | goto error; | ||
| 446 | |||
| 447 | err = ops->dev_set_opt_mode(priv); | 443 | err = ops->dev_set_opt_mode(priv); |
| 448 | if (err) | 444 | if (err) |
| 449 | goto error; | 445 | goto error; |
| @@ -534,6 +530,91 @@ static int kvaser_usb_close(struct net_device *netdev) · 84 unmodified lines | |||
| 534 | return 0; | 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 | static void kvaser_usb_write_bulk_callback(struct urb *urb) | 618 | static void kvaser_usb_write_bulk_callback(struct urb *urb) |
| 538 | { | 619 | { |
| 539 | struct kvaser_usb_tx_urb_context *context = urb->context; | 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 | static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) | 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 | int i; | 769 | int i; |
| 688 | 770 | ||
| 689 | for (i = 0; i < dev->nchannels; i++) { | 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 | if (!dev->nets[i]) | 781 | if (!dev->nets[i]) |
| 700 | continue; | 782 | continue; |
| 701 | 783 | ||
| 784 | if (ops->dev_remove_channel) | ||
| 785 | ops->dev_remove_channel(dev->nets[i]); | ||
| 786 | |||
| 702 | free_candev(dev->nets[i]->netdev); | 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 | init_completion(&priv->start_comp); | 815 | init_completion(&priv->start_comp); |
| 731 | init_completion(&priv->stop_comp); | 816 | init_completion(&priv->stop_comp); |
| 732 | init_completion(&priv->flush_comp); | 817 | init_completion(&priv->flush_comp); |
| 818 | init_completion(&priv->get_busparams_comp); | ||
| 733 | priv->can.ctrlmode_supported = 0; | 819 | priv->can.ctrlmode_supported = 0; |
| 734 | 820 | ||
| 735 | priv->dev = dev; | 821 | priv->dev = dev; |
| @@ -742,7 +828,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) · 6 unmodified lines | |||
| 742 | priv->can.state = CAN_STATE_STOPPED; | 828 | priv->can.state = CAN_STATE_STOPPED; |
| 743 | priv->can.clock.freq = dev->cfg->clock.freq; | 829 | priv->can.clock.freq = dev->cfg->clock.freq; |
| 744 | priv->can.bittiming_const = dev->cfg->bittiming_const; | 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 | priv->can.do_set_mode = ops->dev_set_mode; | 832 | priv->can.do_set_mode = ops->dev_set_mode; |
| 747 | if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) || | 833 | if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) || |
| 748 | (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP)) | 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 | if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { | 841 | if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { |
| 756 | priv->can.data_bittiming_const = dev->cfg->data_bittiming_const; | 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 | netdev->flags |= IFF_ECHO; | 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 | dev->nets[channel] = priv; | 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 | err = register_candev(netdev); | 867 | err = register_candev(netdev); |
| 776 | if (err) { | 868 | if (err) { |
| 777 | dev_err(&dev->intf->dev, "Failed to register CAN device\n"); | 869 | dev_err(&dev->intf->dev, "Failed to register CAN device\n"); |
| 778 | free_candev(netdev); | 870 | goto err; |
| 779 | dev->nets[channel] = NULL; | ||
| 780 | return err; | ||
| 781 | } | 871 | } |
| 782 | 872 | ||
| 783 | netdev_dbg(netdev, "device registered\n"); | 873 | netdev_dbg(netdev, "device registered\n"); |
| 784 | 874 | ||
| 785 | return 0; | 875 | return 0; |
| 876 | |||
| 877 | err: | ||
| 878 | free_candev(netdev); | ||
| 879 | dev->nets[channel] = NULL; | ||
| 880 | return err; | ||
| 786 | } | 881 | } |
| 787 | 882 | ||
| 788 | static int kvaser_usb_probe(struct usb_interface *intf, | 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 | /* Minihydra command IDs */ | 46 | /* Minihydra command IDs */ |
| 47 | #define CMD_SET_BUSPARAMS_REQ 16 | 47 | #define CMD_SET_BUSPARAMS_REQ 16 |
| 48 | #define CMD_GET_BUSPARAMS_REQ 17 | ||
| 49 | #define CMD_GET_BUSPARAMS_RESP 18 | ||
| 48 | #define CMD_GET_CHIP_STATE_REQ 19 | 50 | #define CMD_GET_CHIP_STATE_REQ 19 |
| 49 | #define CMD_CHIP_STATE_EVENT 20 | 51 | #define CMD_CHIP_STATE_EVENT 20 |
| 50 | #define CMD_SET_DRIVERMODE_REQ 21 | 52 | #define CMD_SET_DRIVERMODE_REQ 21 |
| @@ -196,21 +198,26 @@ struct kvaser_cmd_chip_state_event { · 145 unmodified lines | |||
| 196 | #define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO 0x01 | 198 | #define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO 0x01 |
| 197 | #define KVASER_USB_HYDRA_BUS_MODE_NONISO 0x02 | 199 | #define KVASER_USB_HYDRA_BUS_MODE_NONISO 0x02 |
| 198 | struct kvaser_cmd_set_busparams { | 200 | struct kvaser_cmd_set_busparams { |
| 199 | __le32 bitrate; | 201 | struct kvaser_usb_busparams busparams_nominal; |
| 200 | u8 tseg1; | ||
| 201 | u8 tseg2; | ||
| 202 | u8 sjw; | ||
| 203 | u8 nsamples; | ||
| 204 | u8 reserved0[4]; | 202 | u8 reserved0[4]; |
| 205 | __le32 bitrate_d; | 203 | struct kvaser_usb_busparams busparams_data; |
| 206 | u8 tseg1_d; | ||
| 207 | u8 tseg2_d; | ||
| 208 | u8 sjw_d; | ||
| 209 | u8 nsamples_d; | ||
| 210 | u8 canfd_mode; | 204 | u8 canfd_mode; |
| 211 | u8 reserved1[7]; | 205 | u8 reserved1[7]; |
| 212 | } __packed; | 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 | /* Ctrl modes */ | 221 | /* Ctrl modes */ |
| 215 | #define KVASER_USB_HYDRA_CTRLMODE_NORMAL 0x01 | 222 | #define KVASER_USB_HYDRA_CTRLMODE_NORMAL 0x01 |
| 216 | #define KVASER_USB_HYDRA_CTRLMODE_LISTEN 0x02 | 223 | #define KVASER_USB_HYDRA_CTRLMODE_LISTEN 0x02 |
| @@ -281,6 +288,8 @@ struct kvaser_cmd { · 64 unmodified lines | |||
| 281 | struct kvaser_cmd_error_event error_event; | 288 | struct kvaser_cmd_error_event error_event; |
| 282 | 289 | ||
| 283 | struct kvaser_cmd_set_busparams set_busparams_req; | 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 | struct kvaser_cmd_chip_state_event chip_state_event; | 294 | struct kvaser_cmd_chip_state_event chip_state_event; |
| 286 | 295 | ||
| @@ -363,6 +372,10 @@ struct kvaser_cmd_ext { · 76 unmodified lines | |||
| 363 | } __packed; | 372 | } __packed; |
| 364 | } __packed; | 373 | } __packed; |
| 365 | 374 | ||
| 375 | struct kvaser_usb_net_hydra_priv { | ||
| 376 | int pending_get_busparams_type; | ||
| 377 | }; | ||
| 378 | |||
| 366 | static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = { | 379 | static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = { |
| 367 | .name = "kvaser_usb_kcan", | 380 | .name = "kvaser_usb_kcan", |
| 368 | .tseg1_min = 1, | 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 | complete(&priv->flush_comp); | 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 | static void | 889 | static void |
| 844 | kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv, | 890 | kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv, |
| 845 | u8 bus_status, | 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 | kvaser_usb_hydra_state_event(dev, cmd); | 1372 | kvaser_usb_hydra_state_event(dev, cmd); |
| 1327 | break; | 1373 | break; |
| 1328 | 1374 | ||
| 1375 | case CMD_GET_BUSPARAMS_RESP: | ||
| 1376 | kvaser_usb_hydra_get_busparams_reply(dev, cmd); | ||
| 1377 | break; | ||
| 1378 | |||
| 1329 | case CMD_ERROR_EVENT: | 1379 | case CMD_ERROR_EVENT: |
| 1330 | kvaser_usb_hydra_error_event(dev, cmd); | 1380 | kvaser_usb_hydra_error_event(dev, cmd); |
| 1331 | break; | 1381 | break; |
| @@ -1522,15 +1572,58 @@ static int kvaser_usb_hydra_set_mode(struct net_device *netdev, · 190 unmodified lines | |||
| 1522 | return err; | 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 | struct kvaser_cmd *cmd; | 1624 | struct kvaser_cmd *cmd; |
| 1528 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); | 1625 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1529 | struct can_bittiming *bt = &priv->can.bittiming; | ||
| 1530 | struct kvaser_usb *dev = priv->dev; | 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 | int err; | 1627 | int err; |
| 1535 | 1628 | ||
| 1536 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 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 | return -ENOMEM; | 1631 | return -ENOMEM; |
| 1539 | 1632 | ||
| 1540 | cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ; | 1633 | cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ; |
| 1541 | cmd->set_busparams_req.bitrate = cpu_to_le32(bt->bitrate); | 1634 | memcpy(&cmd->set_busparams_req.busparams_nominal, busparams, |
| 1542 | cmd->set_busparams_req.sjw = (u8)sjw; | 1635 | sizeof(cmd->set_busparams_req.busparams_nominal)); |
| 1543 | cmd->set_busparams_req.tseg1 = (u8)tseg1; | ||
| 1544 | cmd->set_busparams_req.tseg2 = (u8)tseg2; | ||
| 1545 | cmd->set_busparams_req.nsamples = 1; | ||
| 1546 | 1636 | ||
| 1547 | kvaser_usb_hydra_set_cmd_dest_he | 1637 | kvaser_usb_hydra_set_cmd_dest_he |
| 1548 | (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); | 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 | return err; | 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 | struct kvaser_cmd *cmd; | 1652 | struct kvaser_cmd *cmd; |
| 1562 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); | 1653 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1563 | struct can_bittiming *dbt = &priv->can.data_bittiming; | ||
| 1564 | struct kvaser_usb *dev = priv->dev; | 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 | int err; | 1655 | int err; |
| 1569 | 1656 | ||
| 1570 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 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 | return -ENOMEM; | 1659 | return -ENOMEM; |
| 1573 | 1660 | ||
| 1574 | cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ; | 1661 | cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ; |
| 1575 | cmd->set_busparams_req.bitrate_d = cpu_to_le32(dbt->bitrate); | 1662 | memcpy(&cmd->set_busparams_req.busparams_data, busparams, |
| 1576 | cmd->set_busparams_req.sjw_d = (u8)sjw; | 1663 | sizeof(cmd->set_busparams_req.busparams_data)); |
| 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; | ||
| 1580 | 1664 | ||
| 1581 | if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { | 1665 | if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { |
| 1582 | if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) | 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 | return 0; | 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 | static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev) | 1783 | static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev) |
| 1687 | { | 1784 | { |
| 1688 | struct kvaser_cmd cmd; | 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 | const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = { | 2124 | const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = { |
| 2028 | .dev_set_mode = kvaser_usb_hydra_set_mode, | 2125 | .dev_set_mode = kvaser_usb_hydra_set_mode, |
| 2029 | .dev_set_bittiming = kvaser_usb_hydra_set_bittiming, | 2126 | .dev_set_bittiming = kvaser_usb_hydra_set_bittiming, |
| 2127 | .dev_get_busparams = kvaser_usb_hydra_get_nominal_busparams, | ||
| 2030 | .dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming, | 2128 | .dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming, |
| 2129 | .dev_get_data_busparams = kvaser_usb_hydra_get_data_busparams, | ||
| 2031 | .dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter, | 2130 | .dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter, |
| 2032 | .dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints, | 2131 | .dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints, |
| 2033 | .dev_init_card = kvaser_usb_hydra_init_card, | 2132 | .dev_init_card = kvaser_usb_hydra_init_card, |
| 2133 | .dev_init_channel = kvaser_usb_hydra_init_channel, | ||
| 2034 | .dev_get_software_info = kvaser_usb_hydra_get_software_info, | 2134 | .dev_get_software_info = kvaser_usb_hydra_get_software_info, |
| 2035 | .dev_get_software_details = kvaser_usb_hydra_get_software_details, | 2135 | .dev_get_software_details = kvaser_usb_hydra_get_software_details, |
| 2036 | .dev_get_card_info = kvaser_usb_hydra_get_card_info, | 2136 | .dev_get_card_info = kvaser_usb_hydra_get_card_info, |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| 22 | #include <linux/units.h> | 22 | #include <linux/units.h> |
| 23 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
| 24 | #include <linux/workqueue.h> | ||
| 24 | 25 | ||
| 25 | #include <linux/can.h> | 26 | #include <linux/can.h> |
| 26 | #include <linux/can/dev.h> | 27 | #include <linux/can/dev.h> |
| @@ -56,6 +57,9 @@ · 29 unmodified lines | |||
| 56 | #define CMD_RX_EXT_MESSAGE 14 | 57 | #define CMD_RX_EXT_MESSAGE 14 |
| 57 | #define CMD_TX_EXT_MESSAGE 15 | 58 | #define CMD_TX_EXT_MESSAGE 15 |
| 58 | #define CMD_SET_BUS_PARAMS 16 | 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 | #define CMD_CHIP_STATE_EVENT 20 | 63 | #define CMD_CHIP_STATE_EVENT 20 |
| 60 | #define CMD_SET_CTRL_MODE 21 | 64 | #define CMD_SET_CTRL_MODE 21 |
| 61 | #define CMD_RESET_CHIP 24 | 65 | #define CMD_RESET_CHIP 24 |
| @@ -70,10 +74,13 @@ · 8 unmodified lines | |||
| 70 | #define CMD_GET_CARD_INFO_REPLY 35 | 74 | #define CMD_GET_CARD_INFO_REPLY 35 |
| 71 | #define CMD_GET_SOFTWARE_INFO 38 | 75 | #define CMD_GET_SOFTWARE_INFO 38 |
| 72 | #define CMD_GET_SOFTWARE_INFO_REPLY 39 | 76 | #define CMD_GET_SOFTWARE_INFO_REPLY 39 |
| 77 | #define CMD_ERROR_EVENT 45 | ||
| 73 | #define CMD_FLUSH_QUEUE 48 | 78 | #define CMD_FLUSH_QUEUE 48 |
| 74 | #define CMD_TX_ACKNOWLEDGE 50 | 79 | #define CMD_TX_ACKNOWLEDGE 50 |
| 75 | #define CMD_CAN_ERROR_EVENT 51 | 80 | #define CMD_CAN_ERROR_EVENT 51 |
| 76 | #define CMD_FLUSH_QUEUE_REPLY 68 | 81 | #define CMD_FLUSH_QUEUE_REPLY 68 |
| 82 | #define CMD_GET_CAPABILITIES_REQ 95 | ||
| 83 | #define CMD_GET_CAPABILITIES_RESP 96 | ||
| 77 | 84 | ||
| 78 | #define CMD_LEAF_LOG_MESSAGE 106 | 85 | #define CMD_LEAF_LOG_MESSAGE 106 |
| 79 | 86 | ||
| @@ -83,6 +90,8 @@ · 3 unmodified lines | |||
| 83 | #define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5) | 90 | #define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5) |
| 84 | #define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6) | 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 | /* error factors */ | 95 | /* error factors */ |
| 87 | #define M16C_EF_ACKE BIT(0) | 96 | #define M16C_EF_ACKE BIT(0) |
| 88 | #define M16C_EF_CRCE BIT(1) | 97 | #define M16C_EF_CRCE BIT(1) |
| @@ -157,11 +166,7 @@ struct usbcan_cmd_softinfo { · 68 unmodified lines | |||
| 157 | struct kvaser_cmd_busparams { | 166 | struct kvaser_cmd_busparams { |
| 158 | u8 tid; | 167 | u8 tid; |
| 159 | u8 channel; | 168 | u8 channel; |
| 160 | __le32 bitrate; | 169 | struct kvaser_usb_busparams busparams; |
| 161 | u8 tseg1; | ||
| 162 | u8 tseg2; | ||
| 163 | u8 sjw; | ||
| 164 | u8 no_samp; | ||
| 165 | } __packed; | 170 | } __packed; |
| 166 | 171 | ||
| 167 | struct kvaser_cmd_tx_can { | 172 | struct kvaser_cmd_tx_can { |
| @@ -230,7 +235,7 @@ struct kvaser_cmd_tx_acknowledge_header { · 62 unmodified lines | |||
| 230 | u8 tid; | 235 | u8 tid; |
| 231 | } __packed; | 236 | } __packed; |
| 232 | 237 | ||
| 233 | struct leaf_cmd_error_event { | 238 | struct leaf_cmd_can_error_event { |
| 234 | u8 tid; | 239 | u8 tid; |
| 235 | u8 flags; | 240 | u8 flags; |
| 236 | __le16 time[3]; | 241 | __le16 time[3]; |
| @@ -242,7 +247,7 @@ struct leaf_cmd_error_event { · 5 unmodified lines | |||
| 242 | u8 error_factor; | 247 | u8 error_factor; |
| 243 | } __packed; | 248 | } __packed; |
| 244 | 249 | ||
| 245 | struct usbcan_cmd_error_event { | 250 | struct usbcan_cmd_can_error_event { |
| 246 | u8 tid; | 251 | u8 tid; |
| 247 | u8 padding; | 252 | u8 padding; |
| 248 | u8 tx_errors_count_ch0; | 253 | u8 tx_errors_count_ch0; |
| @@ -254,6 +259,28 @@ struct usbcan_cmd_error_event { · 5 unmodified lines | |||
| 254 | __le16 time; | 259 | __le16 time; |
| 255 | } __packed; | 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 | struct kvaser_cmd_ctrl_mode { | 284 | struct kvaser_cmd_ctrl_mode { |
| 258 | u8 tid; | 285 | u8 tid; |
| 259 | u8 channel; | 286 | u8 channel; |
| @@ -278,6 +305,28 @@ struct leaf_cmd_log_message { · 18 unmodified lines | |||
| 278 | u8 data[8]; | 305 | u8 data[8]; |
| 279 | } __packed; | 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 | struct kvaser_cmd { | 330 | struct kvaser_cmd { |
| 282 | u8 len; | 331 | u8 len; |
| 283 | u8 id; | 332 | u8 id; |
| @@ -293,14 +342,18 @@ struct kvaser_cmd { · 9 unmodified lines | |||
| 293 | struct leaf_cmd_softinfo softinfo; | 342 | struct leaf_cmd_softinfo softinfo; |
| 294 | struct leaf_cmd_rx_can rx_can; | 343 | struct leaf_cmd_rx_can rx_can; |
| 295 | struct leaf_cmd_chip_state_event chip_state_event; | 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 | struct leaf_cmd_log_message log_message; | 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 | } __packed leaf; | 350 | } __packed leaf; |
| 299 | 351 | ||
| 300 | union { | 352 | union { |
| 301 | struct usbcan_cmd_softinfo softinfo; | 353 | struct usbcan_cmd_softinfo softinfo; |
| 302 | struct usbcan_cmd_rx_can rx_can; | 354 | struct usbcan_cmd_rx_can rx_can; |
| 303 | struct usbcan_cmd_chip_state_event chip_state_event; | 355 | struct usbcan_cmd_chip_state_event chip_state_event; |
| 356 | struct usbcan_cmd_can_error_event can_error_event; | ||
| 304 | struct usbcan_cmd_error_event error_event; | 357 | struct usbcan_cmd_error_event error_event; |
| 305 | } __packed usbcan; | 358 | } __packed usbcan; |
| 306 | 359 | ||
| @@ -323,7 +376,10 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = { · 16 unmodified lines | |||
| 323 | [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can), | 376 | [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can), |
| 324 | [CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message), | 377 | [CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message), |
| 325 | [CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event), | 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 | /* ignored events: */ | 383 | /* ignored events: */ |
| 328 | [CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY, | 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 | [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), | 393 | [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), |
| 338 | [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), | 394 | [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), |
| 339 | [CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event), | 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 | /* ignored events: */ | 398 | /* ignored events: */ |
| 342 | [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY, | 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 | static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = { | 434 | static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = { |
| 369 | .name = "kvaser_usb_ucii", | 435 | .name = "kvaser_usb_ucii", |
| 370 | .tseg1_min = 4, | 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 | dev->fw_version = le32_to_cpu(softinfo->fw_version); | 672 | dev->fw_version = le32_to_cpu(softinfo->fw_version); |
| 607 | dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx); | 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 | if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) { | 678 | if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) { |
| 610 | /* Firmware expects bittiming parameters calculated for 16MHz | 679 | /* Firmware expects bittiming parameters calculated for 16MHz |
| 611 | * clock, regardless of the actual clock | 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 | return 0; | 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 | static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev, | 875 | static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev, |
| 697 | const struct kvaser_cmd *cmd) | 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 | context = &priv->tx_contexts[tid % dev->max_tx_urbs]; | 900 | context = &priv->tx_contexts[tid % dev->max_tx_urbs]; |
| 722 | 901 | ||
| 723 | /* Sometimes the state change doesn't come after a bus-off event */ | 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 | struct sk_buff *skb; | 904 | struct sk_buff *skb; |
| 726 | struct can_frame *cf; | 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 | return err; | 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 | static void | 966 | static void |
| 778 | kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, | 967 | kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, |
| 779 | const struct kvaser_usb_err_summary *es, | 968 | const struct kvaser_usb_err_summary *es, |
| 780 | struct can_frame *cf) | 969 | struct can_frame *cf) |
| 781 | { | 970 | { |
| 971 | struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | ||
| 782 | struct kvaser_usb *dev = priv->dev; | 972 | struct kvaser_usb *dev = priv->dev; |
| 783 | struct net_device_stats *stats = &priv->netdev->stats; | 973 | struct net_device_stats *stats = &priv->netdev->stats; |
| 784 | enum can_state cur_state, new_state, tx_state, rx_state; | 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 | new_state = CAN_STATE_BUS_OFF; | 982 | new_state = CAN_STATE_BUS_OFF; |
| 793 | } else if (es->status & M16C_STATE_BUS_PASSIVE) { | 983 | } else if (es->status & M16C_STATE_BUS_PASSIVE) { |
| 794 | new_state = CAN_STATE_ERROR_PASSIVE; | 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 | /* Guard against spurious error events after a busoff */ | 987 | /* Guard against spurious error events after a busoff */ |
| 797 | if (cur_state < CAN_STATE_BUS_OFF) { | 988 | } else if (es->txerr >= 128 || es->rxerr >= 128) { |
| 798 | if (es->txerr >= 128 || es->rxerr >= 128) | 989 | new_state = CAN_STATE_ERROR_PASSIVE; |
| 799 | new_state = CAN_STATE_ERROR_PASSIVE; | 990 | } else if (es->txerr >= 96 || es->rxerr >= 96) { |
| 800 | else if (es->txerr >= 96 || es->rxerr >= 96) | 991 | new_state = CAN_STATE_ERROR_WARNING; |
| 801 | new_state = CAN_STATE_ERROR_WARNING; | 992 | } else { |
| 802 | else if (cur_state > CAN_STATE_ERROR_ACTIVE) | 993 | new_state = CAN_STATE_ERROR_ACTIVE; |
| 803 | new_state = CAN_STATE_ERROR_ACTIVE; | ||
| 804 | } | ||
| 805 | } | 994 | } |
| 806 | 995 | ||
| 807 | if (!es->status) | 996 | /* 0bfd:0124 FW 4.18.778 was observed to send the initial |
| 808 | new_state = CAN_STATE_ERROR_ACTIVE; | 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 | if (new_state != cur_state) { | 1012 | if (new_state != cur_state) { |
| 811 | tx_state = (es->txerr >= es->rxerr) ? new_state : 0; | 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 | if (priv->can.restart_ms && | 1019 | if (priv->can.restart_ms && |
| 818 | cur_state >= CAN_STATE_BUS_OFF && | 1020 | cur_state == CAN_STATE_BUS_OFF && |
| 819 | new_state < CAN_STATE_BUS_OFF) | 1021 | new_state < CAN_STATE_BUS_OFF) |
| 820 | priv->can.can_stats.restarts++; | 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 | struct sk_buff *skb; | 1051 | struct sk_buff *skb; |
| 850 | struct net_device_stats *stats; | 1052 | struct net_device_stats *stats; |
| 851 | struct kvaser_usb_net_priv *priv; | 1053 | struct kvaser_usb_net_priv *priv; |
| 1054 | struct kvaser_usb_net_leaf_priv *leaf; | ||
| 852 | enum can_state old_state, new_state; | 1055 | enum can_state old_state, new_state; |
| 853 | 1056 | ||
| 854 | if (es->channel >= dev->nchannels) { | 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 | priv = dev->nets[es->channel]; | 1063 | priv = dev->nets[es->channel]; |
| 1064 | leaf = priv->sub_priv; | ||
| 861 | stats = &priv->netdev->stats; | 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 | /* Update all of the CAN interface's state and error counters before | 1071 | /* Update all of the CAN interface's state and error counters before |
| 864 | * trying any memory allocation that can actually fail with -ENOMEM. | 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 | kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf); | 1082 | kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf); |
| 875 | new_state = priv->can.state; | 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 | skb = alloc_can_err_skb(priv->netdev, &cf); | 1096 | skb = alloc_can_err_skb(priv->netdev, &cf); |
| 878 | if (!skb) { | 1097 | if (!skb) { |
| 879 | stats->rx_dropped++; | 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 | if (priv->can.restart_ms && | 1112 | if (priv->can.restart_ms && |
| 894 | old_state >= CAN_STATE_BUS_OFF && | 1113 | old_state == CAN_STATE_BUS_OFF && |
| 895 | new_state < CAN_STATE_BUS_OFF) { | 1114 | new_state < CAN_STATE_BUS_OFF) { |
| 896 | cf->can_id |= CAN_ERR_RESTARTED; | 1115 | cf->can_id |= CAN_ERR_RESTARTED; |
| 897 | netif_carrier_on(priv->netdev); | 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 | case CMD_CAN_ERROR_EVENT: | 1210 | case CMD_CAN_ERROR_EVENT: |
| 992 | es.channel = 0; | 1211 | es.channel = 0; |
| 993 | es.status = cmd->u.usbcan.error_event.status_ch0; | 1212 | es.status = cmd->u.usbcan.can_error_event.status_ch0; |
| 994 | es.txerr = cmd->u.usbcan.error_event.tx_errors_count_ch0; | 1213 | es.txerr = cmd->u.usbcan.can_error_event.tx_errors_count_ch0; |
| 995 | es.rxerr = cmd->u.usbcan.error_event.rx_errors_count_ch0; | 1214 | es.rxerr = cmd->u.usbcan.can_error_event.rx_errors_count_ch0; |
| 996 | es.usbcan.other_ch_status = | 1215 | es.usbcan.other_ch_status = |
| 997 | cmd->u.usbcan.error_event.status_ch1; | 1216 | cmd->u.usbcan.can_error_event.status_ch1; |
| 998 | kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es); | 1217 | kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es); |
| 999 | 1218 | ||
| 1000 | /* The USBCAN firmware supports up to 2 channels. | 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 | if (dev->nchannels == MAX_USBCAN_NET_DEVICES) { | 1222 | if (dev->nchannels == MAX_USBCAN_NET_DEVICES) { |
| 1004 | es.channel = 1; | 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 | es.txerr = | 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 | es.rxerr = | 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 | es.usbcan.other_ch_status = | 1229 | es.usbcan.other_ch_status = |
| 1011 | cmd->u.usbcan.error_event.status_ch0; | 1230 | cmd->u.usbcan.can_error_event.status_ch0; |
| 1012 | kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es); | 1231 | kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es); |
| 1013 | } | 1232 | } |
| 1014 | break; | 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 | switch (cmd->id) { | 1245 | switch (cmd->id) { |
| 1027 | case CMD_CAN_ERROR_EVENT: | 1246 | case CMD_CAN_ERROR_EVENT: |
| 1028 | es.channel = cmd->u.leaf.error_event.channel; | 1247 | es.channel = cmd->u.leaf.can_error_event.channel; |
| 1029 | es.status = cmd->u.leaf.error_event.status; | 1248 | es.status = cmd->u.leaf.can_error_event.status; |
| 1030 | es.txerr = cmd->u.leaf.error_event.tx_errors_count; | 1249 | es.txerr = cmd->u.leaf.can_error_event.tx_errors_count; |
| 1031 | es.rxerr = cmd->u.leaf.error_event.rx_errors_count; | 1250 | es.rxerr = cmd->u.leaf.can_error_event.rx_errors_count; |
| 1032 | es.leaf.error_factor = cmd->u.leaf.error_event.error_factor; | 1251 | es.leaf.error_factor = cmd->u.leaf.can_error_event.error_factor; |
| 1033 | break; | 1252 | break; |
| 1034 | case CMD_LEAF_LOG_MESSAGE: | 1253 | case CMD_LEAF_LOG_MESSAGE: |
| 1035 | es.channel = cmd->u.leaf.log_message.channel; | 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 | netif_rx(skb); | 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 | static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev, | 1452 | static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev, |
| 1166 | const struct kvaser_cmd *cmd) | 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 | complete(&priv->stop_comp); | 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 | static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev, | 1511 | static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev, |
| 1206 | const struct kvaser_cmd *cmd) | 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 | kvaser_usb_leaf_tx_acknowledge(dev, cmd); | 1546 | kvaser_usb_leaf_tx_acknowledge(dev, cmd); |
| 1241 | break; | 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 | /* Ignored commands */ | 1557 | /* Ignored commands */ |
| 1244 | case CMD_USBCAN_CLOCK_OVERFLOW_EVENT: | 1558 | case CMD_USBCAN_CLOCK_OVERFLOW_EVENT: |
| 1245 | if (dev->driver_info->family != KVASER_USBCAN) | 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 | static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv) | 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 | int err; | 1636 | int err; |
| 1322 | 1637 | ||
| 1638 | leaf->joining_bus = true; | ||
| 1639 | |||
| 1323 | reinit_completion(&priv->start_comp); | 1640 | reinit_completion(&priv->start_comp); |
| 1324 | 1641 | ||
| 1325 | err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP, | 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 | static int kvaser_usb_leaf_stop_chip(struct kvaser_usb_net_priv *priv) | 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 | int err; | 1657 | int err; |
| 1340 | 1658 | ||
| 1341 | reinit_completion(&priv->stop_comp); | 1659 | reinit_completion(&priv->stop_comp); |
| 1342 | 1660 | ||
| 1661 | cancel_delayed_work(&leaf->chip_state_req_work); | ||
| 1662 | |||
| 1343 | err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_STOP_CHIP, | 1663 | err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_STOP_CHIP, |
| 1344 | priv->channel); | 1664 | priv->channel); |
| 1345 | if (err) | 1665 | if (err) |
| @@ -1386,10 +1706,35 @@ static int kvaser_usb_leaf_init_card(struct kvaser_usb *dev) · 40 unmodified lines | |||
| 1386 | return 0; | 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 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); | 1737 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1392 | struct can_bittiming *bt = &priv->can.bittiming; | ||
| 1393 | struct kvaser_usb *dev = priv->dev; | 1738 | struct kvaser_usb *dev = priv->dev; |
| 1394 | struct kvaser_cmd *cmd; | 1739 | struct kvaser_cmd *cmd; |
| 1395 | int rc; | 1740 | int rc; |
| @@ -1402,15 +1747,8 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev) · 6 unmodified lines | |||
| 1402 | cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams); | 1747 | cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams); |
| 1403 | cmd->u.busparams.channel = priv->channel; | 1748 | cmd->u.busparams.channel = priv->channel; |
| 1404 | cmd->u.busparams.tid = 0xff; | 1749 | cmd->u.busparams.tid = 0xff; |
| 1405 | cmd->u.busparams.bitrate = cpu_to_le32(bt->bitrate); | 1750 | memcpy(&cmd->u.busparams.busparams, busparams, |
| 1406 | cmd->u.busparams.sjw = bt->sjw; | 1751 | sizeof(cmd->u.busparams.busparams)); |
| 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; | ||
| 1414 | 1752 | ||
| 1415 | rc = kvaser_usb_send_cmd(dev, cmd, cmd->len); | 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 | return rc; | 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 | static int kvaser_usb_leaf_set_mode(struct net_device *netdev, | 1780 | static int kvaser_usb_leaf_set_mode(struct net_device *netdev, |
| 1422 | enum can_mode mode) | 1781 | enum can_mode mode) |
| 1423 | { | 1782 | { |
| 1424 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); | 1783 | struct kvaser_usb_net_priv *priv = netdev_priv(netdev); |
| 1784 | struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv; | ||
| 1425 | int err; | 1785 | int err; |
| 1426 | 1786 | ||
| 1427 | switch (mode) { | 1787 | switch (mode) { |
| 1428 | case CAN_MODE_START: | 1788 | case CAN_MODE_START: |
| 1429 | kvaser_usb_unlink_tx_urbs(priv); | 1789 | kvaser_usb_unlink_tx_urbs(priv); |
| 1430 | 1790 | ||
| 1791 | leaf->joining_bus = true; | ||
| 1792 | |||
| 1431 | err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP); | 1793 | err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP); |
| 1432 | if (err) | 1794 | if (err) |
| 1433 | return err; | 1795 | return err; |
| @@ -1479,14 +1841,18 @@ static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev) · 45 unmodified lines | |||
| 1479 | const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = { | 1841 | const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = { |
| 1480 | .dev_set_mode = kvaser_usb_leaf_set_mode, | 1842 | .dev_set_mode = kvaser_usb_leaf_set_mode, |
| 1481 | .dev_set_bittiming = kvaser_usb_leaf_set_bittiming, | 1843 | .dev_set_bittiming = kvaser_usb_leaf_set_bittiming, |
| 1844 | .dev_get_busparams = kvaser_usb_leaf_get_busparams, | ||
| 1482 | .dev_set_data_bittiming = NULL, | 1845 | .dev_set_data_bittiming = NULL, |
| 1846 | .dev_get_data_busparams = NULL, | ||
| 1483 | .dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter, | 1847 | .dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter, |
| 1484 | .dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints, | 1848 | .dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints, |
| 1485 | .dev_init_card = kvaser_usb_leaf_init_card, | 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 | .dev_get_software_info = kvaser_usb_leaf_get_software_info, | 1852 | .dev_get_software_info = kvaser_usb_leaf_get_software_info, |
| 1487 | .dev_get_software_details = NULL, | 1853 | .dev_get_software_details = NULL, |
| 1488 | .dev_get_card_info = kvaser_usb_leaf_get_card_info, | 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 | .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode, | 1856 | .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode, |
| 1491 | .dev_start_chip = kvaser_usb_leaf_start_chip, | 1857 | .dev_start_chip = kvaser_usb_leaf_start_chip, |
| 1492 | .dev_stop_chip = kvaser_usb_leaf_stop_chip, | 1858 | .dev_stop_chip = kvaser_usb_leaf_stop_chip, |
| @@ -245,7 +245,8 @@ struct ucan_message_in { · 244 unmodified lines | |||
| 245 | /* CAN transmission complete | 245 | /* CAN transmission complete |
| 246 | * (type == UCAN_IN_TX_COMPLETE) | 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 | } __aligned(0x4) msg; | 250 | } __aligned(0x4) msg; |
| 250 | } __packed __aligned(0x4); | 251 | } __packed __aligned(0x4); |
| 251 | 252 | ||
| @@ -276,7 +277,6 @@ struct ucan_priv { · 24 unmodified lines | |||
| 276 | 277 | ||
| 277 | /* linux USB device structures */ | 278 | /* linux USB device structures */ |
| 278 | struct usb_device *udev; | 279 | struct usb_device *udev; |
| 279 | struct usb_interface *intf; | ||
| 280 | struct net_device *netdev; | 280 | struct net_device *netdev; |
| 281 | 281 | ||
| 282 | /* lock for can->echo_skb (used around | 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 | /* initialize data */ | 1501 | /* initialize data */ |
| 1502 | up->udev = udev; | 1502 | up->udev = udev; |
| 1503 | up->intf = intf; | ||
| 1504 | up->netdev = netdev; | 1503 | up->netdev = netdev; |
| 1505 | up->intf_index = iface_desc->desc.bInterfaceNumber; | 1504 | up->intf_index = iface_desc->desc.bInterfaceNumber; |
| 1506 | up->in_ep_addr = in_ep_addr; | 1505 | up->in_ep_addr = in_ep_addr; |
| @@ -1533,9 +1532,8 @@ static int ucan_probe(struct usb_interface *intf, · 26 unmodified lines | |||
| 1533 | sizeof(union ucan_ctl_payload)); | 1532 | sizeof(union ucan_ctl_payload)); |
| 1534 | if (ret > 0) { | 1533 | if (ret > 0) { |
| 1535 | /* copy string while ensuring zero termination */ | 1534 | /* copy string while ensuring zero termination */ |
| 1536 | strncpy(firmware_str, up->ctl_msg_buffer->raw, | 1535 | strscpy(firmware_str, up->ctl_msg_buffer->raw, |
| 1537 | sizeof(union ucan_ctl_payload)); | 1536 | sizeof(union ucan_ctl_payload) + 1); |
| 1538 | firmware_str[sizeof(union ucan_ctl_payload)] = '\0'; | ||
| 1539 | } else { | 1537 | } else { |
| 1540 | strcpy(firmware_str, "unknown"); | 1538 | strcpy(firmware_str, "unknown"); |
| 1541 | } | 1539 | } |
| @@ -1581,7 +1579,7 @@ static void ucan_disconnect(struct usb_interface *intf) · 39 unmodified lines | |||
| 1581 | usb_set_intfdata(intf, NULL); | 1579 | usb_set_intfdata(intf, NULL); |
| 1582 | 1580 | ||
| 1583 | if (up) { | 1581 | if (up) { |
| 1584 | unregister_netdev(up->netdev); | 1582 | unregister_candev(up->netdev); |
| 1585 | free_candev(up->netdev); | 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 | netif_carrier_off(peer); | 237 | netif_carrier_off(peer); |
| 238 | 238 | ||
| 239 | err = rtnl_configure_link(peer, ifmp); | 239 | err = rtnl_configure_link(peer, ifmp, 0, NULL); |
| 240 | if (err < 0) | 240 | if (err < 0) |
| 241 | goto unregister_network_device; | 241 | goto unregister_network_device; |
| 242 | 242 | ||
| @@ -18,6 +18,7 @@ config NET_DSA_BCM_SF2 · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | config NET_DSA_LOOP | 19 | config NET_DSA_LOOP |
| 20 | tristate "DSA mock-up Ethernet switch chip support" | 20 | tristate "DSA mock-up Ethernet switch chip support" |
| 21 | select NET_DSA_TAG_NONE | ||
| 21 | select FIXED_PHY | 22 | select FIXED_PHY |
| 22 | help | 23 | help |
| 23 | This enables support for a fake mock-up switch chip which | 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 | config NET_DSA_VITESSE_VSC73XX | 101 | config NET_DSA_VITESSE_VSC73XX |
| 101 | tristate | 102 | tristate |
| 103 | select NET_DSA_TAG_NONE | ||
| 102 | select FIXED_PHY | 104 | select FIXED_PHY |
| 103 | select VITESSE_PHY | 105 | select VITESSE_PHY |
| 104 | select GPIOLIB | 106 | select GPIOLIB |
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | menuconfig B53 | 2 | menuconfig B53 |
| 3 | tristate "Broadcom BCM53xx managed switch support" | 3 | tristate "Broadcom BCM53xx managed switch support" |
| 4 | depends on NET_DSA | 4 | depends on NET_DSA |
| 5 | select NET_DSA_TAG_NONE | ||
| 5 | select NET_DSA_TAG_BRCM | 6 | select NET_DSA_TAG_BRCM |
| 6 | select NET_DSA_TAG_BRCM_LEGACY | 7 | select NET_DSA_TAG_BRCM_LEGACY |
| 7 | select NET_DSA_TAG_BRCM_PREPEND | 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 | struct netlink_ext_ack *extack) | 1176 | struct netlink_ext_ack *extack) |
| 1177 | { | 1177 | { |
| 1178 | struct hellcreek *hellcreek = ds->priv; | 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 | return devlink_info_version_fixed_put(req, | 1180 | return devlink_info_version_fixed_put(req, |
| 1186 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, | 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 | ret = lan9303_read_switch_port( | 1005 | ret = lan9303_read_switch_port( |
| 1006 | chip, port, lan9303_mib[u].offset, ®); | 1006 | chip, port, lan9303_mib[u].offset, ®); |
| 1007 | 1007 | ||
| 1008 | if (ret) | 1008 | if (ret) { |
| 1009 | dev_warn(chip->dev, "Reading status port %d reg %u failed\n", | 1009 | dev_warn(chip->dev, "Reading status port %d reg %u failed\n", |
| 1010 | port, lan9303_mib[u].offset); | 1010 | port, lan9303_mib[u].offset); |
| 1011 | reg = 0; | ||
| 1012 | } | ||
| 1011 | data[u] = reg; | 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 | .cache_type = REGCACHE_NONE, | 29 | .cache_type = REGCACHE_NONE, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | static int lan9303_i2c_probe(struct i2c_client *client, | 32 | static int lan9303_i2c_probe(struct i2c_client *client) |
| 33 | const struct i2c_device_id *id) | ||
| 34 | { | 33 | { |
| 35 | struct lan9303_i2c *sw_dev; | 34 | struct lan9303_i2c *sw_dev; |
| 36 | int ret; | 35 | int ret; |
| @@ -106,7 +105,7 @@ static struct i2c_driver lan9303_i2c_driver = { · 69 unmodified lines | |||
| 106 | .name = "LAN9303_I2C", | 105 | .name = "LAN9303_I2C", |
| 107 | .of_match_table = of_match_ptr(lan9303_i2c_of_match), | 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 | .remove = lan9303_i2c_remove, | 109 | .remove = lan9303_i2c_remove, |
| 111 | .shutdown = lan9303_i2c_shutdown, | 110 | .shutdown = lan9303_i2c_shutdown, |
| 112 | .id_table = lan9303_i2c_id, | 111 | .id_table = lan9303_i2c_id, |
| @@ -3,6 +3,7 @@ menuconfig NET_DSA_MICROCHIP_KSZ_COMMON · 2 unmodified lines | |||
| 3 | tristate "Microchip KSZ8795/KSZ9477/LAN937x series switch support" | 3 | tristate "Microchip KSZ8795/KSZ9477/LAN937x series switch support" |
| 4 | depends on NET_DSA | 4 | depends on NET_DSA |
| 5 | select NET_DSA_TAG_KSZ | 5 | select NET_DSA_TAG_KSZ |
| 6 | select NET_DSA_TAG_NONE | ||
| 6 | help | 7 | help |
| 7 | This driver adds support for Microchip KSZ9477 series switch and | 8 | This driver adds support for Microchip KSZ9477 series switch and |
| 8 | KSZ8795/KSZ88x3 switch chips. | 9 | KSZ8795/KSZ88x3 switch chips. |
| @@ -57,5 +57,6 @@ int ksz8_reset_switch(struct ksz_device *dev); · 56 unmodified lines | |||
| 57 | int ksz8_switch_detect(struct ksz_device *dev); | 57 | int ksz8_switch_detect(struct ksz_device *dev); |
| 58 | int ksz8_switch_init(struct ksz_device *dev); | 58 | int ksz8_switch_init(struct ksz_device *dev); |
| 59 | void ksz8_switch_exit(struct ksz_device *dev); | 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 | #endif | 62 | #endif |
| @@ -76,6 +76,57 @@ int ksz8_reset_switch(struct ksz_device *dev) · 75 unmodified lines | |||
| 76 | return 0; | 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 | static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) | 130 | static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) |
| 80 | { | 131 | { |
| 81 | u8 hi, lo; | 132 | u8 hi, lo; |
| @@ -1233,8 +1284,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) · 1151 unmodified lines | |||
| 1233 | masks = dev->info->masks; | 1284 | masks = dev->info->masks; |
| 1234 | regs = dev->info->regs; | 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 | ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true); | 1287 | ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true); |
| 1239 | 1288 | ||
| 1240 | p = &dev->ports[dev->cpu_port]; | 1289 | p = &dev->ports[dev->cpu_port]; |
| @@ -1308,6 +1357,18 @@ int ksz8_setup(struct dsa_switch *ds) · 67 unmodified lines | |||
| 1308 | struct ksz_device *dev = ds->priv; | 1357 | struct ksz_device *dev = ds->priv; |
| 1309 | int i; | 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 | ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); | 1372 | ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); |
| 1312 | 1373 | ||
| 1313 | /* Enable automatic fast aging when link changed detected. */ | 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 | dev->phy_port_cnt = dev->info->port_cnt - 1; | 1428 | dev->phy_port_cnt = dev->info->port_cnt - 1; |
| 1368 | dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports; | 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 | return 0; | 1431 | return 0; |
| 1381 | } | 1432 | } |
| 1382 | 1433 | ||
| @@ -48,6 +48,9 @@ · 47 unmodified lines | |||
| 48 | #define NO_EXC_COLLISION_DROP BIT(3) | 48 | #define NO_EXC_COLLISION_DROP BIT(3) |
| 49 | #define SW_LEGAL_PACKET_DISABLE BIT(1) | 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 | #define REG_SW_CTRL_3 0x05 | 54 | #define REG_SW_CTRL_3 0x05 |
| 52 | #define WEIGHTED_FAIR_QUEUE_ENABLE BIT(3) | 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 | ®map_smi[i], dev, | 152 | ®map_smi[i], dev, |
| 153 | &rc); | 153 | &rc); |
| 154 | if (IS_ERR(dev->regmap[i])) { | 154 | if (IS_ERR(dev->regmap[i])) { |
| 155 | ret = PTR_ERR(dev->regmap[i]); | 155 | return dev_err_probe(&mdiodev->dev, |
| 156 | dev_err(&mdiodev->dev, | 156 | PTR_ERR(dev->regmap[i]), |
| 157 | "Failed to initialize regmap%i: %d\n", | 157 | "Failed to initialize regmap%i\n", |
| 158 | ksz8863_regmap_config[i].val_bits, ret); | 158 | ksz8863_regmap_config[i].val_bits); |
| 159 | return ret; | ||
| 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 | int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) | 46 | int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) |
| 47 | { | 47 | { |
| 48 | u16 frame_size, max_frame = 0; | 48 | u16 frame_size; |
| 49 | int i; | ||
| 50 | |||
| 51 | frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; | ||
| 52 | 49 | ||
| 53 | /* Cache the per-port MTU setting */ | 50 | if (!dsa_is_cpu_port(dev->ds, port)) |
| 54 | dev->ports[port].max_frame = frame_size; | 51 | return 0; |
| 55 | 52 | ||
| 56 | for (i = 0; i < dev->info->port_cnt; i++) | 53 | frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; |
| 57 | max_frame = max(max_frame, dev->ports[i].max_frame); | ||
| 58 | 54 | ||
| 59 | return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, | 55 | return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, |
| 60 | REG_SW_MTU_MASK, max_frame); | 56 | REG_SW_MTU_MASK, frame_size); |
| 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; | ||
| 66 | } | 57 | } |
| 67 | 58 | ||
| 68 | static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) | 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 | /* KSZ9893 compatible chips do not support refclk configuration */ | 187 | /* KSZ9893 compatible chips do not support refclk configuration */ |
| 197 | if (dev->chip_id == KSZ9893_CHIP_ID || | 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 | return 0; | 191 | return 0; |
| 200 | 192 | ||
| 201 | data8 = SW_ENABLE_REFCLKO; | 193 | data8 = SW_ENABLE_REFCLKO; |
| @@ -1142,6 +1134,8 @@ int ksz9477_setup(struct dsa_switch *ds) · 940 unmodified lines | |||
| 1142 | struct ksz_device *dev = ds->priv; | 1134 | struct ksz_device *dev = ds->priv; |
| 1143 | int ret = 0; | 1135 | int ret = 0; |
| 1144 | 1136 | ||
| 1137 | ds->mtu_enforcement_ingress = true; | ||
| 1138 | |||
| 1145 | /* Required for port partitioning. */ | 1139 | /* Required for port partitioning. */ |
| 1146 | ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, | 1140 | ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, |
| 1147 | true); | 1141 | true); |
| @@ -50,7 +50,6 @@ int ksz9477_mdb_add(struct ksz_device *dev, int port, · 49 unmodified lines | |||
| 50 | int ksz9477_mdb_del(struct ksz_device *dev, int port, | 50 | int ksz9477_mdb_del(struct ksz_device *dev, int port, |
| 51 | const struct switchdev_obj_port_mdb *mdb, struct dsa_db db); | 51 | const struct switchdev_obj_port_mdb *mdb, struct dsa_db db); |
| 52 | int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu); | 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 | void ksz9477_config_cpu_port(struct dsa_switch *ds); | 53 | void ksz9477_config_cpu_port(struct dsa_switch *ds); |
| 55 | int ksz9477_enable_stp_addr(struct ksz_device *dev); | 54 | int ksz9477_enable_stp_addr(struct ksz_device *dev); |
| 56 | int ksz9477_reset_switch(struct ksz_device *dev); | 55 | int ksz9477_reset_switch(struct ksz_device *dev); |
| @@ -14,8 +14,7 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0); | 15 | KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0); |
| 16 | 16 | ||
| 17 | static int ksz9477_i2c_probe(struct i2c_client *i2c, | 17 | static int ksz9477_i2c_probe(struct i2c_client *i2c) |
| 18 | const struct i2c_device_id *i2c_id) | ||
| 19 | { | 18 | { |
| 20 | struct regmap_config rc; | 19 | struct regmap_config rc; |
| 21 | struct ksz_device *dev; | 20 | struct ksz_device *dev; |
| @@ -30,17 +29,17 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c, · 8 unmodified lines | |||
| 30 | rc.lock_arg = &dev->regmap_mutex; | 29 | rc.lock_arg = &dev->regmap_mutex; |
| 31 | dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc); | 30 | dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc); |
| 32 | if (IS_ERR(dev->regmap[i])) { | 31 | if (IS_ERR(dev->regmap[i])) { |
| 33 | ret = PTR_ERR(dev->regmap[i]); | 32 | return dev_err_probe(&i2c->dev, PTR_ERR(dev->regmap[i]), |
| 34 | dev_err(&i2c->dev, | 33 | "Failed to initialize regmap%i\n", |
| 35 | "Failed to initialize regmap%i: %d\n", | 34 | ksz9477_regmap_config[i].val_bits); |
| 36 | ksz9477_regmap_config[i].val_bits, ret); | ||
| 37 | return ret; | ||
| 38 | } | 35 | } |
| 39 | } | 36 | } |
| 40 | 37 | ||
| 41 | if (i2c->dev.platform_data) | 38 | if (i2c->dev.platform_data) |
| 42 | dev->pdata = i2c->dev.platform_data; | 39 | dev->pdata = i2c->dev.platform_data; |
| 43 | 40 | ||
| 41 | dev->irq = i2c->irq; | ||
| 42 | |||
| 44 | ret = ksz_switch_register(dev); | 43 | ret = ksz_switch_register(dev); |
| 45 | 44 | ||
| 46 | /* Main DSA driver may not be started yet. */ | 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 | .compatible = "microchip,ksz9563", | 102 | .compatible = "microchip,ksz9563", |
| 104 | .data = &ksz_switch_chips[KSZ9893] | 103 | .data = &ksz_switch_chips[KSZ9563] |
| 105 | }, | 104 | }, |
| 106 | { | 105 | { |
| 107 | .compatible = "microchip,ksz8563", | 106 | .compatible = "microchip,ksz8563", |
| @@ -120,7 +119,7 @@ static struct i2c_driver ksz9477_i2c_driver = { · 12 unmodified lines | |||
| 120 | .name = "ksz9477-switch", | 119 | .name = "ksz9477-switch", |
| 121 | .of_match_table = of_match_ptr(ksz9477_dt_ids), | 120 | .of_match_table = of_match_ptr(ksz9477_dt_ids), |
| 122 | }, | 121 | }, |
| 123 | .probe = ksz9477_i2c_probe, | 122 | .probe_new = ksz9477_i2c_probe, |
| 124 | .remove = ksz9477_i2c_remove, | 123 | .remove = ksz9477_i2c_remove, |
| 125 | .shutdown = ksz9477_i2c_shutdown, | 124 | .shutdown = ksz9477_i2c_shutdown, |
| 126 | .id_table = ksz9477_i2c_id, | 125 | .id_table = ksz9477_i2c_id, |
| @@ -1615,6 +1615,4 @@ · 1614 unmodified lines | |||
| 1615 | #define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) | 1615 | #define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) |
| 1616 | #define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) | 1616 | #define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) |
| 1617 | 1617 | ||
| 1618 | #define KSZ9477_MAX_FRAME_SIZE 9000 | ||
| 1619 | |||
| 1620 | #endif /* KSZ9477_REGS_H */ | 1618 | #endif /* KSZ9477_REGS_H */ |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/phy.h> | 14 | #include <linux/phy.h> |
| 15 | #include <linux/etherdevice.h> | 15 | #include <linux/etherdevice.h> |
| 16 | #include <linux/if_bridge.h> | 16 | #include <linux/if_bridge.h> |
| 17 | #include <linux/if_vlan.h> | ||
| 17 | #include <linux/irq.h> | 18 | #include <linux/irq.h> |
| 18 | #include <linux/irqdomain.h> | 19 | #include <linux/irqdomain.h> |
| 19 | #include <linux/of_mdio.h> | 20 | #include <linux/of_mdio.h> |
| @@ -69,6 +70,43 @@ struct ksz_stats_raw { · 49 unmodified lines | |||
| 69 | u64 tx_discards; | 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 | static const struct ksz_mib_names ksz88xx_mib_names[] = { | 110 | static const struct ksz_mib_names ksz88xx_mib_names[] = { |
| 73 | { 0x00, "rx" }, | 111 | { 0x00, "rx" }, |
| 74 | { 0x01, "rx_hi" }, | 112 | { 0x01, "rx_hi" }, |
| @@ -155,6 +193,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = { · 80 unmodified lines | |||
| 155 | .w_phy = ksz8_w_phy, | 193 | .w_phy = ksz8_w_phy, |
| 156 | .r_mib_cnt = ksz8_r_mib_cnt, | 194 | .r_mib_cnt = ksz8_r_mib_cnt, |
| 157 | .r_mib_pkt = ksz8_r_mib_pkt, | 195 | .r_mib_pkt = ksz8_r_mib_pkt, |
| 196 | .r_mib_stat64 = ksz88xx_r_mib_stats64, | ||
| 158 | .freeze_mib = ksz8_freeze_mib, | 197 | .freeze_mib = ksz8_freeze_mib, |
| 159 | .port_init_cnt = ksz8_port_init_cnt, | 198 | .port_init_cnt = ksz8_port_init_cnt, |
| 160 | .fdb_dump = ksz8_fdb_dump, | 199 | .fdb_dump = ksz8_fdb_dump, |
| @@ -171,6 +210,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = { · 10 unmodified lines | |||
| 171 | .reset = ksz8_reset_switch, | 210 | .reset = ksz8_reset_switch, |
| 172 | .init = ksz8_switch_init, | 211 | .init = ksz8_switch_init, |
| 173 | .exit = ksz8_switch_exit, | 212 | .exit = ksz8_switch_exit, |
| 213 | .change_mtu = ksz8_change_mtu, | ||
| 174 | }; | 214 | }; |
| 175 | 215 | ||
| 176 | static void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port, | 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 | .mdb_add = ksz9477_mdb_add, | 246 | .mdb_add = ksz9477_mdb_add, |
| 207 | .mdb_del = ksz9477_mdb_del, | 247 | .mdb_del = ksz9477_mdb_del, |
| 208 | .change_mtu = ksz9477_change_mtu, | 248 | .change_mtu = ksz9477_change_mtu, |
| 209 | .max_mtu = ksz9477_max_mtu, | ||
| 210 | .phylink_mac_link_up = ksz9477_phylink_mac_link_up, | 249 | .phylink_mac_link_up = ksz9477_phylink_mac_link_up, |
| 211 | .config_cpu_port = ksz9477_config_cpu_port, | 250 | .config_cpu_port = ksz9477_config_cpu_port, |
| 212 | .enable_stp_addr = ksz9477_enable_stp_addr, | 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 | .mdb_add = ksz9477_mdb_add, | 282 | .mdb_add = ksz9477_mdb_add, |
| 244 | .mdb_del = ksz9477_mdb_del, | 283 | .mdb_del = ksz9477_mdb_del, |
| 245 | .change_mtu = lan937x_change_mtu, | 284 | .change_mtu = lan937x_change_mtu, |
| 246 | .max_mtu = ksz9477_max_mtu, | ||
| 247 | .phylink_mac_link_up = ksz9477_phylink_mac_link_up, | 285 | .phylink_mac_link_up = ksz9477_phylink_mac_link_up, |
| 248 | .config_cpu_port = lan937x_config_cpu_port, | 286 | .config_cpu_port = lan937x_config_cpu_port, |
| 249 | .enable_stp_addr = ksz9477_enable_stp_addr, | 287 | .enable_stp_addr = ksz9477_enable_stp_addr, |
| @@ -1039,6 +1077,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { · 789 unmodified lines | |||
| 1039 | .num_statics = 16, | 1077 | .num_statics = 16, |
| 1040 | .cpu_ports = 0x07, /* can be configured as cpu port */ | 1078 | .cpu_ports = 0x07, /* can be configured as cpu port */ |
| 1041 | .port_cnt = 3, /* total port count */ | 1079 | .port_cnt = 3, /* total port count */ |
| 1080 | .port_nirqs = 3, | ||
| 1042 | .ops = &ksz9477_dev_ops, | 1081 | .ops = &ksz9477_dev_ops, |
| 1043 | .mib_names = ksz9477_mib_names, | 1082 | .mib_names = ksz9477_mib_names, |
| 1044 | .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), | 1083 | .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), |
| @@ -1282,6 +1321,31 @@ const struct ksz_chip_data ksz_switch_chips[] = { · 237 unmodified lines | |||
| 1282 | .gbit_capable = {true, true, true}, | 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 | [KSZ9567] = { | 1349 | [KSZ9567] = { |
| 1286 | .chip_id = KSZ9567_CHIP_ID, | 1350 | .chip_id = KSZ9567_CHIP_ID, |
| 1287 | .dev_name = "KSZ9567", | 1351 | .dev_name = "KSZ9567", |
| @@ -1557,6 +1621,55 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port) · 269 unmodified lines | |||
| 1557 | spin_unlock(&mib->stats64_lock); | 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 | static void ksz_get_stats64(struct dsa_switch *ds, int port, | 1673 | static void ksz_get_stats64(struct dsa_switch *ds, int port, |
| 1561 | struct rtnl_link_stats64 *s) | 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 | if (dev->chip_id == KSZ8830_CHIP_ID || | 2503 | if (dev->chip_id == KSZ8830_CHIP_ID || |
| 2391 | dev->chip_id == KSZ8563_CHIP_ID || | 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 | proto = DSA_TAG_PROTO_KSZ9893; | 2507 | proto = DSA_TAG_PROTO_KSZ9893; |
| 2394 | 2508 | ||
| 2395 | if (dev->chip_id == KSZ9477_CHIP_ID || | 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 | struct ksz_device *dev = ds->priv; | 2588 | struct ksz_device *dev = ds->priv; |
| 2475 | 2589 | ||
| 2476 | if (!dev->dev_ops->max_mtu) | 2590 | switch (dev->chip_id) { |
| 2477 | return -EOPNOTSUPP; | 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 | static void ksz_set_xmii(struct ksz_device *dev, int port, | 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 | data8 |= bitval[P_RGMII_SEL]; | 2642 | data8 |= bitval[P_RGMII_SEL]; |
| 2510 | /* On KSZ9893, disable RGMII in-band status support */ | 2643 | /* On KSZ9893, disable RGMII in-band status support */ |
| 2511 | if (dev->chip_id == KSZ9893_CHIP_ID || | 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 | data8 &= ~P_MII_MAC_MODE; | 2647 | data8 &= ~P_MII_MAC_MODE; |
| 2514 | break; | 2648 | break; |
| 2515 | default: | 2649 | default: |
| @@ -2782,6 +2916,8 @@ static int ksz_switch_detect(struct ksz_device *dev) · 266 unmodified lines | |||
| 2782 | 2916 | ||
| 2783 | if (id4 == SKU_ID_KSZ8563) | 2917 | if (id4 == SKU_ID_KSZ8563) |
| 2784 | dev->chip_id = KSZ8563_CHIP_ID; | 2918 | dev->chip_id = KSZ8563_CHIP_ID; |
| 2919 | else if (id4 == SKU_ID_KSZ9563) | ||
| 2920 | dev->chip_id = KSZ9563_CHIP_ID; | ||
| 2785 | else | 2921 | else |
| 2786 | dev->chip_id = KSZ9893_CHIP_ID; | 2922 | dev->chip_id = KSZ9893_CHIP_ID; |
| 2787 | 2923 | ||
| @@ -95,7 +95,6 @@ struct ksz_port { · 94 unmodified lines | |||
| 95 | 95 | ||
| 96 | struct ksz_port_mib mib; | 96 | struct ksz_port_mib mib; |
| 97 | phy_interface_t interface; | 97 | phy_interface_t interface; |
| 98 | u16 max_frame; | ||
| 99 | u32 rgmii_tx_val; | 98 | u32 rgmii_tx_val; |
| 100 | u32 rgmii_rx_val; | 99 | u32 rgmii_rx_val; |
| 101 | struct ksz_device *ksz_dev; | 100 | struct ksz_device *ksz_dev; |
| @@ -154,6 +153,7 @@ enum ksz_model { · 52 unmodified lines | |||
| 154 | KSZ9896, | 153 | KSZ9896, |
| 155 | KSZ9897, | 154 | KSZ9897, |
| 156 | KSZ9893, | 155 | KSZ9893, |
| 156 | KSZ9563, | ||
| 157 | KSZ9567, | 157 | KSZ9567, |
| 158 | LAN9370, | 158 | LAN9370, |
| 159 | LAN9371, | 159 | LAN9371, |
| @@ -172,6 +172,7 @@ enum ksz_chip_id { · 12 unmodified lines | |||
| 172 | KSZ9896_CHIP_ID = 0x00989600, | 172 | KSZ9896_CHIP_ID = 0x00989600, |
| 173 | KSZ9897_CHIP_ID = 0x00989700, | 173 | KSZ9897_CHIP_ID = 0x00989700, |
| 174 | KSZ9893_CHIP_ID = 0x00989300, | 174 | KSZ9893_CHIP_ID = 0x00989300, |
| 175 | KSZ9563_CHIP_ID = 0x00956300, | ||
| 175 | KSZ9567_CHIP_ID = 0x00956700, | 176 | KSZ9567_CHIP_ID = 0x00956700, |
| 176 | LAN9370_CHIP_ID = 0x00937000, | 177 | LAN9370_CHIP_ID = 0x00937000, |
| 177 | LAN9371_CHIP_ID = 0x00937100, | 178 | LAN9371_CHIP_ID = 0x00937100, |
| @@ -320,7 +321,6 @@ struct ksz_dev_ops { · 142 unmodified lines | |||
| 320 | void (*get_caps)(struct ksz_device *dev, int port, | 321 | void (*get_caps)(struct ksz_device *dev, int port, |
| 321 | struct phylink_config *config); | 322 | struct phylink_config *config); |
| 322 | int (*change_mtu)(struct ksz_device *dev, int port, int mtu); | 323 | int (*change_mtu)(struct ksz_device *dev, int port, int mtu); |
| 323 | int (*max_mtu)(struct ksz_device *dev, int port); | ||
| 324 | void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); | 324 | void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); |
| 325 | void (*port_init_cnt)(struct ksz_device *dev, int port); | 325 | void (*port_init_cnt)(struct ksz_device *dev, int port); |
| 326 | void (*phylink_mac_config)(struct ksz_device *dev, int port, | 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 | void ksz_init_mib_timer(struct ksz_device *dev); | 346 | void ksz_init_mib_timer(struct ksz_device *dev); |
| 347 | void ksz_r_mib_stats64(struct ksz_device *dev, int port); | 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 | void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); | 349 | void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); |
| 349 | bool ksz_get_gbit(struct ksz_device *dev, int port); | 350 | bool ksz_get_gbit(struct ksz_device *dev, int port); |
| 350 | phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit); | 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 | return regmap_bulk_write(dev->regmap[2], reg, val, 2); | 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 | static inline int ksz_pread8(struct ksz_device *dev, int port, int offset, | 463 | static inline int ksz_pread8(struct ksz_device *dev, int port, int offset, |
| 458 | u8 *data) | 464 | u8 *data) |
| 459 | { | 465 | { |
| @@ -551,6 +557,7 @@ static inline int is_lan937x(struct ksz_device *dev) · 91 unmodified lines | |||
| 551 | /* KSZ9893, KSZ9563, KSZ8563 specific register */ | 557 | /* KSZ9893, KSZ9563, KSZ8563 specific register */ |
| 552 | #define REG_CHIP_ID4 0x0f | 558 | #define REG_CHIP_ID4 0x0f |
| 553 | #define SKU_ID_KSZ8563 0x3c | 559 | #define SKU_ID_KSZ8563 0x3c |
| 560 | #define SKU_ID_KSZ9563 0x1c | ||
| 554 | 561 | ||
| 555 | /* Driver set switch broadcast storm protection at 10% rate. */ | 562 | /* Driver set switch broadcast storm protection at 10% rate. */ |
| 556 | #define BROADCAST_STORM_PROT_RATE 10 | 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 | #define PORT_SRC_PHY_INT 1 | 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 | /* Regmap tables generation */ | 601 | /* Regmap tables generation */ |
| 589 | #define KSZ_SPI_OP_RD 3 | 602 | #define KSZ_SPI_OP_RD 3 |
| 590 | #define KSZ_SPI_OP_WR 2 | 603 | #define KSZ_SPI_OP_WR 2 |
| @@ -71,11 +71,9 @@ static int ksz_spi_probe(struct spi_device *spi) · 70 unmodified lines | |||
| 71 | dev->regmap[i] = devm_regmap_init_spi(spi, &rc); | 71 | dev->regmap[i] = devm_regmap_init_spi(spi, &rc); |
| 72 | 72 | ||
| 73 | if (IS_ERR(dev->regmap[i])) { | 73 | if (IS_ERR(dev->regmap[i])) { |
| 74 | ret = PTR_ERR(dev->regmap[i]); | 74 | return dev_err_probe(&spi->dev, PTR_ERR(dev->regmap[i]), |
| 75 | dev_err(&spi->dev, | 75 | "Failed to initialize regmap%i\n", |
| 76 | "Failed to initialize regmap%i: %d\n", | 76 | regmap_config[i].val_bits); |
| 77 | regmap_config[i].val_bits, ret); | ||
| 78 | return ret; | ||
| 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 | .compatible = "microchip,ksz9563", | 163 | .compatible = "microchip,ksz9563", |
| 166 | .data = &ksz_switch_chips[KSZ9893] | 164 | .data = &ksz_switch_chips[KSZ9563] |
| 167 | }, | 165 | }, |
| 168 | { | 166 | { |
| 169 | .compatible = "microchip,ksz8563", | 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 | /* Write the frame size in PORT_MAX_FR_SIZE register */ | 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 | return 0; | 251 | return 0; |
| 248 | } | 252 | } |
| @@ -15,3 +15,7 @@ mv88e6xxx-objs += port_hidden.o · 14 unmodified lines | |||
| 15 | mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o | 15 | mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o |
| 16 | mv88e6xxx-objs += serdes.o | 16 | mv88e6xxx-objs += serdes.o |
| 17 | mv88e6xxx-objs += smi.o | 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 | .port_sync_link = mv88e6xxx_port_sync_link, | 4077 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 4078 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, | 4078 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 4079 | .port_tag_remap = mv88e6095_port_tag_remap, | 4079 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 4080 | .port_set_policy = mv88e6352_port_set_policy, | ||
| 4080 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, | 4081 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 4081 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, | 4082 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 4082 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, | 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 | .port_sync_link = mv88e6xxx_port_sync_link, | 4350 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 4350 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, | 4351 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 4351 | .port_tag_remap = mv88e6095_port_tag_remap, | 4352 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 4353 | .port_set_policy = mv88e6352_port_set_policy, | ||
| 4352 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, | 4354 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, |
| 4353 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, | 4355 | .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, |
| 4354 | .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, | 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 | .phy_write = mv88e6xxx_g2_smi_phy_write, | 5034 | .phy_write = mv88e6xxx_g2_smi_phy_write, |
| 5033 | .port_set_link = mv88e6xxx_port_set_link, | 5035 | .port_set_link = mv88e6xxx_port_set_link, |
| 5034 | .port_sync_link = mv88e6xxx_port_sync_link, | 5036 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 5037 | .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, | ||
| 5035 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, | 5038 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 5036 | .port_tag_remap = mv88e6095_port_tag_remap, | 5039 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 5037 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, | 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 | .phy_write = mv88e6xxx_g2_smi_phy_write, | 5079 | .phy_write = mv88e6xxx_g2_smi_phy_write, |
| 5077 | .port_set_link = mv88e6xxx_port_set_link, | 5080 | .port_set_link = mv88e6xxx_port_set_link, |
| 5078 | .port_sync_link = mv88e6xxx_port_sync_link, | 5081 | .port_sync_link = mv88e6xxx_port_sync_link, |
| 5082 | .port_set_rgmii_delay = mv88e6320_port_set_rgmii_delay, | ||
| 5079 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, | 5083 | .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, |
| 5080 | .port_tag_remap = mv88e6095_port_tag_remap, | 5084 | .port_tag_remap = mv88e6095_port_tag_remap, |
| 5081 | .port_set_frame_mode = mv88e6351_port_set_frame_mode, | 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 | struct netlink_ext_ack *extack) | 821 | struct netlink_ext_ack *extack) |
| 822 | { | 822 | { |
| 823 | struct mv88e6xxx_chip *chip = ds->priv; | 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 | return devlink_info_version_fixed_put(req, | 825 | return devlink_info_version_fixed_put(req, |
| 831 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, | 826 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | #include "chip.h" | 13 | #include "chip.h" |
| 14 | #include "global1.h" | 14 | #include "global1.h" |
| 15 | #include "trace.h" | ||
| 15 | 16 | ||
| 16 | /* Offset 0x01: ATU FID Register */ | 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 | return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0); | 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 | static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) | 131 | static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) |
| 118 | { | 132 | { |
| 119 | u16 val; | 133 | u16 val; |
| @@ -159,6 +173,41 @@ int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid) · 39 unmodified lines | |||
| 159 | return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); | 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 | /* Offset 0x0C: ATU Data Register */ | 211 | /* Offset 0x0C: ATU Data Register */ |
| 163 | 212 | ||
| 164 | static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, | 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 | struct mv88e6xxx_chip *chip = dev_id; | 403 | struct mv88e6xxx_chip *chip = dev_id; |
| 355 | struct mv88e6xxx_atu_entry entry; | 404 | struct mv88e6xxx_atu_entry entry; |
| 356 | int spid; | 405 | int err, spid; |
| 357 | int err; | 406 | u16 val, fid; |
| 358 | u16 val; | ||
| 359 | 407 | ||
| 360 | mv88e6xxx_reg_lock(chip); | 408 | mv88e6xxx_reg_lock(chip); |
| 361 | 409 | ||
| 362 | err = mv88e6xxx_g1_atu_op(chip, 0, | 410 | err = mv88e6xxx_g1_read_atu_violation(chip); |
| 363 | MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION); | ||
| 364 | if (err) | 411 | if (err) |
| 365 | goto out; | 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 | if (err) | 415 | if (err) |
| 369 | goto out; | 416 | goto out; |
| 370 | 417 | ||
| 418 | err = mv88e6xxx_g1_atu_fid_read(chip, &fid); | ||
| 419 | if (err) | ||
| 420 | goto out; | ||
| 421 | |||
| 371 | err = mv88e6xxx_g1_atu_data_read(chip, &entry); | 422 | err = mv88e6xxx_g1_atu_data_read(chip, &entry); |
| 372 | if (err) | 423 | if (err) |
| 373 | goto out; | 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 | spid = entry.state; | 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 | if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { | 432 | if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { |
| 388 | dev_err_ratelimited(chip->dev, | 433 | trace_mv88e6xxx_atu_member_violation(chip->dev, spid, |
| 389 | "ATU member violation for %pM portvec %x spid %d\n", | 434 | entry.portvec, entry.mac, |
| 390 | entry.mac, entry.portvec, spid); | 435 | fid); |
| 391 | chip->ports[spid].atu_member_violation++; | 436 | chip->ports[spid].atu_member_violation++; |
| 392 | } | 437 | } |
| 393 | 438 | ||
| 394 | if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { | 439 | if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { |
| 395 | dev_err_ratelimited(chip->dev, | 440 | trace_mv88e6xxx_atu_miss_violation(chip->dev, spid, |
| 396 | "ATU miss violation for %pM portvec %x spid %d\n", | 441 | entry.portvec, entry.mac, |
| 397 | entry.mac, entry.portvec, spid); | 442 | fid); |
| 398 | chip->ports[spid].atu_miss_violation++; | 443 | chip->ports[spid].atu_miss_violation++; |
| 399 | } | 444 | } |
| 400 | 445 | ||
| 401 | if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { | 446 | if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { |
| 402 | dev_err_ratelimited(chip->dev, | 447 | trace_mv88e6xxx_atu_full_violation(chip->dev, spid, |
| 403 | "ATU full violation for %pM portvec %x spid %d\n", | 448 | entry.portvec, entry.mac, |
| 404 | entry.mac, entry.portvec, spid); | 449 | fid); |
| 405 | chip->ports[spid].atu_full_violation++; | 450 | chip->ports[spid].atu_full_violation++; |
| 406 | } | 451 | } |
| 407 | mv88e6xxx_reg_unlock(chip); | 452 | mv88e6xxx_reg_unlock(chip); |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | #include "chip.h" | 14 | #include "chip.h" |
| 15 | #include "global1.h" | 15 | #include "global1.h" |
| 16 | #include "trace.h" | ||
| 16 | 17 | ||
| 17 | /* Offset 0x02: VTU FID Register */ | 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 | spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK; | 629 | spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK; |
| 629 | 630 | ||
| 630 | if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) { | 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 | trace_mv88e6xxx_vtu_member_violation(chip->dev, spid, vid); |
| 632 | vid, spid); | ||
| 633 | chip->ports[spid].vtu_member_violation++; | 633 | chip->ports[spid].vtu_member_violation++; |
| 634 | } | 634 | } |
| 635 | 635 | ||
| 636 | if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) { | 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", | 637 | trace_mv88e6xxx_vtu_miss_violation(chip->dev, spid, vid); |
| 638 | vid, spid); | ||
| 639 | chip->ports[spid].vtu_miss_violation++; | 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 | return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); | 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 | int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) | 145 | int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) |
| 137 | { | 146 | { |
| 138 | u16 reg; | 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 | int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, | 333 | int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, |
| 334 | int pause); | 334 | int pause); |
| 335 | int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | ||
| 336 | phy_interface_t mode); | ||
| 335 | int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | 337 | int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, |
| 336 | phy_interface_t mode); | 338 | phy_interface_t mode); |
| 337 | int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, | 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 | config->legacy_pre_march2020 = false; | 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 | __set_bit(ocelot->ports[port]->phy_mode, | 1055 | __set_bit(ocelot->ports[port]->phy_mode, |
| 1052 | config->supported_interfaces); | 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 | static struct phylink_pcs *felix_phylink_mac_select_pcs(struct dsa_switch *ds, | 1059 | static struct phylink_pcs *felix_phylink_mac_select_pcs(struct dsa_switch *ds, |
| 1067 | int port, | 1060 | int port, |
| 1068 | phy_interface_t iface) | 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 | return -ENOMEM; | 1363 | return -ENOMEM; |
| 1371 | 1364 | ||
| 1372 | ocelot->map = felix->info->map; | 1365 | ocelot->map = felix->info->map; |
| 1373 | ocelot->stats_layout = felix->info->stats_layout; | ||
| 1374 | ocelot->num_mact_rows = felix->info->num_mact_rows; | 1366 | ocelot->num_mact_rows = felix->info->num_mact_rows; |
| 1375 | ocelot->vcap = felix->info->vcap; | 1367 | ocelot->vcap = felix->info->vcap; |
| 1376 | ocelot->vcap_pol.base = felix->info->vcap_pol_base; | 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 | .get_sset_count = felix_get_sset_count, | 2042 | .get_sset_count = felix_get_sset_count, |
| 2051 | .get_ts_info = felix_get_ts_info, | 2043 | .get_ts_info = felix_get_ts_info, |
| 2052 | .phylink_get_caps = felix_phylink_get_caps, | 2044 | .phylink_get_caps = felix_phylink_get_caps, |
| 2053 | .phylink_validate = felix_phylink_validate, | ||
| 2054 | .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, | 2045 | .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, |
| 2055 | .phylink_mac_link_down = felix_phylink_mac_link_down, | 2046 | .phylink_mac_link_down = felix_phylink_mac_link_down, |
| 2056 | .phylink_mac_link_up = felix_phylink_mac_link_up, | 2047 | .phylink_mac_link_up = felix_phylink_mac_link_up, |
| @@ -28,7 +28,6 @@ struct felix_info { · 27 unmodified lines | |||
| 28 | const struct ocelot_ops *ops; | 28 | const struct ocelot_ops *ops; |
| 29 | const u32 *port_modes; | 29 | const u32 *port_modes; |
| 30 | int num_mact_rows; | 30 | int num_mact_rows; |
| 31 | const struct ocelot_stat_layout *stats_layout; | ||
| 32 | int num_ports; | 31 | int num_ports; |
| 33 | int num_tx_queues; | 32 | int num_tx_queues; |
| 34 | struct vcap_props *vcap; | 33 | struct vcap_props *vcap; |
| @@ -52,9 +51,6 @@ struct felix_info { · 17 unmodified lines | |||
| 52 | 51 | ||
| 53 | int (*mdio_bus_alloc)(struct ocelot *ocelot); | 52 | int (*mdio_bus_alloc)(struct ocelot *ocelot); |
| 54 | void (*mdio_bus_free)(struct ocelot *ocelot); | 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 | int (*port_setup_tc)(struct dsa_switch *ds, int port, | 54 | int (*port_setup_tc)(struct dsa_switch *ds, int port, |
| 59 | enum tc_setup_type type, void *type_data); | 55 | enum tc_setup_type type, void *type_data); |
| 60 | void (*tas_guard_bands_update)(struct ocelot *ocelot, int port); | 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 | [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4), | 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 | static const struct vcap_field vsc9959_vcap_es0_keys[] = { | 568 | static const struct vcap_field vsc9959_vcap_es0_keys[] = { |
| 573 | [VCAP_ES0_EGR_PORT] = { 0, 3}, | 569 | [VCAP_ES0_EGR_PORT] = { 0, 3}, |
| 574 | [VCAP_ES0_IGR_PORT] = { 3, 3}, | 570 | [VCAP_ES0_IGR_PORT] = { 3, 3}, |
| @@ -885,35 +881,6 @@ static int vsc9959_reset(struct ocelot *ocelot) · 310 unmodified lines | |||
| 885 | return 0; | 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 | /* Watermark encode | 884 | /* Watermark encode |
| 918 | * Bit 8: Unit; 0:1, 1:16 | 885 | * Bit 8: Unit; 0:1, 1:16 |
| 919 | * Bit 7-0: Value to be multiplied with unit | 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 | .regfields = vsc9959_regfields, | 2542 | .regfields = vsc9959_regfields, |
| 2576 | .map = vsc9959_regmap, | 2543 | .map = vsc9959_regmap, |
| 2577 | .ops = &vsc9959_ops, | 2544 | .ops = &vsc9959_ops, |
| 2578 | .stats_layout = vsc9959_stats_layout, | ||
| 2579 | .vcap = vsc9959_vcap_props, | 2545 | .vcap = vsc9959_vcap_props, |
| 2580 | .vcap_pol_base = VSC9959_VCAP_POLICER_BASE, | 2546 | .vcap_pol_base = VSC9959_VCAP_POLICER_BASE, |
| 2581 | .vcap_pol_max = VSC9959_VCAP_POLICER_MAX, | 2547 | .vcap_pol_max = VSC9959_VCAP_POLICER_MAX, |
| @@ -2588,7 +2554,6 @@ static const struct felix_info felix_info_vsc9959 = { · 6 unmodified lines | |||
| 2588 | .ptp_caps = &vsc9959_ptp_caps, | 2554 | .ptp_caps = &vsc9959_ptp_caps, |
| 2589 | .mdio_bus_alloc = vsc9959_mdio_bus_alloc, | 2555 | .mdio_bus_alloc = vsc9959_mdio_bus_alloc, |
| 2590 | .mdio_bus_free = vsc9959_mdio_bus_free, | 2556 | .mdio_bus_free = vsc9959_mdio_bus_free, |
| 2591 | .phylink_validate = vsc9959_phylink_validate, | ||
| 2592 | .port_modes = vsc9959_port_modes, | 2557 | .port_modes = vsc9959_port_modes, |
| 2593 | .port_setup_tc = vsc9959_port_setup_tc, | 2558 | .port_setup_tc = vsc9959_port_setup_tc, |
| 2594 | .port_sched_speed_set = vsc9959_sched_speed_set, | 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 | [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 11, 4), | 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 | static const struct vcap_field vsc9953_vcap_es0_keys[] = { | 546 | static const struct vcap_field vsc9953_vcap_es0_keys[] = { |
| 551 | [VCAP_ES0_EGR_PORT] = { 0, 4}, | 547 | [VCAP_ES0_EGR_PORT] = { 0, 4}, |
| 552 | [VCAP_ES0_IGR_PORT] = { 4, 4}, | 548 | [VCAP_ES0_IGR_PORT] = { 4, 4}, |
| @@ -840,32 +836,6 @@ static int vsc9953_reset(struct ocelot *ocelot) · 287 unmodified lines | |||
| 840 | return 0; | 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 | /* Watermark encode | 839 | /* Watermark encode |
| 870 | * Bit 9: Unit; 0:1, 1:16 | 840 | * Bit 9: Unit; 0:1, 1:16 |
| 871 | * Bit 8-0: Value to be multiplied with unit | 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 | .regfields = vsc9953_regfields, | 966 | .regfields = vsc9953_regfields, |
| 997 | .map = vsc9953_regmap, | 967 | .map = vsc9953_regmap, |
| 998 | .ops = &vsc9953_ops, | 968 | .ops = &vsc9953_ops, |
| 999 | .stats_layout = vsc9953_stats_layout, | ||
| 1000 | .vcap = vsc9953_vcap_props, | 969 | .vcap = vsc9953_vcap_props, |
| 1001 | .vcap_pol_base = VSC9953_VCAP_POLICER_BASE, | 970 | .vcap_pol_base = VSC9953_VCAP_POLICER_BASE, |
| 1002 | .vcap_pol_max = VSC9953_VCAP_POLICER_MAX, | 971 | .vcap_pol_max = VSC9953_VCAP_POLICER_MAX, |
| @@ -1007,7 +976,6 @@ static const struct felix_info seville_info_vsc9953 = { · 4 unmodified lines | |||
| 1007 | .num_tx_queues = OCELOT_NUM_TC, | 976 | .num_tx_queues = OCELOT_NUM_TC, |
| 1008 | .mdio_bus_alloc = vsc9953_mdio_bus_alloc, | 977 | .mdio_bus_alloc = vsc9953_mdio_bus_alloc, |
| 1009 | .mdio_bus_free = vsc9953_mdio_bus_free, | 978 | .mdio_bus_free = vsc9953_mdio_bus_free, |
| 1010 | .phylink_validate = vsc9953_phylink_validate, | ||
| 1011 | .port_modes = vsc9953_port_modes, | 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 | struct netlink_ext_ack *extack) | 122 | struct netlink_ext_ack *extack) |
| 123 | { | 123 | { |
| 124 | struct sja1105_private *priv = ds->priv; | 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, | 126 | return devlink_info_version_fixed_put(req, |
| 132 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, | 127 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, |
| 133 | priv->info->name); | 128 | priv->info->name); |
| 134 | return rc; | ||
| 135 | } | 129 | } |
| 136 | 130 | ||
| 137 | int sja1105_devlink_setup(struct dsa_switch *ds) | 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 | .val_format_endian = REGMAP_ENDIAN_BIG | 76 | .val_format_endian = REGMAP_ENDIAN_BIG |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | static int xrs700x_i2c_probe(struct i2c_client *i2c, | 79 | static int xrs700x_i2c_probe(struct i2c_client *i2c) |
| 80 | const struct i2c_device_id *i2c_id) | ||
| 81 | { | 80 | { |
| 82 | struct xrs700x *priv; | 81 | struct xrs700x *priv; |
| 83 | int ret; | 82 | int ret; |
| @@ -148,7 +147,7 @@ static struct i2c_driver xrs700x_i2c_driver = { · 64 unmodified lines | |||
| 148 | .name = "xrs700x-i2c", | 147 | .name = "xrs700x-i2c", |
| 149 | .of_match_table = of_match_ptr(xrs700x_i2c_dt_ids), | 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 | .remove = xrs700x_i2c_remove, | 151 | .remove = xrs700x_i2c_remove, |
| 153 | .shutdown = xrs700x_i2c_shutdown, | 152 | .shutdown = xrs700x_i2c_shutdown, |
| 154 | .id_table = xrs700x_i2c_id, | 153 | .id_table = xrs700x_i2c_id, |
| @@ -99,14 +99,7 @@ static const struct net_device_ops dummy_netdev_ops = { · 98 unmodified lines | |||
| 99 | .ndo_change_carrier = dummy_change_carrier, | 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 | static const struct ethtool_ops dummy_ethtool_ops = { | 102 | static const struct ethtool_ops dummy_ethtool_ops = { |
| 109 | .get_drvinfo = dummy_get_drvinfo, | ||
| 110 | .get_ts_info = ethtool_op_get_ts_info, | 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 | source "drivers/net/ethernet/microsoft/Kconfig" | 132 | source "drivers/net/ethernet/microsoft/Kconfig" |
| 133 | source "drivers/net/ethernet/moxa/Kconfig" | 133 | source "drivers/net/ethernet/moxa/Kconfig" |
| 134 | source "drivers/net/ethernet/myricom/Kconfig" | 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 | source "drivers/net/ethernet/ni/Kconfig" | 135 | source "drivers/net/ethernet/ni/Kconfig" |
| 146 | source "drivers/net/ethernet/natsemi/Kconfig" | 136 | source "drivers/net/ethernet/natsemi/Kconfig" |
| 147 | source "drivers/net/ethernet/neterion/Kconfig" | 137 | source "drivers/net/ethernet/neterion/Kconfig" |
| @@ -64,7 +64,6 @@ obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/ · 63 unmodified lines | |||
| 64 | obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/ | 64 | obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/ |
| 65 | obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/ | 65 | obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/ |
| 66 | obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/ | 66 | obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/ |
| 67 | obj-$(CONFIG_FEALNX) += fealnx.o | ||
| 68 | obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/ | 67 | obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/ |
| 69 | obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/ | 68 | obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/ |
| 70 | obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/ | 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 | u32 header_len = ADIN1110_RD_HEADER_LEN; | 197 | u32 header_len = ADIN1110_RD_HEADER_LEN; |
| 198 | u32 read_len = ADIN1110_REG_LEN; | 198 | u32 read_len = ADIN1110_REG_LEN; |
| 199 | struct spi_transfer t[2] = {0}; | 199 | struct spi_transfer t = {0}; |
| 200 | int ret; | 200 | int ret; |
| 201 | 201 | ||
| 202 | priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); | 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 | header_len++; | 209 | header_len++; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | t[0].tx_buf = &priv->data[0]; | ||
| 213 | t[0].len = header_len; | ||
| 214 | |||
| 215 | if (priv->append_crc) | 212 | if (priv->append_crc) |
| 216 | read_len++; | 213 | read_len++; |
| 217 | 214 | ||
| 218 | memset(&priv->data[header_len], 0, read_len); | 215 | memset(&priv->data[header_len], 0, read_len); |
| 219 | t[1].rx_buf = &priv->data[header_len]; | 216 | t.tx_buf = &priv->data[0]; |
| 220 | t[1].len = read_len; | 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 | if (ret) | 221 | if (ret) |
| 224 | return ret; | 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 | struct adin1110_priv *priv = port_priv->priv; | 295 | struct adin1110_priv *priv = port_priv->priv; |
| 298 | u32 header_len = ADIN1110_RD_HEADER_LEN; | 296 | u32 header_len = ADIN1110_RD_HEADER_LEN; |
| 299 | struct spi_transfer t[2] = {0}; | 297 | struct spi_transfer t; |
| 300 | u32 frame_size_no_fcs; | 298 | u32 frame_size_no_fcs; |
| 301 | struct sk_buff *rxb; | 299 | struct sk_buff *rxb; |
| 302 | u32 frame_size; | 300 | u32 frame_size; |
| @@ -327,12 +325,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) · 24 unmodified lines | |||
| 327 | return ret; | 325 | return ret; |
| 328 | 326 | ||
| 329 | frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; | 327 | frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN; |
| 330 | 328 | memset(priv->data, 0, ADIN1110_RD_HEADER_LEN); | |
| 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); | ||
| 336 | 329 | ||
| 337 | priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); | 330 | priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg); |
| 338 | priv->data[1] = FIELD_GET(GENMASK(7, 0), reg); | 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 | header_len++; | 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]; | 342 | skb_put(rxb, frame_size_no_fcs + header_len + ADIN1110_FRAME_HEADER_LEN); |
| 348 | t[0].len = header_len; | ||
| 349 | 343 | ||
| 350 | t[1].rx_buf = &rxb->data[0]; | 344 | t.tx_buf = &priv->data[0]; |
| 351 | t[1].len = round_len; | 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 | if (ret) { | 349 | if (ret) { |
| 355 | kfree_skb(rxb); | 350 | kfree_skb(rxb); |
| 356 | return ret; | 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 | rxb->protocol = eth_type_trans(rxb, port_priv->netdev); | 355 | rxb->protocol = eth_type_trans(rxb, port_priv->netdev); |
| 361 | 356 | ||
| 362 | if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) || | 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 | static int adin1110_check_spi(struct adin1110_priv *priv) | 1083 | static int adin1110_check_spi(struct adin1110_priv *priv) |
| 1089 | { | 1084 | { |
| 1085 | struct gpio_desc *reset_gpio; | ||
| 1090 | int ret; | 1086 | int ret; |
| 1091 | u32 val; | 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 | ret = adin1110_read_reg(priv, ADIN1110_PHY_ID, &val); | 1109 | ret = adin1110_read_reg(priv, ADIN1110_PHY_ID, &val); |
| 1094 | if (ret < 0) | 1110 | if (ret < 0) |
| 1095 | return ret; | 1111 | return ret; |
| @@ -288,13 +288,13 @@ do { \ · 287 unmodified lines | |||
| 288 | u64_stats_update_end(&(st)->syncp); \ | 288 | u64_stats_update_end(&(st)->syncp); \ |
| 289 | } while (0) | 289 | } while (0) |
| 290 | 290 | ||
| 291 | #define SLIC_GET_STATS_COUNTER(newst, st, counter) \ | 291 | #define SLIC_GET_STATS_COUNTER(newst, st, counter) \ |
| 292 | { \ | 292 | { \ |
| 293 | unsigned int start; \ | 293 | unsigned int start; \ |
| 294 | do { \ | 294 | do { \ |
| 295 | start = u64_stats_fetch_begin_irq(&(st)->syncp); \ | 295 | start = u64_stats_fetch_begin(&(st)->syncp); \ |
| 296 | newst = (st)->counter; \ | 296 | newst = (st)->counter; \ |
| 297 | } while (u64_stats_fetch_retry_irq(&(st)->syncp, start)); \ | 297 | } while (u64_stats_fetch_retry(&(st)->syncp, start)); \ |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | struct slic_upr { | 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 | static const struct phylink_mac_ops alt_tse_phylink_ops = { | 1098 | static const struct phylink_mac_ops alt_tse_phylink_ops = { |
| 1099 | .validate = phylink_generic_validate, | ||
| 1100 | .mac_an_restart = alt_tse_mac_an_restart, | 1099 | .mac_an_restart = alt_tse_mac_an_restart, |
| 1101 | .mac_config = alt_tse_mac_config, | 1100 | .mac_config = alt_tse_mac_config, |
| 1102 | .mac_link_down = alt_tse_mac_link_down, | 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 | unsigned int start; | 118 | unsigned int start; |
| 119 | 119 | ||
| 120 | do { | 120 | do { |
| 121 | start = u64_stats_fetch_begin_irq(syncp); | 121 | start = u64_stats_fetch_begin(syncp); |
| 122 | *(dst) = *src; | 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 | static void ena_queue_stats(struct ena_adapter *adapter, u64 **data) | 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 | tx_ring = &adapter->tx_ring[i]; | 3268 | tx_ring = &adapter->tx_ring[i]; |
| 3269 | 3269 | ||
| 3270 | do { | 3270 | do { |
| 3271 | start = u64_stats_fetch_begin_irq(&tx_ring->syncp); | 3271 | start = u64_stats_fetch_begin(&tx_ring->syncp); |
| 3272 | packets = tx_ring->tx_stats.cnt; | 3272 | packets = tx_ring->tx_stats.cnt; |
| 3273 | bytes = tx_ring->tx_stats.bytes; | 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 | stats->tx_packets += packets; | 3276 | stats->tx_packets += packets; |
| 3277 | stats->tx_bytes += bytes; | 3277 | stats->tx_bytes += bytes; |
| @@ -3279,20 +3279,20 @@ static void ena_get_stats64(struct net_device *netdev, · 1 unmodified line | |||
| 3279 | rx_ring = &adapter->rx_ring[i]; | 3279 | rx_ring = &adapter->rx_ring[i]; |
| 3280 | 3280 | ||
| 3281 | do { | 3281 | do { |
| 3282 | start = u64_stats_fetch_begin_irq(&rx_ring->syncp); | 3282 | start = u64_stats_fetch_begin(&rx_ring->syncp); |
| 3283 | packets = rx_ring->rx_stats.cnt; | 3283 | packets = rx_ring->rx_stats.cnt; |
| 3284 | bytes = rx_ring->rx_stats.bytes; | 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 | stats->rx_packets += packets; | 3287 | stats->rx_packets += packets; |
| 3288 | stats->rx_bytes += bytes; | 3288 | stats->rx_bytes += bytes; |
| 3289 | } | 3289 | } |
| 3290 | 3290 | ||
| 3291 | do { | 3291 | do { |
| 3292 | start = u64_stats_fetch_begin_irq(&adapter->syncp); | 3292 | start = u64_stats_fetch_begin(&adapter->syncp); |
| 3293 | rx_drops = adapter->dev_stats.rx_drops; | 3293 | rx_drops = adapter->dev_stats.rx_drops; |
| 3294 | tx_drops = adapter->dev_stats.tx_drops; | 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 | stats->rx_dropped = rx_drops; | 3297 | stats->rx_dropped = rx_drops; |
| 3298 | stats->tx_dropped = tx_drops; | 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 | lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); | 824 | lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); |
| 825 | head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; | 825 | head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; |
| 826 | dev->stats.tx_bytes += skb->len; | 826 | dev->stats.tx_bytes += skb->len; |
| 827 | dev_kfree_skb( skb ); | 827 | dev_consume_skb_irq(skb); |
| 828 | lp->cur_tx++; | 828 | lp->cur_tx++; |
| 829 | while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { | 829 | while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { |
| 830 | lp->cur_tx -= TX_RING_SIZE; | 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 | skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len); | 1001 | skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len); |
| 1002 | lp->tx_ring[entry].base = | 1002 | lp->tx_ring[entry].base = |
| 1003 | ((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000; | 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 | } else { | 1005 | } else { |
| 1006 | lp->tx_skbuff[entry] = skb; | 1006 | lp->tx_skbuff[entry] = skb; |
| 1007 | lp->tx_ring[entry].base = ((u32)isa_virt_to_bus(skb->data) & 0xffffff) | 0x83000000; | 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 | XGBE_SFP_CABLE_UNKNOWN = 0, | 189 | XGBE_SFP_CABLE_UNKNOWN = 0, |
| 190 | XGBE_SFP_CABLE_ACTIVE, | 190 | XGBE_SFP_CABLE_ACTIVE, |
| 191 | XGBE_SFP_CABLE_PASSIVE, | 191 | XGBE_SFP_CABLE_PASSIVE, |
| 192 | XGBE_SFP_CABLE_FIBER, | ||
| 192 | }; | 193 | }; |
| 193 | 194 | ||
| 194 | enum xgbe_sfp_base { | 195 | enum xgbe_sfp_base { |
| @@ -236,10 +237,7 @@ enum xgbe_sfp_speed { · 41 unmodified lines | |||
| 236 | 237 | ||
| 237 | #define XGBE_SFP_BASE_BR 12 | 238 | #define XGBE_SFP_BASE_BR 12 |
| 238 | #define XGBE_SFP_BASE_BR_1GBE_MIN 0x0a | 239 | #define XGBE_SFP_BASE_BR_1GBE_MIN 0x0a |
| 239 | #define XGBE_SFP_BASE_BR_1GBE_MAX 0x0d | ||
| 240 | #define XGBE_SFP_BASE_BR_10GBE_MIN 0x64 | 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 | #define XGBE_SFP_BASE_CU_CABLE_LEN 18 | 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 | static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, | 824 | static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, |
| 827 | enum xgbe_sfp_speed sfp_speed) | 825 | enum xgbe_sfp_speed sfp_speed) |
| 828 | { | 826 | { |
| 829 | u8 *sfp_base, min, max; | 827 | u8 *sfp_base, min; |
| 830 | 828 | ||
| 831 | sfp_base = sfp_eeprom->base; | 829 | sfp_base = sfp_eeprom->base; |
| 832 | 830 | ||
| 833 | switch (sfp_speed) { | 831 | switch (sfp_speed) { |
| 834 | case XGBE_SFP_SPEED_1000: | 832 | case XGBE_SFP_SPEED_1000: |
| 835 | min = XGBE_SFP_BASE_BR_1GBE_MIN; | 833 | min = XGBE_SFP_BASE_BR_1GBE_MIN; |
| 836 | max = XGBE_SFP_BASE_BR_1GBE_MAX; | ||
| 837 | break; | 834 | break; |
| 838 | case XGBE_SFP_SPEED_10000: | 835 | case XGBE_SFP_SPEED_10000: |
| 839 | min = XGBE_SFP_BASE_BR_10GBE_MIN; | 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 | break; | 837 | break; |
| 846 | default: | 838 | default: |
| 847 | return false; | 839 | return false; |
| 848 | } | 840 | } |
| 849 | 841 | ||
| 850 | return ((sfp_base[XGBE_SFP_BASE_BR] >= min) && | 842 | return sfp_base[XGBE_SFP_BASE_BR] >= min; |
| 851 | (sfp_base[XGBE_SFP_BASE_BR] <= max)); | ||
| 852 | } | 843 | } |
| 853 | 844 | ||
| 854 | static void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) | 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 | phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data); | 1140 | phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data); |
| 1150 | phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data); | 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 | if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) { | 1144 | if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) { |
| 1154 | phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE; | 1145 | phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE; |
| 1155 | phy_data->sfp_cable_len = sfp_base[XGBE_SFP_BASE_CU_CABLE_LEN]; | 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 | phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE; | 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 | /* Determine the type of SFP */ | 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 | xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) | 1155 | xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) |
| 1163 | phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; | 1156 | phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; |
| 1164 | else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) | 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 | return nsec; | 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 | struct xgbe_prv_data *pdata = container_of(info, | 139 | struct xgbe_prv_data *pdata = container_of(info, |
| 140 | struct xgbe_prv_data, | 140 | struct xgbe_prv_data, |
| 141 | ptp_clock_info); | 141 | ptp_clock_info); |
| 142 | unsigned long flags; | 142 | unsigned long flags; |
| 143 | u64 adjust; | 143 | u64 addend; |
| 144 | u32 addend, diff; | ||
| 145 | unsigned int neg_adjust = 0; | ||
| 146 | 144 | ||
| 147 | if (delta < 0) { | 145 | addend = adjust_by_scaled_ppm(pdata->tstamp_addend, scaled_ppm); |
| 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; | ||
| 158 | 146 | ||
| 159 | spin_lock_irqsave(&pdata->tstamp_lock, flags); | 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 | netdev_name(pdata->netdev)); | 223 | netdev_name(pdata->netdev)); |
| 236 | info->owner = THIS_MODULE; | 224 | info->owner = THIS_MODULE; |
| 237 | info->max_adj = pdata->ptpclk_rate; | 225 | info->max_adj = pdata->ptpclk_rate; |
| 238 | info->adjfreq = xgbe_adjfreq; | 226 | info->adjfine = xgbe_adjfine; |
| 239 | info->adjtime = xgbe_adjtime; | 227 | info->adjtime = xgbe_adjtime; |
| 240 | info->gettime64 = xgbe_gettime; | 228 | info->gettime64 = xgbe_gettime; |
| 241 | info->settime64 = xgbe_settime; | 229 | info->settime64 = xgbe_settime; |
| @@ -1510,7 +1510,7 @@ static void bmac_tx_timeout(struct timer_list *t) · 1509 unmodified lines | |||
| 1510 | i = bp->tx_empty; | 1510 | i = bp->tx_empty; |
| 1511 | ++dev->stats.tx_errors; | 1511 | ++dev->stats.tx_errors; |
| 1512 | if (i != bp->tx_fill) { | 1512 | if (i != bp->tx_fill) { |
| 1513 | dev_kfree_skb(bp->tx_bufs[i]); | 1513 | dev_kfree_skb_irq(bp->tx_bufs[i]); |
| 1514 | bp->tx_bufs[i] = NULL; | 1514 | bp->tx_bufs[i] = NULL; |
| 1515 | if (++i >= N_TX_RING) i = 0; | 1515 | if (++i >= N_TX_RING) i = 0; |
| 1516 | bp->tx_empty = i; | 1516 | bp->tx_empty = i; |
| @@ -846,7 +846,7 @@ static void mace_tx_timeout(struct timer_list *t) · 845 unmodified lines | |||
| 846 | if (mp->tx_bad_runt) { | 846 | if (mp->tx_bad_runt) { |
| 847 | mp->tx_bad_runt = 0; | 847 | mp->tx_bad_runt = 0; |
| 848 | } else if (i != mp->tx_fill) { | 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 | if (++i >= N_TX_RING) | 850 | if (++i >= N_TX_RING) |
| 851 | i = 0; | 851 | i = 0; |
| 852 | mp->tx_empty = i; | 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 | /* This data should mimic aq_ethtool_queue_rx_stat_names structure */ | 934 | /* This data should mimic aq_ethtool_queue_rx_stat_names structure */ |
| 935 | do { | 935 | do { |
| 936 | count = 0; | 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 | data[count] = self->stats.rx.packets; | 938 | data[count] = self->stats.rx.packets; |
| 939 | data[++count] = self->stats.rx.jumbo_packets; | 939 | data[++count] = self->stats.rx.jumbo_packets; |
| 940 | data[++count] = self->stats.rx.lro_packets; | 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 | data[++count] = self->stats.rx.xdp_tx; | 951 | data[++count] = self->stats.rx.xdp_tx; |
| 952 | data[++count] = self->stats.rx.xdp_invalid; | 952 | data[++count] = self->stats.rx.xdp_invalid; |
| 953 | data[++count] = self->stats.rx.xdp_redirect; | 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 | } else { | 955 | } else { |
| 956 | /* This data should mimic aq_ethtool_queue_tx_stat_names structure */ | 956 | /* This data should mimic aq_ethtool_queue_tx_stat_names structure */ |
| 957 | do { | 957 | do { |
| 958 | count = 0; | 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 | data[count] = self->stats.tx.packets; | 960 | data[count] = self->stats.tx.packets; |
| 961 | data[++count] = self->stats.tx.queue_restarts; | 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 | return ++count; | 965 | return ++count; |
| @@ -662,12 +662,12 @@ static void ax88796c_get_stats64(struct net_device *ndev, · 661 unmodified lines | |||
| 662 | s = per_cpu_ptr(ax_local->stats, cpu); | 662 | s = per_cpu_ptr(ax_local->stats, cpu); |
| 663 | 663 | ||
| 664 | do { | 664 | do { |
| 665 | start = u64_stats_fetch_begin_irq(&s->syncp); | 665 | start = u64_stats_fetch_begin(&s->syncp); |
| 666 | rx_packets = u64_stats_read(&s->rx_packets); | 666 | rx_packets = u64_stats_read(&s->rx_packets); |
| 667 | rx_bytes = u64_stats_read(&s->rx_bytes); | 667 | rx_bytes = u64_stats_read(&s->rx_bytes); |
| 668 | tx_packets = u64_stats_read(&s->tx_packets); | 668 | tx_packets = u64_stats_read(&s->tx_packets); |
| 669 | tx_bytes = u64_stats_read(&s->tx_bytes); | 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 | stats->rx_packets += rx_packets; | 672 | stats->rx_packets += rx_packets; |
| 673 | stats->rx_bytes += rx_bytes; | 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 | static const struct phylink_mac_ops ag71xx_phylink_mac_ops = { | 1088 | static const struct phylink_mac_ops ag71xx_phylink_mac_ops = { |
| 1089 | .validate = phylink_generic_validate, | ||
| 1090 | .mac_config = ag71xx_mac_config, | 1089 | .mac_config = ag71xx_mac_config, |
| 1091 | .mac_link_down = ag71xx_mac_link_down, | 1090 | .mac_link_down = ag71xx_mac_link_down, |
| 1092 | .mac_link_up = ag71xx_mac_link_up, | 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 | unsigned int start; | 1680 | unsigned int start; |
| 1681 | 1681 | ||
| 1682 | do { | 1682 | do { |
| 1683 | start = u64_stats_fetch_begin_irq(&hwstat->syncp); | 1683 | start = u64_stats_fetch_begin(&hwstat->syncp); |
| 1684 | 1684 | ||
| 1685 | /* Convert HW stats into rtnl_link_stats64 stats. */ | 1685 | /* Convert HW stats into rtnl_link_stats64 stats. */ |
| 1686 | nstat->rx_packets = hwstat->rx_pkts; | 1686 | nstat->rx_packets = hwstat->rx_pkts; |
| @@ -1714,7 +1714,7 @@ static void b44_get_stats64(struct net_device *dev, · 27 unmodified lines | |||
| 1714 | /* Carrier lost counter seems to be broken for some devices */ | 1714 | /* Carrier lost counter seems to be broken for some devices */ |
| 1715 | nstat->tx_carrier_errors = hwstat->tx_carrier_lost; | 1715 | nstat->tx_carrier_errors = hwstat->tx_carrier_lost; |
| 1716 | #endif | 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 | do { | 2082 | do { |
| 2083 | data_src = &hwstat->tx_good_octets; | 2083 | data_src = &hwstat->tx_good_octets; |
| 2084 | data_dst = data; | 2084 | data_dst = data; |
| 2085 | start = u64_stats_fetch_begin_irq(&hwstat->syncp); | 2085 | start = u64_stats_fetch_begin(&hwstat->syncp); |
| 2086 | 2086 | ||
| 2087 | for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) | 2087 | for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) |
| 2088 | *data_dst++ = *data_src++; | 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 | static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | 2093 | static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
| @@ -36,13 +36,24 @@ · 35 unmodified lines | |||
| 36 | #define ENET_MAX_ETH_OVERHEAD (ETH_HLEN + BRCM_MAX_TAG_LEN + VLAN_HLEN + \ | 36 | #define ENET_MAX_ETH_OVERHEAD (ETH_HLEN + BRCM_MAX_TAG_LEN + VLAN_HLEN + \ |
| 37 | ETH_FCS_LEN + 4) /* 32 */ | 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 | struct bcm4908_enet_dma_ring_bd { | 47 | struct bcm4908_enet_dma_ring_bd { |
| 40 | __le32 ctl; | 48 | __le32 ctl; |
| 41 | __le32 addr; | 49 | __le32 addr; |
| 42 | } __packed; | 50 | } __packed; |
| 43 | 51 | ||
| 44 | struct bcm4908_enet_dma_ring_slot { | 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 | unsigned int len; | 57 | unsigned int len; |
| 47 | dma_addr_t dma_addr; | 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 | u32 tmp; | 271 | u32 tmp; |
| 261 | int err; | 272 | int err; |
| 262 | 273 | ||
| 263 | slot->len = ENET_MTU_MAX + ENET_MAX_ETH_OVERHEAD; | 274 | slot->buf = napi_alloc_frag(ENET_RX_SKB_BUF_ALLOC_SIZE); |
| 264 | 275 | if (!slot->buf) | |
| 265 | slot->skb = netdev_alloc_skb(enet->netdev, slot->len); | ||
| 266 | if (!slot->skb) | ||
| 267 | return -ENOMEM; | 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 | err = dma_mapping_error(dev, slot->dma_addr); | 280 | err = dma_mapping_error(dev, slot->dma_addr); |
| 271 | if (err) { | 281 | if (err) { |
| 272 | dev_err(dev, "Failed to map DMA buffer: %d\n", err); | 282 | dev_err(dev, "Failed to map DMA buffer: %d\n", err); |
| 273 | kfree_skb(slot->skb); | 283 | skb_free_frag(slot->buf); |
| 274 | slot->skb = NULL; | 284 | slot->buf = NULL; |
| 275 | return err; | 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 | tmp |= DMA_CTL_STATUS_OWN; | 289 | tmp |= DMA_CTL_STATUS_OWN; |
| 280 | if (idx == enet->rx_ring.length - 1) | 290 | if (idx == enet->rx_ring.length - 1) |
| 281 | tmp |= DMA_CTL_STATUS_WRAP; | 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 | for (i = rx_ring->length - 1; i >= 0; i--) { | 326 | for (i = rx_ring->length - 1; i >= 0; i--) { |
| 317 | slot = &rx_ring->slots[i]; | 327 | slot = &rx_ring->slots[i]; |
| 318 | if (!slot->skb) | 328 | if (!slot->buf) |
| 319 | continue; | 329 | continue; |
| 320 | dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE); | 330 | dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE); |
| 321 | kfree_skb(slot->skb); | 331 | skb_free_frag(slot->buf); |
| 322 | slot->skb = NULL; | 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 | netif_carrier_off(netdev); | 505 | netif_carrier_off(netdev); |
| 496 | napi_disable(&rx_ring->napi); | 506 | napi_disable(&rx_ring->napi); |
| 497 | napi_disable(&tx_ring->napi); | 507 | napi_disable(&tx_ring->napi); |
| 508 | netdev_reset_queue(netdev); | ||
| 498 | 509 | ||
| 499 | bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring); | 510 | bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring); |
| 500 | bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring); | 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 | if (ring->write_idx + 1 == ring->length - 1) | 565 | if (ring->write_idx + 1 == ring->length - 1) |
| 555 | tmp |= DMA_CTL_STATUS_WRAP; | 566 | tmp |= DMA_CTL_STATUS_WRAP; |
| 556 | 567 | ||
| 568 | netdev_sent_queue(enet->netdev, skb->len); | ||
| 569 | |||
| 557 | buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr); | 570 | buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr); |
| 558 | buf_desc->ctl = cpu_to_le32(tmp); | 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 | while (handled < weight) { | 588 | while (handled < weight) { |
| 576 | struct bcm4908_enet_dma_ring_bd *buf_desc; | 589 | struct bcm4908_enet_dma_ring_bd *buf_desc; |
| 577 | struct bcm4908_enet_dma_ring_slot slot; | 590 | struct bcm4908_enet_dma_ring_slot slot; |
| 591 | struct sk_buff *skb; | ||
| 578 | u32 ctl; | 592 | u32 ctl; |
| 579 | int len; | 593 | int len; |
| 580 | int err; | 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 | if (len < ETH_ZLEN || | 613 | if (len < ETH_ZLEN || |
| 600 | (ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) { | 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 | enet->netdev->stats.rx_dropped++; | 616 | enet->netdev->stats.rx_dropped++; |
| 603 | break; | 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); | 632 | netif_receive_skb(skb); |
| 609 | slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev); | ||
| 610 | netif_receive_skb(slot.skb); | ||
| 611 | 633 | ||
| 612 | enet->netdev->stats.rx_packets++; | 634 | enet->netdev->stats.rx_packets++; |
| 613 | enet->netdev->stats.rx_bytes += len; | 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 | tx_ring->read_idx = 0; | 674 | tx_ring->read_idx = 0; |
| 653 | } | 675 | } |
| 654 | 676 | ||
| 677 | netdev_completed_queue(enet->netdev, handled, bytes); | ||
| 655 | enet->netdev->stats.tx_packets += handled; | 678 | enet->netdev->stats.tx_packets += handled; |
| 656 | enet->netdev->stats.tx_bytes += bytes; | 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 | /* RBUF misc statistics */ | 295 | /* RBUF misc statistics */ |
| 296 | STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR), | 296 | STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR), |
| 297 | STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR), | 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 | STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), | 300 | STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), |
| 299 | STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed), | 301 | STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed), |
| 300 | STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed), | 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 | case BCM_SYSPORT_STAT_NETDEV64: | 335 | case BCM_SYSPORT_STAT_NETDEV64: |
| 334 | case BCM_SYSPORT_STAT_RXCHK: | 336 | case BCM_SYSPORT_STAT_RXCHK: |
| 335 | case BCM_SYSPORT_STAT_RBUF: | 337 | case BCM_SYSPORT_STAT_RBUF: |
| 338 | case BCM_SYSPORT_STAT_RDMA: | ||
| 336 | case BCM_SYSPORT_STAT_SOFT: | 339 | case BCM_SYSPORT_STAT_SOFT: |
| 337 | return true; | 340 | return true; |
| 338 | default: | 341 | default: |
| @@ -436,6 +439,14 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv) · 97 unmodified lines | |||
| 436 | if (val == ~0) | 439 | if (val == ~0) |
| 437 | rbuf_writel(priv, 0, s->reg_offset); | 440 | rbuf_writel(priv, 0, s->reg_offset); |
| 438 | break; | 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 | j += s->stat_sizeof; | 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 | for (q = 0; q < priv->netdev->num_tx_queues; q++) { | 468 | for (q = 0; q < priv->netdev->num_tx_queues; q++) { |
| 458 | ring = &priv->tx_rings[q]; | 469 | ring = &priv->tx_rings[q]; |
| 459 | do { | 470 | do { |
| 460 | start = u64_stats_fetch_begin_irq(&priv->syncp); | 471 | start = u64_stats_fetch_begin(&priv->syncp); |
| 461 | bytes = ring->bytes; | 472 | bytes = ring->bytes; |
| 462 | packets = ring->packets; | 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 | *tx_bytes += bytes; | 476 | *tx_bytes += bytes; |
| 466 | *tx_packets += packets; | 477 | *tx_packets += packets; |
| @@ -504,9 +515,9 @@ static void bcm_sysport_get_stats(struct net_device *dev, · 37 unmodified lines | |||
| 504 | if (s->stat_sizeof == sizeof(u64) && | 515 | if (s->stat_sizeof == sizeof(u64) && |
| 505 | s->type == BCM_SYSPORT_STAT_NETDEV64) { | 516 | s->type == BCM_SYSPORT_STAT_NETDEV64) { |
| 506 | do { | 517 | do { |
| 507 | start = u64_stats_fetch_begin_irq(syncp); | 518 | start = u64_stats_fetch_begin(syncp); |
| 508 | data[i] = *(u64 *)p; | 519 | data[i] = *(u64 *)p; |
| 509 | } while (u64_stats_fetch_retry_irq(syncp, start)); | 520 | } while (u64_stats_fetch_retry(syncp, start)); |
| 510 | } else | 521 | } else |
| 511 | data[i] = *(u32 *)p; | 522 | data[i] = *(u32 *)p; |
| 512 | j++; | 523 | j++; |
| @@ -1878,10 +1889,10 @@ static void bcm_sysport_get_stats64(struct net_device *dev, · 1365 unmodified lines | |||
| 1878 | &stats->tx_packets); | 1889 | &stats->tx_packets); |
| 1879 | 1890 | ||
| 1880 | do { | 1891 | do { |
| 1881 | start = u64_stats_fetch_begin_irq(&priv->syncp); | 1892 | start = u64_stats_fetch_begin(&priv->syncp); |
| 1882 | stats->rx_packets = stats64->rx_packets; | 1893 | stats->rx_packets = stats64->rx_packets; |
| 1883 | stats->rx_bytes = stats64->rx_bytes; | 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 | static void bcm_sysport_netif_start(struct net_device *dev) | 1898 | static void bcm_sysport_netif_start(struct net_device *dev) |
| @@ -290,6 +290,7 @@ struct bcm_rsb { · 289 unmodified lines | |||
| 290 | 290 | ||
| 291 | #define RDMA_WRITE_PTR_HI 0x1010 | 291 | #define RDMA_WRITE_PTR_HI 0x1010 |
| 292 | #define RDMA_WRITE_PTR_LO 0x1014 | 292 | #define RDMA_WRITE_PTR_LO 0x1014 |
| 293 | #define RDMA_OVFL_DISC_CNTR 0x1018 | ||
| 293 | #define RDMA_PROD_INDEX 0x1018 | 294 | #define RDMA_PROD_INDEX 0x1018 |
| 294 | #define RDMA_PROD_INDEX_MASK 0xffff | 295 | #define RDMA_PROD_INDEX_MASK 0xffff |
| 295 | 296 | ||
| @@ -565,6 +566,7 @@ struct bcm_sysport_mib { · 269 unmodified lines | |||
| 565 | u32 rxchk_other_pkt_disc; | 566 | u32 rxchk_other_pkt_disc; |
| 566 | u32 rbuf_ovflow_cnt; | 567 | u32 rbuf_ovflow_cnt; |
| 567 | u32 rbuf_err_cnt; | 568 | u32 rbuf_err_cnt; |
| 569 | u32 rdma_ovflow_cnt; | ||
| 568 | u32 alloc_rx_buff_failed; | 570 | u32 alloc_rx_buff_failed; |
| 569 | u32 rx_dma_failed; | 571 | u32 rx_dma_failed; |
| 570 | u32 tx_dma_failed; | 572 | u32 tx_dma_failed; |
| @@ -581,6 +583,7 @@ enum bcm_sysport_stat_type { · 10 unmodified lines | |||
| 581 | BCM_SYSPORT_STAT_RUNT, | 583 | BCM_SYSPORT_STAT_RUNT, |
| 582 | BCM_SYSPORT_STAT_RXCHK, | 584 | BCM_SYSPORT_STAT_RXCHK, |
| 583 | BCM_SYSPORT_STAT_RBUF, | 585 | BCM_SYSPORT_STAT_RBUF, |
| 586 | BCM_SYSPORT_STAT_RDMA, | ||
| 584 | BCM_SYSPORT_STAT_SOFT, | 587 | BCM_SYSPORT_STAT_SOFT, |
| 585 | }; | 588 | }; |
| 586 | 589 | ||
| @@ -627,6 +630,14 @@ enum bcm_sysport_stat_type { · 40 unmodified lines | |||
| 627 | .reg_offset = ofs, \ | 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 | /* TX bytes and packets */ | 641 | /* TX bytes and packets */ |
| 631 | #define NUM_SYSPORT_TXQ_STAT 2 | 642 | #define NUM_SYSPORT_TXQ_STAT 2 |
| 632 | 643 | ||
| @@ -3045,7 +3045,7 @@ error: · 3044 unmodified lines | |||
| 3045 | 3045 | ||
| 3046 | dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, | 3046 | dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, |
| 3047 | DMA_FROM_DEVICE); | 3047 | DMA_FROM_DEVICE); |
| 3048 | skb = build_skb(data, 0); | 3048 | skb = slab_build_skb(data); |
| 3049 | if (!skb) { | 3049 | if (!skb) { |
| 3050 | kfree(data); | 3050 | kfree(data); |
| 3051 | goto error; | 3051 | goto error; |
| @@ -5415,8 +5415,9 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) · 2363 unmodified lines | |||
| 5415 | 5415 | ||
| 5416 | bp->rx_buf_use_size = rx_size; | 5416 | bp->rx_buf_use_size = rx_size; |
| 5417 | /* hw alignment + build_skb() overhead*/ | 5417 | /* hw alignment + build_skb() overhead*/ |
| 5418 | bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) + | 5418 | bp->rx_buf_size = kmalloc_size_roundup( |
| 5419 | NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); | 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 | bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; | 5421 | bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; |
| 5421 | bp->rx_ring_size = size; | 5422 | bp->rx_ring_size = size; |
| 5422 | bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS); | 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 | return bnx2x_func_state_change(bp, &func_params); | 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 | struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info); | 13676 | struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info); |
| 13677 | int rc; | 13677 | int rc; |
| 13678 | int drift_dir = 1; | 13678 | int drift_dir = 1; |
| 13679 | int val, period, period1, period2, dif, dif1, dif2; | 13679 | int val, period, period1, period2, dif, dif1, dif2; |
| 13680 | int best_dif = BNX2X_MAX_PHC_DRIFT, best_period = 0, best_val = 0; | 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 | if (!netif_running(bp->dev)) { | 13685 | if (!netif_running(bp->dev)) { |
| 13685 | DP(BNX2X_MSG_PTP, | 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 | return -ENETDOWN; | 13688 | return -ENETDOWN; |
| 13688 | } | 13689 | } |
| 13689 | 13690 | ||
| @@ -13818,7 +13819,7 @@ void bnx2x_register_phc(struct bnx2x *bp) · 128 unmodified lines | |||
| 13818 | bp->ptp_clock_info.n_ext_ts = 0; | 13819 | bp->ptp_clock_info.n_ext_ts = 0; |
| 13819 | bp->ptp_clock_info.n_per_out = 0; | 13820 | bp->ptp_clock_info.n_per_out = 0; |
| 13820 | bp->ptp_clock_info.pps = 0; | 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 | bp->ptp_clock_info.adjtime = bnx2x_ptp_adjtime; | 13823 | bp->ptp_clock_info.adjtime = bnx2x_ptp_adjtime; |
| 13823 | bp->ptp_clock_info.gettime64 = bnx2x_ptp_gettime; | 13824 | bp->ptp_clock_info.gettime64 = bnx2x_ptp_gettime; |
| 13824 | bp->ptp_clock_info.settime64 = bnx2x_ptp_settime; | 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 | return NETDEV_TX_BUSY; | 389 | return NETDEV_TX_BUSY; |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | if (unlikely(ipv6_hopopt_jumbo_remove(skb))) | ||
| 393 | goto tx_free; | ||
| 394 | |||
| 392 | length = skb->len; | 395 | length = skb->len; |
| 393 | len = skb_headlen(skb); | 396 | len = skb_headlen(skb); |
| 394 | last_frag = skb_shinfo(skb)->nr_frags; | 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 | return 1; | 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 | bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG); | 5258 | bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG); |
| 5256 | u16 i, j; | 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, | 5269 | static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, |
| 5267 | struct bnxt_vnic_info *vnic) | 5270 | struct bnxt_vnic_info *vnic) |
| 5268 | { | 5271 | { |
| 5269 | __le16 *ring_tbl = vnic->rss_table; | 5272 | __le16 *ring_tbl = vnic->rss_table; |
| 5270 | struct bnxt_rx_ring_info *rxr; | 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 | if (bp->flags & BNXT_FLAG_CHIP_P5) | 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 | else | 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 | static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) | 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 | if (rc) | 5325 | if (rc) |
| 5308 | return rc; | 5326 | return rc; |
| 5309 | 5327 | ||
| 5310 | if (set_rss) { | 5328 | if (set_rss) |
| 5311 | bnxt_fill_hw_rss_tbl(bp, vnic); | 5329 | __bnxt_hwrm_vnic_set_rss(bp, req, 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 | } | ||
| 5318 | req->rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[0]); | 5330 | req->rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[0]); |
| 5319 | return hwrm_req_send(bp, req); | 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 | if (!set_rss) | 5347 | if (!set_rss) |
| 5336 | return hwrm_req_send(bp, req); | 5348 | return hwrm_req_send(bp, req); |
| 5337 | 5349 | ||
| 5338 | bnxt_fill_hw_rss_tbl(bp, vnic); | 5350 | __bnxt_hwrm_vnic_set_rss(bp, req, 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); | ||
| 5342 | ring_tbl_map = vnic->rss_table_dma_addr; | 5351 | ring_tbl_map = vnic->rss_table_dma_addr; |
| 5343 | nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings); | 5352 | nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings); |
| 5344 | 5353 | ||
| @@ -5357,6 +5366,25 @@ exit: · 12 unmodified lines | |||
| 5357 | return rc; | 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 | static int bnxt_hwrm_vnic_set_hds(struct bnxt *bp, u16 vnic_id) | 5388 | static int bnxt_hwrm_vnic_set_hds(struct bnxt *bp, u16 vnic_id) |
| 5361 | { | 5389 | { |
| 5362 | struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; | 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 | (BNXT_CHIP_P5_THOR(bp) && | 5642 | (BNXT_CHIP_P5_THOR(bp) && |
| 5615 | !(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED))) | 5643 | !(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED))) |
| 5616 | bp->fw_cap |= BNXT_FW_CAP_VLAN_RX_STRIP; | 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 | bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported); | 5647 | bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported); |
| 5618 | if (bp->max_tpa_v2) { | 5648 | if (bp->max_tpa_v2) { |
| 5619 | if (BNXT_CHIP_P5_THOR(bp)) | 5649 | if (BNXT_CHIP_P5_THOR(bp)) |
| @@ -6958,8 +6988,11 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) · 1338 unmodified lines | |||
| 6958 | if (flags & FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED) | 6988 | if (flags & FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED) |
| 6959 | bp->fw_cap |= BNXT_FW_CAP_DCBX_AGENT; | 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 | bp->flags |= BNXT_FLAG_MULTI_HOST; | 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 | if (flags & FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED) | 6996 | if (flags & FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED) |
| 6964 | bp->fw_cap |= BNXT_FW_CAP_RING_MONITOR; | 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 | rc = bnxt_setup_vnic(bp, 0); | 8841 | rc = bnxt_setup_vnic(bp, 0); |
| 8809 | if (rc) | 8842 | if (rc) |
| 8810 | goto err_out; | 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 | if (bp->flags & BNXT_FLAG_RFS) { | 8847 | if (bp->flags & BNXT_FLAG_RFS) { |
| 8813 | rc = bnxt_alloc_rfs_vnics(bp); | 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 | u8 **nextp) | 11318 | u8 **nextp) |
| 11284 | { | 11319 | { |
| 11285 | struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + nw_off); | 11320 | struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + nw_off); |
| 11321 | struct hop_jumbo_hdr *jhdr; | ||
| 11286 | int hdr_count = 0; | 11322 | int hdr_count = 0; |
| 11287 | u8 *nexthdr; | 11323 | u8 *nexthdr; |
| 11288 | int start; | 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 | if (hdrlen > 64) | 11347 | if (hdrlen > 64) |
| 11312 | return false; | 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 | nexthdr = &hp->nexthdr; | 11368 | nexthdr = &hp->nexthdr; |
| 11314 | start += hdrlen; | 11369 | start += hdrlen; |
| 11315 | hdr_count++; | ||
| 11316 | } | 11370 | } |
| 11317 | if (nextp) { | 11371 | if (nextp) { |
| 11318 | /* Caller will check inner protocol */ | 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 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | | 12306 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | |
| 12253 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | | 12307 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | |
| 12254 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; | 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 | if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { | 12311 | if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { |
| 12256 | bp->flags |= BNXT_FLAG_UDP_RSS_CAP; | 12312 | bp->flags |= BNXT_FLAG_UDP_RSS_CAP; |
| 12257 | bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 | | 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 | return 0; | 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 | static const struct net_device_ops bnxt_netdev_ops = { | 13141 | static const struct net_device_ops bnxt_netdev_ops = { |
| 13093 | .ndo_open = bnxt_open, | 13142 | .ndo_open = bnxt_open, |
| 13094 | .ndo_start_xmit = bnxt_start_xmit, | 13143 | .ndo_start_xmit = bnxt_start_xmit, |
| @@ -13120,7 +13169,6 @@ static const struct net_device_ops bnxt_netdev_ops = { · 25 unmodified lines | |||
| 13120 | .ndo_xdp_xmit = bnxt_xdp_xmit, | 13169 | .ndo_xdp_xmit = bnxt_xdp_xmit, |
| 13121 | .ndo_bridge_getlink = bnxt_bridge_getlink, | 13170 | .ndo_bridge_getlink = bnxt_bridge_getlink, |
| 13122 | .ndo_bridge_setlink = bnxt_bridge_setlink, | 13171 | .ndo_bridge_setlink = bnxt_bridge_setlink, |
| 13123 | .ndo_get_devlink_port = bnxt_get_devlink_port, | ||
| 13124 | }; | 13172 | }; |
| 13125 | 13173 | ||
| 13126 | static void bnxt_remove_one(struct pci_dev *pdev) | 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 | if (BNXT_PF(bp)) | 13179 | if (BNXT_PF(bp)) |
| 13132 | bnxt_sriov_disable(bp); | 13180 | bnxt_sriov_disable(bp); |
| 13133 | 13181 | ||
| 13134 | if (BNXT_PF(bp)) | ||
| 13135 | devlink_port_type_clear(&bp->dl_port); | ||
| 13136 | |||
| 13137 | bnxt_ptp_clear(bp); | 13182 | bnxt_ptp_clear(bp); |
| 13138 | pci_disable_pcie_error_reporting(pdev); | 13183 | pci_disable_pcie_error_reporting(pdev); |
| 13139 | unregister_netdev(dev); | 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 | return -ENOMEM; | 13591 | return -ENOMEM; |
| 13547 | 13592 | ||
| 13548 | bp = netdev_priv(dev); | 13593 | bp = netdev_priv(dev); |
| 13594 | SET_NETDEV_DEVLINK_PORT(dev, &bp->dl_port); | ||
| 13549 | bp->board_idx = ent->driver_data; | 13595 | bp->board_idx = ent->driver_data; |
| 13550 | bp->msg_enable = BNXT_DEF_MSG_ENABLE; | 13596 | bp->msg_enable = BNXT_DEF_MSG_ENABLE; |
| 13551 | bnxt_set_max_func_irqs(bp, max_irqs); | 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 | dev->features &= ~NETIF_F_LRO; | 13679 | dev->features &= ~NETIF_F_LRO; |
| 13634 | dev->priv_flags |= IFF_UNICAST_FLT; | 13680 | dev->priv_flags |= IFF_UNICAST_FLT; |
| 13635 | 13681 | ||
| 13682 | netif_set_tso_max_size(dev, GSO_MAX_SIZE); | ||
| 13683 | |||
| 13636 | #ifdef CONFIG_BNXT_SRIOV | 13684 | #ifdef CONFIG_BNXT_SRIOV |
| 13637 | init_waitqueue_head(&bp->sriov_cfg_wait); | 13685 | init_waitqueue_head(&bp->sriov_cfg_wait); |
| 13638 | #endif | 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 | if (rc) | 13769 | if (rc) |
| 13722 | goto init_err_cleanup; | 13770 | goto init_err_cleanup; |
| 13723 | 13771 | ||
| 13724 | if (BNXT_PF(bp)) | ||
| 13725 | devlink_port_type_eth_set(&bp->dl_port, bp->dev); | ||
| 13726 | bnxt_dl_fw_reporters_create(bp); | 13772 | bnxt_dl_fw_reporters_create(bp); |
| 13727 | 13773 | ||
| 13728 | bnxt_print_device_info(bp); | 13774 | bnxt_print_device_info(bp); |
| @@ -1901,6 +1901,7 @@ struct bnxt { · 1900 unmodified lines | |||
| 1901 | u16 *rss_indir_tbl; | 1901 | u16 *rss_indir_tbl; |
| 1902 | u16 rss_indir_tbl_entries; | 1902 | u16 rss_indir_tbl_entries; |
| 1903 | u32 rss_hash_cfg; | 1903 | u32 rss_hash_cfg; |
| 1904 | u32 rss_hash_delta; | ||
| 1904 | 1905 | ||
| 1905 | u16 max_mtu; | 1906 | u16 max_mtu; |
| 1906 | u8 max_tc; | 1907 | u8 max_tc; |
| @@ -1966,6 +1967,7 @@ struct bnxt { · 59 unmodified lines | |||
| 1966 | #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 0x00010000 | 1967 | #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 0x00010000 |
| 1967 | #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED 0x00020000 | 1968 | #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED 0x00020000 |
| 1968 | #define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000 | 1969 | #define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000 |
| 1970 | #define BNXT_FW_CAP_RSS_HASH_TYPE_DELTA 0x00080000 | ||
| 1969 | #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000 | 1971 | #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000 |
| 1970 | #define BNXT_FW_CAP_HOT_RESET 0x00200000 | 1972 | #define BNXT_FW_CAP_HOT_RESET 0x00200000 |
| 1971 | #define BNXT_FW_CAP_PTP_RTC 0x00400000 | 1973 | #define BNXT_FW_CAP_PTP_RTC 0x00400000 |
| @@ -2117,6 +2119,7 @@ struct bnxt { · 145 unmodified lines | |||
| 2117 | #define BNXT_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS | 2119 | #define BNXT_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS |
| 2118 | #define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) | 2120 | #define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) |
| 2119 | #define BNXT_PHY_FL_NO_PFC (PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED << 8) | 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 | u8 num_tests; | 2124 | u8 num_tests; |
| 2122 | struct bnxt_test_info *test_info; | 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 | u32 ver = 0; | 892 | u32 ver = 0; |
| 893 | int rc; | 893 | int rc; |
| 894 | 894 | ||
| 895 | rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME); | ||
| 896 | if (rc) | ||
| 897 | return rc; | ||
| 898 | |||
| 899 | if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) { | 895 | if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) { |
| 900 | sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", | 896 | sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", |
| 901 | bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4], | 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 | if (bp->rss_hash_cfg == rss_hash_cfg) | 1234 | if (bp->rss_hash_cfg == rss_hash_cfg) |
| 1235 | return 0; | 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 | bp->rss_hash_cfg = rss_hash_cfg; | 1239 | bp->rss_hash_cfg = rss_hash_cfg; |
| 1238 | if (netif_running(bp->dev)) { | 1240 | if (netif_running(bp->dev)) { |
| 1239 | bnxt_close_nic(bp, false, false); | 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 | rx = bp->rx_port_stats_ext.sw_stats; | 2007 | rx = bp->rx_port_stats_ext.sw_stats; |
| 2006 | fec_stats->corrected_bits.total = | 2008 | fec_stats->corrected_bits.total = |
| 2007 | *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); | 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 | static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, | 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 | #define MSG_INTERNAL_ERR "PKG install error : Internal error" | 2524 | #define MSG_INTERNAL_ERR "PKG install error : Internal error" |
| 2515 | #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" | 2525 | #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" |
| 2516 | #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" | 2526 | #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" |
| 2527 | #define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" | ||
| 2517 | #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" | 2528 | #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" |
| 2518 | #define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" | 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 | #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) | 2575 | #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) |
| 2565 | #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) | 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 | int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, | 2604 | int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, |
| 2568 | u32 install_type, struct netlink_ext_ack *extack) | 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 | u16 index; | 2617 | u16 index; |
| 2581 | int rc; | 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 | bnxt_hwrm_fw_set_time(bp); | 2625 | bnxt_hwrm_fw_set_time(bp); |
| 2584 | 2626 | ||
| 2585 | rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); | 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 | static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, | 3190 | static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, |
| 3149 | u16 page_number, u16 start_addr, | 3191 | u16 page_number, u8 bank, |
| 3150 | u16 data_length, u8 *buf) | 3192 | u16 start_addr, u16 data_length, |
| 3193 | u8 *buf) | ||
| 3151 | { | 3194 | { |
| 3152 | struct hwrm_port_phy_i2c_read_output *output; | 3195 | struct hwrm_port_phy_i2c_read_output *output; |
| 3153 | struct hwrm_port_phy_i2c_read_input *req; | 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 | data_length -= xfer_size; | 3211 | data_length -= xfer_size; |
| 3169 | req->page_offset = cpu_to_le16(start_addr + byte_offset); | 3212 | req->page_offset = cpu_to_le16(start_addr + byte_offset); |
| 3170 | req->data_length = xfer_size; | 3213 | req->data_length = xfer_size; |
| 3171 | req->enables = cpu_to_le32(start_addr + byte_offset ? | 3214 | req->enables = |
| 3172 | PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); | 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 | rc = hwrm_req_send(bp, req); | 3221 | rc = hwrm_req_send(bp, req); |
| 3174 | if (!rc) | 3222 | if (!rc) |
| 3175 | memcpy(buf + byte_offset, output->data, xfer_size); | 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 | if (bp->hwrm_spec_code < 0x10202) | 3247 | if (bp->hwrm_spec_code < 0x10202) |
| 3200 | return -EOPNOTSUPP; | 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 | SFF_DIAG_SUPPORT_OFFSET + 1, | 3251 | SFF_DIAG_SUPPORT_OFFSET + 1, |
| 3204 | data); | 3252 | data); |
| 3205 | if (!rc) { | 3253 | if (!rc) { |
| @@ -3244,7 +3292,7 @@ static int bnxt_get_module_eeprom(struct net_device *dev, · 38 unmodified lines | |||
| 3244 | if (start < ETH_MODULE_SFF_8436_LEN) { | 3292 | if (start < ETH_MODULE_SFF_8436_LEN) { |
| 3245 | if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) | 3293 | if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) |
| 3246 | length = ETH_MODULE_SFF_8436_LEN - start; | 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 | start, length, data); | 3296 | start, length, data); |
| 3249 | if (rc) | 3297 | if (rc) |
| 3250 | return rc; | 3298 | return rc; |
| @@ -3256,12 +3304,68 @@ static int bnxt_get_module_eeprom(struct net_device *dev, · 5 unmodified lines | |||
| 3256 | /* Read A2 portion of the EEPROM */ | 3304 | /* Read A2 portion of the EEPROM */ |
| 3257 | if (length) { | 3305 | if (length) { |
| 3258 | start -= ETH_MODULE_SFF_8436_LEN; | 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 | start, length, data); | 3308 | start, length, data); |
| 3261 | } | 3309 | } |
| 3262 | return rc; | 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 | static int bnxt_nway_reset(struct net_device *dev) | 3369 | static int bnxt_nway_reset(struct net_device *dev) |
| 3266 | { | 3370 | { |
| 3267 | int rc = 0; | 3371 | int rc = 0; |
| @@ -4018,6 +4122,20 @@ static void bnxt_get_rmon_stats(struct net_device *dev, · 750 unmodified lines | |||
| 4018 | *ranges = bnxt_rmon_ranges; | 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 | void bnxt_ethtool_free(struct bnxt *bp) | 4139 | void bnxt_ethtool_free(struct bnxt *bp) |
| 4022 | { | 4140 | { |
| 4023 | kfree(bp->test_info); | 4141 | kfree(bp->test_info); |
| @@ -4067,10 +4185,12 @@ const struct ethtool_ops bnxt_ethtool_ops = { · 43 unmodified lines | |||
| 4067 | .get_eeprom = bnxt_get_eeprom, | 4185 | .get_eeprom = bnxt_get_eeprom, |
| 4068 | .set_eeprom = bnxt_set_eeprom, | 4186 | .set_eeprom = bnxt_set_eeprom, |
| 4069 | .get_link = bnxt_get_link, | 4187 | .get_link = bnxt_get_link, |
| 4188 | .get_link_ext_stats = bnxt_get_link_ext_stats, | ||
| 4070 | .get_eee = bnxt_get_eee, | 4189 | .get_eee = bnxt_get_eee, |
| 4071 | .set_eee = bnxt_set_eee, | 4190 | .set_eee = bnxt_set_eee, |
| 4072 | .get_module_info = bnxt_get_module_info, | 4191 | .get_module_info = bnxt_get_module_info, |
| 4073 | .get_module_eeprom = bnxt_get_module_eeprom, | 4192 | .get_module_eeprom = bnxt_get_module_eeprom, |
| 4193 | .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, | ||
| 4074 | .nway_reset = bnxt_nway_reset, | 4194 | .nway_reset = bnxt_nway_reset, |
| 4075 | .set_phys_id = bnxt_set_phys_id, | 4195 | .set_phys_id = bnxt_set_phys_id, |
| 4076 | .self_test = bnxt_self_test, | 4196 | .self_test = bnxt_self_test, |
| @@ -254,6 +254,8 @@ struct cmd_nums { · 253 unmodified lines | |||
| 254 | #define HWRM_PORT_DSC_DUMP 0xd9UL | 254 | #define HWRM_PORT_DSC_DUMP 0xd9UL |
| 255 | #define HWRM_PORT_EP_TX_QCFG 0xdaUL | 255 | #define HWRM_PORT_EP_TX_QCFG 0xdaUL |
| 256 | #define HWRM_PORT_EP_TX_CFG 0xdbUL | 256 | #define HWRM_PORT_EP_TX_CFG 0xdbUL |
| 257 | #define HWRM_PORT_CFG 0xdcUL | ||
| 258 | #define HWRM_PORT_QCFG 0xddUL | ||
| 257 | #define HWRM_TEMP_MONITOR_QUERY 0xe0UL | 259 | #define HWRM_TEMP_MONITOR_QUERY 0xe0UL |
| 258 | #define HWRM_REG_POWER_QUERY 0xe1UL | 260 | #define HWRM_REG_POWER_QUERY 0xe1UL |
| 259 | #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL | 261 | #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL |
| @@ -379,6 +381,8 @@ struct cmd_nums { · 119 unmodified lines | |||
| 379 | #define HWRM_FUNC_BACKING_STORE_QCAPS_V2 0x1a8UL | 381 | #define HWRM_FUNC_BACKING_STORE_QCAPS_V2 0x1a8UL |
| 380 | #define HWRM_FUNC_DBR_PACING_NQLIST_QUERY 0x1a9UL | 382 | #define HWRM_FUNC_DBR_PACING_NQLIST_QUERY 0x1a9UL |
| 381 | #define HWRM_FUNC_DBR_RECOVERY_COMPLETED 0x1aaUL | 383 | #define HWRM_FUNC_DBR_RECOVERY_COMPLETED 0x1aaUL |
| 384 | #define HWRM_FUNC_SYNCE_CFG 0x1abUL | ||
| 385 | #define HWRM_FUNC_SYNCE_QCFG 0x1acUL | ||
| 382 | #define HWRM_SELFTEST_QLIST 0x200UL | 386 | #define HWRM_SELFTEST_QLIST 0x200UL |
| 383 | #define HWRM_SELFTEST_EXEC 0x201UL | 387 | #define HWRM_SELFTEST_EXEC 0x201UL |
| 384 | #define HWRM_SELFTEST_IRQ 0x202UL | 388 | #define HWRM_SELFTEST_IRQ 0x202UL |
| @@ -417,6 +421,8 @@ struct cmd_nums { · 32 unmodified lines | |||
| 417 | #define HWRM_TF_SESSION_RESC_FREE 0x2ceUL | 421 | #define HWRM_TF_SESSION_RESC_FREE 0x2ceUL |
| 418 | #define HWRM_TF_SESSION_RESC_FLUSH 0x2cfUL | 422 | #define HWRM_TF_SESSION_RESC_FLUSH 0x2cfUL |
| 419 | #define HWRM_TF_SESSION_RESC_INFO 0x2d0UL | 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 | #define HWRM_TF_TBL_TYPE_GET 0x2daUL | 426 | #define HWRM_TF_TBL_TYPE_GET 0x2daUL |
| 421 | #define HWRM_TF_TBL_TYPE_SET 0x2dbUL | 427 | #define HWRM_TF_TBL_TYPE_SET 0x2dbUL |
| 422 | #define HWRM_TF_TBL_TYPE_BULK_GET 0x2dcUL | 428 | #define HWRM_TF_TBL_TYPE_BULK_GET 0x2dcUL |
| @@ -440,6 +446,25 @@ struct cmd_nums { · 17 unmodified lines | |||
| 440 | #define HWRM_TF_GLOBAL_CFG_GET 0x2fdUL | 446 | #define HWRM_TF_GLOBAL_CFG_GET 0x2fdUL |
| 441 | #define HWRM_TF_IF_TBL_SET 0x2feUL | 447 | #define HWRM_TF_IF_TBL_SET 0x2feUL |
| 442 | #define HWRM_TF_IF_TBL_GET 0x2ffUL | 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 | #define HWRM_SV 0x400UL | 468 | #define HWRM_SV 0x400UL |
| 444 | #define HWRM_DBG_READ_DIRECT 0xff10UL | 469 | #define HWRM_DBG_READ_DIRECT 0xff10UL |
| 445 | #define HWRM_DBG_READ_INDIRECT 0xff11UL | 470 | #define HWRM_DBG_READ_INDIRECT 0xff11UL |
| @@ -546,8 +571,8 @@ struct hwrm_err_output { · 100 unmodified lines | |||
| 546 | #define HWRM_VERSION_MAJOR 1 | 571 | #define HWRM_VERSION_MAJOR 1 |
| 547 | #define HWRM_VERSION_MINOR 10 | 572 | #define HWRM_VERSION_MINOR 10 |
| 548 | #define HWRM_VERSION_UPDATE 2 | 573 | #define HWRM_VERSION_UPDATE 2 |
| 549 | #define HWRM_VERSION_RSVD 95 | 574 | #define HWRM_VERSION_RSVD 118 |
| 550 | #define HWRM_VERSION_STR "1.10.2.95" | 575 | #define HWRM_VERSION_STR "1.10.2.118" |
| 551 | 576 | ||
| 552 | /* hwrm_ver_get_input (size:192b/24B) */ | 577 | /* hwrm_ver_get_input (size:192b/24B) */ |
| 553 | struct hwrm_ver_get_input { | 578 | struct hwrm_ver_get_input { |
| @@ -1657,6 +1682,10 @@ struct hwrm_func_qcaps_output { · 1103 unmodified lines | |||
| 1657 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL | 1682 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL |
| 1658 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL | 1683 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL |
| 1659 | #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL | 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 | __le16 tunnel_disable_flag; | 1689 | __le16 tunnel_disable_flag; |
| 1661 | #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_VXLAN 0x1UL | 1690 | #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_VXLAN 0x1UL |
| 1662 | #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_NGE 0x2UL | 1691 | #define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_NGE 0x2UL |
| @@ -1804,7 +1833,20 @@ struct hwrm_func_qcfg_output { · 141 unmodified lines | |||
| 1804 | #define FUNC_QCFG_RESP_MPC_CHNLS_TE_CFA_ENABLED 0x4UL | 1833 | #define FUNC_QCFG_RESP_MPC_CHNLS_TE_CFA_ENABLED 0x4UL |
| 1805 | #define FUNC_QCFG_RESP_MPC_CHNLS_RE_CFA_ENABLED 0x8UL | 1834 | #define FUNC_QCFG_RESP_MPC_CHNLS_RE_CFA_ENABLED 0x8UL |
| 1806 | #define FUNC_QCFG_RESP_MPC_CHNLS_PRIMATE_ENABLED 0x10UL | 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 | __le32 partition_min_bw; | 1850 | __le32 partition_min_bw; |
| 1809 | #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_MASK 0xfffffffUL | 1851 | #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_MASK 0xfffffffUL |
| 1810 | #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_SFT 0 | 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 | #define FUNC_CFG_REQ_FLAGS_PPP_PUSH_MODE_DISABLE 0x10000000UL | 1918 | #define FUNC_CFG_REQ_FLAGS_PPP_PUSH_MODE_DISABLE 0x10000000UL |
| 1877 | #define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL | 1919 | #define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL |
| 1878 | #define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL | 1920 | #define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL |
| 1921 | #define FUNC_CFG_REQ_FLAGS_KEY_CTX_ASSETS_TEST 0x80000000UL | ||
| 1879 | __le32 enables; | 1922 | __le32 enables; |
| 1880 | #define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL | 1923 | #define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL |
| 1881 | #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL | 1924 | #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL |
| @@ -2021,12 +2064,26 @@ struct hwrm_func_cfg_input { · 139 unmodified lines | |||
| 2021 | __le16 num_tx_key_ctxs; | 2064 | __le16 num_tx_key_ctxs; |
| 2022 | __le16 num_rx_key_ctxs; | 2065 | __le16 num_rx_key_ctxs; |
| 2023 | __le32 enables2; | 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 | u8 port_kdnet_mode; | 2069 | u8 port_kdnet_mode; |
| 2026 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL | 2070 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL |
| 2027 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL | 2071 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL |
| 2028 | #define FUNC_CFG_REQ_PORT_KDNET_MODE_LAST FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED | 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 | /* hwrm_func_cfg_output (size:128b/16B) */ | 2089 | /* hwrm_func_cfg_output (size:128b/16B) */ |
| @@ -2060,10 +2117,9 @@ struct hwrm_func_qstats_input { · 27 unmodified lines | |||
| 2060 | __le64 resp_addr; | 2117 | __le64 resp_addr; |
| 2061 | __le16 fid; | 2118 | __le16 fid; |
| 2062 | u8 flags; | 2119 | u8 flags; |
| 2063 | #define FUNC_QSTATS_REQ_FLAGS_UNUSED 0x0UL | 2120 | #define FUNC_QSTATS_REQ_FLAGS_ROCE_ONLY 0x1UL |
| 2064 | #define FUNC_QSTATS_REQ_FLAGS_ROCE_ONLY 0x1UL | 2121 | #define FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x2UL |
| 2065 | #define FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x2UL | 2122 | #define FUNC_QSTATS_REQ_FLAGS_L2_ONLY 0x4UL |
| 2066 | #define FUNC_QSTATS_REQ_FLAGS_LAST FUNC_QSTATS_REQ_FLAGS_COUNTER_MASK | ||
| 2067 | u8 unused_0[5]; | 2123 | u8 unused_0[5]; |
| 2068 | }; | 2124 | }; |
| 2069 | 2125 | ||
| @@ -2093,7 +2149,8 @@ struct hwrm_func_qstats_output { · 23 unmodified lines | |||
| 2093 | __le64 rx_agg_bytes; | 2149 | __le64 rx_agg_bytes; |
| 2094 | __le64 rx_agg_events; | 2150 | __le64 rx_agg_events; |
| 2095 | __le64 rx_agg_aborts; | 2151 | __le64 rx_agg_aborts; |
| 2096 | u8 unused_0[7]; | 2152 | u8 clear_seq; |
| 2153 | u8 unused_0[6]; | ||
| 2097 | u8 valid; | 2154 | u8 valid; |
| 2098 | }; | 2155 | }; |
| 2099 | 2156 | ||
| @@ -2106,10 +2163,8 @@ struct hwrm_func_qstats_ext_input { · 6 unmodified lines | |||
| 2106 | __le64 resp_addr; | 2163 | __le64 resp_addr; |
| 2107 | __le16 fid; | 2164 | __le16 fid; |
| 2108 | u8 flags; | 2165 | u8 flags; |
| 2109 | #define FUNC_QSTATS_EXT_REQ_FLAGS_UNUSED 0x0UL | 2166 | #define FUNC_QSTATS_EXT_REQ_FLAGS_ROCE_ONLY 0x1UL |
| 2110 | #define FUNC_QSTATS_EXT_REQ_FLAGS_ROCE_ONLY 0x1UL | 2167 | #define FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x2UL |
| 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 | ||
| 2113 | u8 unused_0[1]; | 2168 | u8 unused_0[1]; |
| 2114 | __le32 enables; | 2169 | __le32 enables; |
| 2115 | #define FUNC_QSTATS_EXT_REQ_ENABLES_SCHQ_ID 0x1UL | 2170 | #define FUNC_QSTATS_EXT_REQ_ENABLES_SCHQ_ID 0x1UL |
| @@ -2210,6 +2265,7 @@ struct hwrm_func_drv_rgtr_input { · 94 unmodified lines | |||
| 2210 | #define FUNC_DRV_RGTR_REQ_FLAGS_FAST_RESET_SUPPORT 0x80UL | 2265 | #define FUNC_DRV_RGTR_REQ_FLAGS_FAST_RESET_SUPPORT 0x80UL |
| 2211 | #define FUNC_DRV_RGTR_REQ_FLAGS_RSS_STRICT_HASH_TYPE_SUPPORT 0x100UL | 2266 | #define FUNC_DRV_RGTR_REQ_FLAGS_RSS_STRICT_HASH_TYPE_SUPPORT 0x100UL |
| 2212 | #define FUNC_DRV_RGTR_REQ_FLAGS_NPAR_1_2_SUPPORT 0x200UL | 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 | __le32 enables; | 2269 | __le32 enables; |
| 2214 | #define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL | 2270 | #define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL |
| 2215 | #define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL | 2271 | #define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL |
| @@ -3155,19 +3211,23 @@ struct hwrm_func_ptp_pin_qcfg_output { · 939 unmodified lines | |||
| 3155 | #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT 0x4UL | 3211 | #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT 0x4UL |
| 3156 | #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT | 3212 | #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT |
| 3157 | u8 pin2_usage; | 3213 | u8 pin2_usage; |
| 3158 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL | 3214 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL |
| 3159 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL | 3215 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL |
| 3160 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL | 3216 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL |
| 3161 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL | 3217 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL |
| 3162 | #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT 0x4UL | 3218 | #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 | 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 | u8 pin3_usage; | 3222 | u8 pin3_usage; |
| 3165 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL | 3223 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL |
| 3166 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL | 3224 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL |
| 3167 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL | 3225 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL |
| 3168 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL | 3226 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL |
| 3169 | #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT 0x4UL | 3227 | #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 | 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 | u8 unused_0; | 3231 | u8 unused_0; |
| 3172 | u8 valid; | 3232 | u8 valid; |
| 3173 | }; | 3233 | }; |
| @@ -3215,23 +3275,27 @@ struct hwrm_func_ptp_pin_cfg_input { · 41 unmodified lines | |||
| 3215 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED 0x1UL | 3275 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED 0x1UL |
| 3216 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED | 3276 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED |
| 3217 | u8 pin2_usage; | 3277 | u8 pin2_usage; |
| 3218 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL | 3278 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL |
| 3219 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL | 3279 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL |
| 3220 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL | 3280 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL |
| 3221 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL | 3281 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL |
| 3222 | #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT 0x4UL | 3282 | #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 | 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 | u8 pin3_state; | 3286 | u8 pin3_state; |
| 3225 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_DISABLED 0x0UL | 3287 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_DISABLED 0x0UL |
| 3226 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED 0x1UL | 3288 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED 0x1UL |
| 3227 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED | 3289 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED |
| 3228 | u8 pin3_usage; | 3290 | u8 pin3_usage; |
| 3229 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL | 3291 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL |
| 3230 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL | 3292 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL |
| 3231 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL | 3293 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL |
| 3232 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL | 3294 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL |
| 3233 | #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT 0x4UL | 3295 | #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 | 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 | u8 unused_0[4]; | 3299 | u8 unused_0[4]; |
| 3236 | }; | 3300 | }; |
| 3237 | 3301 | ||
| @@ -3319,9 +3383,9 @@ struct hwrm_func_ptp_ts_query_output { · 81 unmodified lines | |||
| 3319 | __le16 seq_id; | 3383 | __le16 seq_id; |
| 3320 | __le16 resp_len; | 3384 | __le16 resp_len; |
| 3321 | __le64 pps_event_ts; | 3385 | __le64 pps_event_ts; |
| 3322 | __le64 ptm_res_local_ts; | 3386 | __le64 ptm_local_ts; |
| 3323 | __le64 ptm_pmstr_ts; | 3387 | __le64 ptm_system_ts; |
| 3324 | __le32 ptm_mstr_prop_dly; | 3388 | __le32 ptm_link_delay; |
| 3325 | u8 unused_0[3]; | 3389 | u8 unused_0[3]; |
| 3326 | u8 valid; | 3390 | u8 valid; |
| 3327 | }; | 3391 | }; |
| @@ -3417,7 +3481,9 @@ struct hwrm_func_backing_store_cfg_v2_input { · 89 unmodified lines | |||
| 3417 | #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID | 3481 | #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID |
| 3418 | __le16 instance; | 3482 | __le16 instance; |
| 3419 | __le32 flags; | 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 | __le64 page_dir; | 3487 | __le64 page_dir; |
| 3422 | __le32 num_entries; | 3488 | __le32 num_entries; |
| 3423 | __le16 entry_size; | 3489 | __le16 entry_size; |
| @@ -3853,7 +3919,7 @@ struct hwrm_port_phy_qcfg_input { · 429 unmodified lines | |||
| 3853 | u8 unused_0[6]; | 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 | struct hwrm_port_phy_qcfg_output { | 3923 | struct hwrm_port_phy_qcfg_output { |
| 3858 | __le16 error_code; | 3924 | __le16 error_code; |
| 3859 | __le16 req_type; | 3925 | __le16 req_type; |
| @@ -4150,6 +4216,9 @@ struct hwrm_port_phy_qcfg_output { · 290 unmodified lines | |||
| 4150 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_50GB 0x1UL | 4216 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_50GB 0x1UL |
| 4151 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL | 4217 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL |
| 4152 | #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL | 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 | u8 valid; | 4222 | u8 valid; |
| 4154 | }; | 4223 | }; |
| 4155 | 4224 | ||
| @@ -4422,9 +4491,7 @@ struct hwrm_port_qstats_input { · 266 unmodified lines | |||
| 4422 | __le64 resp_addr; | 4491 | __le64 resp_addr; |
| 4423 | __le16 port_id; | 4492 | __le16 port_id; |
| 4424 | u8 flags; | 4493 | u8 flags; |
| 4425 | #define PORT_QSTATS_REQ_FLAGS_UNUSED 0x0UL | 4494 | #define PORT_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL |
| 4426 | #define PORT_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL | ||
| 4427 | #define PORT_QSTATS_REQ_FLAGS_LAST PORT_QSTATS_REQ_FLAGS_COUNTER_MASK | ||
| 4428 | u8 unused_0[5]; | 4495 | u8 unused_0[5]; |
| 4429 | __le64 tx_stat_host_addr; | 4496 | __le64 tx_stat_host_addr; |
| 4430 | __le64 rx_stat_host_addr; | 4497 | __le64 rx_stat_host_addr; |
| @@ -4552,9 +4619,7 @@ struct hwrm_port_qstats_ext_input { · 121 unmodified lines | |||
| 4552 | __le16 tx_stat_size; | 4619 | __le16 tx_stat_size; |
| 4553 | __le16 rx_stat_size; | 4620 | __le16 rx_stat_size; |
| 4554 | u8 flags; | 4621 | u8 flags; |
| 4555 | #define PORT_QSTATS_EXT_REQ_FLAGS_UNUSED 0x0UL | 4622 | #define PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK 0x1UL |
| 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 | ||
| 4558 | u8 unused_0; | 4623 | u8 unused_0; |
| 4559 | __le64 tx_stat_host_addr; | 4624 | __le64 tx_stat_host_addr; |
| 4560 | __le64 rx_stat_host_addr; | 4625 | __le64 rx_stat_host_addr; |
| @@ -4613,9 +4678,7 @@ struct hwrm_port_ecn_qstats_input { · 52 unmodified lines | |||
| 4613 | __le16 port_id; | 4678 | __le16 port_id; |
| 4614 | __le16 ecn_stat_buf_size; | 4679 | __le16 ecn_stat_buf_size; |
| 4615 | u8 flags; | 4680 | u8 flags; |
| 4616 | #define PORT_ECN_QSTATS_REQ_FLAGS_UNUSED 0x0UL | 4681 | #define PORT_ECN_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL |
| 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 | ||
| 4619 | u8 unused_0[3]; | 4682 | u8 unused_0[3]; |
| 4620 | __le64 ecn_stat_host_addr; | 4683 | __le64 ecn_stat_host_addr; |
| 4621 | }; | 4684 | }; |
| @@ -4814,8 +4877,9 @@ struct hwrm_port_phy_qcaps_output { · 192 unmodified lines | |||
| 4814 | #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_100G 0x2UL | 4877 | #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_100G 0x2UL |
| 4815 | #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_200G 0x4UL | 4878 | #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_200G 0x4UL |
| 4816 | __le16 flags2; | 4879 | __le16 flags2; |
| 4817 | #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL | 4880 | #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL |
| 4818 | #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL | 4881 | #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL |
| 4882 | #define PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED 0x4UL | ||
| 4819 | u8 internal_port_cnt; | 4883 | u8 internal_port_cnt; |
| 4820 | u8 valid; | 4884 | u8 valid; |
| 4821 | }; | 4885 | }; |
| @@ -4830,9 +4894,10 @@ struct hwrm_port_phy_i2c_read_input { · 8 unmodified lines | |||
| 4830 | __le32 flags; | 4894 | __le32 flags; |
| 4831 | __le32 enables; | 4895 | __le32 enables; |
| 4832 | #define PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET 0x1UL | 4896 | #define PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET 0x1UL |
| 4897 | #define PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER 0x2UL | ||
| 4833 | __le16 port_id; | 4898 | __le16 port_id; |
| 4834 | u8 i2c_slave_addr; | 4899 | u8 i2c_slave_addr; |
| 4835 | u8 unused_0; | 4900 | u8 bank_number; |
| 4836 | __le16 page_number; | 4901 | __le16 page_number; |
| 4837 | __le16 page_offset; | 4902 | __le16 page_offset; |
| 4838 | u8 data_length; | 4903 | u8 data_length; |
| @@ -6537,6 +6602,7 @@ struct hwrm_vnic_qcaps_output { · 1698 unmodified lines | |||
| 6537 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV4_CAP 0x400000UL | 6602 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV4_CAP 0x400000UL |
| 6538 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV6_CAP 0x800000UL | 6603 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV6_CAP 0x800000UL |
| 6539 | #define VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP 0x1000000UL | 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 | __le16 max_aggs_supported; | 6606 | __le16 max_aggs_supported; |
| 6541 | u8 unused_1[5]; | 6607 | u8 unused_1[5]; |
| 6542 | u8 valid; | 6608 | u8 valid; |
| @@ -6702,6 +6768,53 @@ struct hwrm_vnic_rss_cfg_cmd_err { · 159 unmodified lines | |||
| 6702 | u8 unused_0[7]; | 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 | /* hwrm_vnic_plcmodes_cfg_input (size:320b/40B) */ | 6818 | /* hwrm_vnic_plcmodes_cfg_input (size:320b/40B) */ |
| 6706 | struct hwrm_vnic_plcmodes_cfg_input { | 6819 | struct hwrm_vnic_plcmodes_cfg_input { |
| 6707 | __le16 req_type; | 6820 | __le16 req_type; |
| @@ -6827,6 +6940,7 @@ struct hwrm_ring_alloc_input { · 119 unmodified lines | |||
| 6827 | #define RING_ALLOC_REQ_FLAGS_RX_SOP_PAD 0x1UL | 6940 | #define RING_ALLOC_REQ_FLAGS_RX_SOP_PAD 0x1UL |
| 6828 | #define RING_ALLOC_REQ_FLAGS_DISABLE_CQ_OVERFLOW_DETECTION 0x2UL | 6941 | #define RING_ALLOC_REQ_FLAGS_DISABLE_CQ_OVERFLOW_DETECTION 0x2UL |
| 6829 | #define RING_ALLOC_REQ_FLAGS_NQ_DBR_PACING 0x4UL | 6942 | #define RING_ALLOC_REQ_FLAGS_NQ_DBR_PACING 0x4UL |
| 6943 | #define RING_ALLOC_REQ_FLAGS_TX_PKT_TS_CMPL_ENABLE 0x8UL | ||
| 6830 | __le64 page_tbl_addr; | 6944 | __le64 page_tbl_addr; |
| 6831 | __le32 fbo; | 6945 | __le32 fbo; |
| 6832 | u8 page_size; | 6946 | u8 page_size; |
| @@ -7626,7 +7740,10 @@ struct hwrm_cfa_ntuple_filter_alloc_input { · 793 unmodified lines | |||
| 7626 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UNKNOWN 0x0UL | 7740 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UNKNOWN 0x0UL |
| 7627 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_TCP 0x6UL | 7741 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_TCP 0x6UL |
| 7628 | #define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP 0x11UL | 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 | __le16 dst_id; | 7747 | __le16 dst_id; |
| 7631 | __le16 mirror_vnic_id; | 7748 | __le16 mirror_vnic_id; |
| 7632 | u8 tunnel_type; | 7749 | u8 tunnel_type; |
| @@ -8337,6 +8454,7 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output { · 704 unmodified lines | |||
| 8337 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_LAG_SUPPORTED 0x20000UL | 8454 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_LAG_SUPPORTED 0x20000UL |
| 8338 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_NO_L2CTX_SUPPORTED 0x40000UL | 8455 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_NO_L2CTX_SUPPORTED 0x40000UL |
| 8339 | #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NIC_FLOW_STATS_SUPPORTED 0x80000UL | 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 | u8 unused_0[3]; | 8458 | u8 unused_0[3]; |
| 8341 | u8 valid; | 8459 | u8 valid; |
| 8342 | }; | 8460 | }; |
| @@ -8355,7 +8473,9 @@ struct hwrm_tunnel_dst_port_query_input { · 12 unmodified lines | |||
| 8355 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL | 8473 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL |
| 8356 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL | 8474 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL |
| 8357 | #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL | 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 | u8 unused_0[7]; | 8479 | u8 unused_0[7]; |
| 8360 | }; | 8480 | }; |
| 8361 | 8481 | ||
| @@ -8367,7 +8487,16 @@ struct hwrm_tunnel_dst_port_query_output { · 5 unmodified lines | |||
| 8367 | __le16 resp_len; | 8487 | __le16 resp_len; |
| 8368 | __le16 tunnel_dst_port_id; | 8488 | __le16 tunnel_dst_port_id; |
| 8369 | __be16 tunnel_dst_port_val; | 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 | u8 valid; | 8500 | u8 valid; |
| 8372 | }; | 8501 | }; |
| 8373 | 8502 | ||
| @@ -8385,7 +8514,9 @@ struct hwrm_tunnel_dst_port_alloc_input { · 11 unmodified lines | |||
| 8385 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL | 8514 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL |
| 8386 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL | 8515 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL |
| 8387 | #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL | 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 | u8 unused_0; | 8520 | u8 unused_0; |
| 8390 | __be16 tunnel_dst_port_val; | 8521 | __be16 tunnel_dst_port_val; |
| 8391 | u8 unused_1[4]; | 8522 | u8 unused_1[4]; |
| @@ -8398,7 +8529,21 @@ struct hwrm_tunnel_dst_port_alloc_output { · 6 unmodified lines | |||
| 8398 | __le16 seq_id; | 8529 | __le16 seq_id; |
| 8399 | __le16 resp_len; | 8530 | __le16 resp_len; |
| 8400 | __le16 tunnel_dst_port_id; | 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 | u8 valid; | 8547 | u8 valid; |
| 8403 | }; | 8548 | }; |
| 8404 | 8549 | ||
| @@ -8416,7 +8561,9 @@ struct hwrm_tunnel_dst_port_free_input { · 11 unmodified lines | |||
| 8416 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL | 8561 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL |
| 8417 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL | 8562 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL |
| 8418 | #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE_V6 0xcUL | 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 | u8 unused_0; | 8567 | u8 unused_0; |
| 8421 | __le16 tunnel_dst_port_id; | 8568 | __le16 tunnel_dst_port_id; |
| 8422 | u8 unused_1[4]; | 8569 | u8 unused_1[4]; |
| @@ -8428,7 +8575,12 @@ struct hwrm_tunnel_dst_port_free_output { · 5 unmodified lines | |||
| 8428 | __le16 req_type; | 8575 | __le16 req_type; |
| 8429 | __le16 seq_id; | 8576 | __le16 seq_id; |
| 8430 | __le16 resp_len; | 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 | u8 valid; | 8584 | u8 valid; |
| 8433 | }; | 8585 | }; |
| 8434 | 8586 | ||
| @@ -8686,9 +8838,7 @@ struct hwrm_stat_generic_qstats_input { · 251 unmodified lines | |||
| 8686 | __le64 resp_addr; | 8838 | __le64 resp_addr; |
| 8687 | __le16 generic_stat_size; | 8839 | __le16 generic_stat_size; |
| 8688 | u8 flags; | 8840 | u8 flags; |
| 8689 | #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER 0x0UL | 8841 | #define STAT_GENERIC_QSTATS_REQ_FLAGS_COUNTER_MASK 0x1UL |
| 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 | ||
| 8692 | u8 unused_0[5]; | 8842 | u8 unused_0[5]; |
| 8693 | __le64 generic_stat_host_addr; | 8843 | __le64 generic_stat_host_addr; |
| 8694 | }; | 8844 | }; |
| @@ -10202,6 +10352,7 @@ struct fw_status_reg { · 1507 unmodified lines | |||
| 10202 | #define FW_STATUS_REG_SHUTDOWN 0x100000UL | 10352 | #define FW_STATUS_REG_SHUTDOWN 0x100000UL |
| 10203 | #define FW_STATUS_REG_CRASHED_NO_MASTER 0x200000UL | 10353 | #define FW_STATUS_REG_CRASHED_NO_MASTER 0x200000UL |
| 10204 | #define FW_STATUS_REG_RECOVERING 0x400000UL | 10354 | #define FW_STATUS_REG_RECOVERING 0x400000UL |
| 10355 | #define FW_STATUS_REG_MANU_DEBUG_STATUS 0x800000UL | ||
| 10205 | }; | 10356 | }; |
| 10206 | 10357 | ||
| 10207 | /* hcomm_status (size:64b/8B) */ | 10358 | /* hcomm_status (size:64b/8B) */ |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/net_tstamp.h> | 14 | #include <linux/net_tstamp.h> |
| 15 | #include <linux/timekeeping.h> | 15 | #include <linux/timekeeping.h> |
| 16 | #include <linux/ptp_classify.h> | 16 | #include <linux/ptp_classify.h> |
| 17 | #include <linux/clocksource.h> | ||
| 17 | #include "bnxt_hsi.h" | 18 | #include "bnxt_hsi.h" |
| 18 | #include "bnxt.h" | 19 | #include "bnxt.h" |
| 19 | #include "bnxt_hwrm.h" | 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 | return 0; | 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 | struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg, | 210 | struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg, |
| 210 | ptp_info); | 211 | ptp_info); |
| 211 | struct hwrm_port_mac_cfg_input *req; | 212 | struct hwrm_port_mac_cfg_input *req; |
| 212 | struct bnxt *bp = ptp->bp; | 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 (!(ptp->bp->fw_cap & BNXT_FW_CAP_PTP_RTC)) { |
| 216 | if (rc) | 217 | spin_lock_bh(&ptp->ptp_lock); |
| 217 | return rc; | 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); | 224 | rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); |
| 220 | req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB); | 225 | if (rc) |
| 221 | rc = hwrm_req_send(ptp->bp, req); | 226 | return rc; |
| 222 | if (rc) | 227 | |
| 223 | netdev_err(ptp->bp->dev, | 228 | req->ptp_freq_adj_ppb = cpu_to_le32(ppb); |
| 224 | "ptp adjfreq failed. rc = %d\n", rc); | 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 | return rc; | 235 | return rc; |
| 226 | } | 236 | } |
| 227 | 237 | ||
| @@ -749,7 +759,7 @@ static const struct ptp_clock_info bnxt_ptp_caps = { · 521 unmodified lines | |||
| 749 | .n_per_out = 0, | 759 | .n_per_out = 0, |
| 750 | .n_pins = 0, | 760 | .n_pins = 0, |
| 751 | .pps = 0, | 761 | .pps = 0, |
| 752 | .adjfreq = bnxt_ptp_adjfreq, | 762 | .adjfine = bnxt_ptp_adjfine, |
| 753 | .adjtime = bnxt_ptp_adjtime, | 763 | .adjtime = bnxt_ptp_adjtime, |
| 754 | .do_aux_work = bnxt_ptp_ts_aux_work, | 764 | .do_aux_work = bnxt_ptp_ts_aux_work, |
| 755 | .gettimex64 = bnxt_ptp_gettimex, | 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 | memset(&ptp->cc, 0, sizeof(ptp->cc)); | 856 | memset(&ptp->cc, 0, sizeof(ptp->cc)); |
| 847 | ptp->cc.read = bnxt_cc_read; | 857 | ptp->cc.read = bnxt_cc_read; |
| 848 | ptp->cc.mask = CYCLECOUNTER_MASK(48); | 858 | ptp->cc.mask = CYCLECOUNTER_MASK(48); |
| 849 | ptp->cc.shift = 0; | 859 | ptp->cc.shift = BNXT_CYCLES_SHIFT; |
| 850 | ptp->cc.mult = 1; | 860 | ptp->cc.mult = clocksource_khz2mult(BNXT_DEVCLK_FREQ, ptp->cc.shift); |
| 861 | ptp->cmult = ptp->cc.mult; | ||
| 851 | ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD; | 862 | ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD; |
| 852 | } | 863 | } |
| 853 | if (init_tc) | 864 | if (init_tc) |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | |||
| 17 | #define BNXT_PTP_GRC_WIN_BASE 0x6000 | 17 | #define BNXT_PTP_GRC_WIN_BASE 0x6000 |
| 18 | 18 | ||
| 19 | #define BNXT_MAX_PHC_DRIFT 31000000 | 19 | #define BNXT_MAX_PHC_DRIFT 31000000 |
| 20 | #define BNXT_CYCLES_SHIFT 23 | ||
| 21 | #define BNXT_DEVCLK_FREQ 1000000 | ||
| 20 | #define BNXT_LO_TIMER_MASK 0x0000ffffffffUL | 22 | #define BNXT_LO_TIMER_MASK 0x0000ffffffffUL |
| 21 | #define BNXT_HI_TIMER_MASK 0xffff00000000UL | 23 | #define BNXT_HI_TIMER_MASK 0xffff00000000UL |
| 22 | 24 | ||
| @@ -88,8 +90,9 @@ struct bnxt_ptp_cfg { · 65 unmodified lines | |||
| 88 | u64 old_time; | 90 | u64 old_time; |
| 89 | unsigned long next_period; | 91 | unsigned long next_period; |
| 90 | unsigned long next_overflow_check; | 92 | unsigned long next_overflow_check; |
| 91 | /* 48-bit PHC overflows in 78 hours. Check overflow every 19 hours. */ | 93 | u32 cmult; |
| 92 | #define BNXT_PHC_OVERFLOW_PERIOD (19 * 3600 * HZ) | 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 | u16 tx_seqid; | 97 | u16 tx_seqid; |
| 95 | u16 tx_hdr_off; | 98 | u16 tx_hdr_off; |
| @@ -117,24 +117,6 @@ static inline void dmadesc_set(struct bcmgenet_priv *priv, · 116 unmodified lines | |||
| 117 | dmadesc_set_length_status(priv, d, val); | 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 | #define GENET_VER_FMT "%1d.%1d EPHY: 0x%04x" | 120 | #define GENET_VER_FMT "%1d.%1d EPHY: 0x%04x" |
| 139 | 121 | ||
| 140 | #define GENET_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ | 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 | struct ethtool_usrip4_spec *l4_mask; | 1369 | struct ethtool_usrip4_spec *l4_mask; |
| 1388 | struct ethhdr *eth_mask; | 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 | netdev_err(dev, "rxnfc: Invalid location (%d)\n", | 1374 | netdev_err(dev, "rxnfc: Invalid location (%d)\n", |
| 1392 | cmd->fs.location); | 1375 | cmd->fs.location); |
| 1393 | return -EINVAL; | 1376 | return -EINVAL; |
| @@ -1452,7 +1435,7 @@ static int bcmgenet_insert_flow(struct net_device *dev, · 58 unmodified lines | |||
| 1452 | { | 1435 | { |
| 1453 | struct bcmgenet_priv *priv = netdev_priv(dev); | 1436 | struct bcmgenet_priv *priv = netdev_priv(dev); |
| 1454 | struct bcmgenet_rxnfc_rule *loc_rule; | 1437 | struct bcmgenet_rxnfc_rule *loc_rule; |
| 1455 | int err; | 1438 | int err, i; |
| 1456 | 1439 | ||
| 1457 | if (priv->hw_params->hfb_filter_size < 128) { | 1440 | if (priv->hw_params->hfb_filter_size < 128) { |
| 1458 | netdev_err(dev, "rxnfc: Not supported by this device\n"); | 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 | if (err) | 1453 | if (err) |
| 1471 | return err; | 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 | if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) | 1479 | if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) |
| 1475 | bcmgenet_hfb_disable_filter(priv, cmd->fs.location); | 1480 | bcmgenet_hfb_disable_filter(priv, cmd->fs.location); |
| 1476 | if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { | 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 | break; | 1588 | break; |
| 1584 | case ETHTOOL_GRXCLSRLCNT: | 1589 | case ETHTOOL_GRXCLSRLCNT: |
| 1585 | cmd->rule_cnt = bcmgenet_get_num_flows(priv); | 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 | break; | 1592 | break; |
| 1588 | case ETHTOOL_GRXCLSRULE: | 1593 | case ETHTOOL_GRXCLSRULE: |
| 1589 | err = bcmgenet_get_flow(dev, cmd, cmd->fs.location); | 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 | * Receive clock is provided by the PHY. | 72 | * Receive clock is provided by the PHY. |
| 73 | */ | 73 | */ |
| 74 | reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); | 74 | reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); |
| 75 | reg &= ~OOB_DISABLE; | ||
| 76 | reg |= RGMII_LINK; | 75 | reg |= RGMII_LINK; |
| 77 | bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); | 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 | void bcmgenet_mii_setup(struct net_device *dev) | 95 | void bcmgenet_mii_setup(struct net_device *dev) |
| 97 | { | 96 | { |
| 97 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
| 98 | struct phy_device *phydev = dev->phydev; | 98 | struct phy_device *phydev = dev->phydev; |
| 99 | u32 reg; | ||
| 99 | 100 | ||
| 100 | if (phydev->link) | 101 | if (phydev->link) { |
| 101 | bcmgenet_mac_config(dev); | 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 | phy_print_status(phydev); | 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 | (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); | 273 | (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); |
| 267 | 274 | ||
| 268 | /* This is an external PHY (xMII), so we need to enable the RGMII | 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 | if (priv->ext_phy) { | 281 | if (priv->ext_phy) { |
| 272 | reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); | ||
| 273 | reg &= ~ID_MODE_DIS; | 282 | reg &= ~ID_MODE_DIS; |
| 274 | reg |= id_mode_dis; | 283 | reg |= id_mode_dis; |
| 275 | if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) | 284 | if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) |
| 276 | reg |= RGMII_MODE_EN_V123; | 285 | reg |= RGMII_MODE_EN_V123; |
| 277 | else | 286 | else |
| 278 | reg |= RGMII_MODE_EN; | 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 | if (init) | 291 | if (init) |
| 283 | dev_info(kdev, "configuring instance for %s\n", phy_name); | 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 | return 0; | 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 | struct tg3 *tp = container_of(ptp, struct tg3, ptp_info); | 6184 | struct tg3 *tp = container_of(ptp, struct tg3, ptp_info); |
| 6185 | bool neg_adj = false; | 6185 | u64 correction; |
| 6186 | u32 correction = 0; | 6186 | bool neg_adj; |
| 6187 | |||
| 6188 | if (ppb < 0) { | ||
| 6189 | neg_adj = true; | ||
| 6190 | ppb = -ppb; | ||
| 6191 | } | ||
| 6192 | 6187 | ||
| 6193 | /* Frequency adjustment is performed using hardware with a 24 bit | 6188 | /* Frequency adjustment is performed using hardware with a 24 bit |
| 6194 | * accumulator and a programmable correction value. On each clk, the | 6189 | * accumulator and a programmable correction value. On each clk, the |
| 6195 | * correction value gets added to the accumulator and when it | 6190 | * correction value gets added to the accumulator and when it |
| 6196 | * overflows, the time counter is incremented/decremented. | 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) & | 6193 | neg_adj = diff_by_scaled_ppm(1 << 24, scaled_ppm, &correction); |
| 6202 | TG3_EAV_REF_CLK_CORRECT_MASK; | ||
| 6203 | 6194 | ||
| 6204 | tg3_full_lock(tp, 0); | 6195 | tg3_full_lock(tp, 0); |
| 6205 | 6196 | ||
| 6206 | if (correction) | 6197 | if (correction) |
| 6207 | tw32(TG3_EAV_REF_CLK_CORRECT_CTL, | 6198 | tw32(TG3_EAV_REF_CLK_CORRECT_CTL, |
| 6208 | TG3_EAV_REF_CLK_CORRECT_EN | | 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 | else | 6202 | else |
| 6211 | tw32(TG3_EAV_REF_CLK_CORRECT_CTL, 0); | 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 | .n_per_out = 1, | 6322 | .n_per_out = 1, |
| 6331 | .n_pins = 0, | 6323 | .n_pins = 0, |
| 6332 | .pps = 0, | 6324 | .pps = 0, |
| 6333 | .adjfreq = tg3_ptp_adjfreq, | 6325 | .adjfine = tg3_ptp_adjfine, |
| 6334 | .adjtime = tg3_ptp_adjtime, | 6326 | .adjtime = tg3_ptp_adjtime, |
| 6335 | .gettimex64 = tg3_ptp_gettimex, | 6327 | .gettimex64 = tg3_ptp_gettimex, |
| 6336 | .settime64 = tg3_ptp_settime, | 6328 | .settime64 = tg3_ptp_settime, |
| @@ -18,15 +18,43 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | /* BFA state machine interfaces */ | 19 | /* BFA state machine interfaces */ |
| 20 | 20 | ||
| 21 | typedef void (*bfa_sm_t)(void *sm, int event); | ||
| 22 | |||
| 23 | /* For converting from state machine function to state encoding. */ | 21 | /* For converting from state machine function to state encoding. */ |
| 24 | struct bfa_sm_table { | 22 | #define BFA_SM_TABLE(n, s, e, t) \ |
| 25 | bfa_sm_t sm; /*!< state machine function */ | 23 | struct s; \ |
| 26 | int state; /*!< state machine encoding */ | 24 | enum e; \ |
| 27 | char *name; /*!< state name for display */ | 25 | typedef void (*t)(struct s *, enum e); \ |
| 28 | }; | 26 | \ |
| 29 | #define BFA_SM(_sm) ((bfa_sm_t)(_sm)) | 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 | /* State machine with entry actions. */ | 59 | /* State machine with entry actions. */ |
| 32 | typedef void (*bfa_fsm_t)(void *fsm, int event); | 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 | static void oc ## _sm_ ## st ## _entry(otype * fsm) | 69 | static void oc ## _sm_ ## st ## _entry(otype * fsm) |
| 42 | 70 | ||
| 43 | #define bfa_fsm_set_state(_fsm, _state) do { \ | 71 | #define bfa_fsm_set_state(_fsm, _state) do { \ |
| 44 | (_fsm)->fsm = (bfa_fsm_t)(_state); \ | 72 | (_fsm)->fsm = (_state); \ |
| 45 | _state ## _entry(_fsm); \ | 73 | _state ## _entry(_fsm); \ |
| 46 | } while (0) | 74 | } while (0) |
| 47 | 75 | ||
| 48 | #define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event))) | 76 | #define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event))) |
| 49 | #define bfa_fsm_cmp_state(_fsm, _state) \ | 77 | #define bfa_fsm_cmp_state(_fsm, _state) ((_fsm)->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 | |||
| 62 | /* Generic wait counter. */ | 78 | /* Generic wait counter. */ |
| 63 | 79 | ||
| 64 | typedef void (*bfa_wc_resume_t) (void *cbarg); | 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 | bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event); | 114 | bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event); |
| 115 | bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc, enum ioc_event); | 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 | {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, | 118 | {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, |
| 119 | {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, | 119 | {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, |
| 120 | {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING}, | 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 | enum iocpf_event); | 183 | enum iocpf_event); |
| 184 | bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf, enum iocpf_event); | 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 | {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET}, | 187 | {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET}, |
| 188 | {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH}, | 188 | {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH}, |
| 189 | {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH}, | 189 | {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH}, |
| @@ -2860,12 +2860,12 @@ static enum bfa_ioc_state · 2670 unmodified lines | |||
| 2860 | bfa_ioc_get_state(struct bfa_ioc *ioc) | 2860 | bfa_ioc_get_state(struct bfa_ioc *ioc) |
| 2861 | { | 2861 | { |
| 2862 | enum bfa_iocpf_state iocpf_st; | 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 | if (ioc_st == BFA_IOC_ENABLING || | 2865 | if (ioc_st == BFA_IOC_ENABLING || |
| 2866 | ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) { | 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 | switch (iocpf_st) { | 2870 | switch (iocpf_st) { |
| 2871 | case BFA_IOCPF_SEMWAIT: | 2871 | case BFA_IOCPF_SEMWAIT: |
| @@ -2983,7 +2983,7 @@ bfa_nw_iocpf_timeout(struct bfa_ioc *ioc) · 111 unmodified lines | |||
| 2983 | { | 2983 | { |
| 2984 | enum bfa_iocpf_state iocpf_st; | 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 | if (iocpf_st == BFA_IOCPF_HWINIT) | 2988 | if (iocpf_st == BFA_IOCPF_HWINIT) |
| 2989 | bfa_ioc_poll_fwinit(ioc); | 2989 | bfa_ioc_poll_fwinit(ioc); |
| @@ -147,16 +147,20 @@ struct bfa_ioc_notify { · 146 unmodified lines | |||
| 147 | (__notify)->cbarg = (__cbarg); \ | 147 | (__notify)->cbarg = (__cbarg); \ |
| 148 | } while (0) | 148 | } while (0) |
| 149 | 149 | ||
| 150 | enum iocpf_event; | ||
| 151 | |||
| 150 | struct bfa_iocpf { | 152 | struct bfa_iocpf { |
| 151 | bfa_fsm_t fsm; | 153 | void (*fsm)(struct bfa_iocpf *s, enum iocpf_event e); |
| 152 | struct bfa_ioc *ioc; | 154 | struct bfa_ioc *ioc; |
| 153 | bool fw_mismatch_notified; | 155 | bool fw_mismatch_notified; |
| 154 | bool auto_recover; | 156 | bool auto_recover; |
| 155 | u32 poll_time; | 157 | u32 poll_time; |
| 156 | }; | 158 | }; |
| 157 | 159 | ||
| 160 | enum ioc_event; | ||
| 161 | |||
| 158 | struct bfa_ioc { | 162 | struct bfa_ioc { |
| 159 | bfa_fsm_t fsm; | 163 | void (*fsm)(struct bfa_ioc *s, enum ioc_event e); |
| 160 | struct bfa *bfa; | 164 | struct bfa *bfa; |
| 161 | struct bfa_pcidev pcidev; | 165 | struct bfa_pcidev pcidev; |
| 162 | struct timer_list ioc_timer; | 166 | struct timer_list ioc_timer; |
| @@ -202,7 +202,6 @@ static void · 201 unmodified lines | |||
| 202 | __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd) | 202 | __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd) |
| 203 | { | 203 | { |
| 204 | size_t len = cmd->msg_size; | 204 | size_t len = cmd->msg_size; |
| 205 | int num_entries = 0; | ||
| 206 | size_t to_copy; | 205 | size_t to_copy; |
| 207 | u8 *src, *dst; | 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 | BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth); | 218 | BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth); |
| 220 | dst = (u8 *)cmdq->addr.kva; | 219 | dst = (u8 *)cmdq->addr.kva; |
| 221 | dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE); | 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 | BFA_MSGQ_CMDQ_F_DB_UPDATE = 1, | 55 | BFA_MSGQ_CMDQ_F_DB_UPDATE = 1, |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | enum cmdq_event; | ||
| 59 | |||
| 58 | struct bfa_msgq_cmdq { | 60 | struct bfa_msgq_cmdq { |
| 59 | bfa_fsm_t fsm; | 61 | void (*fsm)(struct bfa_msgq_cmdq *s, enum cmdq_event e); |
| 60 | enum bfa_msgq_cmdq_flags flags; | 62 | enum bfa_msgq_cmdq_flags flags; |
| 61 | 63 | ||
| 62 | u16 producer_index; | 64 | u16 producer_index; |
| @@ -81,8 +83,10 @@ enum bfa_msgq_rspq_flags { · 18 unmodified lines | |||
| 81 | 83 | ||
| 82 | typedef void (*bfa_msgq_mcfunc_t)(void *cbarg, struct bfi_msgq_mhdr *mhdr); | 84 | typedef void (*bfa_msgq_mcfunc_t)(void *cbarg, struct bfi_msgq_mhdr *mhdr); |
| 83 | 85 | ||
| 86 | enum rspq_event; | ||
| 87 | |||
| 84 | struct bfa_msgq_rspq { | 88 | struct bfa_msgq_rspq { |
| 85 | bfa_fsm_t fsm; | 89 | void (*fsm)(struct bfa_msgq_rspq *s, enum rspq_event e); |
| 86 | enum bfa_msgq_rspq_flags flags; | 90 | enum bfa_msgq_rspq_flags flags; |
| 87 | 91 | ||
| 88 | u16 producer_index; | 92 | u16 producer_index; |
| @@ -1257,7 +1257,7 @@ bna_enet_mtu_get(struct bna_enet *enet) · 1256 unmodified lines | |||
| 1257 | void | 1257 | void |
| 1258 | bna_enet_enable(struct bna_enet *enet) | 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 | return; | 1261 | return; |
| 1262 | 1262 | ||
| 1263 | enet->flags |= BNA_ENET_F_ENABLED; | 1263 | enet->flags |= BNA_ENET_F_ENABLED; |
| @@ -1751,12 +1751,12 @@ bna_ioceth_uninit(struct bna_ioceth *ioceth) · 487 unmodified lines | |||
| 1751 | void | 1751 | void |
| 1752 | bna_ioceth_enable(struct bna_ioceth *ioceth) | 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 | bnad_cb_ioceth_ready(ioceth->bna->bnad); | 1755 | bnad_cb_ioceth_ready(ioceth->bna->bnad); |
| 1756 | return; | 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 | bfa_fsm_send_event(ioceth, IOCETH_E_ENABLE); | 1760 | bfa_fsm_send_event(ioceth, IOCETH_E_ENABLE); |
| 1761 | } | 1761 | } |
| 1762 | 1762 | ||
| @@ -1956,7 +1956,7 @@ static void · 1955 unmodified lines | |||
| 1956 | bna_rx_stop(struct bna_rx *rx) | 1956 | bna_rx_stop(struct bna_rx *rx) |
| 1957 | { | 1957 | { |
| 1958 | rx->rx_flags &= ~BNA_RX_F_ENET_STARTED; | 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 | bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx); | 1960 | bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx); |
| 1961 | else { | 1961 | else { |
| 1962 | rx->stop_cbfn = bna_rx_mod_cb_rx_stopped; | 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 | void | 2535 | void |
| 2536 | bna_rx_enable(struct bna_rx *rx) | 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 | return; | 2539 | return; |
| 2540 | 2540 | ||
| 2541 | rx->rx_flags |= BNA_RX_F_ENABLED; | 2541 | rx->rx_flags |= BNA_RX_F_ENABLED; |
| @@ -3523,7 +3523,7 @@ bna_tx_destroy(struct bna_tx *tx) · 981 unmodified lines | |||
| 3523 | void | 3523 | void |
| 3524 | bna_tx_enable(struct bna_tx *tx) | 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 | return; | 3527 | return; |
| 3528 | 3528 | ||
| 3529 | tx->flags |= BNA_TX_F_ENABLED; | 3529 | tx->flags |= BNA_TX_F_ENABLED; |
| @@ -312,8 +312,10 @@ struct bna_attr { · 311 unmodified lines | |||
| 312 | 312 | ||
| 313 | /* IOCEth */ | 313 | /* IOCEth */ |
| 314 | 314 | ||
| 315 | enum bna_ioceth_event; | ||
| 316 | |||
| 315 | struct bna_ioceth { | 317 | struct bna_ioceth { |
| 316 | bfa_fsm_t fsm; | 318 | void (*fsm)(struct bna_ioceth *s, enum bna_ioceth_event e); |
| 317 | struct bfa_ioc ioc; | 319 | struct bfa_ioc ioc; |
| 318 | 320 | ||
| 319 | struct bna_attr attr; | 321 | struct bna_attr attr; |
| @@ -334,8 +336,10 @@ struct bna_pause_config { · 14 unmodified lines | |||
| 334 | enum bna_status rx_pause; | 336 | enum bna_status rx_pause; |
| 335 | }; | 337 | }; |
| 336 | 338 | ||
| 339 | enum bna_enet_event; | ||
| 340 | |||
| 337 | struct bna_enet { | 341 | struct bna_enet { |
| 338 | bfa_fsm_t fsm; | 342 | void (*fsm)(struct bna_enet *s, enum bna_enet_event e); |
| 339 | enum bna_enet_flags flags; | 343 | enum bna_enet_flags flags; |
| 340 | 344 | ||
| 341 | enum bna_enet_type type; | 345 | enum bna_enet_type type; |
| @@ -360,8 +364,10 @@ struct bna_enet { · 18 unmodified lines | |||
| 360 | 364 | ||
| 361 | /* Ethport */ | 365 | /* Ethport */ |
| 362 | 366 | ||
| 367 | enum bna_ethport_event; | ||
| 368 | |||
| 363 | struct bna_ethport { | 369 | struct bna_ethport { |
| 364 | bfa_fsm_t fsm; | 370 | void (*fsm)(struct bna_ethport *s, enum bna_ethport_event e); |
| 365 | enum bna_ethport_flags flags; | 371 | enum bna_ethport_flags flags; |
| 366 | 372 | ||
| 367 | enum bna_link_status link_status; | 373 | enum bna_link_status link_status; |
| @@ -454,13 +460,16 @@ struct bna_txq { · 86 unmodified lines | |||
| 454 | }; | 460 | }; |
| 455 | 461 | ||
| 456 | /* Tx object */ | 462 | /* Tx object */ |
| 463 | |||
| 464 | enum bna_tx_event; | ||
| 465 | |||
| 457 | struct bna_tx { | 466 | struct bna_tx { |
| 458 | /* This should be the first one */ | 467 | /* This should be the first one */ |
| 459 | struct list_head qe; | 468 | struct list_head qe; |
| 460 | int rid; | 469 | int rid; |
| 461 | int hw_id; | 470 | int hw_id; |
| 462 | 471 | ||
| 463 | bfa_fsm_t fsm; | 472 | void (*fsm)(struct bna_tx *s, enum bna_tx_event e); |
| 464 | enum bna_tx_flags flags; | 473 | enum bna_tx_flags flags; |
| 465 | 474 | ||
| 466 | enum bna_tx_type type; | 475 | enum bna_tx_type type; |
| @@ -698,8 +707,11 @@ struct bna_rxp { · 231 unmodified lines | |||
| 698 | }; | 707 | }; |
| 699 | 708 | ||
| 700 | /* RxF structure (hardware Rx Function) */ | 709 | /* RxF structure (hardware Rx Function) */ |
| 710 | |||
| 711 | enum bna_rxf_event; | ||
| 712 | |||
| 701 | struct bna_rxf { | 713 | struct bna_rxf { |
| 702 | bfa_fsm_t fsm; | 714 | void (*fsm)(struct bna_rxf *s, enum bna_rxf_event e); |
| 703 | 715 | ||
| 704 | struct bfa_msgq_cmd_entry msgq_cmd; | 716 | struct bfa_msgq_cmd_entry msgq_cmd; |
| 705 | union { | 717 | union { |
| @@ -769,13 +781,16 @@ struct bna_rxf { · 63 unmodified lines | |||
| 769 | }; | 781 | }; |
| 770 | 782 | ||
| 771 | /* Rx object */ | 783 | /* Rx object */ |
| 784 | |||
| 785 | enum bna_rx_event; | ||
| 786 | |||
| 772 | struct bna_rx { | 787 | struct bna_rx { |
| 773 | /* This should be the first one */ | 788 | /* This should be the first one */ |
| 774 | struct list_head qe; | 789 | struct list_head qe; |
| 775 | int rid; | 790 | int rid; |
| 776 | int hw_id; | 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 | enum bna_rx_type type; | 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.