Pull networking updates from Jakub Kicinski: - Add redirect_neigh() BPF packet redirect helper, allowing to limit stack traversal in common container configs and improving TCP back-pressure. Daniel reports ~10Gbps => ~15Gbps single stream TCP performance gain. - Expand netlink policy support and improve policy export to user space. (Ge)netlink core performs request validation according to declared policies. Expand the expressiveness of those policies (min/max length and bitmasks). Allow dumping policies for particular commands. This is used for feature discovery by user space (instead of kernel version parsing or trial and error). - Support IGMPv3/MLDv2 multicast listener discovery protocols in bridge. - Allow more than 255 IPv4 multicast interfaces. - Add support for Type of Service (ToS) reflection in SYN/SYN-ACK packets of TCPv6. - In Multi-patch TCP (MPTCP) support concurrent transmission of data on multiple subflows in a load balancing scenario. Enhance advertising addresses via the RM_ADDR/ADD_ADDR options. - Support SMC-Dv2 version of SMC, which enables multi-subnet deployments. - Allow more calls to same peer in RxRPC. - Support two new Controller Area Network (CAN) protocols - CAN-FD and ISO 15765-2:2016. - Add xfrm/IPsec compat layer, solving the 32bit user space on 64bit kernel problem. - Add TC actions for implementing MPLS L2 VPNs. - Improve nexthop code - e.g. handle various corner cases when nexthop objects are removed from groups better, skip unnecessary notifications and make it easier to offload nexthops into HW by converting to a blocking notifier. - Support adding and consuming TCP header options by BPF programs, opening the doors for easy experimental and deployment-specific TCP option use. - Reorganize TCP congestion control (CC) initialization to simplify life of TCP CC implemented in BPF. - Add support for shipping BPF programs with the kernel and loading them early on boot via the User Mode Driver mechanism, hence reusing all the user space infra we have. - Support sleepable BPF programs, initially targeting LSM and tracing. - Add bpf_d_path() helper for returning full path for given 'struct path'. - Make bpf_tail_call compatible with bpf-to-bpf calls. - Allow BPF programs to call map_update_elem on sockmaps. - Add BPF Type Format (BTF) support for type and enum discovery, as well as support for using BTF within the kernel itself (current use is for pretty printing structures). - Support listing and getting information about bpf_links via the bpf syscall. - Enhance kernel interfaces around NIC firmware update. Allow specifying overwrite mask to control if settings etc. are reset during update; report expected max time operation may take to users; support firmware activation without machine reboot incl. limits of how much impact reset may have (e.g. dropping link or not). - Extend ethtool configuration interface to report IEEE-standard counters, to limit the need for per-vendor logic in user space. - Adopt or extend devlink use for debug, monitoring, fw update in many drivers (dsa loop, ice, ionic, sja1105, qed, mlxsw, mv88e6xxx, dpaa2-eth). - In mlxsw expose critical and emergency SFP module temperature alarms. Refactor port buffer handling to make the defaults more suitable and support setting these values explicitly via the DCBNL interface. - Add XDP support for Intel's igb driver. - Support offloading TC flower classification and filtering rules to mscc_ocelot switches. - Add PTP support for Marvell Octeontx2 and PP2.2 hardware, as well as fixed interval period pulse generator and one-step timestamping in dpaa-eth. - Add support for various auth offloads in WiFi APs, e.g. SAE (WPA3) offload. - Add Lynx PHY/PCS MDIO module, and convert various drivers which have this HW to use it. Convert mvpp2 to split PCS. - Support Marvell Prestera 98DX3255 24-port switch ASICs, as well as 7-port Mediatek MT7531 IP. - Add initial support for QCA6390 and IPQ6018 in ath11k WiFi driver, and wcn3680 support in wcn36xx. - Improve performance for packets which don't require much offloads on recent Mellanox NICs by 20% by making multiple packets share a descriptor entry. - Move chelsio inline crypto drivers (for TLS and IPsec) from the crypto subtree to drivers/net. Move MDIO drivers out of the phy directory. - Clean up a lot of W=1 warnings, reportedly the actively developed subsections of networking drivers should now build W=1 warning free. - Make sure drivers don't use in_interrupt() to dynamically adapt their code. Convert tasklets to use new tasklet_setup API (sadly this conversion is not yet complete). * tag 'net-next-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2583 commits) Revert "bpfilter: Fix build error with CONFIG_BPFILTER_UMH" net, sockmap: Don't call bpf_prog_put() on NULL pointer bpf, selftest: Fix flaky tcp_hdr_options test when adding addr to lo bpf, sockmap: Add locking annotations to iterator netfilter: nftables: allow re-computing sctp CRC-32C in 'payload' statements net: fix pos incrementment in ipv6_route_seq_next net/smc: fix invalid return code in smcd_new_buf_create() net/smc: fix valid DMBE buffer sizes net/smc: fix use-after-free of delayed events bpfilter: Fix build error with CONFIG_BPFILTER_UMH cxgb4/ch_ipsec: Replace the module name to ch_ipsec from chcr net: sched: Fix suspicious RCU usage while accessing tcf_tunnel_info bpf: Fix register equivalence tracking. rxrpc: Fix loss of final ack on shutdown rxrpc: Fix bundle counting for exclusive connections netfilter: restore NF_INET_NUMHOOKS ibmveth: Identify ingress large send packets. ibmveth: Switch order of ibmveth_helper calls. cxgb4: handle 4-tuple PEDIT to NAT mode translation selftests: Add VRF route leaking tests ...
Unified · Split
| @@ -191,6 +191,10 @@ N: Krishna Balasubramanian · 190 unmodified lines | ||
| 191 | 191 | E: balasub@cis.ohio-state.edu |
| 192 | 192 | D: Wrote SYS V IPC (part of standard kernel since 0.99.10) |
| 193 | 193 | |
| 194 | +B: Robert Baldyga | |
| 195 | +E: r.baldyga@hackerion.com | |
| 196 | +D: Samsung S3FWRN5 NCI NFC Controller | |
| 197 | + | |
| 194 | 198 | N: Chris Ball |
| 195 | 199 | E: chris@printf.net |
| 196 | 200 | D: Former maintainer of the MMC/SD/SDIO subsystem. |
| @@ -1349,6 +1349,11 @@ · 1348 unmodified lines | ||
| 1349 | 1349 | Format: <interval>,<probability>,<space>,<times> |
| 1350 | 1350 | See also Documentation/fault-injection/. |
| 1351 | 1351 | |
| 1352 | + fb_tunnels= [NET] | |
| 1353 | + Format: { initns | none } | |
| 1354 | + See Documentation/admin-guide/sysctl/net.rst for | |
| 1355 | + fb_tunnels_only_for_init_ns | |
| 1356 | + | |
| 1352 | 1357 | floppy= [HW] |
| 1353 | 1358 | See Documentation/admin-guide/blockdev/floppy.rst. |
| 1354 | 1359 | |
| @@ -300,7 +300,6 @@ Note: · 299 unmodified lines | ||
| 300 | 300 | 0: 0 1 2 3 4 5 6 7 |
| 301 | 301 | RSS hash key: |
| 302 | 302 | 84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89 |
| 303 | − | |
| 304 | 303 | netdev_tstamp_prequeue |
| 305 | 304 | ---------------------- |
| 306 | 305 | |
| @@ -321,11 +320,20 @@ fb_tunnels_only_for_init_net · 14 unmodified lines | ||
| 321 | 320 | ---------------------------- |
| 322 | 321 | |
| 323 | 322 | Controls if fallback tunnels (like tunl0, gre0, gretap0, erspan0, |
| 324 | −sit0, ip6tnl0, ip6gre0) are automatically created when a new | |
| 325 | −network namespace is created, if corresponding tunnel is present | |
| 326 | −in initial network namespace. | |
| 327 | −If set to 1, these devices are not automatically created, and | |
| 328 | −user space is responsible for creating them if needed. | |
| 323 | +sit0, ip6tnl0, ip6gre0) are automatically created. There are 3 possibilities | |
| 324 | +(a) value = 0; respective fallback tunnels are created when module is | |
| 325 | +loaded in every net namespaces (backward compatible behavior). | |
| 326 | +(b) value = 1; [kcmd value: initns] respective fallback tunnels are | |
| 327 | +created only in init net namespace and every other net namespace will | |
| 328 | +not have them. | |
| 329 | +(c) value = 2; [kcmd value: none] fallback tunnels are not created | |
| 330 | +when a module is loaded in any of the net namespace. Setting value to | |
| 331 | +"2" is pointless after boot if these modules are built-in, so there is | |
| 332 | +a kernel command-line option that can change this default. Please refer to | |
| 333 | +Documentation/admin-guide/kernel-parameters.txt for additional details. | |
| 334 | + | |
| 335 | +Not creating fallback tunnels gives control to userspace to create | |
| 336 | +whatever is needed only and avoid creating devices which are redundant. | |
| 329 | 337 | |
| 330 | 338 | Default : 0 (for compatibility reasons) |
| 331 | 339 | |
| @@ -60,13 +60,13 @@ Q: Where can I find patches currently under discussion for BPF subsystem? · 59 unmodified lines | ||
| 60 | 60 | A: All patches that are Cc'ed to netdev are queued for review under netdev |
| 61 | 61 | patchwork project: |
| 62 | 62 | |
| 63 | − http://patchwork.ozlabs.org/project/netdev/list/ | |
| 63 | + https://patchwork.kernel.org/project/netdevbpf/list/ | |
| 64 | 64 | |
| 65 | 65 | Those patches which target BPF, are assigned to a 'bpf' delegate for |
| 66 | 66 | further processing from BPF maintainers. The current queue with |
| 67 | 67 | patches under review can be found at: |
| 68 | 68 | |
| 69 | − https://patchwork.ozlabs.org/project/netdev/list/?delegate=77147 | |
| 69 | + https://patchwork.kernel.org/project/netdevbpf/list/?delegate=121173 | |
| 70 | 70 | |
| 71 | 71 | Once the patches have been reviewed by the BPF community as a whole |
| 72 | 72 | and approved by the BPF maintainers, their status in patchwork will be |
| @@ -149,7 +149,7 @@ In case the patch or patch series has to be reworked and sent out · 76 unmodified lines | ||
| 149 | 149 | again in a second or later revision, it is also required to add a |
| 150 | 150 | version number (``v2``, ``v3``, ...) into the subject prefix:: |
| 151 | 151 | |
| 152 | − git format-patch --subject-prefix='PATCH net-next v2' start..finish | |
| 152 | + git format-patch --subject-prefix='PATCH bpf-next v2' start..finish | |
| 153 | 153 | |
| 154 | 154 | When changes have been requested to the patch series, always send the |
| 155 | 155 | whole patch series again with the feedback incorporated (never send |
| @@ -479,17 +479,18 @@ LLVM's static compiler lists the supported targets through · 323 unmodified lines | ||
| 479 | 479 | |
| 480 | 480 | $ llc --version |
| 481 | 481 | LLVM (http://llvm.org/): |
| 482 | − LLVM version 6.0.0svn | |
| 482 | + LLVM version 10.0.0 | |
| 483 | 483 | Optimized build. |
| 484 | 484 | Default target: x86_64-unknown-linux-gnu |
| 485 | 485 | Host CPU: skylake |
| 486 | 486 | |
| 487 | 487 | Registered Targets: |
| 488 | − bpf - BPF (host endian) | |
| 489 | − bpfeb - BPF (big endian) | |
| 490 | − bpfel - BPF (little endian) | |
| 491 | − x86 - 32-bit X86: Pentium-Pro and above | |
| 492 | − x86-64 - 64-bit X86: EM64T and AMD64 | |
| 488 | + aarch64 - AArch64 (little endian) | |
| 489 | + bpf - BPF (host endian) | |
| 490 | + bpfeb - BPF (big endian) | |
| 491 | + bpfel - BPF (little endian) | |
| 492 | + x86 - 32-bit X86: Pentium-Pro and above | |
| 493 | + x86-64 - 64-bit X86: EM64T and AMD64 | |
| 493 | 494 | |
| 494 | 495 | For developers in order to utilize the latest features added to LLVM's |
| 495 | 496 | BPF back end, it is advisable to run the latest LLVM releases. Support |
| @@ -517,6 +518,10 @@ from the git repositories:: · 21 unmodified lines | ||
| 517 | 518 | The built binaries can then be found in the build/bin/ directory, where |
| 518 | 519 | you can point the PATH variable to. |
| 519 | 520 | |
| 521 | +Set ``-DLLVM_TARGETS_TO_BUILD`` equal to the target you wish to build, you | |
| 522 | +will find a full list of targets within the llvm-project/llvm/lib/Target | |
| 523 | +directory. | |
| 524 | + | |
| 520 | 525 | Q: Reporting LLVM BPF issues |
| 521 | 526 | ---------------------------- |
| 522 | 527 | Q: Should I notify BPF kernel maintainers about issues in LLVM's BPF code |
| @@ -724,6 +724,31 @@ want to define unused entry in BTF_ID_LIST, like:: · 723 unmodified lines | ||
| 724 | 724 | BTF_ID_UNUSED |
| 725 | 725 | BTF_ID(struct, task_struct) |
| 726 | 726 | |
| 727 | +The ``BTF_SET_START/END`` macros pair defines sorted list of BTF ID values | |
| 728 | +and their count, with following syntax:: | |
| 729 | + | |
| 730 | + BTF_SET_START(set) | |
| 731 | + BTF_ID(type1, name1) | |
| 732 | + BTF_ID(type2, name2) | |
| 733 | + BTF_SET_END(set) | |
| 734 | + | |
| 735 | +resulting in following layout in .BTF_ids section:: | |
| 736 | + | |
| 737 | + __BTF_ID__set__set: | |
| 738 | + .zero 4 | |
| 739 | + __BTF_ID__type1__name1__3: | |
| 740 | + .zero 4 | |
| 741 | + __BTF_ID__type2__name2__4: | |
| 742 | + .zero 4 | |
| 743 | + | |
| 744 | +The ``struct btf_id_set set;`` variable is defined to access the list. | |
| 745 | + | |
| 746 | +The ``typeX`` name can be one of following:: | |
| 747 | + | |
| 748 | + struct, union, typedef, func | |
| 749 | + | |
| 750 | +and is used as a filter when resolving the BTF ID value. | |
| 751 | + | |
| 727 | 752 | All the BTF ID lists and sets are compiled in the .BTF_ids section and |
| 728 | 753 | resolved during the linking phase of kernel build by ``resolve_btfids`` tool. |
| 729 | 754 | |
| @@ -52,6 +52,7 @@ Program types · 51 unmodified lines | ||
| 52 | 52 | prog_cgroup_sysctl |
| 53 | 53 | prog_flow_dissector |
| 54 | 54 | bpf_lsm |
| 55 | + prog_sk_lookup | |
| 55 | 56 | |
| 56 | 57 | |
| 57 | 58 | Map types |
| @@ -0,0 +1,98 @@ | ||
| 1 | +.. SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +===================== | |
| 4 | +BPF sk_lookup program | |
| 5 | +===================== | |
| 6 | + | |
| 7 | +BPF sk_lookup program type (``BPF_PROG_TYPE_SK_LOOKUP``) introduces programmability | |
| 8 | +into the socket lookup performed by the transport layer when a packet is to be | |
| 9 | +delivered locally. | |
| 10 | + | |
| 11 | +When invoked BPF sk_lookup program can select a socket that will receive the | |
| 12 | +incoming packet by calling the ``bpf_sk_assign()`` BPF helper function. | |
| 13 | + | |
| 14 | +Hooks for a common attach point (``BPF_SK_LOOKUP``) exist for both TCP and UDP. | |
| 15 | + | |
| 16 | +Motivation | |
| 17 | +========== | |
| 18 | + | |
| 19 | +BPF sk_lookup program type was introduced to address setup scenarios where | |
| 20 | +binding sockets to an address with ``bind()`` socket call is impractical, such | |
| 21 | +as: | |
| 22 | + | |
| 23 | +1. receiving connections on a range of IP addresses, e.g. 192.0.2.0/24, when | |
| 24 | + binding to a wildcard address ``INADRR_ANY`` is not possible due to a port | |
| 25 | + conflict, | |
| 26 | +2. receiving connections on all or a wide range of ports, i.e. an L7 proxy use | |
| 27 | + case. | |
| 28 | + | |
| 29 | +Such setups would require creating and ``bind()``'ing one socket to each of the | |
| 30 | +IP address/port in the range, leading to resource consumption and potential | |
| 31 | +latency spikes during socket lookup. | |
| 32 | + | |
| 33 | +Attachment | |
| 34 | +========== | |
| 35 | + | |
| 36 | +BPF sk_lookup program can be attached to a network namespace with | |
| 37 | +``bpf(BPF_LINK_CREATE, ...)`` syscall using the ``BPF_SK_LOOKUP`` attach type and a | |
| 38 | +netns FD as attachment ``target_fd``. | |
| 39 | + | |
| 40 | +Multiple programs can be attached to one network namespace. Programs will be | |
| 41 | +invoked in the same order as they were attached. | |
| 42 | + | |
| 43 | +Hooks | |
| 44 | +===== | |
| 45 | + | |
| 46 | +The attached BPF sk_lookup programs run whenever the transport layer needs to | |
| 47 | +find a listening (TCP) or an unconnected (UDP) socket for an incoming packet. | |
| 48 | + | |
| 49 | +Incoming traffic to established (TCP) and connected (UDP) sockets is delivered | |
| 50 | +as usual without triggering the BPF sk_lookup hook. | |
| 51 | + | |
| 52 | +The attached BPF programs must return with either ``SK_PASS`` or ``SK_DROP`` | |
| 53 | +verdict code. As for other BPF program types that are network filters, | |
| 54 | +``SK_PASS`` signifies that the socket lookup should continue on to regular | |
| 55 | +hashtable-based lookup, while ``SK_DROP`` causes the transport layer to drop the | |
| 56 | +packet. | |
| 57 | + | |
| 58 | +A BPF sk_lookup program can also select a socket to receive the packet by | |
| 59 | +calling ``bpf_sk_assign()`` BPF helper. Typically, the program looks up a socket | |
| 60 | +in a map holding sockets, such as ``SOCKMAP`` or ``SOCKHASH``, and passes a | |
| 61 | +``struct bpf_sock *`` to ``bpf_sk_assign()`` helper to record the | |
| 62 | +selection. Selecting a socket only takes effect if the program has terminated | |
| 63 | +with ``SK_PASS`` code. | |
| 64 | + | |
| 65 | +When multiple programs are attached, the end result is determined from return | |
| 66 | +codes of all the programs according to the following rules: | |
| 67 | + | |
| 68 | +1. If any program returned ``SK_PASS`` and selected a valid socket, the socket | |
| 69 | + is used as the result of the socket lookup. | |
| 70 | +2. If more than one program returned ``SK_PASS`` and selected a socket, the last | |
| 71 | + selection takes effect. | |
| 72 | +3. If any program returned ``SK_DROP``, and no program returned ``SK_PASS`` and | |
| 73 | + selected a socket, socket lookup fails. | |
| 74 | +4. If all programs returned ``SK_PASS`` and none of them selected a socket, | |
| 75 | + socket lookup continues on. | |
| 76 | + | |
| 77 | +API | |
| 78 | +=== | |
| 79 | + | |
| 80 | +In its context, an instance of ``struct bpf_sk_lookup``, BPF sk_lookup program | |
| 81 | +receives information about the packet that triggered the socket lookup. Namely: | |
| 82 | + | |
| 83 | +* IP version (``AF_INET`` or ``AF_INET6``), | |
| 84 | +* L4 protocol identifier (``IPPROTO_TCP`` or ``IPPROTO_UDP``), | |
| 85 | +* source and destination IP address, | |
| 86 | +* source and destination L4 port, | |
| 87 | +* the socket that has been selected with ``bpf_sk_assign()``. | |
| 88 | + | |
| 89 | +Refer to ``struct bpf_sk_lookup`` declaration in ``linux/bpf.h`` user API | |
| 90 | +header, and `bpf-helpers(7) | |
| 91 | +<https://man7.org/linux/man-pages/man7/bpf-helpers.7.html>`_ man-page section | |
| 92 | +for ``bpf_sk_assign()`` for details. | |
| 93 | + | |
| 94 | +Example | |
| 95 | +======= | |
| 96 | + | |
| 97 | +See ``tools/testing/selftests/bpf/prog_tests/sk_lookup.c`` for the reference | |
| 98 | +implementation. | |
| @@ -50,6 +50,13 @@ Optional properties: · 49 unmodified lines | ||
| 50 | 50 | - reset-names: If the "reset" property is specified, this property should have |
| 51 | 51 | the value "switch" to denote the switch reset line. |
| 52 | 52 | |
| 53 | +- clocks: when provided, the first phandle is to the switch's main clock and | |
| 54 | + is valid for both BCM7445 and BCM7278. The second phandle is only applicable | |
| 55 | + to BCM7445 and is to support dividing the switch core clock. | |
| 56 | + | |
| 57 | +- clock-names: when provided, the first phandle must be "sw_switch", and the | |
| 58 | + second must be named "sw_switch_mdiv". | |
| 59 | + | |
| 53 | 60 | Port subnodes: |
| 54 | 61 | |
| 55 | 62 | Optional properties: |
| @@ -20,6 +20,11 @@ Optional properties: · 19 unmodified lines | ||
| 20 | 20 | - systemport,num-tier1-arb: number of tier 1 arbiters, an integer |
| 21 | 21 | - systemport,num-txq: number of HW transmit queues, an integer |
| 22 | 22 | - systemport,num-rxq: number of HW receive queues, an integer |
| 23 | +- clocks: When provided, must be two phandles to the functional clocks nodes of | |
| 24 | + the SYSTEMPORT block. The first phandle is the main SYSTEMPORT clock used | |
| 25 | + during normal operation, while the second phandle is the Wake-on-LAN clock. | |
| 26 | +- clock-names: When provided, names of the functional clock phandles, first | |
| 27 | + name should be "sw_sysport" and second should be "sw_sysportwol". | |
| 23 | 28 | |
| 24 | 29 | Example: |
| 25 | 30 | ethernet@f04a0000 { |
| @@ -4,6 +4,12 @@ Required properties: · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | - compatible : Should be "fsl,<processor>-flexcan" |
| 6 | 6 | |
| 7 | + where <processor> is imx8qm, imx6q, imx28, imx53, imx35, imx25, p1010, | |
| 8 | + vf610, ls1021ar2, lx2160ar1, ls1028ar1. | |
| 9 | + | |
| 10 | + The ls1028ar1 must be followed by lx2160ar1, e.g. | |
| 11 | + - "fsl,ls1028ar1-flexcan", "fsl,lx2160ar1-flexcan" | |
| 12 | + | |
| 7 | 13 | An implementation should also claim any of the following compatibles |
| 8 | 14 | that it is fully backwards compatible with: |
| 9 | 15 | |
| @@ -25,12 +31,10 @@ Optional properties: · 15 unmodified lines | ||
| 25 | 31 | endian. |
| 26 | 32 | |
| 27 | 33 | - fsl,stop-mode: register bits of stop mode control, the format is |
| 28 | − <&gpr req_gpr req_bit ack_gpr ack_bit>. | |
| 34 | + <&gpr req_gpr req_bit>. | |
| 29 | 35 | gpr is the phandle to general purpose register node. |
| 30 | 36 | req_gpr is the gpr register offset of CAN stop request. |
| 31 | 37 | req_bit is the bit offset of CAN stop request. |
| 32 | − ack_gpr is the gpr register offset of CAN stop acknowledge. | |
| 33 | − ack_bit is the bit offset of CAN stop acknowledge. | |
| 34 | 38 | |
| 35 | 39 | - fsl,clk-source: Select the clock source to the CAN Protocol Engine (PE). |
| 36 | 40 | It's SoC Implementation dependent. Refer to RM for detailed |
| @@ -12,6 +12,9 @@ Required properties: · 11 unmodified lines | ||
| 12 | 12 | Optional properties: |
| 13 | 13 | - vdd-supply: Regulator that powers the CAN controller. |
| 14 | 14 | - xceiver-supply: Regulator that powers the CAN transceiver. |
| 15 | + - gpio-controller: Indicates this device is a GPIO controller. | |
| 16 | + - #gpio-cells: Should be two. The first cell is the pin number and | |
| 17 | + the second cell is used to specify the gpio polarity. | |
| 15 | 18 | |
| 16 | 19 | Example: |
| 17 | 20 | can0: can@1 { |
| @@ -19,7 +22,9 @@ Example: · 1 unmodified line | ||
| 19 | 22 | reg = <1>; |
| 20 | 23 | clocks = <&clk24m>; |
| 21 | 24 | interrupt-parent = <&gpio4>; |
| 22 | − interrupts = <13 0x2>; | |
| 25 | + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; | |
| 23 | 26 | vdd-supply = <®5v0>; |
| 24 | 27 | xceiver-supply = <®5v0>; |
| 28 | + gpio-controller; | |
| 29 | + #gpio-cells = <2>; | |
| 25 | 30 | }; |
| @@ -0,0 +1,79 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/can/microchip,mcp251xfd.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: | |
| 8 | + Microchip MCP2517FD and MCP2518FD stand-alone CAN controller device tree | |
| 9 | + bindings | |
| 10 | + | |
| 11 | +maintainers: | |
| 12 | + - Marc Kleine-Budde <mkl@pengutronix.de> | |
| 13 | + | |
| 14 | +properties: | |
| 15 | + compatible: | |
| 16 | + oneOf: | |
| 17 | + - const: microchip,mcp2517fd | |
| 18 | + description: for MCP2517FD | |
| 19 | + - const: microchip,mcp2518fd | |
| 20 | + description: for MCP2518FD | |
| 21 | + - const: microchip,mcp251xfd | |
| 22 | + description: to autodetect chip variant | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + interrupts: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + clocks: | |
| 31 | + maxItems: 1 | |
| 32 | + | |
| 33 | + vdd-supply: | |
| 34 | + description: Regulator that powers the CAN controller. | |
| 35 | + | |
| 36 | + xceiver-supply: | |
| 37 | + description: Regulator that powers the CAN transceiver. | |
| 38 | + | |
| 39 | + microchip,rx-int-gpios: | |
| 40 | + description: | |
| 41 | + GPIO phandle of GPIO connected to to INT1 pin of the MCP251XFD, which | |
| 42 | + signals a pending RX interrupt. | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | + spi-max-frequency: | |
| 46 | + description: | |
| 47 | + Must be half or less of "clocks" frequency. | |
| 48 | + maximum: 20000000 | |
| 49 | + | |
| 50 | +required: | |
| 51 | + - compatible | |
| 52 | + - reg | |
| 53 | + - interrupts | |
| 54 | + - clocks | |
| 55 | + | |
| 56 | +additionalProperties: false | |
| 57 | + | |
| 58 | +examples: | |
| 59 | + - | | |
| 60 | + #include <dt-bindings/gpio/gpio.h> | |
| 61 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 62 | + | |
| 63 | + spi0 { | |
| 64 | + #address-cells = <1>; | |
| 65 | + #size-cells = <0>; | |
| 66 | + | |
| 67 | + can@0 { | |
| 68 | + compatible = "microchip,mcp251xfd"; | |
| 69 | + reg = <0>; | |
| 70 | + clocks = <&can0_osc>; | |
| 71 | + pinctrl-names = "default"; | |
| 72 | + pinctrl-0 = <&can0_pins>; | |
| 73 | + spi-max-frequency = <20000000>; | |
| 74 | + interrupts-extended = <&gpio 13 IRQ_TYPE_LEVEL_LOW>; | |
| 75 | + microchip,rx-int-gpios = <&gpio 27 GPIO_ACTIVE_LOW>; | |
| 76 | + vdd-supply = <®5v0>; | |
| 77 | + xceiver-supply = <®5v0>; | |
| 78 | + }; | |
| 79 | + }; | |
| @@ -2,13 +2,15 @@ Renesas R-Car CAN controller Device Tree Bindings · 1 unmodified line | ||
| 2 | 2 | ------------------------------------------------- |
| 3 | 3 | |
| 4 | 4 | Required properties: |
| 5 | −- compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. | |
| 5 | +- compatible: "renesas,can-r8a7742" if CAN controller is a part of R8A7742 SoC. | |
| 6 | + "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. | |
| 6 | 7 | "renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC. |
| 7 | 8 | "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC. |
| 8 | 9 | "renesas,can-r8a77470" if CAN controller is a part of R8A77470 SoC. |
| 9 | 10 | "renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC. |
| 10 | 11 | "renesas,can-r8a774b1" if CAN controller is a part of R8A774B1 SoC. |
| 11 | 12 | "renesas,can-r8a774c0" if CAN controller is a part of R8A774C0 SoC. |
| 13 | + "renesas,can-r8a774e1" if CAN controller is a part of R8A774E1 SoC. | |
| 12 | 14 | "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. |
| 13 | 15 | "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC. |
| 14 | 16 | "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC. |
| @@ -37,8 +39,8 @@ Required properties: · 22 unmodified lines | ||
| 37 | 39 | - pinctrl-0: pin control group to be used for this controller. |
| 38 | 40 | - pinctrl-names: must be "default". |
| 39 | 41 | |
| 40 | −Required properties for R8A774A1, R8A774B1, R8A774C0, R8A7795, R8A7796, | |
| 41 | −R8A77965, R8A77990, and R8A77995: | |
| 42 | +Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795, | |
| 43 | +R8A7796, R8A77965, R8A77990, and R8A77995: | |
| 42 | 44 | For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can |
| 43 | 45 | be used by both CAN and CAN FD controller at the same time. It needs to be |
| 44 | 46 | scaled to maximum frequency if any of these controllers use it. This is done |
| @@ -7,6 +7,7 @@ Required properties: · 6 unmodified lines | ||
| 7 | 7 | - "renesas,r8a774a1-canfd" for R8A774A1 (RZ/G2M) compatible controller. |
| 8 | 8 | - "renesas,r8a774b1-canfd" for R8A774B1 (RZ/G2N) compatible controller. |
| 9 | 9 | - "renesas,r8a774c0-canfd" for R8A774C0 (RZ/G2E) compatible controller. |
| 10 | + - "renesas,r8a774e1-canfd" for R8A774E1 (RZ/G2H) compatible controller. | |
| 10 | 11 | - "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller. |
| 11 | 12 | - "renesas,r8a7796-canfd" for R8A7796 (R-Car M3-W) compatible controller. |
| 12 | 13 | - "renesas,r8a77965-canfd" for R8A77965 (R-Car M3-N) compatible controller. |
| @@ -32,8 +33,8 @@ The name of the child nodes are "channel0" and "channel1" respectively. Each · 19 unmodified lines | ||
| 32 | 33 | child node supports the "status" property only, which is used to |
| 33 | 34 | enable/disable the respective channel. |
| 34 | 35 | |
| 35 | −Required properties for R8A774A1, R8A774B1, R8A774C0, R8A7795, R8A7796, | |
| 36 | −R8A77965, R8A77990, and R8A77995: | |
| 36 | +Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795, | |
| 37 | +R8A7796, R8A77965, R8A77990, and R8A77995: | |
| 37 | 38 | In the denoted SoCs, canfd clock is a div6 clock and can be used by both CAN |
| 38 | 39 | and CAN FD controller at the same time. It needs to be scaled to maximum |
| 39 | 40 | frequency if any of these controllers use it. This is done using the below |
| @@ -95,7 +95,7 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0: · 94 unmodified lines | ||
| 95 | 95 | |
| 96 | 96 | fixed-link { |
| 97 | 97 | speed = <1000>; |
| 98 | − duplex-full; | |
| 98 | + full-duplex; | |
| 99 | 99 | }; |
| 100 | 100 | }; |
| 101 | 101 | |
| @@ -104,8 +104,9 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0: · 2 unmodified lines | ||
| 104 | 104 | #address-cells = <1>; |
| 105 | 105 | #size-cells = <0>; |
| 106 | 106 | |
| 107 | − switch0: ethernet-switch@30 { | |
| 107 | + switch0: ethernet-switch@1e { | |
| 108 | 108 | compatible = "brcm,bcm53125"; |
| 109 | + reg = <30>; | |
| 109 | 110 | #address-cells = <1>; |
| 110 | 111 | #size-cells = <0>; |
| 111 | 112 | |
| @@ -128,7 +129,7 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0: · 16 unmodified lines | ||
| 128 | 129 | label = "cable-modem"; |
| 129 | 130 | fixed-link { |
| 130 | 131 | speed = <1000>; |
| 131 | − duplex-full; | |
| 132 | + full-duplex; | |
| 132 | 133 | }; |
| 133 | 134 | phy-mode = "rgmii-txid"; |
| 134 | 135 | }; |
| @@ -138,7 +139,7 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0: · 3 unmodified lines | ||
| 138 | 139 | label = "cpu"; |
| 139 | 140 | fixed-link { |
| 140 | 141 | speed = <1000>; |
| 141 | − duplex-full; | |
| 142 | + full-duplex; | |
| 142 | 143 | }; |
| 143 | 144 | phy-mode = "rgmii-txid"; |
| 144 | 145 | ethernet = <ð0>; |
| @@ -5,6 +5,7 @@ Required properties: · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | - compatible: may be compatible = "mediatek,mt7530" |
| 7 | 7 | or compatible = "mediatek,mt7621" |
| 8 | + or compatible = "mediatek,mt7531" | |
| 8 | 9 | - #address-cells: Must be 1. |
| 9 | 10 | - #size-cells: Must be 0. |
| 10 | 11 | - mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part |
| @@ -32,10 +33,14 @@ Required properties for the child nodes within ports container: · 21 unmodified lines | ||
| 32 | 33 | |
| 33 | 34 | - reg: Port address described must be 6 for CPU port and from 0 to 5 for |
| 34 | 35 | user ports. |
| 35 | −- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled | |
| 36 | − "cpu". | |
| 37 | − | |
| 38 | −Port 5 of the switch is muxed between: | |
| 36 | +- phy-mode: String, the following values are acceptable for port labeled | |
| 37 | + "cpu": | |
| 38 | + If compatible mediatek,mt7530 or mediatek,mt7621 is set, | |
| 39 | + must be either "trgmii" or "rgmii" | |
| 40 | + If compatible mediatek,mt7531 is set, | |
| 41 | + must be either "sgmii", "1000base-x" or "2500base-x" | |
| 42 | + | |
| 43 | +Port 5 of mt7530 and mt7621 switch is muxed between: | |
| 39 | 44 | 1. GMAC5: GMAC5 can interface with another external MAC or PHY. |
| 40 | 45 | 2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC |
| 41 | 46 | of the SOC. Used in many setups where port 0/4 becomes the WAN port. |
| @@ -120,6 +120,13 @@ properties: · 119 unmodified lines | ||
| 120 | 120 | and is useful for determining certain configuration settings |
| 121 | 121 | such as flow control thresholds. |
| 122 | 122 | |
| 123 | + rx-internal-delay-ps: | |
| 124 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 125 | + description: | | |
| 126 | + RGMII Receive Clock Delay defined in pico seconds. | |
| 127 | + This is used for controllers that have configurable RX internal delays. | |
| 128 | + If this property is present then the MAC applies the RX delay. | |
| 129 | + | |
| 123 | 130 | sfp: |
| 124 | 131 | $ref: /schemas/types.yaml#definitions/phandle |
| 125 | 132 | description: |
| @@ -131,6 +138,13 @@ properties: · 5 unmodified lines | ||
| 131 | 138 | The size of the controller\'s transmit fifo in bytes. This |
| 132 | 139 | is used for components that can have configurable fifo sizes. |
| 133 | 140 | |
| 141 | + tx-internal-delay-ps: | |
| 142 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 143 | + description: | | |
| 144 | + RGMII Transmit Clock Delay defined in pico seconds. | |
| 145 | + This is used for controllers that have configurable TX internal delays. | |
| 146 | + If this property is present then the MAC applies the TX delay. | |
| 147 | + | |
| 134 | 148 | managed: |
| 135 | 149 | description: |
| 136 | 150 | Specifies the PHY management type. If auto is set and fixed-link |
| @@ -0,0 +1,130 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/net/intel,dwmac-plat.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Intel DWMAC glue layer Device Tree Bindings | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Vineetha G. Jaya Kumaran <vineetha.g.jaya.kumaran@intel.com> | |
| 11 | + | |
| 12 | +select: | |
| 13 | + properties: | |
| 14 | + compatible: | |
| 15 | + contains: | |
| 16 | + enum: | |
| 17 | + - intel,keembay-dwmac | |
| 18 | + required: | |
| 19 | + - compatible | |
| 20 | + | |
| 21 | +allOf: | |
| 22 | + - $ref: "snps,dwmac.yaml#" | |
| 23 | + | |
| 24 | +properties: | |
| 25 | + compatible: | |
| 26 | + oneOf: | |
| 27 | + - items: | |
| 28 | + - enum: | |
| 29 | + - intel,keembay-dwmac | |
| 30 | + - const: snps,dwmac-4.10a | |
| 31 | + | |
| 32 | + clocks: | |
| 33 | + items: | |
| 34 | + - description: GMAC main clock | |
| 35 | + - description: PTP reference clock | |
| 36 | + - description: Tx clock | |
| 37 | + | |
| 38 | + clock-names: | |
| 39 | + items: | |
| 40 | + - const: stmmaceth | |
| 41 | + - const: ptp_ref | |
| 42 | + - const: tx_clk | |
| 43 | + | |
| 44 | +required: | |
| 45 | + - compatible | |
| 46 | + - clocks | |
| 47 | + - clock-names | |
| 48 | + | |
| 49 | +examples: | |
| 50 | +# FIXME: Remove defines and include the correct header file | |
| 51 | +# once it is available in mainline. | |
| 52 | + - | | |
| 53 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 54 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 55 | + #define MOVISOC_KMB_PSS_GBE | |
| 56 | + #define MOVISOC_KMB_PSS_AUX_GBE_PTP | |
| 57 | + #define MOVISOC_KMB_PSS_AUX_GBE_TX | |
| 58 | + | |
| 59 | + stmmac_axi_setup: stmmac-axi-config { | |
| 60 | + snps,lpi_en; | |
| 61 | + snps,wr_osr_lmt = <0x0>; | |
| 62 | + snps,rd_osr_lmt = <0x2>; | |
| 63 | + snps,blen = <0 0 0 0 16 8 4>; | |
| 64 | + }; | |
| 65 | + | |
| 66 | + mtl_rx_setup: rx-queues-config { | |
| 67 | + snps,rx-queues-to-use = <2>; | |
| 68 | + snps,rx-sched-sp; | |
| 69 | + queue0 { | |
| 70 | + snps,dcb-algorithm; | |
| 71 | + snps,map-to-dma-channel = <0x0>; | |
| 72 | + snps,priority = <0x0>; | |
| 73 | + }; | |
| 74 | + | |
| 75 | + queue1 { | |
| 76 | + snps,dcb-algorithm; | |
| 77 | + snps,map-to-dma-channel = <0x1>; | |
| 78 | + snps,priority = <0x1>; | |
| 79 | + }; | |
| 80 | + }; | |
| 81 | + | |
| 82 | + mtl_tx_setup: tx-queues-config { | |
| 83 | + snps,tx-queues-to-use = <2>; | |
| 84 | + snps,tx-sched-wrr; | |
| 85 | + queue0 { | |
| 86 | + snps,weight = <0x10>; | |
| 87 | + snps,dcb-algorithm; | |
| 88 | + snps,priority = <0x0>; | |
| 89 | + }; | |
| 90 | + | |
| 91 | + queue1 { | |
| 92 | + snps,weight = <0x10>; | |
| 93 | + snps,dcb-algorithm; | |
| 94 | + snps,priority = <0x1>; | |
| 95 | + }; | |
| 96 | + }; | |
| 97 | + | |
| 98 | + gmac0: ethernet@3a000000 { | |
| 99 | + compatible = "intel,keembay-dwmac", "snps,dwmac-4.10a"; | |
| 100 | + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; | |
| 101 | + interrupt-names = "macirq"; | |
| 102 | + reg = <0x3a000000 0x8000>; | |
| 103 | + snps,perfect-filter-entries = <128>; | |
| 104 | + phy-handle = <ð_phy0>; | |
| 105 | + phy-mode = "rgmii"; | |
| 106 | + rx-fifo-depth = <4096>; | |
| 107 | + tx-fifo-depth = <4096>; | |
| 108 | + clock-names = "stmmaceth", "ptp_ref", "tx_clk"; | |
| 109 | + clocks = <&scmi_clk MOVISOC_KMB_PSS_GBE>, | |
| 110 | + <&scmi_clk MOVISOC_KMB_PSS_AUX_GBE_PTP>, | |
| 111 | + <&scmi_clk MOVISOC_KMB_PSS_AUX_GBE_TX>; | |
| 112 | + snps,pbl = <0x4>; | |
| 113 | + snps,axi-config = <&stmmac_axi_setup>; | |
| 114 | + snps,mtl-rx-config = <&mtl_rx_setup>; | |
| 115 | + snps,mtl-tx-config = <&mtl_tx_setup>; | |
| 116 | + snps,tso; | |
| 117 | + status = "okay"; | |
| 118 | + | |
| 119 | + mdio0 { | |
| 120 | + #address-cells = <1>; | |
| 121 | + #size-cells = <0>; | |
| 122 | + compatible = "snps,dwmac-mdio"; | |
| 123 | + | |
| 124 | + ethernet-phy@0 { | |
| 125 | + reg = <0>; | |
| 126 | + }; | |
| 127 | + }; | |
| 128 | + }; | |
| 129 | + | |
| 130 | +... | |
| @@ -45,3 +45,37 @@ dfx-server { · 44 unmodified lines | ||
| 45 | 45 | ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; |
| 46 | 46 | reg = <MBUS_ID(0x08, 0x00) 0 0x100000>; |
| 47 | 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 | +}; | |
| @@ -1,25 +0,0 @@ | ||
| 1 | −* Samsung S3FWRN5 NCI NFC Controller | |
| 2 | − | |
| 3 | −Required properties: | |
| 4 | −- compatible: Should be "samsung,s3fwrn5-i2c". | |
| 5 | −- reg: address on the bus | |
| 6 | −- interrupts: GPIO interrupt to which the chip is connected | |
| 7 | −- s3fwrn5,en-gpios: Output GPIO pin used for enabling/disabling the chip | |
| 8 | −- s3fwrn5,fw-gpios: Output GPIO pin used to enter firmware mode and | |
| 9 | − sleep/wakeup control | |
| 10 | − | |
| 11 | −Example: | |
| 12 | − | |
| 13 | −&hsi2c_4 { | |
| 14 | − s3fwrn5@27 { | |
| 15 | − compatible = "samsung,s3fwrn5-i2c"; | |
| 16 | − | |
| 17 | − reg = <0x27>; | |
| 18 | − | |
| 19 | − interrupt-parent = <&gpa1>; | |
| 20 | − interrupts = <3 0 0>; | |
| 21 | − | |
| 22 | − s3fwrn5,en-gpios = <&gpf1 4 0>; | |
| 23 | − s3fwrn5,fw-gpios = <&gpj0 2 0>; | |
| 24 | − }; | |
| 25 | −}; | |
| @@ -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/nfc/samsung,s3fwrn5.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S3FWRN5 NCI NFC Controller | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzk@kernel.org> | |
| 11 | + - Krzysztof Opasiak <k.opasiak@samsung.com> | |
| 12 | + | |
| 13 | +properties: | |
| 14 | + compatible: | |
| 15 | + const: samsung,s3fwrn5-i2c | |
| 16 | + | |
| 17 | + en-gpios: | |
| 18 | + maxItems: 1 | |
| 19 | + description: | |
| 20 | + Output GPIO pin used for enabling/disabling the chip | |
| 21 | + | |
| 22 | + interrupts: | |
| 23 | + maxItems: 1 | |
| 24 | + | |
| 25 | + reg: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + wake-gpios: | |
| 29 | + maxItems: 1 | |
| 30 | + description: | |
| 31 | + Output GPIO pin used to enter firmware mode and sleep/wakeup control | |
| 32 | + | |
| 33 | + s3fwrn5,en-gpios: | |
| 34 | + maxItems: 1 | |
| 35 | + deprecated: true | |
| 36 | + description: | |
| 37 | + Use en-gpios | |
| 38 | + | |
| 39 | + s3fwrn5,fw-gpios: | |
| 40 | + maxItems: 1 | |
| 41 | + deprecated: true | |
| 42 | + description: | |
| 43 | + Use wake-gpios | |
| 44 | + | |
| 45 | +additionalProperties: false | |
| 46 | + | |
| 47 | +required: | |
| 48 | + - compatible | |
| 49 | + - en-gpios | |
| 50 | + - interrupts | |
| 51 | + - reg | |
| 52 | + - wake-gpios | |
| 53 | + | |
| 54 | +examples: | |
| 55 | + - | | |
| 56 | + #include <dt-bindings/gpio/gpio.h> | |
| 57 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 58 | + | |
| 59 | + i2c4 { | |
| 60 | + #address-cells = <1>; | |
| 61 | + #size-cells = <0>; | |
| 62 | + | |
| 63 | + s3fwrn5@27 { | |
| 64 | + compatible = "samsung,s3fwrn5-i2c"; | |
| 65 | + reg = <0x27>; | |
| 66 | + | |
| 67 | + interrupt-parent = <&gpa1>; | |
| 68 | + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; | |
| 69 | + | |
| 70 | + en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>; | |
| 71 | + wake-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>; | |
| 72 | + }; | |
| 73 | + }; | |
| @@ -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,etheravb.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Renesas Ethernet AVB | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Sergei Shtylyov <sergei.shtylyov@gmail.com> | |
| 11 | + | |
| 12 | +properties: | |
| 13 | + compatible: | |
| 14 | + oneOf: | |
| 15 | + - items: | |
| 16 | + - enum: | |
| 17 | + - renesas,etheravb-r8a7742 # RZ/G1H | |
| 18 | + - renesas,etheravb-r8a7743 # RZ/G1M | |
| 19 | + - renesas,etheravb-r8a7744 # RZ/G1N | |
| 20 | + - renesas,etheravb-r8a7745 # RZ/G1E | |
| 21 | + - renesas,etheravb-r8a77470 # RZ/G1C | |
| 22 | + - renesas,etheravb-r8a7790 # R-Car H2 | |
| 23 | + - renesas,etheravb-r8a7791 # R-Car M2-W | |
| 24 | + - renesas,etheravb-r8a7792 # R-Car V2H | |
| 25 | + - renesas,etheravb-r8a7793 # R-Car M2-N | |
| 26 | + - renesas,etheravb-r8a7794 # R-Car E2 | |
| 27 | + - const: renesas,etheravb-rcar-gen2 # R-Car Gen2 and RZ/G1 | |
| 28 | + | |
| 29 | + - items: | |
| 30 | + - enum: | |
| 31 | + - renesas,etheravb-r8a774a1 # RZ/G2M | |
| 32 | + - renesas,etheravb-r8a774b1 # RZ/G2N | |
| 33 | + - renesas,etheravb-r8a774c0 # RZ/G2E | |
| 34 | + - renesas,etheravb-r8a774e1 # RZ/G2H | |
| 35 | + - renesas,etheravb-r8a7795 # R-Car H3 | |
| 36 | + - renesas,etheravb-r8a7796 # R-Car M3-W | |
| 37 | + - renesas,etheravb-r8a77961 # R-Car M3-W+ | |
| 38 | + - renesas,etheravb-r8a77965 # R-Car M3-N | |
| 39 | + - renesas,etheravb-r8a77970 # R-Car V3M | |
| 40 | + - renesas,etheravb-r8a77980 # R-Car V3H | |
| 41 | + - renesas,etheravb-r8a77990 # R-Car E3 | |
| 42 | + - renesas,etheravb-r8a77995 # R-Car D3 | |
| 43 | + - const: renesas,etheravb-rcar-gen3 # R-Car Gen3 and RZ/G2 | |
| 44 | + | |
| 45 | + reg: true | |
| 46 | + | |
| 47 | + interrupts: true | |
| 48 | + | |
| 49 | + interrupt-names: true | |
| 50 | + | |
| 51 | + clocks: | |
| 52 | + maxItems: 1 | |
| 53 | + | |
| 54 | + iommus: | |
| 55 | + maxItems: 1 | |
| 56 | + | |
| 57 | + power-domains: | |
| 58 | + maxItems: 1 | |
| 59 | + | |
| 60 | + resets: | |
| 61 | + maxItems: 1 | |
| 62 | + | |
| 63 | + phy-mode: true | |
| 64 | + | |
| 65 | + phy-handle: true | |
| 66 | + | |
| 67 | + '#address-cells': | |
| 68 | + description: Number of address cells for the MDIO bus. | |
| 69 | + const: 1 | |
| 70 | + | |
| 71 | + '#size-cells': | |
| 72 | + description: Number of size cells on the MDIO bus. | |
| 73 | + const: 0 | |
| 74 | + | |
| 75 | + renesas,no-ether-link: | |
| 76 | + type: boolean | |
| 77 | + description: | |
| 78 | + Specify when a board does not provide a proper AVB_LINK signal. | |
| 79 | + | |
| 80 | + renesas,ether-link-active-low: | |
| 81 | + type: boolean | |
| 82 | + description: | |
| 83 | + Specify when the AVB_LINK signal is active-low instead of normal | |
| 84 | + active-high. | |
| 85 | + | |
| 86 | + rx-internal-delay-ps: | |
| 87 | + enum: [0, 1800] | |
| 88 | + | |
| 89 | + tx-internal-delay-ps: | |
| 90 | + enum: [0, 2000] | |
| 91 | + | |
| 92 | +patternProperties: | |
| 93 | + "^ethernet-phy@[0-9a-f]$": | |
| 94 | + type: object | |
| 95 | + $ref: ethernet-phy.yaml# | |
| 96 | + | |
| 97 | +required: | |
| 98 | + - compatible | |
| 99 | + - reg | |
| 100 | + - interrupts | |
| 101 | + - clocks | |
| 102 | + - power-domains | |
| 103 | + - resets | |
| 104 | + - phy-mode | |
| 105 | + - phy-handle | |
| 106 | + - '#address-cells' | |
| 107 | + - '#size-cells' | |
| 108 | + | |
| 109 | +allOf: | |
| 110 | + - $ref: ethernet-controller.yaml# | |
| 111 | + | |
| 112 | + - if: | |
| 113 | + properties: | |
| 114 | + compatible: | |
| 115 | + contains: | |
| 116 | + enum: | |
| 117 | + - renesas,etheravb-rcar-gen2 | |
| 118 | + - renesas,etheravb-r8a7795 | |
| 119 | + - renesas,etheravb-r8a7796 | |
| 120 | + - renesas,etheravb-r8a77961 | |
| 121 | + - renesas,etheravb-r8a77965 | |
| 122 | + then: | |
| 123 | + properties: | |
| 124 | + reg: | |
| 125 | + items: | |
| 126 | + - description: MAC register block | |
| 127 | + - description: Stream buffer | |
| 128 | + else: | |
| 129 | + properties: | |
| 130 | + reg: | |
| 131 | + items: | |
| 132 | + - description: MAC register block | |
| 133 | + | |
| 134 | + - if: | |
| 135 | + properties: | |
| 136 | + compatible: | |
| 137 | + contains: | |
| 138 | + const: renesas,etheravb-rcar-gen2 | |
| 139 | + then: | |
| 140 | + properties: | |
| 141 | + interrupts: | |
| 142 | + maxItems: 1 | |
| 143 | + interrupt-names: | |
| 144 | + items: | |
| 145 | + - const: mux | |
| 146 | + rx-internal-delay-ps: false | |
| 147 | + else: | |
| 148 | + properties: | |
| 149 | + interrupts: | |
| 150 | + minItems: 25 | |
| 151 | + maxItems: 25 | |
| 152 | + interrupt-names: | |
| 153 | + items: | |
| 154 | + pattern: '^ch[0-9]+$' | |
| 155 | + required: | |
| 156 | + - interrupt-names | |
| 157 | + - rx-internal-delay-ps | |
| 158 | + | |
| 159 | + - if: | |
| 160 | + properties: | |
| 161 | + compatible: | |
| 162 | + contains: | |
| 163 | + enum: | |
| 164 | + - renesas,etheravb-r8a774a1 | |
| 165 | + - renesas,etheravb-r8a774b1 | |
| 166 | + - renesas,etheravb-r8a7795 | |
| 167 | + - renesas,etheravb-r8a7796 | |
| 168 | + - renesas,etheravb-r8a77961 | |
| 169 | + - renesas,etheravb-r8a77965 | |
| 170 | + - renesas,etheravb-r8a77970 | |
| 171 | + - renesas,etheravb-r8a77980 | |
| 172 | + then: | |
| 173 | + required: | |
| 174 | + - tx-internal-delay-ps | |
| 175 | + else: | |
| 176 | + properties: | |
| 177 | + tx-internal-delay-ps: false | |
| 178 | + | |
| 179 | + - if: | |
| 180 | + properties: | |
| 181 | + compatible: | |
| 182 | + contains: | |
| 183 | + const: renesas,etheravb-r8a77995 | |
| 184 | + then: | |
| 185 | + properties: | |
| 186 | + rx-internal-delay-ps: | |
| 187 | + const: 1800 | |
| 188 | + | |
| 189 | + - if: | |
| 190 | + properties: | |
| 191 | + compatible: | |
| 192 | + contains: | |
| 193 | + const: renesas,etheravb-r8a77980 | |
| 194 | + then: | |
| 195 | + properties: | |
| 196 | + tx-internal-delay-ps: | |
| 197 | + const: 2000 | |
| 198 | + | |
| 199 | +additionalProperties: false | |
| 200 | + | |
| 201 | +examples: | |
| 202 | + - | | |
| 203 | + #include <dt-bindings/clock/r8a7795-cpg-mssr.h> | |
| 204 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 205 | + #include <dt-bindings/power/r8a7795-sysc.h> | |
| 206 | + #include <dt-bindings/gpio/gpio.h> | |
| 207 | + aliases { | |
| 208 | + ethernet0 = &avb; | |
| 209 | + }; | |
| 210 | + | |
| 211 | + avb: ethernet@e6800000 { | |
| 212 | + compatible = "renesas,etheravb-r8a7795", | |
| 213 | + "renesas,etheravb-rcar-gen3"; | |
| 214 | + reg = <0xe6800000 0x800>, <0xe6a00000 0x10000>; | |
| 215 | + interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, | |
| 216 | + <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, | |
| 217 | + <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>, | |
| 218 | + <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>, | |
| 219 | + <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>, | |
| 220 | + <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>, | |
| 221 | + <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>, | |
| 222 | + <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>, | |
| 223 | + <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>, | |
| 224 | + <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>, | |
| 225 | + <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, | |
| 226 | + <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>, | |
| 227 | + <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>, | |
| 228 | + <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, | |
| 229 | + <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>, | |
| 230 | + <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>, | |
| 231 | + <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>, | |
| 232 | + <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>, | |
| 233 | + <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>, | |
| 234 | + <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>, | |
| 235 | + <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>, | |
| 236 | + <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>, | |
| 237 | + <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>, | |
| 238 | + <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>, | |
| 239 | + <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>; | |
| 240 | + interrupt-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", | |
| 241 | + "ch7", "ch8", "ch9", "ch10", "ch11", "ch12", | |
| 242 | + "ch13", "ch14", "ch15", "ch16", "ch17", "ch18", | |
| 243 | + "ch19", "ch20", "ch21", "ch22", "ch23", "ch24"; | |
| 244 | + clocks = <&cpg CPG_MOD 812>; | |
| 245 | + iommus = <&ipmmu_ds0 16>; | |
| 246 | + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; | |
| 247 | + resets = <&cpg 812>; | |
| 248 | + phy-mode = "rgmii"; | |
| 249 | + phy-handle = <&phy0>; | |
| 250 | + rx-internal-delay-ps = <0>; | |
| 251 | + tx-internal-delay-ps = <2000>; | |
| 252 | + #address-cells = <1>; | |
| 253 | + #size-cells = <0>; | |
| 254 | + | |
| 255 | + phy0: ethernet-phy@0 { | |
| 256 | + rxc-skew-ps = <1500>; | |
| 257 | + reg = <0>; | |
| 258 | + interrupt-parent = <&gpio2>; | |
| 259 | + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; | |
| 260 | + reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; | |
| 261 | + }; | |
| 262 | + }; | |
| @@ -1,135 +0,0 @@ | ||
| 1 | −* Renesas Electronics Ethernet AVB | |
| 2 | − | |
| 3 | −This file provides information on what the device node for the Ethernet AVB | |
| 4 | −interface contains. | |
| 5 | − | |
| 6 | −Required properties: | |
| 7 | −- compatible: Must contain one or more of the following: | |
| 8 | − - "renesas,etheravb-r8a7742" for the R8A7742 SoC. | |
| 9 | − - "renesas,etheravb-r8a7743" for the R8A7743 SoC. | |
| 10 | − - "renesas,etheravb-r8a7744" for the R8A7744 SoC. | |
| 11 | − - "renesas,etheravb-r8a7745" for the R8A7745 SoC. | |
| 12 | − - "renesas,etheravb-r8a77470" for the R8A77470 SoC. | |
| 13 | − - "renesas,etheravb-r8a7790" for the R8A7790 SoC. | |
| 14 | − - "renesas,etheravb-r8a7791" for the R8A7791 SoC. | |
| 15 | − - "renesas,etheravb-r8a7792" for the R8A7792 SoC. | |
| 16 | − - "renesas,etheravb-r8a7793" for the R8A7793 SoC. | |
| 17 | − - "renesas,etheravb-r8a7794" for the R8A7794 SoC. | |
| 18 | − - "renesas,etheravb-rcar-gen2" as a fallback for the above | |
| 19 | − R-Car Gen2 and RZ/G1 devices. | |
| 20 | − | |
| 21 | − - "renesas,etheravb-r8a774a1" for the R8A774A1 SoC. | |
| 22 | − - "renesas,etheravb-r8a774b1" for the R8A774B1 SoC. | |
| 23 | − - "renesas,etheravb-r8a774c0" for the R8A774C0 SoC. | |
| 24 | − - "renesas,etheravb-r8a774e1" for the R8A774E1 SoC. | |
| 25 | − - "renesas,etheravb-r8a7795" for the R8A7795 SoC. | |
| 26 | − - "renesas,etheravb-r8a7796" for the R8A77960 SoC. | |
| 27 | − - "renesas,etheravb-r8a77961" for the R8A77961 SoC. | |
| 28 | − - "renesas,etheravb-r8a77965" for the R8A77965 SoC. | |
| 29 | − - "renesas,etheravb-r8a77970" for the R8A77970 SoC. | |
| 30 | − - "renesas,etheravb-r8a77980" for the R8A77980 SoC. | |
| 31 | − - "renesas,etheravb-r8a77990" for the R8A77990 SoC. | |
| 32 | − - "renesas,etheravb-r8a77995" for the R8A77995 SoC. | |
| 33 | − - "renesas,etheravb-rcar-gen3" as a fallback for the above | |
| 34 | − R-Car Gen3 and RZ/G2 devices. | |
| 35 | − | |
| 36 | − When compatible with the generic version, nodes must list the | |
| 37 | − SoC-specific version corresponding to the platform first followed by | |
| 38 | − the generic version. | |
| 39 | − | |
| 40 | −- reg: Offset and length of (1) the register block and (2) the stream buffer. | |
| 41 | − The region for the register block is mandatory. | |
| 42 | − The region for the stream buffer is optional, as it is only present on | |
| 43 | − R-Car Gen2 and RZ/G1 SoCs, and on R-Car H3 (R8A7795), M3-W (R8A77960), | |
| 44 | − M3-W+ (R8A77961), and M3-N (R8A77965). | |
| 45 | −- interrupts: A list of interrupt-specifiers, one for each entry in | |
| 46 | − interrupt-names. | |
| 47 | − If interrupt-names is not present, an interrupt specifier | |
| 48 | − for a single muxed interrupt. | |
| 49 | −- phy-mode: see ethernet.txt file in the same directory. | |
| 50 | −- phy-handle: see ethernet.txt file in the same directory. | |
| 51 | −- #address-cells: number of address cells for the MDIO bus, must be equal to 1. | |
| 52 | −- #size-cells: number of size cells on the MDIO bus, must be equal to 0. | |
| 53 | −- clocks: clock phandle and specifier pair. | |
| 54 | −- pinctrl-0: phandle, referring to a default pin configuration node. | |
| 55 | − | |
| 56 | −Optional properties: | |
| 57 | −- interrupt-names: A list of interrupt names. | |
| 58 | − For the R-Car Gen 3 SoCs this property is mandatory; | |
| 59 | − it should include one entry per channel, named "ch%u", | |
| 60 | − where %u is the channel number ranging from 0 to 24. | |
| 61 | − For other SoCs this property is optional; if present | |
| 62 | − it should contain "mux" for a single muxed interrupt. | |
| 63 | −- pinctrl-names: pin configuration state name ("default"). | |
| 64 | −- renesas,no-ether-link: boolean, specify when a board does not provide a proper | |
| 65 | − AVB_LINK signal. | |
| 66 | −- renesas,ether-link-active-low: boolean, specify when the AVB_LINK signal is | |
| 67 | − active-low instead of normal active-high. | |
| 68 | − | |
| 69 | −Example: | |
| 70 | − | |
| 71 | − ethernet@e6800000 { | |
| 72 | − compatible = "renesas,etheravb-r8a7795", "renesas,etheravb-rcar-gen3"; | |
| 73 | − reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>; | |
| 74 | − interrupt-parent = <&gic>; | |
| 75 | − interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, | |
| 76 | − <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, | |
| 77 | − <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>, | |
| 78 | − <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>, | |
| 79 | − <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>, | |
| 80 | − <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>, | |
| 81 | − <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>, | |
| 82 | − <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>, | |
| 83 | − <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>, | |
| 84 | − <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>, | |
| 85 | − <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, | |
| 86 | − <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>, | |
| 87 | − <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>, | |
| 88 | − <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, | |
| 89 | − <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>, | |
| 90 | − <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>, | |
| 91 | − <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>, | |
| 92 | − <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>, | |
| 93 | − <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>, | |
| 94 | − <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>, | |
| 95 | − <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>, | |
| 96 | − <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>, | |
| 97 | − <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>, | |
| 98 | − <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>, | |
| 99 | − <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>; | |
| 100 | − interrupt-names = "ch0", "ch1", "ch2", "ch3", | |
| 101 | − "ch4", "ch5", "ch6", "ch7", | |
| 102 | − "ch8", "ch9", "ch10", "ch11", | |
| 103 | − "ch12", "ch13", "ch14", "ch15", | |
| 104 | − "ch16", "ch17", "ch18", "ch19", | |
| 105 | − "ch20", "ch21", "ch22", "ch23", | |
| 106 | − "ch24"; | |
| 107 | − clocks = <&cpg CPG_MOD 812>; | |
| 108 | − power-domains = <&cpg>; | |
| 109 | − phy-mode = "rgmii-id"; | |
| 110 | − phy-handle = <&phy0>; | |
| 111 | − | |
| 112 | − pinctrl-0 = <ðer_pins>; | |
| 113 | − pinctrl-names = "default"; | |
| 114 | − renesas,no-ether-link; | |
| 115 | − #address-cells = <1>; | |
| 116 | − #size-cells = <0>; | |
| 117 | − | |
| 118 | − phy0: ethernet-phy@0 { | |
| 119 | − rxc-skew-ps = <900>; | |
| 120 | − rxdv-skew-ps = <0>; | |
| 121 | − rxd0-skew-ps = <0>; | |
| 122 | − rxd1-skew-ps = <0>; | |
| 123 | − rxd2-skew-ps = <0>; | |
| 124 | − rxd3-skew-ps = <0>; | |
| 125 | − txc-skew-ps = <900>; | |
| 126 | − txen-skew-ps = <0>; | |
| 127 | − txd0-skew-ps = <0>; | |
| 128 | − txd1-skew-ps = <0>; | |
| 129 | − txd2-skew-ps = <0>; | |
| 130 | − txd3-skew-ps = <0>; | |
| 131 | − reg = <0>; | |
| 132 | − interrupt-parent = <&gpio2>; | |
| 133 | − interrupts = <11 IRQ_TYPE_LEVEL_LOW>; | |
| 134 | − }; | |
| 135 | − }; | |
| @@ -5,6 +5,10 @@ through an Ethernet OF device node. · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | Optional properties: |
| 7 | 7 | |
| 8 | +- clocks: | |
| 9 | + The clock used as phy reference clock and is connected to phy | |
| 10 | + pin XTAL1/CLKIN. | |
| 11 | + | |
| 8 | 12 | - smsc,disable-energy-detect: |
| 9 | 13 | If set, do not enable energy detect mode for the SMSC phy. |
| 10 | 14 | default: enable energy detect mode |
| @@ -0,0 +1,80 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause) | |
| 2 | +# Copyright (C) 2020 Texas Instruments Incorporated | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/net/ti,dp83822.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: TI DP83822 ethernet PHY | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Dan Murphy <dmurphy@ti.com> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The DP83822 is a low-power, single-port, 10/100 Mbps Ethernet PHY. It | |
| 15 | + provides all of the physical layer functions needed to transmit and receive | |
| 16 | + data over standard, twisted-pair cables or to connect to an external, | |
| 17 | + fiber-optic transceiver. Additionally, the DP83822 provides flexibility to | |
| 18 | + connect to a MAC through a standard MII, RMII, or RGMII interface | |
| 19 | + | |
| 20 | + Specifications about the Ethernet PHY can be found at: | |
| 21 | + http://www.ti.com/lit/ds/symlink/dp83822i.pdf | |
| 22 | + | |
| 23 | +allOf: | |
| 24 | + - $ref: "ethernet-phy.yaml#" | |
| 25 | + | |
| 26 | +properties: | |
| 27 | + reg: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + ti,link-loss-low: | |
| 31 | + type: boolean | |
| 32 | + description: | | |
| 33 | + DP83822 PHY in Fiber mode only. | |
| 34 | + Sets the DP83822 to detect a link drop condition when the signal goes | |
| 35 | + high. If not set then link drop will occur when the signal goes low. | |
| 36 | + This property is only applicable if the fiber mode support is strapped | |
| 37 | + to on. | |
| 38 | + | |
| 39 | + ti,fiber-mode: | |
| 40 | + type: boolean | |
| 41 | + description: | | |
| 42 | + DP83822 PHY only. | |
| 43 | + If present the DP83822 PHY is configured to operate in fiber mode | |
| 44 | + Fiber mode support can also be strapped. If the strap pin is not set | |
| 45 | + correctly or not set at all then this boolean can be used to enable it. | |
| 46 | + If the fiber mode is not strapped then signal detection for the PHY | |
| 47 | + is disabled. | |
| 48 | + In fiber mode, auto-negotiation is disabled and the PHY can only work in | |
| 49 | + 100base-fx (full and half duplex) modes. | |
| 50 | + | |
| 51 | + rx-internal-delay-ps: | |
| 52 | + description: | | |
| 53 | + DP83822 PHY only. | |
| 54 | + Setting this property to a non-zero number sets the RX internal delay | |
| 55 | + for the PHY. The internal delay for the PHY is fixed to 3.5ns relative | |
| 56 | + to receive data. | |
| 57 | + | |
| 58 | + tx-internal-delay-ps: | |
| 59 | + description: | | |
| 60 | + DP83822 PHY only. | |
| 61 | + Setting this property to a non-zero number sets the TX internal delay | |
| 62 | + for the PHY. The internal delay for the PHY is fixed to 3.5ns relative | |
| 63 | + to transmit data. | |
| 64 | + | |
| 65 | +required: | |
| 66 | + - reg | |
| 67 | + | |
| 68 | +examples: | |
| 69 | + - | | |
| 70 | + mdio0 { | |
| 71 | + #address-cells = <1>; | |
| 72 | + #size-cells = <0>; | |
| 73 | + ethphy0: ethernet-phy@0 { | |
| 74 | + reg = <0>; | |
| 75 | + rx-internal-delay-ps = <1>; | |
| 76 | + tx-internal-delay-ps = <1>; | |
| 77 | + }; | |
| 78 | + }; | |
| 79 | + | |
| 80 | +... | |
| @@ -65,7 +65,8 @@ Optional properties: · 64 unmodified lines | ||
| 65 | 65 | the length can vary between hw versions. |
| 66 | 66 | - <supply-name>-supply: handle to the regulator device tree node |
| 67 | 67 | optional "supply-name" are "vdd-0.8-cx-mx", |
| 68 | − "vdd-1.8-xo", "vdd-1.3-rfa" and "vdd-3.3-ch0". | |
| 68 | + "vdd-1.8-xo", "vdd-1.3-rfa", "vdd-3.3-ch0", | |
| 69 | + and "vdd-3.3-ch1". | |
| 69 | 70 | - memory-region: |
| 70 | 71 | Usage: optional |
| 71 | 72 | Value type: <phandle> |
| @@ -204,6 +205,7 @@ wifi@18000000 { · 132 unmodified lines | ||
| 204 | 205 | vdd-1.8-xo-supply = <&vreg_l7a_1p8>; |
| 205 | 206 | vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; |
| 206 | 207 | vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; |
| 208 | + vdd-3.3-ch1-supply = <&vreg_l26a_3p3>; | |
| 207 | 209 | memory-region = <&wifi_msa_mem>; |
| 208 | 210 | iommus = <&apps_smmu 0x0040 0x1>; |
| 209 | 211 | qcom,msa-fixed-perm; |
| @@ -17,7 +17,9 @@ description: | · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | properties: |
| 19 | 19 | compatible: |
| 20 | − const: qcom,ipq8074-wifi | |
| 20 | + enum: | |
| 21 | + - qcom,ipq8074-wifi | |
| 22 | + - qcom,ipq6018-wifi | |
| 21 | 23 | |
| 22 | 24 | reg: |
| 23 | 25 | maxItems: 1 |
| @@ -18,6 +18,8 @@ Clock Properties: · 17 unmodified lines | ||
| 18 | 18 | - fsl,tmr-add Frequency compensation value. |
| 19 | 19 | - fsl,tmr-fiper1 Fixed interval period pulse generator. |
| 20 | 20 | - fsl,tmr-fiper2 Fixed interval period pulse generator. |
| 21 | + - fsl,tmr-fiper3 Fixed interval period pulse generator. | |
| 22 | + Supported only on DPAA2 and ENETC hardware. | |
| 21 | 23 | - fsl,max-adj Maximum frequency adjustment in parts per billion. |
| 22 | 24 | - fsl,extts-fifo The presence of this property indicates hardware |
| 23 | 25 | support for the external trigger stamp FIFO. |
| @@ -12,79 +12,32 @@ Device registration · 11 unmodified lines | ||
| 12 | 12 | :doc: Device registration |
| 13 | 13 | |
| 14 | 14 | .. kernel-doc:: include/net/cfg80211.h |
| 15 | − :functions: ieee80211_channel_flags | |
| 16 | − | |
| 17 | −.. kernel-doc:: include/net/cfg80211.h | |
| 18 | − :functions: ieee80211_channel | |
| 19 | − | |
| 20 | −.. kernel-doc:: include/net/cfg80211.h | |
| 21 | − :functions: ieee80211_rate_flags | |
| 22 | − | |
| 23 | −.. kernel-doc:: include/net/cfg80211.h | |
| 24 | − :functions: ieee80211_rate | |
| 25 | − | |
| 26 | −.. kernel-doc:: include/net/cfg80211.h | |
| 27 | − :functions: ieee80211_sta_ht_cap | |
| 28 | − | |
| 29 | −.. kernel-doc:: include/net/cfg80211.h | |
| 30 | − :functions: ieee80211_supported_band | |
| 31 | − | |
| 32 | −.. kernel-doc:: include/net/cfg80211.h | |
| 33 | − :functions: cfg80211_signal_type | |
| 34 | − | |
| 35 | −.. kernel-doc:: include/net/cfg80211.h | |
| 36 | − :functions: wiphy_params_flags | |
| 37 | − | |
| 38 | −.. kernel-doc:: include/net/cfg80211.h | |
| 39 | − :functions: wiphy_flags | |
| 40 | − | |
| 41 | −.. kernel-doc:: include/net/cfg80211.h | |
| 42 | − :functions: wiphy | |
| 43 | − | |
| 44 | −.. kernel-doc:: include/net/cfg80211.h | |
| 45 | − :functions: wireless_dev | |
| 46 | − | |
| 47 | −.. kernel-doc:: include/net/cfg80211.h | |
| 48 | − :functions: wiphy_new | |
| 49 | − | |
| 50 | −.. kernel-doc:: include/net/cfg80211.h | |
| 51 | − :functions: wiphy_read_of_freq_limits | |
| 52 | − | |
| 53 | −.. kernel-doc:: include/net/cfg80211.h | |
| 54 | − :functions: wiphy_register | |
| 55 | − | |
| 56 | −.. kernel-doc:: include/net/cfg80211.h | |
| 57 | − :functions: wiphy_unregister | |
| 58 | − | |
| 59 | −.. kernel-doc:: include/net/cfg80211.h | |
| 60 | − :functions: wiphy_free | |
| 61 | − | |
| 62 | −.. kernel-doc:: include/net/cfg80211.h | |
| 63 | − :functions: wiphy_name | |
| 64 | − | |
| 65 | −.. kernel-doc:: include/net/cfg80211.h | |
| 66 | − :functions: wiphy_dev | |
| 67 | − | |
| 68 | −.. kernel-doc:: include/net/cfg80211.h | |
| 69 | − :functions: wiphy_priv | |
| 70 | − | |
| 71 | −.. kernel-doc:: include/net/cfg80211.h | |
| 72 | − :functions: priv_to_wiphy | |
| 73 | − | |
| 74 | −.. kernel-doc:: include/net/cfg80211.h | |
| 75 | − :functions: set_wiphy_dev | |
| 76 | − | |
| 77 | −.. kernel-doc:: include/net/cfg80211.h | |
| 78 | − :functions: wdev_priv | |
| 79 | − | |
| 80 | −.. kernel-doc:: include/net/cfg80211.h | |
| 81 | − :functions: ieee80211_iface_limit | |
| 82 | − | |
| 83 | −.. kernel-doc:: include/net/cfg80211.h | |
| 84 | − :functions: ieee80211_iface_combination | |
| 85 | − | |
| 86 | −.. kernel-doc:: include/net/cfg80211.h | |
| 87 | − :functions: cfg80211_check_combinations | |
| 15 | + :functions: | |
| 16 | + ieee80211_channel_flags | |
| 17 | + ieee80211_channel | |
| 18 | + ieee80211_rate_flags | |
| 19 | + ieee80211_rate | |
| 20 | + ieee80211_sta_ht_cap | |
| 21 | + ieee80211_supported_band | |
| 22 | + cfg80211_signal_type | |
| 23 | + wiphy_params_flags | |
| 24 | + wiphy_flags | |
| 25 | + wiphy | |
| 26 | + wireless_dev | |
| 27 | + wiphy_new | |
| 28 | + wiphy_read_of_freq_limits | |
| 29 | + wiphy_register | |
| 30 | + wiphy_unregister | |
| 31 | + wiphy_free | |
| 32 | + wiphy_name | |
| 33 | + wiphy_dev | |
| 34 | + wiphy_priv | |
| 35 | + priv_to_wiphy | |
| 36 | + set_wiphy_dev | |
| 37 | + wdev_priv | |
| 38 | + ieee80211_iface_limit | |
| 39 | + ieee80211_iface_combination | |
| 40 | + cfg80211_check_combinations | |
| 88 | 41 | |
| 89 | 42 | Actions and configuration |
| 90 | 43 | ========================= |
| @@ -93,139 +46,52 @@ Actions and configuration · 2 unmodified lines | ||
| 93 | 46 | :doc: Actions and configuration |
| 94 | 47 | |
| 95 | 48 | .. kernel-doc:: include/net/cfg80211.h |
| 96 | − :functions: cfg80211_ops | |
| 97 | − | |
| 98 | −.. kernel-doc:: include/net/cfg80211.h | |
| 99 | − :functions: vif_params | |
| 100 | − | |
| 101 | −.. kernel-doc:: include/net/cfg80211.h | |
| 102 | − :functions: key_params | |
| 103 | − | |
| 104 | −.. kernel-doc:: include/net/cfg80211.h | |
| 105 | − :functions: survey_info_flags | |
| 106 | − | |
| 107 | −.. kernel-doc:: include/net/cfg80211.h | |
| 108 | − :functions: survey_info | |
| 109 | − | |
| 110 | −.. kernel-doc:: include/net/cfg80211.h | |
| 111 | − :functions: cfg80211_beacon_data | |
| 112 | − | |
| 113 | −.. kernel-doc:: include/net/cfg80211.h | |
| 114 | − :functions: cfg80211_ap_settings | |
| 115 | − | |
| 116 | −.. kernel-doc:: include/net/cfg80211.h | |
| 117 | − :functions: station_parameters | |
| 118 | − | |
| 119 | −.. kernel-doc:: include/net/cfg80211.h | |
| 120 | − :functions: rate_info_flags | |
| 121 | − | |
| 122 | −.. kernel-doc:: include/net/cfg80211.h | |
| 123 | − :functions: rate_info | |
| 124 | − | |
| 125 | −.. kernel-doc:: include/net/cfg80211.h | |
| 126 | − :functions: station_info | |
| 127 | − | |
| 128 | −.. kernel-doc:: include/net/cfg80211.h | |
| 129 | − :functions: monitor_flags | |
| 130 | − | |
| 131 | −.. kernel-doc:: include/net/cfg80211.h | |
| 132 | − :functions: mpath_info_flags | |
| 133 | − | |
| 134 | −.. kernel-doc:: include/net/cfg80211.h | |
| 135 | − :functions: mpath_info | |
| 136 | − | |
| 137 | −.. kernel-doc:: include/net/cfg80211.h | |
| 138 | − :functions: bss_parameters | |
| 139 | − | |
| 140 | −.. kernel-doc:: include/net/cfg80211.h | |
| 141 | − :functions: ieee80211_txq_params | |
| 142 | − | |
| 143 | −.. kernel-doc:: include/net/cfg80211.h | |
| 144 | − :functions: cfg80211_crypto_settings | |
| 145 | − | |
| 146 | −.. kernel-doc:: include/net/cfg80211.h | |
| 147 | − :functions: cfg80211_auth_request | |
| 148 | − | |
| 149 | −.. kernel-doc:: include/net/cfg80211.h | |
| 150 | − :functions: cfg80211_assoc_request | |
| 151 | − | |
| 152 | −.. kernel-doc:: include/net/cfg80211.h | |
| 153 | − :functions: cfg80211_deauth_request | |
| 154 | − | |
| 155 | −.. kernel-doc:: include/net/cfg80211.h | |
| 156 | − :functions: cfg80211_disassoc_request | |
| 157 | − | |
| 158 | −.. kernel-doc:: include/net/cfg80211.h | |
| 159 | − :functions: cfg80211_ibss_params | |
| 160 | − | |
| 161 | −.. kernel-doc:: include/net/cfg80211.h | |
| 162 | − :functions: cfg80211_connect_params | |
| 163 | − | |
| 164 | −.. kernel-doc:: include/net/cfg80211.h | |
| 165 | − :functions: cfg80211_pmksa | |
| 166 | − | |
| 167 | −.. kernel-doc:: include/net/cfg80211.h | |
| 168 | − :functions: cfg80211_rx_mlme_mgmt | |
| 169 | − | |
| 170 | −.. kernel-doc:: include/net/cfg80211.h | |
| 171 | − :functions: cfg80211_auth_timeout | |
| 172 | − | |
| 173 | −.. kernel-doc:: include/net/cfg80211.h | |
| 174 | − :functions: cfg80211_rx_assoc_resp | |
| 175 | − | |
| 176 | −.. kernel-doc:: include/net/cfg80211.h | |
| 177 | − :functions: cfg80211_assoc_timeout | |
| 178 | − | |
| 179 | −.. kernel-doc:: include/net/cfg80211.h | |
| 180 | − :functions: cfg80211_tx_mlme_mgmt | |
| 181 | − | |
| 182 | −.. kernel-doc:: include/net/cfg80211.h | |
| 183 | − :functions: cfg80211_ibss_joined | |
| 184 | − | |
| 185 | −.. kernel-doc:: include/net/cfg80211.h | |
| 186 | − :functions: cfg80211_connect_resp_params | |
| 187 | − | |
| 188 | −.. kernel-doc:: include/net/cfg80211.h | |
| 189 | − :functions: cfg80211_connect_done | |
| 190 | − | |
| 191 | −.. kernel-doc:: include/net/cfg80211.h | |
| 192 | − :functions: cfg80211_connect_result | |
| 193 | − | |
| 194 | −.. kernel-doc:: include/net/cfg80211.h | |
| 195 | − :functions: cfg80211_connect_bss | |
| 196 | − | |
| 197 | −.. kernel-doc:: include/net/cfg80211.h | |
| 198 | − :functions: cfg80211_connect_timeout | |
| 199 | − | |
| 200 | −.. kernel-doc:: include/net/cfg80211.h | |
| 201 | − :functions: cfg80211_roamed | |
| 202 | − | |
| 203 | −.. kernel-doc:: include/net/cfg80211.h | |
| 204 | − :functions: cfg80211_disconnected | |
| 205 | − | |
| 206 | −.. kernel-doc:: include/net/cfg80211.h | |
| 207 | − :functions: cfg80211_ready_on_channel | |
| 208 | − | |
| 209 | −.. kernel-doc:: include/net/cfg80211.h | |
| 210 | − :functions: cfg80211_remain_on_channel_expired | |
| 211 | − | |
| 212 | −.. kernel-doc:: include/net/cfg80211.h | |
| 213 | − :functions: cfg80211_new_sta | |
| 214 | − | |
| 215 | −.. kernel-doc:: include/net/cfg80211.h | |
| 216 | − :functions: cfg80211_rx_mgmt | |
| 217 | − | |
| 218 | −.. kernel-doc:: include/net/cfg80211.h | |
| 219 | − :functions: cfg80211_mgmt_tx_status | |
| 220 | − | |
| 221 | −.. kernel-doc:: include/net/cfg80211.h | |
| 222 | − :functions: cfg80211_cqm_rssi_notify | |
| 223 | − | |
| 224 | −.. kernel-doc:: include/net/cfg80211.h | |
| 225 | − :functions: cfg80211_cqm_pktloss_notify | |
| 226 | − | |
| 227 | −.. kernel-doc:: include/net/cfg80211.h | |
| 228 | − :functions: cfg80211_michael_mic_failure | |
| 49 | + :functions: | |
| 50 | + cfg80211_ops | |
| 51 | + vif_params | |
| 52 | + key_params | |
| 53 | + survey_info_flags | |
| 54 | + survey_info | |
| 55 | + cfg80211_beacon_data | |
| 56 | + cfg80211_ap_settings | |
| 57 | + station_parameters | |
| 58 | + rate_info_flags | |
| 59 | + rate_info | |
| 60 | + station_info | |
| 61 | + monitor_flags | |
| 62 | + mpath_info_flags | |
| 63 | + mpath_info | |
| 64 | + bss_parameters | |
| 65 | + ieee80211_txq_params | |
| 66 | + cfg80211_crypto_settings | |
| 67 | + cfg80211_auth_request | |
| 68 | + cfg80211_assoc_request | |
| 69 | + cfg80211_deauth_request | |
| 70 | + cfg80211_disassoc_request | |
| 71 | + cfg80211_ibss_params | |
| 72 | + cfg80211_connect_params | |
| 73 | + cfg80211_pmksa | |
| 74 | + cfg80211_rx_mlme_mgmt | |
| 75 | + cfg80211_auth_timeout | |
| 76 | + cfg80211_rx_assoc_resp | |
| 77 | + cfg80211_assoc_timeout | |
| 78 | + cfg80211_tx_mlme_mgmt | |
| 79 | + cfg80211_ibss_joined | |
| 80 | + cfg80211_connect_resp_params | |
| 81 | + cfg80211_connect_done | |
| 82 | + cfg80211_connect_result | |
| 83 | + cfg80211_connect_bss | |
| 84 | + cfg80211_connect_timeout | |
| 85 | + cfg80211_roamed | |
| 86 | + cfg80211_disconnected | |
| 87 | + cfg80211_ready_on_channel | |
| 88 | + cfg80211_remain_on_channel_expired | |
| 89 | + cfg80211_new_sta | |
| 90 | + cfg80211_rx_mgmt | |
| 91 | + cfg80211_mgmt_tx_status | |
| 92 | + cfg80211_cqm_rssi_notify | |
| 93 | + cfg80211_cqm_pktloss_notify | |
| 94 | + cfg80211_michael_mic_failure | |
| 229 | 95 | |
| 230 | 96 | Scanning and BSS list handling |
| 231 | 97 | ============================== |
| @@ -234,34 +100,17 @@ Scanning and BSS list handling · 2 unmodified lines | ||
| 234 | 100 | :doc: Scanning and BSS list handling |
| 235 | 101 | |
| 236 | 102 | .. kernel-doc:: include/net/cfg80211.h |
| 237 | − :functions: cfg80211_ssid | |
| 238 | − | |
| 239 | −.. kernel-doc:: include/net/cfg80211.h | |
| 240 | − :functions: cfg80211_scan_request | |
| 241 | − | |
| 242 | −.. kernel-doc:: include/net/cfg80211.h | |
| 243 | − :functions: cfg80211_scan_done | |
| 244 | − | |
| 245 | −.. kernel-doc:: include/net/cfg80211.h | |
| 246 | − :functions: cfg80211_bss | |
| 247 | − | |
| 248 | −.. kernel-doc:: include/net/cfg80211.h | |
| 249 | − :functions: cfg80211_inform_bss | |
| 250 | − | |
| 251 | −.. kernel-doc:: include/net/cfg80211.h | |
| 252 | − :functions: cfg80211_inform_bss_frame_data | |
| 253 | − | |
| 254 | −.. kernel-doc:: include/net/cfg80211.h | |
| 255 | − :functions: cfg80211_inform_bss_data | |
| 256 | − | |
| 257 | −.. kernel-doc:: include/net/cfg80211.h | |
| 258 | − :functions: cfg80211_unlink_bss | |
| 259 | − | |
| 260 | −.. kernel-doc:: include/net/cfg80211.h | |
| 261 | − :functions: cfg80211_find_ie | |
| 262 | − | |
| 263 | −.. kernel-doc:: include/net/cfg80211.h | |
| 264 | − :functions: ieee80211_bss_get_ie | |
| 103 | + :functions: | |
| 104 | + cfg80211_ssid | |
| 105 | + cfg80211_scan_request | |
| 106 | + cfg80211_scan_done | |
| 107 | + cfg80211_bss | |
| 108 | + cfg80211_inform_bss | |
| 109 | + cfg80211_inform_bss_frame_data | |
| 110 | + cfg80211_inform_bss_data | |
| 111 | + cfg80211_unlink_bss | |
| 112 | + cfg80211_find_ie | |
| 113 | + ieee80211_bss_get_ie | |
| 265 | 114 | |
| 266 | 115 | Utility functions |
| 267 | 116 | ================= |
| @@ -270,25 +119,14 @@ Utility functions · 2 unmodified lines | ||
| 270 | 119 | :doc: Utility functions |
| 271 | 120 | |
| 272 | 121 | .. kernel-doc:: include/net/cfg80211.h |
| 273 | − :functions: ieee80211_channel_to_frequency | |
| 274 | − | |
| 275 | −.. kernel-doc:: include/net/cfg80211.h | |
| 276 | − :functions: ieee80211_frequency_to_channel | |
| 277 | − | |
| 278 | −.. kernel-doc:: include/net/cfg80211.h | |
| 279 | − :functions: ieee80211_get_channel | |
| 280 | − | |
| 281 | −.. kernel-doc:: include/net/cfg80211.h | |
| 282 | − :functions: ieee80211_get_response_rate | |
| 283 | − | |
| 284 | −.. kernel-doc:: include/net/cfg80211.h | |
| 285 | − :functions: ieee80211_hdrlen | |
| 286 | − | |
| 287 | −.. kernel-doc:: include/net/cfg80211.h | |
| 288 | − :functions: ieee80211_get_hdrlen_from_skb | |
| 289 | − | |
| 290 | −.. kernel-doc:: include/net/cfg80211.h | |
| 291 | − :functions: ieee80211_radiotap_iterator | |
| 122 | + :functions: | |
| 123 | + ieee80211_channel_to_frequency | |
| 124 | + ieee80211_frequency_to_channel | |
| 125 | + ieee80211_get_channel | |
| 126 | + ieee80211_get_response_rate | |
| 127 | + ieee80211_hdrlen | |
| 128 | + ieee80211_get_hdrlen_from_skb | |
| 129 | + ieee80211_radiotap_iterator | |
| 292 | 130 | |
| 293 | 131 | Data path helpers |
| 294 | 132 | ================= |
| @@ -297,13 +135,10 @@ Data path helpers · 2 unmodified lines | ||
| 297 | 135 | :doc: Data path helpers |
| 298 | 136 | |
| 299 | 137 | .. kernel-doc:: include/net/cfg80211.h |
| 300 | − :functions: ieee80211_data_to_8023 | |
| 301 | − | |
| 302 | −.. kernel-doc:: include/net/cfg80211.h | |
| 303 | − :functions: ieee80211_amsdu_to_8023s | |
| 304 | − | |
| 305 | −.. kernel-doc:: include/net/cfg80211.h | |
| 306 | − :functions: cfg80211_classify8021d | |
| 138 | + :functions: | |
| 139 | + ieee80211_data_to_8023 | |
| 140 | + ieee80211_amsdu_to_8023s | |
| 141 | + cfg80211_classify8021d | |
| 307 | 142 | |
| 308 | 143 | Regulatory enforcement infrastructure |
| 309 | 144 | ===================================== |
| @@ -312,13 +147,10 @@ Regulatory enforcement infrastructure · 2 unmodified lines | ||
| 312 | 147 | :doc: Regulatory enforcement infrastructure |
| 313 | 148 | |
| 314 | 149 | .. kernel-doc:: include/net/cfg80211.h |
| 315 | − :functions: regulatory_hint | |
| 316 | − | |
| 317 | −.. kernel-doc:: include/net/cfg80211.h | |
| 318 | − :functions: wiphy_apply_custom_regulatory | |
| 319 | − | |
| 320 | −.. kernel-doc:: include/net/cfg80211.h | |
| 321 | − :functions: freq_reg_info | |
| 150 | + :functions: | |
| 151 | + regulatory_hint | |
| 152 | + wiphy_apply_custom_regulatory | |
| 153 | + freq_reg_info | |
| 322 | 154 | |
| 323 | 155 | RFkill integration |
| 324 | 156 | ================== |
| @@ -327,13 +159,10 @@ RFkill integration · 2 unmodified lines | ||
| 327 | 159 | :doc: RFkill integration |
| 328 | 160 | |
| 329 | 161 | .. kernel-doc:: include/net/cfg80211.h |
| 330 | − :functions: wiphy_rfkill_set_hw_state | |
| 331 | − | |
| 332 | −.. kernel-doc:: include/net/cfg80211.h | |
| 333 | − :functions: wiphy_rfkill_start_polling | |
| 334 | − | |
| 335 | −.. kernel-doc:: include/net/cfg80211.h | |
| 336 | − :functions: wiphy_rfkill_stop_polling | |
| 162 | + :functions: | |
| 163 | + wiphy_rfkill_set_hw_state | |
| 164 | + wiphy_rfkill_start_polling | |
| 165 | + wiphy_rfkill_stop_polling | |
| 337 | 166 | |
| 338 | 167 | Test mode |
| 339 | 168 | ========= |
| @@ -342,13 +171,8 @@ Test mode · 2 unmodified lines | ||
| 342 | 171 | :doc: Test mode |
| 343 | 172 | |
| 344 | 173 | .. kernel-doc:: include/net/cfg80211.h |
| 345 | − :functions: cfg80211_testmode_alloc_reply_skb | |
| 346 | − | |
| 347 | −.. kernel-doc:: include/net/cfg80211.h | |
| 348 | − :functions: cfg80211_testmode_reply | |
| 349 | − | |
| 350 | −.. kernel-doc:: include/net/cfg80211.h | |
| 351 | − :functions: cfg80211_testmode_alloc_event_skb | |
| 352 | − | |
| 353 | −.. kernel-doc:: include/net/cfg80211.h | |
| 354 | − :functions: cfg80211_testmode_event | |
| 174 | + :functions: | |
| 175 | + cfg80211_testmode_alloc_reply_skb | |
| 176 | + cfg80211_testmode_reply | |
| 177 | + cfg80211_testmode_alloc_event_skb | |
| 178 | + cfg80211_testmode_event | |
| @@ -15,25 +15,14 @@ appropriate trigger, which will then be triggered appropriately by · 14 unmodified lines | ||
| 15 | 15 | mac80211. |
| 16 | 16 | |
| 17 | 17 | .. kernel-doc:: include/net/mac80211.h |
| 18 | − :functions: ieee80211_get_tx_led_name | |
| 19 | − | |
| 20 | −.. kernel-doc:: include/net/mac80211.h | |
| 21 | − :functions: ieee80211_get_rx_led_name | |
| 22 | − | |
| 23 | −.. kernel-doc:: include/net/mac80211.h | |
| 24 | − :functions: ieee80211_get_assoc_led_name | |
| 25 | − | |
| 26 | −.. kernel-doc:: include/net/mac80211.h | |
| 27 | − :functions: ieee80211_get_radio_led_name | |
| 28 | − | |
| 29 | −.. kernel-doc:: include/net/mac80211.h | |
| 30 | − :functions: ieee80211_tpt_blink | |
| 31 | − | |
| 32 | −.. kernel-doc:: include/net/mac80211.h | |
| 33 | − :functions: ieee80211_tpt_led_trigger_flags | |
| 34 | − | |
| 35 | −.. kernel-doc:: include/net/mac80211.h | |
| 36 | − :functions: ieee80211_create_tpt_led_trigger | |
| 18 | + :functions: | |
| 19 | + ieee80211_get_tx_led_name | |
| 20 | + ieee80211_get_rx_led_name | |
| 21 | + ieee80211_get_assoc_led_name | |
| 22 | + ieee80211_get_radio_led_name | |
| 23 | + ieee80211_tpt_blink | |
| 24 | + ieee80211_tpt_led_trigger_flags | |
| 25 | + ieee80211_create_tpt_led_trigger | |
| 37 | 26 | |
| 38 | 27 | Hardware crypto acceleration |
| 39 | 28 | ============================ |
| @@ -42,22 +31,13 @@ Hardware crypto acceleration · 2 unmodified lines | ||
| 42 | 31 | :doc: Hardware crypto acceleration |
| 43 | 32 | |
| 44 | 33 | .. kernel-doc:: include/net/mac80211.h |
| 45 | − :functions: set_key_cmd | |
| 46 | − | |
| 47 | −.. kernel-doc:: include/net/mac80211.h | |
| 48 | − :functions: ieee80211_key_conf | |
| 49 | − | |
| 50 | −.. kernel-doc:: include/net/mac80211.h | |
| 51 | − :functions: ieee80211_key_flags | |
| 52 | − | |
| 53 | −.. kernel-doc:: include/net/mac80211.h | |
| 54 | − :functions: ieee80211_get_tkip_p1k | |
| 55 | − | |
| 56 | −.. kernel-doc:: include/net/mac80211.h | |
| 57 | − :functions: ieee80211_get_tkip_p1k_iv | |
| 58 | − | |
| 59 | −.. kernel-doc:: include/net/mac80211.h | |
| 60 | − :functions: ieee80211_get_tkip_p2k | |
| 34 | + :functions: | |
| 35 | + set_key_cmd | |
| 36 | + ieee80211_key_conf | |
| 37 | + ieee80211_key_flags | |
| 38 | + ieee80211_get_tkip_p1k | |
| 39 | + ieee80211_get_tkip_p1k_iv | |
| 40 | + ieee80211_get_tkip_p2k | |
| 61 | 41 | |
| 62 | 42 | Powersave support |
| 63 | 43 | ================= |
| @@ -99,28 +79,15 @@ support for powersaving clients · 35 unmodified lines | ||
| 99 | 79 | :doc: AP support for powersaving clients |
| 100 | 80 | |
| 101 | 81 | .. kernel-doc:: include/net/mac80211.h |
| 102 | − :functions: ieee80211_get_buffered_bc | |
| 103 | − | |
| 104 | −.. kernel-doc:: include/net/mac80211.h | |
| 105 | − :functions: ieee80211_beacon_get | |
| 106 | − | |
| 107 | −.. kernel-doc:: include/net/mac80211.h | |
| 108 | − :functions: ieee80211_sta_eosp | |
| 109 | − | |
| 110 | −.. kernel-doc:: include/net/mac80211.h | |
| 111 | − :functions: ieee80211_frame_release_type | |
| 112 | − | |
| 113 | −.. kernel-doc:: include/net/mac80211.h | |
| 114 | − :functions: ieee80211_sta_ps_transition | |
| 115 | − | |
| 116 | −.. kernel-doc:: include/net/mac80211.h | |
| 117 | − :functions: ieee80211_sta_ps_transition_ni | |
| 118 | − | |
| 119 | −.. kernel-doc:: include/net/mac80211.h | |
| 120 | − :functions: ieee80211_sta_set_buffered | |
| 121 | − | |
| 122 | −.. kernel-doc:: include/net/mac80211.h | |
| 123 | − :functions: ieee80211_sta_block_awake | |
| 82 | + :functions: | |
| 83 | + ieee80211_get_buffered_bc | |
| 84 | + ieee80211_beacon_get | |
| 85 | + ieee80211_sta_eosp | |
| 86 | + ieee80211_frame_release_type | |
| 87 | + ieee80211_sta_ps_transition | |
| 88 | + ieee80211_sta_ps_transition_ni | |
| 89 | + ieee80211_sta_set_buffered | |
| 90 | + ieee80211_sta_block_awake | |
| 124 | 91 | |
| 125 | 92 | Supporting multiple virtual interfaces |
| 126 | 93 | ====================================== |
| @@ -134,10 +101,9 @@ addresses here, note which configurations are supported by mac80211, add · 7 unmodified lines | ||
| 134 | 101 | notes about supporting hw crypto with it. |
| 135 | 102 | |
| 136 | 103 | .. kernel-doc:: include/net/mac80211.h |
| 137 | − :functions: ieee80211_iterate_active_interfaces | |
| 138 | − | |
| 139 | −.. kernel-doc:: include/net/mac80211.h | |
| 140 | − :functions: ieee80211_iterate_active_interfaces_atomic | |
| 104 | + :functions: | |
| 105 | + ieee80211_iterate_active_interfaces | |
| 106 | + ieee80211_iterate_active_interfaces_atomic | |
| 141 | 107 | |
| 142 | 108 | Station handling |
| 143 | 109 | ================ |
| @@ -145,16 +111,11 @@ Station handling · 1 unmodified line | ||
| 145 | 111 | TODO |
| 146 | 112 | |
| 147 | 113 | .. kernel-doc:: include/net/mac80211.h |
| 148 | − :functions: ieee80211_sta | |
| 149 | − | |
| 150 | −.. kernel-doc:: include/net/mac80211.h | |
| 151 | − :functions: sta_notify_cmd | |
| 152 | − | |
| 153 | −.. kernel-doc:: include/net/mac80211.h | |
| 154 | − :functions: ieee80211_find_sta | |
| 155 | − | |
| 156 | −.. kernel-doc:: include/net/mac80211.h | |
| 157 | − :functions: ieee80211_find_sta_by_ifaddr | |
| 114 | + :functions: | |
| 115 | + ieee80211_sta | |
| 116 | + sta_notify_cmd | |
| 117 | + ieee80211_find_sta | |
| 118 | + ieee80211_find_sta_by_ifaddr | |
| 158 | 119 | |
| 159 | 120 | Hardware scan offload |
| 160 | 121 | ===================== |
| @@ -193,10 +154,9 @@ Spatial Multiplexing Powersave (SMPS) · 32 unmodified lines | ||
| 193 | 154 | :doc: Spatial multiplexing power save |
| 194 | 155 | |
| 195 | 156 | .. kernel-doc:: include/net/mac80211.h |
| 196 | − :functions: ieee80211_request_smps | |
| 197 | − | |
| 198 | −.. kernel-doc:: include/net/mac80211.h | |
| 199 | − :functions: ieee80211_smps_mode | |
| 157 | + :functions: | |
| 158 | + ieee80211_request_smps | |
| 159 | + ieee80211_smps_mode | |
| 200 | 160 | |
| 201 | 161 | TBD |
| 202 | 162 | |
| @@ -209,22 +169,13 @@ Rate Control API · 6 unmodified lines | ||
| 209 | 169 | TBD |
| 210 | 170 | |
| 211 | 171 | .. kernel-doc:: include/net/mac80211.h |
| 212 | − :functions: ieee80211_start_tx_ba_session | |
| 213 | − | |
| 214 | −.. kernel-doc:: include/net/mac80211.h | |
| 215 | − :functions: ieee80211_start_tx_ba_cb_irqsafe | |
| 216 | − | |
| 217 | −.. kernel-doc:: include/net/mac80211.h | |
| 218 | − :functions: ieee80211_stop_tx_ba_session | |
| 219 | − | |
| 220 | −.. kernel-doc:: include/net/mac80211.h | |
| 221 | − :functions: ieee80211_stop_tx_ba_cb_irqsafe | |
| 222 | − | |
| 223 | −.. kernel-doc:: include/net/mac80211.h | |
| 224 | − :functions: ieee80211_rate_control_changed | |
| 225 | − | |
| 226 | −.. kernel-doc:: include/net/mac80211.h | |
| 227 | − :functions: ieee80211_tx_rate_control | |
| 172 | + :functions: | |
| 173 | + ieee80211_start_tx_ba_session | |
| 174 | + ieee80211_start_tx_ba_cb_irqsafe | |
| 175 | + ieee80211_stop_tx_ba_session | |
| 176 | + ieee80211_stop_tx_ba_cb_irqsafe | |
| 177 | + ieee80211_rate_control_changed | |
| 178 | + ieee80211_tx_rate_control | |
| 228 | 179 | |
| 229 | 180 | TBD |
| 230 | 181 | |
| @@ -261,10 +212,9 @@ Programming information · 30 unmodified lines | ||
| 261 | 212 | ----------------------- |
| 262 | 213 | |
| 263 | 214 | .. kernel-doc:: net/mac80211/sta_info.h |
| 264 | − :functions: sta_info | |
| 265 | − | |
| 266 | −.. kernel-doc:: net/mac80211/sta_info.h | |
| 267 | − :functions: ieee80211_sta_info_flags | |
| 215 | + :functions: | |
| 216 | + sta_info | |
| 217 | + ieee80211_sta_info_flags | |
| 268 | 218 | |
| 269 | 219 | STA information lifetime rules |
| 270 | 220 | ------------------------------ |
| @@ -276,13 +226,10 @@ Aggregation Functions · 5 unmodified lines | ||
| 276 | 226 | ===================== |
| 277 | 227 | |
| 278 | 228 | .. kernel-doc:: net/mac80211/sta_info.h |
| 279 | − :functions: sta_ampdu_mlme | |
| 280 | − | |
| 281 | −.. kernel-doc:: net/mac80211/sta_info.h | |
| 282 | − :functions: tid_ampdu_tx | |
| 283 | − | |
| 284 | −.. kernel-doc:: net/mac80211/sta_info.h | |
| 285 | − :functions: tid_ampdu_rx | |
| 229 | + :functions: | |
| 230 | + sta_ampdu_mlme | |
| 231 | + tid_ampdu_tx | |
| 232 | + tid_ampdu_rx | |
| 286 | 233 | |
| 287 | 234 | Synchronisation Functions |
| 288 | 235 | ========================= |
| @@ -30,31 +30,16 @@ Finally, a discussion of hardware capabilities should be done with · 29 unmodified lines | ||
| 30 | 30 | references to other parts of the book. |
| 31 | 31 | |
| 32 | 32 | .. kernel-doc:: include/net/mac80211.h |
| 33 | − :functions: ieee80211_hw | |
| 34 | − | |
| 35 | −.. kernel-doc:: include/net/mac80211.h | |
| 36 | − :functions: ieee80211_hw_flags | |
| 37 | − | |
| 38 | −.. kernel-doc:: include/net/mac80211.h | |
| 39 | − :functions: SET_IEEE80211_DEV | |
| 40 | − | |
| 41 | −.. kernel-doc:: include/net/mac80211.h | |
| 42 | − :functions: SET_IEEE80211_PERM_ADDR | |
| 43 | − | |
| 44 | −.. kernel-doc:: include/net/mac80211.h | |
| 45 | − :functions: ieee80211_ops | |
| 46 | − | |
| 47 | −.. kernel-doc:: include/net/mac80211.h | |
| 48 | − :functions: ieee80211_alloc_hw | |
| 49 | − | |
| 50 | −.. kernel-doc:: include/net/mac80211.h | |
| 51 | − :functions: ieee80211_register_hw | |
| 52 | − | |
| 53 | −.. kernel-doc:: include/net/mac80211.h | |
| 54 | − :functions: ieee80211_unregister_hw | |
| 55 | − | |
| 56 | −.. kernel-doc:: include/net/mac80211.h | |
| 57 | − :functions: ieee80211_free_hw | |
| 33 | + :functions: | |
| 34 | + ieee80211_hw | |
| 35 | + ieee80211_hw_flags | |
| 36 | + SET_IEEE80211_DEV | |
| 37 | + SET_IEEE80211_PERM_ADDR | |
| 38 | + ieee80211_ops | |
| 39 | + ieee80211_alloc_hw | |
| 40 | + ieee80211_register_hw | |
| 41 | + ieee80211_unregister_hw | |
| 42 | + ieee80211_free_hw | |
| 58 | 43 | |
| 59 | 44 | PHY configuration |
| 60 | 45 | ================= |
| @@ -65,10 +50,9 @@ This chapter should describe PHY handling including start/stop callbacks · 4 unmodified lines | ||
| 65 | 50 | and the various structures used. |
| 66 | 51 | |
| 67 | 52 | .. kernel-doc:: include/net/mac80211.h |
| 68 | − :functions: ieee80211_conf | |
| 69 | − | |
| 70 | −.. kernel-doc:: include/net/mac80211.h | |
| 71 | − :functions: ieee80211_conf_flags | |
| 53 | + :functions: | |
| 54 | + ieee80211_conf | |
| 55 | + ieee80211_conf_flags | |
| 72 | 56 | |
| 73 | 57 | Virtual interfaces |
| 74 | 58 | ================== |
| @@ -123,79 +107,32 @@ functions/definitions · 48 unmodified lines | ||
| 123 | 107 | --------------------- |
| 124 | 108 | |
| 125 | 109 | .. kernel-doc:: include/net/mac80211.h |
| 126 | − :functions: ieee80211_rx_status | |
| 127 | − | |
| 128 | −.. kernel-doc:: include/net/mac80211.h | |
| 129 | − :functions: mac80211_rx_encoding_flags | |
| 130 | − | |
| 131 | −.. kernel-doc:: include/net/mac80211.h | |
| 132 | − :functions: mac80211_rx_flags | |
| 133 | − | |
| 134 | −.. kernel-doc:: include/net/mac80211.h | |
| 135 | − :functions: mac80211_tx_info_flags | |
| 136 | − | |
| 137 | −.. kernel-doc:: include/net/mac80211.h | |
| 138 | − :functions: mac80211_tx_control_flags | |
| 139 | − | |
| 140 | −.. kernel-doc:: include/net/mac80211.h | |
| 141 | − :functions: mac80211_rate_control_flags | |
| 142 | − | |
| 143 | −.. kernel-doc:: include/net/mac80211.h | |
| 144 | − :functions: ieee80211_tx_rate | |
| 145 | − | |
| 146 | −.. kernel-doc:: include/net/mac80211.h | |
| 147 | − :functions: ieee80211_tx_info | |
| 148 | − | |
| 149 | −.. kernel-doc:: include/net/mac80211.h | |
| 150 | − :functions: ieee80211_tx_info_clear_status | |
| 151 | − | |
| 152 | −.. kernel-doc:: include/net/mac80211.h | |
| 153 | − :functions: ieee80211_rx | |
| 154 | − | |
| 155 | −.. kernel-doc:: include/net/mac80211.h | |
| 156 | − :functions: ieee80211_rx_ni | |
| 157 | − | |
| 158 | −.. kernel-doc:: include/net/mac80211.h | |
| 159 | − :functions: ieee80211_rx_irqsafe | |
| 160 | − | |
| 161 | −.. kernel-doc:: include/net/mac80211.h | |
| 162 | − :functions: ieee80211_tx_status | |
| 163 | − | |
| 164 | −.. kernel-doc:: include/net/mac80211.h | |
| 165 | − :functions: ieee80211_tx_status_ni | |
| 166 | − | |
| 167 | −.. kernel-doc:: include/net/mac80211.h | |
| 168 | − :functions: ieee80211_tx_status_irqsafe | |
| 169 | − | |
| 170 | −.. kernel-doc:: include/net/mac80211.h | |
| 171 | − :functions: ieee80211_rts_get | |
| 172 | − | |
| 173 | −.. kernel-doc:: include/net/mac80211.h | |
| 174 | − :functions: ieee80211_rts_duration | |
| 175 | − | |
| 176 | −.. kernel-doc:: include/net/mac80211.h | |
| 177 | − :functions: ieee80211_ctstoself_get | |
| 178 | − | |
| 179 | −.. kernel-doc:: include/net/mac80211.h | |
| 180 | − :functions: ieee80211_ctstoself_duration | |
| 181 | − | |
| 182 | −.. kernel-doc:: include/net/mac80211.h | |
| 183 | − :functions: ieee80211_generic_frame_duration | |
| 184 | − | |
| 185 | −.. kernel-doc:: include/net/mac80211.h | |
| 186 | − :functions: ieee80211_wake_queue | |
| 187 | − | |
| 188 | −.. kernel-doc:: include/net/mac80211.h | |
| 189 | − :functions: ieee80211_stop_queue | |
| 190 | − | |
| 191 | −.. kernel-doc:: include/net/mac80211.h | |
| 192 | − :functions: ieee80211_wake_queues | |
| 193 | − | |
| 194 | −.. kernel-doc:: include/net/mac80211.h | |
| 195 | − :functions: ieee80211_stop_queues | |
| 196 | − | |
| 197 | −.. kernel-doc:: include/net/mac80211.h | |
| 198 | − :functions: ieee80211_queue_stopped | |
| 110 | + :functions: | |
| 111 | + ieee80211_rx_status | |
| 112 | + mac80211_rx_encoding_flags | |
| 113 | + mac80211_rx_flags | |
| 114 | + mac80211_tx_info_flags | |
| 115 | + mac80211_tx_control_flags | |
| 116 | + mac80211_rate_control_flags | |
| 117 | + ieee80211_tx_rate | |
| 118 | + ieee80211_tx_info | |
| 119 | + ieee80211_tx_info_clear_status | |
| 120 | + ieee80211_rx | |
| 121 | + ieee80211_rx_ni | |
| 122 | + ieee80211_rx_irqsafe | |
| 123 | + ieee80211_tx_status | |
| 124 | + ieee80211_tx_status_ni | |
| 125 | + ieee80211_tx_status_irqsafe | |
| 126 | + ieee80211_rts_get | |
| 127 | + ieee80211_rts_duration | |
| 128 | + ieee80211_ctstoself_get | |
| 129 | + ieee80211_ctstoself_duration | |
| 130 | + ieee80211_generic_frame_duration | |
| 131 | + ieee80211_wake_queue | |
| 132 | + ieee80211_stop_queue | |
| 133 | + ieee80211_wake_queues | |
| 134 | + ieee80211_stop_queues | |
| 135 | + ieee80211_queue_stopped | |
| 199 | 136 | |
| 200 | 137 | Frame filtering |
| 201 | 138 | =============== |
| @@ -213,7 +150,6 @@ The mac80211 workqueue · 11 unmodified lines | ||
| 213 | 150 | :doc: mac80211 workqueue |
| 214 | 151 | |
| 215 | 152 | .. kernel-doc:: include/net/mac80211.h |
| 216 | − :functions: ieee80211_queue_work | |
| 217 | − | |
| 218 | −.. kernel-doc:: include/net/mac80211.h | |
| 219 | − :functions: ieee80211_queue_delayed_work | |
| 153 | + :functions: | |
| 154 | + ieee80211_queue_work | |
| 155 | + ieee80211_queue_delayed_work | |
| @@ -258,14 +258,21 @@ socket into zero-copy mode or fail. · 257 unmodified lines | ||
| 258 | 258 | XDP_SHARED_UMEM bind flag |
| 259 | 259 | ------------------------- |
| 260 | 260 | |
| 261 | −This flag enables you to bind multiple sockets to the same UMEM, but | |
| 262 | −only if they share the same queue id. In this mode, each socket has | |
| 263 | −their own RX and TX rings, but the UMEM (tied to the fist socket | |
| 264 | −created) only has a single FILL ring and a single COMPLETION | |
| 265 | −ring. To use this mode, create the first socket and bind it in the normal | |
| 266 | −way. Create a second socket and create an RX and a TX ring, or at | |
| 267 | −least one of them, but no FILL or COMPLETION rings as the ones from | |
| 268 | −the first socket will be used. In the bind call, set he | |
| 261 | +This flag enables you to bind multiple sockets to the same UMEM. It | |
| 262 | +works on the same queue id, between queue ids and between | |
| 263 | +netdevs/devices. In this mode, each socket has their own RX and TX | |
| 264 | +rings as usual, but you are going to have one or more FILL and | |
| 265 | +COMPLETION ring pairs. You have to create one of these pairs per | |
| 266 | +unique netdev and queue id tuple that you bind to. | |
| 267 | + | |
| 268 | +Starting with the case were we would like to share a UMEM between | |
| 269 | +sockets bound to the same netdev and queue id. The UMEM (tied to the | |
| 270 | +fist socket created) will only have a single FILL ring and a single | |
| 271 | +COMPLETION ring as there is only on unique netdev,queue_id tuple that | |
| 272 | +we have bound to. To use this mode, create the first socket and bind | |
| 273 | +it in the normal way. Create a second socket and create an RX and a TX | |
| 274 | +ring, or at least one of them, but no FILL or COMPLETION rings as the | |
| 275 | +ones from the first socket will be used. In the bind call, set he | |
| 269 | 276 | XDP_SHARED_UMEM option and provide the initial socket's fd in the |
| 270 | 277 | sxdp_shared_umem_fd field. You can attach an arbitrary number of extra |
| 271 | 278 | sockets this way. |
| @@ -305,11 +312,41 @@ concurrently. There are no synchronization primitives in the · 33 unmodified lines | ||
| 305 | 312 | libbpf code that protects multiple users at this point in time. |
| 306 | 313 | |
| 307 | 314 | Libbpf uses this mode if you create more than one socket tied to the |
| 308 | −same umem. However, note that you need to supply the | |
| 315 | +same UMEM. However, note that you need to supply the | |
| 309 | 316 | XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD libbpf_flag with the |
| 310 | 317 | xsk_socket__create calls and load your own XDP program as there is no |
| 311 | 318 | built in one in libbpf that will route the traffic for you. |
| 312 | 319 | |
| 320 | +The second case is when you share a UMEM between sockets that are | |
| 321 | +bound to different queue ids and/or netdevs. In this case you have to | |
| 322 | +create one FILL ring and one COMPLETION ring for each unique | |
| 323 | +netdev,queue_id pair. Let us say you want to create two sockets bound | |
| 324 | +to two different queue ids on the same netdev. Create the first socket | |
| 325 | +and bind it in the normal way. Create a second socket and create an RX | |
| 326 | +and a TX ring, or at least one of them, and then one FILL and | |
| 327 | +COMPLETION ring for this socket. Then in the bind call, set he | |
| 328 | +XDP_SHARED_UMEM option and provide the initial socket's fd in the | |
| 329 | +sxdp_shared_umem_fd field as you registered the UMEM on that | |
| 330 | +socket. These two sockets will now share one and the same UMEM. | |
| 331 | + | |
| 332 | +There is no need to supply an XDP program like the one in the previous | |
| 333 | +case where sockets were bound to the same queue id and | |
| 334 | +device. Instead, use the NIC's packet steering capabilities to steer | |
| 335 | +the packets to the right queue. In the previous example, there is only | |
| 336 | +one queue shared among sockets, so the NIC cannot do this steering. It | |
| 337 | +can only steer between queues. | |
| 338 | + | |
| 339 | +In libbpf, you need to use the xsk_socket__create_shared() API as it | |
| 340 | +takes a reference to a FILL ring and a COMPLETION ring that will be | |
| 341 | +created for you and bound to the shared UMEM. You can use this | |
| 342 | +function for all the sockets you create, or you can use it for the | |
| 343 | +second and following ones and use xsk_socket__create() for the first | |
| 344 | +one. Both methods yield the same result. | |
| 345 | + | |
| 346 | +Note that a UMEM can be shared between sockets on the same queue id | |
| 347 | +and device, as well as between queues on the same device and between | |
| 348 | +devices at the same time. | |
| 349 | + | |
| 313 | 350 | XDP_USE_NEED_WAKEUP bind flag |
| 314 | 351 | ----------------------------- |
| 315 | 352 | |
| @@ -364,7 +401,7 @@ resources by only setting up one of them. Both the FILL ring and the · 48 unmodified lines | ||
| 364 | 401 | COMPLETION ring are mandatory as you need to have a UMEM tied to your |
| 365 | 402 | socket. But if the XDP_SHARED_UMEM flag is used, any socket after the |
| 366 | 403 | first one does not have a UMEM and should in that case not have any |
| 367 | −FILL or COMPLETION rings created as the ones from the shared umem will | |
| 404 | +FILL or COMPLETION rings created as the ones from the shared UMEM will | |
| 368 | 405 | be used. Note, that the rings are single-producer single-consumer, so |
| 369 | 406 | do not try to access them from multiple processes at the same |
| 370 | 407 | time. See the XDP_SHARED_UMEM section. |
| @@ -567,6 +604,17 @@ A: The short answer is no, that is not supported at the moment. The · 196 unmodified lines | ||
| 567 | 604 | switch, or other distribution mechanism, in your NIC to direct |
| 568 | 605 | traffic to the correct queue id and socket. |
| 569 | 606 | |
| 607 | +Q: My packets are sometimes corrupted. What is wrong? | |
| 608 | + | |
| 609 | +A: Care has to be taken not to feed the same buffer in the UMEM into | |
| 610 | + more than one ring at the same time. If you for example feed the | |
| 611 | + same buffer into the FILL ring and the TX ring at the same time, the | |
| 612 | + NIC might receive data into the buffer at the same time it is | |
| 613 | + sending it. This will cause some packets to become corrupted. Same | |
| 614 | + thing goes for feeding the same buffer into the FILL rings | |
| 615 | + belonging to different queue ids or netdevs bound with the | |
| 616 | + XDP_SHARED_UMEM flag. | |
| 617 | + | |
| 570 | 618 | Credits |
| 571 | 619 | ======= |
| 572 | 620 | |
| @@ -10,4 +10,3 @@ Contents: · 9 unmodified lines | ||
| 10 | 10 | |
| 11 | 11 | linux_caif |
| 12 | 12 | caif |
| 13 | − spi_porting | |
| @@ -1,229 +0,0 @@ | ||
| 1 | −.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | − | |
| 3 | −================ | |
| 4 | −CAIF SPI porting | |
| 5 | −================ | |
| 6 | − | |
| 7 | −CAIF SPI basics | |
| 8 | −=============== | |
| 9 | − | |
| 10 | −Running CAIF over SPI needs some extra setup, owing to the nature of SPI. | |
| 11 | −Two extra GPIOs have been added in order to negotiate the transfers | |
| 12 | −between the master and the slave. The minimum requirement for running | |
| 13 | −CAIF over SPI is a SPI slave chip and two GPIOs (more details below). | |
| 14 | −Please note that running as a slave implies that you need to keep up | |
| 15 | −with the master clock. An overrun or underrun event is fatal. | |
| 16 | − | |
| 17 | −CAIF SPI framework | |
| 18 | −================== | |
| 19 | − | |
| 20 | −To make porting as easy as possible, the CAIF SPI has been divided in | |
| 21 | −two parts. The first part (called the interface part) deals with all | |
| 22 | −generic functionality such as length framing, SPI frame negotiation | |
| 23 | −and SPI frame delivery and transmission. The other part is the CAIF | |
| 24 | −SPI slave device part, which is the module that you have to write if | |
| 25 | −you want to run SPI CAIF on a new hardware. This part takes care of | |
| 26 | −the physical hardware, both with regard to SPI and to GPIOs. | |
| 27 | − | |
| 28 | −- Implementing a CAIF SPI device: | |
| 29 | − | |
| 30 | − - Functionality provided by the CAIF SPI slave device: | |
| 31 | − | |
| 32 | − In order to implement a SPI device you will, as a minimum, | |
| 33 | − need to implement the following | |
| 34 | − functions: | |
| 35 | − | |
| 36 | − :: | |
| 37 | − | |
| 38 | − int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev): | |
| 39 | − | |
| 40 | − This function is called by the CAIF SPI interface to give | |
| 41 | − you a chance to set up your hardware to be ready to receive | |
| 42 | − a stream of data from the master. The xfer structure contains | |
| 43 | − both physical and logical addresses, as well as the total length | |
| 44 | − of the transfer in both directions.The dev parameter can be used | |
| 45 | − to map to different CAIF SPI slave devices. | |
| 46 | − | |
| 47 | − :: | |
| 48 | − | |
| 49 | − void (*sig_xfer) (bool xfer, struct cfspi_dev *dev): | |
| 50 | − | |
| 51 | − This function is called by the CAIF SPI interface when the output | |
| 52 | − (SPI_INT) GPIO needs to change state. The boolean value of the xfer | |
| 53 | − variable indicates whether the GPIO should be asserted (HIGH) or | |
| 54 | − deasserted (LOW). The dev parameter can be used to map to different CAIF | |
| 55 | − SPI slave devices. | |
| 56 | − | |
| 57 | − - Functionality provided by the CAIF SPI interface: | |
| 58 | − | |
| 59 | − :: | |
| 60 | − | |
| 61 | − void (*ss_cb) (bool assert, struct cfspi_ifc *ifc); | |
| 62 | − | |
| 63 | − This function is called by the CAIF SPI slave device in order to | |
| 64 | − signal a change of state of the input GPIO (SS) to the interface. | |
| 65 | − Only active edges are mandatory to be reported. | |
| 66 | − This function can be called from IRQ context (recommended in order | |
| 67 | − not to introduce latency). The ifc parameter should be the pointer | |
| 68 | − returned from the platform probe function in the SPI device structure. | |
| 69 | − | |
| 70 | − :: | |
| 71 | − | |
| 72 | − void (*xfer_done_cb) (struct cfspi_ifc *ifc); | |
| 73 | − | |
| 74 | − This function is called by the CAIF SPI slave device in order to | |
| 75 | − report that a transfer is completed. This function should only be | |
| 76 | − called once both the transmission and the reception are completed. | |
| 77 | − This function can be called from IRQ context (recommended in order | |
| 78 | − not to introduce latency). The ifc parameter should be the pointer | |
| 79 | − returned from the platform probe function in the SPI device structure. | |
| 80 | − | |
| 81 | − - Connecting the bits and pieces: | |
| 82 | − | |
| 83 | − - Filling in the SPI slave device structure: | |
| 84 | − | |
| 85 | − Connect the necessary callback functions. | |
| 86 | − | |
| 87 | − Indicate clock speed (used to calculate toggle delays). | |
| 88 | − | |
| 89 | − Chose a suitable name (helps debugging if you use several CAIF | |
| 90 | − SPI slave devices). | |
| 91 | − | |
| 92 | − Assign your private data (can be used to map to your | |
| 93 | − structure). | |
| 94 | − | |
| 95 | − - Filling in the SPI slave platform device structure: | |
| 96 | − | |
| 97 | − Add name of driver to connect to ("cfspi_sspi"). | |
| 98 | − | |
| 99 | − Assign the SPI slave device structure as platform data. | |
| 100 | − | |
| 101 | −Padding | |
| 102 | −======= | |
| 103 | − | |
| 104 | −In order to optimize throughput, a number of SPI padding options are provided. | |
| 105 | −Padding can be enabled independently for uplink and downlink transfers. | |
| 106 | −Padding can be enabled for the head, the tail and for the total frame size. | |
| 107 | −The padding needs to be correctly configured on both sides of the link. | |
| 108 | −The padding can be changed via module parameters in cfspi_sspi.c or via | |
| 109 | −the sysfs directory of the cfspi_sspi driver (before device registration). | |
| 110 | − | |
| 111 | −- CAIF SPI device template:: | |
| 112 | − | |
| 113 | − /* | |
| 114 | − * Copyright (C) ST-Ericsson AB 2010 | |
| 115 | − * Author: Daniel Martensson / Daniel.Martensson@stericsson.com | |
| 116 | − * License terms: GNU General Public License (GPL), version 2. | |
| 117 | − * | |
| 118 | − */ | |
| 119 | − | |
| 120 | − #include <linux/init.h> | |
| 121 | − #include <linux/module.h> | |
| 122 | − #include <linux/device.h> | |
| 123 | − #include <linux/wait.h> | |
| 124 | − #include <linux/interrupt.h> | |
| 125 | − #include <linux/dma-mapping.h> | |
| 126 | − #include <net/caif/caif_spi.h> | |
| 127 | − | |
| 128 | − MODULE_LICENSE("GPL"); | |
| 129 | − | |
| 130 | − struct sspi_struct { | |
| 131 | − struct cfspi_dev sdev; | |
| 132 | − struct cfspi_xfer *xfer; | |
| 133 | − }; | |
| 134 | − | |
| 135 | − static struct sspi_struct slave; | |
| 136 | − static struct platform_device slave_device; | |
| 137 | − | |
| 138 | − static irqreturn_t sspi_irq(int irq, void *arg) | |
| 139 | − { | |
| 140 | − /* You only need to trigger on an edge to the active state of the | |
| 141 | − * SS signal. Once a edge is detected, the ss_cb() function should be | |
| 142 | − * called with the parameter assert set to true. It is OK | |
| 143 | − * (and even advised) to call the ss_cb() function in IRQ context in | |
| 144 | − * order not to add any delay. */ | |
| 145 | − | |
| 146 | − return IRQ_HANDLED; | |
| 147 | − } | |
| 148 | − | |
| 149 | − static void sspi_complete(void *context) | |
| 150 | − { | |
| 151 | − /* Normally the DMA or the SPI framework will call you back | |
| 152 | − * in something similar to this. The only thing you need to | |
| 153 | − * do is to call the xfer_done_cb() function, providing the pointer | |
| 154 | − * to the CAIF SPI interface. It is OK to call this function | |
| 155 | − * from IRQ context. */ | |
| 156 | − } | |
| 157 | − | |
| 158 | − static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev) | |
| 159 | − { | |
| 160 | − /* Store transfer info. For a normal implementation you should | |
| 161 | − * set up your DMA here and make sure that you are ready to | |
| 162 | − * receive the data from the master SPI. */ | |
| 163 | − | |
| 164 | − struct sspi_struct *sspi = (struct sspi_struct *)dev->priv; | |
| 165 | − | |
| 166 | − sspi->xfer = xfer; | |
| 167 | − | |
| 168 | − return 0; | |
| 169 | − } | |
| 170 | − | |
| 171 | − void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev) | |
| 172 | − { | |
| 173 | − /* If xfer is true then you should assert the SPI_INT to indicate to | |
| 174 | − * the master that you are ready to receive the data from the master | |
| 175 | − * SPI. If xfer is false then you should de-assert SPI_INT to indicate | |
| 176 | − * that the transfer is done. | |
| 177 | − */ | |
| 178 | − | |
| 179 | − struct sspi_struct *sspi = (struct sspi_struct *)dev->priv; | |
| 180 | − } | |
| 181 | − | |
| 182 | − static void sspi_release(struct device *dev) | |
| 183 | − { | |
| 184 | − /* | |
| 185 | − * Here you should release your SPI device resources. | |
| 186 | − */ | |
| 187 | − } | |
| 188 | − | |
| 189 | − static int __init sspi_init(void) | |
| 190 | − { | |
| 191 | − /* Here you should initialize your SPI device by providing the | |
| 192 | − * necessary functions, clock speed, name and private data. Once | |
| 193 | − * done, you can register your device with the | |
| 194 | − * platform_device_register() function. This function will return | |
| 195 | − * with the CAIF SPI interface initialized. This is probably also | |
| 196 | − * the place where you should set up your GPIOs, interrupts and SPI | |
| 197 | − * resources. */ | |
| 198 | − | |
| 199 | − int res = 0; | |
| 200 | − | |
| 201 | − /* Initialize slave device. */ | |
| 202 | − slave.sdev.init_xfer = sspi_init_xfer; | |
| 203 | − slave.sdev.sig_xfer = sspi_sig_xfer; | |
| 204 | − slave.sdev.clk_mhz = 13; | |
| 205 | − slave.sdev.priv = &slave; | |
| 206 | − slave.sdev.name = "spi_sspi"; | |
| 207 | − slave_device.dev.release = sspi_release; | |
| 208 | − | |
| 209 | − /* Initialize platform device. */ | |
| 210 | − slave_device.name = "cfspi_sspi"; | |
| 211 | − slave_device.dev.platform_data = &slave.sdev; | |
| 212 | − | |
| 213 | − /* Register platform device. */ | |
| 214 | − res = platform_device_register(&slave_device); | |
| 215 | − if (res) { | |
| 216 | − printk(KERN_WARNING "sspi_init: failed to register dev.\n"); | |
| 217 | − return -ENODEV; | |
| 218 | − } | |
| 219 | − | |
| 220 | − return res; | |
| 221 | − } | |
| 222 | − | |
| 223 | − static void __exit sspi_exit(void) | |
| 224 | − { | |
| 225 | − platform_device_del(&slave_device); | |
| 226 | − } | |
| 227 | − | |
| 228 | − module_init(sspi_init); | |
| 229 | − module_exit(sspi_exit); | |
| @@ -39,16 +39,6 @@ debug logs. · 38 unmodified lines | ||
| 39 | 39 | Some of the ENA devices support a working mode called Low-latency |
| 40 | 40 | Queue (LLQ), which saves several more microseconds. |
| 41 | 41 | |
| 42 | −Supported PCI vendor ID/device IDs | |
| 43 | −================================== | |
| 44 | − | |
| 45 | −========= ======================= | |
| 46 | −1d0f:0ec2 ENA PF | |
| 47 | −1d0f:1ec2 ENA PF with LLQ support | |
| 48 | −1d0f:ec20 ENA VF | |
| 49 | −1d0f:ec21 ENA VF with LLQ support | |
| 50 | −========= ======================= | |
| 51 | − | |
| 52 | 42 | ENA Source Code Directory Structure |
| 53 | 43 | =================================== |
| 54 | 44 | |
| @@ -212,20 +202,11 @@ In adaptive interrupt moderation mode the interrupt delay value is · 157 unmodified lines | ||
| 212 | 202 | updated by the driver dynamically and adjusted every NAPI cycle |
| 213 | 203 | according to the traffic nature. |
| 214 | 204 | |
| 215 | −By default ENA driver applies adaptive coalescing on Rx traffic and | |
| 216 | −conventional coalescing on Tx traffic. | |
| 217 | − | |
| 218 | 205 | Adaptive coalescing can be switched on/off through ethtool(8) |
| 219 | 206 | adaptive_rx on|off parameter. |
| 220 | 207 | |
| 221 | −The driver chooses interrupt delay value according to the number of | |
| 222 | −bytes and packets received between interrupt unmasking and interrupt | |
| 223 | −posting. The driver uses interrupt delay table that subdivides the | |
| 224 | −range of received bytes/packets into 5 levels and assigns interrupt | |
| 225 | −delay value to each level. | |
| 226 | − | |
| 227 | −The user can enable/disable adaptive moderation, modify the interrupt | |
| 228 | −delay table and restore its default values through sysfs. | |
| 208 | +More information about Adaptive Interrupt Moderation (DIM) can be found in | |
| 209 | +Documentation/networking/net_dim.rst | |
| 229 | 210 | |
| 230 | 211 | RX copybreak |
| 231 | 212 | ============ |
| @@ -274,7 +255,7 @@ RSS · 42 unmodified lines | ||
| 274 | 255 | inputs for hash functions. |
| 275 | 256 | - The driver configures RSS settings using the AQ SetFeature command |
| 276 | 257 | (ENA_ADMIN_RSS_HASH_FUNCTION, ENA_ADMIN_RSS_HASH_INPUT and |
| 277 | − ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG properties). | |
| 258 | + ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG properties). | |
| 278 | 259 | - If the NETIF_F_RXHASH flag is set, the 32-bit result of the hash |
| 279 | 260 | function delivered in the Rx CQ descriptor is set in the received |
| 280 | 261 | SKB. |
| @@ -16,6 +16,34 @@ Note that the file name is a path relative to the firmware loading path · 15 unmodified lines | ||
| 16 | 16 | (usually ``/lib/firmware/``). Drivers may send status updates to inform |
| 17 | 17 | user space about the progress of the update operation. |
| 18 | 18 | |
| 19 | +Overwrite Mask | |
| 20 | +============== | |
| 21 | + | |
| 22 | +The ``devlink-flash`` command allows optionally specifying a mask indicating | |
| 23 | +how the device should handle subsections of flash components when updating. | |
| 24 | +This mask indicates the set of sections which are allowed to be overwritten. | |
| 25 | + | |
| 26 | +.. list-table:: List of overwrite mask bits | |
| 27 | + :widths: 5 95 | |
| 28 | + | |
| 29 | + * - Name | |
| 30 | + - Description | |
| 31 | + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` | |
| 32 | + - Indicates that the device should overwrite settings in the components | |
| 33 | + being updated with the settings found in the provided image. | |
| 34 | + * - ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` | |
| 35 | + - Indicates that the device should overwrite identifiers in the | |
| 36 | + components being updated with the identifiers found in the provided | |
| 37 | + image. This includes MAC addresses, serial IDs, and similar device | |
| 38 | + identifiers. | |
| 39 | + | |
| 40 | +Multiple overwrite bits may be combined and requested together. If no bits | |
| 41 | +are provided, it is expected that the device only update firmware binaries | |
| 42 | +in the components being updated. Settings and identifiers are expected to be | |
| 43 | +preserved across the update. A device may not support every combination and | |
| 44 | +the driver for such a device must reject any combination which cannot be | |
| 45 | +faithfully implemented. | |
| 46 | + | |
| 19 | 47 | Firmware Loading |
| 20 | 48 | ================ |
| 21 | 49 | |
| @@ -108,3 +108,9 @@ own name. · 107 unmodified lines | ||
| 108 | 108 | * - ``region_snapshot_enable`` |
| 109 | 109 | - Boolean |
| 110 | 110 | - Enable capture of ``devlink-region`` snapshots. |
| 111 | + * - ``enable_remote_dev_reset`` | |
| 112 | + - Boolean | |
| 113 | + - Enable device reset by remote host. When cleared, the device driver | |
| 114 | + will NACK any attempt of other host to reset the device. This parameter | |
| 115 | + is useful for setups where a device is shared by different hosts, such | |
| 116 | + as multi-host setup. | |
| @@ -0,0 +1,81 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +============== | |
| 4 | +Devlink Reload | |
| 5 | +============== | |
| 6 | + | |
| 7 | +``devlink-reload`` provides mechanism to reinit driver entities, applying | |
| 8 | +``devlink-params`` and ``devlink-resources`` new values. It also provides | |
| 9 | +mechanism to activate firmware. | |
| 10 | + | |
| 11 | +Reload Actions | |
| 12 | +============== | |
| 13 | + | |
| 14 | +User may select a reload action. | |
| 15 | +By default ``driver_reinit`` action is selected. | |
| 16 | + | |
| 17 | +.. list-table:: Possible reload actions | |
| 18 | + :widths: 5 90 | |
| 19 | + | |
| 20 | + * - Name | |
| 21 | + - Description | |
| 22 | + * - ``driver-reinit`` | |
| 23 | + - Devlink driver entities re-initialization, including applying | |
| 24 | + new values to devlink entities which are used during driver | |
| 25 | + load such as ``devlink-params`` in configuration mode | |
| 26 | + ``driverinit`` or ``devlink-resources`` | |
| 27 | + * - ``fw_activate`` | |
| 28 | + - Firmware activate. Activates new firmware if such image is stored and | |
| 29 | + pending activation. If no limitation specified this action may involve | |
| 30 | + firmware reset. If no new image pending this action will reload current | |
| 31 | + firmware image. | |
| 32 | + | |
| 33 | +Note that even though user asks for a specific action, the driver | |
| 34 | +implementation might require to perform another action alongside with | |
| 35 | +it. For example, some driver do not support driver reinitialization | |
| 36 | +being performed without fw activation. Therefore, the devlink reload | |
| 37 | +command returns the list of actions which were actrually performed. | |
| 38 | + | |
| 39 | +Reload Limits | |
| 40 | +============= | |
| 41 | + | |
| 42 | +By default reload actions are not limited and driver implementation may | |
| 43 | +include reset or downtime as needed to perform the actions. | |
| 44 | + | |
| 45 | +However, some drivers support action limits, which limit the action | |
| 46 | +implementation to specific constraints. | |
| 47 | + | |
| 48 | +.. list-table:: Possible reload limits | |
| 49 | + :widths: 5 90 | |
| 50 | + | |
| 51 | + * - Name | |
| 52 | + - Description | |
| 53 | + * - ``no_reset`` | |
| 54 | + - No reset allowed, no down time allowed, no link flap and no | |
| 55 | + configuration is lost. | |
| 56 | + | |
| 57 | +Change Namespace | |
| 58 | +================ | |
| 59 | + | |
| 60 | +The netns option allows user to be able to move devlink instances into | |
| 61 | +namespaces during devlink reload operation. | |
| 62 | +By default all devlink instances are created in init_net and stay there. | |
| 63 | + | |
| 64 | +example usage | |
| 65 | +------------- | |
| 66 | + | |
| 67 | +.. code:: shell | |
| 68 | + | |
| 69 | + $ devlink dev reload help | |
| 70 | + $ devlink dev reload DEV [ netns { PID | NAME | ID } ] [ action { driver_reinit | fw_activate } ] [ limit no_reset ] | |
| 71 | + | |
| 72 | + # Run reload command for devlink driver entities re-initialization: | |
| 73 | + $ devlink dev reload pci/0000:82:00.0 action driver_reinit | |
| 74 | + reload_actions_performed: | |
| 75 | + driver_reinit | |
| 76 | + | |
| 77 | + # Run reload command to activate firmware: | |
| 78 | + # Note that mlx5 driver reloads the driver while activating firmware | |
| 79 | + $ devlink dev reload pci/0000:82:00.0 action fw_activate | |
| 80 | + reload_actions_performed: | |
| 81 | + driver_reinit fw_activate | |
| @@ -409,6 +409,73 @@ be added to the following table: · 408 unmodified lines | ||
| 409 | 409 | - ``drop`` |
| 410 | 410 | - Traps packets dropped due to the RED (Random Early Detection) algorithm |
| 411 | 411 | (i.e., early drops) |
| 412 | + * - ``vxlan_parsing`` | |
| 413 | + - ``drop`` | |
| 414 | + - Traps packets dropped due to an error in the VXLAN header parsing which | |
| 415 | + might be because of packet truncation or the I flag is not set. | |
| 416 | + * - ``llc_snap_parsing`` | |
| 417 | + - ``drop`` | |
| 418 | + - Traps packets dropped due to an error in the LLC+SNAP header parsing | |
| 419 | + * - ``vlan_parsing`` | |
| 420 | + - ``drop`` | |
| 421 | + - Traps packets dropped due to an error in the VLAN header parsing. Could | |
| 422 | + include unexpected packet truncation. | |
| 423 | + * - ``pppoe_ppp_parsing`` | |
| 424 | + - ``drop`` | |
| 425 | + - Traps packets dropped due to an error in the PPPoE+PPP header parsing. | |
| 426 | + This could include finding a session ID of 0xFFFF (which is reserved and | |
| 427 | + not for use), a PPPoE length which is larger than the frame received or | |
| 428 | + any common error on this type of header | |
| 429 | + * - ``mpls_parsing`` | |
| 430 | + - ``drop`` | |
| 431 | + - Traps packets dropped due to an error in the MPLS header parsing which | |
| 432 | + could include unexpected header truncation | |
| 433 | + * - ``arp_parsing`` | |
| 434 | + - ``drop`` | |
| 435 | + - Traps packets dropped due to an error in the ARP header parsing | |
| 436 | + * - ``ip_1_parsing`` | |
| 437 | + - ``drop`` | |
| 438 | + - Traps packets dropped due to an error in the first IP header parsing. | |
| 439 | + This packet trap could include packets which do not pass an IP checksum | |
| 440 | + check, a header length check (a minimum of 20 bytes), which might suffer | |
| 441 | + from packet truncation thus the total length field exceeds the received | |
| 442 | + packet length etc | |
| 443 | + * - ``ip_n_parsing`` | |
| 444 | + - ``drop`` | |
| 445 | + - Traps packets dropped due to an error in the parsing of the last IP | |
| 446 | + header (the inner one in case of an IP over IP tunnel). The same common | |
| 447 | + error checking is performed here as for the ip_1_parsing trap | |
| 448 | + * - ``gre_parsing`` | |
| 449 | + - ``drop`` | |
| 450 | + - Traps packets dropped due to an error in the GRE header parsing | |
| 451 | + * - ``udp_parsing`` | |
| 452 | + - ``drop`` | |
| 453 | + - Traps packets dropped due to an error in the UDP header parsing. | |
| 454 | + This packet trap could include checksum errorrs, an improper UDP | |
| 455 | + length detected (smaller than 8 bytes) or detection of header | |
| 456 | + truncation. | |
| 457 | + * - ``tcp_parsing`` | |
| 458 | + - ``drop`` | |
| 459 | + - Traps packets dropped due to an error in the TCP header parsing. | |
| 460 | + This could include TCP checksum errors, improper combination of SYN, FIN | |
| 461 | + and/or RESET etc. | |
| 462 | + * - ``ipsec_parsing`` | |
| 463 | + - ``drop`` | |
| 464 | + - Traps packets dropped due to an error in the IPSEC header parsing | |
| 465 | + * - ``sctp_parsing`` | |
| 466 | + - ``drop`` | |
| 467 | + - Traps packets dropped due to an error in the SCTP header parsing. | |
| 468 | + This would mean that port number 0 was used or that the header is | |
| 469 | + truncated. | |
| 470 | + * - ``dccp_parsing`` | |
| 471 | + - ``drop`` | |
| 472 | + - Traps packets dropped due to an error in the DCCP header parsing | |
| 473 | + * - ``gtp_parsing`` | |
| 474 | + - ``drop`` | |
| 475 | + - Traps packets dropped due to an error in the GTP header parsing | |
| 476 | + * - ``esp_parsing`` | |
| 477 | + - ``drop`` | |
| 478 | + - Traps packets dropped due to an error in the ESP header parsing | |
| 412 | 479 | |
| 413 | 480 | Driver-specific Packet Traps |
| 414 | 481 | ============================ |
| @@ -509,6 +576,9 @@ narrow. The description of these groups must be added to the following table: · 94 unmodified lines | ||
| 509 | 576 | * - ``acl_trap`` |
| 510 | 577 | - Contains packet traps for packets that were trapped (logged) by the |
| 511 | 578 | device during ACL processing |
| 579 | + * - ``parser_error_drops`` | |
| 580 | + - Contains packet traps for packets that were marked by the device during | |
| 581 | + parsing as erroneous | |
| 512 | 582 | |
| 513 | 583 | Packet Trap Policers |
| 514 | 584 | ==================== |
| @@ -69,6 +69,11 @@ The ``ice`` driver reports the following versions · 68 unmodified lines | ||
| 69 | 69 | - The version of the DDP package that is active in the device. Note |
| 70 | 70 | that both the name (as reported by ``fw.app.name``) and version are |
| 71 | 71 | required to uniquely identify the package. |
| 72 | + * - ``fw.app.bundle_id`` | |
| 73 | + - 0xc0000001 | |
| 74 | + - Unique identifier for the DDP package loaded in the device. Also | |
| 75 | + referred to as the DDP Track ID. Can be used to uniquely identify | |
| 76 | + the specific DDP package. | |
| 72 | 77 | * - ``fw.netlist`` |
| 73 | 78 | - running |
| 74 | 79 | - 1.1.2000-6.7.0 |
| @@ -81,6 +86,37 @@ The ``ice`` driver reports the following versions · 6 unmodified lines | ||
| 81 | 86 | - 0xee16ced7 |
| 82 | 87 | - The first 4 bytes of the hash of the netlist module contents. |
| 83 | 88 | |
| 89 | +Flash Update | |
| 90 | +============ | |
| 91 | + | |
| 92 | +The ``ice`` driver implements support for flash update using the | |
| 93 | +``devlink-flash`` interface. It supports updating the device flash using a | |
| 94 | +combined flash image that contains the ``fw.mgmt``, ``fw.undi``, and | |
| 95 | +``fw.netlist`` components. | |
| 96 | + | |
| 97 | +.. list-table:: List of supported overwrite modes | |
| 98 | + :widths: 5 95 | |
| 99 | + | |
| 100 | + * - Bits | |
| 101 | + - Behavior | |
| 102 | + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` | |
| 103 | + - Do not preserve settings stored in the flash components being | |
| 104 | + updated. This includes overwriting the port configuration that | |
| 105 | + determines the number of physical functions the device will | |
| 106 | + initialize with. | |
| 107 | + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` and ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` | |
| 108 | + - Do not preserve either settings or identifiers. Overwrite everything | |
| 109 | + in the flash with the contents from the provided image, without | |
| 110 | + performing any preservation. This includes overwriting device | |
| 111 | + identifying fields such as the MAC address, VPD area, and device | |
| 112 | + serial number. It is expected that this combination be used with an | |
| 113 | + image customized for the specific device. | |
| 114 | + | |
| 115 | +The ice hardware does not support overwriting only identifiers while | |
| 116 | +preserving settings, and thus ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` on its | |
| 117 | +own will be rejected. If no overwrite mask is provided, the firmware will be | |
| 118 | +instructed to preserve all settings and identifying fields when updating. | |
| 119 | + | |
| 84 | 120 | Regions |
| 85 | 121 | ======= |
| 86 | 122 | |
| @@ -20,6 +20,7 @@ general. · 19 unmodified lines | ||
| 20 | 20 | devlink-params |
| 21 | 21 | devlink-region |
| 22 | 22 | devlink-resource |
| 23 | + devlink-reload | |
| 23 | 24 | devlink-trap |
| 24 | 25 | |
| 25 | 26 | Driver-specific documentation |
| @@ -68,6 +68,7 @@ the flags may not apply to requests. Recognized flags are: · 67 unmodified lines | ||
| 68 | 68 | ================================= =================================== |
| 69 | 69 | ``ETHTOOL_FLAG_COMPACT_BITSETS`` use compact format bitsets in reply |
| 70 | 70 | ``ETHTOOL_FLAG_OMIT_REPLY`` omit optional reply (_SET and _ACT) |
| 71 | + ``ETHTOOL_FLAG_STATS`` include optional device statistics | |
| 71 | 72 | ================================= =================================== |
| 72 | 73 | |
| 73 | 74 | New request flags should follow the general idea that if the flag is not set, |
| @@ -991,8 +992,18 @@ Kernel response contents: · 917 unmodified lines | ||
| 991 | 992 | ``ETHTOOL_A_PAUSE_AUTONEG`` bool pause autonegotiation |
| 992 | 993 | ``ETHTOOL_A_PAUSE_RX`` bool receive pause frames |
| 993 | 994 | ``ETHTOOL_A_PAUSE_TX`` bool transmit pause frames |
| 995 | + ``ETHTOOL_A_PAUSE_STATS`` nested pause statistics | |
| 994 | 996 | ===================================== ====== ========================== |
| 995 | 997 | |
| 998 | +``ETHTOOL_A_PAUSE_STATS`` are reported if ``ETHTOOL_FLAG_STATS`` was set | |
| 999 | +in ``ETHTOOL_A_HEADER_FLAGS``. | |
| 1000 | +It will be empty if driver did not report any statistics. Drivers fill in | |
| 1001 | +the statistics in the following structure: | |
| 1002 | + | |
| 1003 | +.. kernel-doc:: include/linux/ethtool.h | |
| 1004 | + :identifiers: ethtool_pause_stats | |
| 1005 | + | |
| 1006 | +Each member has a corresponding attribute defined. | |
| 996 | 1007 | |
| 997 | 1008 | PAUSE_SET |
| 998 | 1009 | ============ |
| @@ -93,6 +93,7 @@ Contents: · 92 unmodified lines | ||
| 93 | 93 | sctp |
| 94 | 94 | secid |
| 95 | 95 | seg6-sysctl |
| 96 | + statistics | |
| 96 | 97 | strparser |
| 97 | 98 | switchdev |
| 98 | 99 | sysfs-tagging |
| @@ -134,6 +134,15 @@ PHY Support · 133 unmodified lines | ||
| 134 | 134 | .. kernel-doc:: drivers/net/phy/phy.c |
| 135 | 135 | :internal: |
| 136 | 136 | |
| 137 | +.. kernel-doc:: drivers/net/phy/phy-core.c | |
| 138 | + :export: | |
| 139 | + | |
| 140 | +.. kernel-doc:: drivers/net/phy/phy-c45.c | |
| 141 | + :export: | |
| 142 | + | |
| 143 | +.. kernel-doc:: include/linux/phy.h | |
| 144 | + :internal: | |
| 145 | + | |
| 137 | 146 | .. kernel-doc:: drivers/net/phy/phy_device.c |
| 138 | 147 | :export: |
| 139 | 148 | |
| @@ -4,124 +4,364 @@ · 3 unmodified lines | ||
| 4 | 4 | L2TP |
| 5 | 5 | ==== |
| 6 | 6 | |
| 7 | −This document describes how to use the kernel's L2TP drivers to | |
| 8 | −provide L2TP functionality. L2TP is a protocol that tunnels one or | |
| 9 | −more sessions over an IP tunnel. It is commonly used for VPNs | |
| 10 | −(L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP | |
| 11 | −network infrastructure. With L2TPv3, it is also useful as a Layer-2 | |
| 12 | −tunneling infrastructure. | |
| 13 | − | |
| 14 | −Features | |
| 7 | +Layer 2 Tunneling Protocol (L2TP) allows L2 frames to be tunneled over | |
| 8 | +an IP network. | |
| 9 | + | |
| 10 | +This document covers the kernel's L2TP subsystem. It documents kernel | |
| 11 | +APIs for application developers who want to use the L2TP subsystem and | |
| 12 | +it provides some technical details about the internal implementation | |
| 13 | +which may be useful to kernel developers and maintainers. | |
| 14 | + | |
| 15 | +Overview | |
| 15 | 16 | ======== |
| 16 | 17 | |
| 17 | −L2TPv2 (PPP over L2TP (UDP tunnels)). | |
| 18 | −L2TPv3 ethernet pseudowires. | |
| 19 | −L2TPv3 PPP pseudowires. | |
| 20 | −L2TPv3 IP encapsulation. | |
| 21 | −Netlink sockets for L2TPv3 configuration management. | |
| 22 | − | |
| 23 | −History | |
| 24 | −======= | |
| 25 | − | |
| 26 | −The original pppol2tp driver was introduced in 2.6.23 and provided | |
| 27 | −L2TPv2 functionality (rfc2661). L2TPv2 is used to tunnel one or more PPP | |
| 28 | −sessions over a UDP tunnel. | |
| 29 | − | |
| 30 | −L2TPv3 (rfc3931) changes the protocol to allow different frame types | |
| 31 | −to be passed over an L2TP tunnel by moving the PPP-specific parts of | |
| 32 | −the protocol out of the core L2TP packet headers. Each frame type is | |
| 33 | −known as a pseudowire type. Ethernet, PPP, HDLC, Frame Relay and ATM | |
| 34 | −pseudowires for L2TP are defined in separate RFC standards. Another | |
| 35 | −change for L2TPv3 is that it can be carried directly over IP with no | |
| 36 | −UDP header (UDP is optional). It is also possible to create static | |
| 37 | −unmanaged L2TPv3 tunnels manually without a control protocol | |
| 38 | −(userspace daemon) to manage them. | |
| 39 | − | |
| 40 | −To support L2TPv3, the original pppol2tp driver was split up to | |
| 41 | −separate the L2TP and PPP functionality. Existing L2TPv2 userspace | |
| 42 | −apps should be unaffected as the original pppol2tp sockets API is | |
| 43 | −retained. L2TPv3, however, uses netlink to manage L2TPv3 tunnels and | |
| 44 | −sessions. | |
| 45 | − | |
| 46 | −Design | |
| 47 | −====== | |
| 48 | − | |
| 49 | −The L2TP protocol separates control and data frames. The L2TP kernel | |
| 50 | −drivers handle only L2TP data frames; control frames are always | |
| 51 | −handled by userspace. L2TP control frames carry messages between L2TP | |
| 52 | −clients/servers and are used to setup / teardown tunnels and | |
| 53 | −sessions. An L2TP client or server is implemented in userspace. | |
| 54 | − | |
| 55 | −Each L2TP tunnel is implemented using a UDP or L2TPIP socket; L2TPIP | |
| 56 | −provides L2TPv3 IP encapsulation (no UDP) and is implemented using a | |
| 57 | −new l2tpip socket family. The tunnel socket is typically created by | |
| 58 | −userspace, though for unmanaged L2TPv3 tunnels, the socket can also be | |
| 59 | −created by the kernel. Each L2TP session (pseudowire) gets a network | |
| 60 | −interface instance. In the case of PPP, these interfaces are created | |
| 61 | −indirectly by pppd using a pppol2tp socket. In the case of ethernet, | |
| 62 | −the netdevice is created upon a netlink request to create an L2TPv3 | |
| 63 | −ethernet pseudowire. | |
| 64 | − | |
| 65 | −For PPP, the PPPoL2TP driver, net/l2tp/l2tp_ppp.c, provides a | |
| 66 | −mechanism by which PPP frames carried through an L2TP session are | |
| 67 | −passed through the kernel's PPP subsystem. The standard PPP daemon, | |
| 68 | −pppd, handles all PPP interaction with the peer. PPP network | |
| 69 | −interfaces are created for each local PPP endpoint. The kernel's PPP | |
| 70 | −subsystem arranges for PPP control frames to be delivered to pppd, | |
| 71 | −while data frames are forwarded as usual. | |
| 72 | − | |
| 73 | −For ethernet, the L2TPETH driver, net/l2tp/l2tp_eth.c, implements a | |
| 74 | −netdevice driver, managing virtual ethernet devices, one per | |
| 75 | −pseudowire. These interfaces can be managed using standard Linux tools | |
| 76 | −such as "ip" and "ifconfig". If only IP frames are passed over the | |
| 77 | −tunnel, the interface can be given an IP addresses of itself and its | |
| 78 | −peer. If non-IP frames are to be passed over the tunnel, the interface | |
| 79 | −can be added to a bridge using brctl. All L2TP datapath protocol | |
| 80 | −functions are handled by the L2TP core driver. | |
| 81 | − | |
| 82 | −Each tunnel and session within a tunnel is assigned a unique tunnel_id | |
| 83 | −and session_id. These ids are carried in the L2TP header of every | |
| 84 | −control and data packet. (Actually, in L2TPv3, the tunnel_id isn't | |
| 85 | −present in data frames - it is inferred from the IP connection on | |
| 86 | −which the packet was received.) The L2TP driver uses the ids to lookup | |
| 87 | −internal tunnel and/or session contexts to determine how to handle the | |
| 88 | −packet. Zero tunnel / session ids are treated specially - zero ids are | |
| 89 | −never assigned to tunnels or sessions in the network. In the driver, | |
| 90 | −the tunnel context keeps a reference to the tunnel UDP or L2TPIP | |
| 91 | −socket. The session context holds data that lets the driver interface | |
| 92 | −to the kernel's network frame type subsystems, i.e. PPP, ethernet. | |
| 93 | − | |
| 94 | −Userspace Programming | |
| 95 | −===================== | |
| 96 | − | |
| 97 | −For L2TPv2, there are a number of requirements on the userspace L2TP | |
| 98 | −daemon in order to use the pppol2tp driver. | |
| 99 | − | |
| 100 | −1. Use a UDP socket per tunnel. | |
| 101 | − | |
| 102 | −2. Create a single PPPoL2TP socket per tunnel bound to a special null | |
| 103 | − session id. This is used only for communicating with the driver but | |
| 104 | − must remain open while the tunnel is active. Opening this tunnel | |
| 105 | − management socket causes the driver to mark the tunnel socket as an | |
| 106 | − L2TP UDP encapsulation socket and flags it for use by the | |
| 107 | − referenced tunnel id. This hooks up the UDP receive path via | |
| 108 | − udp_encap_rcv() in net/ipv4/udp.c. PPP data frames are never passed | |
| 109 | − in this special PPPoX socket. | |
| 110 | − | |
| 111 | −3. Create a PPPoL2TP socket per L2TP session. This is typically done | |
| 112 | − by starting pppd with the pppol2tp plugin and appropriate | |
| 113 | − arguments. A PPPoL2TP tunnel management socket (Step 2) must be | |
| 114 | − created before the first PPPoL2TP session socket is created. | |
| 18 | +The kernel's L2TP subsystem implements the datapath for L2TPv2 and | |
| 19 | +L2TPv3. L2TPv2 is carried over UDP. L2TPv3 is carried over UDP or | |
| 20 | +directly over IP (protocol 115). | |
| 21 | + | |
| 22 | +The L2TP RFCs define two basic kinds of L2TP packets: control packets | |
| 23 | +(the "control plane"), and data packets (the "data plane"). The kernel | |
| 24 | +deals only with data packets. The more complex control packets are | |
| 25 | +handled by user space. | |
| 26 | + | |
| 27 | +An L2TP tunnel carries one or more L2TP sessions. Each tunnel is | |
| 28 | +associated with a socket. Each session is associated with a virtual | |
| 29 | +netdevice, e.g. ``pppN``, ``l2tpethN``, through which data frames pass | |
| 30 | +to/from L2TP. Fields in the L2TP header identify the tunnel or session | |
| 31 | +and whether it is a control or data packet. When tunnels and sessions | |
| 32 | +are set up using the Linux kernel API, we're just setting up the L2TP | |
| 33 | +data path. All aspects of the control protocol are to be handled by | |
| 34 | +user space. | |
| 35 | + | |
| 36 | +This split in responsibilities leads to a natural sequence of | |
| 37 | +operations when establishing tunnels and sessions. The procedure looks | |
| 38 | +like this: | |
| 39 | + | |
| 40 | + 1) Create a tunnel socket. Exchange L2TP control protocol messages | |
| 41 | + with the peer over that socket in order to establish a tunnel. | |
| 42 | + | |
| 43 | + 2) Create a tunnel context in the kernel, using information | |
| 44 | + obtained from the peer using the control protocol messages. | |
| 45 | + | |
| 46 | + 3) Exchange L2TP control protocol messages with the peer over the | |
| 47 | + tunnel socket in order to establish a session. | |
| 48 | + | |
| 49 | + 4) Create a session context in the kernel using information | |
| 50 | + obtained from the peer using the control protocol messages. | |
| 51 | + | |
| 52 | +L2TP APIs | |
| 53 | +========= | |
| 54 | + | |
| 55 | +This section documents each userspace API of the L2TP subsystem. | |
| 56 | + | |
| 57 | +Tunnel Sockets | |
| 58 | +-------------- | |
| 59 | + | |
| 60 | +L2TPv2 always uses UDP. L2TPv3 may use UDP or IP encapsulation. | |
| 61 | + | |
| 62 | +To create a tunnel socket for use by L2TP, the standard POSIX | |
| 63 | +socket API is used. | |
| 64 | + | |
| 65 | +For example, for a tunnel using IPv4 addresses and UDP encapsulation:: | |
| 66 | + | |
| 67 | + int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
| 68 | + | |
| 69 | +Or for a tunnel using IPv6 addresses and IP encapsulation:: | |
| 70 | + | |
| 71 | + int sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_L2TP); | |
| 72 | + | |
| 73 | +UDP socket programming doesn't need to be covered here. | |
| 74 | + | |
| 75 | +IPPROTO_L2TP is an IP protocol type implemented by the kernel's L2TP | |
| 76 | +subsystem. The L2TPIP socket address is defined in struct | |
| 77 | +sockaddr_l2tpip and struct sockaddr_l2tpip6 at | |
| 78 | +`include/uapi/linux/l2tp.h`_. The address includes the L2TP tunnel | |
| 79 | +(connection) id. To use L2TP IP encapsulation, an L2TPv3 application | |
| 80 | +should bind the L2TPIP socket using the locally assigned | |
| 81 | +tunnel id. When the peer's tunnel id and IP address is known, a | |
| 82 | +connect must be done. | |
| 83 | + | |
| 84 | +If the L2TP application needs to handle L2TPv3 tunnel setup requests | |
| 85 | +from peers using L2TPIP, it must open a dedicated L2TPIP | |
| 86 | +socket to listen for those requests and bind the socket using tunnel | |
| 87 | +id 0 since tunnel setup requests are addressed to tunnel id 0. | |
| 88 | + | |
| 89 | +An L2TP tunnel and all of its sessions are automatically closed when | |
| 90 | +its tunnel socket is closed. | |
| 91 | + | |
| 92 | +Netlink API | |
| 93 | +----------- | |
| 94 | + | |
| 95 | +L2TP applications use netlink to manage L2TP tunnel and session | |
| 96 | +instances in the kernel. The L2TP netlink API is defined in | |
| 97 | +`include/uapi/linux/l2tp.h`_. | |
| 98 | + | |
| 99 | +L2TP uses `Generic Netlink`_ (GENL). Several commands are defined: | |
| 100 | +Create, Delete, Modify and Get for tunnel and session | |
| 101 | +instances, e.g. ``L2TP_CMD_TUNNEL_CREATE``. The API header lists the | |
| 102 | +netlink attribute types that can be used with each command. | |
| 103 | + | |
| 104 | +Tunnel and session instances are identified by a locally unique | |
| 105 | +32-bit id. L2TP tunnel ids are given by ``L2TP_ATTR_CONN_ID`` and | |
| 106 | +``L2TP_ATTR_PEER_CONN_ID`` attributes and L2TP session ids are given | |
| 107 | +by ``L2TP_ATTR_SESSION_ID`` and ``L2TP_ATTR_PEER_SESSION_ID`` | |
| 108 | +attributes. If netlink is used to manage L2TPv2 tunnel and session | |
| 109 | +instances, the L2TPv2 16-bit tunnel/session id is cast to a 32-bit | |
| 110 | +value in these attributes. | |
| 111 | + | |
| 112 | +In the ``L2TP_CMD_TUNNEL_CREATE`` command, ``L2TP_ATTR_FD`` tells the | |
| 113 | +kernel the tunnel socket fd being used. If not specified, the kernel | |
| 114 | +creates a kernel socket for the tunnel, using IP parameters set in | |
| 115 | +``L2TP_ATTR_IP[6]_SADDR``, ``L2TP_ATTR_IP[6]_DADDR``, | |
| 116 | +``L2TP_ATTR_UDP_SPORT``, ``L2TP_ATTR_UDP_DPORT`` attributes. Kernel | |
| 117 | +sockets are used to implement unmanaged L2TPv3 tunnels (iproute2's "ip | |
| 118 | +l2tp" commands). If ``L2TP_ATTR_FD`` is given, it must be a socket fd | |
| 119 | +that is already bound and connected. There is more information about | |
| 120 | +unmanaged tunnels later in this document. | |
| 121 | + | |
| 122 | +``L2TP_CMD_TUNNEL_CREATE`` attributes:- | |
| 123 | + | |
| 124 | +================== ======== === | |
| 125 | +Attribute Required Use | |
| 126 | +================== ======== === | |
| 127 | +CONN_ID Y Sets the tunnel (connection) id. | |
| 128 | +PEER_CONN_ID Y Sets the peer tunnel (connection) id. | |
| 129 | +PROTO_VERSION Y Protocol version. 2 or 3. | |
| 130 | +ENCAP_TYPE Y Encapsulation type: UDP or IP. | |
| 131 | +FD N Tunnel socket file descriptor. | |
| 132 | +UDP_CSUM N Enable IPv4 UDP checksums. Used only if FD is | |
| 133 | + not set. | |
| 134 | +UDP_ZERO_CSUM6_TX N Zero IPv6 UDP checksum on transmit. Used only | |
| 135 | + if FD is not set. | |
| 136 | +UDP_ZERO_CSUM6_RX N Zero IPv6 UDP checksum on receive. Used only if | |
| 137 | + FD is not set. | |
| 138 | +IP_SADDR N IPv4 source address. Used only if FD is not | |
| 139 | + set. | |
| 140 | +IP_DADDR N IPv4 destination address. Used only if FD is | |
| 141 | + not set. | |
| 142 | +UDP_SPORT N UDP source port. Used only if FD is not set. | |
| 143 | +UDP_DPORT N UDP destination port. Used only if FD is not | |
| 144 | + set. | |
| 145 | +IP6_SADDR N IPv6 source address. Used only if FD is not | |
| 146 | + set. | |
| 147 | +IP6_DADDR N IPv6 destination address. Used only if FD is | |
| 148 | + not set. | |
| 149 | +DEBUG N Debug flags. | |
| 150 | +================== ======== === | |
| 151 | + | |
| 152 | +``L2TP_CMD_TUNNEL_DESTROY`` attributes:- | |
| 153 | + | |
| 154 | +================== ======== === | |
| 155 | +Attribute Required Use | |
| 156 | +================== ======== === | |
| 157 | +CONN_ID Y Identifies the tunnel id to be destroyed. | |
| 158 | +================== ======== === | |
| 159 | + | |
| 160 | +``L2TP_CMD_TUNNEL_MODIFY`` attributes:- | |
| 161 | + | |
| 162 | +================== ======== === | |
| 163 | +Attribute Required Use | |
| 164 | +================== ======== === | |
| 165 | +CONN_ID Y Identifies the tunnel id to be modified. | |
| 166 | +DEBUG N Debug flags. | |
| 167 | +================== ======== === | |
| 168 | + | |
| 169 | +``L2TP_CMD_TUNNEL_GET`` attributes:- | |
| 170 | + | |
| 171 | +================== ======== === | |
| 172 | +Attribute Required Use | |
| 173 | +================== ======== === | |
| 174 | +CONN_ID N Identifies the tunnel id to be queried. | |
| 175 | + Ignored in DUMP requests. | |
| 176 | +================== ======== === | |
| 177 | + | |
| 178 | +``L2TP_CMD_SESSION_CREATE`` attributes:- | |
| 179 | + | |
| 180 | +================== ======== === | |
| 181 | +Attribute Required Use | |
| 182 | +================== ======== === | |
| 183 | +CONN_ID Y The parent tunnel id. | |
| 184 | +SESSION_ID Y Sets the session id. | |
| 185 | +PEER_SESSION_ID Y Sets the parent session id. | |
| 186 | +PW_TYPE Y Sets the pseudowire type. | |
| 187 | +DEBUG N Debug flags. | |
| 188 | +RECV_SEQ N Enable rx data sequence numbers. | |
| 189 | +SEND_SEQ N Enable tx data sequence numbers. | |
| 190 | +LNS_MODE N Enable LNS mode (auto-enable data sequence | |
| 191 | + numbers). | |
| 192 | +RECV_TIMEOUT N Timeout to wait when reordering received | |
| 193 | + packets. | |
| 194 | +L2SPEC_TYPE N Sets layer2-specific-sublayer type (L2TPv3 | |
| 195 | + only). | |
| 196 | +COOKIE N Sets optional cookie (L2TPv3 only). | |
| 197 | +PEER_COOKIE N Sets optional peer cookie (L2TPv3 only). | |
| 198 | +IFNAME N Sets interface name (L2TPv3 only). | |
| 199 | +================== ======== === | |
| 200 | + | |
| 201 | +For Ethernet session types, this will create an l2tpeth virtual | |
| 202 | +interface which can then be configured as required. For PPP session | |
| 203 | +types, a PPPoL2TP socket must also be opened and connected, mapping it | |
| 204 | +onto the new session. This is covered in "PPPoL2TP Sockets" later. | |
| 205 | + | |
| 206 | +``L2TP_CMD_SESSION_DESTROY`` attributes:- | |
| 207 | + | |
| 208 | +================== ======== === | |
| 209 | +Attribute Required Use | |
| 210 | +================== ======== === | |
| 211 | +CONN_ID Y Identifies the parent tunnel id of the session | |
| 212 | + to be destroyed. | |
| 213 | +SESSION_ID Y Identifies the session id to be destroyed. | |
| 214 | +IFNAME N Identifies the session by interface name. If | |
| 215 | + set, this overrides any CONN_ID and SESSION_ID | |
| 216 | + attributes. Currently supported for L2TPv3 | |
| 217 | + Ethernet sessions only. | |
| 218 | +================== ======== === | |
| 219 | + | |
| 220 | +``L2TP_CMD_SESSION_MODIFY`` attributes:- | |
| 221 | + | |
| 222 | +================== ======== === | |
| 223 | +Attribute Required Use | |
| 224 | +================== ======== === | |
| 225 | +CONN_ID Y Identifies the parent tunnel id of the session | |
| 226 | + to be modified. | |
| 227 | +SESSION_ID Y Identifies the session id to be modified. | |
| 228 | +IFNAME N Identifies the session by interface name. If | |
| 229 | + set, this overrides any CONN_ID and SESSION_ID | |
| 230 | + attributes. Currently supported for L2TPv3 | |
| 231 | + Ethernet sessions only. | |
| 232 | +DEBUG N Debug flags. | |
| 233 | +RECV_SEQ N Enable rx data sequence numbers. | |
| 234 | +SEND_SEQ N Enable tx data sequence numbers. | |
| 235 | +LNS_MODE N Enable LNS mode (auto-enable data sequence | |
| 236 | + numbers). | |
| 237 | +RECV_TIMEOUT N Timeout to wait when reordering received | |
| 238 | + packets. | |
| 239 | +================== ======== === | |
| 240 | + | |
| 241 | +``L2TP_CMD_SESSION_GET`` attributes:- | |
| 242 | + | |
| 243 | +================== ======== === | |
| 244 | +Attribute Required Use | |
| 245 | +================== ======== === | |
| 246 | +CONN_ID N Identifies the tunnel id to be queried. | |
| 247 | + Ignored for DUMP requests. | |
| 248 | +SESSION_ID N Identifies the session id to be queried. | |
| 249 | + Ignored for DUMP requests. | |
| 250 | +IFNAME N Identifies the session by interface name. | |
| 251 | + If set, this overrides any CONN_ID and | |
| 252 | + SESSION_ID attributes. Ignored for DUMP | |
| 253 | + requests. Currently supported for L2TPv3 | |
| 254 | + Ethernet sessions only. | |
| 255 | +================== ======== === | |
| 256 | + | |
| 257 | +Application developers should refer to `include/uapi/linux/l2tp.h`_ for | |
| 258 | +netlink command and attribute definitions. | |
| 259 | + | |
| 260 | +Sample userspace code using libmnl_: | |
| 261 | + | |
| 262 | + - Open L2TP netlink socket:: | |
| 263 | + | |
| 264 | + struct nl_sock *nl_sock; | |
| 265 | + int l2tp_nl_family_id; | |
| 266 | + | |
| 267 | + nl_sock = nl_socket_alloc(); | |
| 268 | + genl_connect(nl_sock); | |
| 269 | + genl_id = genl_ctrl_resolve(nl_sock, L2TP_GENL_NAME); | |
| 270 | + | |
| 271 | + - Create a tunnel:: | |
| 272 | + | |
| 273 | + struct nlmsghdr *nlh; | |
| 274 | + struct genlmsghdr *gnlh; | |
| 275 | + | |
| 276 | + nlh = mnl_nlmsg_put_header(buf); | |
| 277 | + nlh->nlmsg_type = genl_id; /* assigned to genl socket */ | |
| 278 | + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
| 279 | + nlh->nlmsg_seq = seq; | |
| 280 | + | |
| 281 | + gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh)); | |
| 282 | + gnlh->cmd = L2TP_CMD_TUNNEL_CREATE; | |
| 283 | + gnlh->version = L2TP_GENL_VERSION; | |
| 284 | + gnlh->reserved = 0; | |
| 285 | + | |
| 286 | + mnl_attr_put_u32(nlh, L2TP_ATTR_FD, tunl_sock_fd); | |
| 287 | + mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid); | |
| 288 | + mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_CONN_ID, peer_tid); | |
| 289 | + mnl_attr_put_u8(nlh, L2TP_ATTR_PROTO_VERSION, protocol_version); | |
| 290 | + mnl_attr_put_u16(nlh, L2TP_ATTR_ENCAP_TYPE, encap); | |
| 291 | + | |
| 292 | + - Create a session:: | |
| 293 | + | |
| 294 | + struct nlmsghdr *nlh; | |
| 295 | + struct genlmsghdr *gnlh; | |
| 296 | + | |
| 297 | + nlh = mnl_nlmsg_put_header(buf); | |
| 298 | + nlh->nlmsg_type = genl_id; /* assigned to genl socket */ | |
| 299 | + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
| 300 | + nlh->nlmsg_seq = seq; | |
| 301 | + | |
| 302 | + gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh)); | |
| 303 | + gnlh->cmd = L2TP_CMD_SESSION_CREATE; | |
| 304 | + gnlh->version = L2TP_GENL_VERSION; | |
| 305 | + gnlh->reserved = 0; | |
| 306 | + | |
| 307 | + mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid); | |
| 308 | + mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_CONN_ID, peer_tid); | |
| 309 | + mnl_attr_put_u32(nlh, L2TP_ATTR_SESSION_ID, sid); | |
| 310 | + mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_SESSION_ID, peer_sid); | |
| 311 | + mnl_attr_put_u16(nlh, L2TP_ATTR_PW_TYPE, pwtype); | |
| 312 | + /* there are other session options which can be set using netlink | |
| 313 | + * attributes during session creation -- see l2tp.h | |
| 314 | + */ | |
| 315 | + | |
| 316 | + - Delete a session:: | |
| 317 | + | |
| 318 | + struct nlmsghdr *nlh; | |
| 319 | + struct genlmsghdr *gnlh; | |
| 320 | + | |
| 321 | + nlh = mnl_nlmsg_put_header(buf); | |
| 322 | + nlh->nlmsg_type = genl_id; /* assigned to genl socket */ | |
| 323 | + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
| 324 | + nlh->nlmsg_seq = seq; | |
| 325 | + | |
| 326 | + gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh)); | |
| 327 | + gnlh->cmd = L2TP_CMD_SESSION_DELETE; | |
| 328 | + gnlh->version = L2TP_GENL_VERSION; | |
| 329 | + gnlh->reserved = 0; | |
| 330 | + | |
| 331 | + mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid); | |
| 332 | + mnl_attr_put_u32(nlh, L2TP_ATTR_SESSION_ID, sid); | |
| 333 | + | |
| 334 | + - Delete a tunnel and all of its sessions (if any):: | |
| 335 | + | |
| 336 | + struct nlmsghdr *nlh; | |
| 337 | + struct genlmsghdr *gnlh; | |
| 338 | + | |
| 339 | + nlh = mnl_nlmsg_put_header(buf); | |
| 340 | + nlh->nlmsg_type = genl_id; /* assigned to genl socket */ | |
| 341 | + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
| 342 | + nlh->nlmsg_seq = seq; | |
| 343 | + | |
| 344 | + gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh)); | |
| 345 | + gnlh->cmd = L2TP_CMD_TUNNEL_DELETE; | |
| 346 | + gnlh->version = L2TP_GENL_VERSION; | |
| 347 | + gnlh->reserved = 0; | |
| 348 | + | |
| 349 | + mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid); | |
| 350 | + | |
| 351 | +PPPoL2TP Session Socket API | |
| 352 | +--------------------------- | |
| 353 | + | |
| 354 | +For PPP session types, a PPPoL2TP socket must be opened and connected | |
| 355 | +to the L2TP session. | |
| 115 | 356 | |
| 116 | 357 | When creating PPPoL2TP sockets, the application provides information |
| 117 | −to the driver about the socket in a socket connect() call. Source and | |
| 118 | −destination tunnel and session ids are provided, as well as the file | |
| 119 | −descriptor of a UDP socket. See struct pppol2tp_addr in | |
| 120 | −include/linux/if_pppol2tp.h. Note that zero tunnel / session ids are | |
| 121 | −treated specially. When creating the per-tunnel PPPoL2TP management | |
| 122 | −socket in Step 2 above, zero source and destination session ids are | |
| 123 | −specified, which tells the driver to prepare the supplied UDP file | |
| 124 | −descriptor for use as an L2TP tunnel socket. | |
| 358 | +to the kernel about the tunnel and session in a socket connect() | |
| 359 | +call. Source and destination tunnel and session ids are provided, as | |
| 360 | +well as the file descriptor of a UDP or L2TPIP socket. See struct | |
| 361 | +pppol2tp_addr in `include/linux/if_pppol2tp.h`_. For historical reasons, | |
| 362 | +there are unfortunately slightly different address structures for | |
| 363 | +L2TPv2/L2TPv3 IPv4/IPv6 tunnels and userspace must use the appropriate | |
| 364 | +structure that matches the tunnel socket type. | |
| 125 | 365 | |
| 126 | 366 | Userspace may control behavior of the tunnel or session using |
| 127 | 367 | setsockopt and ioctl on the PPPoX socket. The following socket |
| @@ -130,229 +370,308 @@ options are supported:- · 2 unmodified lines | ||
| 130 | 370 | ========= =========================================================== |
| 131 | 371 | DEBUG bitmask of debug message categories. See below. |
| 132 | 372 | SENDSEQ - 0 => don't send packets with sequence numbers |
| 133 | − - 1 => send packets with sequence numbers | |
| 373 | + - 1 => send packets with sequence numbers | |
| 134 | 374 | RECVSEQ - 0 => receive packet sequence numbers are optional |
| 135 | − - 1 => drop receive packets without sequence numbers | |
| 375 | + - 1 => drop receive packets without sequence numbers | |
| 136 | 376 | LNSMODE - 0 => act as LAC. |
| 137 | − - 1 => act as LNS. | |
| 377 | + - 1 => act as LNS. | |
| 138 | 378 | REORDERTO reorder timeout (in millisecs). If 0, don't try to reorder. |
| 139 | 379 | ========= =========================================================== |
| 140 | 380 | |
| 141 | −Only the DEBUG option is supported by the special tunnel management | |
| 142 | −PPPoX socket. | |
| 143 | − | |
| 144 | 381 | In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided |
| 145 | 382 | to retrieve tunnel and session statistics from the kernel using the |
| 146 | 383 | PPPoX socket of the appropriate tunnel or session. |
| 147 | 384 | |
| 148 | −For L2TPv3, userspace must use the netlink API defined in | |
| 149 | −include/linux/l2tp.h to manage tunnel and session contexts. The | |
| 150 | −general procedure to create a new L2TP tunnel with one session is:- | |
| 151 | − | |
| 152 | −1. Open a GENL socket using L2TP_GENL_NAME for configuring the kernel | |
| 153 | − using netlink. | |
| 154 | − | |
| 155 | −2. Create a UDP or L2TPIP socket for the tunnel. | |
| 156 | − | |
| 157 | −3. Create a new L2TP tunnel using a L2TP_CMD_TUNNEL_CREATE | |
| 158 | − request. Set attributes according to desired tunnel parameters, | |
| 159 | − referencing the UDP or L2TPIP socket created in the previous step. | |
| 160 | − | |
| 161 | −4. Create a new L2TP session in the tunnel using a | |
| 162 | − L2TP_CMD_SESSION_CREATE request. | |
| 163 | − | |
| 164 | −The tunnel and all of its sessions are closed when the tunnel socket | |
| 165 | −is closed. The netlink API may also be used to delete sessions and | |
| 166 | −tunnels. Configuration and status info may be set or read using netlink. | |
| 167 | − | |
| 168 | −The L2TP driver also supports static (unmanaged) L2TPv3 tunnels. These | |
| 169 | −are where there is no L2TP control message exchange with the peer to | |
| 170 | −setup the tunnel; the tunnel is configured manually at each end of the | |
| 171 | −tunnel. There is no need for an L2TP userspace application in this | |
| 172 | −case -- the tunnel socket is created by the kernel and configured | |
| 173 | −using parameters sent in the L2TP_CMD_TUNNEL_CREATE netlink | |
| 174 | −request. The "ip" utility of iproute2 has commands for managing static | |
| 175 | −L2TPv3 tunnels; do "ip l2tp help" for more information. | |
| 385 | +Sample userspace code: | |
| 386 | + | |
| 387 | + - Create session PPPoX data socket:: | |
| 388 | + | |
| 389 | + struct sockaddr_pppol2tp sax; | |
| 390 | + int fd; | |
| 391 | + | |
| 392 | + /* Note, the tunnel socket must be bound already, else it | |
| 393 | + * will not be ready | |
| 394 | + */ | |
| 395 | + sax.sa_family = AF_PPPOX; | |
| 396 | + sax.sa_protocol = PX_PROTO_OL2TP; | |
| 397 | + sax.pppol2tp.fd = tunnel_fd; | |
| 398 | + sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr; | |
| 399 | + sax.pppol2tp.addr.sin_port = addr->sin_port; | |
| 400 | + sax.pppol2tp.addr.sin_family = AF_INET; | |
| 401 | + sax.pppol2tp.s_tunnel = tunnel_id; | |
| 402 | + sax.pppol2tp.s_session = session_id; | |
| 403 | + sax.pppol2tp.d_tunnel = peer_tunnel_id; | |
| 404 | + sax.pppol2tp.d_session = peer_session_id; | |
| 405 | + | |
| 406 | + /* session_fd is the fd of the session's PPPoL2TP socket. | |
| 407 | + * tunnel_fd is the fd of the tunnel UDP / L2TPIP socket. | |
| 408 | + */ | |
| 409 | + fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax)); | |
| 410 | + if (fd < 0 ) { | |
| 411 | + return -errno; | |
| 412 | + } | |
| 413 | + return 0; | |
| 414 | + | |
| 415 | +Old L2TPv2-only API | |
| 416 | +------------------- | |
| 417 | + | |
| 418 | +When L2TP was first added to the Linux kernel in 2.6.23, it | |
| 419 | +implemented only L2TPv2 and did not include a netlink API. Instead, | |
| 420 | +tunnel and session instances in the kernel were managed directly using | |
| 421 | +only PPPoL2TP sockets. The PPPoL2TP socket is used as described in | |
| 422 | +section "PPPoL2TP Session Socket API" but tunnel and session instances | |
| 423 | +are automatically created on a connect() of the socket instead of | |
| 424 | +being created by a separate netlink request: | |
| 425 | + | |
| 426 | + - Tunnels are managed using a tunnel management socket which is a | |
| 427 | + dedicated PPPoL2TP socket, connected to (invalid) session | |
| 428 | + id 0. The L2TP tunnel instance is created when the PPPoL2TP | |
| 429 | + tunnel management socket is connected and is destroyed when the | |
| 430 | + socket is closed. | |
| 431 | + | |
| 432 | + - Session instances are created in the kernel when a PPPoL2TP | |
| 433 | + socket is connected to a non-zero session id. Session parameters | |
| 434 | + are set using setsockopt. The L2TP session instance is destroyed | |
| 435 | + when the socket is closed. | |
| 436 | + | |
| 437 | +This API is still supported but its use is discouraged. Instead, new | |
| 438 | +L2TPv2 applications should use netlink to first create the tunnel and | |
| 439 | +session, then create a PPPoL2TP socket for the session. | |
| 440 | + | |
| 441 | +Unmanaged L2TPv3 tunnels | |
| 442 | +------------------------ | |
| 443 | + | |
| 444 | +The kernel L2TP subsystem also supports static (unmanaged) L2TPv3 | |
| 445 | +tunnels. Unmanaged tunnels have no userspace tunnel socket, and | |
| 446 | +exchange no control messages with the peer to set up the tunnel; the | |
| 447 | +tunnel is configured manually at each end of the tunnel. All | |
| 448 | +configuration is done using netlink. There is no need for an L2TP | |
| 449 | +userspace application in this case -- the tunnel socket is created by | |
| 450 | +the kernel and configured using parameters sent in the | |
| 451 | +``L2TP_CMD_TUNNEL_CREATE`` netlink request. The ``ip`` utility of | |
| 452 | +``iproute2`` has commands for managing static L2TPv3 tunnels; do ``ip | |
| 453 | +l2tp help`` for more information. | |
| 176 | 454 | |
| 177 | 455 | Debugging |
| 178 | −========= | |
| 179 | − | |
| 180 | −The driver supports a flexible debug scheme where kernel trace | |
| 181 | −messages may be optionally enabled per tunnel and per session. Care is | |
| 182 | −needed when debugging a live system since the messages are not | |
| 183 | −rate-limited and a busy system could be swamped. Userspace uses | |
| 184 | −setsockopt on the PPPoX socket to set a debug mask. | |
| 456 | +--------- | |
| 185 | 457 | |
| 186 | −The following debug mask bits are available: | |
| 458 | +The L2TP subsystem offers a range of debugging interfaces through the | |
| 459 | +debugfs filesystem. | |
| 187 | 460 | |
| 188 | −================ ============================== | |
| 189 | −L2TP_MSG_DEBUG verbose debug (if compiled in) | |
| 190 | −L2TP_MSG_CONTROL userspace - kernel interface | |
| 191 | −L2TP_MSG_SEQ sequence numbers handling | |
| 192 | −L2TP_MSG_DATA data packets | |
| 193 | −================ ============================== | |
| 461 | +To access these interfaces, the debugfs filesystem must first be mounted:: | |
| 194 | 462 | |
| 195 | −If enabled, files under a l2tp debugfs directory can be used to dump | |
| 196 | −kernel state about L2TP tunnels and sessions. To access it, the | |
| 197 | −debugfs filesystem must first be mounted:: | |
| 463 | + # mount -t debugfs debugfs /debug | |
| 198 | 464 | |
| 199 | − # mount -t debugfs debugfs /debug | |
| 465 | +Files under the l2tp directory can then be accessed, providing a summary | |
| 466 | +of the current population of tunnel and session contexts existing in the | |
| 467 | +kernel:: | |
| 200 | 468 | |
| 201 | −Files under the l2tp directory can then be accessed:: | |
| 202 | − | |
| 203 | − # cat /debug/l2tp/tunnels | |
| 469 | + # cat /debug/l2tp/tunnels | |
| 204 | 470 | |
| 205 | 471 | The debugfs files should not be used by applications to obtain L2TP |
| 206 | 472 | state information because the file format is subject to change. It is |
| 207 | 473 | implemented to provide extra debug information to help diagnose |
| 208 | −problems.) Users should use the netlink API. | |
| 474 | +problems. Applications should instead use the netlink API. | |
| 209 | 475 | |
| 210 | −/proc/net/pppol2tp is also provided for backwards compatibility with | |
| 211 | −the original pppol2tp driver. It lists information about L2TPv2 | |
| 212 | −tunnels and sessions only. Its use is discouraged. | |
| 476 | +In addition the L2TP subsystem implements tracepoints using the standard | |
| 477 | +kernel event tracing API. The available L2TP events can be reviewed as | |
| 478 | +follows:: | |
| 213 | 479 | |
| 214 | −Unmanaged L2TPv3 Tunnels | |
| 215 | −======================== | |
| 216 | − | |
| 217 | −Some commercial L2TP products support unmanaged L2TPv3 ethernet | |
| 218 | −tunnels, where there is no L2TP control protocol; tunnels are | |
| 219 | −configured at each side manually. New commands are available in | |
| 220 | −iproute2's ip utility to support this. | |
| 221 | − | |
| 222 | −To create an L2TPv3 ethernet pseudowire between local host 192.168.1.1 | |
| 223 | −and peer 192.168.1.2, using IP addresses 10.5.1.1 and 10.5.1.2 for the | |
| 224 | −tunnel endpoints:: | |
| 225 | − | |
| 226 | − # ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 udp_sport 5000 \ | |
| 227 | − udp_dport 5000 encap udp local 192.168.1.1 remote 192.168.1.2 | |
| 228 | − # ip l2tp add session tunnel_id 1 session_id 1 peer_session_id 1 | |
| 229 | − # ip -s -d show dev l2tpeth0 | |
| 230 | − # ip addr add 10.5.1.2/32 peer 10.5.1.1/32 dev l2tpeth0 | |
| 231 | − # ip li set dev l2tpeth0 up | |
| 232 | − | |
| 233 | −Choose IP addresses to be the address of a local IP interface and that | |
| 234 | −of the remote system. The IP addresses of the l2tpeth0 interface can be | |
| 235 | −anything suitable. | |
| 236 | − | |
| 237 | −Repeat the above at the peer, with ports, tunnel/session ids and IP | |
| 238 | −addresses reversed. The tunnel and session IDs can be any non-zero | |
| 239 | −32-bit number, but the values must be reversed at the peer. | |
| 240 | − | |
| 241 | −======================== =================== | |
| 242 | −Host 1 Host2 | |
| 243 | −======================== =================== | |
| 244 | −udp_sport=5000 udp_sport=5001 | |
| 245 | −udp_dport=5001 udp_dport=5000 | |
| 246 | −tunnel_id=42 tunnel_id=45 | |
| 247 | −peer_tunnel_id=45 peer_tunnel_id=42 | |
| 248 | −session_id=128 session_id=5196755 | |
| 249 | −peer_session_id=5196755 peer_session_id=128 | |
| 250 | −======================== =================== | |
| 251 | − | |
| 252 | −When done at both ends of the tunnel, it should be possible to send | |
| 253 | −data over the network. e.g.:: | |
| 254 | − | |
| 255 | − # ping 10.5.1.1 | |
| 256 | − | |
| 257 | − | |
| 258 | −Sample Userspace Code | |
| 259 | −===================== | |
| 260 | − | |
| 261 | −1. Create tunnel management PPPoX socket:: | |
| 262 | − | |
| 263 | − kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); | |
| 264 | − if (kernel_fd >= 0) { | |
| 265 | − struct sockaddr_pppol2tp sax; | |
| 266 | − struct sockaddr_in const *peer_addr; | |
| 267 | − | |
| 268 | − peer_addr = l2tp_tunnel_get_peer_addr(tunnel); | |
| 269 | − memset(&sax, 0, sizeof(sax)); | |
| 270 | − sax.sa_family = AF_PPPOX; | |
| 271 | − sax.sa_protocol = PX_PROTO_OL2TP; | |
| 272 | − sax.pppol2tp.fd = udp_fd; /* fd of tunnel UDP socket */ | |
| 273 | − sax.pppol2tp.addr.sin_addr.s_addr = peer_addr->sin_addr.s_addr; | |
| 274 | − sax.pppol2tp.addr.sin_port = peer_addr->sin_port; | |
| 275 | − sax.pppol2tp.addr.sin_family = AF_INET; | |
| 276 | − sax.pppol2tp.s_tunnel = tunnel_id; | |
| 277 | − sax.pppol2tp.s_session = 0; /* special case: mgmt socket */ | |
| 278 | − sax.pppol2tp.d_tunnel = 0; | |
| 279 | − sax.pppol2tp.d_session = 0; /* special case: mgmt socket */ | |
| 280 | − | |
| 281 | − if(connect(kernel_fd, (struct sockaddr *)&sax, sizeof(sax) ) < 0 ) { | |
| 282 | − perror("connect failed"); | |
| 283 | − result = -errno; | |
| 284 | − goto err; | |
| 285 | − } | |
| 286 | − } | |
| 287 | − | |
| 288 | −2. Create session PPPoX data socket:: | |
| 289 | − | |
| 290 | − struct sockaddr_pppol2tp sax; | |
| 291 | − int fd; | |
| 292 | − | |
| 293 | − /* Note, the target socket must be bound already, else it will not be ready */ | |
| 294 | − sax.sa_family = AF_PPPOX; | |
| 295 | − sax.sa_protocol = PX_PROTO_OL2TP; | |
| 296 | − sax.pppol2tp.fd = tunnel_fd; | |
| 297 | − sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr; | |
| 298 | − sax.pppol2tp.addr.sin_port = addr->sin_port; | |
| 299 | − sax.pppol2tp.addr.sin_family = AF_INET; | |
| 300 | − sax.pppol2tp.s_tunnel = tunnel_id; | |
| 301 | − sax.pppol2tp.s_session = session_id; | |
| 302 | − sax.pppol2tp.d_tunnel = peer_tunnel_id; | |
| 303 | − sax.pppol2tp.d_session = peer_session_id; | |
| 304 | − | |
| 305 | − /* session_fd is the fd of the session's PPPoL2TP socket. | |
| 306 | − * tunnel_fd is the fd of the tunnel UDP socket. | |
| 307 | − */ | |
| 308 | − fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax)); | |
| 309 | − if (fd < 0 ) { | |
| 310 | − return -errno; | |
| 311 | − } | |
| 312 | − return 0; | |
| 480 | + # find /debug/tracing/events/l2tp | |
| 481 | + | |
| 482 | +Finally, /proc/net/pppol2tp is also provided for backwards compatibility | |
| 483 | +with the original pppol2tp code. It lists information about L2TPv2 | |
| 484 | +tunnels and sessions only. Its use is discouraged. | |
| 313 | 485 | |
| 314 | 486 | Internal Implementation |
| 315 | 487 | ======================= |
| 316 | 488 | |
| 317 | −The driver keeps a struct l2tp_tunnel context per L2TP tunnel and a | |
| 318 | −struct l2tp_session context for each session. The l2tp_tunnel is | |
| 319 | −always associated with a UDP or L2TP/IP socket and keeps a list of | |
| 320 | −sessions in the tunnel. The l2tp_session context keeps kernel state | |
| 321 | −about the session. It has private data which is used for data specific | |
| 322 | −to the session type. With L2TPv2, the session always carried PPP | |
| 323 | −traffic. With L2TPv3, the session can also carry ethernet frames | |
| 324 | −(ethernet pseudowire) or other data types such as ATM, HDLC or Frame | |
| 325 | −Relay. | |
| 326 | − | |
| 327 | −When a tunnel is first opened, the reference count on the socket is | |
| 328 | −increased using sock_hold(). This ensures that the kernel socket | |
| 329 | −cannot be removed while L2TP's data structures reference it. | |
| 330 | − | |
| 331 | −Some L2TP sessions also have a socket (PPP pseudowires) while others | |
| 332 | −do not (ethernet pseudowires). We can't use the socket reference count | |
| 333 | −as the reference count for session contexts. The L2TP implementation | |
| 334 | −therefore has its own internal reference counts on the session | |
| 335 | −contexts. | |
| 336 | − | |
| 337 | −To Do | |
| 338 | −===== | |
| 339 | − | |
| 340 | −Add L2TP tunnel switching support. This would route tunneled traffic | |
| 341 | −from one L2TP tunnel into another. Specified in | |
| 342 | −http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08 | |
| 343 | − | |
| 344 | −Add L2TPv3 VLAN pseudowire support. | |
| 345 | − | |
| 346 | −Add L2TPv3 IP pseudowire support. | |
| 347 | − | |
| 348 | −Add L2TPv3 ATM pseudowire support. | |
| 489 | +This section is for kernel developers and maintainers. | |
| 490 | + | |
| 491 | +Sockets | |
| 492 | +------- | |
| 493 | + | |
| 494 | +UDP sockets are implemented by the networking core. When an L2TP | |
| 495 | +tunnel is created using a UDP socket, the socket is set up as an | |
| 496 | +encapsulated UDP socket by setting encap_rcv and encap_destroy | |
| 497 | +callbacks on the UDP socket. l2tp_udp_encap_recv is called when | |
| 498 | +packets are received on the socket. l2tp_udp_encap_destroy is called | |
| 499 | +when userspace closes the socket. | |
| 500 | + | |
| 501 | +L2TPIP sockets are implemented in `net/l2tp/l2tp_ip.c`_ and | |
| 502 | +`net/l2tp/l2tp_ip6.c`_. | |
| 503 | + | |
| 504 | +Tunnels | |
| 505 | +------- | |
| 506 | + | |
| 507 | +The kernel keeps a struct l2tp_tunnel context per L2TP tunnel. The | |
| 508 | +l2tp_tunnel is always associated with a UDP or L2TP/IP socket and | |
| 509 | +keeps a list of sessions in the tunnel. When a tunnel is first | |
| 510 | +registered with L2TP core, the reference count on the socket is | |
| 511 | +increased. This ensures that the socket cannot be removed while L2TP's | |
| 512 | +data structures reference it. | |
| 513 | + | |
| 514 | +Tunnels are identified by a unique tunnel id. The id is 16-bit for | |
| 515 | +L2TPv2 and 32-bit for L2TPv3. Internally, the id is stored as a 32-bit | |
| 516 | +value. | |
| 517 | + | |
| 518 | +Tunnels are kept in a per-net list, indexed by tunnel id. The tunnel | |
| 519 | +id namespace is shared by L2TPv2 and L2TPv3. The tunnel context can be | |
| 520 | +derived from the socket's sk_user_data. | |
| 521 | + | |
| 522 | +Handling tunnel socket close is perhaps the most tricky part of the | |
| 523 | +L2TP implementation. If userspace closes a tunnel socket, the L2TP | |
| 524 | +tunnel and all of its sessions must be closed and destroyed. Since the | |
| 525 | +tunnel context holds a ref on the tunnel socket, the socket's | |
| 526 | +sk_destruct won't be called until the tunnel sock_put's its | |
| 527 | +socket. For UDP sockets, when userspace closes the tunnel socket, the | |
| 528 | +socket's encap_destroy handler is invoked, which L2TP uses to initiate | |
| 529 | +its tunnel close actions. For L2TPIP sockets, the socket's close | |
| 530 | +handler initiates the same tunnel close actions. All sessions are | |
| 531 | +first closed. Each session drops its tunnel ref. When the tunnel ref | |
| 532 | +reaches zero, the tunnel puts its socket ref. When the socket is | |
| 533 | +eventually destroyed, it's sk_destruct finally frees the L2TP tunnel | |
| 534 | +context. | |
| 535 | + | |
| 536 | +Sessions | |
| 537 | +-------- | |
| 538 | + | |
| 539 | +The kernel keeps a struct l2tp_session context for each session. Each | |
| 540 | +session has private data which is used for data specific to the | |
| 541 | +session type. With L2TPv2, the session always carries PPP | |
| 542 | +traffic. With L2TPv3, the session can carry Ethernet frames (Ethernet | |
| 543 | +pseudowire) or other data types such as PPP, ATM, HDLC or Frame | |
| 544 | +Relay. Linux currently implements only Ethernet and PPP session types. | |
| 545 | + | |
| 546 | +Some L2TP session types also have a socket (PPP pseudowires) while | |
| 547 | +others do not (Ethernet pseudowires). We can't therefore use the | |
| 548 | +socket reference count as the reference count for session | |
| 549 | +contexts. The L2TP implementation therefore has its own internal | |
| 550 | +reference counts on the session contexts. | |
| 551 | + | |
| 552 | +Like tunnels, L2TP sessions are identified by a unique | |
| 553 | +session id. Just as with tunnel ids, the session id is 16-bit for | |
| 554 | +L2TPv2 and 32-bit for L2TPv3. Internally, the id is stored as a 32-bit | |
| 555 | +value. | |
| 556 | + | |
| 557 | +Sessions hold a ref on their parent tunnel to ensure that the tunnel | |
| 558 | +stays extant while one or more sessions references it. | |
| 559 | + | |
| 560 | +Sessions are kept in a per-tunnel list, indexed by session id. L2TPv3 | |
| 561 | +sessions are also kept in a per-net list indexed by session id, | |
| 562 | +because L2TPv3 session ids are unique across all tunnels and L2TPv3 | |
| 563 | +data packets do not contain a tunnel id in the header. This list is | |
| 564 | +therefore needed to find the session context associated with a | |
| 565 | +received data packet when the tunnel context cannot be derived from | |
| 566 | +the tunnel socket. | |
| 567 | + | |
| 568 | +Although the L2TPv3 RFC specifies that L2TPv3 session ids are not | |
| 569 | +scoped by the tunnel, the kernel does not police this for L2TPv3 UDP | |
| 570 | +tunnels and does not add sessions of L2TPv3 UDP tunnels into the | |
| 571 | +per-net session list. In the UDP receive code, we must trust that the | |
| 572 | +tunnel can be identified using the tunnel socket's sk_user_data and | |
| 573 | +lookup the session in the tunnel's session list instead of the per-net | |
| 574 | +session list. | |
| 575 | + | |
| 576 | +PPP | |
| 577 | +--- | |
| 578 | + | |
| 579 | +`net/l2tp/l2tp_ppp.c`_ implements the PPPoL2TP socket family. Each PPP | |
| 580 | +session has a PPPoL2TP socket. | |
| 581 | + | |
| 582 | +The PPPoL2TP socket's sk_user_data references the l2tp_session. | |
| 583 | + | |
| 584 | +Userspace sends and receives PPP packets over L2TP using a PPPoL2TP | |
| 585 | +socket. Only PPP control frames pass over this socket: PPP data | |
| 586 | +packets are handled entirely by the kernel, passing between the L2TP | |
| 587 | +session and its associated ``pppN`` netdev through the PPP channel | |
| 588 | +interface of the kernel PPP subsystem. | |
| 589 | + | |
| 590 | +The L2TP PPP implementation handles the closing of a PPPoL2TP socket | |
| 591 | +by closing its corresponding L2TP session. This is complicated because | |
| 592 | +it must consider racing with netlink session create/destroy requests | |
| 593 | +and pppol2tp_connect trying to reconnect with a session that is in the | |
| 594 | +process of being closed. Unlike tunnels, PPP sessions do not hold a | |
| 595 | +ref on their associated socket, so code must be careful to sock_hold | |
| 596 | +the socket where necessary. For all the details, see commit | |
| 597 | +3d609342cc04129ff7568e19316ce3d7451a27e8. | |
| 598 | + | |
| 599 | +Ethernet | |
| 600 | +-------- | |
| 601 | + | |
| 602 | +`net/l2tp/l2tp_eth.c`_ implements L2TPv3 Ethernet pseudowires. It | |
| 603 | +manages a netdev for each session. | |
| 604 | + | |
| 605 | +L2TP Ethernet sessions are created and destroyed by netlink request, | |
| 606 | +or are destroyed when the tunnel is destroyed. Unlike PPP sessions, | |
| 607 | +Ethernet sessions do not have an associated socket. | |
| 349 | 608 | |
| 350 | 609 | Miscellaneous |
| 351 | 610 | ============= |
| 352 | 611 | |
| 353 | −The L2TP drivers were developed as part of the OpenL2TP project by | |
| 354 | −Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server, | |
| 355 | −designed from the ground up to have the L2TP datapath in the | |
| 356 | −kernel. The project also implemented the pppol2tp plugin for pppd | |
| 357 | −which allows pppd to use the kernel driver. Details can be found at | |
| 358 | −http://www.openl2tp.org. | |
| 612 | +RFCs | |
| 613 | +---- | |
| 614 | + | |
| 615 | +The kernel code implements the datapath features specified in the | |
| 616 | +following RFCs: | |
| 617 | + | |
| 618 | +======= =============== =================================== | |
| 619 | +RFC2661 L2TPv2 https://tools.ietf.org/html/rfc2661 | |
| 620 | +RFC3931 L2TPv3 https://tools.ietf.org/html/rfc3931 | |
| 621 | +RFC4719 L2TPv3 Ethernet https://tools.ietf.org/html/rfc4719 | |
| 622 | +======= =============== =================================== | |
| 623 | + | |
| 624 | +Implementations | |
| 625 | +--------------- | |
| 626 | + | |
| 627 | +A number of open source applications use the L2TP kernel subsystem: | |
| 628 | + | |
| 629 | +============ ============================================== | |
| 630 | +iproute2 https://github.com/shemminger/iproute2 | |
| 631 | +go-l2tp https://github.com/katalix/go-l2tp | |
| 632 | +tunneldigger https://github.com/wlanslovenija/tunneldigger | |
| 633 | +xl2tpd https://github.com/xelerance/xl2tpd | |
| 634 | +============ ============================================== | |
| 635 | + | |
| 636 | +Limitations | |
| 637 | +----------- | |
| 638 | + | |
| 639 | +The current implementation has a number of limitations: | |
| 640 | + | |
| 641 | + 1) Multiple UDP sockets with the same 5-tuple address cannot be | |
| 642 | + used. The kernel's tunnel context is identified using private | |
| 643 | + data associated with the socket so it is important that each | |
| 644 | + socket is uniquely identified by its address. | |
| 645 | + | |
| 646 | + 2) Interfacing with openvswitch is not yet implemented. It may be | |
| 647 | + useful to map OVS Ethernet and VLAN ports into L2TPv3 tunnels. | |
| 648 | + | |
| 649 | + 3) VLAN pseudowires are implemented using an ``l2tpethN`` interface | |
| 650 | + configured with a VLAN sub-interface. Since L2TPv3 VLAN | |
| 651 | + pseudowires carry one and only one VLAN, it may be better to use | |
| 652 | + a single netdevice rather than an ``l2tpethN`` and ``l2tpethN``:M | |
| 653 | + pair per VLAN session. The netlink attribute | |
| 654 | + ``L2TP_ATTR_VLAN_ID`` was added for this, but it was never | |
| 655 | + implemented. | |
| 656 | + | |
| 657 | +Testing | |
| 658 | +------- | |
| 659 | + | |
| 660 | +Unmanaged L2TPv3 Ethernet features are tested by the kernel's built-in | |
| 661 | +selftests. See `tools/testing/selftests/net/l2tp.sh`_. | |
| 662 | + | |
| 663 | +Another test suite, l2tp-ktest_, covers all | |
| 664 | +of the L2TP APIs and tunnel/session types. This may be integrated into | |
| 665 | +the kernel's built-in L2TP selftests in the future. | |
| 666 | + | |
| 667 | +.. Links | |
| 668 | +.. _Generic Netlink: generic_netlink.html | |
| 669 | +.. _libmnl: https://www.netfilter.org/projects/libmnl | |
| 670 | +.. _include/uapi/linux/l2tp.h: ../../../include/uapi/linux/l2tp.h | |
| 671 | +.. _include/linux/if_pppol2tp.h: ../../../include/linux/if_pppol2tp.h | |
| 672 | +.. _net/l2tp/l2tp_ip.c: ../../../net/l2tp/l2tp_ip.c | |
| 673 | +.. _net/l2tp/l2tp_ip6.c: ../../../net/l2tp/l2tp_ip6.c | |
| 674 | +.. _net/l2tp/l2tp_ppp.c: ../../../net/l2tp/l2tp_ppp.c | |
| 675 | +.. _net/l2tp/l2tp_eth.c: ../../../net/l2tp/l2tp_eth.c | |
| 676 | +.. _tools/testing/selftests/net/l2tp.sh: ../../../tools/testing/selftests/net/l2tp.sh | |
| 677 | +.. _l2tp-ktest: https://github.com/katalix/l2tp-ktest | |
| @@ -465,9 +465,9 @@ XPS Configuration · 464 unmodified lines | ||
| 465 | 465 | ----------------- |
| 466 | 466 | |
| 467 | 467 | XPS is only available if the kconfig symbol CONFIG_XPS is enabled (on by |
| 468 | −default for SMP). The functionality remains disabled until explicitly | |
| 469 | −configured. To enable XPS, the bitmap of CPUs/receive-queues that may | |
| 470 | −use a transmit queue is configured using the sysfs file entry: | |
| 468 | +default for SMP). If compiled in, it is driver dependent whether, and | |
| 469 | +how, XPS is configured at device init. The mapping of CPUs/receive-queues | |
| 470 | +to transmit queue can be inspected and configured using sysfs: | |
| 471 | 471 | |
| 472 | 472 | For selection based on CPUs map:: |
| 473 | 473 | |
| @@ -0,0 +1,179 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +==================== | |
| 4 | +Interface statistics | |
| 5 | +==================== | |
| 6 | + | |
| 7 | +Overview | |
| 8 | +======== | |
| 9 | + | |
| 10 | +This document is a guide to Linux network interface statistics. | |
| 11 | + | |
| 12 | +There are three main sources of interface statistics in Linux: | |
| 13 | + | |
| 14 | + - standard interface statistics based on | |
| 15 | + :c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`; | |
| 16 | + - protocol-specific statistics; and | |
| 17 | + - driver-defined statistics available via ethtool. | |
| 18 | + | |
| 19 | +Standard interface statistics | |
| 20 | +----------------------------- | |
| 21 | + | |
| 22 | +There are multiple interfaces to reach the standard statistics. | |
| 23 | +Most commonly used is the `ip` command from `iproute2`:: | |
| 24 | + | |
| 25 | + $ ip -s -s link show dev ens4u1u1 | |
| 26 | + 6: ens4u1u1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 | |
| 27 | + link/ether 48:2a:e3:4c:b1:d1 brd ff:ff:ff:ff:ff:ff | |
| 28 | + RX: bytes packets errors dropped overrun mcast | |
| 29 | + 74327665117 69016965 0 0 0 0 | |
| 30 | + RX errors: length crc frame fifo missed | |
| 31 | + 0 0 0 0 0 | |
| 32 | + TX: bytes packets errors dropped carrier collsns | |
| 33 | + 21405556176 44608960 0 0 0 0 | |
| 34 | + TX errors: aborted fifo window heartbeat transns | |
| 35 | + 0 0 0 0 128 | |
| 36 | + altname enp58s0u1u1 | |
| 37 | + | |
| 38 | +Note that `-s` has been specified twice to see all members of | |
| 39 | +:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`. | |
| 40 | +If `-s` is specified once the detailed errors won't be shown. | |
| 41 | + | |
| 42 | +`ip` supports JSON formatting via the `-j` option. | |
| 43 | + | |
| 44 | +Protocol-specific statistics | |
| 45 | +---------------------------- | |
| 46 | + | |
| 47 | +Some of the interfaces used for configuring devices are also able | |
| 48 | +to report related statistics. For example ethtool interface used | |
| 49 | +to configure pause frames can report corresponding hardware counters:: | |
| 50 | + | |
| 51 | + $ ethtool --include-statistics -a eth0 | |
| 52 | + Pause parameters for eth0: | |
| 53 | + Autonegotiate: on | |
| 54 | + RX: on | |
| 55 | + TX: on | |
| 56 | + Statistics: | |
| 57 | + tx_pause_frames: 1 | |
| 58 | + rx_pause_frames: 1 | |
| 59 | + | |
| 60 | +Driver-defined statistics | |
| 61 | +------------------------- | |
| 62 | + | |
| 63 | +Driver-defined ethtool statistics can be dumped using `ethtool -S $ifc`, e.g.:: | |
| 64 | + | |
| 65 | + $ ethtool -S ens4u1u1 | |
| 66 | + NIC statistics: | |
| 67 | + tx_single_collisions: 0 | |
| 68 | + tx_multi_collisions: 0 | |
| 69 | + | |
| 70 | +uAPIs | |
| 71 | +===== | |
| 72 | + | |
| 73 | +procfs | |
| 74 | +------ | |
| 75 | + | |
| 76 | +The historical `/proc/net/dev` text interface gives access to the list | |
| 77 | +of interfaces as well as their statistics. | |
| 78 | + | |
| 79 | +Note that even though this interface is using | |
| 80 | +:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` | |
| 81 | +internally it combines some of the fields. | |
| 82 | + | |
| 83 | +sysfs | |
| 84 | +----- | |
| 85 | + | |
| 86 | +Each device directory in sysfs contains a `statistics` directory (e.g. | |
| 87 | +`/sys/class/net/lo/statistics/`) with files corresponding to | |
| 88 | +members of :c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`. | |
| 89 | + | |
| 90 | +This simple interface is convenient especially in constrained/embedded | |
| 91 | +environments without access to tools. However, it's inefficient when | |
| 92 | +reading multiple stats as it internally performs a full dump of | |
| 93 | +:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` | |
| 94 | +and reports only the stat corresponding to the accessed file. | |
| 95 | + | |
| 96 | +Sysfs files are documented in | |
| 97 | +`Documentation/ABI/testing/sysfs-class-net-statistics`. | |
| 98 | + | |
| 99 | + | |
| 100 | +netlink | |
| 101 | +------- | |
| 102 | + | |
| 103 | +`rtnetlink` (`NETLINK_ROUTE`) is the preferred method of accessing | |
| 104 | +:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` stats. | |
| 105 | + | |
| 106 | +Statistics are reported both in the responses to link information | |
| 107 | +requests (`RTM_GETLINK`) and statistic requests (`RTM_GETSTATS`, | |
| 108 | +when `IFLA_STATS_LINK_64` bit is set in the `.filter_mask` of the request). | |
| 109 | + | |
| 110 | +ethtool | |
| 111 | +------- | |
| 112 | + | |
| 113 | +Ethtool IOCTL interface allows drivers to report implementation | |
| 114 | +specific statistics. Historically it has also been used to report | |
| 115 | +statistics for which other APIs did not exist, like per-device-queue | |
| 116 | +statistics, or standard-based statistics (e.g. RFC 2863). | |
| 117 | + | |
| 118 | +Statistics and their string identifiers are retrieved separately. | |
| 119 | +Identifiers via `ETHTOOL_GSTRINGS` with `string_set` set to `ETH_SS_STATS`, | |
| 120 | +and values via `ETHTOOL_GSTATS`. User space should use `ETHTOOL_GDRVINFO` | |
| 121 | +to retrieve the number of statistics (`.n_stats`). | |
| 122 | + | |
| 123 | +ethtool-netlink | |
| 124 | +--------------- | |
| 125 | + | |
| 126 | +Ethtool netlink is a replacement for the older IOCTL interface. | |
| 127 | + | |
| 128 | +Protocol-related statistics can be requested in get commands by setting | |
| 129 | +the `ETHTOOL_FLAG_STATS` flag in `ETHTOOL_A_HEADER_FLAGS`. Currently | |
| 130 | +statistics are supported in the following commands: | |
| 131 | + | |
| 132 | + - `ETHTOOL_MSG_PAUSE_GET` | |
| 133 | + | |
| 134 | +debugfs | |
| 135 | +------- | |
| 136 | + | |
| 137 | +Some drivers expose extra statistics via `debugfs`. | |
| 138 | + | |
| 139 | +struct rtnl_link_stats64 | |
| 140 | +======================== | |
| 141 | + | |
| 142 | +.. kernel-doc:: include/uapi/linux/if_link.h | |
| 143 | + :identifiers: rtnl_link_stats64 | |
| 144 | + | |
| 145 | +Notes for driver authors | |
| 146 | +======================== | |
| 147 | + | |
| 148 | +Drivers should report all statistics which have a matching member in | |
| 149 | +:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` exclusively | |
| 150 | +via `.ndo_get_stats64`. Reporting such standard stats via ethtool | |
| 151 | +or debugfs will not be accepted. | |
| 152 | + | |
| 153 | +Drivers must ensure best possible compliance with | |
| 154 | +:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`. | |
| 155 | +Please note for example that detailed error statistics must be | |
| 156 | +added into the general `rx_error` / `tx_error` counters. | |
| 157 | + | |
| 158 | +The `.ndo_get_stats64` callback can not sleep because of accesses | |
| 159 | +via `/proc/net/dev`. If driver may sleep when retrieving the statistics | |
| 160 | +from the device it should do so periodically asynchronously and only return | |
| 161 | +a recent copy from `.ndo_get_stats64`. Ethtool interrupt coalescing interface | |
| 162 | +allows setting the frequency of refreshing statistics, if needed. | |
| 163 | + | |
| 164 | +Retrieving ethtool statistics is a multi-syscall process, drivers are advised | |
| 165 | +to keep the number of statistics constant to avoid race conditions with | |
| 166 | +user space trying to read them. | |
| 167 | + | |
| 168 | +Statistics must persist across routine operations like bringing the interface | |
| 169 | +down and up. | |
| 170 | + | |
| 171 | +Kernel-internal data structures | |
| 172 | +------------------------------- | |
| 173 | + | |
| 174 | +The following structures are internal to the kernel, their members are | |
| 175 | +translated to netlink attributes when dumped. Drivers must not overwrite | |
| 176 | +the statistics they don't report with 0. | |
| 177 | + | |
| 178 | +.. kernel-doc:: include/linux/ethtool.h | |
| 179 | + :identifiers: ethtool_pause_stats | |
| @@ -58,3 +58,31 @@ forwarding table using the new bridge command. · 57 unmodified lines | ||
| 58 | 58 | 3. Show forwarding table:: |
| 59 | 59 | |
| 60 | 60 | # bridge fdb show dev vxlan0 |
| 61 | + | |
| 62 | +The following NIC features may indicate support for UDP tunnel-related | |
| 63 | +offloads (most commonly VXLAN features, but support for a particular | |
| 64 | +encapsulation protocol is NIC specific): | |
| 65 | + | |
| 66 | + - `tx-udp_tnl-segmentation` | |
| 67 | + - `tx-udp_tnl-csum-segmentation` | |
| 68 | + ability to perform TCP segmentation offload of UDP encapsulated frames | |
| 69 | + | |
| 70 | + - `rx-udp_tunnel-port-offload` | |
| 71 | + receive side parsing of UDP encapsulated frames which allows NICs to | |
| 72 | + perform protocol-aware offloads, like checksum validation offload of | |
| 73 | + inner frames (only needed by NICs without protocol-agnostic offloads) | |
| 74 | + | |
| 75 | +For devices supporting `rx-udp_tunnel-port-offload` the list of currently | |
| 76 | +offloaded ports can be interrogated with `ethtool`:: | |
| 77 | + | |
| 78 | + $ ethtool --show-tunnels eth0 | |
| 79 | + Tunnel information for eth0: | |
| 80 | + UDP port table 0: | |
| 81 | + Size: 4 | |
| 82 | + Types: vxlan | |
| 83 | + No entries | |
| 84 | + UDP port table 1: | |
| 85 | + Size: 4 | |
| 86 | + Types: geneve, vxlan-gpe | |
| 87 | + Entries (1): | |
| 88 | + port 1230, vxlan-gpe | |
| @@ -1259,7 +1259,7 @@ S: Supported · 1258 unmodified lines | ||
| 1259 | 1259 | F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt |
| 1260 | 1260 | F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt |
| 1261 | 1261 | F: drivers/net/ethernet/apm/xgene/ |
| 1262 | −F: drivers/net/phy/mdio-xgene.c | |
| 1262 | +F: drivers/net/mdio/mdio-xgene.c | |
| 1263 | 1263 | |
| 1264 | 1264 | APPLIED MICRO (APM) X-GENE SOC PMU |
| 1265 | 1265 | M: Khuong Dinh <khuong@os.amperecomputing.com> |
| @@ -3238,7 +3238,7 @@ M: Daniel Borkmann <daniel@iogearbox.net> · 1972 unmodified lines | ||
| 3238 | 3238 | R: Martin KaFai Lau <kafai@fb.com> |
| 3239 | 3239 | R: Song Liu <songliubraving@fb.com> |
| 3240 | 3240 | R: Yonghong Song <yhs@fb.com> |
| 3241 | −R: Andrii Nakryiko <andriin@fb.com> | |
| 3241 | +R: Andrii Nakryiko <andrii@kernel.org> | |
| 3242 | 3242 | R: John Fastabend <john.fastabend@gmail.com> |
| 3243 | 3243 | R: KP Singh <kpsingh@chromium.org> |
| 3244 | 3244 | L: netdev@vger.kernel.org |
| @@ -3914,6 +3914,7 @@ F: include/net/netns/can.h · 669 unmodified lines | ||
| 3914 | 3914 | F: include/uapi/linux/can.h |
| 3915 | 3915 | F: include/uapi/linux/can/bcm.h |
| 3916 | 3916 | F: include/uapi/linux/can/gw.h |
| 3917 | +F: include/uapi/linux/can/isotp.h | |
| 3917 | 3918 | F: include/uapi/linux/can/raw.h |
| 3918 | 3919 | F: net/can/ |
| 3919 | 3920 | |
| @@ -4713,6 +4714,15 @@ S: Supported · 793 unmodified lines | ||
| 4713 | 4714 | W: http://www.chelsio.com |
| 4714 | 4715 | F: drivers/crypto/chelsio |
| 4715 | 4716 | |
| 4717 | +CXGB4 INLINE CRYPTO DRIVER | |
| 4718 | +M: Ayush Sawal <ayush.sawal@chelsio.com> | |
| 4719 | +M: Vinay Kumar Yadav <vinay.yadav@chelsio.com> | |
| 4720 | +M: Rohit Maheshwari <rohitm@chelsio.com> | |
| 4721 | +L: netdev@vger.kernel.org | |
| 4722 | +S: Supported | |
| 4723 | +W: http://www.chelsio.com | |
| 4724 | +F: drivers/net/ethernet/chelsio/inline_crypto/ | |
| 4725 | + | |
| 4716 | 4726 | CXGB4 ETHERNET DRIVER (CXGB4) |
| 4717 | 4727 | M: Vishal Kulkarni <vishal@chelsio.com> |
| 4718 | 4728 | L: netdev@vger.kernel.org |
| @@ -6546,11 +6556,14 @@ F: Documentation/devicetree/bindings/net/ethernet-phy.yaml · 1827 unmodified lines | ||
| 6546 | 6556 | F: Documentation/devicetree/bindings/net/mdio* |
| 6547 | 6557 | F: Documentation/devicetree/bindings/net/qca,ar803x.yaml |
| 6548 | 6558 | F: Documentation/networking/phy.rst |
| 6559 | +F: drivers/net/mdio/ | |
| 6560 | +F: drivers/net/mdio/of_mdio.c | |
| 6561 | +F: drivers/net/pcs/ | |
| 6549 | 6562 | F: drivers/net/phy/ |
| 6550 | −F: drivers/of/of_mdio.c | |
| 6551 | 6563 | F: drivers/of/of_net.c |
| 6552 | 6564 | F: include/dt-bindings/net/qca-ar803x.h |
| 6553 | 6565 | F: include/linux/*mdio*.h |
| 6566 | +F: include/linux/mdio/*.h | |
| 6554 | 6567 | F: include/linux/of_net.h |
| 6555 | 6568 | F: include/linux/phy.h |
| 6556 | 6569 | F: include/linux/phy_fixed.h |
| @@ -10347,6 +10360,13 @@ S: Maintained · 3790 unmodified lines | ||
| 10347 | 10360 | W: http://linux-test-project.github.io/ |
| 10348 | 10361 | T: git git://github.com/linux-test-project/ltp.git |
| 10349 | 10362 | |
| 10363 | +LYNX PCS MODULE | |
| 10364 | +M: Ioana Ciornei <ioana.ciornei@nxp.com> | |
| 10365 | +L: netdev@vger.kernel.org | |
| 10366 | +S: Supported | |
| 10367 | +F: drivers/net/pcs/pcs-lynx.c | |
| 10368 | +F: include/linux/pcs-lynx.h | |
| 10369 | + | |
| 10350 | 10370 | M68K ARCHITECTURE |
| 10351 | 10371 | M: Geert Uytterhoeven <geert@linux-m68k.org> |
| 10352 | 10372 | L: linux-m68k@lists.linux-m68k.org |
| @@ -10554,7 +10574,7 @@ M: Tobias Waldekranz <tobias@waldekranz.com> · 201 unmodified lines | ||
| 10554 | 10574 | L: netdev@vger.kernel.org |
| 10555 | 10575 | S: Maintained |
| 10556 | 10576 | F: Documentation/devicetree/bindings/net/marvell,mvusb.yaml |
| 10557 | −F: drivers/net/phy/mdio-mvusb.c | |
| 10577 | +F: drivers/net/mdio/mdio-mvusb.c | |
| 10558 | 10578 | |
| 10559 | 10579 | MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER |
| 10560 | 10580 | M: Hu Ziji <huziji@marvell.com> |
| @@ -10701,6 +10721,15 @@ L: linux-input@vger.kernel.org · 140 unmodified lines | ||
| 10701 | 10721 | S: Maintained |
| 10702 | 10722 | F: drivers/hid/hid-mcp2221.c |
| 10703 | 10723 | |
| 10724 | +MCP251XFD SPI-CAN NETWORK DRIVER | |
| 10725 | +M: Marc Kleine-Budde <mkl@pengutronix.de> | |
| 10726 | +M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | |
| 10727 | +R: Thomas Kopp <thomas.kopp@microchip.com> | |
| 10728 | +L: linux-can@vger.kernel.org | |
| 10729 | +S: Maintained | |
| 10730 | +F: Documentation/devicetree/bindings/net/can/microchip,mcp251xfd.yaml | |
| 10731 | +F: drivers/net/can/spi/mcp251xfd/ | |
| 10732 | + | |
| 10704 | 10733 | MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS |
| 10705 | 10734 | M: Peter Rosin <peda@axentia.se> |
| 10706 | 10735 | L: linux-iio@vger.kernel.org |
| @@ -12090,7 +12119,6 @@ M: Neil Horman <nhorman@tuxdriver.com> · 1383 unmodified lines | ||
| 12090 | 12119 | L: netdev@vger.kernel.org |
| 12091 | 12120 | S: Maintained |
| 12092 | 12121 | W: https://fedorahosted.org/dropwatch/ |
| 12093 | −F: include/net/drop_monitor.h | |
| 12094 | 12122 | F: include/uapi/linux/net_dropmon.h |
| 12095 | 12123 | F: net/core/drop_monitor.c |
| 12096 | 12124 | |
| @@ -12185,6 +12213,7 @@ F: net/ipv6/ipcomp6.c · 88 unmodified lines | ||
| 12185 | 12213 | F: net/ipv6/xfrm* |
| 12186 | 12214 | F: net/key/ |
| 12187 | 12215 | F: net/xfrm/ |
| 12216 | +F: tools/testing/selftests/net/ipsec.c | |
| 12188 | 12217 | |
| 12189 | 12218 | NETWORKING [IPv4/IPv6] |
| 12190 | 12219 | M: "David S. Miller" <davem@davemloft.net> |
| @@ -12597,6 +12626,7 @@ F: drivers/net/dsa/ocelot/* · 406 unmodified lines | ||
| 12597 | 12626 | F: drivers/net/ethernet/mscc/ |
| 12598 | 12627 | F: include/soc/mscc/ocelot* |
| 12599 | 12628 | F: net/dsa/tag_ocelot.c |
| 12629 | +F: tools/testing/selftests/drivers/net/ocelot/* | |
| 12600 | 12630 | |
| 12601 | 12631 | OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER |
| 12602 | 12632 | M: Frederic Barrat <fbarrat@linux.ibm.com> |
| @@ -15372,10 +15402,11 @@ F: drivers/media/platform/s3c-camif/ · 2769 unmodified lines | ||
| 15372 | 15402 | F: include/media/drv-intf/s3c_camif.h |
| 15373 | 15403 | |
| 15374 | 15404 | SAMSUNG S3FWRN5 NFC DRIVER |
| 15375 | −M: Robert Baldyga <r.baldyga@samsung.com> | |
| 15405 | +M: Krzysztof Kozlowski <krzk@kernel.org> | |
| 15376 | 15406 | M: Krzysztof Opasiak <k.opasiak@samsung.com> |
| 15377 | 15407 | L: linux-nfc@lists.01.org (moderated for non-subscribers) |
| 15378 | −S: Supported | |
| 15408 | +S: Maintained | |
| 15409 | +F: Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml | |
| 15379 | 15410 | F: drivers/nfc/s3fwrn5 |
| 15380 | 15411 | |
| 15381 | 15412 | SAMSUNG S5C73M3 CAMERA DRIVER |
| @@ -15762,6 +15793,7 @@ L: netdev@vger.kernel.org · 380 unmodified lines | ||
| 15762 | 15793 | S: Maintained |
| 15763 | 15794 | F: drivers/net/phy/phylink.c |
| 15764 | 15795 | F: drivers/net/phy/sfp* |
| 15796 | +F: include/linux/mdio/mdio-i2c.h | |
| 15765 | 15797 | F: include/linux/phylink.h |
| 15766 | 15798 | F: include/linux/sfp.h |
| 15767 | 15799 | K: phylink\.h|struct\s+phylink|\.phylink|>phylink_|phylink_(autoneg|clear|connect|create|destroy|disconnect|ethtool|helper|mac|mii|of|set|start|stop|test|validate) |
| @@ -16851,8 +16883,8 @@ SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER · 1083 unmodified lines | ||
| 16851 | 16883 | M: Jose Abreu <Jose.Abreu@synopsys.com> |
| 16852 | 16884 | L: netdev@vger.kernel.org |
| 16853 | 16885 | S: Supported |
| 16854 | −F: drivers/net/phy/mdio-xpcs.c | |
| 16855 | −F: include/linux/mdio-xpcs.h | |
| 16886 | +F: drivers/net/pcs/pcs-xpcs.c | |
| 16887 | +F: include/linux/pcs/pcs-xpcs.h | |
| 16856 | 16888 | |
| 16857 | 16889 | SYNOPSYS DESIGNWARE I2C DRIVER |
| 16858 | 16890 | M: Jarkko Nikula <jarkko.nikula@linux.intel.com> |
| @@ -1071,13 +1071,15 @@ ifdef CONFIG_STACK_VALIDATION · 1070 unmodified lines | ||
| 1071 | 1071 | endif |
| 1072 | 1072 | endif |
| 1073 | 1073 | |
| 1074 | +ifdef CONFIG_BPF | |
| 1074 | 1075 | ifdef CONFIG_DEBUG_INFO_BTF |
| 1075 | 1076 | ifeq ($(has_libelf),1) |
| 1076 | 1077 | resolve_btfids_target := tools/bpf/resolve_btfids FORCE |
| 1077 | 1078 | else |
| 1078 | 1079 | ERROR_RESOLVE_BTFIDS := 1 |
| 1079 | 1080 | endif |
| 1080 | −endif | |
| 1081 | +endif # CONFIG_DEBUG_INFO_BTF | |
| 1082 | +endif # CONFIG_BPF | |
| 1081 | 1083 | |
| 1082 | 1084 | PHONY += prepare0 |
| 1083 | 1085 | |
| @@ -795,8 +795,8 @@ · 794 unmodified lines | ||
| 795 | 795 | reg = <0x27>; |
| 796 | 796 | interrupt-parent = <&gpa1>; |
| 797 | 797 | interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; |
| 798 | − s3fwrn5,en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>; | |
| 799 | − s3fwrn5,fw-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>; | |
| 798 | + en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>; | |
| 799 | + wake-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>; | |
| 800 | 800 | }; |
| 801 | 801 | }; |
| 802 | 802 | |
| @@ -199,6 +199,7 @@ · 198 unmodified lines | ||
| 199 | 199 | &enetc_port0 { |
| 200 | 200 | phy-handle = <&sgmii_phy0>; |
| 201 | 201 | phy-connection-type = "sgmii"; |
| 202 | + managed = "in-band-status"; | |
| 202 | 203 | status = "okay"; |
| 203 | 204 | |
| 204 | 205 | mdio { |
| @@ -143,6 +143,56 @@ · 142 unmodified lines | ||
| 143 | 143 | mdio: mdio-bus { |
| 144 | 144 | #address-cells = <1>; |
| 145 | 145 | #size-cells = <0>; |
| 146 | + | |
| 147 | + switch@0 { | |
| 148 | + compatible = "mediatek,mt7531"; | |
| 149 | + reg = <0>; | |
| 150 | + reset-gpios = <&pio 54 0>; | |
| 151 | + | |
| 152 | + ports { | |
| 153 | + #address-cells = <1>; | |
| 154 | + #size-cells = <0>; | |
| 155 | + | |
| 156 | + port@0 { | |
| 157 | + reg = <0>; | |
| 158 | + label = "wan"; | |
| 159 | + }; | |
| 160 | + | |
| 161 | + port@1 { | |
| 162 | + reg = <1>; | |
| 163 | + label = "lan0"; | |
| 164 | + }; | |
| 165 | + | |
| 166 | + port@2 { | |
| 167 | + reg = <2>; | |
| 168 | + label = "lan1"; | |
| 169 | + }; | |
| 170 | + | |
| 171 | + port@3 { | |
| 172 | + reg = <3>; | |
| 173 | + label = "lan2"; | |
| 174 | + }; | |
| 175 | + | |
| 176 | + port@4 { | |
| 177 | + reg = <4>; | |
| 178 | + label = "lan3"; | |
| 179 | + }; | |
| 180 | + | |
| 181 | + port@6 { | |
| 182 | + reg = <6>; | |
| 183 | + label = "cpu"; | |
| 184 | + ethernet = <&gmac0>; | |
| 185 | + phy-mode = "2500base-x"; | |
| 186 | + | |
| 187 | + fixed-link { | |
| 188 | + speed = <2500>; | |
| 189 | + full-duplex; | |
| 190 | + pause; | |
| 191 | + }; | |
| 192 | + }; | |
| 193 | + }; | |
| 194 | + }; | |
| 195 | + | |
| 146 | 196 | }; |
| 147 | 197 | }; |
| 148 | 198 | |
| @@ -105,20 +105,71 @@ · 104 unmodified lines | ||
| 105 | 105 | pinctrl-0 = <ð_pins>; |
| 106 | 106 | status = "okay"; |
| 107 | 107 | |
| 108 | − gmac1: mac@1 { | |
| 108 | + gmac0: mac@0 { | |
| 109 | 109 | compatible = "mediatek,eth-mac"; |
| 110 | − reg = <1>; | |
| 111 | − phy-handle = <&phy5>; | |
| 110 | + reg = <0>; | |
| 111 | + phy-mode = "2500base-x"; | |
| 112 | + | |
| 113 | + fixed-link { | |
| 114 | + speed = <2500>; | |
| 115 | + full-duplex; | |
| 116 | + pause; | |
| 117 | + }; | |
| 112 | 118 | }; |
| 113 | 119 | |
| 114 | 120 | mdio-bus { |
| 115 | 121 | #address-cells = <1>; |
| 116 | 122 | #size-cells = <0>; |
| 117 | 123 | |
| 118 | − phy5: ethernet-phy@5 { | |
| 119 | − reg = <5>; | |
| 120 | − phy-mode = "sgmii"; | |
| 124 | + switch@0 { | |
| 125 | + compatible = "mediatek,mt7531"; | |
| 126 | + reg = <0>; | |
| 127 | + reset-gpios = <&pio 54 0>; | |
| 128 | + | |
| 129 | + ports { | |
| 130 | + #address-cells = <1>; | |
| 131 | + #size-cells = <0>; | |
| 132 | + | |
| 133 | + port@0 { | |
| 134 | + reg = <0>; | |
| 135 | + label = "lan0"; | |
| 136 | + }; | |
| 137 | + | |
| 138 | + port@1 { | |
| 139 | + reg = <1>; | |
| 140 | + label = "lan1"; | |
| 141 | + }; | |
| 142 | + | |
| 143 | + port@2 { | |
| 144 | + reg = <2>; | |
| 145 | + label = "lan2"; | |
| 146 | + }; | |
| 147 | + | |
| 148 | + port@3 { | |
| 149 | + reg = <3>; | |
| 150 | + label = "lan3"; | |
| 151 | + }; | |
| 152 | + | |
| 153 | + port@4 { | |
| 154 | + reg = <4>; | |
| 155 | + label = "wan"; | |
| 156 | + }; | |
| 157 | + | |
| 158 | + port@6 { | |
| 159 | + reg = <6>; | |
| 160 | + label = "cpu"; | |
| 161 | + ethernet = <&gmac0>; | |
| 162 | + phy-mode = "2500base-x"; | |
| 163 | + | |
| 164 | + fixed-link { | |
| 165 | + speed = <2500>; | |
| 166 | + full-duplex; | |
| 167 | + pause; | |
| 168 | + }; | |
| 169 | + }; | |
| 170 | + }; | |
| 121 | 171 | }; |
| 172 | + | |
| 122 | 173 | }; |
| 123 | 174 | }; |
| 124 | 175 | |
| @@ -134,11 +134,13 @@ · 133 unmodified lines | ||
| 134 | 134 | <0x1280000 0x100>, |
| 135 | 135 | <0x1800000 0x80000>, |
| 136 | 136 | <0x1880000 0x10000>, |
| 137 | + <0x1040000 0x10000>, | |
| 138 | + <0x1050000 0x10000>, | |
| 137 | 139 | <0x1060000 0x10000>; |
| 138 | 140 | reg-names = "sys", "rew", "qs", "ptp", "port0", "port1", |
| 139 | 141 | "port2", "port3", "port4", "port5", "port6", |
| 140 | 142 | "port7", "port8", "port9", "port10", "qsys", |
| 141 | − "ana", "s2"; | |
| 143 | + "ana", "s0", "s1", "s2"; | |
| 142 | 144 | interrupts = <18 21 22>; |
| 143 | 145 | interrupt-names = "ptp_rdy", "xtr", "inj"; |
| 144 | 146 | |
| @@ -64,6 +64,40 @@ · 63 unmodified lines | ||
| 64 | 64 | phy_sgmii_2: ethernet-phy@3 { |
| 65 | 65 | reg = <0x03>; |
| 66 | 66 | }; |
| 67 | + | |
| 68 | + /* VSC8514 QSGMII PHY */ | |
| 69 | + phy_qsgmii_0: ethernet-phy@4 { | |
| 70 | + reg = <0x4>; | |
| 71 | + }; | |
| 72 | + | |
| 73 | + phy_qsgmii_1: ethernet-phy@5 { | |
| 74 | + reg = <0x5>; | |
| 75 | + }; | |
| 76 | + | |
| 77 | + phy_qsgmii_2: ethernet-phy@6 { | |
| 78 | + reg = <0x6>; | |
| 79 | + }; | |
| 80 | + | |
| 81 | + phy_qsgmii_3: ethernet-phy@7 { | |
| 82 | + reg = <0x7>; | |
| 83 | + }; | |
| 84 | + | |
| 85 | + /* VSC8514 QSGMII PHY */ | |
| 86 | + phy_qsgmii_4: ethernet-phy@8 { | |
| 87 | + reg = <0x8>; | |
| 88 | + }; | |
| 89 | + | |
| 90 | + phy_qsgmii_5: ethernet-phy@9 { | |
| 91 | + reg = <0x9>; | |
| 92 | + }; | |
| 93 | + | |
| 94 | + phy_qsgmii_6: ethernet-phy@a { | |
| 95 | + reg = <0xa>; | |
| 96 | + }; | |
| 97 | + | |
| 98 | + phy_qsgmii_7: ethernet-phy@b { | |
| 99 | + reg = <0xb>; | |
| 100 | + }; | |
| 67 | 101 | }; |
| 68 | 102 | }; |
| 69 | 103 | }; |
| @@ -76,3 +110,76 @@ · 6 unmodified lines | ||
| 76 | 110 | }; |
| 77 | 111 | |
| 78 | 112 | #include "t1040si-post.dtsi" |
| 113 | + | |
| 114 | +&seville_switch { | |
| 115 | + status = "okay"; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +&seville_port0 { | |
| 119 | + managed = "in-band-status"; | |
| 120 | + phy-handle = <&phy_qsgmii_0>; | |
| 121 | + phy-mode = "qsgmii"; | |
| 122 | + label = "ETH5"; | |
| 123 | + status = "okay"; | |
| 124 | +}; | |
| 125 | + | |
| 126 | +&seville_port1 { | |
| 127 | + managed = "in-band-status"; | |
| 128 | + phy-handle = <&phy_qsgmii_1>; | |
| 129 | + phy-mode = "qsgmii"; | |
| 130 | + label = "ETH4"; | |
| 131 | + status = "okay"; | |
| 132 | +}; | |
| 133 | + | |
| 134 | +&seville_port2 { | |
| 135 | + managed = "in-band-status"; | |
| 136 | + phy-handle = <&phy_qsgmii_2>; | |
| 137 | + phy-mode = "qsgmii"; | |
| 138 | + label = "ETH7"; | |
| 139 | + status = "okay"; | |
| 140 | +}; | |
| 141 | + | |
| 142 | +&seville_port3 { | |
| 143 | + managed = "in-band-status"; | |
| 144 | + phy-handle = <&phy_qsgmii_3>; | |
| 145 | + phy-mode = "qsgmii"; | |
| 146 | + label = "ETH6"; | |
| 147 | + status = "okay"; | |
| 148 | +}; | |
| 149 | + | |
| 150 | +&seville_port4 { | |
| 151 | + managed = "in-band-status"; | |
| 152 | + phy-handle = <&phy_qsgmii_4>; | |
| 153 | + phy-mode = "qsgmii"; | |
| 154 | + label = "ETH9"; | |
| 155 | + status = "okay"; | |
| 156 | +}; | |
| 157 | + | |
| 158 | +&seville_port5 { | |
| 159 | + managed = "in-band-status"; | |
| 160 | + phy-handle = <&phy_qsgmii_5>; | |
| 161 | + phy-mode = "qsgmii"; | |
| 162 | + label = "ETH8"; | |
| 163 | + status = "okay"; | |
| 164 | +}; | |
| 165 | + | |
| 166 | +&seville_port6 { | |
| 167 | + managed = "in-band-status"; | |
| 168 | + phy-handle = <&phy_qsgmii_6>; | |
| 169 | + phy-mode = "qsgmii"; | |
| 170 | + label = "ETH11"; | |
| 171 | + status = "okay"; | |
| 172 | +}; | |
| 173 | + | |
| 174 | +&seville_port7 { | |
| 175 | + managed = "in-band-status"; | |
| 176 | + phy-handle = <&phy_qsgmii_7>; | |
| 177 | + phy-mode = "qsgmii"; | |
| 178 | + label = "ETH10"; | |
| 179 | + status = "okay"; | |
| 180 | +}; | |
| 181 | + | |
| 182 | +&seville_port8 { | |
| 183 | + ethernet = <&enet0>; | |
| 184 | + status = "okay"; | |
| 185 | +}; | |
| @@ -628,6 +628,84 @@ · 627 unmodified lines | ||
| 628 | 628 | status = "disabled"; |
| 629 | 629 | }; |
| 630 | 630 | }; |
| 631 | + | |
| 632 | + seville_switch: ethernet-switch@800000 { | |
| 633 | + compatible = "mscc,vsc9953-switch"; | |
| 634 | + reg = <0x800000 0x290000>; | |
| 635 | + interrupts = <26 2 0 0>; | |
| 636 | + interrupt-names = "xtr"; | |
| 637 | + little-endian; | |
| 638 | + #address-cells = <1>; | |
| 639 | + #size-cells = <0>; | |
| 640 | + status = "disabled"; | |
| 641 | + | |
| 642 | + ports { | |
| 643 | + #address-cells = <1>; | |
| 644 | + #size-cells = <0>; | |
| 645 | + | |
| 646 | + seville_port0: port@0 { | |
| 647 | + reg = <0>; | |
| 648 | + status = "disabled"; | |
| 649 | + }; | |
| 650 | + | |
| 651 | + seville_port1: port@1 { | |
| 652 | + reg = <1>; | |
| 653 | + status = "disabled"; | |
| 654 | + }; | |
| 655 | + | |
| 656 | + seville_port2: port@2 { | |
| 657 | + reg = <2>; | |
| 658 | + status = "disabled"; | |
| 659 | + }; | |
| 660 | + | |
| 661 | + seville_port3: port@3 { | |
| 662 | + reg = <3>; | |
| 663 | + status = "disabled"; | |
| 664 | + }; | |
| 665 | + | |
| 666 | + seville_port4: port@4 { | |
| 667 | + reg = <4>; | |
| 668 | + status = "disabled"; | |
| 669 | + }; | |
| 670 | + | |
| 671 | + seville_port5: port@5 { | |
| 672 | + reg = <5>; | |
| 673 | + status = "disabled"; | |
| 674 | + }; | |
| 675 | + | |
| 676 | + seville_port6: port@6 { | |
| 677 | + reg = <6>; | |
| 678 | + status = "disabled"; | |
| 679 | + }; | |
| 680 | + | |
| 681 | + seville_port7: port@7 { | |
| 682 | + reg = <7>; | |
| 683 | + status = "disabled"; | |
| 684 | + }; | |
| 685 | + | |
| 686 | + seville_port8: port@8 { | |
| 687 | + reg = <8>; | |
| 688 | + phy-mode = "internal"; | |
| 689 | + status = "disabled"; | |
| 690 | + | |
| 691 | + fixed-link { | |
| 692 | + speed = <2500>; | |
| 693 | + full-duplex; | |
| 694 | + }; | |
| 695 | + }; | |
| 696 | + | |
| 697 | + seville_port9: port@9 { | |
| 698 | + reg = <9>; | |
| 699 | + phy-mode = "internal"; | |
| 700 | + status = "disabled"; | |
| 701 | + | |
| 702 | + fixed-link { | |
| 703 | + speed = <2500>; | |
| 704 | + full-duplex; | |
| 705 | + }; | |
| 706 | + }; | |
| 707 | + }; | |
| 708 | + }; | |
| 631 | 709 | }; |
| 632 | 710 | |
| 633 | 711 | &qe { |
| @@ -238,7 +238,10 @@ extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *); · 237 unmodified lines | ||
| 238 | 238 | struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *, int); |
| 239 | 239 | u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx); |
| 240 | 240 | int ccw_device_pnso(struct ccw_device *cdev, |
| 241 | − struct chsc_pnso_area *pnso_area, | |
| 242 | − struct chsc_pnso_resume_token resume_token, | |
| 243 | − int cnc); | |
| 241 | + struct chsc_pnso_area *pnso_area, u8 oc, | |
| 242 | + struct chsc_pnso_resume_token resume_token, int cnc); | |
| 243 | +int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid); | |
| 244 | +int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid); | |
| 245 | +int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid); | |
| 246 | +int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid); | |
| 244 | 247 | #endif /* _S390_CCWDEV_H_ */ |
| @@ -11,6 +11,13 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include <uapi/asm/chsc.h> |
| 13 | 13 | |
| 14 | +/** | |
| 15 | + * Operation codes for CHSC PNSO: | |
| 16 | + * PNSO_OC_NET_BRIDGE_INFO - only addresses that are visible to a bridgeport | |
| 17 | + * PNSO_OC_NET_ADDR_INFO - all addresses | |
| 18 | + */ | |
| 19 | +#define PNSO_OC_NET_BRIDGE_INFO 0 | |
| 20 | +#define PNSO_OC_NET_ADDR_INFO 3 | |
| 14 | 21 | /** |
| 15 | 22 | * struct chsc_pnso_naid_l2 - network address information descriptor |
| 16 | 23 | * @nit: Network interface token |
| @@ -36,7 +36,9 @@ struct css_general_char { · 35 unmodified lines | ||
| 36 | 36 | u64 alt_ssi : 1; /* bit 108 */ |
| 37 | 37 | u64 : 1; |
| 38 | 38 | u64 narf : 1; /* bit 110 */ |
| 39 | − u64 : 12; | |
| 39 | + u64 : 5; | |
| 40 | + u64 enarf: 1; /* bit 116 */ | |
| 41 | + u64 : 6; | |
| 40 | 42 | u64 util_str : 1;/* bit 123 */ |
| 41 | 43 | } __packed; |
| 42 | 44 | |
| @@ -50,7 +50,6 @@ struct bpf_jit { · 49 unmodified lines | ||
| 50 | 50 | int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */ |
| 51 | 51 | int tail_call_start; /* Tail call start offset */ |
| 52 | 52 | int excnt; /* Number of exception table entries */ |
| 53 | − int labels[1]; /* Labels for local jumps */ | |
| 54 | 53 | }; |
| 55 | 54 | |
| 56 | 55 | #define SEEN_MEM BIT(0) /* use mem[] for temporary storage */ |
| @@ -229,18 +228,18 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1) · 172 unmodified lines | ||
| 229 | 228 | REG_SET_SEEN(b3); \ |
| 230 | 229 | }) |
| 231 | 230 | |
| 232 | −#define EMIT6_PCREL_LABEL(op1, op2, b1, b2, label, mask) \ | |
| 231 | +#define EMIT6_PCREL_RIEB(op1, op2, b1, b2, mask, target) \ | |
| 233 | 232 | ({ \ |
| 234 | − int rel = (jit->labels[label] - jit->prg) >> 1; \ | |
| 233 | + unsigned int rel = (int)((target) - jit->prg) / 2; \ | |
| 235 | 234 | _EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), \ |
| 236 | 235 | (op2) | (mask) << 12); \ |
| 237 | 236 | REG_SET_SEEN(b1); \ |
| 238 | 237 | REG_SET_SEEN(b2); \ |
| 239 | 238 | }) |
| 240 | 239 | |
| 241 | −#define EMIT6_PCREL_IMM_LABEL(op1, op2, b1, imm, label, mask) \ | |
| 240 | +#define EMIT6_PCREL_RIEC(op1, op2, b1, imm, mask, target) \ | |
| 242 | 241 | ({ \ |
| 243 | − int rel = (jit->labels[label] - jit->prg) >> 1; \ | |
| 242 | + unsigned int rel = (int)((target) - jit->prg) / 2; \ | |
| 244 | 243 | _EMIT6((op1) | (reg_high(b1) | (mask)) << 16 | \ |
| 245 | 244 | (rel & 0xffff), (op2) | ((imm) & 0xff) << 8); \ |
| 246 | 245 | REG_SET_SEEN(b1); \ |
| @@ -1282,7 +1281,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, · 1035 unmodified lines | ||
| 1282 | 1281 | EMIT4(0xb9040000, BPF_REG_0, REG_2); |
| 1283 | 1282 | break; |
| 1284 | 1283 | } |
| 1285 | − case BPF_JMP | BPF_TAIL_CALL: | |
| 1284 | + case BPF_JMP | BPF_TAIL_CALL: { | |
| 1285 | + int patch_1_clrj, patch_2_clij, patch_3_brc; | |
| 1286 | + | |
| 1286 | 1287 | /* |
| 1287 | 1288 | * Implicit input: |
| 1288 | 1289 | * B1: pointer to ctx |
| @@ -1300,16 +1301,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, · 11 unmodified lines | ||
| 1300 | 1301 | EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2, |
| 1301 | 1302 | offsetof(struct bpf_array, map.max_entries)); |
| 1302 | 1303 | /* if ((u32)%b3 >= (u32)%w1) goto out; */ |
| 1303 | − if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) { | |
| 1304 | − /* clrj %b3,%w1,0xa,label0 */ | |
| 1305 | − EMIT6_PCREL_LABEL(0xec000000, 0x0077, BPF_REG_3, | |
| 1306 | − REG_W1, 0, 0xa); | |
| 1307 | − } else { | |
| 1308 | − /* clr %b3,%w1 */ | |
| 1309 | − EMIT2(0x1500, BPF_REG_3, REG_W1); | |
| 1310 | − /* brcl 0xa,label0 */ | |
| 1311 | − EMIT6_PCREL_RILC(0xc0040000, 0xa, jit->labels[0]); | |
| 1312 | − } | |
| 1304 | + /* clrj %b3,%w1,0xa,out */ | |
| 1305 | + patch_1_clrj = jit->prg; | |
| 1306 | + EMIT6_PCREL_RIEB(0xec000000, 0x0077, BPF_REG_3, REG_W1, 0xa, | |
| 1307 | + jit->prg); | |
| 1313 | 1308 | |
| 1314 | 1309 | /* |
| 1315 | 1310 | * if (tail_call_cnt++ > MAX_TAIL_CALL_CNT) |
| @@ -1324,16 +1319,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, · 8 unmodified lines | ||
| 1324 | 1319 | EMIT4_IMM(0xa7080000, REG_W0, 1); |
| 1325 | 1320 | /* laal %w1,%w0,off(%r15) */ |
| 1326 | 1321 | EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off); |
| 1327 | − if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) { | |
| 1328 | − /* clij %w1,MAX_TAIL_CALL_CNT,0x2,label0 */ | |
| 1329 | − EMIT6_PCREL_IMM_LABEL(0xec000000, 0x007f, REG_W1, | |
| 1330 | − MAX_TAIL_CALL_CNT, 0, 0x2); | |
| 1331 | − } else { | |
| 1332 | − /* clfi %w1,MAX_TAIL_CALL_CNT */ | |
| 1333 | − EMIT6_IMM(0xc20f0000, REG_W1, MAX_TAIL_CALL_CNT); | |
| 1334 | − /* brcl 0x2,label0 */ | |
| 1335 | − EMIT6_PCREL_RILC(0xc0040000, 0x2, jit->labels[0]); | |
| 1336 | − } | |
| 1322 | + /* clij %w1,MAX_TAIL_CALL_CNT,0x2,out */ | |
| 1323 | + patch_2_clij = jit->prg; | |
| 1324 | + EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT, | |
| 1325 | + 2, jit->prg); | |
| 1337 | 1326 | |
| 1338 | 1327 | /* |
| 1339 | 1328 | * prog = array->ptrs[index]; |
| @@ -1348,13 +1337,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, · 8 unmodified lines | ||
| 1348 | 1337 | /* ltg %r1,prog(%b2,%r1) */ |
| 1349 | 1338 | EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2, |
| 1350 | 1339 | REG_1, offsetof(struct bpf_array, ptrs)); |
| 1351 | − if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) { | |
| 1352 | − /* brc 0x8,label0 */ | |
| 1353 | − EMIT4_PCREL_RIC(0xa7040000, 0x8, jit->labels[0]); | |
| 1354 | − } else { | |
| 1355 | − /* brcl 0x8,label0 */ | |
| 1356 | − EMIT6_PCREL_RILC(0xc0040000, 0x8, jit->labels[0]); | |
| 1357 | − } | |
| 1340 | + /* brc 0x8,out */ | |
| 1341 | + patch_3_brc = jit->prg; | |
| 1342 | + EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg); | |
| 1358 | 1343 | |
| 1359 | 1344 | /* |
| 1360 | 1345 | * Restore registers before calling function |
| @@ -1371,8 +1356,16 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, · 10 unmodified lines | ||
| 1371 | 1356 | /* bc 0xf,tail_call_start(%r1) */ |
| 1372 | 1357 | _EMIT4(0x47f01000 + jit->tail_call_start); |
| 1373 | 1358 | /* out: */ |
| 1374 | − jit->labels[0] = jit->prg; | |
| 1359 | + if (jit->prg_buf) { | |
| 1360 | + *(u16 *)(jit->prg_buf + patch_1_clrj + 2) = | |
| 1361 | + (jit->prg - patch_1_clrj) >> 1; | |
| 1362 | + *(u16 *)(jit->prg_buf + patch_2_clij + 2) = | |
| 1363 | + (jit->prg - patch_2_clij) >> 1; | |
| 1364 | + *(u16 *)(jit->prg_buf + patch_3_brc + 2) = | |
| 1365 | + (jit->prg - patch_3_brc) >> 1; | |
| 1366 | + } | |
| 1375 | 1367 | break; |
| 1368 | + } | |
| 1376 | 1369 | case BPF_JMP | BPF_EXIT: /* return b0 */ |
| 1377 | 1370 | last = (i == fp->len - 1) ? 1 : 0; |
| 1378 | 1371 | if (last) |
| @@ -314,19 +314,19 @@ static inline void mds_idle_clear_cpu_buffers(void) · 313 unmodified lines | ||
| 314 | 314 | * lfence |
| 315 | 315 | * jmp spec_trap |
| 316 | 316 | * do_rop: |
| 317 | − * mov %rax,(%rsp) for x86_64 | |
| 317 | + * mov %rcx,(%rsp) for x86_64 | |
| 318 | 318 | * mov %edx,(%esp) for x86_32 |
| 319 | 319 | * retq |
| 320 | 320 | * |
| 321 | 321 | * Without retpolines configured: |
| 322 | 322 | * |
| 323 | − * jmp *%rax for x86_64 | |
| 323 | + * jmp *%rcx for x86_64 | |
| 324 | 324 | * jmp *%edx for x86_32 |
| 325 | 325 | */ |
| 326 | 326 | #ifdef CONFIG_RETPOLINE |
| 327 | 327 | # ifdef CONFIG_X86_64 |
| 328 | −# define RETPOLINE_RAX_BPF_JIT_SIZE 17 | |
| 329 | −# define RETPOLINE_RAX_BPF_JIT() \ | |
| 328 | +# define RETPOLINE_RCX_BPF_JIT_SIZE 17 | |
| 329 | +# define RETPOLINE_RCX_BPF_JIT() \ | |
| 330 | 330 | do { \ |
| 331 | 331 | EMIT1_off32(0xE8, 7); /* callq do_rop */ \ |
| 332 | 332 | /* spec_trap: */ \ |
| @@ -334,7 +334,7 @@ do { \ · 1 unmodified line | ||
| 334 | 334 | EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \ |
| 335 | 335 | EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \ |
| 336 | 336 | /* do_rop: */ \ |
| 337 | − EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \ | |
| 337 | + EMIT4(0x48, 0x89, 0x0C, 0x24); /* mov %rcx,(%rsp) */ \ | |
| 338 | 338 | EMIT1(0xC3); /* retq */ \ |
| 339 | 339 | } while (0) |
| 340 | 340 | # else /* !CONFIG_X86_64 */ |
| @@ -352,9 +352,9 @@ do { \ · 11 unmodified lines | ||
| 352 | 352 | # endif |
| 353 | 353 | #else /* !CONFIG_RETPOLINE */ |
| 354 | 354 | # ifdef CONFIG_X86_64 |
| 355 | −# define RETPOLINE_RAX_BPF_JIT_SIZE 2 | |
| 356 | −# define RETPOLINE_RAX_BPF_JIT() \ | |
| 357 | − EMIT2(0xFF, 0xE0); /* jmp *%rax */ | |
| 355 | +# define RETPOLINE_RCX_BPF_JIT_SIZE 2 | |
| 356 | +# define RETPOLINE_RCX_BPF_JIT() \ | |
| 357 | + EMIT2(0xFF, 0xE1); /* jmp *%rcx */ | |
| 358 | 358 | # else /* !CONFIG_X86_64 */ |
| 359 | 359 | # define RETPOLINE_EDX_BPF_JIT() \ |
| 360 | 360 | EMIT2(0xFF, 0xE2) /* jmp *%edx */ |
| @@ -221,14 +221,48 @@ struct jit_context { · 220 unmodified lines | ||
| 221 | 221 | |
| 222 | 222 | /* Number of bytes emit_patch() needs to generate instructions */ |
| 223 | 223 | #define X86_PATCH_SIZE 5 |
| 224 | +/* Number of bytes that will be skipped on tailcall */ | |
| 225 | +#define X86_TAIL_CALL_OFFSET 11 | |
| 224 | 226 | |
| 225 | −#define PROLOGUE_SIZE 25 | |
| 227 | +static void push_callee_regs(u8 **pprog, bool *callee_regs_used) | |
| 228 | +{ | |
| 229 | + u8 *prog = *pprog; | |
| 230 | + int cnt = 0; | |
| 231 | + | |
| 232 | + if (callee_regs_used[0]) | |
| 233 | + EMIT1(0x53); /* push rbx */ | |
| 234 | + if (callee_regs_used[1]) | |
| 235 | + EMIT2(0x41, 0x55); /* push r13 */ | |
| 236 | + if (callee_regs_used[2]) | |
| 237 | + EMIT2(0x41, 0x56); /* push r14 */ | |
| 238 | + if (callee_regs_used[3]) | |
| 239 | + EMIT2(0x41, 0x57); /* push r15 */ | |
| 240 | + *pprog = prog; | |
| 241 | +} | |
| 242 | + | |
| 243 | +static void pop_callee_regs(u8 **pprog, bool *callee_regs_used) | |
| 244 | +{ | |
| 245 | + u8 *prog = *pprog; | |
| 246 | + int cnt = 0; | |
| 247 | + | |
| 248 | + if (callee_regs_used[3]) | |
| 249 | + EMIT2(0x41, 0x5F); /* pop r15 */ | |
| 250 | + if (callee_regs_used[2]) | |
| 251 | + EMIT2(0x41, 0x5E); /* pop r14 */ | |
| 252 | + if (callee_regs_used[1]) | |
| 253 | + EMIT2(0x41, 0x5D); /* pop r13 */ | |
| 254 | + if (callee_regs_used[0]) | |
| 255 | + EMIT1(0x5B); /* pop rbx */ | |
| 256 | + *pprog = prog; | |
| 257 | +} | |
| 226 | 258 | |
| 227 | 259 | /* |
| 228 | − * Emit x86-64 prologue code for BPF program and check its size. | |
| 229 | − * bpf_tail_call helper will skip it while jumping into another program | |
| 260 | + * Emit x86-64 prologue code for BPF program. | |
| 261 | + * bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes | |
| 262 | + * while jumping to another program | |
| 230 | 263 | */ |
| 231 | −static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf) | |
| 264 | +static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf, | |
| 265 | + bool tail_call_reachable, bool is_subprog) | |
| 232 | 266 | { |
| 233 | 267 | u8 *prog = *pprog; |
| 234 | 268 | int cnt = X86_PATCH_SIZE; |
| @@ -238,19 +272,19 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf) · 3 unmodified lines | ||
| 238 | 272 | */ |
| 239 | 273 | memcpy(prog, ideal_nops[NOP_ATOMIC5], cnt); |
| 240 | 274 | prog += cnt; |
| 275 | + if (!ebpf_from_cbpf) { | |
| 276 | + if (tail_call_reachable && !is_subprog) | |
| 277 | + EMIT2(0x31, 0xC0); /* xor eax, eax */ | |
| 278 | + else | |
| 279 | + EMIT2(0x66, 0x90); /* nop2 */ | |
| 280 | + } | |
| 241 | 281 | EMIT1(0x55); /* push rbp */ |
| 242 | 282 | EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */ |
| 243 | 283 | /* sub rsp, rounded_stack_depth */ |
| 244 | − EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8)); | |
| 245 | − EMIT1(0x53); /* push rbx */ | |
| 246 | − EMIT2(0x41, 0x55); /* push r13 */ | |
| 247 | − EMIT2(0x41, 0x56); /* push r14 */ | |
| 248 | − EMIT2(0x41, 0x57); /* push r15 */ | |
| 249 | − if (!ebpf_from_cbpf) { | |
| 250 | − /* zero init tail_call_cnt */ | |
| 251 | − EMIT2(0x6a, 0x00); | |
| 252 | − BUILD_BUG_ON(cnt != PROLOGUE_SIZE); | |
| 253 | − } | |
| 284 | + if (stack_depth) | |
| 285 | + EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8)); | |
| 286 | + if (tail_call_reachable) | |
| 287 | + EMIT1(0x50); /* push rax */ | |
| 254 | 288 | *pprog = prog; |
| 255 | 289 | } |
| 256 | 290 | |
| @@ -314,13 +348,14 @@ static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, · 57 unmodified lines | ||
| 314 | 348 | mutex_lock(&text_mutex); |
| 315 | 349 | if (memcmp(ip, old_insn, X86_PATCH_SIZE)) |
| 316 | 350 | goto out; |
| 351 | + ret = 1; | |
| 317 | 352 | if (memcmp(ip, new_insn, X86_PATCH_SIZE)) { |
| 318 | 353 | if (text_live) |
| 319 | 354 | text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL); |
| 320 | 355 | else |
| 321 | 356 | memcpy(ip, new_insn, X86_PATCH_SIZE); |
| 357 | + ret = 0; | |
| 322 | 358 | } |
| 323 | − ret = 0; | |
| 324 | 359 | out: |
| 325 | 360 | mutex_unlock(&text_mutex); |
| 326 | 361 | return ret; |
| @@ -337,6 +372,22 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, · 10 unmodified lines | ||
| 337 | 372 | return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true); |
| 338 | 373 | } |
| 339 | 374 | |
| 375 | +static int get_pop_bytes(bool *callee_regs_used) | |
| 376 | +{ | |
| 377 | + int bytes = 0; | |
| 378 | + | |
| 379 | + if (callee_regs_used[3]) | |
| 380 | + bytes += 2; | |
| 381 | + if (callee_regs_used[2]) | |
| 382 | + bytes += 2; | |
| 383 | + if (callee_regs_used[1]) | |
| 384 | + bytes += 2; | |
| 385 | + if (callee_regs_used[0]) | |
| 386 | + bytes += 1; | |
| 387 | + | |
| 388 | + return bytes; | |
| 389 | +} | |
| 390 | + | |
| 340 | 391 | /* |
| 341 | 392 | * Generate the following code: |
| 342 | 393 | * |
| @@ -351,12 +402,32 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, · 8 unmodified lines | ||
| 351 | 402 | * goto *(prog->bpf_func + prologue_size); |
| 352 | 403 | * out: |
| 353 | 404 | */ |
| 354 | −static void emit_bpf_tail_call_indirect(u8 **pprog) | |
| 405 | +static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used, | |
| 406 | + u32 stack_depth) | |
| 355 | 407 | { |
| 408 | + int tcc_off = -4 - round_up(stack_depth, 8); | |
| 356 | 409 | u8 *prog = *pprog; |
| 357 | − int label1, label2, label3; | |
| 410 | + int pop_bytes = 0; | |
| 411 | + int off1 = 42; | |
| 412 | + int off2 = 31; | |
| 413 | + int off3 = 9; | |
| 358 | 414 | int cnt = 0; |
| 359 | 415 | |
| 416 | + /* count the additional bytes used for popping callee regs from stack | |
| 417 | + * that need to be taken into account for each of the offsets that | |
| 418 | + * are used for bailing out of the tail call | |
| 419 | + */ | |
| 420 | + pop_bytes = get_pop_bytes(callee_regs_used); | |
| 421 | + off1 += pop_bytes; | |
| 422 | + off2 += pop_bytes; | |
| 423 | + off3 += pop_bytes; | |
| 424 | + | |
| 425 | + if (stack_depth) { | |
| 426 | + off1 += 7; | |
| 427 | + off2 += 7; | |
| 428 | + off3 += 7; | |
| 429 | + } | |
| 430 | + | |
| 360 | 431 | /* |
| 361 | 432 | * rdi - pointer to ctx |
| 362 | 433 | * rsi - pointer to bpf_array |
| @@ -370,72 +441,112 @@ static void emit_bpf_tail_call_indirect(u8 **pprog) · 7 unmodified lines | ||
| 370 | 441 | EMIT2(0x89, 0xD2); /* mov edx, edx */ |
| 371 | 442 | EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */ |
| 372 | 443 | offsetof(struct bpf_array, map.max_entries)); |
| 373 | −#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* Number of bytes to jump */ | |
| 444 | +#define OFFSET1 (off1 + RETPOLINE_RCX_BPF_JIT_SIZE) /* Number of bytes to jump */ | |
| 374 | 445 | EMIT2(X86_JBE, OFFSET1); /* jbe out */ |
| 375 | − label1 = cnt; | |
| 376 | 446 | |
| 377 | 447 | /* |
| 378 | 448 | * if (tail_call_cnt > MAX_TAIL_CALL_CNT) |
| 379 | 449 | * goto out; |
| 380 | 450 | */ |
| 381 | − EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */ | |
| 451 | + EMIT2_off32(0x8B, 0x85, tcc_off); /* mov eax, dword ptr [rbp - tcc_off] */ | |
| 382 | 452 | EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */ |
| 383 | −#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE) | |
| 453 | +#define OFFSET2 (off2 + RETPOLINE_RCX_BPF_JIT_SIZE) | |
| 384 | 454 | EMIT2(X86_JA, OFFSET2); /* ja out */ |
| 385 | − label2 = cnt; | |
| 386 | 455 | EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ |
| 387 | − EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */ | |
| 456 | + EMIT2_off32(0x89, 0x85, tcc_off); /* mov dword ptr [rbp - tcc_off], eax */ | |
| 388 | 457 | |
| 389 | 458 | /* prog = array->ptrs[index]; */ |
| 390 | − EMIT4_off32(0x48, 0x8B, 0x84, 0xD6, /* mov rax, [rsi + rdx * 8 + offsetof(...)] */ | |
| 459 | + EMIT4_off32(0x48, 0x8B, 0x8C, 0xD6, /* mov rcx, [rsi + rdx * 8 + offsetof(...)] */ | |
| 391 | 460 | offsetof(struct bpf_array, ptrs)); |
| 392 | 461 | |
| 393 | 462 | /* |
| 394 | 463 | * if (prog == NULL) |
| 395 | 464 | * goto out; |
| 396 | 465 | */ |
| 397 | − EMIT3(0x48, 0x85, 0xC0); /* test rax,rax */ | |
| 398 | −#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE) | |
| 466 | + EMIT3(0x48, 0x85, 0xC9); /* test rcx,rcx */ | |
| 467 | +#define OFFSET3 (off3 + RETPOLINE_RCX_BPF_JIT_SIZE) | |
| 399 | 468 | EMIT2(X86_JE, OFFSET3); /* je out */ |
| 400 | − label3 = cnt; | |
| 401 | 469 | |
| 402 | − /* goto *(prog->bpf_func + prologue_size); */ | |
| 403 | − EMIT4(0x48, 0x8B, 0x40, /* mov rax, qword ptr [rax + 32] */ | |
| 404 | − offsetof(struct bpf_prog, bpf_func)); | |
| 405 | − EMIT4(0x48, 0x83, 0xC0, PROLOGUE_SIZE); /* add rax, prologue_size */ | |
| 470 | + *pprog = prog; | |
| 471 | + pop_callee_regs(pprog, callee_regs_used); | |
| 472 | + prog = *pprog; | |
| 473 | + | |
| 474 | + EMIT1(0x58); /* pop rax */ | |
| 475 | + if (stack_depth) | |
| 476 | + EMIT3_off32(0x48, 0x81, 0xC4, /* add rsp, sd */ | |
| 477 | + round_up(stack_depth, 8)); | |
| 406 | 478 | |
| 479 | + /* goto *(prog->bpf_func + X86_TAIL_CALL_OFFSET); */ | |
| 480 | + EMIT4(0x48, 0x8B, 0x49, /* mov rcx, qword ptr [rcx + 32] */ | |
| 481 | + offsetof(struct bpf_prog, bpf_func)); | |
| 482 | + EMIT4(0x48, 0x83, 0xC1, /* add rcx, X86_TAIL_CALL_OFFSET */ | |
| 483 | + X86_TAIL_CALL_OFFSET); | |
| 407 | 484 | /* |
| 408 | − * Wow we're ready to jump into next BPF program | |
| 485 | + * Now we're ready to jump into next BPF program | |
| 409 | 486 | * rdi == ctx (1st arg) |
| 410 | − * rax == prog->bpf_func + prologue_size | |
| 487 | + * rcx == prog->bpf_func + X86_TAIL_CALL_OFFSET | |
| 411 | 488 | */ |
| 412 | − RETPOLINE_RAX_BPF_JIT(); | |
| 489 | + RETPOLINE_RCX_BPF_JIT(); | |
| 413 | 490 | |
| 414 | 491 | /* out: */ |
| 415 | − BUILD_BUG_ON(cnt - label1 != OFFSET1); | |
| 416 | − BUILD_BUG_ON(cnt - label2 != OFFSET2); | |
| 417 | − BUILD_BUG_ON(cnt - label3 != OFFSET3); | |
| 418 | 492 | *pprog = prog; |
| 419 | 493 | } |
| 420 | 494 | |
| 421 | 495 | static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke, |
| 422 | − u8 **pprog, int addr, u8 *image) | |
| 496 | + u8 **pprog, int addr, u8 *image, | |
| 497 | + bool *callee_regs_used, u32 stack_depth) | |
| 423 | 498 | { |
| 499 | + int tcc_off = -4 - round_up(stack_depth, 8); | |
| 424 | 500 | u8 *prog = *pprog; |
| 501 | + int pop_bytes = 0; | |
| 502 | + int off1 = 20; | |
| 503 | + int poke_off; | |
| 425 | 504 | int cnt = 0; |
| 426 | 505 | |
| 506 | + /* count the additional bytes used for popping callee regs to stack | |
| 507 | + * that need to be taken into account for jump offset that is used for | |
| 508 | + * bailing out from of the tail call when limit is reached | |
| 509 | + */ | |
| 510 | + pop_bytes = get_pop_bytes(callee_regs_used); | |
| 511 | + off1 += pop_bytes; | |
| 512 | + | |
| 513 | + /* | |
| 514 | + * total bytes for: | |
| 515 | + * - nop5/ jmpq $off | |
| 516 | + * - pop callee regs | |
| 517 | + * - sub rsp, $val if depth > 0 | |
| 518 | + * - pop rax | |
| 519 | + */ | |
| 520 | + poke_off = X86_PATCH_SIZE + pop_bytes + 1; | |
| 521 | + if (stack_depth) { | |
| 522 | + poke_off += 7; | |
| 523 | + off1 += 7; | |
| 524 | + } | |
| 525 | + | |
| 427 | 526 | /* |
| 428 | 527 | * if (tail_call_cnt > MAX_TAIL_CALL_CNT) |
| 429 | 528 | * goto out; |
| 430 | 529 | */ |
| 431 | − EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */ | |
| 530 | + EMIT2_off32(0x8B, 0x85, tcc_off); /* mov eax, dword ptr [rbp - tcc_off] */ | |
| 432 | 531 | EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */ |
| 433 | − EMIT2(X86_JA, 14); /* ja out */ | |
| 532 | + EMIT2(X86_JA, off1); /* ja out */ | |
| 434 | 533 | EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ |
| 435 | − EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */ | |
| 534 | + EMIT2_off32(0x89, 0x85, tcc_off); /* mov dword ptr [rbp - tcc_off], eax */ | |
| 436 | 535 | |
| 437 | − poke->ip = image + (addr - X86_PATCH_SIZE); | |
| 438 | − poke->adj_off = PROLOGUE_SIZE; | |
| 536 | + poke->tailcall_bypass = image + (addr - poke_off - X86_PATCH_SIZE); | |
| 537 | + poke->adj_off = X86_TAIL_CALL_OFFSET; | |
| 538 | + poke->tailcall_target = image + (addr - X86_PATCH_SIZE); | |
| 539 | + poke->bypass_addr = (u8 *)poke->tailcall_target + X86_PATCH_SIZE; | |
| 540 | + | |
| 541 | + emit_jump(&prog, (u8 *)poke->tailcall_target + X86_PATCH_SIZE, | |
| 542 | + poke->tailcall_bypass); | |
| 543 | + | |
| 544 | + *pprog = prog; | |
| 545 | + pop_callee_regs(pprog, callee_regs_used); | |
| 546 | + prog = *pprog; | |
| 547 | + EMIT1(0x58); /* pop rax */ | |
| 548 | + if (stack_depth) | |
| 549 | + EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8)); | |
| 439 | 550 | |
| 440 | 551 | memcpy(prog, ideal_nops[NOP_ATOMIC5], X86_PATCH_SIZE); |
| 441 | 552 | prog += X86_PATCH_SIZE; |
| @@ -453,7 +564,7 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog) · 11 unmodified lines | ||
| 453 | 564 | |
| 454 | 565 | for (i = 0; i < prog->aux->size_poke_tab; i++) { |
| 455 | 566 | poke = &prog->aux->poke_tab[i]; |
| 456 | − WARN_ON_ONCE(READ_ONCE(poke->ip_stable)); | |
| 567 | + WARN_ON_ONCE(READ_ONCE(poke->tailcall_target_stable)); | |
| 457 | 568 | |
| 458 | 569 | if (poke->reason != BPF_POKE_REASON_TAIL_CALL) |
| 459 | 570 | continue; |
| @@ -464,18 +575,25 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog) · 4 unmodified lines | ||
| 464 | 575 | if (target) { |
| 465 | 576 | /* Plain memcpy is used when image is not live yet |
| 466 | 577 | * and still not locked as read-only. Once poke |
| 467 | − * location is active (poke->ip_stable), any parallel | |
| 468 | − * bpf_arch_text_poke() might occur still on the | |
| 469 | − * read-write image until we finally locked it as | |
| 470 | − * read-only. Both modifications on the given image | |
| 471 | − * are under text_mutex to avoid interference. | |
| 578 | + * location is active (poke->tailcall_target_stable), | |
| 579 | + * any parallel bpf_arch_text_poke() might occur | |
| 580 | + * still on the read-write image until we finally | |
| 581 | + * locked it as read-only. Both modifications on | |
| 582 | + * the given image are under text_mutex to avoid | |
| 583 | + * interference. | |
| 472 | 584 | */ |
| 473 | − ret = __bpf_arch_text_poke(poke->ip, BPF_MOD_JUMP, NULL, | |
| 585 | + ret = __bpf_arch_text_poke(poke->tailcall_target, | |
| 586 | + BPF_MOD_JUMP, NULL, | |
| 474 | 587 | (u8 *)target->bpf_func + |
| 475 | 588 | poke->adj_off, false); |
| 476 | 589 | BUG_ON(ret < 0); |
| 590 | + ret = __bpf_arch_text_poke(poke->tailcall_bypass, | |
| 591 | + BPF_MOD_JUMP, | |
| 592 | + (u8 *)poke->tailcall_target + | |
| 593 | + X86_PATCH_SIZE, NULL, false); | |
| 594 | + BUG_ON(ret < 0); | |
| 477 | 595 | } |
| 478 | − WRITE_ONCE(poke->ip_stable, true); | |
| 596 | + WRITE_ONCE(poke->tailcall_target_stable, true); | |
| 479 | 597 | mutex_unlock(&array->aux->poke_mutex); |
| 480 | 598 | } |
| 481 | 599 | } |
| @@ -652,19 +770,49 @@ static bool ex_handler_bpf(const struct exception_table_entry *x, · 170 unmodified lines | ||
| 652 | 770 | return true; |
| 653 | 771 | } |
| 654 | 772 | |
| 773 | +static void detect_reg_usage(struct bpf_insn *insn, int insn_cnt, | |
| 774 | + bool *regs_used, bool *tail_call_seen) | |
| 775 | +{ | |
| 776 | + int i; | |
| 777 | + | |
| 778 | + for (i = 1; i <= insn_cnt; i++, insn++) { | |
| 779 | + if (insn->code == (BPF_JMP | BPF_TAIL_CALL)) | |
| 780 | + *tail_call_seen = true; | |
| 781 | + if (insn->dst_reg == BPF_REG_6 || insn->src_reg == BPF_REG_6) | |
| 782 | + regs_used[0] = true; | |
| 783 | + if (insn->dst_reg == BPF_REG_7 || insn->src_reg == BPF_REG_7) | |
| 784 | + regs_used[1] = true; | |
| 785 | + if (insn->dst_reg == BPF_REG_8 || insn->src_reg == BPF_REG_8) | |
| 786 | + regs_used[2] = true; | |
| 787 | + if (insn->dst_reg == BPF_REG_9 || insn->src_reg == BPF_REG_9) | |
| 788 | + regs_used[3] = true; | |
| 789 | + } | |
| 790 | +} | |
| 791 | + | |
| 655 | 792 | static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, |
| 656 | 793 | int oldproglen, struct jit_context *ctx) |
| 657 | 794 | { |
| 795 | + bool tail_call_reachable = bpf_prog->aux->tail_call_reachable; | |
| 658 | 796 | struct bpf_insn *insn = bpf_prog->insnsi; |
| 797 | + bool callee_regs_used[4] = {}; | |
| 659 | 798 | int insn_cnt = bpf_prog->len; |
| 799 | + bool tail_call_seen = false; | |
| 660 | 800 | bool seen_exit = false; |
| 661 | 801 | u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY]; |
| 662 | 802 | int i, cnt = 0, excnt = 0; |
| 663 | 803 | int proglen = 0; |
| 664 | 804 | u8 *prog = temp; |
| 665 | 805 | |
| 806 | + detect_reg_usage(insn, insn_cnt, callee_regs_used, | |
| 807 | + &tail_call_seen); | |
| 808 | + | |
| 809 | + /* tail call's presence in current prog implies it is reachable */ | |
| 810 | + tail_call_reachable |= tail_call_seen; | |
| 811 | + | |
| 666 | 812 | emit_prologue(&prog, bpf_prog->aux->stack_depth, |
| 667 | − bpf_prog_was_classic(bpf_prog)); | |
| 813 | + bpf_prog_was_classic(bpf_prog), tail_call_reachable, | |
| 814 | + bpf_prog->aux->func_idx != 0); | |
| 815 | + push_callee_regs(&prog, callee_regs_used); | |
| 668 | 816 | addrs[0] = prog - temp; |
| 669 | 817 | |
| 670 | 818 | for (i = 1; i <= insn_cnt; i++, insn++) { |
| @@ -1102,16 +1250,27 @@ xadd: if (is_imm8(insn->off)) · 431 unmodified lines | ||
| 1102 | 1250 | /* call */ |
| 1103 | 1251 | case BPF_JMP | BPF_CALL: |
| 1104 | 1252 | func = (u8 *) __bpf_call_base + imm32; |
| 1105 | − if (!imm32 || emit_call(&prog, func, image + addrs[i - 1])) | |
| 1106 | − return -EINVAL; | |
| 1253 | + if (tail_call_reachable) { | |
| 1254 | + EMIT3_off32(0x48, 0x8B, 0x85, | |
| 1255 | + -(bpf_prog->aux->stack_depth + 8)); | |
| 1256 | + if (!imm32 || emit_call(&prog, func, image + addrs[i - 1] + 7)) | |
| 1257 | + return -EINVAL; | |
| 1258 | + } else { | |
| 1259 | + if (!imm32 || emit_call(&prog, func, image + addrs[i - 1])) | |
| 1260 | + return -EINVAL; | |
| 1261 | + } | |
| 1107 | 1262 | break; |
| 1108 | 1263 | |
| 1109 | 1264 | case BPF_JMP | BPF_TAIL_CALL: |
| 1110 | 1265 | if (imm32) |
| 1111 | 1266 | emit_bpf_tail_call_direct(&bpf_prog->aux->poke_tab[imm32 - 1], |
| 1112 | − &prog, addrs[i], image); | |
| 1267 | + &prog, addrs[i], image, | |
| 1268 | + callee_regs_used, | |
| 1269 | + bpf_prog->aux->stack_depth); | |
| 1113 | 1270 | else |
| 1114 | − emit_bpf_tail_call_indirect(&prog); | |
| 1271 | + emit_bpf_tail_call_indirect(&prog, | |
| 1272 | + callee_regs_used, | |
| 1273 | + bpf_prog->aux->stack_depth); | |
| 1115 | 1274 | break; |
| 1116 | 1275 | |
| 1117 | 1276 | /* cond jump */ |
| @@ -1294,12 +1453,7 @@ emit_jmp: · 176 unmodified lines | ||
| 1294 | 1453 | seen_exit = true; |
| 1295 | 1454 | /* Update cleanup_addr */ |
| 1296 | 1455 | ctx->cleanup_addr = proglen; |
| 1297 | − if (!bpf_prog_was_classic(bpf_prog)) | |
| 1298 | − EMIT1(0x5B); /* get rid of tail_call_cnt */ | |
| 1299 | − EMIT2(0x41, 0x5F); /* pop r15 */ | |
| 1300 | − EMIT2(0x41, 0x5E); /* pop r14 */ | |
| 1301 | − EMIT2(0x41, 0x5D); /* pop r13 */ | |
| 1302 | − EMIT1(0x5B); /* pop rbx */ | |
| 1456 | + pop_callee_regs(&prog, callee_regs_used); | |
| 1303 | 1457 | EMIT1(0xC9); /* leave */ |
| 1304 | 1458 | EMIT1(0xC3); /* ret */ |
| 1305 | 1459 | break; |
| @@ -1379,10 +1533,15 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, · 73 unmodified lines | ||
| 1379 | 1533 | u8 *prog = *pprog; |
| 1380 | 1534 | int cnt = 0; |
| 1381 | 1535 | |
| 1382 | − if (emit_call(&prog, __bpf_prog_enter, prog)) | |
| 1383 | − return -EINVAL; | |
| 1384 | − /* remember prog start time returned by __bpf_prog_enter */ | |
| 1385 | − emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0); | |
| 1536 | + if (p->aux->sleepable) { | |
| 1537 | + if (emit_call(&prog, __bpf_prog_enter_sleepable, prog)) | |
| 1538 | + return -EINVAL; | |
| 1539 | + } else { | |
| 1540 | + if (emit_call(&prog, __bpf_prog_enter, prog)) | |
| 1541 | + return -EINVAL; | |
| 1542 | + /* remember prog start time returned by __bpf_prog_enter */ | |
| 1543 | + emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0); | |
| 1544 | + } | |
| 1386 | 1545 | |
| 1387 | 1546 | /* arg1: lea rdi, [rbp - stack_size] */ |
| 1388 | 1547 | EMIT4(0x48, 0x8D, 0x7D, -stack_size); |
| @@ -1402,13 +1561,18 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, · 13 unmodified lines | ||
| 1402 | 1561 | if (mod_ret) |
| 1403 | 1562 | emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); |
| 1404 | 1563 | |
| 1405 | − /* arg1: mov rdi, progs[i] */ | |
| 1406 | − emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, | |
| 1407 | − (u32) (long) p); | |
| 1408 | − /* arg2: mov rsi, rbx <- start time in nsec */ | |
| 1409 | − emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6); | |
| 1410 | − if (emit_call(&prog, __bpf_prog_exit, prog)) | |
| 1411 | − return -EINVAL; | |
| 1564 | + if (p->aux->sleepable) { | |
| 1565 | + if (emit_call(&prog, __bpf_prog_exit_sleepable, prog)) | |
| 1566 | + return -EINVAL; | |
| 1567 | + } else { | |
| 1568 | + /* arg1: mov rdi, progs[i] */ | |
| 1569 | + emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, | |
| 1570 | + (u32) (long) p); | |
| 1571 | + /* arg2: mov rsi, rbx <- start time in nsec */ | |
| 1572 | + emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6); | |
| 1573 | + if (emit_call(&prog, __bpf_prog_exit, prog)) | |
| 1574 | + return -EINVAL; | |
| 1575 | + } | |
| 1412 | 1576 | |
| 1413 | 1577 | *pprog = prog; |
| 1414 | 1578 | return 0; |
| @@ -327,7 +327,7 @@ done: · 326 unmodified lines | ||
| 327 | 327 | */ |
| 328 | 328 | |
| 329 | 329 | |
| 330 | −static struct atmdev_ops atmtcp_v_dev_ops = { | |
| 330 | +static const struct atmdev_ops atmtcp_v_dev_ops = { | |
| 331 | 331 | .dev_close = atmtcp_v_dev_close, |
| 332 | 332 | .open = atmtcp_v_open, |
| 333 | 333 | .close = atmtcp_v_close, |
| @@ -419,12 +419,12 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) · 418 unmodified lines | ||
| 419 | 419 | pc_host->pci_ops.read = bcma_core_pci_hostmode_read_config; |
| 420 | 420 | pc_host->pci_ops.write = bcma_core_pci_hostmode_write_config; |
| 421 | 421 | |
| 422 | − pc_host->mem_resource.name = "BCMA PCIcore external memory", | |
| 422 | + pc_host->mem_resource.name = "BCMA PCIcore external memory"; | |
| 423 | 423 | pc_host->mem_resource.start = BCMA_SOC_PCI_DMA; |
| 424 | 424 | pc_host->mem_resource.end = BCMA_SOC_PCI_DMA + BCMA_SOC_PCI_DMA_SZ - 1; |
| 425 | 425 | pc_host->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; |
| 426 | 426 | |
| 427 | − pc_host->io_resource.name = "BCMA PCIcore external I/O", | |
| 427 | + pc_host->io_resource.name = "BCMA PCIcore external I/O"; | |
| 428 | 428 | pc_host->io_resource.start = 0x100; |
| 429 | 429 | pc_host->io_resource.end = 0x7FF; |
| 430 | 430 | pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED; |
| @@ -2184,7 +2184,7 @@ out: · 2183 unmodified lines | ||
| 2184 | 2184 | return ret; |
| 2185 | 2185 | } |
| 2186 | 2186 | |
| 2187 | −static const struct genl_ops nbd_connect_genl_ops[] = { | |
| 2187 | +static const struct genl_small_ops nbd_connect_genl_ops[] = { | |
| 2188 | 2188 | { |
| 2189 | 2189 | .cmd = NBD_CMD_CONNECT, |
| 2190 | 2190 | .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
| @@ -2216,8 +2216,8 @@ static struct genl_family nbd_genl_family __ro_after_init = { · 25 unmodified lines | ||
| 2216 | 2216 | .name = NBD_GENL_FAMILY_NAME, |
| 2217 | 2217 | .version = NBD_GENL_VERSION, |
| 2218 | 2218 | .module = THIS_MODULE, |
| 2219 | − .ops = nbd_connect_genl_ops, | |
| 2220 | − .n_ops = ARRAY_SIZE(nbd_connect_genl_ops), | |
| 2219 | + .small_ops = nbd_connect_genl_ops, | |
| 2220 | + .n_small_ops = ARRAY_SIZE(nbd_connect_genl_ops), | |
| 2221 | 2221 | .maxattr = NBD_ATTR_MAX, |
| 2222 | 2222 | .policy = nbd_attr_policy, |
| 2223 | 2223 | .mcgrps = nbd_mcast_grps, |
| @@ -18,7 +18,11 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #define VERSION "0.1" |
| 20 | 20 | |
| 21 | −#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) | |
| 21 | +#define BDADDR_INTEL (&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) | |
| 22 | +#define RSA_HEADER_LEN 644 | |
| 23 | +#define CSS_HEADER_OFFSET 8 | |
| 24 | +#define ECDSA_OFFSET 644 | |
| 25 | +#define ECDSA_HEADER_LEN 320 | |
| 22 | 26 | |
| 23 | 27 | int btintel_check_bdaddr(struct hci_dev *hdev) |
| 24 | 28 | { |
| @@ -360,6 +364,144 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver) · 335 unmodified lines | ||
| 360 | 364 | } |
| 361 | 365 | EXPORT_SYMBOL_GPL(btintel_read_version); |
| 362 | 366 | |
| 367 | +void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version) | |
| 368 | +{ | |
| 369 | + const char *variant; | |
| 370 | + | |
| 371 | + switch (version->img_type) { | |
| 372 | + case 0x01: | |
| 373 | + variant = "Bootloader"; | |
| 374 | + bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id); | |
| 375 | + bt_dev_info(hdev, "Secure boot is %s", | |
| 376 | + version->secure_boot ? "enabled" : "disabled"); | |
| 377 | + bt_dev_info(hdev, "OTP lock is %s", | |
| 378 | + version->otp_lock ? "enabled" : "disabled"); | |
| 379 | + bt_dev_info(hdev, "API lock is %s", | |
| 380 | + version->api_lock ? "enabled" : "disabled"); | |
| 381 | + bt_dev_info(hdev, "Debug lock is %s", | |
| 382 | + version->debug_lock ? "enabled" : "disabled"); | |
| 383 | + bt_dev_info(hdev, "Minimum firmware build %u week %u %u", | |
| 384 | + version->min_fw_build_nn, version->min_fw_build_cw, | |
| 385 | + 2000 + version->min_fw_build_yy); | |
| 386 | + break; | |
| 387 | + case 0x03: | |
| 388 | + variant = "Firmware"; | |
| 389 | + break; | |
| 390 | + default: | |
| 391 | + bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type); | |
| 392 | + goto done; | |
| 393 | + } | |
| 394 | + | |
| 395 | + bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant, | |
| 396 | + 2000 + (version->timestamp >> 8), version->timestamp & 0xff, | |
| 397 | + version->build_type, version->build_num); | |
| 398 | + | |
| 399 | +done: | |
| 400 | + return; | |
| 401 | +} | |
| 402 | +EXPORT_SYMBOL_GPL(btintel_version_info_tlv); | |
| 403 | + | |
| 404 | +int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version) | |
| 405 | +{ | |
| 406 | + struct sk_buff *skb; | |
| 407 | + const u8 param[1] = { 0xFF }; | |
| 408 | + | |
| 409 | + if (!version) | |
| 410 | + return -EINVAL; | |
| 411 | + | |
| 412 | + skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT); | |
| 413 | + if (IS_ERR(skb)) { | |
| 414 | + bt_dev_err(hdev, "Reading Intel version information failed (%ld)", | |
| 415 | + PTR_ERR(skb)); | |
| 416 | + return PTR_ERR(skb); | |
| 417 | + } | |
| 418 | + | |
| 419 | + if (skb->data[0]) { | |
| 420 | + bt_dev_err(hdev, "Intel Read Version command failed (%02x)", | |
| 421 | + skb->data[0]); | |
| 422 | + kfree_skb(skb); | |
| 423 | + return -EIO; | |
| 424 | + } | |
| 425 | + | |
| 426 | + /* Consume Command Complete Status field */ | |
| 427 | + skb_pull(skb, 1); | |
| 428 | + | |
| 429 | + /* Event parameters contatin multiple TLVs. Read each of them | |
| 430 | + * and only keep the required data. Also, it use existing legacy | |
| 431 | + * version field like hw_platform, hw_variant, and fw_variant | |
| 432 | + * to keep the existing setup flow | |
| 433 | + */ | |
| 434 | + while (skb->len) { | |
| 435 | + struct intel_tlv *tlv; | |
| 436 | + | |
| 437 | + tlv = (struct intel_tlv *)skb->data; | |
| 438 | + switch (tlv->type) { | |
| 439 | + case INTEL_TLV_CNVI_TOP: | |
| 440 | + version->cnvi_top = get_unaligned_le32(tlv->val); | |
| 441 | + break; | |
| 442 | + case INTEL_TLV_CNVR_TOP: | |
| 443 | + version->cnvr_top = get_unaligned_le32(tlv->val); | |
| 444 | + break; | |
| 445 | + case INTEL_TLV_CNVI_BT: | |
| 446 | + version->cnvi_bt = get_unaligned_le32(tlv->val); | |
| 447 | + break; | |
| 448 | + case INTEL_TLV_CNVR_BT: | |
| 449 | + version->cnvr_bt = get_unaligned_le32(tlv->val); | |
| 450 | + break; | |
| 451 | + case INTEL_TLV_DEV_REV_ID: | |
| 452 | + version->dev_rev_id = get_unaligned_le16(tlv->val); | |
| 453 | + break; | |
| 454 | + case INTEL_TLV_IMAGE_TYPE: | |
| 455 | + version->img_type = tlv->val[0]; | |
| 456 | + break; | |
| 457 | + case INTEL_TLV_TIME_STAMP: | |
| 458 | + version->timestamp = get_unaligned_le16(tlv->val); | |
| 459 | + break; | |
| 460 | + case INTEL_TLV_BUILD_TYPE: | |
| 461 | + version->build_type = tlv->val[0]; | |
| 462 | + break; | |
| 463 | + case INTEL_TLV_BUILD_NUM: | |
| 464 | + version->build_num = get_unaligned_le32(tlv->val); | |
| 465 | + break; | |
| 466 | + case INTEL_TLV_SECURE_BOOT: | |
| 467 | + version->secure_boot = tlv->val[0]; | |
| 468 | + break; | |
| 469 | + case INTEL_TLV_OTP_LOCK: | |
| 470 | + version->otp_lock = tlv->val[0]; | |
| 471 | + break; | |
| 472 | + case INTEL_TLV_API_LOCK: | |
| 473 | + version->api_lock = tlv->val[0]; | |
| 474 | + break; | |
| 475 | + case INTEL_TLV_DEBUG_LOCK: | |
| 476 | + version->debug_lock = tlv->val[0]; | |
| 477 | + break; | |
| 478 | + case INTEL_TLV_MIN_FW: | |
| 479 | + version->min_fw_build_nn = tlv->val[0]; | |
| 480 | + version->min_fw_build_cw = tlv->val[1]; | |
| 481 | + version->min_fw_build_yy = tlv->val[2]; | |
| 482 | + break; | |
| 483 | + case INTEL_TLV_LIMITED_CCE: | |
| 484 | + version->limited_cce = tlv->val[0]; | |
| 485 | + break; | |
| 486 | + case INTEL_TLV_SBE_TYPE: | |
| 487 | + version->sbe_type = tlv->val[0]; | |
| 488 | + break; | |
| 489 | + case INTEL_TLV_OTP_BDADDR: | |
| 490 | + memcpy(&version->otp_bd_addr, tlv->val, tlv->len); | |
| 491 | + break; | |
| 492 | + default: | |
| 493 | + /* Ignore rest of information */ | |
| 494 | + break; | |
| 495 | + } | |
| 496 | + /* consume the current tlv and move to next*/ | |
| 497 | + skb_pull(skb, tlv->len + sizeof(*tlv)); | |
| 498 | + } | |
| 499 | + | |
| 500 | + kfree_skb(skb); | |
| 501 | + return 0; | |
| 502 | +} | |
| 503 | +EXPORT_SYMBOL_GPL(btintel_read_version_tlv); | |
| 504 | + | |
| 363 | 505 | /* ------- REGMAP IBT SUPPORT ------- */ |
| 364 | 506 | |
| 365 | 507 | #define IBT_REG_MODE_8BIT 0x00 |
| @@ -626,12 +768,10 @@ int btintel_read_boot_params(struct hci_dev *hdev, · 260 unmodified lines | ||
| 626 | 768 | } |
| 627 | 769 | EXPORT_SYMBOL_GPL(btintel_read_boot_params); |
| 628 | 770 | |
| 629 | −int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw, | |
| 630 | − u32 *boot_param) | |
| 771 | +static int btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev, | |
| 772 | + const struct firmware *fw) | |
| 631 | 773 | { |
| 632 | 774 | int err; |
| 633 | − const u8 *fw_ptr; | |
| 634 | − u32 frag_len; | |
| 635 | 775 | |
| 636 | 776 | /* Start the firmware download transaction with the Init fragment |
| 637 | 777 | * represented by the 128 bytes of CSS header. |
| @@ -660,8 +800,56 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw, · 22 unmodified lines | ||
| 660 | 800 | goto done; |
| 661 | 801 | } |
| 662 | 802 | |
| 663 | − fw_ptr = fw->data + 644; | |
| 803 | +done: | |
| 804 | + return err; | |
| 805 | +} | |
| 806 | + | |
| 807 | +static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev, | |
| 808 | + const struct firmware *fw) | |
| 809 | +{ | |
| 810 | + int err; | |
| 811 | + | |
| 812 | + /* Start the firmware download transaction with the Init fragment | |
| 813 | + * represented by the 128 bytes of CSS header. | |
| 814 | + */ | |
| 815 | + err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644); | |
| 816 | + if (err < 0) { | |
| 817 | + bt_dev_err(hdev, "Failed to send firmware header (%d)", err); | |
| 818 | + return err; | |
| 819 | + } | |
| 820 | + | |
| 821 | + /* Send the 96 bytes of public key information from the firmware | |
| 822 | + * as the PKey fragment. | |
| 823 | + */ | |
| 824 | + err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128); | |
| 825 | + if (err < 0) { | |
| 826 | + bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err); | |
| 827 | + return err; | |
| 828 | + } | |
| 829 | + | |
| 830 | + /* Send the 96 bytes of signature information from the firmware | |
| 831 | + * as the Sign fragment | |
| 832 | + */ | |
| 833 | + err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224); | |
| 834 | + if (err < 0) { | |
| 835 | + bt_dev_err(hdev, "Failed to send firmware signature (%d)", | |
| 836 | + err); | |
| 837 | + return err; | |
| 838 | + } | |
| 839 | + return 0; | |
| 840 | +} | |
| 841 | + | |
| 842 | +static int btintel_download_firmware_payload(struct hci_dev *hdev, | |
| 843 | + const struct firmware *fw, | |
| 844 | + u32 *boot_param, size_t offset) | |
| 845 | +{ | |
| 846 | + int err; | |
| 847 | + const u8 *fw_ptr; | |
| 848 | + u32 frag_len; | |
| 849 | + | |
| 850 | + fw_ptr = fw->data + offset; | |
| 664 | 851 | frag_len = 0; |
| 852 | + err = -EINVAL; | |
| 665 | 853 | |
| 666 | 854 | while (fw_ptr - fw->data < fw->size) { |
| 667 | 855 | struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); |
| @@ -707,8 +895,99 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw, · 39 unmodified lines | ||
| 707 | 895 | done: |
| 708 | 896 | return err; |
| 709 | 897 | } |
| 898 | + | |
| 899 | +int btintel_download_firmware(struct hci_dev *hdev, | |
| 900 | + const struct firmware *fw, | |
| 901 | + u32 *boot_param) | |
| 902 | +{ | |
| 903 | + int err; | |
| 904 | + | |
| 905 | + err = btintel_sfi_rsa_header_secure_send(hdev, fw); | |
| 906 | + if (err) | |
| 907 | + return err; | |
| 908 | + | |
| 909 | + return btintel_download_firmware_payload(hdev, fw, boot_param, | |
| 910 | + RSA_HEADER_LEN); | |
| 911 | +} | |
| 710 | 912 | EXPORT_SYMBOL_GPL(btintel_download_firmware); |
| 711 | 913 | |
| 914 | +int btintel_download_firmware_newgen(struct hci_dev *hdev, | |
| 915 | + const struct firmware *fw, u32 *boot_param, | |
| 916 | + u8 hw_variant, u8 sbe_type) | |
| 917 | +{ | |
| 918 | + int err; | |
| 919 | + u32 css_header_ver; | |
| 920 | + | |
| 921 | + /* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support | |
| 922 | + * only RSA secure boot engine. Hence, the corresponding sfi file will | |
| 923 | + * have RSA header of 644 bytes followed by Command Buffer. | |
| 924 | + * | |
| 925 | + * iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA | |
| 926 | + * secure boot engine. As a result, the corresponding sfi file will | |
| 927 | + * have RSA header of 644, ECDSA header of 320 bytes followed by | |
| 928 | + * Command Buffer. | |
| 929 | + * | |
| 930 | + * CSS Header byte positions 0x08 to 0x0B represent the CSS Header | |
| 931 | + * version: RSA(0x00010000) , ECDSA (0x00020000) | |
| 932 | + */ | |
| 933 | + css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET); | |
| 934 | + if (css_header_ver != 0x00010000) { | |
| 935 | + bt_dev_err(hdev, "Invalid CSS Header version"); | |
| 936 | + return -EINVAL; | |
| 937 | + } | |
| 938 | + | |
| 939 | + if (hw_variant <= 0x14) { | |
| 940 | + if (sbe_type != 0x00) { | |
| 941 | + bt_dev_err(hdev, "Invalid SBE type for hardware variant (%d)", | |
| 942 | + hw_variant); | |
| 943 | + return -EINVAL; | |
| 944 | + } | |
| 945 | + | |
| 946 | + err = btintel_sfi_rsa_header_secure_send(hdev, fw); | |
| 947 | + if (err) | |
| 948 | + return err; | |
| 949 | + | |
| 950 | + err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN); | |
| 951 | + if (err) | |
| 952 | + return err; | |
| 953 | + } else if (hw_variant >= 0x17) { | |
| 954 | + /* Check if CSS header for ECDSA follows the RSA header */ | |
| 955 | + if (fw->data[ECDSA_OFFSET] != 0x06) | |
| 956 | + return -EINVAL; | |
| 957 | + | |
| 958 | + /* Check if the CSS Header version is ECDSA(0x00020000) */ | |
| 959 | + css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET); | |
| 960 | + if (css_header_ver != 0x00020000) { | |
| 961 | + bt_dev_err(hdev, "Invalid CSS Header version"); | |
| 962 | + return -EINVAL; | |
| 963 | + } | |
| 964 | + | |
| 965 | + if (sbe_type == 0x00) { | |
| 966 | + err = btintel_sfi_rsa_header_secure_send(hdev, fw); | |
| 967 | + if (err) | |
| 968 | + return err; | |
| 969 | + | |
| 970 | + err = btintel_download_firmware_payload(hdev, fw, | |
| 971 | + boot_param, | |
| 972 | + RSA_HEADER_LEN + ECDSA_HEADER_LEN); | |
| 973 | + if (err) | |
| 974 | + return err; | |
| 975 | + } else if (sbe_type == 0x01) { | |
| 976 | + err = btintel_sfi_ecdsa_header_secure_send(hdev, fw); | |
| 977 | + if (err) | |
| 978 | + return err; | |
| 979 | + | |
| 980 | + err = btintel_download_firmware_payload(hdev, fw, | |
| 981 | + boot_param, | |
| 982 | + RSA_HEADER_LEN + ECDSA_HEADER_LEN); | |
| 983 | + if (err) | |
| 984 | + return err; | |
| 985 | + } | |
| 986 | + } | |
| 987 | + return 0; | |
| 988 | +} | |
| 989 | +EXPORT_SYMBOL_GPL(btintel_download_firmware_newgen); | |
| 990 | + | |
| 712 | 991 | void btintel_reset_to_bootloader(struct hci_dev *hdev) |
| 713 | 992 | { |
| 714 | 993 | struct intel_reset params; |
| @@ -6,6 +6,72 @@ · 5 unmodified lines | ||
| 6 | 6 | * Copyright (C) 2015 Intel Corporation |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | +/* List of tlv type */ | |
| 10 | +enum { | |
| 11 | + INTEL_TLV_CNVI_TOP = 0x10, | |
| 12 | + INTEL_TLV_CNVR_TOP, | |
| 13 | + INTEL_TLV_CNVI_BT, | |
| 14 | + INTEL_TLV_CNVR_BT, | |
| 15 | + INTEL_TLV_CNVI_OTP, | |
| 16 | + INTEL_TLV_CNVR_OTP, | |
| 17 | + INTEL_TLV_DEV_REV_ID, | |
| 18 | + INTEL_TLV_USB_VENDOR_ID, | |
| 19 | + INTEL_TLV_USB_PRODUCT_ID, | |
| 20 | + INTEL_TLV_PCIE_VENDOR_ID, | |
| 21 | + INTEL_TLV_PCIE_DEVICE_ID, | |
| 22 | + INTEL_TLV_PCIE_SUBSYSTEM_ID, | |
| 23 | + INTEL_TLV_IMAGE_TYPE, | |
| 24 | + INTEL_TLV_TIME_STAMP, | |
| 25 | + INTEL_TLV_BUILD_TYPE, | |
| 26 | + INTEL_TLV_BUILD_NUM, | |
| 27 | + INTEL_TLV_FW_BUILD_PRODUCT, | |
| 28 | + INTEL_TLV_FW_BUILD_HW, | |
| 29 | + INTEL_TLV_FW_STEP, | |
| 30 | + INTEL_TLV_BT_SPEC, | |
| 31 | + INTEL_TLV_MFG_NAME, | |
| 32 | + INTEL_TLV_HCI_REV, | |
| 33 | + INTEL_TLV_LMP_SUBVER, | |
| 34 | + INTEL_TLV_OTP_PATCH_VER, | |
| 35 | + INTEL_TLV_SECURE_BOOT, | |
| 36 | + INTEL_TLV_KEY_FROM_HDR, | |
| 37 | + INTEL_TLV_OTP_LOCK, | |
| 38 | + INTEL_TLV_API_LOCK, | |
| 39 | + INTEL_TLV_DEBUG_LOCK, | |
| 40 | + INTEL_TLV_MIN_FW, | |
| 41 | + INTEL_TLV_LIMITED_CCE, | |
| 42 | + INTEL_TLV_SBE_TYPE, | |
| 43 | + INTEL_TLV_OTP_BDADDR, | |
| 44 | + INTEL_TLV_UNLOCKED_STATE | |
| 45 | +}; | |
| 46 | + | |
| 47 | +struct intel_tlv { | |
| 48 | + u8 type; | |
| 49 | + u8 len; | |
| 50 | + u8 val[0]; | |
| 51 | +} __packed; | |
| 52 | + | |
| 53 | +struct intel_version_tlv { | |
| 54 | + u32 cnvi_top; | |
| 55 | + u32 cnvr_top; | |
| 56 | + u32 cnvi_bt; | |
| 57 | + u32 cnvr_bt; | |
| 58 | + u16 dev_rev_id; | |
| 59 | + u8 img_type; | |
| 60 | + u16 timestamp; | |
| 61 | + u8 build_type; | |
| 62 | + u32 build_num; | |
| 63 | + u8 secure_boot; | |
| 64 | + u8 otp_lock; | |
| 65 | + u8 api_lock; | |
| 66 | + u8 debug_lock; | |
| 67 | + u8 min_fw_build_nn; | |
| 68 | + u8 min_fw_build_cw; | |
| 69 | + u8 min_fw_build_yy; | |
| 70 | + u8 limited_cce; | |
| 71 | + u8 sbe_type; | |
| 72 | + bdaddr_t otp_bd_addr; | |
| 73 | +}; | |
| 74 | + | |
| 9 | 75 | struct intel_version { |
| 10 | 76 | u8 status; |
| 11 | 77 | u8 hw_platform; |
| @@ -77,12 +143,14 @@ int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable); · 65 unmodified lines | ||
| 77 | 143 | void btintel_hw_error(struct hci_dev *hdev, u8 code); |
| 78 | 144 | |
| 79 | 145 | void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver); |
| 146 | +void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version); | |
| 80 | 147 | int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, |
| 81 | 148 | const void *param); |
| 82 | 149 | int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name); |
| 83 | 150 | int btintel_set_event_mask(struct hci_dev *hdev, bool debug); |
| 84 | 151 | int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug); |
| 85 | 152 | int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver); |
| 153 | +int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver); | |
| 86 | 154 | |
| 87 | 155 | struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read, |
| 88 | 156 | u16 opcode_write); |
| @@ -91,6 +159,10 @@ int btintel_read_boot_params(struct hci_dev *hdev, · 2 unmodified lines | ||
| 91 | 159 | struct intel_boot_params *params); |
| 92 | 160 | int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw, |
| 93 | 161 | u32 *boot_param); |
| 162 | +int btintel_download_firmware_newgen(struct hci_dev *hdev, | |
| 163 | + const struct firmware *fw, | |
| 164 | + u32 *boot_param, u8 hw_variant, | |
| 165 | + u8 sbe_type); | |
| 94 | 166 | void btintel_reset_to_bootloader(struct hci_dev *hdev); |
| 95 | 167 | int btintel_read_debug_features(struct hci_dev *hdev, |
| 96 | 168 | struct intel_debug_features *features); |
| @@ -137,6 +209,11 @@ static inline void btintel_version_info(struct hci_dev *hdev, · 40 unmodified lines | ||
| 137 | 209 | { |
| 138 | 210 | } |
| 139 | 211 | |
| 212 | +static inline void btintel_version_info_tlv(struct hci_dev *hdev, | |
| 213 | + struct intel_version_tlv *version) | |
| 214 | +{ | |
| 215 | +} | |
| 216 | + | |
| 140 | 217 | static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, |
| 141 | 218 | u32 plen, const void *param) |
| 142 | 219 | { |
| @@ -165,6 +242,12 @@ static inline int btintel_read_version(struct hci_dev *hdev, · 22 unmodified lines | ||
| 165 | 242 | return -EOPNOTSUPP; |
| 166 | 243 | } |
| 167 | 244 | |
| 245 | +static inline int btintel_read_version_tlv(struct hci_dev *hdev, | |
| 246 | + struct intel_version_tlv *ver) | |
| 247 | +{ | |
| 248 | + return -EOPNOTSUPP; | |
| 249 | +} | |
| 250 | + | |
| 168 | 251 | static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev, |
| 169 | 252 | u16 opcode_read, |
| 170 | 253 | u16 opcode_write) |
| @@ -191,6 +274,14 @@ static inline int btintel_download_firmware(struct hci_dev *dev, · 20 unmodified lines | ||
| 191 | 274 | return -EOPNOTSUPP; |
| 192 | 275 | } |
| 193 | 276 | |
| 277 | +static inline int btintel_download_firmware_newgen(struct hci_dev *hdev, | |
| 278 | + const struct firmware *fw, | |
| 279 | + u32 *boot_param, | |
| 280 | + u8 hw_variant, u8 sbe_type) | |
| 281 | +{ | |
| 282 | + return -EOPNOTSUPP; | |
| 283 | +} | |
| 284 | + | |
| 194 | 285 | static inline void btintel_reset_to_bootloader(struct hci_dev *hdev) |
| 195 | 286 | { |
| 196 | 287 | } |
| @@ -215,30 +215,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { · 214 unmodified lines | ||
| 215 | 215 | .fw_dump_end = 0xea, |
| 216 | 216 | }; |
| 217 | 217 | |
| 218 | −static const struct btmrvl_sdio_card_reg btmrvl_reg_8977 = { | |
| 219 | − .cfg = 0x00, | |
| 220 | − .host_int_mask = 0x08, | |
| 221 | − .host_intstatus = 0x0c, | |
| 222 | − .card_status = 0x5c, | |
| 223 | − .sq_read_base_addr_a0 = 0xf8, | |
| 224 | − .sq_read_base_addr_a1 = 0xf9, | |
| 225 | − .card_revision = 0xc8, | |
| 226 | − .card_fw_status0 = 0xe8, | |
| 227 | − .card_fw_status1 = 0xe9, | |
| 228 | − .card_rx_len = 0xea, | |
| 229 | − .card_rx_unit = 0xeb, | |
| 230 | − .io_port_0 = 0xe4, | |
| 231 | − .io_port_1 = 0xe5, | |
| 232 | − .io_port_2 = 0xe6, | |
| 233 | − .int_read_to_clear = true, | |
| 234 | − .host_int_rsr = 0x04, | |
| 235 | − .card_misc_cfg = 0xD8, | |
| 236 | − .fw_dump_ctrl = 0xf0, | |
| 237 | − .fw_dump_start = 0xf1, | |
| 238 | − .fw_dump_end = 0xf8, | |
| 239 | −}; | |
| 240 | − | |
| 241 | −static const struct btmrvl_sdio_card_reg btmrvl_reg_8987 = { | |
| 218 | +static const struct btmrvl_sdio_card_reg btmrvl_reg_89xx = { | |
| 242 | 219 | .cfg = 0x00, |
| 243 | 220 | .host_int_mask = 0x08, |
| 244 | 221 | .host_intstatus = 0x0c, |
| @@ -261,29 +238,6 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8987 = { · 16 unmodified lines | ||
| 261 | 238 | .fw_dump_end = 0xf8, |
| 262 | 239 | }; |
| 263 | 240 | |
| 264 | −static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = { | |
| 265 | − .cfg = 0x00, | |
| 266 | − .host_int_mask = 0x08, | |
| 267 | − .host_intstatus = 0x0c, | |
| 268 | − .card_status = 0x5c, | |
| 269 | − .sq_read_base_addr_a0 = 0xf8, | |
| 270 | − .sq_read_base_addr_a1 = 0xf9, | |
| 271 | − .card_revision = 0xc8, | |
| 272 | − .card_fw_status0 = 0xe8, | |
| 273 | − .card_fw_status1 = 0xe9, | |
| 274 | − .card_rx_len = 0xea, | |
| 275 | − .card_rx_unit = 0xeb, | |
| 276 | − .io_port_0 = 0xe4, | |
| 277 | − .io_port_1 = 0xe5, | |
| 278 | − .io_port_2 = 0xe6, | |
| 279 | − .int_read_to_clear = true, | |
| 280 | − .host_int_rsr = 0x04, | |
| 281 | − .card_misc_cfg = 0xD8, | |
| 282 | − .fw_dump_ctrl = 0xf0, | |
| 283 | − .fw_dump_start = 0xf1, | |
| 284 | − .fw_dump_end = 0xf8, | |
| 285 | −}; | |
| 286 | − | |
| 287 | 241 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { |
| 288 | 242 | .helper = "mrvl/sd8688_helper.bin", |
| 289 | 243 | .firmware = "mrvl/sd8688.bin", |
| @@ -332,7 +286,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { · 42 unmodified lines | ||
| 332 | 286 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = { |
| 333 | 287 | .helper = NULL, |
| 334 | 288 | .firmware = "mrvl/sdsd8977_combo_v2.bin", |
| 335 | − .reg = &btmrvl_reg_8977, | |
| 289 | + .reg = &btmrvl_reg_89xx, | |
| 336 | 290 | .support_pscan_win_report = true, |
| 337 | 291 | .sd_blksz_fw_dl = 256, |
| 338 | 292 | .supports_fw_dump = true, |
| @@ -341,7 +295,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = { · 2 unmodified lines | ||
| 341 | 295 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = { |
| 342 | 296 | .helper = NULL, |
| 343 | 297 | .firmware = "mrvl/sd8987_uapsta.bin", |
| 344 | − .reg = &btmrvl_reg_8987, | |
| 298 | + .reg = &btmrvl_reg_89xx, | |
| 345 | 299 | .support_pscan_win_report = true, |
| 346 | 300 | .sd_blksz_fw_dl = 256, |
| 347 | 301 | .supports_fw_dump = true, |
| @@ -350,7 +304,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = { · 2 unmodified lines | ||
| 350 | 304 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = { |
| 351 | 305 | .helper = NULL, |
| 352 | 306 | .firmware = "mrvl/sdsd8997_combo_v4.bin", |
| 353 | − .reg = &btmrvl_reg_8997, | |
| 307 | + .reg = &btmrvl_reg_89xx, | |
| 354 | 308 | .support_pscan_win_report = true, |
| 355 | 309 | .sd_blksz_fw_dl = 256, |
| 356 | 310 | .supports_fw_dump = true, |
| @@ -496,7 +496,7 @@ static void btmtksdio_interrupt(struct sdio_func *func) · 495 unmodified lines | ||
| 496 | 496 | sdio_claim_host(bdev->func); |
| 497 | 497 | |
| 498 | 498 | /* Disable interrupt */ |
| 499 | − sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0); | |
| 499 | + sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL); | |
| 500 | 500 | |
| 501 | 501 | int_status = sdio_readl(func, MTK_REG_CHISR, NULL); |
| 502 | 502 | |
| @@ -530,7 +530,7 @@ static void btmtksdio_interrupt(struct sdio_func *func) · 27 unmodified lines | ||
| 530 | 530 | } |
| 531 | 531 | |
| 532 | 532 | /* Enable interrupt */ |
| 533 | − sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, 0); | |
| 533 | + sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL); | |
| 534 | 534 | |
| 535 | 535 | pm_runtime_mark_last_busy(bdev->dev); |
| 536 | 536 | pm_runtime_put_autosuspend(bdev->dev); |
| @@ -59,6 +59,7 @@ static struct usb_driver btusb_driver; · 58 unmodified lines | ||
| 59 | 59 | #define BTUSB_MEDIATEK 0x200000 |
| 60 | 60 | #define BTUSB_WIDEBAND_SPEECH 0x400000 |
| 61 | 61 | #define BTUSB_VALID_LE_STATES 0x800000 |
| 62 | +#define BTUSB_QCA_WCN6855 0x1000000 | |
| 62 | 63 | |
| 63 | 64 | static const struct usb_device_id btusb_table[] = { |
| 64 | 65 | /* Generic Bluetooth USB device */ |
| @@ -254,24 +255,46 @@ static const struct usb_device_id blacklist_table[] = { · 189 unmodified lines | ||
| 254 | 255 | { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, |
| 255 | 256 | |
| 256 | 257 | /* QCA ROME chipset */ |
| 257 | − { USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME }, | |
| 258 | − { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME }, | |
| 259 | − { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME }, | |
| 260 | − { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME }, | |
| 261 | − { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME }, | |
| 262 | − { USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME }, | |
| 263 | − { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME }, | |
| 264 | − { USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME }, | |
| 265 | − { USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME }, | |
| 266 | − { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME }, | |
| 267 | − { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, | |
| 268 | − { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME }, | |
| 269 | − { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, | |
| 270 | − { USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME }, | |
| 271 | − { USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME }, | |
| 272 | − { USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME }, | |
| 273 | − { USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME }, | |
| 274 | − { USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME }, | |
| 258 | + { USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME | | |
| 259 | + BTUSB_WIDEBAND_SPEECH }, | |
| 260 | + { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME | | |
| 261 | + BTUSB_WIDEBAND_SPEECH }, | |
| 262 | + { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME | | |
| 263 | + BTUSB_WIDEBAND_SPEECH }, | |
| 264 | + { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME | | |
| 265 | + BTUSB_WIDEBAND_SPEECH }, | |
| 266 | + { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME | | |
| 267 | + BTUSB_WIDEBAND_SPEECH }, | |
| 268 | + { USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME | | |
| 269 | + BTUSB_WIDEBAND_SPEECH }, | |
| 270 | + { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME | | |
| 271 | + BTUSB_WIDEBAND_SPEECH }, | |
| 272 | + { USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME | | |
| 273 | + BTUSB_WIDEBAND_SPEECH }, | |
| 274 | + { USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME | | |
| 275 | + BTUSB_WIDEBAND_SPEECH }, | |
| 276 | + { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME | | |
| 277 | + BTUSB_WIDEBAND_SPEECH }, | |
| 278 | + { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME | | |
| 279 | + BTUSB_WIDEBAND_SPEECH }, | |
| 280 | + { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME | | |
| 281 | + BTUSB_WIDEBAND_SPEECH }, | |
| 282 | + { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME | | |
| 283 | + BTUSB_WIDEBAND_SPEECH }, | |
| 284 | + { USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME | | |
| 285 | + BTUSB_WIDEBAND_SPEECH }, | |
| 286 | + { USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME | | |
| 287 | + BTUSB_WIDEBAND_SPEECH }, | |
| 288 | + { USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME | | |
| 289 | + BTUSB_WIDEBAND_SPEECH }, | |
| 290 | + { USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME | | |
| 291 | + BTUSB_WIDEBAND_SPEECH }, | |
| 292 | + { USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME | | |
| 293 | + BTUSB_WIDEBAND_SPEECH }, | |
| 294 | + | |
| 295 | + /* QCA WCN6855 chipset */ | |
| 296 | + { USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 | | |
| 297 | + BTUSB_WIDEBAND_SPEECH }, | |
| 275 | 298 | |
| 276 | 299 | /* Broadcom BCM2035 */ |
| 277 | 300 | { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, |
| @@ -2338,10 +2361,10 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver, · 2060 unmodified lines | ||
| 2338 | 2361 | |
| 2339 | 2362 | static int btusb_intel_download_firmware(struct hci_dev *hdev, |
| 2340 | 2363 | struct intel_version *ver, |
| 2341 | − struct intel_boot_params *params) | |
| 2364 | + struct intel_boot_params *params, | |
| 2365 | + u32 *boot_param) | |
| 2342 | 2366 | { |
| 2343 | 2367 | const struct firmware *fw; |
| 2344 | − u32 boot_param; | |
| 2345 | 2368 | char fwname[64]; |
| 2346 | 2369 | int err; |
| 2347 | 2370 | struct btusb_data *data = hci_get_drvdata(hdev); |
| @@ -2479,7 +2502,7 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev, · 131 unmodified lines | ||
| 2479 | 2502 | set_bit(BTUSB_DOWNLOADING, &data->flags); |
| 2480 | 2503 | |
| 2481 | 2504 | /* Start firmware downloading and get boot parameter */ |
| 2482 | − err = btintel_download_firmware(hdev, fw, &boot_param); | |
| 2505 | + err = btintel_download_firmware(hdev, fw, boot_param); | |
| 2483 | 2506 | if (err < 0) { |
| 2484 | 2507 | /* When FW download fails, send Intel Reset to retry |
| 2485 | 2508 | * FW download. |
| @@ -2561,7 +2584,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) · 75 unmodified lines | ||
| 2561 | 2584 | return err; |
| 2562 | 2585 | } |
| 2563 | 2586 | |
| 2564 | − err = btusb_intel_download_firmware(hdev, &ver, ¶ms); | |
| 2587 | + err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param); | |
| 2565 | 2588 | if (err) |
| 2566 | 2589 | return err; |
| 2567 | 2590 | |
| @@ -2896,6 +2919,7 @@ static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev) · 328 unmodified lines | ||
| 2896 | 2919 | buf = kmalloc(size, GFP_KERNEL); |
| 2897 | 2920 | if (!buf) { |
| 2898 | 2921 | kfree(dr); |
| 2922 | + usb_free_urb(urb); | |
| 2899 | 2923 | return -ENOMEM; |
| 2900 | 2924 | } |
| 2901 | 2925 | |
| @@ -3390,6 +3414,27 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev, · 488 unmodified lines | ||
| 3390 | 3414 | return 0; |
| 3391 | 3415 | } |
| 3392 | 3416 | |
| 3417 | +static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev, | |
| 3418 | + const bdaddr_t *bdaddr) | |
| 3419 | +{ | |
| 3420 | + struct sk_buff *skb; | |
| 3421 | + u8 buf[6]; | |
| 3422 | + long ret; | |
| 3423 | + | |
| 3424 | + memcpy(buf, bdaddr, sizeof(bdaddr_t)); | |
| 3425 | + | |
| 3426 | + skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(buf), buf, | |
| 3427 | + HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT); | |
| 3428 | + if (IS_ERR(skb)) { | |
| 3429 | + ret = PTR_ERR(skb); | |
| 3430 | + bt_dev_err(hdev, "Change address command failed (%ld)", ret); | |
| 3431 | + return ret; | |
| 3432 | + } | |
| 3433 | + kfree_skb(skb); | |
| 3434 | + | |
| 3435 | + return 0; | |
| 3436 | +} | |
| 3437 | + | |
| 3393 | 3438 | #define QCA_DFU_PACKET_LEN 4096 |
| 3394 | 3439 | |
| 3395 | 3440 | #define QCA_GET_TARGET_VERSION 0x09 |
| @@ -3409,7 +3454,8 @@ struct qca_version { · 13 unmodified lines | ||
| 3409 | 3454 | } __packed; |
| 3410 | 3455 | |
| 3411 | 3456 | struct qca_rampatch_version { |
| 3412 | − __le16 rom_version; | |
| 3457 | + __le16 rom_version_high; | |
| 3458 | + __le16 rom_version_low; | |
| 3413 | 3459 | __le16 patch_version; |
| 3414 | 3460 | } __packed; |
| 3415 | 3461 | |
| @@ -3421,12 +3467,14 @@ struct qca_device_info { · 5 unmodified lines | ||
| 3421 | 3467 | }; |
| 3422 | 3468 | |
| 3423 | 3469 | static const struct qca_device_info qca_devices_table[] = { |
| 3424 | − { 0x00000100, 20, 4, 10 }, /* Rome 1.0 */ | |
| 3425 | − { 0x00000101, 20, 4, 10 }, /* Rome 1.1 */ | |
| 3426 | − { 0x00000200, 28, 4, 18 }, /* Rome 2.0 */ | |
| 3427 | − { 0x00000201, 28, 4, 18 }, /* Rome 2.1 */ | |
| 3428 | − { 0x00000300, 28, 4, 18 }, /* Rome 3.0 */ | |
| 3429 | − { 0x00000302, 28, 4, 18 }, /* Rome 3.2 */ | |
| 3470 | + { 0x00000100, 20, 4, 8 }, /* Rome 1.0 */ | |
| 3471 | + { 0x00000101, 20, 4, 8 }, /* Rome 1.1 */ | |
| 3472 | + { 0x00000200, 28, 4, 16 }, /* Rome 2.0 */ | |
| 3473 | + { 0x00000201, 28, 4, 16 }, /* Rome 2.1 */ | |
| 3474 | + { 0x00000300, 28, 4, 16 }, /* Rome 3.0 */ | |
| 3475 | + { 0x00000302, 28, 4, 16 }, /* Rome 3.2 */ | |
| 3476 | + { 0x00130100, 40, 4, 16 }, /* WCN6855 1.0 */ | |
| 3477 | + { 0x00130200, 40, 4, 16 }, /* WCN6855 2.0 */ | |
| 3430 | 3478 | }; |
| 3431 | 3479 | |
| 3432 | 3480 | static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request, |
| @@ -3528,8 +3576,8 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, · 95 unmodified lines | ||
| 3528 | 3576 | { |
| 3529 | 3577 | struct qca_rampatch_version *rver; |
| 3530 | 3578 | const struct firmware *fw; |
| 3531 | − u32 ver_rom, ver_patch; | |
| 3532 | − u16 rver_rom, rver_patch; | |
| 3579 | + u32 ver_rom, ver_patch, rver_rom; | |
| 3580 | + u16 rver_rom_low, rver_rom_high, rver_patch; | |
| 3533 | 3581 | char fwname[64]; |
| 3534 | 3582 | int err; |
| 3535 | 3583 | |
| @@ -3548,9 +3596,16 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, · 12 unmodified lines | ||
| 3548 | 3596 | bt_dev_info(hdev, "using rampatch file: %s", fwname); |
| 3549 | 3597 | |
| 3550 | 3598 | rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset); |
| 3551 | − rver_rom = le16_to_cpu(rver->rom_version); | |
| 3599 | + rver_rom_low = le16_to_cpu(rver->rom_version_low); | |
| 3552 | 3600 | rver_patch = le16_to_cpu(rver->patch_version); |
| 3553 | 3601 | |
| 3602 | + if (ver_rom & ~0xffffU) { | |
| 3603 | + rver_rom_high = le16_to_cpu(rver->rom_version_high); | |
| 3604 | + rver_rom = le32_to_cpu(rver_rom_high << 16 | rver_rom_low); | |
| 3605 | + } else { | |
| 3606 | + rver_rom = rver_rom_low; | |
| 3607 | + } | |
| 3608 | + | |
| 3554 | 3609 | bt_dev_info(hdev, "QCA: patch rome 0x%x build 0x%x, " |
| 3555 | 3610 | "firmware rome 0x%x build 0x%x", |
| 3556 | 3611 | rver_rom, rver_patch, ver_rom, ver_patch); |
| @@ -3624,9 +3679,6 @@ static int btusb_setup_qca(struct hci_dev *hdev) · 67 unmodified lines | ||
| 3624 | 3679 | return err; |
| 3625 | 3680 | |
| 3626 | 3681 | ver_rom = le32_to_cpu(ver.rom_version); |
| 3627 | − /* Don't care about high ROM versions */ | |
| 3628 | − if (ver_rom & ~0xffffU) | |
| 3629 | − return 0; | |
| 3630 | 3682 | |
| 3631 | 3683 | for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) { |
| 3632 | 3684 | if (ver_rom == qca_devices_table[i].rom_version) |
| @@ -4062,6 +4114,13 @@ static int btusb_probe(struct usb_interface *intf, · 429 unmodified lines | ||
| 4062 | 4114 | btusb_check_needs_reset_resume(intf); |
| 4063 | 4115 | } |
| 4064 | 4116 | |
| 4117 | + if (id->driver_info & BTUSB_QCA_WCN6855) { | |
| 4118 | + data->setup_on_usb = btusb_setup_qca; | |
| 4119 | + hdev->set_bdaddr = btusb_set_bdaddr_wcn6855; | |
| 4120 | + hdev->cmd_timeout = btusb_qca_cmd_timeout; | |
| 4121 | + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); | |
| 4122 | + } | |
| 4123 | + | |
| 4065 | 4124 | if (id->driver_info & BTUSB_AMP) { |
| 4066 | 4125 | /* AMP controllers do not support SCO packets */ |
| 4067 | 4126 | data->isoc = NULL; |
| @@ -793,8 +793,6 @@ static int h5_serdev_probe(struct serdev_device *serdev) · 792 unmodified lines | ||
| 793 | 793 | if (!h5) |
| 794 | 794 | return -ENOMEM; |
| 795 | 795 | |
| 796 | − set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.hdev_flags); | |
| 797 | − | |
| 798 | 796 | h5->hu = &h5->serdev_hu; |
| 799 | 797 | h5->serdev_hu.serdev = serdev; |
| 800 | 798 | serdev_device_set_drvdata(serdev, h5); |
| @@ -288,7 +288,7 @@ static irqreturn_t intel_irq(int irq, void *dev_id) · 287 unmodified lines | ||
| 288 | 288 | |
| 289 | 289 | static int intel_set_power(struct hci_uart *hu, bool powered) |
| 290 | 290 | { |
| 291 | − struct list_head *p; | |
| 291 | + struct intel_device *idev; | |
| 292 | 292 | int err = -ENODEV; |
| 293 | 293 | |
| 294 | 294 | if (!hu->tty->dev) |
| @@ -296,10 +296,7 @@ static int intel_set_power(struct hci_uart *hu, bool powered) · 1 unmodified line | ||
| 296 | 296 | |
| 297 | 297 | mutex_lock(&intel_device_list_lock); |
| 298 | 298 | |
| 299 | − list_for_each(p, &intel_device_list) { | |
| 300 | − struct intel_device *idev = list_entry(p, struct intel_device, | |
| 301 | − list); | |
| 302 | − | |
| 299 | + list_for_each_entry(idev, &intel_device_list, list) { | |
| 303 | 300 | /* tty device and pdev device should share the same parent |
| 304 | 301 | * which is the UART port. |
| 305 | 302 | */ |
| @@ -362,19 +359,16 @@ static int intel_set_power(struct hci_uart *hu, bool powered) · 56 unmodified lines | ||
| 362 | 359 | |
| 363 | 360 | static void intel_busy_work(struct work_struct *work) |
| 364 | 361 | { |
| 365 | − struct list_head *p; | |
| 366 | 362 | struct intel_data *intel = container_of(work, struct intel_data, |
| 367 | 363 | busy_work); |
| 364 | + struct intel_device *idev; | |
| 368 | 365 | |
| 369 | 366 | if (!intel->hu->tty->dev) |
| 370 | 367 | return; |
| 371 | 368 | |
| 372 | 369 | /* Link is busy, delay the suspend */ |
| 373 | 370 | mutex_lock(&intel_device_list_lock); |
| 374 | − list_for_each(p, &intel_device_list) { | |
| 375 | − struct intel_device *idev = list_entry(p, struct intel_device, | |
| 376 | − list); | |
| 377 | − | |
| 371 | + list_for_each_entry(idev, &intel_device_list, list) { | |
| 378 | 372 | if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) { |
| 379 | 373 | pm_runtime_get(&idev->pdev->dev); |
| 380 | 374 | pm_runtime_mark_last_busy(&idev->pdev->dev); |
| @@ -533,7 +527,7 @@ static int intel_setup(struct hci_uart *hu) · 152 unmodified lines | ||
| 533 | 527 | struct sk_buff *skb; |
| 534 | 528 | struct intel_version ver; |
| 535 | 529 | struct intel_boot_params params; |
| 536 | − struct list_head *p; | |
| 530 | + struct intel_device *idev; | |
| 537 | 531 | const struct firmware *fw; |
| 538 | 532 | char fwname[64]; |
| 539 | 533 | u32 boot_param; |
| @@ -693,14 +687,11 @@ static int intel_setup(struct hci_uart *hu) · 153 unmodified lines | ||
| 693 | 687 | case 0x0b: /* SfP */ |
| 694 | 688 | case 0x0c: /* WsP */ |
| 695 | 689 | snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", |
| 696 | − le16_to_cpu(ver.hw_variant), | |
| 697 | − le16_to_cpu(params.dev_revid)); | |
| 690 | + ver.hw_variant, le16_to_cpu(params.dev_revid)); | |
| 698 | 691 | break; |
| 699 | 692 | case 0x12: /* ThP */ |
| 700 | 693 | snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi", |
| 701 | − le16_to_cpu(ver.hw_variant), | |
| 702 | − le16_to_cpu(ver.hw_revision), | |
| 703 | − le16_to_cpu(ver.fw_revision)); | |
| 694 | + ver.hw_variant, ver.hw_revision, ver.fw_revision); | |
| 704 | 695 | break; |
| 705 | 696 | default: |
| 706 | 697 | bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)", |
| @@ -722,14 +713,11 @@ static int intel_setup(struct hci_uart *hu) · 15 unmodified lines | ||
| 722 | 713 | case 0x0b: /* SfP */ |
| 723 | 714 | case 0x0c: /* WsP */ |
| 724 | 715 | snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc", |
| 725 | − le16_to_cpu(ver.hw_variant), | |
| 726 | − le16_to_cpu(params.dev_revid)); | |
| 716 | + ver.hw_variant, le16_to_cpu(params.dev_revid)); | |
| 727 | 717 | break; |
| 728 | 718 | case 0x12: /* ThP */ |
| 729 | 719 | snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc", |
| 730 | − le16_to_cpu(ver.hw_variant), | |
| 731 | − le16_to_cpu(ver.hw_revision), | |
| 732 | − le16_to_cpu(ver.fw_revision)); | |
| 720 | + ver.hw_variant, ver.hw_revision, ver.fw_revision); | |
| 733 | 721 | break; |
| 734 | 722 | default: |
| 735 | 723 | bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)", |
| @@ -839,13 +827,11 @@ done: · 103 unmodified lines | ||
| 839 | 827 | * until further LPM TX notification. |
| 840 | 828 | */ |
| 841 | 829 | mutex_lock(&intel_device_list_lock); |
| 842 | − list_for_each(p, &intel_device_list) { | |
| 843 | − struct intel_device *dev = list_entry(p, struct intel_device, | |
| 844 | − list); | |
| 830 | + list_for_each_entry(idev, &intel_device_list, list) { | |
| 845 | 831 | if (!hu->tty->dev) |
| 846 | 832 | break; |
| 847 | − if (hu->tty->dev->parent == dev->pdev->dev.parent) { | |
| 848 | − if (device_may_wakeup(&dev->pdev->dev)) { | |
| 833 | + if (hu->tty->dev->parent == idev->pdev->dev.parent) { | |
| 834 | + if (device_may_wakeup(&idev->pdev->dev)) { | |
| 849 | 835 | set_bit(STATE_LPM_ENABLED, &intel->flags); |
| 850 | 836 | set_bit(STATE_TX_ACTIVE, &intel->flags); |
| 851 | 837 | } |
| @@ -999,7 +985,7 @@ static int intel_recv(struct hci_uart *hu, const void *data, int count) · 147 unmodified lines | ||
| 999 | 985 | static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb) |
| 1000 | 986 | { |
| 1001 | 987 | struct intel_data *intel = hu->priv; |
| 1002 | − struct list_head *p; | |
| 988 | + struct intel_device *idev; | |
| 1003 | 989 | |
| 1004 | 990 | BT_DBG("hu %p skb %p", hu, skb); |
| 1005 | 991 | |
| @@ -1010,10 +996,7 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb) · 4 unmodified lines | ||
| 1010 | 996 | * completed before enqueuing any packet. |
| 1011 | 997 | */ |
| 1012 | 998 | mutex_lock(&intel_device_list_lock); |
| 1013 | − list_for_each(p, &intel_device_list) { | |
| 1014 | − struct intel_device *idev = list_entry(p, struct intel_device, | |
| 1015 | − list); | |
| 1016 | − | |
| 999 | + list_for_each_entry(idev, &intel_device_list, list) { | |
| 1017 | 1000 | if (hu->tty->dev->parent == idev->pdev->dev.parent) { |
| 1018 | 1001 | pm_runtime_get_sync(&idev->pdev->dev); |
| 1019 | 1002 | pm_runtime_mark_last_busy(&idev->pdev->dev); |
| @@ -1076,7 +1059,8 @@ static const struct hci_uart_proto intel_proto = { · 56 unmodified lines | ||
| 1076 | 1059 | #ifdef CONFIG_ACPI |
| 1077 | 1060 | static const struct acpi_device_id intel_acpi_match[] = { |
| 1078 | 1061 | { "INT33E1", 0 }, |
| 1079 | − { }, | |
| 1062 | + { "INT33E3", 0 }, | |
| 1063 | + { } | |
| 1080 | 1064 | }; |
| 1081 | 1065 | MODULE_DEVICE_TABLE(acpi, intel_acpi_match); |
| 1082 | 1066 | #endif |
| @@ -1138,9 +1122,9 @@ static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; · 55 unmodified lines | ||
| 1138 | 1122 | static const struct acpi_gpio_params host_wake_gpios = { 1, 0, false }; |
| 1139 | 1123 | |
| 1140 | 1124 | static const struct acpi_gpio_mapping acpi_hci_intel_gpios[] = { |
| 1141 | − { "reset-gpios", &reset_gpios, 1 }, | |
| 1142 | − { "host-wake-gpios", &host_wake_gpios, 1 }, | |
| 1143 | − { }, | |
| 1125 | + { "reset-gpios", &reset_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, | |
| 1126 | + { "host-wake-gpios", &host_wake_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, | |
| 1127 | + { } | |
| 1144 | 1128 | }; |
| 1145 | 1129 | |
| 1146 | 1130 | static int intel_probe(struct platform_device *pdev) |
| @@ -538,6 +538,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) · 537 unmodified lines | ||
| 538 | 538 | clear_bit(HCI_UART_PROTO_READY, &hu->flags); |
| 539 | 539 | percpu_up_write(&hu->proto_lock); |
| 540 | 540 | |
| 541 | + cancel_work_sync(&hu->init_ready); | |
| 541 | 542 | cancel_work_sync(&hu->write_work); |
| 542 | 543 | |
| 543 | 544 | if (hdev) { |
| @@ -693,8 +693,6 @@ static int qca_close(struct hci_uart *hu) · 692 unmodified lines | ||
| 693 | 693 | destroy_workqueue(qca->workqueue); |
| 694 | 694 | qca->hu = NULL; |
| 695 | 695 | |
| 696 | − qca_power_shutdown(hu); | |
| 697 | − | |
| 698 | 696 | kfree_skb(qca->rx_skb); |
| 699 | 697 | |
| 700 | 698 | hu->priv = NULL; |
| @@ -2007,8 +2005,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) · 1306 unmodified lines | ||
| 2007 | 2005 | err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto); |
| 2008 | 2006 | if (err) { |
| 2009 | 2007 | BT_ERR("Rome serdev registration failed"); |
| 2010 | − if (qcadev->susclk) | |
| 2011 | − clk_disable_unprepare(qcadev->susclk); | |
| 2008 | + clk_disable_unprepare(qcadev->susclk); | |
| 2012 | 2009 | return err; |
| 2013 | 2010 | } |
| 2014 | 2011 | } |
| @@ -2032,8 +2029,9 @@ static int qca_serdev_probe(struct serdev_device *serdev) · 17 unmodified lines | ||
| 2032 | 2029 | static void qca_serdev_remove(struct serdev_device *serdev) |
| 2033 | 2030 | { |
| 2034 | 2031 | struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); |
| 2032 | + struct qca_power *power = qcadev->bt_power; | |
| 2035 | 2033 | |
| 2036 | − if (qca_is_wcn399x(qcadev->btsoc_type)) | |
| 2034 | + if (qca_is_wcn399x(qcadev->btsoc_type) && power->vregs_on) | |
| 2037 | 2035 | qca_power_shutdown(&qcadev->serdev_hu); |
| 2038 | 2036 | else if (qcadev->susclk) |
| 2039 | 2037 | clk_disable_unprepare(qcadev->susclk); |
| @@ -113,8 +113,22 @@ static int hci_uart_flush(struct hci_dev *hdev) · 112 unmodified lines | ||
| 113 | 113 | /* Initialize device */ |
| 114 | 114 | static int hci_uart_open(struct hci_dev *hdev) |
| 115 | 115 | { |
| 116 | + struct hci_uart *hu = hci_get_drvdata(hdev); | |
| 117 | + int err; | |
| 118 | + | |
| 116 | 119 | BT_DBG("%s %p", hdev->name, hdev); |
| 117 | 120 | |
| 121 | + /* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by | |
| 122 | + * driver, BT SoC is completely turned OFF during | |
| 123 | + * BT OFF. Upon next BT ON UART port should be opened. | |
| 124 | + */ | |
| 125 | + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { | |
| 126 | + err = serdev_device_open(hu->serdev); | |
| 127 | + if (err) | |
| 128 | + return err; | |
| 129 | + set_bit(HCI_UART_PROTO_READY, &hu->flags); | |
| 130 | + } | |
| 131 | + | |
| 118 | 132 | /* Undo clearing this from hci_uart_close() */ |
| 119 | 133 | hdev->flush = hci_uart_flush; |
| 120 | 134 | |
| @@ -124,11 +138,25 @@ static int hci_uart_open(struct hci_dev *hdev) · 3 unmodified lines | ||
| 124 | 138 | /* Close device */ |
| 125 | 139 | static int hci_uart_close(struct hci_dev *hdev) |
| 126 | 140 | { |
| 141 | + struct hci_uart *hu = hci_get_drvdata(hdev); | |
| 142 | + | |
| 127 | 143 | BT_DBG("hdev %p", hdev); |
| 128 | 144 | |
| 145 | + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) | |
| 146 | + return 0; | |
| 147 | + | |
| 129 | 148 | hci_uart_flush(hdev); |
| 130 | 149 | hdev->flush = NULL; |
| 131 | 150 | |
| 151 | + /* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver, | |
| 152 | + * BT SOC is completely powered OFF during BT OFF, holding port | |
| 153 | + * open may drain the battery. | |
| 154 | + */ | |
| 155 | + if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) { | |
| 156 | + clear_bit(HCI_UART_PROTO_READY, &hu->flags); | |
| 157 | + serdev_device_close(hu->serdev); | |
| 158 | + } | |
| 159 | + | |
| 132 | 160 | return 0; |
| 133 | 161 | } |
| 134 | 162 | |
| @@ -354,7 +382,7 @@ void hci_uart_unregister_device(struct hci_uart *hu) · 219 unmodified lines | ||
| 354 | 382 | { |
| 355 | 383 | struct hci_dev *hdev = hu->hdev; |
| 356 | 384 | |
| 357 | − clear_bit(HCI_UART_PROTO_READY, &hu->flags); | |
| 385 | + cancel_work_sync(&hu->init_ready); | |
| 358 | 386 | if (test_bit(HCI_UART_REGISTERED, &hu->flags)) |
| 359 | 387 | hci_unregister_dev(hdev); |
| 360 | 388 | hci_free_dev(hdev); |
| @@ -362,6 +390,10 @@ void hci_uart_unregister_device(struct hci_uart *hu) · 1 unmodified line | ||
| 362 | 390 | cancel_work_sync(&hu->write_work); |
| 363 | 391 | |
| 364 | 392 | hu->proto->close(hu); |
| 365 | − serdev_device_close(hu->serdev); | |
| 393 | + | |
| 394 | + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { | |
| 395 | + clear_bit(HCI_UART_PROTO_READY, &hu->flags); | |
| 396 | + serdev_device_close(hu->serdev); | |
| 397 | + } | |
| 366 | 398 | } |
| 367 | 399 | EXPORT_SYMBOL_GPL(hci_uart_unregister_device); |
| @@ -197,17 +197,12 @@ int cn_add_callback(struct cb_id *id, const char *name, · 196 unmodified lines | ||
| 197 | 197 | void (*callback)(struct cn_msg *, |
| 198 | 198 | struct netlink_skb_parms *)) |
| 199 | 199 | { |
| 200 | − int err; | |
| 201 | 200 | struct cn_dev *dev = &cdev; |
| 202 | 201 | |
| 203 | 202 | if (!cn_already_initialized) |
| 204 | 203 | return -EAGAIN; |
| 205 | 204 | |
| 206 | − err = cn_queue_add_callback(dev->cbdev, name, id, callback); | |
| 207 | − if (err) | |
| 208 | − return err; | |
| 209 | − | |
| 210 | − return 0; | |
| 205 | + return cn_queue_add_callback(dev->cbdev, name, id, callback); | |
| 211 | 206 | } |
| 212 | 207 | EXPORT_SYMBOL_GPL(cn_add_callback); |
| 213 | 208 | |
| @@ -21,35 +21,3 @@ config CRYPTO_DEV_CHELSIO · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | To compile this driver as a module, choose M here: the module |
| 23 | 23 | will be called chcr. |
| 24 | − | |
| 25 | −config CHELSIO_IPSEC_INLINE | |
| 26 | − bool "Chelsio IPSec XFRM Tx crypto offload" | |
| 27 | − depends on CHELSIO_T4 | |
| 28 | − depends on CRYPTO_DEV_CHELSIO | |
| 29 | − depends on XFRM_OFFLOAD | |
| 30 | − depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD | |
| 31 | − default n | |
| 32 | − help | |
| 33 | − Enable support for IPSec Tx Inline. | |
| 34 | − | |
| 35 | −config CRYPTO_DEV_CHELSIO_TLS | |
| 36 | − tristate "Chelsio Crypto Inline TLS Driver" | |
| 37 | − depends on CHELSIO_T4 | |
| 38 | − depends on TLS_TOE | |
| 39 | − select CRYPTO_DEV_CHELSIO | |
| 40 | − help | |
| 41 | − Support Chelsio Inline TLS with Chelsio crypto accelerator. | |
| 42 | − | |
| 43 | − To compile this driver as a module, choose M here: the module | |
| 44 | − will be called chtls. | |
| 45 | − | |
| 46 | −config CHELSIO_TLS_DEVICE | |
| 47 | − bool "Chelsio Inline KTLS Offload" | |
| 48 | − depends on CHELSIO_T4 | |
| 49 | − depends on TLS_DEVICE | |
| 50 | − select CRYPTO_DEV_CHELSIO | |
| 51 | − default y | |
| 52 | − help | |
| 53 | − This flag enables support for kernel tls offload over Chelsio T6 | |
| 54 | − crypto accelerator. CONFIG_CHELSIO_TLS_DEVICE flag can be enabled | |
| 55 | − only if CONFIG_TLS and CONFIG_TLS_DEVICE flags are enabled. | |
| @@ -3,8 +3,3 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/chelsio/cxgb4 · 2 unmodified lines | ||
| 3 | 3 | |
| 4 | 4 | obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chcr.o |
| 5 | 5 | chcr-objs := chcr_core.o chcr_algo.o |
| 6 | −#ifdef CONFIG_CHELSIO_TLS_DEVICE | |
| 7 | −chcr-objs += chcr_ktls.o | |
| 8 | −#endif | |
| 9 | −chcr-$(CONFIG_CHELSIO_IPSEC_INLINE) += chcr_ipsec.o | |
| 10 | −obj-$(CONFIG_CRYPTO_DEV_CHELSIO_TLS) += chtls/ | |
| @@ -86,39 +86,6 @@ · 85 unmodified lines | ||
| 86 | 86 | KEY_CONTEXT_OPAD_PRESENT_M) |
| 87 | 87 | #define KEY_CONTEXT_OPAD_PRESENT_F KEY_CONTEXT_OPAD_PRESENT_V(1U) |
| 88 | 88 | |
| 89 | −#define TLS_KEYCTX_RXFLIT_CNT_S 24 | |
| 90 | −#define TLS_KEYCTX_RXFLIT_CNT_V(x) ((x) << TLS_KEYCTX_RXFLIT_CNT_S) | |
| 91 | − | |
| 92 | −#define TLS_KEYCTX_RXPROT_VER_S 20 | |
| 93 | −#define TLS_KEYCTX_RXPROT_VER_M 0xf | |
| 94 | −#define TLS_KEYCTX_RXPROT_VER_V(x) ((x) << TLS_KEYCTX_RXPROT_VER_S) | |
| 95 | − | |
| 96 | −#define TLS_KEYCTX_RXCIPH_MODE_S 16 | |
| 97 | −#define TLS_KEYCTX_RXCIPH_MODE_M 0xf | |
| 98 | −#define TLS_KEYCTX_RXCIPH_MODE_V(x) ((x) << TLS_KEYCTX_RXCIPH_MODE_S) | |
| 99 | − | |
| 100 | −#define TLS_KEYCTX_RXAUTH_MODE_S 12 | |
| 101 | −#define TLS_KEYCTX_RXAUTH_MODE_M 0xf | |
| 102 | −#define TLS_KEYCTX_RXAUTH_MODE_V(x) ((x) << TLS_KEYCTX_RXAUTH_MODE_S) | |
| 103 | − | |
| 104 | −#define TLS_KEYCTX_RXCIAU_CTRL_S 11 | |
| 105 | −#define TLS_KEYCTX_RXCIAU_CTRL_V(x) ((x) << TLS_KEYCTX_RXCIAU_CTRL_S) | |
| 106 | − | |
| 107 | −#define TLS_KEYCTX_RX_SEQCTR_S 9 | |
| 108 | −#define TLS_KEYCTX_RX_SEQCTR_M 0x3 | |
| 109 | −#define TLS_KEYCTX_RX_SEQCTR_V(x) ((x) << TLS_KEYCTX_RX_SEQCTR_S) | |
| 110 | − | |
| 111 | −#define TLS_KEYCTX_RX_VALID_S 8 | |
| 112 | −#define TLS_KEYCTX_RX_VALID_V(x) ((x) << TLS_KEYCTX_RX_VALID_S) | |
| 113 | − | |
| 114 | −#define TLS_KEYCTX_RXCK_SIZE_S 3 | |
| 115 | −#define TLS_KEYCTX_RXCK_SIZE_M 0x7 | |
| 116 | −#define TLS_KEYCTX_RXCK_SIZE_V(x) ((x) << TLS_KEYCTX_RXCK_SIZE_S) | |
| 117 | − | |
| 118 | −#define TLS_KEYCTX_RXMK_SIZE_S 0 | |
| 119 | −#define TLS_KEYCTX_RXMK_SIZE_M 0x7 | |
| 120 | −#define TLS_KEYCTX_RXMK_SIZE_V(x) ((x) << TLS_KEYCTX_RXMK_SIZE_S) | |
| 121 | − | |
| 122 | 89 | #define CHCR_HASH_MAX_DIGEST_SIZE 64 |
| 123 | 90 | #define CHCR_MAX_SHA_DIGEST_SIZE 64 |
| 124 | 91 | |
| @@ -33,23 +33,8 @@ static int cpl_fw6_pld_handler(struct adapter *adap, unsigned char *input); · 32 unmodified lines | ||
| 33 | 33 | static void *chcr_uld_add(const struct cxgb4_lld_info *lld); |
| 34 | 34 | static int chcr_uld_state_change(void *handle, enum cxgb4_state state); |
| 35 | 35 | |
| 36 | −#if defined(CONFIG_CHELSIO_TLS_DEVICE) | |
| 37 | −static const struct tlsdev_ops chcr_ktls_ops = { | |
| 38 | − .tls_dev_add = chcr_ktls_dev_add, | |
| 39 | − .tls_dev_del = chcr_ktls_dev_del, | |
| 40 | −}; | |
| 41 | −#endif | |
| 42 | − | |
| 43 | −#ifdef CONFIG_CHELSIO_IPSEC_INLINE | |
| 44 | −static void update_netdev_features(void); | |
| 45 | −#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ | |
| 46 | − | |
| 47 | 36 | static chcr_handler_func work_handlers[NUM_CPL_CMDS] = { |
| 48 | 37 | [CPL_FW6_PLD] = cpl_fw6_pld_handler, |
| 49 | −#ifdef CONFIG_CHELSIO_TLS_DEVICE | |
| 50 | − [CPL_ACT_OPEN_RPL] = chcr_ktls_cpl_act_open_rpl, | |
| 51 | − [CPL_SET_TCB_RPL] = chcr_ktls_cpl_set_tcb_rpl, | |
| 52 | −#endif | |
| 53 | 38 | }; |
| 54 | 39 | |
| 55 | 40 | static struct cxgb4_uld_info chcr_uld_info = { |
| @@ -60,12 +45,6 @@ static struct cxgb4_uld_info chcr_uld_info = { · 4 unmodified lines | ||
| 60 | 45 | .add = chcr_uld_add, |
| 61 | 46 | .state_change = chcr_uld_state_change, |
| 62 | 47 | .rx_handler = chcr_uld_rx_handler, |
| 63 | −#if defined(CONFIG_CHELSIO_IPSEC_INLINE) || defined(CONFIG_CHELSIO_TLS_DEVICE) | |
| 64 | − .tx_handler = chcr_uld_tx_handler, | |
| 65 | −#endif /* CONFIG_CHELSIO_IPSEC_INLINE || CONFIG_CHELSIO_TLS_DEVICE */ | |
| 66 | −#if defined(CONFIG_CHELSIO_TLS_DEVICE) | |
| 67 | − .tlsdev_ops = &chcr_ktls_ops, | |
| 68 | −#endif | |
| 69 | 48 | }; |
| 70 | 49 | |
| 71 | 50 | static void detach_work_fn(struct work_struct *work) |
| @@ -241,23 +220,6 @@ int chcr_uld_rx_handler(void *handle, const __be64 *rsp, · 169 unmodified lines | ||
| 241 | 220 | return 0; |
| 242 | 221 | } |
| 243 | 222 | |
| 244 | −#if defined(CONFIG_CHELSIO_IPSEC_INLINE) || defined(CONFIG_CHELSIO_TLS_DEVICE) | |
| 245 | −int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev) | |
| 246 | −{ | |
| 247 | − /* In case if skb's decrypted bit is set, it's nic tls packet, else it's | |
| 248 | − * ipsec packet. | |
| 249 | − */ | |
| 250 | −#ifdef CONFIG_CHELSIO_TLS_DEVICE | |
| 251 | − if (skb->decrypted) | |
| 252 | − return chcr_ktls_xmit(skb, dev); | |
| 253 | −#endif | |
| 254 | −#ifdef CONFIG_CHELSIO_IPSEC_INLINE | |
| 255 | − return chcr_ipsec_xmit(skb, dev); | |
| 256 | −#endif | |
| 257 | − return 0; | |
| 258 | −} | |
| 259 | −#endif /* CONFIG_CHELSIO_IPSEC_INLINE || CONFIG_CHELSIO_TLS_DEVICE */ | |
| 260 | − | |
| 261 | 223 | static void chcr_detach_device(struct uld_ctx *u_ctx) |
| 262 | 224 | { |
| 263 | 225 | struct chcr_dev *dev = &u_ctx->dev; |
| @@ -305,24 +267,6 @@ static int chcr_uld_state_change(void *handle, enum cxgb4_state state) · 41 unmodified lines | ||
| 305 | 267 | return ret; |
| 306 | 268 | } |
| 307 | 269 | |
| 308 | −#ifdef CONFIG_CHELSIO_IPSEC_INLINE | |
| 309 | −static void update_netdev_features(void) | |
| 310 | −{ | |
| 311 | − struct uld_ctx *u_ctx, *tmp; | |
| 312 | − | |
| 313 | − mutex_lock(&drv_data.drv_mutex); | |
| 314 | − list_for_each_entry_safe(u_ctx, tmp, &drv_data.inact_dev, entry) { | |
| 315 | − if (u_ctx->lldi.crypto & ULP_CRYPTO_IPSEC_INLINE) | |
| 316 | − chcr_add_xfrmops(&u_ctx->lldi); | |
| 317 | − } | |
| 318 | − list_for_each_entry_safe(u_ctx, tmp, &drv_data.act_dev, entry) { | |
| 319 | − if (u_ctx->lldi.crypto & ULP_CRYPTO_IPSEC_INLINE) | |
| 320 | − chcr_add_xfrmops(&u_ctx->lldi); | |
| 321 | − } | |
| 322 | − mutex_unlock(&drv_data.drv_mutex); | |
| 323 | −} | |
| 324 | −#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ | |
| 325 | − | |
| 326 | 270 | static int __init chcr_crypto_init(void) |
| 327 | 271 | { |
| 328 | 272 | INIT_LIST_HEAD(&drv_data.act_dev); |
| @@ -332,12 +276,6 @@ static int __init chcr_crypto_init(void) · 3 unmodified lines | ||
| 332 | 276 | drv_data.last_dev = NULL; |
| 333 | 277 | cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info); |
| 334 | 278 | |
| 335 | − #ifdef CONFIG_CHELSIO_IPSEC_INLINE | |
| 336 | − rtnl_lock(); | |
| 337 | − update_netdev_features(); | |
| 338 | − rtnl_unlock(); | |
| 339 | − #endif /* CONFIG_CHELSIO_IPSEC_INLINE */ | |
| 340 | − | |
| 341 | 279 | return 0; |
| 342 | 280 | } |
| 343 | 281 | |
| @@ -72,54 +72,6 @@ struct _key_ctx { · 71 unmodified lines | ||
| 72 | 72 | unsigned char key[]; |
| 73 | 73 | }; |
| 74 | 74 | |
| 75 | −#define KEYCTX_TX_WR_IV_S 55 | |
| 76 | −#define KEYCTX_TX_WR_IV_M 0x1ffULL | |
| 77 | −#define KEYCTX_TX_WR_IV_V(x) ((x) << KEYCTX_TX_WR_IV_S) | |
| 78 | −#define KEYCTX_TX_WR_IV_G(x) \ | |
| 79 | − (((x) >> KEYCTX_TX_WR_IV_S) & KEYCTX_TX_WR_IV_M) | |
| 80 | − | |
| 81 | −#define KEYCTX_TX_WR_AAD_S 47 | |
| 82 | −#define KEYCTX_TX_WR_AAD_M 0xffULL | |
| 83 | −#define KEYCTX_TX_WR_AAD_V(x) ((x) << KEYCTX_TX_WR_AAD_S) | |
| 84 | −#define KEYCTX_TX_WR_AAD_G(x) (((x) >> KEYCTX_TX_WR_AAD_S) & \ | |
| 85 | − KEYCTX_TX_WR_AAD_M) | |
| 86 | − | |
| 87 | −#define KEYCTX_TX_WR_AADST_S 39 | |
| 88 | −#define KEYCTX_TX_WR_AADST_M 0xffULL | |
| 89 | −#define KEYCTX_TX_WR_AADST_V(x) ((x) << KEYCTX_TX_WR_AADST_S) | |
| 90 | −#define KEYCTX_TX_WR_AADST_G(x) \ | |
| 91 | − (((x) >> KEYCTX_TX_WR_AADST_S) & KEYCTX_TX_WR_AADST_M) | |
| 92 | − | |
| 93 | −#define KEYCTX_TX_WR_CIPHER_S 30 | |
| 94 | −#define KEYCTX_TX_WR_CIPHER_M 0x1ffULL | |
| 95 | −#define KEYCTX_TX_WR_CIPHER_V(x) ((x) << KEYCTX_TX_WR_CIPHER_S) | |
| 96 | −#define KEYCTX_TX_WR_CIPHER_G(x) \ | |
| 97 | − (((x) >> KEYCTX_TX_WR_CIPHER_S) & KEYCTX_TX_WR_CIPHER_M) | |
| 98 | − | |
| 99 | −#define KEYCTX_TX_WR_CIPHERST_S 23 | |
| 100 | −#define KEYCTX_TX_WR_CIPHERST_M 0x7f | |
| 101 | −#define KEYCTX_TX_WR_CIPHERST_V(x) ((x) << KEYCTX_TX_WR_CIPHERST_S) | |
| 102 | −#define KEYCTX_TX_WR_CIPHERST_G(x) \ | |
| 103 | − (((x) >> KEYCTX_TX_WR_CIPHERST_S) & KEYCTX_TX_WR_CIPHERST_M) | |
| 104 | − | |
| 105 | −#define KEYCTX_TX_WR_AUTH_S 14 | |
| 106 | −#define KEYCTX_TX_WR_AUTH_M 0x1ff | |
| 107 | −#define KEYCTX_TX_WR_AUTH_V(x) ((x) << KEYCTX_TX_WR_AUTH_S) | |
| 108 | −#define KEYCTX_TX_WR_AUTH_G(x) \ | |
| 109 | − (((x) >> KEYCTX_TX_WR_AUTH_S) & KEYCTX_TX_WR_AUTH_M) | |
| 110 | − | |
| 111 | −#define KEYCTX_TX_WR_AUTHST_S 7 | |
| 112 | −#define KEYCTX_TX_WR_AUTHST_M 0x7f | |
| 113 | −#define KEYCTX_TX_WR_AUTHST_V(x) ((x) << KEYCTX_TX_WR_AUTHST_S) | |
| 114 | −#define KEYCTX_TX_WR_AUTHST_G(x) \ | |
| 115 | − (((x) >> KEYCTX_TX_WR_AUTHST_S) & KEYCTX_TX_WR_AUTHST_M) | |
| 116 | − | |
| 117 | −#define KEYCTX_TX_WR_AUTHIN_S 0 | |
| 118 | −#define KEYCTX_TX_WR_AUTHIN_M 0x7f | |
| 119 | −#define KEYCTX_TX_WR_AUTHIN_V(x) ((x) << KEYCTX_TX_WR_AUTHIN_S) | |
| 120 | −#define KEYCTX_TX_WR_AUTHIN_G(x) \ | |
| 121 | − (((x) >> KEYCTX_TX_WR_AUTHIN_S) & KEYCTX_TX_WR_AUTHIN_M) | |
| 122 | − | |
| 123 | 75 | #define WQ_RETRY 5 |
| 124 | 76 | struct chcr_driver_data { |
| 125 | 77 | struct list_head act_dev; |
| @@ -157,42 +109,6 @@ struct uld_ctx { · 31 unmodified lines | ||
| 157 | 109 | struct chcr_dev dev; |
| 158 | 110 | }; |
| 159 | 111 | |
| 160 | −struct sge_opaque_hdr { | |
| 161 | − void *dev; | |
| 162 | − dma_addr_t addr[MAX_SKB_FRAGS + 1]; | |
| 163 | −}; | |
| 164 | − | |
| 165 | −struct chcr_ipsec_req { | |
| 166 | − struct ulp_txpkt ulptx; | |
| 167 | − struct ulptx_idata sc_imm; | |
| 168 | − struct cpl_tx_sec_pdu sec_cpl; | |
| 169 | − struct _key_ctx key_ctx; | |
| 170 | −}; | |
| 171 | − | |
| 172 | −struct chcr_ipsec_wr { | |
| 173 | − struct fw_ulptx_wr wreq; | |
| 174 | − struct chcr_ipsec_req req; | |
| 175 | −}; | |
| 176 | − | |
| 177 | −#define ESN_IV_INSERT_OFFSET 12 | |
| 178 | −struct chcr_ipsec_aadiv { | |
| 179 | − __be32 spi; | |
| 180 | − u8 seq_no[8]; | |
| 181 | − u8 iv[8]; | |
| 182 | −}; | |
| 183 | − | |
| 184 | −struct ipsec_sa_entry { | |
| 185 | − int hmac_ctrl; | |
| 186 | − u16 esn; | |
| 187 | − u16 resv; | |
| 188 | − unsigned int enckey_len; | |
| 189 | − unsigned int kctx_len; | |
| 190 | − unsigned int authsize; | |
| 191 | − __be32 key_ctx_hdr; | |
| 192 | − char salt[MAX_SALT]; | |
| 193 | − char key[2 * AES_MAX_KEY_SIZE]; | |
| 194 | −}; | |
| 195 | − | |
| 196 | 112 | /* |
| 197 | 113 | * sgl_len - calculates the size of an SGL of the given capacity |
| 198 | 114 | * @n: the number of SGL entries |
| @@ -221,18 +137,4 @@ int chcr_uld_rx_handler(void *handle, const __be64 *rsp, · 22 unmodified lines | ||
| 221 | 137 | int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev); |
| 222 | 138 | int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, |
| 223 | 139 | int err); |
| 224 | −int chcr_ipsec_xmit(struct sk_buff *skb, struct net_device *dev); | |
| 225 | −void chcr_add_xfrmops(const struct cxgb4_lld_info *lld); | |
| 226 | −#ifdef CONFIG_CHELSIO_TLS_DEVICE | |
| 227 | −int chcr_ktls_cpl_act_open_rpl(struct adapter *adap, unsigned char *input); | |
| 228 | −int chcr_ktls_cpl_set_tcb_rpl(struct adapter *adap, unsigned char *input); | |
| 229 | −int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev); | |
| 230 | −extern int chcr_ktls_dev_add(struct net_device *netdev, struct sock *sk, | |
| 231 | − enum tls_offload_ctx_dir direction, | |
| 232 | − struct tls_crypto_info *crypto_info, | |
| 233 | − u32 start_offload_tcp_sn); | |
| 234 | −extern void chcr_ktls_dev_del(struct net_device *netdev, | |
| 235 | − struct tls_context *tls_ctx, | |
| 236 | − enum tls_offload_ctx_dir direction); | |
| 237 | −#endif | |
| 238 | 140 | #endif /* __CHCR_CORE_H__ */ |
| @@ -97,41 +97,9 @@ static void hfi1_ipoib_dev_get_stats64(struct net_device *dev, · 96 unmodified lines | ||
| 97 | 97 | struct rtnl_link_stats64 *storage) |
| 98 | 98 | { |
| 99 | 99 | struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); |
| 100 | − u64 rx_packets = 0ull; | |
| 101 | − u64 rx_bytes = 0ull; | |
| 102 | − u64 tx_packets = 0ull; | |
| 103 | − u64 tx_bytes = 0ull; | |
| 104 | − int i; | |
| 105 | 100 | |
| 106 | 101 | netdev_stats_to_stats64(storage, &dev->stats); |
| 107 | − | |
| 108 | − for_each_possible_cpu(i) { | |
| 109 | − const struct pcpu_sw_netstats *stats; | |
| 110 | − unsigned int start; | |
| 111 | − u64 trx_packets; | |
| 112 | − u64 trx_bytes; | |
| 113 | − u64 ttx_packets; | |
| 114 | − u64 ttx_bytes; | |
| 115 | − | |
| 116 | − stats = per_cpu_ptr(priv->netstats, i); | |
| 117 | − do { | |
| 118 | − start = u64_stats_fetch_begin_irq(&stats->syncp); | |
| 119 | − trx_packets = stats->rx_packets; | |
| 120 | − trx_bytes = stats->rx_bytes; | |
| 121 | − ttx_packets = stats->tx_packets; | |
| 122 | − ttx_bytes = stats->tx_bytes; | |
| 123 | − } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); | |
| 124 | − | |
| 125 | − rx_packets += trx_packets; | |
| 126 | − rx_bytes += trx_bytes; | |
| 127 | − tx_packets += ttx_packets; | |
| 128 | − tx_bytes += ttx_bytes; | |
| 129 | − } | |
| 130 | − | |
| 131 | − storage->rx_packets += rx_packets; | |
| 132 | − storage->rx_bytes += rx_bytes; | |
| 133 | − storage->tx_packets += tx_packets; | |
| 134 | − storage->tx_bytes += tx_bytes; | |
| 102 | + dev_fetch_sw_netstats(storage, priv->netstats); | |
| 135 | 103 | } |
| 136 | 104 | |
| 137 | 105 | static const struct net_device_ops hfi1_ipoib_netdev_ops = { |
| @@ -473,6 +473,10 @@ config NET_SB1000 · 472 unmodified lines | ||
| 473 | 473 | |
| 474 | 474 | source "drivers/net/phy/Kconfig" |
| 475 | 475 | |
| 476 | +source "drivers/net/mdio/Kconfig" | |
| 477 | + | |
| 478 | +source "drivers/net/pcs/Kconfig" | |
| 479 | + | |
| 476 | 480 | source "drivers/net/plip/Kconfig" |
| 477 | 481 | |
| 478 | 482 | source "drivers/net/ppp/Kconfig" |
| @@ -21,6 +21,8 @@ obj-$(CONFIG_MDIO) += mdio.o · 20 unmodified lines | ||
| 21 | 21 | obj-$(CONFIG_NET) += Space.o loopback.o |
| 22 | 22 | obj-$(CONFIG_NETCONSOLE) += netconsole.o |
| 23 | 23 | obj-y += phy/ |
| 24 | +obj-y += mdio/ | |
| 25 | +obj-y += pcs/ | |
| 24 | 26 | obj-$(CONFIG_RIONET) += rionet.o |
| 25 | 27 | obj-$(CONFIG_NET_TEAM) += team/ |
| 26 | 28 | obj-$(CONFIG_TUN) += tun.o |
| @@ -70,6 +70,8 @@ static const char *version = · 69 unmodified lines | ||
| 70 | 70 | #include <linux/bitops.h> |
| 71 | 71 | #include <linux/jiffies.h> |
| 72 | 72 | |
| 73 | +#include <net/Space.h> | |
| 74 | + | |
| 73 | 75 | #include <asm/io.h> |
| 74 | 76 | #include <asm/dma.h> |
| 75 | 77 | |
| @@ -229,6 +229,8 @@ static int dma; · 228 unmodified lines | ||
| 229 | 229 | #include <linux/bitops.h> |
| 230 | 230 | #include <linux/gfp.h> |
| 231 | 231 | |
| 232 | +#include <net/Space.h> | |
| 233 | + | |
| 232 | 234 | #include <asm/dma.h> |
| 233 | 235 | #include <asm/io.h> |
| 234 | 236 | |
| @@ -54,7 +54,6 @@ struct bareudp_dev { · 53 unmodified lines | ||
| 54 | 54 | static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) |
| 55 | 55 | { |
| 56 | 56 | struct metadata_dst *tun_dst = NULL; |
| 57 | − struct pcpu_sw_netstats *stats; | |
| 58 | 57 | struct bareudp_dev *bareudp; |
| 59 | 58 | unsigned short family; |
| 60 | 59 | unsigned int len; |
| @@ -160,13 +159,9 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) · 99 unmodified lines | ||
| 160 | 159 | |
| 161 | 160 | len = skb->len; |
| 162 | 161 | err = gro_cells_receive(&bareudp->gro_cells, skb); |
| 163 | − if (likely(err == NET_RX_SUCCESS)) { | |
| 164 | − stats = this_cpu_ptr(bareudp->dev->tstats); | |
| 165 | − u64_stats_update_begin(&stats->syncp); | |
| 166 | − stats->rx_packets++; | |
| 167 | − stats->rx_bytes += len; | |
| 168 | − u64_stats_update_end(&stats->syncp); | |
| 169 | − } | |
| 162 | + if (likely(err == NET_RX_SUCCESS)) | |
| 163 | + dev_sw_netstats_rx_add(bareudp->dev, len); | |
| 164 | + | |
| 170 | 165 | return 0; |
| 171 | 166 | drop: |
| 172 | 167 | /* Consume bad packet */ |
| @@ -20,25 +20,6 @@ config CAIF_TTY · 19 unmodified lines | ||
| 20 | 20 | identified as N_CAIF. When this ldisc is opened from user space |
| 21 | 21 | it will redirect the TTY's traffic into the CAIF stack. |
| 22 | 22 | |
| 23 | −config CAIF_SPI_SLAVE | |
| 24 | − tristate "CAIF SPI transport driver for slave interface" | |
| 25 | − depends on CAIF && HAS_DMA | |
| 26 | − default n | |
| 27 | − help | |
| 28 | − The CAIF Link layer SPI Protocol driver for Slave SPI interface. | |
| 29 | − This driver implements a platform driver to accommodate for a | |
| 30 | − platform specific SPI device. A sample CAIF SPI Platform device is | |
| 31 | − provided in <file:Documentation/networking/caif/spi_porting.rst>. | |
| 32 | − | |
| 33 | −config CAIF_SPI_SYNC | |
| 34 | − bool "Next command and length in start of frame" | |
| 35 | − depends on CAIF_SPI_SLAVE | |
| 36 | − default n | |
| 37 | − help | |
| 38 | − Putting the next command and length in the start of the frame can | |
| 39 | − help to synchronize to the next transfer in case of over or under-runs. | |
| 40 | − This option also needs to be enabled on the modem. | |
| 41 | − | |
| 42 | 23 | config CAIF_HSI |
| 43 | 24 | tristate "CAIF HSI transport driver" |
| 44 | 25 | depends on CAIF |
| @@ -4,10 +4,6 @@ ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG · 3 unmodified lines | ||
| 4 | 4 | # Serial interface |
| 5 | 5 | obj-$(CONFIG_CAIF_TTY) += caif_serial.o |
| 6 | 6 | |
| 7 | −# SPI slave physical interfaces module | |
| 8 | −cfspi_slave-objs := caif_spi.o caif_spi_slave.o | |
| 9 | −obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o | |
| 10 | − | |
| 11 | 7 | # HSI interface |
| 12 | 8 | obj-$(CONFIG_CAIF_HSI) += caif_hsi.o |
| 13 | 9 | |
| @@ -458,15 +458,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) · 457 unmodified lines | ||
| 458 | 458 | skb_reset_mac_header(skb); |
| 459 | 459 | skb->dev = cfhsi->ndev; |
| 460 | 460 | |
| 461 | − /* | |
| 462 | − * We are in a callback handler and | |
| 463 | − * unfortunately we don't know what context we're | |
| 464 | − * running in. | |
| 465 | − */ | |
| 466 | − if (in_interrupt()) | |
| 467 | − netif_rx(skb); | |
| 468 | − else | |
| 469 | − netif_rx_ni(skb); | |
| 461 | + netif_rx_any_context(skb); | |
| 470 | 462 | |
| 471 | 463 | /* Update network statistics. */ |
| 472 | 464 | cfhsi->ndev->stats.rx_packets++; |
| @@ -587,14 +579,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) · 114 unmodified lines | ||
| 587 | 579 | skb_reset_mac_header(skb); |
| 588 | 580 | skb->dev = cfhsi->ndev; |
| 589 | 581 | |
| 590 | − /* | |
| 591 | − * We're called in callback from HSI | |
| 592 | − * and don't know the context we're running in. | |
| 593 | − */ | |
| 594 | − if (in_interrupt()) | |
| 595 | − netif_rx(skb); | |
| 596 | − else | |
| 597 | − netif_rx_ni(skb); | |
| 582 | + netif_rx_any_context(skb); | |
| 598 | 583 | |
| 599 | 584 | /* Update network statistics. */ |
| 600 | 585 | cfhsi->ndev->stats.rx_packets++; |
| @@ -1,874 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (C) ST-Ericsson AB 2010 | |
| 4 | − * Author: Daniel Martensson | |
| 5 | − */ | |
| 6 | − | |
| 7 | −#include <linux/init.h> | |
| 8 | −#include <linux/module.h> | |
| 9 | −#include <linux/device.h> | |
| 10 | −#include <linux/platform_device.h> | |
| 11 | −#include <linux/string.h> | |
| 12 | −#include <linux/workqueue.h> | |
| 13 | −#include <linux/completion.h> | |
| 14 | −#include <linux/list.h> | |
| 15 | −#include <linux/interrupt.h> | |
| 16 | −#include <linux/dma-mapping.h> | |
| 17 | −#include <linux/delay.h> | |
| 18 | −#include <linux/sched.h> | |
| 19 | −#include <linux/debugfs.h> | |
| 20 | −#include <linux/if_arp.h> | |
| 21 | −#include <net/caif/caif_layer.h> | |
| 22 | −#include <net/caif/caif_spi.h> | |
| 23 | − | |
| 24 | −#ifndef CONFIG_CAIF_SPI_SYNC | |
| 25 | −#define FLAVOR "Flavour: Vanilla.\n" | |
| 26 | −#else | |
| 27 | −#define FLAVOR "Flavour: Master CMD&LEN at start.\n" | |
| 28 | −#endif /* CONFIG_CAIF_SPI_SYNC */ | |
| 29 | − | |
| 30 | −MODULE_LICENSE("GPL"); | |
| 31 | −MODULE_AUTHOR("Daniel Martensson"); | |
| 32 | −MODULE_DESCRIPTION("CAIF SPI driver"); | |
| 33 | − | |
| 34 | −/* Returns the number of padding bytes for alignment. */ | |
| 35 | −#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1))))) | |
| 36 | − | |
| 37 | −static bool spi_loop; | |
| 38 | −module_param(spi_loop, bool, 0444); | |
| 39 | −MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode."); | |
| 40 | − | |
| 41 | −/* SPI frame alignment. */ | |
| 42 | −module_param(spi_frm_align, int, 0444); | |
| 43 | −MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment."); | |
| 44 | − | |
| 45 | −/* | |
| 46 | − * SPI padding options. | |
| 47 | − * Warning: must be a base of 2 (& operation used) and can not be zero ! | |
| 48 | − */ | |
| 49 | −module_param(spi_up_head_align, int, 0444); | |
| 50 | −MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment."); | |
| 51 | − | |
| 52 | −module_param(spi_up_tail_align, int, 0444); | |
| 53 | −MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment."); | |
| 54 | − | |
| 55 | −module_param(spi_down_head_align, int, 0444); | |
| 56 | −MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment."); | |
| 57 | − | |
| 58 | −module_param(spi_down_tail_align, int, 0444); | |
| 59 | −MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment."); | |
| 60 | − | |
| 61 | −#ifdef CONFIG_ARM | |
| 62 | −#define BYTE_HEX_FMT "%02X" | |
| 63 | −#else | |
| 64 | −#define BYTE_HEX_FMT "%02hhX" | |
| 65 | −#endif | |
| 66 | − | |
| 67 | −#define SPI_MAX_PAYLOAD_SIZE 4096 | |
| 68 | −/* | |
| 69 | − * Threshold values for the SPI packet queue. Flowcontrol will be asserted | |
| 70 | − * when the number of packets exceeds HIGH_WATER_MARK. It will not be | |
| 71 | − * deasserted before the number of packets drops below LOW_WATER_MARK. | |
| 72 | − */ | |
| 73 | −#define LOW_WATER_MARK 100 | |
| 74 | −#define HIGH_WATER_MARK (LOW_WATER_MARK*5) | |
| 75 | − | |
| 76 | −#ifndef CONFIG_HAS_DMA | |
| 77 | − | |
| 78 | −/* | |
| 79 | − * We sometimes use UML for debugging, but it cannot handle | |
| 80 | − * dma_alloc_coherent so we have to wrap it. | |
| 81 | − */ | |
| 82 | −static inline void *dma_alloc(struct cfspi *cfspi, dma_addr_t *daddr) | |
| 83 | −{ | |
| 84 | − return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL); | |
| 85 | −} | |
| 86 | − | |
| 87 | −static inline void dma_free(struct cfspi *cfspi, void *cpu_addr, | |
| 88 | − dma_addr_t handle) | |
| 89 | −{ | |
| 90 | − kfree(cpu_addr); | |
| 91 | −} | |
| 92 | − | |
| 93 | −#else | |
| 94 | − | |
| 95 | −static inline void *dma_alloc(struct cfspi *cfspi, dma_addr_t *daddr) | |
| 96 | −{ | |
| 97 | − return dma_alloc_coherent(&cfspi->pdev->dev, SPI_DMA_BUF_LEN, daddr, | |
| 98 | − GFP_KERNEL); | |
| 99 | −} | |
| 100 | − | |
| 101 | −static inline void dma_free(struct cfspi *cfspi, void *cpu_addr, | |
| 102 | − dma_addr_t handle) | |
| 103 | −{ | |
| 104 | − dma_free_coherent(&cfspi->pdev->dev, SPI_DMA_BUF_LEN, cpu_addr, handle); | |
| 105 | −} | |
| 106 | −#endif /* CONFIG_HAS_DMA */ | |
| 107 | − | |
| 108 | −#ifdef CONFIG_DEBUG_FS | |
| 109 | − | |
| 110 | −#define DEBUGFS_BUF_SIZE 4096 | |
| 111 | − | |
| 112 | −static struct dentry *dbgfs_root; | |
| 113 | − | |
| 114 | −static inline void driver_debugfs_create(void) | |
| 115 | −{ | |
| 116 | − dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL); | |
| 117 | −} | |
| 118 | − | |
| 119 | −static inline void driver_debugfs_remove(void) | |
| 120 | −{ | |
| 121 | − debugfs_remove(dbgfs_root); | |
| 122 | −} | |
| 123 | − | |
| 124 | −static inline void dev_debugfs_rem(struct cfspi *cfspi) | |
| 125 | −{ | |
| 126 | − debugfs_remove(cfspi->dbgfs_frame); | |
| 127 | − debugfs_remove(cfspi->dbgfs_state); | |
| 128 | − debugfs_remove(cfspi->dbgfs_dir); | |
| 129 | −} | |
| 130 | − | |
| 131 | −static ssize_t dbgfs_state(struct file *file, char __user *user_buf, | |
| 132 | − size_t count, loff_t *ppos) | |
| 133 | −{ | |
| 134 | − char *buf; | |
| 135 | − int len = 0; | |
| 136 | − ssize_t size; | |
| 137 | − struct cfspi *cfspi = file->private_data; | |
| 138 | − | |
| 139 | − buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL); | |
| 140 | − if (!buf) | |
| 141 | − return 0; | |
| 142 | − | |
| 143 | − /* Print out debug information. */ | |
| 144 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 145 | − "CAIF SPI debug information:\n"); | |
| 146 | − | |
| 147 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR); | |
| 148 | − | |
| 149 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 150 | − "STATE: %d\n", cfspi->dbg_state); | |
| 151 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 152 | − "Previous CMD: 0x%x\n", cfspi->pcmd); | |
| 153 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 154 | − "Current CMD: 0x%x\n", cfspi->cmd); | |
| 155 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 156 | − "Previous TX len: %d\n", cfspi->tx_ppck_len); | |
| 157 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 158 | − "Previous RX len: %d\n", cfspi->rx_ppck_len); | |
| 159 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 160 | − "Current TX len: %d\n", cfspi->tx_cpck_len); | |
| 161 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 162 | − "Current RX len: %d\n", cfspi->rx_cpck_len); | |
| 163 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 164 | − "Next TX len: %d\n", cfspi->tx_npck_len); | |
| 165 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 166 | − "Next RX len: %d\n", cfspi->rx_npck_len); | |
| 167 | − | |
| 168 | − if (len > DEBUGFS_BUF_SIZE) | |
| 169 | − len = DEBUGFS_BUF_SIZE; | |
| 170 | − | |
| 171 | − size = simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
| 172 | − kfree(buf); | |
| 173 | − | |
| 174 | − return size; | |
| 175 | −} | |
| 176 | − | |
| 177 | −static ssize_t print_frame(char *buf, size_t size, char *frm, | |
| 178 | − size_t count, size_t cut) | |
| 179 | −{ | |
| 180 | − int len = 0; | |
| 181 | − int i; | |
| 182 | − for (i = 0; i < count; i++) { | |
| 183 | − len += scnprintf((buf + len), (size - len), | |
| 184 | − "[0x" BYTE_HEX_FMT "]", | |
| 185 | − frm[i]); | |
| 186 | − if ((i == cut) && (count > (cut * 2))) { | |
| 187 | − /* Fast forward. */ | |
| 188 | − i = count - cut; | |
| 189 | − len += scnprintf((buf + len), (size - len), | |
| 190 | − "--- %zu bytes skipped ---\n", | |
| 191 | − count - (cut * 2)); | |
| 192 | − } | |
| 193 | − | |
| 194 | − if ((!(i % 10)) && i) { | |
| 195 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 196 | − "\n"); | |
| 197 | − } | |
| 198 | − } | |
| 199 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n"); | |
| 200 | − return len; | |
| 201 | −} | |
| 202 | − | |
| 203 | −static ssize_t dbgfs_frame(struct file *file, char __user *user_buf, | |
| 204 | − size_t count, loff_t *ppos) | |
| 205 | −{ | |
| 206 | − char *buf; | |
| 207 | − int len = 0; | |
| 208 | − ssize_t size; | |
| 209 | − struct cfspi *cfspi; | |
| 210 | − | |
| 211 | − cfspi = file->private_data; | |
| 212 | − buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL); | |
| 213 | − if (!buf) | |
| 214 | − return 0; | |
| 215 | − | |
| 216 | − /* Print out debug information. */ | |
| 217 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 218 | − "Current frame:\n"); | |
| 219 | − | |
| 220 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 221 | − "Tx data (Len: %d):\n", cfspi->tx_cpck_len); | |
| 222 | − | |
| 223 | − len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 224 | − cfspi->xfer.va_tx[0], | |
| 225 | − (cfspi->tx_cpck_len + SPI_CMD_SZ), 100); | |
| 226 | − | |
| 227 | − len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 228 | − "Rx data (Len: %d):\n", cfspi->rx_cpck_len); | |
| 229 | − | |
| 230 | − len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len), | |
| 231 | − cfspi->xfer.va_rx, | |
| 232 | − (cfspi->rx_cpck_len + SPI_CMD_SZ), 100); | |
| 233 | − | |
| 234 | − size = simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
| 235 | − kfree(buf); | |
| 236 | − | |
| 237 | − return size; | |
| 238 | −} | |
| 239 | − | |
| 240 | −static const struct file_operations dbgfs_state_fops = { | |
| 241 | − .open = simple_open, | |
| 242 | − .read = dbgfs_state, | |
| 243 | − .owner = THIS_MODULE | |
| 244 | −}; | |
| 245 | − | |
| 246 | −static const struct file_operations dbgfs_frame_fops = { | |
| 247 | − .open = simple_open, | |
| 248 | − .read = dbgfs_frame, | |
| 249 | − .owner = THIS_MODULE | |
| 250 | −}; | |
| 251 | − | |
| 252 | −static inline void dev_debugfs_add(struct cfspi *cfspi) | |
| 253 | −{ | |
| 254 | − cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root); | |
| 255 | − cfspi->dbgfs_state = debugfs_create_file("state", 0444, | |
| 256 | − cfspi->dbgfs_dir, cfspi, | |
| 257 | − &dbgfs_state_fops); | |
| 258 | − cfspi->dbgfs_frame = debugfs_create_file("frame", 0444, | |
| 259 | − cfspi->dbgfs_dir, cfspi, | |
| 260 | − &dbgfs_frame_fops); | |
| 261 | −} | |
| 262 | − | |
| 263 | −inline void cfspi_dbg_state(struct cfspi *cfspi, int state) | |
| 264 | −{ | |
| 265 | − cfspi->dbg_state = state; | |
| 266 | −}; | |
| 267 | −#else | |
| 268 | − | |
| 269 | −static inline void driver_debugfs_create(void) | |
| 270 | −{ | |
| 271 | −} | |
| 272 | − | |
| 273 | −static inline void driver_debugfs_remove(void) | |
| 274 | −{ | |
| 275 | −} | |
| 276 | − | |
| 277 | −static inline void dev_debugfs_add(struct cfspi *cfspi) | |
| 278 | −{ | |
| 279 | −} | |
| 280 | − | |
| 281 | −static inline void dev_debugfs_rem(struct cfspi *cfspi) | |
| 282 | −{ | |
| 283 | −} | |
| 284 | − | |
| 285 | −inline void cfspi_dbg_state(struct cfspi *cfspi, int state) | |
| 286 | −{ | |
| 287 | −} | |
| 288 | −#endif /* CONFIG_DEBUG_FS */ | |
| 289 | − | |
| 290 | −static LIST_HEAD(cfspi_list); | |
| 291 | −static spinlock_t cfspi_list_lock; | |
| 292 | − | |
| 293 | −/* SPI uplink head alignment. */ | |
| 294 | −static ssize_t up_head_align_show(struct device_driver *driver, char *buf) | |
| 295 | −{ | |
| 296 | − return sprintf(buf, "%d\n", spi_up_head_align); | |
| 297 | −} | |
| 298 | − | |
| 299 | −static DRIVER_ATTR_RO(up_head_align); | |
| 300 | − | |
| 301 | −/* SPI uplink tail alignment. */ | |
| 302 | −static ssize_t up_tail_align_show(struct device_driver *driver, char *buf) | |
| 303 | −{ | |
| 304 | − return sprintf(buf, "%d\n", spi_up_tail_align); | |
| 305 | −} | |
| 306 | − | |
| 307 | −static DRIVER_ATTR_RO(up_tail_align); | |
| 308 | − | |
| 309 | −/* SPI downlink head alignment. */ | |
| 310 | −static ssize_t down_head_align_show(struct device_driver *driver, char *buf) | |
| 311 | −{ | |
| 312 | − return sprintf(buf, "%d\n", spi_down_head_align); | |
| 313 | −} | |
| 314 | − | |
| 315 | −static DRIVER_ATTR_RO(down_head_align); | |
| 316 | − | |
| 317 | −/* SPI downlink tail alignment. */ | |
| 318 | −static ssize_t down_tail_align_show(struct device_driver *driver, char *buf) | |
| 319 | −{ | |
| 320 | − return sprintf(buf, "%d\n", spi_down_tail_align); | |
| 321 | −} | |
| 322 | − | |
| 323 | −static DRIVER_ATTR_RO(down_tail_align); | |
| 324 | − | |
| 325 | −/* SPI frame alignment. */ | |
| 326 | −static ssize_t frame_align_show(struct device_driver *driver, char *buf) | |
| 327 | −{ | |
| 328 | − return sprintf(buf, "%d\n", spi_frm_align); | |
| 329 | −} | |
| 330 | − | |
| 331 | −static DRIVER_ATTR_RO(frame_align); | |
| 332 | − | |
| 333 | −int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len) | |
| 334 | −{ | |
| 335 | − u8 *dst = buf; | |
| 336 | − caif_assert(buf); | |
| 337 | − | |
| 338 | − if (cfspi->slave && !cfspi->slave_talked) | |
| 339 | − cfspi->slave_talked = true; | |
| 340 | − | |
| 341 | − do { | |
| 342 | − struct sk_buff *skb; | |
| 343 | − struct caif_payload_info *info; | |
| 344 | − int spad = 0; | |
| 345 | − int epad; | |
| 346 | − | |
| 347 | − skb = skb_dequeue(&cfspi->chead); | |
| 348 | − if (!skb) | |
| 349 | − break; | |
| 350 | − | |
| 351 | − /* | |
| 352 | − * Calculate length of frame including SPI padding. | |
| 353 | − * The payload position is found in the control buffer. | |
| 354 | − */ | |
| 355 | − info = (struct caif_payload_info *)&skb->cb; | |
| 356 | − | |
| 357 | − /* | |
| 358 | − * Compute head offset i.e. number of bytes to add to | |
| 359 | − * get the start of the payload aligned. | |
| 360 | − */ | |
| 361 | − if (spi_up_head_align > 1) { | |
| 362 | − spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align); | |
| 363 | − *dst = (u8)(spad - 1); | |
| 364 | − dst += spad; | |
| 365 | − } | |
| 366 | − | |
| 367 | − /* Copy in CAIF frame. */ | |
| 368 | − skb_copy_bits(skb, 0, dst, skb->len); | |
| 369 | − dst += skb->len; | |
| 370 | − cfspi->ndev->stats.tx_packets++; | |
| 371 | − cfspi->ndev->stats.tx_bytes += skb->len; | |
| 372 | − | |
| 373 | − /* | |
| 374 | − * Compute tail offset i.e. number of bytes to add to | |
| 375 | − * get the complete CAIF frame aligned. | |
| 376 | − */ | |
| 377 | − epad = PAD_POW2((skb->len + spad), spi_up_tail_align); | |
| 378 | − dst += epad; | |
| 379 | − | |
| 380 | − dev_kfree_skb(skb); | |
| 381 | − | |
| 382 | − } while ((dst - buf) < len); | |
| 383 | − | |
| 384 | − return dst - buf; | |
| 385 | −} | |
| 386 | − | |
| 387 | −int cfspi_xmitlen(struct cfspi *cfspi) | |
| 388 | −{ | |
| 389 | − struct sk_buff *skb = NULL; | |
| 390 | − int frm_len = 0; | |
| 391 | − int pkts = 0; | |
| 392 | − | |
| 393 | − /* | |
| 394 | − * Decommit previously committed frames. | |
| 395 | − * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead) | |
| 396 | − */ | |
| 397 | − while (skb_peek(&cfspi->chead)) { | |
| 398 | − skb = skb_dequeue_tail(&cfspi->chead); | |
| 399 | − skb_queue_head(&cfspi->qhead, skb); | |
| 400 | − } | |
| 401 | − | |
| 402 | − do { | |
| 403 | − struct caif_payload_info *info = NULL; | |
| 404 | − int spad = 0; | |
| 405 | − int epad = 0; | |
| 406 | − | |
| 407 | − skb = skb_dequeue(&cfspi->qhead); | |
| 408 | − if (!skb) | |
| 409 | − break; | |
| 410 | − | |
| 411 | − /* | |
| 412 | − * Calculate length of frame including SPI padding. | |
| 413 | − * The payload position is found in the control buffer. | |
| 414 | − */ | |
| 415 | − info = (struct caif_payload_info *)&skb->cb; | |
| 416 | − | |
| 417 | − /* | |
| 418 | − * Compute head offset i.e. number of bytes to add to | |
| 419 | − * get the start of the payload aligned. | |
| 420 | − */ | |
| 421 | − if (spi_up_head_align > 1) | |
| 422 | − spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align); | |
| 423 | − | |
| 424 | − /* | |
| 425 | − * Compute tail offset i.e. number of bytes to add to | |
| 426 | − * get the complete CAIF frame aligned. | |
| 427 | − */ | |
| 428 | − epad = PAD_POW2((skb->len + spad), spi_up_tail_align); | |
| 429 | − | |
| 430 | − if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) { | |
| 431 | − skb_queue_tail(&cfspi->chead, skb); | |
| 432 | − pkts++; | |
| 433 | − frm_len += skb->len + spad + epad; | |
| 434 | − } else { | |
| 435 | − /* Put back packet. */ | |
| 436 | − skb_queue_head(&cfspi->qhead, skb); | |
| 437 | − break; | |
| 438 | − } | |
| 439 | − } while (pkts <= CAIF_MAX_SPI_PKTS); | |
| 440 | − | |
| 441 | − /* | |
| 442 | − * Send flow on if previously sent flow off | |
| 443 | − * and now go below the low water mark | |
| 444 | − */ | |
| 445 | − if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark && | |
| 446 | − cfspi->cfdev.flowctrl) { | |
| 447 | − cfspi->flow_off_sent = 0; | |
| 448 | − cfspi->cfdev.flowctrl(cfspi->ndev, 1); | |
| 449 | − } | |
| 450 | − | |
| 451 | − return frm_len; | |
| 452 | −} | |
| 453 | − | |
| 454 | −static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc) | |
| 455 | −{ | |
| 456 | − struct cfspi *cfspi = (struct cfspi *)ifc->priv; | |
| 457 | − | |
| 458 | − /* | |
| 459 | − * The slave device is the master on the link. Interrupts before the | |
| 460 | − * slave has transmitted are considered spurious. | |
| 461 | − */ | |
| 462 | − if (cfspi->slave && !cfspi->slave_talked) { | |
| 463 | − printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n"); | |
| 464 | − return; | |
| 465 | − } | |
| 466 | − | |
| 467 | − if (!in_interrupt()) | |
| 468 | − spin_lock(&cfspi->lock); | |
| 469 | − if (assert) { | |
| 470 | − set_bit(SPI_SS_ON, &cfspi->state); | |
| 471 | − set_bit(SPI_XFER, &cfspi->state); | |
| 472 | − } else { | |
| 473 | − set_bit(SPI_SS_OFF, &cfspi->state); | |
| 474 | − } | |
| 475 | − if (!in_interrupt()) | |
| 476 | − spin_unlock(&cfspi->lock); | |
| 477 | − | |
| 478 | − /* Wake up the xfer thread. */ | |
| 479 | − if (assert) | |
| 480 | − wake_up_interruptible(&cfspi->wait); | |
| 481 | −} | |
| 482 | − | |
| 483 | −static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc) | |
| 484 | −{ | |
| 485 | − struct cfspi *cfspi = (struct cfspi *)ifc->priv; | |
| 486 | − | |
| 487 | − /* Transfer done, complete work queue */ | |
| 488 | − complete(&cfspi->comp); | |
| 489 | −} | |
| 490 | − | |
| 491 | −static netdev_tx_t cfspi_xmit(struct sk_buff *skb, struct net_device *dev) | |
| 492 | −{ | |
| 493 | − struct cfspi *cfspi = NULL; | |
| 494 | − unsigned long flags; | |
| 495 | − if (!dev) | |
| 496 | − return -EINVAL; | |
| 497 | − | |
| 498 | − cfspi = netdev_priv(dev); | |
| 499 | − | |
| 500 | − skb_queue_tail(&cfspi->qhead, skb); | |
| 501 | − | |
| 502 | − spin_lock_irqsave(&cfspi->lock, flags); | |
| 503 | − if (!test_and_set_bit(SPI_XFER, &cfspi->state)) { | |
| 504 | − /* Wake up xfer thread. */ | |
| 505 | − wake_up_interruptible(&cfspi->wait); | |
| 506 | − } | |
| 507 | − spin_unlock_irqrestore(&cfspi->lock, flags); | |
| 508 | − | |
| 509 | − /* Send flow off if number of bytes is above high water mark */ | |
| 510 | − if (!cfspi->flow_off_sent && | |
| 511 | − cfspi->qhead.qlen > cfspi->qd_high_mark && | |
| 512 | − cfspi->cfdev.flowctrl) { | |
| 513 | − cfspi->flow_off_sent = 1; | |
| 514 | − cfspi->cfdev.flowctrl(cfspi->ndev, 0); | |
| 515 | − } | |
| 516 | − | |
| 517 | − return NETDEV_TX_OK; | |
| 518 | −} | |
| 519 | − | |
| 520 | −int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len) | |
| 521 | −{ | |
| 522 | − u8 *src = buf; | |
| 523 | − | |
| 524 | − caif_assert(buf != NULL); | |
| 525 | − | |
| 526 | − do { | |
| 527 | − int res; | |
| 528 | − struct sk_buff *skb = NULL; | |
| 529 | − int spad = 0; | |
| 530 | − int epad = 0; | |
| 531 | − int pkt_len = 0; | |
| 532 | − | |
| 533 | − /* | |
| 534 | − * Compute head offset i.e. number of bytes added to | |
| 535 | − * get the start of the payload aligned. | |
| 536 | − */ | |
| 537 | − if (spi_down_head_align > 1) { | |
| 538 | − spad = 1 + *src; | |
| 539 | − src += spad; | |
| 540 | − } | |
| 541 | − | |
| 542 | − /* Read length of CAIF frame (little endian). */ | |
| 543 | − pkt_len = *src; | |
| 544 | − pkt_len |= ((*(src+1)) << 8) & 0xFF00; | |
| 545 | − pkt_len += 2; /* Add FCS fields. */ | |
| 546 | − | |
| 547 | − /* Get a suitable caif packet and copy in data. */ | |
| 548 | − | |
| 549 | − skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1); | |
| 550 | − caif_assert(skb != NULL); | |
| 551 | − | |
| 552 | − skb_put_data(skb, src, pkt_len); | |
| 553 | − src += pkt_len; | |
| 554 | − | |
| 555 | − skb->protocol = htons(ETH_P_CAIF); | |
| 556 | − skb_reset_mac_header(skb); | |
| 557 | − | |
| 558 | − /* | |
| 559 | − * Push received packet up the stack. | |
| 560 | − */ | |
| 561 | − if (!spi_loop) | |
| 562 | − res = netif_rx_ni(skb); | |
| 563 | − else | |
| 564 | − res = cfspi_xmit(skb, cfspi->ndev); | |
| 565 | − | |
| 566 | − if (!res) { | |
| 567 | − cfspi->ndev->stats.rx_packets++; | |
| 568 | − cfspi->ndev->stats.rx_bytes += pkt_len; | |
| 569 | − } else | |
| 570 | − cfspi->ndev->stats.rx_dropped++; | |
| 571 | − | |
| 572 | − /* | |
| 573 | − * Compute tail offset i.e. number of bytes added to | |
| 574 | − * get the complete CAIF frame aligned. | |
| 575 | − */ | |
| 576 | − epad = PAD_POW2((pkt_len + spad), spi_down_tail_align); | |
| 577 | − src += epad; | |
| 578 | − } while ((src - buf) < len); | |
| 579 | − | |
| 580 | − return src - buf; | |
| 581 | −} | |
| 582 | − | |
| 583 | −static int cfspi_open(struct net_device *dev) | |
| 584 | −{ | |
| 585 | − netif_wake_queue(dev); | |
| 586 | − return 0; | |
| 587 | −} | |
| 588 | − | |
| 589 | −static int cfspi_close(struct net_device *dev) | |
| 590 | −{ | |
| 591 | − netif_stop_queue(dev); | |
| 592 | − return 0; | |
| 593 | −} | |
| 594 | − | |
| 595 | −static int cfspi_init(struct net_device *dev) | |
| 596 | −{ | |
| 597 | − int res = 0; | |
| 598 | − struct cfspi *cfspi = netdev_priv(dev); | |
| 599 | − | |
| 600 | − /* Set flow info. */ | |
| 601 | − cfspi->flow_off_sent = 0; | |
| 602 | − cfspi->qd_low_mark = LOW_WATER_MARK; | |
| 603 | − cfspi->qd_high_mark = HIGH_WATER_MARK; | |
| 604 | − | |
| 605 | − /* Set slave info. */ | |
| 606 | − if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) { | |
| 607 | − cfspi->slave = true; | |
| 608 | − cfspi->slave_talked = false; | |
| 609 | − } else { | |
| 610 | − cfspi->slave = false; | |
| 611 | − cfspi->slave_talked = false; | |
| 612 | − } | |
| 613 | − | |
| 614 | − /* Allocate DMA buffers. */ | |
| 615 | − cfspi->xfer.va_tx[0] = dma_alloc(cfspi, &cfspi->xfer.pa_tx[0]); | |
| 616 | − if (!cfspi->xfer.va_tx[0]) { | |
| 617 | − res = -ENODEV; | |
| 618 | − goto err_dma_alloc_tx_0; | |
| 619 | − } | |
| 620 | − | |
| 621 | − cfspi->xfer.va_rx = dma_alloc(cfspi, &cfspi->xfer.pa_rx); | |
| 622 | − | |
| 623 | − if (!cfspi->xfer.va_rx) { | |
| 624 | − res = -ENODEV; | |
| 625 | − goto err_dma_alloc_rx; | |
| 626 | − } | |
| 627 | − | |
| 628 | − /* Initialize the work queue. */ | |
| 629 | − INIT_WORK(&cfspi->work, cfspi_xfer); | |
| 630 | − | |
| 631 | − /* Initialize spin locks. */ | |
| 632 | − spin_lock_init(&cfspi->lock); | |
| 633 | − | |
| 634 | − /* Initialize flow control state. */ | |
| 635 | − cfspi->flow_stop = false; | |
| 636 | − | |
| 637 | − /* Initialize wait queue. */ | |
| 638 | − init_waitqueue_head(&cfspi->wait); | |
| 639 | − | |
| 640 | − /* Create work thread. */ | |
| 641 | − cfspi->wq = create_singlethread_workqueue(dev->name); | |
| 642 | − if (!cfspi->wq) { | |
| 643 | − printk(KERN_WARNING "CFSPI: failed to create work queue.\n"); | |
| 644 | − res = -ENODEV; | |
| 645 | − goto err_create_wq; | |
| 646 | − } | |
| 647 | − | |
| 648 | − /* Initialize work queue. */ | |
| 649 | − init_completion(&cfspi->comp); | |
| 650 | − | |
| 651 | − /* Create debugfs entries. */ | |
| 652 | − dev_debugfs_add(cfspi); | |
| 653 | − | |
| 654 | − /* Set up the ifc. */ | |
| 655 | − cfspi->ifc.ss_cb = cfspi_ss_cb; | |
| 656 | − cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb; | |
| 657 | − cfspi->ifc.priv = cfspi; | |
| 658 | − | |
| 659 | − /* Add CAIF SPI device to list. */ | |
| 660 | − spin_lock(&cfspi_list_lock); | |
| 661 | − list_add_tail(&cfspi->list, &cfspi_list); | |
| 662 | − spin_unlock(&cfspi_list_lock); | |
| 663 | − | |
| 664 | − /* Schedule the work queue. */ | |
| 665 | − queue_work(cfspi->wq, &cfspi->work); | |
| 666 | − | |
| 667 | − return 0; | |
| 668 | − | |
| 669 | − err_create_wq: | |
| 670 | − dma_free(cfspi, cfspi->xfer.va_rx, cfspi->xfer.pa_rx); | |
| 671 | − err_dma_alloc_rx: | |
| 672 | − dma_free(cfspi, cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]); | |
| 673 | − err_dma_alloc_tx_0: | |
| 674 | − return res; | |
| 675 | −} | |
| 676 | − | |
| 677 | −static void cfspi_uninit(struct net_device *dev) | |
| 678 | −{ | |
| 679 | − struct cfspi *cfspi = netdev_priv(dev); | |
| 680 | − | |
| 681 | − /* Remove from list. */ | |
| 682 | − spin_lock(&cfspi_list_lock); | |
| 683 | − list_del(&cfspi->list); | |
| 684 | − spin_unlock(&cfspi_list_lock); | |
| 685 | − | |
| 686 | − cfspi->ndev = NULL; | |
| 687 | − /* Free DMA buffers. */ | |
| 688 | − dma_free(cfspi, cfspi->xfer.va_rx, cfspi->xfer.pa_rx); | |
| 689 | − dma_free(cfspi, cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]); | |
| 690 | − set_bit(SPI_TERMINATE, &cfspi->state); | |
| 691 | − wake_up_interruptible(&cfspi->wait); | |
| 692 | − destroy_workqueue(cfspi->wq); | |
| 693 | − /* Destroy debugfs directory and files. */ | |
| 694 | − dev_debugfs_rem(cfspi); | |
| 695 | − return; | |
| 696 | −} | |
| 697 | − | |
| 698 | −static const struct net_device_ops cfspi_ops = { | |
| 699 | − .ndo_open = cfspi_open, | |
| 700 | − .ndo_stop = cfspi_close, | |
| 701 | − .ndo_init = cfspi_init, | |
| 702 | − .ndo_uninit = cfspi_uninit, | |
| 703 | − .ndo_start_xmit = cfspi_xmit | |
| 704 | −}; | |
| 705 | − | |
| 706 | −static void cfspi_setup(struct net_device *dev) | |
| 707 | −{ | |
| 708 | − struct cfspi *cfspi = netdev_priv(dev); | |
| 709 | − dev->features = 0; | |
| 710 | − dev->netdev_ops = &cfspi_ops; | |
| 711 | − dev->type = ARPHRD_CAIF; | |
| 712 | − dev->flags = IFF_NOARP | IFF_POINTOPOINT; | |
| 713 | − dev->priv_flags |= IFF_NO_QUEUE; | |
| 714 | − dev->mtu = SPI_MAX_PAYLOAD_SIZE; | |
| 715 | − dev->needs_free_netdev = true; | |
| 716 | − skb_queue_head_init(&cfspi->qhead); | |
| 717 | − skb_queue_head_init(&cfspi->chead); | |
| 718 | − cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW; | |
| 719 | − cfspi->cfdev.use_frag = false; | |
| 720 | − cfspi->cfdev.use_stx = false; | |
| 721 | − cfspi->cfdev.use_fcs = false; | |
| 722 | − cfspi->ndev = dev; | |
| 723 | −} | |
| 724 | − | |
| 725 | −int cfspi_spi_probe(struct platform_device *pdev) | |
| 726 | −{ | |
| 727 | − struct cfspi *cfspi = NULL; | |
| 728 | − struct net_device *ndev; | |
| 729 | − struct cfspi_dev *dev; | |
| 730 | − int res; | |
| 731 | − dev = (struct cfspi_dev *)pdev->dev.platform_data; | |
| 732 | − | |
| 733 | − if (!dev) | |
| 734 | − return -ENODEV; | |
| 735 | − | |
| 736 | − ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d", | |
| 737 | − NET_NAME_UNKNOWN, cfspi_setup); | |
| 738 | − if (!ndev) | |
| 739 | − return -ENOMEM; | |
| 740 | − | |
| 741 | − cfspi = netdev_priv(ndev); | |
| 742 | − netif_stop_queue(ndev); | |
| 743 | − cfspi->ndev = ndev; | |
| 744 | − cfspi->pdev = pdev; | |
| 745 | − | |
| 746 | − /* Assign the SPI device. */ | |
| 747 | − cfspi->dev = dev; | |
| 748 | − /* Assign the device ifc to this SPI interface. */ | |
| 749 | − dev->ifc = &cfspi->ifc; | |
| 750 | − | |
| 751 | − /* Register network device. */ | |
| 752 | − res = register_netdev(ndev); | |
| 753 | − if (res) { | |
| 754 | − printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res); | |
| 755 | − goto err_net_reg; | |
| 756 | − } | |
| 757 | − return res; | |
| 758 | − | |
| 759 | − err_net_reg: | |
| 760 | − free_netdev(ndev); | |
| 761 | − | |
| 762 | − return res; | |
| 763 | −} | |
| 764 | − | |
| 765 | −int cfspi_spi_remove(struct platform_device *pdev) | |
| 766 | −{ | |
| 767 | − /* Everything is done in cfspi_uninit(). */ | |
| 768 | − return 0; | |
| 769 | −} | |
| 770 | − | |
| 771 | −static void __exit cfspi_exit_module(void) | |
| 772 | −{ | |
| 773 | − struct list_head *list_node; | |
| 774 | − struct list_head *n; | |
| 775 | − struct cfspi *cfspi = NULL; | |
| 776 | − | |
| 777 | − list_for_each_safe(list_node, n, &cfspi_list) { | |
| 778 | − cfspi = list_entry(list_node, struct cfspi, list); | |
| 779 | − unregister_netdev(cfspi->ndev); | |
| 780 | − } | |
| 781 | − | |
| 782 | − /* Destroy sysfs files. */ | |
| 783 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 784 | − &driver_attr_up_head_align); | |
| 785 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 786 | − &driver_attr_up_tail_align); | |
| 787 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 788 | − &driver_attr_down_head_align); | |
| 789 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 790 | − &driver_attr_down_tail_align); | |
| 791 | − driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align); | |
| 792 | − /* Unregister platform driver. */ | |
| 793 | − platform_driver_unregister(&cfspi_spi_driver); | |
| 794 | − /* Destroy debugfs root directory. */ | |
| 795 | − driver_debugfs_remove(); | |
| 796 | −} | |
| 797 | − | |
| 798 | −static int __init cfspi_init_module(void) | |
| 799 | −{ | |
| 800 | − int result; | |
| 801 | − | |
| 802 | − /* Initialize spin lock. */ | |
| 803 | − spin_lock_init(&cfspi_list_lock); | |
| 804 | − | |
| 805 | − /* Register platform driver. */ | |
| 806 | − result = platform_driver_register(&cfspi_spi_driver); | |
| 807 | − if (result) { | |
| 808 | − printk(KERN_ERR "Could not register platform SPI driver.\n"); | |
| 809 | − goto err_dev_register; | |
| 810 | − } | |
| 811 | − | |
| 812 | − /* Create sysfs files. */ | |
| 813 | − result = | |
| 814 | − driver_create_file(&cfspi_spi_driver.driver, | |
| 815 | − &driver_attr_up_head_align); | |
| 816 | − if (result) { | |
| 817 | − printk(KERN_ERR "Sysfs creation failed 1.\n"); | |
| 818 | − goto err_create_up_head_align; | |
| 819 | − } | |
| 820 | − | |
| 821 | − result = | |
| 822 | − driver_create_file(&cfspi_spi_driver.driver, | |
| 823 | − &driver_attr_up_tail_align); | |
| 824 | − if (result) { | |
| 825 | − printk(KERN_ERR "Sysfs creation failed 2.\n"); | |
| 826 | − goto err_create_up_tail_align; | |
| 827 | − } | |
| 828 | − | |
| 829 | − result = | |
| 830 | − driver_create_file(&cfspi_spi_driver.driver, | |
| 831 | − &driver_attr_down_head_align); | |
| 832 | − if (result) { | |
| 833 | − printk(KERN_ERR "Sysfs creation failed 3.\n"); | |
| 834 | − goto err_create_down_head_align; | |
| 835 | − } | |
| 836 | − | |
| 837 | − result = | |
| 838 | − driver_create_file(&cfspi_spi_driver.driver, | |
| 839 | − &driver_attr_down_tail_align); | |
| 840 | − if (result) { | |
| 841 | − printk(KERN_ERR "Sysfs creation failed 4.\n"); | |
| 842 | − goto err_create_down_tail_align; | |
| 843 | − } | |
| 844 | − | |
| 845 | − result = | |
| 846 | − driver_create_file(&cfspi_spi_driver.driver, | |
| 847 | − &driver_attr_frame_align); | |
| 848 | − if (result) { | |
| 849 | − printk(KERN_ERR "Sysfs creation failed 5.\n"); | |
| 850 | − goto err_create_frame_align; | |
| 851 | − } | |
| 852 | − driver_debugfs_create(); | |
| 853 | − return result; | |
| 854 | − | |
| 855 | − err_create_frame_align: | |
| 856 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 857 | − &driver_attr_down_tail_align); | |
| 858 | − err_create_down_tail_align: | |
| 859 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 860 | − &driver_attr_down_head_align); | |
| 861 | − err_create_down_head_align: | |
| 862 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 863 | − &driver_attr_up_tail_align); | |
| 864 | − err_create_up_tail_align: | |
| 865 | − driver_remove_file(&cfspi_spi_driver.driver, | |
| 866 | − &driver_attr_up_head_align); | |
| 867 | − err_create_up_head_align: | |
| 868 | − platform_driver_unregister(&cfspi_spi_driver); | |
| 869 | − err_dev_register: | |
| 870 | − return result; | |
| 871 | −} | |
| 872 | − | |
| 873 | −module_init(cfspi_init_module); | |
| 874 | −module_exit(cfspi_exit_module); | |
| @@ -1,254 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (C) ST-Ericsson AB 2010 | |
| 4 | − * Author: Daniel Martensson | |
| 5 | − */ | |
| 6 | −#include <linux/module.h> | |
| 7 | −#include <linux/device.h> | |
| 8 | −#include <linux/platform_device.h> | |
| 9 | −#include <linux/string.h> | |
| 10 | −#include <linux/semaphore.h> | |
| 11 | −#include <linux/workqueue.h> | |
| 12 | −#include <linux/completion.h> | |
| 13 | −#include <linux/list.h> | |
| 14 | −#include <linux/interrupt.h> | |
| 15 | −#include <linux/dma-mapping.h> | |
| 16 | −#include <linux/delay.h> | |
| 17 | −#include <linux/sched.h> | |
| 18 | −#include <linux/debugfs.h> | |
| 19 | −#include <net/caif/caif_spi.h> | |
| 20 | − | |
| 21 | −#ifndef CONFIG_CAIF_SPI_SYNC | |
| 22 | −#define SPI_DATA_POS 0 | |
| 23 | −static inline int forward_to_spi_cmd(struct cfspi *cfspi) | |
| 24 | −{ | |
| 25 | − return cfspi->rx_cpck_len; | |
| 26 | −} | |
| 27 | −#else | |
| 28 | −#define SPI_DATA_POS SPI_CMD_SZ | |
| 29 | −static inline int forward_to_spi_cmd(struct cfspi *cfspi) | |
| 30 | −{ | |
| 31 | − return 0; | |
| 32 | −} | |
| 33 | −#endif | |
| 34 | − | |
| 35 | −int spi_frm_align = 2; | |
| 36 | − | |
| 37 | −/* | |
| 38 | − * SPI padding options. | |
| 39 | − * Warning: must be a base of 2 (& operation used) and can not be zero ! | |
| 40 | − */ | |
| 41 | −int spi_up_head_align = 1 << 1; | |
| 42 | −int spi_up_tail_align = 1 << 0; | |
| 43 | −int spi_down_head_align = 1 << 2; | |
| 44 | −int spi_down_tail_align = 1 << 1; | |
| 45 | − | |
| 46 | −#ifdef CONFIG_DEBUG_FS | |
| 47 | −static inline void debugfs_store_prev(struct cfspi *cfspi) | |
| 48 | −{ | |
| 49 | − /* Store previous command for debugging reasons.*/ | |
| 50 | − cfspi->pcmd = cfspi->cmd; | |
| 51 | − /* Store previous transfer. */ | |
| 52 | − cfspi->tx_ppck_len = cfspi->tx_cpck_len; | |
| 53 | − cfspi->rx_ppck_len = cfspi->rx_cpck_len; | |
| 54 | −} | |
| 55 | −#else | |
| 56 | −static inline void debugfs_store_prev(struct cfspi *cfspi) | |
| 57 | −{ | |
| 58 | −} | |
| 59 | −#endif | |
| 60 | − | |
| 61 | −void cfspi_xfer(struct work_struct *work) | |
| 62 | −{ | |
| 63 | − struct cfspi *cfspi; | |
| 64 | − u8 *ptr = NULL; | |
| 65 | − unsigned long flags; | |
| 66 | − int ret; | |
| 67 | − cfspi = container_of(work, struct cfspi, work); | |
| 68 | − | |
| 69 | − /* Initialize state. */ | |
| 70 | − cfspi->cmd = SPI_CMD_EOT; | |
| 71 | − | |
| 72 | − for (;;) { | |
| 73 | − | |
| 74 | − cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING); | |
| 75 | − | |
| 76 | − /* Wait for master talk or transmit event. */ | |
| 77 | − wait_event_interruptible(cfspi->wait, | |
| 78 | − test_bit(SPI_XFER, &cfspi->state) || | |
| 79 | − test_bit(SPI_TERMINATE, &cfspi->state)); | |
| 80 | − | |
| 81 | − if (test_bit(SPI_TERMINATE, &cfspi->state)) | |
| 82 | − return; | |
| 83 | − | |
| 84 | −#if CFSPI_DBG_PREFILL | |
| 85 | − /* Prefill buffers for easier debugging. */ | |
| 86 | − memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN); | |
| 87 | − memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN); | |
| 88 | −#endif /* CFSPI_DBG_PREFILL */ | |
| 89 | − | |
| 90 | − cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE); | |
| 91 | − | |
| 92 | − /* Check whether we have a committed frame. */ | |
| 93 | − if (cfspi->tx_cpck_len) { | |
| 94 | − int len; | |
| 95 | − | |
| 96 | − cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT); | |
| 97 | − | |
| 98 | − /* Copy committed SPI frames after the SPI indication. */ | |
| 99 | − ptr = (u8 *) cfspi->xfer.va_tx; | |
| 100 | − ptr += SPI_IND_SZ; | |
| 101 | − len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len); | |
| 102 | − WARN_ON(len != cfspi->tx_cpck_len); | |
| 103 | − } | |
| 104 | − | |
| 105 | − cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT); | |
| 106 | − | |
| 107 | − /* Get length of next frame to commit. */ | |
| 108 | − cfspi->tx_npck_len = cfspi_xmitlen(cfspi); | |
| 109 | − | |
| 110 | − WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN); | |
| 111 | − | |
| 112 | − /* | |
| 113 | − * Add indication and length at the beginning of the frame, | |
| 114 | − * using little endian. | |
| 115 | − */ | |
| 116 | − ptr = (u8 *) cfspi->xfer.va_tx; | |
| 117 | − *ptr++ = SPI_CMD_IND; | |
| 118 | − *ptr++ = (SPI_CMD_IND & 0xFF00) >> 8; | |
| 119 | − *ptr++ = cfspi->tx_npck_len & 0x00FF; | |
| 120 | − *ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8; | |
| 121 | − | |
| 122 | − /* Calculate length of DMAs. */ | |
| 123 | − cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ; | |
| 124 | − cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ; | |
| 125 | − | |
| 126 | − /* Add SPI TX frame alignment padding, if necessary. */ | |
| 127 | − if (cfspi->tx_cpck_len && | |
| 128 | − (cfspi->xfer.tx_dma_len % spi_frm_align)) { | |
| 129 | − | |
| 130 | − cfspi->xfer.tx_dma_len += spi_frm_align - | |
| 131 | − (cfspi->xfer.tx_dma_len % spi_frm_align); | |
| 132 | − } | |
| 133 | − | |
| 134 | − /* Add SPI RX frame alignment padding, if necessary. */ | |
| 135 | − if (cfspi->rx_cpck_len && | |
| 136 | − (cfspi->xfer.rx_dma_len % spi_frm_align)) { | |
| 137 | − | |
| 138 | − cfspi->xfer.rx_dma_len += spi_frm_align - | |
| 139 | − (cfspi->xfer.rx_dma_len % spi_frm_align); | |
| 140 | − } | |
| 141 | − | |
| 142 | − cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER); | |
| 143 | − | |
| 144 | − /* Start transfer. */ | |
| 145 | − ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev); | |
| 146 | − WARN_ON(ret); | |
| 147 | − | |
| 148 | − cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE); | |
| 149 | − | |
| 150 | − /* | |
| 151 | − * TODO: We might be able to make an assumption if this is the | |
| 152 | − * first loop. Make sure that minimum toggle time is respected. | |
| 153 | − */ | |
| 154 | − udelay(MIN_TRANSITION_TIME_USEC); | |
| 155 | − | |
| 156 | − cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE); | |
| 157 | − | |
| 158 | − /* Signal that we are ready to receive data. */ | |
| 159 | − cfspi->dev->sig_xfer(true, cfspi->dev); | |
| 160 | − | |
| 161 | − cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE); | |
| 162 | − | |
| 163 | − /* Wait for transfer completion. */ | |
| 164 | − wait_for_completion(&cfspi->comp); | |
| 165 | − | |
| 166 | − cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE); | |
| 167 | − | |
| 168 | − if (cfspi->cmd == SPI_CMD_EOT) { | |
| 169 | − /* | |
| 170 | − * Clear the master talk bit. A xfer is always at | |
| 171 | − * least two bursts. | |
| 172 | − */ | |
| 173 | − clear_bit(SPI_SS_ON, &cfspi->state); | |
| 174 | − } | |
| 175 | − | |
| 176 | − cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE); | |
| 177 | − | |
| 178 | − /* Make sure that the minimum toggle time is respected. */ | |
| 179 | − if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len, | |
| 180 | − cfspi->dev->clk_mhz) < | |
| 181 | − MIN_TRANSITION_TIME_USEC) { | |
| 182 | − | |
| 183 | − udelay(MIN_TRANSITION_TIME_USEC - | |
| 184 | − SPI_XFER_TIME_USEC | |
| 185 | − (cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz)); | |
| 186 | − } | |
| 187 | − | |
| 188 | − cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE); | |
| 189 | − | |
| 190 | − /* De-assert transfer signal. */ | |
| 191 | − cfspi->dev->sig_xfer(false, cfspi->dev); | |
| 192 | − | |
| 193 | − /* Check whether we received a CAIF packet. */ | |
| 194 | − if (cfspi->rx_cpck_len) { | |
| 195 | − int len; | |
| 196 | − | |
| 197 | − cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT); | |
| 198 | − | |
| 199 | − /* Parse SPI frame. */ | |
| 200 | − ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS)); | |
| 201 | − | |
| 202 | − len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len); | |
| 203 | − WARN_ON(len != cfspi->rx_cpck_len); | |
| 204 | − } | |
| 205 | − | |
| 206 | − /* Check the next SPI command and length. */ | |
| 207 | − ptr = (u8 *) cfspi->xfer.va_rx; | |
| 208 | − | |
| 209 | − ptr += forward_to_spi_cmd(cfspi); | |
| 210 | − | |
| 211 | − cfspi->cmd = *ptr++; | |
| 212 | − cfspi->cmd |= ((*ptr++) << 8) & 0xFF00; | |
| 213 | − cfspi->rx_npck_len = *ptr++; | |
| 214 | − cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00; | |
| 215 | − | |
| 216 | − WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN); | |
| 217 | − WARN_ON(cfspi->cmd > SPI_CMD_EOT); | |
| 218 | − | |
| 219 | − debugfs_store_prev(cfspi); | |
| 220 | − | |
| 221 | − /* Check whether the master issued an EOT command. */ | |
| 222 | − if (cfspi->cmd == SPI_CMD_EOT) { | |
| 223 | − /* Reset state. */ | |
| 224 | − cfspi->tx_cpck_len = 0; | |
| 225 | − cfspi->rx_cpck_len = 0; | |
| 226 | − } else { | |
| 227 | − /* Update state. */ | |
| 228 | − cfspi->tx_cpck_len = cfspi->tx_npck_len; | |
| 229 | − cfspi->rx_cpck_len = cfspi->rx_npck_len; | |
| 230 | − } | |
| 231 | − | |
| 232 | − /* | |
| 233 | − * Check whether we need to clear the xfer bit. | |
| 234 | − * Spin lock needed for packet insertion. | |
| 235 | − * Test and clear of different bits | |
| 236 | − * are not supported. | |
| 237 | − */ | |
| 238 | − spin_lock_irqsave(&cfspi->lock, flags); | |
| 239 | − if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi) | |
| 240 | − && !test_bit(SPI_SS_ON, &cfspi->state)) | |
| 241 | − clear_bit(SPI_XFER, &cfspi->state); | |
| 242 | − | |
| 243 | − spin_unlock_irqrestore(&cfspi->lock, flags); | |
| 244 | − } | |
| 245 | −} | |
| 246 | − | |
| 247 | −struct platform_driver cfspi_spi_driver = { | |
| 248 | − .probe = cfspi_spi_probe, | |
| 249 | − .remove = cfspi_spi_remove, | |
| 250 | − .driver = { | |
| 251 | − .name = "cfspi_sspi", | |
| 252 | − .owner = THIS_MODULE, | |
| 253 | − }, | |
| 254 | −}; | |
| @@ -652,7 +652,7 @@ static int cfv_probe(struct virtio_device *vdev) · 651 unmodified lines | ||
| 652 | 652 | const char *cfv_netdev_name = "cfvrt"; |
| 653 | 653 | struct net_device *netdev; |
| 654 | 654 | struct cfv_info *cfv; |
| 655 | − int err = -EINVAL; | |
| 655 | + int err; | |
| 656 | 656 | |
| 657 | 657 | netdev = alloc_netdev(sizeof(struct cfv_info), cfv_netdev_name, |
| 658 | 658 | NET_NAME_UNKNOWN, cfv_netdev_setup); |
| @@ -41,8 +41,8 @@ config CAN_SLCAN · 40 unmodified lines | ||
| 41 | 41 | www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de |
| 42 | 42 | |
| 43 | 43 | Userspace tools to attach the SLCAN line discipline (slcan_attach, |
| 44 | − slcand) can be found in the can-utils at the SocketCAN SVN, see | |
| 45 | − http://developer.berlios.de/projects/socketcan for details. | |
| 44 | + slcand) can be found in the can-utils at the linux-can project, see | |
| 45 | + https://github.com/linux-can/can-utils for details. | |
| 46 | 46 | |
| 47 | 47 | The slcan driver supports up to 10 CAN netdevices by default which |
| 48 | 48 | can be changed by the 'maxdev=xx' module option. This driver can |
| @@ -643,7 +643,7 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) · 642 unmodified lines | ||
| 643 | 643 | * |
| 644 | 644 | * The first message goes into mb nr. 1 and issues an interrupt. All |
| 645 | 645 | * rx ints are disabled in the interrupt handler and a napi poll is |
| 646 | − * scheduled. We read the mailbox, but do _not_ reenable the mb (to | |
| 646 | + * scheduled. We read the mailbox, but do _not_ re-enable the mb (to | |
| 647 | 647 | * receive another message). |
| 648 | 648 | * |
| 649 | 649 | * lower mbxs upper |
| @@ -661,13 +661,13 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) · 11 unmodified lines | ||
| 661 | 661 | * |
| 662 | 662 | * The variable priv->rx_next points to the next mailbox to read a |
| 663 | 663 | * message from. As long we're in the lower mailboxes we just read the |
| 664 | − * mailbox but not reenable it. | |
| 664 | + * mailbox but not re-enable it. | |
| 665 | 665 | * |
| 666 | − * With completion of the last of the lower mailboxes, we reenable the | |
| 666 | + * With completion of the last of the lower mailboxes, we re-enable the | |
| 667 | 667 | * whole first group, but continue to look for filled mailboxes in the |
| 668 | 668 | * upper mailboxes. Imagine the second group like overflow mailboxes, |
| 669 | 669 | * which takes CAN messages if the lower goup is full. While in the |
| 670 | − * upper group we reenable the mailbox right after reading it. Giving | |
| 670 | + * upper group we re-enable the mailbox right after reading it. Giving | |
| 671 | 671 | * the chip more room to store messages. |
| 672 | 672 | * |
| 673 | 673 | * After finishing we look again in the lower group if we've still |
| @@ -356,15 +356,6 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface, · 355 unmodified lines | ||
| 356 | 356 | } |
| 357 | 357 | } |
| 358 | 358 | |
| 359 | −static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev, | |
| 360 | − int iface) | |
| 361 | −{ | |
| 362 | − int i; | |
| 363 | − | |
| 364 | − for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) | |
| 365 | − c_can_object_get(dev, iface, i, IF_COMM_CLR_NEWDAT); | |
| 366 | −} | |
| 367 | − | |
| 368 | 359 | static int c_can_handle_lost_msg_obj(struct net_device *dev, |
| 369 | 360 | int iface, int objno, u32 ctrl) |
| 370 | 361 | { |
| @@ -81,7 +81,7 @@ enum reg { · 80 unmodified lines | ||
| 81 | 81 | C_CAN_FUNCTION_REG, |
| 82 | 82 | }; |
| 83 | 83 | |
| 84 | −static const u16 reg_map_c_can[] = { | |
| 84 | +static const u16 __maybe_unused reg_map_c_can[] = { | |
| 85 | 85 | [C_CAN_CTRL_REG] = 0x00, |
| 86 | 86 | [C_CAN_STS_REG] = 0x02, |
| 87 | 87 | [C_CAN_ERR_CNT_REG] = 0x04, |
| @@ -121,7 +121,7 @@ static const u16 reg_map_c_can[] = { · 33 unmodified lines | ||
| 121 | 121 | [C_CAN_MSGVAL2_REG] = 0xB2, |
| 122 | 122 | }; |
| 123 | 123 | |
| 124 | −static const u16 reg_map_d_can[] = { | |
| 124 | +static const u16 __maybe_unused reg_map_d_can[] = { | |
| 125 | 125 | [C_CAN_CTRL_REG] = 0x00, |
| 126 | 126 | [C_CAN_CTRL_EX_REG] = 0x02, |
| 127 | 127 | [C_CAN_STS_REG] = 0x04, |
| @@ -538,7 +538,7 @@ static int cc770_err(struct net_device *dev, u8 status) · 537 unmodified lines | ||
| 538 | 538 | priv->can.can_stats.error_warning++; |
| 539 | 539 | } |
| 540 | 540 | } else { |
| 541 | − /* Back to error avtive */ | |
| 541 | + /* Back to error active */ | |
| 542 | 542 | cf->can_id |= CAN_ERR_PROT; |
| 543 | 543 | cf->data[2] = CAN_ERR_PROT_ACTIVE; |
| 544 | 544 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
| @@ -184,7 +184,7 @@ struct cc770_priv { · 183 unmodified lines | ||
| 184 | 184 | u8 control_normal_mode; /* Control register for normal mode */ |
| 185 | 185 | u8 cpu_interface; /* CPU interface register */ |
| 186 | 186 | u8 clkout; /* Clock out register */ |
| 187 | − u8 bus_config; /* Bus conffiguration register */ | |
| 187 | + u8 bus_config; /* Bus configuration register */ | |
| 188 | 188 | |
| 189 | 189 | struct sk_buff *tx_skb; |
| 190 | 190 | }; |
| @@ -60,7 +60,6 @@ EXPORT_SYMBOL_GPL(can_len2dlc); · 59 unmodified lines | ||
| 60 | 60 | |
| 61 | 61 | #ifdef CONFIG_CAN_CALC_BITTIMING |
| 62 | 62 | #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ |
| 63 | −#define CAN_CALC_SYNC_SEG 1 | |
| 64 | 63 | |
| 65 | 64 | /* Bit-timing calculation derived from: |
| 66 | 65 | * |
| @@ -86,8 +85,8 @@ can_update_sample_point(const struct can_bittiming_const *btc, · 19 unmodified lines | ||
| 86 | 85 | int i; |
| 87 | 86 | |
| 88 | 87 | for (i = 0; i <= 1; i++) { |
| 89 | − tseg2 = tseg + CAN_CALC_SYNC_SEG - | |
| 90 | − (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / | |
| 88 | + tseg2 = tseg + CAN_SYNC_SEG - | |
| 89 | + (sample_point_nominal * (tseg + CAN_SYNC_SEG)) / | |
| 91 | 90 | 1000 - i; |
| 92 | 91 | tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); |
| 93 | 92 | tseg1 = tseg - tseg2; |
| @@ -96,8 +95,8 @@ can_update_sample_point(const struct can_bittiming_const *btc, · 2 unmodified lines | ||
| 96 | 95 | tseg2 = tseg - tseg1; |
| 97 | 96 | } |
| 98 | 97 | |
| 99 | − sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / | |
| 100 | − (tseg + CAN_CALC_SYNC_SEG); | |
| 98 | + sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) / | |
| 99 | + (tseg + CAN_SYNC_SEG); | |
| 101 | 100 | sample_point_error = abs(sample_point_nominal - sample_point); |
| 102 | 101 | |
| 103 | 102 | if (sample_point <= sample_point_nominal && |
| @@ -145,7 +144,7 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, · 41 unmodified lines | ||
| 145 | 144 | /* tseg even = round down, odd = round up */ |
| 146 | 145 | for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; |
| 147 | 146 | tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { |
| 148 | − tsegall = CAN_CALC_SYNC_SEG + tseg / 2; | |
| 147 | + tsegall = CAN_SYNC_SEG + tseg / 2; | |
| 149 | 148 | |
| 150 | 149 | /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ |
| 151 | 150 | brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; |
| @@ -223,7 +222,7 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, · 71 unmodified lines | ||
| 223 | 222 | |
| 224 | 223 | /* real bitrate */ |
| 225 | 224 | bt->bitrate = priv->clock.freq / |
| 226 | − (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2)); | |
| 225 | + (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2)); | |
| 227 | 226 | |
| 228 | 227 | return 0; |
| 229 | 228 | } |
| @@ -371,6 +370,28 @@ static int can_rx_state_to_frame(struct net_device *dev, enum can_state state) · 141 unmodified lines | ||
| 371 | 370 | } |
| 372 | 371 | } |
| 373 | 372 | |
| 373 | +static const char *can_get_state_str(const enum can_state state) | |
| 374 | +{ | |
| 375 | + switch (state) { | |
| 376 | + case CAN_STATE_ERROR_ACTIVE: | |
| 377 | + return "Error Active"; | |
| 378 | + case CAN_STATE_ERROR_WARNING: | |
| 379 | + return "Error Warning"; | |
| 380 | + case CAN_STATE_ERROR_PASSIVE: | |
| 381 | + return "Error Passive"; | |
| 382 | + case CAN_STATE_BUS_OFF: | |
| 383 | + return "Bus Off"; | |
| 384 | + case CAN_STATE_STOPPED: | |
| 385 | + return "Stopped"; | |
| 386 | + case CAN_STATE_SLEEPING: | |
| 387 | + return "Sleeping"; | |
| 388 | + default: | |
| 389 | + return "<unknown>"; | |
| 390 | + } | |
| 391 | + | |
| 392 | + return "<unknown>"; | |
| 393 | +} | |
| 394 | + | |
| 374 | 395 | void can_change_state(struct net_device *dev, struct can_frame *cf, |
| 375 | 396 | enum can_state tx_state, enum can_state rx_state) |
| 376 | 397 | { |
| @@ -382,7 +403,9 @@ void can_change_state(struct net_device *dev, struct can_frame *cf, · 5 unmodified lines | ||
| 382 | 403 | return; |
| 383 | 404 | } |
| 384 | 405 | |
| 385 | − netdev_dbg(dev, "New error state: %d\n", new_state); | |
| 406 | + netdev_dbg(dev, "Controller changed from %s State (%d) into %s State (%d).\n", | |
| 407 | + can_get_state_str(priv->state), priv->state, | |
| 408 | + can_get_state_str(new_state), new_state); | |
| 386 | 409 | |
| 387 | 410 | can_update_state_error_stats(dev, new_state); |
| 388 | 411 | priv->state = new_state; |
| @@ -434,8 +457,8 @@ static void can_flush_echo_skb(struct net_device *dev) · 45 unmodified lines | ||
| 434 | 457 | * of the device driver. The driver must protect access to |
| 435 | 458 | * priv->echo_skb, if necessary. |
| 436 | 459 | */ |
| 437 | −void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, | |
| 438 | − unsigned int idx) | |
| 460 | +int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, | |
| 461 | + unsigned int idx) | |
| 439 | 462 | { |
| 440 | 463 | struct can_priv *priv = netdev_priv(dev); |
| 441 | 464 | |
| @@ -446,13 +469,13 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, · 4 unmodified lines | ||
| 446 | 469 | (skb->protocol != htons(ETH_P_CAN) && |
| 447 | 470 | skb->protocol != htons(ETH_P_CANFD))) { |
| 448 | 471 | kfree_skb(skb); |
| 449 | − return; | |
| 472 | + return 0; | |
| 450 | 473 | } |
| 451 | 474 | |
| 452 | 475 | if (!priv->echo_skb[idx]) { |
| 453 | 476 | skb = can_create_echo_skb(skb); |
| 454 | 477 | if (!skb) |
| 455 | − return; | |
| 478 | + return -ENOMEM; | |
| 456 | 479 | |
| 457 | 480 | /* make settings for echo to reduce code in irq context */ |
| 458 | 481 | skb->pkt_type = PACKET_BROADCAST; |
| @@ -463,9 +486,12 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, · 4 unmodified lines | ||
| 463 | 486 | priv->echo_skb[idx] = skb; |
| 464 | 487 | } else { |
| 465 | 488 | /* locking problem with netif_stop_queue() ?? */ |
| 466 | − netdev_err(dev, "%s: BUG! echo_skb is occupied!\n", __func__); | |
| 489 | + netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx); | |
| 467 | 490 | kfree_skb(skb); |
| 491 | + return -EBUSY; | |
| 468 | 492 | } |
| 493 | + | |
| 494 | + return 0; | |
| 469 | 495 | } |
| 470 | 496 | EXPORT_SYMBOL_GPL(can_put_echo_skb); |
| 471 | 497 | |
| @@ -612,7 +638,11 @@ void can_bus_off(struct net_device *dev) · 140 unmodified lines | ||
| 612 | 638 | { |
| 613 | 639 | struct can_priv *priv = netdev_priv(dev); |
| 614 | 640 | |
| 615 | − netdev_info(dev, "bus-off\n"); | |
| 641 | + if (priv->restart_ms) | |
| 642 | + netdev_info(dev, "bus-off, scheduling restart in %d ms\n", | |
| 643 | + priv->restart_ms); | |
| 644 | + else | |
| 645 | + netdev_info(dev, "bus-off\n"); | |
| 616 | 646 | |
| 617 | 647 | netif_carrier_off(dev); |
| 618 | 648 | |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | // |
| 10 | 10 | // Based on code originally by Andrey Volkov <avolkov@varma-el.com> |
| 11 | 11 | |
| 12 | −#include <linux/netdevice.h> | |
| 12 | +#include <linux/bitfield.h> | |
| 13 | 13 | #include <linux/can.h> |
| 14 | 14 | #include <linux/can/dev.h> |
| 15 | 15 | #include <linux/can/error.h> |
| @@ -21,12 +21,14 @@ · 5 unmodified lines | ||
| 21 | 21 | #include <linux/io.h> |
| 22 | 22 | #include <linux/mfd/syscon.h> |
| 23 | 23 | #include <linux/module.h> |
| 24 | +#include <linux/netdevice.h> | |
| 24 | 25 | #include <linux/of.h> |
| 25 | 26 | #include <linux/of_device.h> |
| 27 | +#include <linux/pinctrl/consumer.h> | |
| 26 | 28 | #include <linux/platform_device.h> |
| 27 | 29 | #include <linux/pm_runtime.h> |
| 28 | −#include <linux/regulator/consumer.h> | |
| 29 | 30 | #include <linux/regmap.h> |
| 31 | +#include <linux/regulator/consumer.h> | |
| 30 | 32 | |
| 31 | 33 | #define DRV_NAME "flexcan" |
| 32 | 34 | |
| @@ -52,6 +54,7 @@ · 19 unmodified lines | ||
| 52 | 54 | #define FLEXCAN_MCR_IRMQ BIT(16) |
| 53 | 55 | #define FLEXCAN_MCR_LPRIO_EN BIT(13) |
| 54 | 56 | #define FLEXCAN_MCR_AEN BIT(12) |
| 57 | +#define FLEXCAN_MCR_FDEN BIT(11) | |
| 55 | 58 | /* MCR_MAXMB: maximum used MBs is MAXMB + 1 */ |
| 56 | 59 | #define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f) |
| 57 | 60 | #define FLEXCAN_MCR_IDAM_A (0x0 << 8) |
| @@ -91,6 +94,7 @@ · 33 unmodified lines | ||
| 91 | 94 | #define FLEXCAN_CTRL2_MRP BIT(18) |
| 92 | 95 | #define FLEXCAN_CTRL2_RRS BIT(17) |
| 93 | 96 | #define FLEXCAN_CTRL2_EACEN BIT(16) |
| 97 | +#define FLEXCAN_CTRL2_ISOCANFDEN BIT(12) | |
| 94 | 98 | |
| 95 | 99 | /* FLEXCAN memory error control register (MECR) bits */ |
| 96 | 100 | #define FLEXCAN_MECR_ECRWRDIS BIT(31) |
| @@ -134,8 +138,35 @@ · 37 unmodified lines | ||
| 134 | 138 | (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE) |
| 135 | 139 | #define FLEXCAN_ESR_ALL_INT \ |
| 136 | 140 | (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \ |
| 137 | − FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \ | |
| 138 | − FLEXCAN_ESR_WAK_INT) | |
| 141 | + FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT) | |
| 142 | + | |
| 143 | +/* FLEXCAN Bit Timing register (CBT) bits */ | |
| 144 | +#define FLEXCAN_CBT_BTF BIT(31) | |
| 145 | +#define FLEXCAN_CBT_EPRESDIV_MASK GENMASK(30, 21) | |
| 146 | +#define FLEXCAN_CBT_ERJW_MASK GENMASK(20, 16) | |
| 147 | +#define FLEXCAN_CBT_EPROPSEG_MASK GENMASK(15, 10) | |
| 148 | +#define FLEXCAN_CBT_EPSEG1_MASK GENMASK(9, 5) | |
| 149 | +#define FLEXCAN_CBT_EPSEG2_MASK GENMASK(4, 0) | |
| 150 | + | |
| 151 | +/* FLEXCAN FD control register (FDCTRL) bits */ | |
| 152 | +#define FLEXCAN_FDCTRL_FDRATE BIT(31) | |
| 153 | +#define FLEXCAN_FDCTRL_MBDSR1 GENMASK(20, 19) | |
| 154 | +#define FLEXCAN_FDCTRL_MBDSR0 GENMASK(17, 16) | |
| 155 | +#define FLEXCAN_FDCTRL_MBDSR_8 0x0 | |
| 156 | +#define FLEXCAN_FDCTRL_MBDSR_12 0x1 | |
| 157 | +#define FLEXCAN_FDCTRL_MBDSR_32 0x2 | |
| 158 | +#define FLEXCAN_FDCTRL_MBDSR_64 0x3 | |
| 159 | +#define FLEXCAN_FDCTRL_TDCEN BIT(15) | |
| 160 | +#define FLEXCAN_FDCTRL_TDCFAIL BIT(14) | |
| 161 | +#define FLEXCAN_FDCTRL_TDCOFF GENMASK(12, 8) | |
| 162 | +#define FLEXCAN_FDCTRL_TDCVAL GENMASK(5, 0) | |
| 163 | + | |
| 164 | +/* FLEXCAN FD Bit Timing register (FDCBT) bits */ | |
| 165 | +#define FLEXCAN_FDCBT_FPRESDIV_MASK GENMASK(29, 20) | |
| 166 | +#define FLEXCAN_FDCBT_FRJW_MASK GENMASK(18, 16) | |
| 167 | +#define FLEXCAN_FDCBT_FPROPSEG_MASK GENMASK(14, 10) | |
| 168 | +#define FLEXCAN_FDCBT_FPSEG1_MASK GENMASK(7, 5) | |
| 169 | +#define FLEXCAN_FDCBT_FPSEG2_MASK GENMASK(2, 0) | |
| 139 | 170 | |
| 140 | 171 | /* FLEXCAN interrupt flag register (IFLAG) bits */ |
| 141 | 172 | /* Errata ERR005829 step7: Reserve first valid MB */ |
| @@ -161,6 +192,9 @@ · 19 unmodified lines | ||
| 161 | 192 | #define FLEXCAN_MB_CODE_TX_DATA (0xc << 24) |
| 162 | 193 | #define FLEXCAN_MB_CODE_TX_TANSWER (0xe << 24) |
| 163 | 194 | |
| 195 | +#define FLEXCAN_MB_CNT_EDL BIT(31) | |
| 196 | +#define FLEXCAN_MB_CNT_BRS BIT(30) | |
| 197 | +#define FLEXCAN_MB_CNT_ESI BIT(29) | |
| 164 | 198 | #define FLEXCAN_MB_CNT_SRR BIT(22) |
| 165 | 199 | #define FLEXCAN_MB_CNT_IDE BIT(21) |
| 166 | 200 | #define FLEXCAN_MB_CNT_RTR BIT(20) |
| @@ -172,26 +206,42 @@ · 5 unmodified lines | ||
| 172 | 206 | /* FLEXCAN hardware feature flags |
| 173 | 207 | * |
| 174 | 208 | * Below is some version info we got: |
| 175 | − * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR re- | |
| 176 | − * Filter? connected? Passive detection ception in MB | |
| 177 | − * MX25 FlexCAN2 03.00.00.00 no no no no no | |
| 178 | − * MX28 FlexCAN2 03.00.04.00 yes yes no no no | |
| 179 | − * MX35 FlexCAN2 03.00.00.00 no no no no no | |
| 180 | − * MX53 FlexCAN2 03.00.00.00 yes no no no no | |
| 181 | − * MX6s FlexCAN3 10.00.12.00 yes yes no no yes | |
| 182 | − * VF610 FlexCAN3 ? no yes no yes yes? | |
| 183 | − * LS1021A FlexCAN2 03.00.04.00 no yes no no yes | |
| 209 | + * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode | |
| 210 | + * Filter? connected? Passive detection ption in MB Supported? | |
| 211 | + * MX25 FlexCAN2 03.00.00.00 no no no no no no | |
| 212 | + * MX28 FlexCAN2 03.00.04.00 yes yes no no no no | |
| 213 | + * MX35 FlexCAN2 03.00.00.00 no no no no no no | |
| 214 | + * MX53 FlexCAN2 03.00.00.00 yes no no no no no | |
| 215 | + * MX6s FlexCAN3 10.00.12.00 yes yes no no yes no | |
| 216 | + * MX8QM FlexCAN3 03.00.23.00 yes yes no no yes yes | |
| 217 | + * MX8MP FlexCAN3 03.00.17.01 yes yes no yes yes yes | |
| 218 | + * VF610 FlexCAN3 ? no yes no yes yes? no | |
| 219 | + * LS1021A FlexCAN2 03.00.04.00 no yes no no yes no | |
| 220 | + * LX2160A FlexCAN3 03.00.23.00 no yes no no yes yes | |
| 184 | 221 | * |
| 185 | 222 | * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. |
| 186 | 223 | */ |
| 187 | −#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) /* [TR]WRN_INT not connected */ | |
| 188 | −#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */ | |
| 189 | −#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) /* Enable EACEN and RRS bit in ctrl2 */ | |
| 190 | −#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable Memory error detection */ | |
| 191 | −#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */ | |
| 192 | −#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */ | |
| 193 | −#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) /* default to BE register access */ | |
| 194 | −#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) /* Setup stop mode to support wakeup */ | |
| 224 | + | |
| 225 | +/* [TR]WRN_INT not connected */ | |
| 226 | +#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) | |
| 227 | + /* Disable RX FIFO Global mask */ | |
| 228 | +#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) | |
| 229 | +/* Enable EACEN and RRS bit in ctrl2 */ | |
| 230 | +#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) | |
| 231 | +/* Disable non-correctable errors interrupt and freeze mode */ | |
| 232 | +#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) | |
| 233 | +/* Use timestamp based offloading */ | |
| 234 | +#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) | |
| 235 | +/* No interrupt for error passive */ | |
| 236 | +#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) | |
| 237 | +/* default to BE register access */ | |
| 238 | +#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) | |
| 239 | +/* Setup stop mode to support wakeup */ | |
| 240 | +#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) | |
| 241 | +/* Support CAN-FD mode */ | |
| 242 | +#define FLEXCAN_QUIRK_SUPPORT_FD BIT(9) | |
| 243 | +/* support memory detection and correction */ | |
| 244 | +#define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10) | |
| 195 | 245 | |
| 196 | 246 | /* Structure of the message buffer */ |
| 197 | 247 | struct flexcan_mb { |
| @@ -203,12 +253,12 @@ struct flexcan_mb { · 5 unmodified lines | ||
| 203 | 253 | /* Structure of the hardware registers */ |
| 204 | 254 | struct flexcan_regs { |
| 205 | 255 | u32 mcr; /* 0x00 */ |
| 206 | − u32 ctrl; /* 0x04 */ | |
| 256 | + u32 ctrl; /* 0x04 - Not affected by Soft Reset */ | |
| 207 | 257 | u32 timer; /* 0x08 */ |
| 208 | − u32 _reserved1; /* 0x0c */ | |
| 209 | − u32 rxgmask; /* 0x10 */ | |
| 210 | − u32 rx14mask; /* 0x14 */ | |
| 211 | − u32 rx15mask; /* 0x18 */ | |
| 258 | + u32 tcr; /* 0x0c */ | |
| 259 | + u32 rxgmask; /* 0x10 - Not affected by Soft Reset */ | |
| 260 | + u32 rx14mask; /* 0x14 - Not affected by Soft Reset */ | |
| 261 | + u32 rx15mask; /* 0x18 - Not affected by Soft Reset */ | |
| 212 | 262 | u32 ecr; /* 0x1c */ |
| 213 | 263 | u32 esr; /* 0x20 */ |
| 214 | 264 | u32 imask2; /* 0x24 */ |
| @@ -217,20 +267,24 @@ struct flexcan_regs { · 2 unmodified lines | ||
| 217 | 267 | u32 iflag1; /* 0x30 */ |
| 218 | 268 | union { /* 0x34 */ |
| 219 | 269 | u32 gfwr_mx28; /* MX28, MX53 */ |
| 220 | − u32 ctrl2; /* MX6, VF610 */ | |
| 270 | + u32 ctrl2; /* MX6, VF610 - Not affected by Soft Reset */ | |
| 221 | 271 | }; |
| 222 | 272 | u32 esr2; /* 0x38 */ |
| 223 | 273 | u32 imeur; /* 0x3c */ |
| 224 | 274 | u32 lrfr; /* 0x40 */ |
| 225 | 275 | u32 crcr; /* 0x44 */ |
| 226 | 276 | u32 rxfgmask; /* 0x48 */ |
| 227 | − u32 rxfir; /* 0x4c */ | |
| 228 | − u32 _reserved3[12]; /* 0x50 */ | |
| 229 | − u8 mb[2][512]; /* 0x80 */ | |
| 277 | + u32 rxfir; /* 0x4c - Not affected by Soft Reset */ | |
| 278 | + u32 cbt; /* 0x50 - Not affected by Soft Reset */ | |
| 279 | + u32 _reserved2; /* 0x54 */ | |
| 280 | + u32 dbg1; /* 0x58 */ | |
| 281 | + u32 dbg2; /* 0x5c */ | |
| 282 | + u32 _reserved3[8]; /* 0x60 */ | |
| 283 | + u8 mb[2][512]; /* 0x80 - Not affected by Soft Reset */ | |
| 230 | 284 | /* FIFO-mode: |
| 231 | 285 | * MB |
| 232 | 286 | * 0x080...0x08f 0 RX message buffer |
| 233 | − * 0x090...0x0df 1-5 reserverd | |
| 287 | + * 0x090...0x0df 1-5 reserved | |
| 234 | 288 | * 0x0e0...0x0ff 6-7 8 entry ID table |
| 235 | 289 | * (mx25, mx28, mx35, mx53) |
| 236 | 290 | * 0x0e0...0x2df 6-7..37 8..128 entry ID table |
| @@ -238,10 +292,19 @@ struct flexcan_regs { · 1 unmodified line | ||
| 238 | 292 | * (mx6, vf610) |
| 239 | 293 | */ |
| 240 | 294 | u32 _reserved4[256]; /* 0x480 */ |
| 241 | − u32 rximr[64]; /* 0x880 */ | |
| 295 | + u32 rximr[64]; /* 0x880 - Not affected by Soft Reset */ | |
| 242 | 296 | u32 _reserved5[24]; /* 0x980 */ |
| 243 | 297 | u32 gfwr_mx6; /* 0x9e0 - MX6 */ |
| 244 | − u32 _reserved6[63]; /* 0x9e4 */ | |
| 298 | + u32 _reserved6[39]; /* 0x9e4 */ | |
| 299 | + u32 _rxfir[6]; /* 0xa80 */ | |
| 300 | + u32 _reserved8[2]; /* 0xa98 */ | |
| 301 | + u32 _rxmgmask; /* 0xaa0 */ | |
| 302 | + u32 _rxfgmask; /* 0xaa4 */ | |
| 303 | + u32 _rx14mask; /* 0xaa8 */ | |
| 304 | + u32 _rx15mask; /* 0xaac */ | |
| 305 | + u32 tx_smb[4]; /* 0xab0 */ | |
| 306 | + u32 rx_smb0[4]; /* 0xac0 */ | |
| 307 | + u32 rx_smb1[4]; /* 0xad0 */ | |
| 245 | 308 | u32 mecr; /* 0xae0 */ |
| 246 | 309 | u32 erriar; /* 0xae4 */ |
| 247 | 310 | u32 erridpr; /* 0xae8 */ |
| @@ -250,8 +313,18 @@ struct flexcan_regs { · 2 unmodified lines | ||
| 250 | 313 | u32 rerrdr; /* 0xaf4 */ |
| 251 | 314 | u32 rerrsynr; /* 0xaf8 */ |
| 252 | 315 | u32 errsr; /* 0xafc */ |
| 316 | + u32 _reserved7[64]; /* 0xb00 */ | |
| 317 | + u32 fdctrl; /* 0xc00 - Not affected by Soft Reset */ | |
| 318 | + u32 fdcbt; /* 0xc04 - Not affected by Soft Reset */ | |
| 319 | + u32 fdcrc; /* 0xc08 */ | |
| 320 | + u32 _reserved9[199]; /* 0xc0c */ | |
| 321 | + u32 tx_smb_fd[18]; /* 0xf28 */ | |
| 322 | + u32 rx_smb0_fd[18]; /* 0xf70 */ | |
| 323 | + u32 rx_smb1_fd[18]; /* 0xfb8 */ | |
| 253 | 324 | }; |
| 254 | 325 | |
| 326 | +static_assert(sizeof(struct flexcan_regs) == 0x4 * 18 + 0xfb8); | |
| 327 | + | |
| 255 | 328 | struct flexcan_devtype_data { |
| 256 | 329 | u32 quirks; /* quirks needed for different IP cores */ |
| 257 | 330 | }; |
| @@ -260,8 +333,6 @@ struct flexcan_stop_mode { · 2 unmodified lines | ||
| 260 | 333 | struct regmap *gpr; |
| 261 | 334 | u8 req_gpr; |
| 262 | 335 | u8 req_bit; |
| 263 | − u8 ack_gpr; | |
| 264 | − u8 ack_bit; | |
| 265 | 336 | }; |
| 266 | 337 | |
| 267 | 338 | struct flexcan_priv { |
| @@ -313,6 +384,19 @@ static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { · 45 unmodified lines | ||
| 313 | 384 | FLEXCAN_QUIRK_SETUP_STOP_MODE, |
| 314 | 385 | }; |
| 315 | 386 | |
| 387 | +static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = { | |
| 388 | + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | | |
| 389 | + FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | | |
| 390 | + FLEXCAN_QUIRK_SUPPORT_FD, | |
| 391 | +}; | |
| 392 | + | |
| 393 | +static struct flexcan_devtype_data fsl_imx8mp_devtype_data = { | |
| 394 | + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | | |
| 395 | + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | | |
| 396 | + FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE | | |
| 397 | + FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC, | |
| 398 | +}; | |
| 399 | + | |
| 316 | 400 | static const struct flexcan_devtype_data fsl_vf610_devtype_data = { |
| 317 | 401 | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | |
| 318 | 402 | FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | |
| @@ -325,6 +409,12 @@ static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = { · 6 unmodified lines | ||
| 325 | 409 | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP, |
| 326 | 410 | }; |
| 327 | 411 | |
| 412 | +static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = { | |
| 413 | + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | | |
| 414 | + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE | | |
| 415 | + FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_SUPPORT_FD, | |
| 416 | +}; | |
| 417 | + | |
| 328 | 418 | static const struct can_bittiming_const flexcan_bittiming_const = { |
| 329 | 419 | .name = DRV_NAME, |
| 330 | 420 | .tseg1_min = 4, |
| @@ -337,6 +427,30 @@ static const struct can_bittiming_const flexcan_bittiming_const = { · 6 unmodified lines | ||
| 337 | 427 | .brp_inc = 1, |
| 338 | 428 | }; |
| 339 | 429 | |
| 430 | +static const struct can_bittiming_const flexcan_fd_bittiming_const = { | |
| 431 | + .name = DRV_NAME, | |
| 432 | + .tseg1_min = 2, | |
| 433 | + .tseg1_max = 96, | |
| 434 | + .tseg2_min = 2, | |
| 435 | + .tseg2_max = 32, | |
| 436 | + .sjw_max = 16, | |
| 437 | + .brp_min = 1, | |
| 438 | + .brp_max = 1024, | |
| 439 | + .brp_inc = 1, | |
| 440 | +}; | |
| 441 | + | |
| 442 | +static const struct can_bittiming_const flexcan_fd_data_bittiming_const = { | |
| 443 | + .name = DRV_NAME, | |
| 444 | + .tseg1_min = 2, | |
| 445 | + .tseg1_max = 39, | |
| 446 | + .tseg2_min = 2, | |
| 447 | + .tseg2_max = 8, | |
| 448 | + .sjw_max = 4, | |
| 449 | + .brp_min = 1, | |
| 450 | + .brp_max = 1024, | |
| 451 | + .brp_inc = 1, | |
| 452 | +}; | |
| 453 | + | |
| 340 | 454 | /* FlexCAN module is essentially modelled as a little-endian IP in most |
| 341 | 455 | * SoCs, i.e the registers as well as the message buffer areas are |
| 342 | 456 | * implemented in a little-endian fashion. |
| @@ -457,7 +571,6 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) · 114 unmodified lines | ||
| 457 | 571 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
| 458 | 572 | 1 << priv->stm.req_bit, 0); |
| 459 | 573 | |
| 460 | − | |
| 461 | 574 | reg_mcr = priv->read(®s->mcr); |
| 462 | 575 | reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; |
| 463 | 576 | priv->write(reg_mcr, ®s->mcr); |
| @@ -628,10 +741,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev, · 164 unmodified lines | ||
| 628 | 741 | static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) |
| 629 | 742 | { |
| 630 | 743 | const struct flexcan_priv *priv = netdev_priv(dev); |
| 631 | − struct can_frame *cf = (struct can_frame *)skb->data; | |
| 744 | + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; | |
| 632 | 745 | u32 can_id; |
| 633 | 746 | u32 data; |
| 634 | − u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16); | |
| 747 | + u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16); | |
| 635 | 748 | int i; |
| 636 | 749 | |
| 637 | 750 | if (can_dropped_invalid_skb(dev, skb)) |
| @@ -639,18 +752,25 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de · 1 unmodified line | ||
| 639 | 752 | |
| 640 | 753 | netif_stop_queue(dev); |
| 641 | 754 | |
| 642 | − if (cf->can_id & CAN_EFF_FLAG) { | |
| 643 | − can_id = cf->can_id & CAN_EFF_MASK; | |
| 755 | + if (cfd->can_id & CAN_EFF_FLAG) { | |
| 756 | + can_id = cfd->can_id & CAN_EFF_MASK; | |
| 644 | 757 | ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; |
| 645 | 758 | } else { |
| 646 | − can_id = (cf->can_id & CAN_SFF_MASK) << 18; | |
| 759 | + can_id = (cfd->can_id & CAN_SFF_MASK) << 18; | |
| 647 | 760 | } |
| 648 | 761 | |
| 649 | − if (cf->can_id & CAN_RTR_FLAG) | |
| 762 | + if (cfd->can_id & CAN_RTR_FLAG) | |
| 650 | 763 | ctrl |= FLEXCAN_MB_CNT_RTR; |
| 651 | 764 | |
| 652 | − for (i = 0; i < cf->can_dlc; i += sizeof(u32)) { | |
| 653 | − data = be32_to_cpup((__be32 *)&cf->data[i]); | |
| 765 | + if (can_is_canfd_skb(skb)) { | |
| 766 | + ctrl |= FLEXCAN_MB_CNT_EDL; | |
| 767 | + | |
| 768 | + if (cfd->flags & CANFD_BRS) | |
| 769 | + ctrl |= FLEXCAN_MB_CNT_BRS; | |
| 770 | + } | |
| 771 | + | |
| 772 | + for (i = 0; i < cfd->len; i += sizeof(u32)) { | |
| 773 | + data = be32_to_cpup((__be32 *)&cfd->data[i]); | |
| 654 | 774 | priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]); |
| 655 | 775 | } |
| 656 | 776 | |
| @@ -822,7 +942,7 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, · 165 unmodified lines | ||
| 822 | 942 | struct flexcan_regs __iomem *regs = priv->regs; |
| 823 | 943 | struct flexcan_mb __iomem *mb; |
| 824 | 944 | struct sk_buff *skb; |
| 825 | − struct can_frame *cf; | |
| 945 | + struct canfd_frame *cfd; | |
| 826 | 946 | u32 reg_ctrl, reg_id, reg_iflag1; |
| 827 | 947 | int i; |
| 828 | 948 | |
| @@ -859,8 +979,11 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, · 30 unmodified lines | ||
| 859 | 979 | reg_ctrl = priv->read(&mb->can_ctrl); |
| 860 | 980 | } |
| 861 | 981 | |
| 862 | − skb = alloc_can_skb(offload->dev, &cf); | |
| 863 | − if (!skb) { | |
| 982 | + if (reg_ctrl & FLEXCAN_MB_CNT_EDL) | |
| 983 | + skb = alloc_canfd_skb(offload->dev, &cfd); | |
| 984 | + else | |
| 985 | + skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd); | |
| 986 | + if (unlikely(!skb)) { | |
| 864 | 987 | skb = ERR_PTR(-ENOMEM); |
| 865 | 988 | goto mark_as_read; |
| 866 | 989 | } |
| @@ -870,17 +993,28 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, · 3 unmodified lines | ||
| 870 | 993 | |
| 871 | 994 | reg_id = priv->read(&mb->can_id); |
| 872 | 995 | if (reg_ctrl & FLEXCAN_MB_CNT_IDE) |
| 873 | − cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG; | |
| 996 | + cfd->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG; | |
| 874 | 997 | else |
| 875 | − cf->can_id = (reg_id >> 18) & CAN_SFF_MASK; | |
| 998 | + cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK; | |
| 999 | + | |
| 1000 | + if (reg_ctrl & FLEXCAN_MB_CNT_EDL) { | |
| 1001 | + cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf)); | |
| 1002 | + | |
| 1003 | + if (reg_ctrl & FLEXCAN_MB_CNT_BRS) | |
| 1004 | + cfd->flags |= CANFD_BRS; | |
| 1005 | + } else { | |
| 1006 | + cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf); | |
| 1007 | + | |
| 1008 | + if (reg_ctrl & FLEXCAN_MB_CNT_RTR) | |
| 1009 | + cfd->can_id |= CAN_RTR_FLAG; | |
| 1010 | + } | |
| 876 | 1011 | |
| 877 | − if (reg_ctrl & FLEXCAN_MB_CNT_RTR) | |
| 878 | − cf->can_id |= CAN_RTR_FLAG; | |
| 879 | − cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf); | |
| 1012 | + if (reg_ctrl & FLEXCAN_MB_CNT_ESI) | |
| 1013 | + cfd->flags |= CANFD_ESI; | |
| 880 | 1014 | |
| 881 | − for (i = 0; i < cf->can_dlc; i += sizeof(u32)) { | |
| 1015 | + for (i = 0; i < cfd->len; i += sizeof(u32)) { | |
| 882 | 1016 | __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)])); |
| 883 | − *(__be32 *)(cf->data + i) = data; | |
| 1017 | + *(__be32 *)(cfd->data + i) = data; | |
| 884 | 1018 | } |
| 885 | 1019 | |
| 886 | 1020 | mark_as_read: |
| @@ -961,10 +1095,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) · 74 unmodified lines | ||
| 961 | 1095 | |
| 962 | 1096 | reg_esr = priv->read(®s->esr); |
| 963 | 1097 | |
| 964 | − /* ACK all bus error and state change IRQ sources */ | |
| 965 | − if (reg_esr & FLEXCAN_ESR_ALL_INT) { | |
| 1098 | + /* ACK all bus error, state change and wake IRQ sources */ | |
| 1099 | + if (reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT)) { | |
| 966 | 1100 | handled = IRQ_HANDLED; |
| 967 | − priv->write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr); | |
| 1101 | + priv->write(reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT), ®s->esr); | |
| 968 | 1102 | } |
| 969 | 1103 | |
| 970 | 1104 | /* state change interrupt or broken error state quirk fix is enabled */ |
| @@ -1019,7 +1153,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) · 48 unmodified lines | ||
| 1019 | 1153 | return handled; |
| 1020 | 1154 | } |
| 1021 | 1155 | |
| 1022 | −static void flexcan_set_bittiming(struct net_device *dev) | |
| 1156 | +static void flexcan_set_bittiming_ctrl(const struct net_device *dev) | |
| 1023 | 1157 | { |
| 1024 | 1158 | const struct flexcan_priv *priv = netdev_priv(dev); |
| 1025 | 1159 | const struct can_bittiming *bt = &priv->can.bittiming; |
| @@ -1031,10 +1165,7 @@ static void flexcan_set_bittiming(struct net_device *dev) · 5 unmodified lines | ||
| 1031 | 1165 | FLEXCAN_CTRL_RJW(0x3) | |
| 1032 | 1166 | FLEXCAN_CTRL_PSEG1(0x7) | |
| 1033 | 1167 | FLEXCAN_CTRL_PSEG2(0x7) | |
| 1034 | − FLEXCAN_CTRL_PROPSEG(0x7) | | |
| 1035 | − FLEXCAN_CTRL_LPB | | |
| 1036 | − FLEXCAN_CTRL_SMP | | |
| 1037 | − FLEXCAN_CTRL_LOM); | |
| 1168 | + FLEXCAN_CTRL_PROPSEG(0x7)); | |
| 1038 | 1169 | |
| 1039 | 1170 | reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) | |
| 1040 | 1171 | FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) | |
| @@ -1042,6 +1173,130 @@ static void flexcan_set_bittiming(struct net_device *dev) · 1 unmodified line | ||
| 1042 | 1173 | FLEXCAN_CTRL_RJW(bt->sjw - 1) | |
| 1043 | 1174 | FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1); |
| 1044 | 1175 | |
| 1176 | + netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); | |
| 1177 | + priv->write(reg, ®s->ctrl); | |
| 1178 | + | |
| 1179 | + /* print chip status */ | |
| 1180 | + netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, | |
| 1181 | + priv->read(®s->mcr), priv->read(®s->ctrl)); | |
| 1182 | +} | |
| 1183 | + | |
| 1184 | +static void flexcan_set_bittiming_cbt(const struct net_device *dev) | |
| 1185 | +{ | |
| 1186 | + struct flexcan_priv *priv = netdev_priv(dev); | |
| 1187 | + struct can_bittiming *bt = &priv->can.bittiming; | |
| 1188 | + struct can_bittiming *dbt = &priv->can.data_bittiming; | |
| 1189 | + struct flexcan_regs __iomem *regs = priv->regs; | |
| 1190 | + u32 reg_cbt, reg_fdctrl; | |
| 1191 | + | |
| 1192 | + /* CBT */ | |
| 1193 | + /* CBT[EPSEG1] is 5 bit long and CBT[EPROPSEG] is 6 bit | |
| 1194 | + * long. The can_calc_bittiming() tries to divide the tseg1 | |
| 1195 | + * equally between phase_seg1 and prop_seg, which may not fit | |
| 1196 | + * in CBT register. Therefore, if phase_seg1 is more than | |
| 1197 | + * possible value, increase prop_seg and decrease phase_seg1. | |
| 1198 | + */ | |
| 1199 | + if (bt->phase_seg1 > 0x20) { | |
| 1200 | + bt->prop_seg += (bt->phase_seg1 - 0x20); | |
| 1201 | + bt->phase_seg1 = 0x20; | |
| 1202 | + } | |
| 1203 | + | |
| 1204 | + reg_cbt = FLEXCAN_CBT_BTF | | |
| 1205 | + FIELD_PREP(FLEXCAN_CBT_EPRESDIV_MASK, bt->brp - 1) | | |
| 1206 | + FIELD_PREP(FLEXCAN_CBT_ERJW_MASK, bt->sjw - 1) | | |
| 1207 | + FIELD_PREP(FLEXCAN_CBT_EPROPSEG_MASK, bt->prop_seg - 1) | | |
| 1208 | + FIELD_PREP(FLEXCAN_CBT_EPSEG1_MASK, bt->phase_seg1 - 1) | | |
| 1209 | + FIELD_PREP(FLEXCAN_CBT_EPSEG2_MASK, bt->phase_seg2 - 1); | |
| 1210 | + | |
| 1211 | + netdev_dbg(dev, "writing cbt=0x%08x\n", reg_cbt); | |
| 1212 | + priv->write(reg_cbt, ®s->cbt); | |
| 1213 | + | |
| 1214 | + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { | |
| 1215 | + u32 reg_fdcbt, reg_ctrl2; | |
| 1216 | + | |
| 1217 | + if (bt->brp != dbt->brp) | |
| 1218 | + netdev_warn(dev, "Data brp=%d and brp=%d don't match, this may result in a phase error. Consider using different bitrate and/or data bitrate.\n", | |
| 1219 | + dbt->brp, bt->brp); | |
| 1220 | + | |
| 1221 | + /* FDCBT */ | |
| 1222 | + /* FDCBT[FPSEG1] is 3 bit long and FDCBT[FPROPSEG] is | |
| 1223 | + * 5 bit long. The can_calc_bittiming tries to divide | |
| 1224 | + * the tseg1 equally between phase_seg1 and prop_seg, | |
| 1225 | + * which may not fit in FDCBT register. Therefore, if | |
| 1226 | + * phase_seg1 is more than possible value, increase | |
| 1227 | + * prop_seg and decrease phase_seg1 | |
| 1228 | + */ | |
| 1229 | + if (dbt->phase_seg1 > 0x8) { | |
| 1230 | + dbt->prop_seg += (dbt->phase_seg1 - 0x8); | |
| 1231 | + dbt->phase_seg1 = 0x8; | |
| 1232 | + } | |
| 1233 | + | |
| 1234 | + reg_fdcbt = priv->read(®s->fdcbt); | |
| 1235 | + reg_fdcbt &= ~(FIELD_PREP(FLEXCAN_FDCBT_FPRESDIV_MASK, 0x3ff) | | |
| 1236 | + FIELD_PREP(FLEXCAN_FDCBT_FRJW_MASK, 0x7) | | |
| 1237 | + FIELD_PREP(FLEXCAN_FDCBT_FPROPSEG_MASK, 0x1f) | | |
| 1238 | + FIELD_PREP(FLEXCAN_FDCBT_FPSEG1_MASK, 0x7) | | |
| 1239 | + FIELD_PREP(FLEXCAN_FDCBT_FPSEG2_MASK, 0x7)); | |
| 1240 | + | |
| 1241 | + reg_fdcbt |= FIELD_PREP(FLEXCAN_FDCBT_FPRESDIV_MASK, dbt->brp - 1) | | |
| 1242 | + FIELD_PREP(FLEXCAN_FDCBT_FRJW_MASK, dbt->sjw - 1) | | |
| 1243 | + FIELD_PREP(FLEXCAN_FDCBT_FPROPSEG_MASK, dbt->prop_seg) | | |
| 1244 | + FIELD_PREP(FLEXCAN_FDCBT_FPSEG1_MASK, dbt->phase_seg1 - 1) | | |
| 1245 | + FIELD_PREP(FLEXCAN_FDCBT_FPSEG2_MASK, dbt->phase_seg2 - 1); | |
| 1246 | + | |
| 1247 | + netdev_dbg(dev, "writing fdcbt=0x%08x\n", reg_fdcbt); | |
| 1248 | + priv->write(reg_fdcbt, ®s->fdcbt); | |
| 1249 | + | |
| 1250 | + /* CTRL2 */ | |
| 1251 | + reg_ctrl2 = priv->read(®s->ctrl2); | |
| 1252 | + reg_ctrl2 &= ~FLEXCAN_CTRL2_ISOCANFDEN; | |
| 1253 | + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) | |
| 1254 | + reg_ctrl2 |= FLEXCAN_CTRL2_ISOCANFDEN; | |
| 1255 | + | |
| 1256 | + netdev_dbg(dev, "writing ctrl2=0x%08x\n", reg_ctrl2); | |
| 1257 | + priv->write(reg_ctrl2, ®s->ctrl2); | |
| 1258 | + } | |
| 1259 | + | |
| 1260 | + /* FDCTRL */ | |
| 1261 | + reg_fdctrl = priv->read(®s->fdctrl); | |
| 1262 | + reg_fdctrl &= ~(FLEXCAN_FDCTRL_FDRATE | | |
| 1263 | + FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF, 0x1f)); | |
| 1264 | + | |
| 1265 | + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { | |
| 1266 | + reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE; | |
| 1267 | + | |
| 1268 | + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { | |
| 1269 | + /* TDC must be disabled for Loop Back mode */ | |
| 1270 | + reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN; | |
| 1271 | + } else { | |
| 1272 | + reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN | | |
| 1273 | + FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF, | |
| 1274 | + ((dbt->phase_seg1 - 1) + | |
| 1275 | + dbt->prop_seg + 2) * | |
| 1276 | + ((dbt->brp - 1 ) + 1)); | |
| 1277 | + } | |
| 1278 | + } | |
| 1279 | + | |
| 1280 | + netdev_dbg(dev, "writing fdctrl=0x%08x\n", reg_fdctrl); | |
| 1281 | + priv->write(reg_fdctrl, ®s->fdctrl); | |
| 1282 | + | |
| 1283 | + netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x ctrl2=0x%08x fdctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n", | |
| 1284 | + __func__, | |
| 1285 | + priv->read(®s->mcr), priv->read(®s->ctrl), | |
| 1286 | + priv->read(®s->ctrl2), priv->read(®s->fdctrl), | |
| 1287 | + priv->read(®s->cbt), priv->read(®s->fdcbt)); | |
| 1288 | +} | |
| 1289 | + | |
| 1290 | +static void flexcan_set_bittiming(struct net_device *dev) | |
| 1291 | +{ | |
| 1292 | + const struct flexcan_priv *priv = netdev_priv(dev); | |
| 1293 | + struct flexcan_regs __iomem *regs = priv->regs; | |
| 1294 | + u32 reg; | |
| 1295 | + | |
| 1296 | + reg = priv->read(®s->ctrl); | |
| 1297 | + reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | | |
| 1298 | + FLEXCAN_CTRL_LOM); | |
| 1299 | + | |
| 1045 | 1300 | if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) |
| 1046 | 1301 | reg |= FLEXCAN_CTRL_LPB; |
| 1047 | 1302 | if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) |
| @@ -1052,9 +1307,41 @@ static void flexcan_set_bittiming(struct net_device *dev) · 4 unmodified lines | ||
| 1052 | 1307 | netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); |
| 1053 | 1308 | priv->write(reg, ®s->ctrl); |
| 1054 | 1309 | |
| 1055 | − /* print chip status */ | |
| 1056 | − netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, | |
| 1057 | − priv->read(®s->mcr), priv->read(®s->ctrl)); | |
| 1310 | + if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) | |
| 1311 | + return flexcan_set_bittiming_cbt(dev); | |
| 1312 | + else | |
| 1313 | + return flexcan_set_bittiming_ctrl(dev); | |
| 1314 | +} | |
| 1315 | + | |
| 1316 | +static void flexcan_ram_init(struct net_device *dev) | |
| 1317 | +{ | |
| 1318 | + struct flexcan_priv *priv = netdev_priv(dev); | |
| 1319 | + struct flexcan_regs __iomem *regs = priv->regs; | |
| 1320 | + u32 reg_ctrl2; | |
| 1321 | + | |
| 1322 | + /* 11.8.3.13 Detection and correction of memory errors: | |
| 1323 | + * CTRL2[WRMFRZ] grants write access to all memory positions | |
| 1324 | + * that require initialization, ranging from 0x080 to 0xADF | |
| 1325 | + * and from 0xF28 to 0xFFF when the CAN FD feature is enabled. | |
| 1326 | + * The RXMGMASK, RX14MASK, RX15MASK, and RXFGMASK registers | |
| 1327 | + * need to be initialized as well. MCR[RFEN] must not be set | |
| 1328 | + * during memory initialization. | |
| 1329 | + */ | |
| 1330 | + reg_ctrl2 = priv->read(®s->ctrl2); | |
| 1331 | + reg_ctrl2 |= FLEXCAN_CTRL2_WRMFRZ; | |
| 1332 | + priv->write(reg_ctrl2, ®s->ctrl2); | |
| 1333 | + | |
| 1334 | + memset_io(®s->mb[0][0], 0, | |
| 1335 | + offsetof(struct flexcan_regs, rx_smb1[3]) - | |
| 1336 | + offsetof(struct flexcan_regs, mb[0][0]) + 0x4); | |
| 1337 | + | |
| 1338 | + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) | |
| 1339 | + memset_io(®s->tx_smb_fd[0], 0, | |
| 1340 | + offsetof(struct flexcan_regs, rx_smb1_fd[17]) - | |
| 1341 | + offsetof(struct flexcan_regs, tx_smb_fd[0]) + 0x4); | |
| 1342 | + | |
| 1343 | + reg_ctrl2 &= ~FLEXCAN_CTRL2_WRMFRZ; | |
| 1344 | + priv->write(reg_ctrl2, ®s->ctrl2); | |
| 1058 | 1345 | } |
| 1059 | 1346 | |
| 1060 | 1347 | /* flexcan_chip_start |
| @@ -1081,6 +1368,9 @@ static int flexcan_chip_start(struct net_device *dev) · 20 unmodified lines | ||
| 1081 | 1368 | if (err) |
| 1082 | 1369 | goto out_chip_disable; |
| 1083 | 1370 | |
| 1371 | + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_ECC) | |
| 1372 | + flexcan_ram_init(dev); | |
| 1373 | + | |
| 1084 | 1374 | flexcan_set_bittiming(dev); |
| 1085 | 1375 | |
| 1086 | 1376 | /* MCR |
| @@ -1127,6 +1417,12 @@ static int flexcan_chip_start(struct net_device *dev) · 40 unmodified lines | ||
| 1127 | 1417 | else |
| 1128 | 1418 | reg_mcr |= FLEXCAN_MCR_SRX_DIS; |
| 1129 | 1419 | |
| 1420 | + /* MCR - CAN-FD */ | |
| 1421 | + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) | |
| 1422 | + reg_mcr |= FLEXCAN_MCR_FDEN; | |
| 1423 | + else | |
| 1424 | + reg_mcr &= ~FLEXCAN_MCR_FDEN; | |
| 1425 | + | |
| 1130 | 1426 | netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); |
| 1131 | 1427 | priv->write(reg_mcr, ®s->mcr); |
| 1132 | 1428 | |
| @@ -1169,6 +1465,32 @@ static int flexcan_chip_start(struct net_device *dev) · 36 unmodified lines | ||
| 1169 | 1465 | priv->write(reg_ctrl2, ®s->ctrl2); |
| 1170 | 1466 | } |
| 1171 | 1467 | |
| 1468 | + if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { | |
| 1469 | + u32 reg_fdctrl; | |
| 1470 | + | |
| 1471 | + reg_fdctrl = priv->read(®s->fdctrl); | |
| 1472 | + reg_fdctrl &= ~(FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, 0x3) | | |
| 1473 | + FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, 0x3)); | |
| 1474 | + | |
| 1475 | + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { | |
| 1476 | + reg_fdctrl |= | |
| 1477 | + FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, | |
| 1478 | + FLEXCAN_FDCTRL_MBDSR_64) | | |
| 1479 | + FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, | |
| 1480 | + FLEXCAN_FDCTRL_MBDSR_64); | |
| 1481 | + } else { | |
| 1482 | + reg_fdctrl |= | |
| 1483 | + FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, | |
| 1484 | + FLEXCAN_FDCTRL_MBDSR_8) | | |
| 1485 | + FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, | |
| 1486 | + FLEXCAN_FDCTRL_MBDSR_8); | |
| 1487 | + } | |
| 1488 | + | |
| 1489 | + netdev_dbg(dev, "%s: writing fdctrl=0x%08x", | |
| 1490 | + __func__, reg_fdctrl); | |
| 1491 | + priv->write(reg_fdctrl, ®s->fdctrl); | |
| 1492 | + } | |
| 1493 | + | |
| 1172 | 1494 | if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { |
| 1173 | 1495 | for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) { |
| 1174 | 1496 | mb = flexcan_get_mb(priv, i); |
| @@ -1204,28 +1526,43 @@ static int flexcan_chip_start(struct net_device *dev) · 29 unmodified lines | ||
| 1204 | 1526 | for (i = 0; i < priv->mb_count; i++) |
| 1205 | 1527 | priv->write(0, ®s->rximr[i]); |
| 1206 | 1528 | |
| 1207 | − /* On Vybrid, disable memory error detection interrupts | |
| 1208 | − * and freeze mode. | |
| 1209 | − * This also works around errata e5295 which generates | |
| 1210 | − * false positive memory errors and put the device in | |
| 1211 | − * freeze mode. | |
| 1529 | + /* On Vybrid, disable non-correctable errors interrupt and | |
| 1530 | + * freeze mode. It still can correct the correctable errors | |
| 1531 | + * when HW supports ECC. | |
| 1532 | + * | |
| 1533 | + * This also works around errata e5295 which generates false | |
| 1534 | + * positive memory errors and put the device in freeze mode. | |
| 1212 | 1535 | */ |
| 1213 | 1536 | if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) { |
| 1214 | 1537 | /* Follow the protocol as described in "Detection |
| 1215 | 1538 | * and Correction of Memory Errors" to write to |
| 1216 | − * MECR register | |
| 1539 | + * MECR register (step 1 - 5) | |
| 1540 | + * | |
| 1541 | + * 1. By default, CTRL2[ECRWRE] = 0, MECR[ECRWRDIS] = 1 | |
| 1542 | + * 2. set CTRL2[ECRWRE] | |
| 1217 | 1543 | */ |
| 1218 | 1544 | reg_ctrl2 = priv->read(®s->ctrl2); |
| 1219 | 1545 | reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE; |
| 1220 | 1546 | priv->write(reg_ctrl2, ®s->ctrl2); |
| 1221 | 1547 | |
| 1548 | + /* 3. clear MECR[ECRWRDIS] */ | |
| 1222 | 1549 | reg_mecr = priv->read(®s->mecr); |
| 1223 | 1550 | reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS; |
| 1224 | 1551 | priv->write(reg_mecr, ®s->mecr); |
| 1225 | − reg_mecr |= FLEXCAN_MECR_ECCDIS; | |
| 1552 | + | |
| 1553 | + /* 4. all writes to MECR must keep MECR[ECRWRDIS] cleared */ | |
| 1226 | 1554 | reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK | |
| 1227 | 1555 | FLEXCAN_MECR_FANCEI_MSK); |
| 1228 | 1556 | priv->write(reg_mecr, ®s->mecr); |
| 1557 | + | |
| 1558 | + /* 5. after configuration done, lock MECR by either | |
| 1559 | + * setting MECR[ECRWRDIS] or clearing CTRL2[ECRWRE] | |
| 1560 | + */ | |
| 1561 | + reg_mecr |= FLEXCAN_MECR_ECRWRDIS; | |
| 1562 | + priv->write(reg_mecr, ®s->mecr); | |
| 1563 | + | |
| 1564 | + reg_ctrl2 &= ~FLEXCAN_CTRL2_ECRWRE; | |
| 1565 | + priv->write(reg_ctrl2, ®s->ctrl2); | |
| 1229 | 1566 | } |
| 1230 | 1567 | |
| 1231 | 1568 | err = flexcan_transceiver_enable(priv); |
| @@ -1260,18 +1597,23 @@ static int flexcan_chip_start(struct net_device *dev) · 28 unmodified lines | ||
| 1260 | 1597 | return err; |
| 1261 | 1598 | } |
| 1262 | 1599 | |
| 1263 | −/* flexcan_chip_stop | |
| 1600 | +/* __flexcan_chip_stop | |
| 1264 | 1601 | * |
| 1265 | − * this functions is entered with clocks enabled | |
| 1602 | + * this function is entered with clocks enabled | |
| 1266 | 1603 | */ |
| 1267 | −static void flexcan_chip_stop(struct net_device *dev) | |
| 1604 | +static int __flexcan_chip_stop(struct net_device *dev, bool disable_on_error) | |
| 1268 | 1605 | { |
| 1269 | 1606 | struct flexcan_priv *priv = netdev_priv(dev); |
| 1270 | 1607 | struct flexcan_regs __iomem *regs = priv->regs; |
| 1608 | + int err; | |
| 1271 | 1609 | |
| 1272 | 1610 | /* freeze + disable module */ |
| 1273 | − flexcan_chip_freeze(priv); | |
| 1274 | − flexcan_chip_disable(priv); | |
| 1611 | + err = flexcan_chip_freeze(priv); | |
| 1612 | + if (err && !disable_on_error) | |
| 1613 | + return err; | |
| 1614 | + err = flexcan_chip_disable(priv); | |
| 1615 | + if (err && !disable_on_error) | |
| 1616 | + goto out_chip_unfreeze; | |
| 1275 | 1617 | |
| 1276 | 1618 | /* Disable all interrupts */ |
| 1277 | 1619 | priv->write(0, ®s->imask2); |
| @@ -1281,6 +1623,23 @@ static void flexcan_chip_stop(struct net_device *dev) · 3 unmodified lines | ||
| 1281 | 1623 | |
| 1282 | 1624 | flexcan_transceiver_disable(priv); |
| 1283 | 1625 | priv->can.state = CAN_STATE_STOPPED; |
| 1626 | + | |
| 1627 | + return 0; | |
| 1628 | + | |
| 1629 | + out_chip_unfreeze: | |
| 1630 | + flexcan_chip_unfreeze(priv); | |
| 1631 | + | |
| 1632 | + return err; | |
| 1633 | +} | |
| 1634 | + | |
| 1635 | +static inline int flexcan_chip_stop_disable_on_error(struct net_device *dev) | |
| 1636 | +{ | |
| 1637 | + return __flexcan_chip_stop(dev, true); | |
| 1638 | +} | |
| 1639 | + | |
| 1640 | +static inline int flexcan_chip_stop(struct net_device *dev) | |
| 1641 | +{ | |
| 1642 | + return __flexcan_chip_stop(dev, false); | |
| 1284 | 1643 | } |
| 1285 | 1644 | |
| 1286 | 1645 | static int flexcan_open(struct net_device *dev) |
| @@ -1288,6 +1647,12 @@ static int flexcan_open(struct net_device *dev) · 1 unmodified line | ||
| 1288 | 1647 | struct flexcan_priv *priv = netdev_priv(dev); |
| 1289 | 1648 | int err; |
| 1290 | 1649 | |
| 1650 | + if ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) && | |
| 1651 | + (priv->can.ctrlmode & CAN_CTRLMODE_FD)) { | |
| 1652 | + netdev_err(dev, "Three Samples mode and CAN-FD mode can't be used together\n"); | |
| 1653 | + return -EINVAL; | |
| 1654 | + } | |
| 1655 | + | |
| 1291 | 1656 | err = pm_runtime_get_sync(priv->dev); |
| 1292 | 1657 | if (err < 0) |
| 1293 | 1658 | return err; |
| @@ -1300,7 +1665,10 @@ static int flexcan_open(struct net_device *dev) · 6 unmodified lines | ||
| 1300 | 1665 | if (err) |
| 1301 | 1666 | goto out_close; |
| 1302 | 1667 | |
| 1303 | − priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; | |
| 1668 | + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) | |
| 1669 | + priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN; | |
| 1670 | + else | |
| 1671 | + priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; | |
| 1304 | 1672 | priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) + |
| 1305 | 1673 | (sizeof(priv->regs->mb[1]) / priv->mb_size); |
| 1306 | 1674 | |
| @@ -1362,7 +1730,7 @@ static int flexcan_close(struct net_device *dev) · 55 unmodified lines | ||
| 1362 | 1730 | |
| 1363 | 1731 | netif_stop_queue(dev); |
| 1364 | 1732 | can_rx_offload_disable(&priv->offload); |
| 1365 | − flexcan_chip_stop(dev); | |
| 1733 | + flexcan_chip_stop_disable_on_error(dev); | |
| 1366 | 1734 | |
| 1367 | 1735 | can_rx_offload_del(&priv->offload); |
| 1368 | 1736 | free_irq(dev->irq, dev); |
| @@ -1477,14 +1845,14 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) · 108 unmodified lines | ||
| 1477 | 1845 | struct device_node *gpr_np; |
| 1478 | 1846 | struct flexcan_priv *priv; |
| 1479 | 1847 | phandle phandle; |
| 1480 | − u32 out_val[5]; | |
| 1848 | + u32 out_val[3]; | |
| 1481 | 1849 | int ret; |
| 1482 | 1850 | |
| 1483 | 1851 | if (!np) |
| 1484 | 1852 | return -EINVAL; |
| 1485 | 1853 | |
| 1486 | 1854 | /* stop mode property format is: |
| 1487 | − * <&gpr req_gpr req_bit ack_gpr ack_bit>. | |
| 1855 | + * <&gpr req_gpr>. | |
| 1488 | 1856 | */ |
| 1489 | 1857 | ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val, |
| 1490 | 1858 | ARRAY_SIZE(out_val)); |
| @@ -1510,13 +1878,10 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) · 19 unmodified lines | ||
| 1510 | 1878 | |
| 1511 | 1879 | priv->stm.req_gpr = out_val[1]; |
| 1512 | 1880 | priv->stm.req_bit = out_val[2]; |
| 1513 | − priv->stm.ack_gpr = out_val[3]; | |
| 1514 | − priv->stm.ack_bit = out_val[4]; | |
| 1515 | 1881 | |
| 1516 | 1882 | dev_dbg(&pdev->dev, |
| 1517 | − "gpr %s req_gpr=0x02%x req_bit=%u ack_gpr=0x02%x ack_bit=%u\n", | |
| 1518 | − gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit, | |
| 1519 | − priv->stm.ack_gpr, priv->stm.ack_bit); | |
| 1883 | + "gpr %s req_gpr=0x02%x req_bit=%u\n", | |
| 1884 | + gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit); | |
| 1520 | 1885 | |
| 1521 | 1886 | device_set_wakeup_capable(&pdev->dev, true); |
| 1522 | 1887 | |
| @@ -1531,6 +1896,8 @@ out_put_node: · 8 unmodified lines | ||
| 1531 | 1896 | } |
| 1532 | 1897 | |
| 1533 | 1898 | static const struct of_device_id flexcan_of_match[] = { |
| 1899 | + { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, | |
| 1900 | + { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, | |
| 1534 | 1901 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, |
| 1535 | 1902 | { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, |
| 1536 | 1903 | { .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, }, |
| @@ -1539,6 +1906,7 @@ static const struct of_device_id flexcan_of_match[] = { · 2 unmodified lines | ||
| 1539 | 1906 | { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, |
| 1540 | 1907 | { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, }, |
| 1541 | 1908 | { .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, }, |
| 1909 | + { .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, }, | |
| 1542 | 1910 | { /* sentinel */ }, |
| 1543 | 1911 | }; |
| 1544 | 1912 | MODULE_DEVICE_TABLE(of, flexcan_of_match); |
| @@ -1562,11 +1930,13 @@ static int flexcan_probe(struct platform_device *pdev) · 17 unmodified lines | ||
| 1562 | 1930 | u8 clk_src = 1; |
| 1563 | 1931 | u32 clock_freq = 0; |
| 1564 | 1932 | |
| 1565 | − reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); | |
| 1933 | + reg_xceiver = devm_regulator_get_optional(&pdev->dev, "xceiver"); | |
| 1566 | 1934 | if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER) |
| 1567 | 1935 | return -EPROBE_DEFER; |
| 1568 | − else if (IS_ERR(reg_xceiver)) | |
| 1936 | + else if (PTR_ERR(reg_xceiver) == -ENODEV) | |
| 1569 | 1937 | reg_xceiver = NULL; |
| 1938 | + else if (IS_ERR(reg_xceiver)) | |
| 1939 | + return PTR_ERR(reg_xceiver); | |
| 1570 | 1940 | |
| 1571 | 1941 | if (pdev->dev.of_node) { |
| 1572 | 1942 | of_property_read_u32(pdev->dev.of_node, |
| @@ -1608,6 +1978,12 @@ static int flexcan_probe(struct platform_device *pdev) · 35 unmodified lines | ||
| 1608 | 1978 | return -ENODEV; |
| 1609 | 1979 | } |
| 1610 | 1980 | |
| 1981 | + if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) && | |
| 1982 | + !(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) { | |
| 1983 | + dev_err(&pdev->dev, "CAN-FD mode doesn't work with FIFO mode!\n"); | |
| 1984 | + return -EINVAL; | |
| 1985 | + } | |
| 1986 | + | |
| 1611 | 1987 | dev = alloc_candev(sizeof(struct flexcan_priv), 1); |
| 1612 | 1988 | if (!dev) |
| 1613 | 1989 | return -ENOMEM; |
| @@ -1632,7 +2008,6 @@ static int flexcan_probe(struct platform_device *pdev) · 18 unmodified lines | ||
| 1632 | 2008 | |
| 1633 | 2009 | priv->dev = &pdev->dev; |
| 1634 | 2010 | priv->can.clock.freq = clock_freq; |
| 1635 | − priv->can.bittiming_const = &flexcan_bittiming_const; | |
| 1636 | 2011 | priv->can.do_set_mode = flexcan_set_mode; |
| 1637 | 2012 | priv->can.do_get_berr_counter = flexcan_get_berr_counter; |
| 1638 | 2013 | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | |
| @@ -1645,6 +2020,16 @@ static int flexcan_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 1645 | 2020 | priv->devtype_data = devtype_data; |
| 1646 | 2021 | priv->reg_xceiver = reg_xceiver; |
| 1647 | 2022 | |
| 2023 | + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) { | |
| 2024 | + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | | |
| 2025 | + CAN_CTRLMODE_FD_NON_ISO; | |
| 2026 | + priv->can.bittiming_const = &flexcan_fd_bittiming_const; | |
| 2027 | + priv->can.data_bittiming_const = | |
| 2028 | + &flexcan_fd_data_bittiming_const; | |
| 2029 | + } else { | |
| 2030 | + priv->can.bittiming_const = &flexcan_bittiming_const; | |
| 2031 | + } | |
| 2032 | + | |
| 1648 | 2033 | pm_runtime_get_noresume(&pdev->dev); |
| 1649 | 2034 | pm_runtime_set_active(&pdev->dev); |
| 1650 | 2035 | pm_runtime_enable(&pdev->dev); |
| @@ -1655,6 +2040,7 @@ static int flexcan_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 1655 | 2040 | goto failed_register; |
| 1656 | 2041 | } |
| 1657 | 2042 | |
| 2043 | + of_can_transceiver(dev); | |
| 1658 | 2044 | devm_can_led_init(dev); |
| 1659 | 2045 | |
| 1660 | 2046 | if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) { |
| @@ -1666,6 +2052,8 @@ static int flexcan_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1666 | 2052 | return 0; |
| 1667 | 2053 | |
| 1668 | 2054 | failed_register: |
| 2055 | + pm_runtime_put_noidle(&pdev->dev); | |
| 2056 | + pm_runtime_disable(&pdev->dev); | |
| 1669 | 2057 | free_candev(dev); |
| 1670 | 2058 | return err; |
| 1671 | 2059 | } |
| @@ -1685,7 +2073,7 @@ static int __maybe_unused flexcan_suspend(struct device *device) · 13 unmodified lines | ||
| 1685 | 2073 | { |
| 1686 | 2074 | struct net_device *dev = dev_get_drvdata(device); |
| 1687 | 2075 | struct flexcan_priv *priv = netdev_priv(dev); |
| 1688 | − int err = 0; | |
| 2076 | + int err; | |
| 1689 | 2077 | |
| 1690 | 2078 | if (netif_running(dev)) { |
| 1691 | 2079 | /* if wakeup is enabled, enter stop mode |
| @@ -1697,25 +2085,27 @@ static int __maybe_unused flexcan_suspend(struct device *device) · 5 unmodified lines | ||
| 1697 | 2085 | if (err) |
| 1698 | 2086 | return err; |
| 1699 | 2087 | } else { |
| 1700 | − err = flexcan_chip_disable(priv); | |
| 2088 | + err = flexcan_chip_stop(dev); | |
| 1701 | 2089 | if (err) |
| 1702 | 2090 | return err; |
| 1703 | 2091 | |
| 1704 | − err = pm_runtime_force_suspend(device); | |
| 2092 | + err = pinctrl_pm_select_sleep_state(device); | |
| 2093 | + if (err) | |
| 2094 | + return err; | |
| 1705 | 2095 | } |
| 1706 | 2096 | netif_stop_queue(dev); |
| 1707 | 2097 | netif_device_detach(dev); |
| 1708 | 2098 | } |
| 1709 | 2099 | priv->can.state = CAN_STATE_SLEEPING; |
| 1710 | 2100 | |
| 1711 | − return err; | |
| 2101 | + return 0; | |
| 1712 | 2102 | } |
| 1713 | 2103 | |
| 1714 | 2104 | static int __maybe_unused flexcan_resume(struct device *device) |
| 1715 | 2105 | { |
| 1716 | 2106 | struct net_device *dev = dev_get_drvdata(device); |
| 1717 | 2107 | struct flexcan_priv *priv = netdev_priv(dev); |
| 1718 | − int err = 0; | |
| 2108 | + int err; | |
| 1719 | 2109 | |
| 1720 | 2110 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
| 1721 | 2111 | if (netif_running(dev)) { |
| @@ -1727,15 +2117,17 @@ static int __maybe_unused flexcan_resume(struct device *device) · 5 unmodified lines | ||
| 1727 | 2117 | if (err) |
| 1728 | 2118 | return err; |
| 1729 | 2119 | } else { |
| 1730 | − err = pm_runtime_force_resume(device); | |
| 2120 | + err = pinctrl_pm_select_default_state(device); | |
| 1731 | 2121 | if (err) |
| 1732 | 2122 | return err; |
| 1733 | 2123 | |
| 1734 | − err = flexcan_chip_enable(priv); | |
| 2124 | + err = flexcan_chip_start(dev); | |
| 2125 | + if (err) | |
| 2126 | + return err; | |
| 1735 | 2127 | } |
| 1736 | 2128 | } |
| 1737 | 2129 | |
| 1738 | − return err; | |
| 2130 | + return 0; | |
| 1739 | 2131 | } |
| 1740 | 2132 | |
| 1741 | 2133 | static int __maybe_unused flexcan_runtime_suspend(struct device *device) |
| @@ -1761,8 +2153,16 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device) · 19 unmodified lines | ||
| 1761 | 2153 | struct net_device *dev = dev_get_drvdata(device); |
| 1762 | 2154 | struct flexcan_priv *priv = netdev_priv(dev); |
| 1763 | 2155 | |
| 1764 | − if (netif_running(dev) && device_may_wakeup(device)) | |
| 1765 | − flexcan_enable_wakeup_irq(priv, true); | |
| 2156 | + if (netif_running(dev)) { | |
| 2157 | + int err; | |
| 2158 | + | |
| 2159 | + if (device_may_wakeup(device)) | |
| 2160 | + flexcan_enable_wakeup_irq(priv, true); | |
| 2161 | + | |
| 2162 | + err = pm_runtime_force_suspend(device); | |
| 2163 | + if (err) | |
| 2164 | + return err; | |
| 2165 | + } | |
| 1766 | 2166 | |
| 1767 | 2167 | return 0; |
| 1768 | 2168 | } |
| @@ -1772,8 +2172,16 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device) · 3 unmodified lines | ||
| 1772 | 2172 | struct net_device *dev = dev_get_drvdata(device); |
| 1773 | 2173 | struct flexcan_priv *priv = netdev_priv(dev); |
| 1774 | 2174 | |
| 1775 | − if (netif_running(dev) && device_may_wakeup(device)) | |
| 1776 | − flexcan_enable_wakeup_irq(priv, false); | |
| 2175 | + if (netif_running(dev)) { | |
| 2176 | + int err; | |
| 2177 | + | |
| 2178 | + err = pm_runtime_force_resume(device); | |
| 2179 | + if (err) | |
| 2180 | + return err; | |
| 2181 | + | |
| 2182 | + if (device_may_wakeup(device)) | |
| 2183 | + flexcan_enable_wakeup_irq(priv, false); | |
| 2184 | + } | |
| 1777 | 2185 | |
| 1778 | 2186 | return 0; |
| 1779 | 2187 | } |
| @@ -726,7 +726,7 @@ static void grcan_err(struct net_device *dev, u32 sources, u32 status) · 725 unmodified lines | ||
| 726 | 726 | txrx = "on rx "; |
| 727 | 727 | stats->rx_errors++; |
| 728 | 728 | } |
| 729 | − netdev_err(dev, "Fatal AHB buss error %s- halting device\n", | |
| 729 | + netdev_err(dev, "Fatal AHB bus error %s- halting device\n", | |
| 730 | 730 | txrx); |
| 731 | 731 | |
| 732 | 732 | spin_lock_irqsave(&priv->lock, flags); |
| @@ -1243,7 +1243,7 @@ static int grcan_poll(struct napi_struct *napi, int budget) · 510 unmodified lines | ||
| 1243 | 1243 | int rx_budget = budget / 2; |
| 1244 | 1244 | int tx_budget = budget - rx_budget; |
| 1245 | 1245 | |
| 1246 | − /* Half of the budget for receiveing messages */ | |
| 1246 | + /* Half of the budget for receiving messages */ | |
| 1247 | 1247 | rx_work_done = grcan_receive(dev, rx_budget); |
| 1248 | 1248 | |
| 1249 | 1249 | /* Half of the budget for transmitting messages as that can trigger echo |
| @@ -20,5 +20,5 @@ config CAN_M_CAN_TCAN4X5X · 19 unmodified lines | ||
| 20 | 20 | tristate "TCAN4X5X M_CAN device" |
| 21 | 21 | help |
| 22 | 22 | Say Y here if you want support for Texas Instruments TCAN4x5x |
| 23 | − M_CAN controller. This device is a peripherial device that uses the | |
| 23 | + M_CAN controller. This device is a peripheral device that uses the | |
| 24 | 24 | SPI bus for communication. |
| @@ -144,8 +144,6 @@ static int __maybe_unused m_can_runtime_suspend(struct device *dev) · 143 unmodified lines | ||
| 144 | 144 | struct net_device *ndev = dev_get_drvdata(dev); |
| 145 | 145 | struct m_can_classdev *mcan_class = netdev_priv(ndev); |
| 146 | 146 | |
| 147 | − m_can_class_suspend(dev); | |
| 148 | − | |
| 149 | 147 | clk_disable_unprepare(mcan_class->cclk); |
| 150 | 148 | clk_disable_unprepare(mcan_class->hclk); |
| 151 | 149 | |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | * Copyright (C) 2004-2005 Andrey Volkov <avolkov@varma-el.com>, |
| 6 | 6 | * Varma Electronics Oy |
| 7 | 7 | * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> |
| 8 | − * Copyright (C) 2009 Wolfram Sang, Pengutronix <w.sang@pengutronix.de> | |
| 8 | + * Copyright (C) 2009 Wolfram Sang, Pengutronix <kernel@pengutronix.de> | |
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | #include <linux/kernel.h> |
| @@ -209,6 +209,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) · 208 unmodified lines | ||
| 209 | 209 | * since buffer with lower id have higher priority (hell..) |
| 210 | 210 | */ |
| 211 | 211 | netif_stop_queue(dev); |
| 212 | + fallthrough; | |
| 212 | 213 | case 2: |
| 213 | 214 | if (buf_id < priv->prev_buf_id) { |
| 214 | 215 | priv->cur_pri++; |
| @@ -540,16 +541,12 @@ static int mscan_open(struct net_device *dev) · 325 unmodified lines | ||
| 540 | 541 | struct mscan_priv *priv = netdev_priv(dev); |
| 541 | 542 | struct mscan_regs __iomem *regs = priv->reg_base; |
| 542 | 543 | |
| 543 | − if (priv->clk_ipg) { | |
| 544 | − ret = clk_prepare_enable(priv->clk_ipg); | |
| 545 | − if (ret) | |
| 546 | − goto exit_retcode; | |
| 547 | − } | |
| 548 | − if (priv->clk_can) { | |
| 549 | − ret = clk_prepare_enable(priv->clk_can); | |
| 550 | − if (ret) | |
| 551 | − goto exit_dis_ipg_clock; | |
| 552 | − } | |
| 544 | + ret = clk_prepare_enable(priv->clk_ipg); | |
| 545 | + if (ret) | |
| 546 | + goto exit_retcode; | |
| 547 | + ret = clk_prepare_enable(priv->clk_can); | |
| 548 | + if (ret) | |
| 549 | + goto exit_dis_ipg_clock; | |
| 553 | 550 | |
| 554 | 551 | /* common open */ |
| 555 | 552 | ret = open_candev(dev); |
| @@ -583,11 +580,9 @@ exit_napi_disable: · 27 unmodified lines | ||
| 583 | 580 | napi_disable(&priv->napi); |
| 584 | 581 | close_candev(dev); |
| 585 | 582 | exit_dis_can_clock: |
| 586 | − if (priv->clk_can) | |
| 587 | − clk_disable_unprepare(priv->clk_can); | |
| 583 | + clk_disable_unprepare(priv->clk_can); | |
| 588 | 584 | exit_dis_ipg_clock: |
| 589 | − if (priv->clk_ipg) | |
| 590 | − clk_disable_unprepare(priv->clk_ipg); | |
| 585 | + clk_disable_unprepare(priv->clk_ipg); | |
| 591 | 586 | exit_retcode: |
| 592 | 587 | return ret; |
| 593 | 588 | } |
| @@ -606,10 +601,8 @@ static int mscan_close(struct net_device *dev) · 12 unmodified lines | ||
| 606 | 601 | close_candev(dev); |
| 607 | 602 | free_irq(dev->irq, dev); |
| 608 | 603 | |
| 609 | − if (priv->clk_can) | |
| 610 | − clk_disable_unprepare(priv->clk_can); | |
| 611 | − if (priv->clk_ipg) | |
| 612 | − clk_disable_unprepare(priv->clk_ipg); | |
| 604 | + clk_disable_unprepare(priv->clk_can); | |
| 605 | + clk_disable_unprepare(priv->clk_ipg); | |
| 613 | 606 | |
| 614 | 607 | return 0; |
| 615 | 608 | } |
| @@ -461,7 +461,7 @@ static void pch_can_int_clr(struct pch_can_priv *priv, u32 mask) · 460 unmodified lines | ||
| 461 | 461 | PCH_ID2_DIR | (0x7ff << 2)); |
| 462 | 462 | iowrite32(0x0, &priv->regs->ifregs[1].id1); |
| 463 | 463 | |
| 464 | − /* Claring NewDat, TxRqst & IntPnd */ | |
| 464 | + /* Clearing NewDat, TxRqst & IntPnd */ | |
| 465 | 465 | pch_can_bit_clear(&priv->regs->ifregs[1].mcont, |
| 466 | 466 | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND | |
| 467 | 467 | PCH_IF_MCONT_TXRQXT); |
| @@ -834,7 +834,7 @@ static int pch_can_open(struct net_device *ndev) · 366 unmodified lines | ||
| 834 | 834 | struct pch_can_priv *priv = netdev_priv(ndev); |
| 835 | 835 | int retval; |
| 836 | 836 | |
| 837 | − /* Regstering the interrupt. */ | |
| 837 | + /* Registering the interrupt. */ | |
| 838 | 838 | retval = request_irq(priv->dev->irq, pch_can_interrupt, IRQF_SHARED, |
| 839 | 839 | ndev->name, ndev); |
| 840 | 840 | if (retval) { |
| @@ -957,8 +957,7 @@ static void pch_can_remove(struct pci_dev *pdev) · 116 unmodified lines | ||
| 957 | 957 | free_candev(priv->ndev); |
| 958 | 958 | } |
| 959 | 959 | |
| 960 | −#ifdef CONFIG_PM | |
| 961 | −static void pch_can_set_int_custom(struct pch_can_priv *priv) | |
| 960 | +static void __maybe_unused pch_can_set_int_custom(struct pch_can_priv *priv) | |
| 962 | 961 | { |
| 963 | 962 | /* Clearing the IE, SIE and EIE bits of Can control register. */ |
| 964 | 963 | pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); |
| @@ -969,14 +968,14 @@ static void pch_can_set_int_custom(struct pch_can_priv *priv) · 4 unmodified lines | ||
| 969 | 968 | } |
| 970 | 969 | |
| 971 | 970 | /* This function retrieves interrupt enabled for the CAN device. */ |
| 972 | −static u32 pch_can_get_int_enables(struct pch_can_priv *priv) | |
| 971 | +static u32 __maybe_unused pch_can_get_int_enables(struct pch_can_priv *priv) | |
| 973 | 972 | { |
| 974 | 973 | /* Obtaining the status of IE, SIE and EIE interrupt bits. */ |
| 975 | 974 | return (ioread32(&priv->regs->cont) & PCH_CTRL_IE_SIE_EIE) >> 1; |
| 976 | 975 | } |
| 977 | 976 | |
| 978 | −static u32 pch_can_get_rxtx_ir(struct pch_can_priv *priv, u32 buff_num, | |
| 979 | − enum pch_ifreg dir) | |
| 977 | +static u32 __maybe_unused pch_can_get_rxtx_ir(struct pch_can_priv *priv, | |
| 978 | + u32 buff_num, enum pch_ifreg dir) | |
| 980 | 979 | { |
| 981 | 980 | u32 ie, enable; |
| 982 | 981 | |
| @@ -997,8 +996,8 @@ static u32 pch_can_get_rxtx_ir(struct pch_can_priv *priv, u32 buff_num, · 14 unmodified lines | ||
| 997 | 996 | return enable; |
| 998 | 997 | } |
| 999 | 998 | |
| 1000 | −static void pch_can_set_rx_buffer_link(struct pch_can_priv *priv, | |
| 1001 | − u32 buffer_num, int set) | |
| 999 | +static void __maybe_unused pch_can_set_rx_buffer_link(struct pch_can_priv *priv, | |
| 1000 | + u32 buffer_num, int set) | |
| 1002 | 1001 | { |
| 1003 | 1002 | iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); |
| 1004 | 1003 | pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); |
| @@ -1013,7 +1012,8 @@ static void pch_can_set_rx_buffer_link(struct pch_can_priv *priv, · 8 unmodified lines | ||
| 1013 | 1012 | pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); |
| 1014 | 1013 | } |
| 1015 | 1014 | |
| 1016 | −static u32 pch_can_get_rx_buffer_link(struct pch_can_priv *priv, u32 buffer_num) | |
| 1015 | +static u32 __maybe_unused pch_can_get_rx_buffer_link(struct pch_can_priv *priv, | |
| 1016 | + u32 buffer_num) | |
| 1017 | 1017 | { |
| 1018 | 1018 | u32 link; |
| 1019 | 1019 | |
| @@ -1027,20 +1027,19 @@ static u32 pch_can_get_rx_buffer_link(struct pch_can_priv *priv, u32 buffer_num) · 7 unmodified lines | ||
| 1027 | 1027 | return link; |
| 1028 | 1028 | } |
| 1029 | 1029 | |
| 1030 | −static int pch_can_get_buffer_status(struct pch_can_priv *priv) | |
| 1030 | +static int __maybe_unused pch_can_get_buffer_status(struct pch_can_priv *priv) | |
| 1031 | 1031 | { |
| 1032 | 1032 | return (ioread32(&priv->regs->treq1) & 0xffff) | |
| 1033 | 1033 | (ioread32(&priv->regs->treq2) << 16); |
| 1034 | 1034 | } |
| 1035 | 1035 | |
| 1036 | −static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state) | |
| 1036 | +static int __maybe_unused pch_can_suspend(struct device *dev_d) | |
| 1037 | 1037 | { |
| 1038 | 1038 | int i; |
| 1039 | − int retval; | |
| 1040 | 1039 | u32 buf_stat; /* Variable for reading the transmit buffer status. */ |
| 1041 | 1040 | int counter = PCH_COUNTER_LIMIT; |
| 1042 | 1041 | |
| 1043 | − struct net_device *dev = pci_get_drvdata(pdev); | |
| 1042 | + struct net_device *dev = dev_get_drvdata(dev_d); | |
| 1044 | 1043 | struct pch_can_priv *priv = netdev_priv(dev); |
| 1045 | 1044 | |
| 1046 | 1045 | /* Stop the CAN controller */ |
| @@ -1058,7 +1057,7 @@ static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state) · 11 unmodified lines | ||
| 1058 | 1057 | udelay(1); |
| 1059 | 1058 | } |
| 1060 | 1059 | if (!counter) |
| 1061 | − dev_err(&pdev->dev, "%s -> Transmission time out.\n", __func__); | |
| 1060 | + dev_err(dev_d, "%s -> Transmission time out.\n", __func__); | |
| 1062 | 1061 | |
| 1063 | 1062 | /* Save interrupt configuration and then disable them */ |
| 1064 | 1063 | priv->int_enables = pch_can_get_int_enables(priv); |
| @@ -1081,35 +1080,16 @@ static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state) · 16 unmodified lines | ||
| 1081 | 1080 | |
| 1082 | 1081 | /* Disable all Receive buffers */ |
| 1083 | 1082 | pch_can_set_rx_all(priv, 0); |
| 1084 | − retval = pci_save_state(pdev); | |
| 1085 | − if (retval) { | |
| 1086 | − dev_err(&pdev->dev, "pci_save_state failed.\n"); | |
| 1087 | − } else { | |
| 1088 | − pci_enable_wake(pdev, PCI_D3hot, 0); | |
| 1089 | − pci_disable_device(pdev); | |
| 1090 | − pci_set_power_state(pdev, pci_choose_state(pdev, state)); | |
| 1091 | − } | |
| 1092 | 1083 | |
| 1093 | − return retval; | |
| 1084 | + return 0; | |
| 1094 | 1085 | } |
| 1095 | 1086 | |
| 1096 | −static int pch_can_resume(struct pci_dev *pdev) | |
| 1087 | +static int __maybe_unused pch_can_resume(struct device *dev_d) | |
| 1097 | 1088 | { |
| 1098 | 1089 | int i; |
| 1099 | − int retval; | |
| 1100 | − struct net_device *dev = pci_get_drvdata(pdev); | |
| 1090 | + struct net_device *dev = dev_get_drvdata(dev_d); | |
| 1101 | 1091 | struct pch_can_priv *priv = netdev_priv(dev); |
| 1102 | 1092 | |
| 1103 | − pci_set_power_state(pdev, PCI_D0); | |
| 1104 | − pci_restore_state(pdev); | |
| 1105 | − retval = pci_enable_device(pdev); | |
| 1106 | − if (retval) { | |
| 1107 | − dev_err(&pdev->dev, "pci_enable_device failed.\n"); | |
| 1108 | − return retval; | |
| 1109 | − } | |
| 1110 | − | |
| 1111 | − pci_enable_wake(pdev, PCI_D3hot, 0); | |
| 1112 | − | |
| 1113 | 1093 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
| 1114 | 1094 | |
| 1115 | 1095 | /* Disabling all interrupts. */ |
| @@ -1146,12 +1126,8 @@ static int pch_can_resume(struct pci_dev *pdev) · 30 unmodified lines | ||
| 1146 | 1126 | /* Restore Run Mode */ |
| 1147 | 1127 | pch_can_set_run_mode(priv, PCH_CAN_RUN); |
| 1148 | 1128 | |
| 1149 | − return retval; | |
| 1129 | + return 0; | |
| 1150 | 1130 | } |
| 1151 | −#else | |
| 1152 | −#define pch_can_suspend NULL | |
| 1153 | −#define pch_can_resume NULL | |
| 1154 | −#endif | |
| 1155 | 1131 | |
| 1156 | 1132 | static int pch_can_get_berr_counter(const struct net_device *dev, |
| 1157 | 1133 | struct can_berr_counter *bec) |
| @@ -1252,13 +1228,16 @@ probe_exit_endev: · 94 unmodified lines | ||
| 1252 | 1228 | return rc; |
| 1253 | 1229 | } |
| 1254 | 1230 | |
| 1231 | +static SIMPLE_DEV_PM_OPS(pch_can_pm_ops, | |
| 1232 | + pch_can_suspend, | |
| 1233 | + pch_can_resume); | |
| 1234 | + | |
| 1255 | 1235 | static struct pci_driver pch_can_pci_driver = { |
| 1256 | 1236 | .name = "pch_can", |
| 1257 | 1237 | .id_table = pch_pci_tbl, |
| 1258 | 1238 | .probe = pch_can_probe, |
| 1259 | 1239 | .remove = pch_can_remove, |
| 1260 | − .suspend = pch_can_suspend, | |
| 1261 | − .resume = pch_can_resume, | |
| 1240 | + .driver.pm = &pch_can_pm_ops, | |
| 1262 | 1241 | }; |
| 1263 | 1242 | |
| 1264 | 1243 | module_pci_driver(pch_can_pci_driver); |
| @@ -116,8 +116,6 @@ MODULE_LICENSE("GPL v2"); · 115 unmodified lines | ||
| 116 | 116 | #define CANFD_CTL_IRQ_CL_DEF 16 /* Rx msg max nb per IRQ in Rx DMA */ |
| 117 | 117 | #define CANFD_CTL_IRQ_TL_DEF 10 /* Time before IRQ if < CL (x100 µs) */ |
| 118 | 118 | |
| 119 | −#define CANFD_OPTIONS_SET (CANFD_OPTION_ERROR | CANFD_OPTION_BUSLOAD) | |
| 120 | − | |
| 121 | 119 | /* Tx anticipation window (link logical address should be aligned on 2K |
| 122 | 120 | * boundary) |
| 123 | 121 | */ |
| @@ -351,6 +351,17 @@ int can_rx_offload_add_fifo(struct net_device *dev, · 350 unmodified lines | ||
| 351 | 351 | } |
| 352 | 352 | EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo); |
| 353 | 353 | |
| 354 | +int can_rx_offload_add_manual(struct net_device *dev, | |
| 355 | + struct can_rx_offload *offload, | |
| 356 | + unsigned int weight) | |
| 357 | +{ | |
| 358 | + if (offload->mailbox_read) | |
| 359 | + return -EINVAL; | |
| 360 | + | |
| 361 | + return can_rx_offload_init_queue(dev, offload, weight); | |
| 362 | +} | |
| 363 | +EXPORT_SYMBOL_GPL(can_rx_offload_add_manual); | |
| 364 | + | |
| 354 | 365 | void can_rx_offload_enable(struct can_rx_offload *offload) |
| 355 | 366 | { |
| 356 | 367 | napi_enable(&offload->napi); |
| @@ -97,7 +97,7 @@ MODULE_DEVICE_TABLE(pci, peak_pci_tbl); · 96 unmodified lines | ||
| 97 | 97 | /* GPIOICR byte access offsets */ |
| 98 | 98 | #define PITA_GPOUT 0x18 /* GPx output value */ |
| 99 | 99 | #define PITA_GPIN 0x19 /* GPx input value */ |
| 100 | −#define PITA_GPOEN 0x1A /* configure GPx as ouput pin */ | |
| 100 | +#define PITA_GPOEN 0x1A /* configure GPx as output pin */ | |
| 101 | 101 | |
| 102 | 102 | /* I2C GP bits */ |
| 103 | 103 | #define PITA_GPIN_SCL 0x01 /* Serial Clock Line */ |
| @@ -671,7 +671,7 @@ static int pcan_probe(struct pcmcia_device *pdev) · 670 unmodified lines | ||
| 671 | 671 | card->fw_major = pcan_read_reg(card, PCC_FW_MAJOR); |
| 672 | 672 | card->fw_minor = pcan_read_reg(card, PCC_FW_MINOR); |
| 673 | 673 | |
| 674 | − /* display board name and firware version */ | |
| 674 | + /* display board name and firmware version */ | |
| 675 | 675 | dev_info(&pdev->dev, "PEAK-System pcmcia card %s fw %d.%d\n", |
| 676 | 676 | pdev->prod_id[1] ? pdev->prod_id[1] : "PCAN-PC Card", |
| 677 | 677 | card->fw_major, card->fw_minor); |
| @@ -5,14 +5,14 @@ config CAN_SOFTING · 4 unmodified lines | ||
| 5 | 5 | help |
| 6 | 6 | Support for CAN cards from Softing Gmbh & some cards |
| 7 | 7 | from Vector Gmbh. |
| 8 | − Softing Gmbh CAN cards come with 1 or 2 physical busses. | |
| 8 | + Softing Gmbh CAN cards come with 1 or 2 physical buses. | |
| 9 | 9 | Those cards typically use Dual Port RAM to communicate |
| 10 | 10 | with the host CPU. The interface is then identical for PCI |
| 11 | 11 | and PCMCIA cards. This driver operates on a platform device, |
| 12 | 12 | which has been created by softing_cs or softing_pci driver. |
| 13 | 13 | Warning: |
| 14 | 14 | The API of the card does not allow fine control per bus, but |
| 15 | − controls the 2 busses on the card together. | |
| 15 | + controls the 2 buses on the card together. | |
| 16 | 16 | As such, some actions (start/stop/busoff recovery) on 1 bus |
| 17 | 17 | must bring down the other bus too temporarily. |
| 18 | 18 | |
| @@ -24,7 +24,7 @@ config CAN_SOFTING_CS · 5 unmodified lines | ||
| 24 | 24 | Support for PCMCIA cards from Softing Gmbh & some cards |
| 25 | 25 | from Vector Gmbh. |
| 26 | 26 | You need firmware for these, which you can get at |
| 27 | − http://developer.berlios.de/projects/socketcan/ | |
| 27 | + https://github.com/linux-can/can-firmware | |
| 28 | 28 | This version of the driver is written against |
| 29 | 29 | firmware version 4.6 (softing-fw-4.6-binaries.tar.gz) |
| 30 | 30 | In order to use the card as CAN device, you need the Softing generic |
| @@ -273,7 +273,7 @@ int softing_load_app_fw(const char *file, struct softing *card) · 272 unmodified lines | ||
| 273 | 273 | goto failed; |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | − /* regualar data */ | |
| 276 | + /* regular data */ | |
| 277 | 277 | for (sum = 0, j = 0; j < len; ++j) |
| 278 | 278 | sum += dat[j]; |
| 279 | 279 | /* work in 16bit (target) */ |
| @@ -474,14 +474,14 @@ int softing_startstop(struct net_device *dev, int up) · 194 unmodified lines | ||
| 474 | 474 | if (ret) |
| 475 | 475 | goto failed; |
| 476 | 476 | if (!bus_bitmask_start) |
| 477 | − /* no busses to be brought up */ | |
| 477 | + /* no buses to be brought up */ | |
| 478 | 478 | goto card_done; |
| 479 | 479 | |
| 480 | 480 | if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2) |
| 481 | 481 | && (softing_error_reporting(card->net[0]) |
| 482 | 482 | != softing_error_reporting(card->net[1]))) { |
| 483 | 483 | dev_alert(&card->pdev->dev, |
| 484 | − "err_reporting flag differs for busses\n"); | |
| 484 | + "err_reporting flag differs for buses\n"); | |
| 485 | 485 | goto invalid; |
| 486 | 486 | } |
| 487 | 487 | error_reporting = 0; |
| @@ -635,7 +635,7 @@ int softing_startstop(struct net_device *dev, int up) · 147 unmodified lines | ||
| 635 | 635 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
| 636 | 636 | open_candev(netdev); |
| 637 | 637 | if (dev != netdev) { |
| 638 | − /* notify other busses on the restart */ | |
| 638 | + /* notify other buses on the restart */ | |
| 639 | 639 | softing_netdev_rx(netdev, &msg, 0); |
| 640 | 640 | ++priv->can.can_stats.restarts; |
| 641 | 641 | } |
| @@ -170,8 +170,8 @@ static int softing_handle_1(struct softing *card) · 169 unmodified lines | ||
| 170 | 170 | msg.can_dlc = CAN_ERR_DLC; |
| 171 | 171 | msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW; |
| 172 | 172 | /* |
| 173 | − * service to all busses, we don't know which it was applicable | |
| 174 | − * but only service busses that are online | |
| 173 | + * service to all buses, we don't know which it was applicable | |
| 174 | + * but only service buses that are online | |
| 175 | 175 | */ |
| 176 | 176 | for (j = 0; j < ARRAY_SIZE(card->net); ++j) { |
| 177 | 177 | netdev = card->net[j]; |
| @@ -339,7 +339,7 @@ static irqreturn_t softing_irq_thread(int irq, void *dev_id) · 161 unmodified lines | ||
| 339 | 339 | continue; |
| 340 | 340 | priv = netdev_priv(netdev); |
| 341 | 341 | if (!canif_is_active(netdev)) |
| 342 | − /* it makes no sense to wake dead busses */ | |
| 342 | + /* it makes no sense to wake dead buses */ | |
| 343 | 343 | continue; |
| 344 | 344 | if (priv->tx.pending >= TX_ECHO_SKB_MAX) |
| 345 | 345 | continue; |
| @@ -374,7 +374,7 @@ static irqreturn_t softing_irq_v1(int irq, void *dev_id) · 28 unmodified lines | ||
| 374 | 374 | } |
| 375 | 375 | |
| 376 | 376 | /* |
| 377 | − * netdev/candev inter-operability | |
| 377 | + * netdev/candev interoperability | |
| 378 | 378 | */ |
| 379 | 379 | static int softing_netdev_open(struct net_device *ndev) |
| 380 | 380 | { |
| @@ -447,8 +447,9 @@ static void softing_card_shutdown(struct softing *card) · 66 unmodified lines | ||
| 447 | 447 | { |
| 448 | 448 | int fw_up = 0; |
| 449 | 449 | |
| 450 | − if (mutex_lock_interruptible(&card->fw.lock)) | |
| 450 | + if (mutex_lock_interruptible(&card->fw.lock)) { | |
| 451 | 451 | /* return -ERESTARTSYS */; |
| 452 | + } | |
| 452 | 453 | fw_up = card->fw.up; |
| 453 | 454 | card->fw.up = 0; |
| 454 | 455 | |
| @@ -19,7 +19,7 @@ struct softing_platform_data { · 18 unmodified lines | ||
| 19 | 19 | * 16bit, shared interrupt |
| 20 | 20 | */ |
| 21 | 21 | int generation; |
| 22 | − int nbus; /* # busses on device */ | |
| 22 | + int nbus; /* # buses on device */ | |
| 23 | 23 | unsigned int freq; /* operating frequency in Hz */ |
| 24 | 24 | unsigned int max_brp; |
| 25 | 25 | unsigned int max_sjw; |
| @@ -4,15 +4,15 @@ menu "CAN SPI interfaces" · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | config CAN_HI311X |
| 6 | 6 | tristate "Holt HI311x SPI CAN controllers" |
| 7 | − depends on CAN_DEV && SPI && HAS_DMA | |
| 8 | 7 | help |
| 9 | 8 | Driver for the Holt HI311x SPI CAN controllers. |
| 10 | 9 | |
| 11 | 10 | config CAN_MCP251X |
| 12 | 11 | tristate "Microchip MCP251x and MCP25625 SPI CAN controllers" |
| 13 | − depends on HAS_DMA | |
| 14 | 12 | help |
| 15 | 13 | Driver for the Microchip MCP251x and MCP25625 SPI CAN |
| 16 | 14 | controllers. |
| 17 | 15 | |
| 16 | +source "drivers/net/can/spi/mcp251xfd/Kconfig" | |
| 17 | + | |
| 18 | 18 | endmenu |
| @@ -6,3 +6,4 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | obj-$(CONFIG_CAN_HI311X) += hi311x.o |
| 8 | 8 | obj-$(CONFIG_CAN_MCP251X) += mcp251x.o |
| 9 | +obj-y += mcp251xfd/ | |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | * Copyright 2007 |
| 20 | 20 | */ |
| 21 | 21 | |
| 22 | +#include <linux/bitfield.h> | |
| 22 | 23 | #include <linux/can/core.h> |
| 23 | 24 | #include <linux/can/dev.h> |
| 24 | 25 | #include <linux/can/led.h> |
| @@ -27,17 +28,20 @@ · 2 unmodified lines | ||
| 27 | 28 | #include <linux/delay.h> |
| 28 | 29 | #include <linux/device.h> |
| 29 | 30 | #include <linux/freezer.h> |
| 31 | +#include <linux/gpio.h> | |
| 32 | +#include <linux/gpio/driver.h> | |
| 30 | 33 | #include <linux/interrupt.h> |
| 31 | 34 | #include <linux/io.h> |
| 35 | +#include <linux/iopoll.h> | |
| 32 | 36 | #include <linux/kernel.h> |
| 33 | 37 | #include <linux/module.h> |
| 34 | 38 | #include <linux/netdevice.h> |
| 35 | −#include <linux/property.h> | |
| 36 | 39 | #include <linux/platform_device.h> |
| 40 | +#include <linux/property.h> | |
| 41 | +#include <linux/regulator/consumer.h> | |
| 37 | 42 | #include <linux/slab.h> |
| 38 | 43 | #include <linux/spi/spi.h> |
| 39 | 44 | #include <linux/uaccess.h> |
| 40 | −#include <linux/regulator/consumer.h> | |
| 41 | 45 | |
| 42 | 46 | /* SPI interface instruction set */ |
| 43 | 47 | #define INSTRUCTION_WRITE 0x02 |
| @@ -52,6 +56,30 @@ · 8 unmodified lines | ||
| 52 | 56 | #define INSTRUCTION_RTS(n) (0x80 | ((n) & 0x07)) |
| 53 | 57 | |
| 54 | 58 | /* MPC251x registers */ |
| 59 | +#define BFPCTRL 0x0c | |
| 60 | +# define BFPCTRL_B0BFM BIT(0) | |
| 61 | +# define BFPCTRL_B1BFM BIT(1) | |
| 62 | +# define BFPCTRL_BFM(n) (BFPCTRL_B0BFM << (n)) | |
| 63 | +# define BFPCTRL_BFM_MASK GENMASK(1, 0) | |
| 64 | +# define BFPCTRL_B0BFE BIT(2) | |
| 65 | +# define BFPCTRL_B1BFE BIT(3) | |
| 66 | +# define BFPCTRL_BFE(n) (BFPCTRL_B0BFE << (n)) | |
| 67 | +# define BFPCTRL_BFE_MASK GENMASK(3, 2) | |
| 68 | +# define BFPCTRL_B0BFS BIT(4) | |
| 69 | +# define BFPCTRL_B1BFS BIT(5) | |
| 70 | +# define BFPCTRL_BFS(n) (BFPCTRL_B0BFS << (n)) | |
| 71 | +# define BFPCTRL_BFS_MASK GENMASK(5, 4) | |
| 72 | +#define TXRTSCTRL 0x0d | |
| 73 | +# define TXRTSCTRL_B0RTSM BIT(0) | |
| 74 | +# define TXRTSCTRL_B1RTSM BIT(1) | |
| 75 | +# define TXRTSCTRL_B2RTSM BIT(2) | |
| 76 | +# define TXRTSCTRL_RTSM(n) (TXRTSCTRL_B0RTSM << (n)) | |
| 77 | +# define TXRTSCTRL_RTSM_MASK GENMASK(2, 0) | |
| 78 | +# define TXRTSCTRL_B0RTS BIT(3) | |
| 79 | +# define TXRTSCTRL_B1RTS BIT(4) | |
| 80 | +# define TXRTSCTRL_B2RTS BIT(5) | |
| 81 | +# define TXRTSCTRL_RTS(n) (TXRTSCTRL_B0RTS << (n)) | |
| 82 | +# define TXRTSCTRL_RTS_MASK GENMASK(5, 3) | |
| 55 | 83 | #define CANSTAT 0x0e |
| 56 | 84 | #define CANCTRL 0x0f |
| 57 | 85 | # define CANCTRL_REQOP_MASK 0xe0 |
| @@ -225,6 +253,10 @@ struct mcp251x_priv { · 167 unmodified lines | ||
| 225 | 253 | struct regulator *power; |
| 226 | 254 | struct regulator *transceiver; |
| 227 | 255 | struct clk *clk; |
| 256 | +#ifdef CONFIG_GPIOLIB | |
| 257 | + struct gpio_chip gpio; | |
| 258 | + u8 reg_bfpctrl; | |
| 259 | +#endif | |
| 228 | 260 | }; |
| 229 | 261 | |
| 230 | 262 | #define MCP251X_IS(_model) \ |
| @@ -290,8 +322,12 @@ static u8 mcp251x_read_reg(struct spi_device *spi, u8 reg) · 59 unmodified lines | ||
| 290 | 322 | priv->spi_tx_buf[0] = INSTRUCTION_READ; |
| 291 | 323 | priv->spi_tx_buf[1] = reg; |
| 292 | 324 | |
| 293 | − mcp251x_spi_trans(spi, 3); | |
| 294 | − val = priv->spi_rx_buf[2]; | |
| 325 | + if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) { | |
| 326 | + spi_write_then_read(spi, priv->spi_tx_buf, 2, &val, 1); | |
| 327 | + } else { | |
| 328 | + mcp251x_spi_trans(spi, 3); | |
| 329 | + val = priv->spi_rx_buf[2]; | |
| 330 | + } | |
| 295 | 331 | |
| 296 | 332 | return val; |
| 297 | 333 | } |
| @@ -303,10 +339,18 @@ static void mcp251x_read_2regs(struct spi_device *spi, u8 reg, u8 *v1, u8 *v2) · 5 unmodified lines | ||
| 303 | 339 | priv->spi_tx_buf[0] = INSTRUCTION_READ; |
| 304 | 340 | priv->spi_tx_buf[1] = reg; |
| 305 | 341 | |
| 306 | − mcp251x_spi_trans(spi, 4); | |
| 342 | + if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) { | |
| 343 | + u8 val[2] = { 0 }; | |
| 307 | 344 | |
| 308 | − *v1 = priv->spi_rx_buf[2]; | |
| 309 | − *v2 = priv->spi_rx_buf[3]; | |
| 345 | + spi_write_then_read(spi, priv->spi_tx_buf, 2, val, 2); | |
| 346 | + *v1 = val[0]; | |
| 347 | + *v2 = val[1]; | |
| 348 | + } else { | |
| 349 | + mcp251x_spi_trans(spi, 4); | |
| 350 | + | |
| 351 | + *v1 = priv->spi_rx_buf[2]; | |
| 352 | + *v2 = priv->spi_rx_buf[3]; | |
| 353 | + } | |
| 310 | 354 | } |
| 311 | 355 | |
| 312 | 356 | static void mcp251x_write_reg(struct spi_device *spi, u8 reg, u8 val) |
| @@ -345,6 +389,222 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg, · 32 unmodified lines | ||
| 345 | 389 | mcp251x_spi_trans(spi, 4); |
| 346 | 390 | } |
| 347 | 391 | |
| 392 | +static u8 mcp251x_read_stat(struct spi_device *spi) | |
| 393 | +{ | |
| 394 | + return mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK; | |
| 395 | +} | |
| 396 | + | |
| 397 | +#define mcp251x_read_stat_poll_timeout(addr, val, cond, delay_us, timeout_us) \ | |
| 398 | + readx_poll_timeout(mcp251x_read_stat, addr, val, cond, \ | |
| 399 | + delay_us, timeout_us) | |
| 400 | + | |
| 401 | +#ifdef CONFIG_GPIOLIB | |
| 402 | +enum { | |
| 403 | + MCP251X_GPIO_TX0RTS = 0, /* inputs */ | |
| 404 | + MCP251X_GPIO_TX1RTS, | |
| 405 | + MCP251X_GPIO_TX2RTS, | |
| 406 | + MCP251X_GPIO_RX0BF, /* outputs */ | |
| 407 | + MCP251X_GPIO_RX1BF, | |
| 408 | +}; | |
| 409 | + | |
| 410 | +#define MCP251X_GPIO_INPUT_MASK \ | |
| 411 | + GENMASK(MCP251X_GPIO_TX2RTS, MCP251X_GPIO_TX0RTS) | |
| 412 | +#define MCP251X_GPIO_OUTPUT_MASK \ | |
| 413 | + GENMASK(MCP251X_GPIO_RX1BF, MCP251X_GPIO_RX0BF) | |
| 414 | + | |
| 415 | +static const char * const mcp251x_gpio_names[] = { | |
| 416 | + [MCP251X_GPIO_TX0RTS] = "TX0RTS", /* inputs */ | |
| 417 | + [MCP251X_GPIO_TX1RTS] = "TX1RTS", | |
| 418 | + [MCP251X_GPIO_TX2RTS] = "TX2RTS", | |
| 419 | + [MCP251X_GPIO_RX0BF] = "RX0BF", /* outputs */ | |
| 420 | + [MCP251X_GPIO_RX1BF] = "RX1BF", | |
| 421 | +}; | |
| 422 | + | |
| 423 | +static inline bool mcp251x_gpio_is_input(unsigned int offset) | |
| 424 | +{ | |
| 425 | + return offset <= MCP251X_GPIO_TX2RTS; | |
| 426 | +} | |
| 427 | + | |
| 428 | +static int mcp251x_gpio_request(struct gpio_chip *chip, | |
| 429 | + unsigned int offset) | |
| 430 | +{ | |
| 431 | + struct mcp251x_priv *priv = gpiochip_get_data(chip); | |
| 432 | + u8 val; | |
| 433 | + | |
| 434 | + /* nothing to be done for inputs */ | |
| 435 | + if (mcp251x_gpio_is_input(offset)) | |
| 436 | + return 0; | |
| 437 | + | |
| 438 | + val = BFPCTRL_BFE(offset - MCP251X_GPIO_RX0BF); | |
| 439 | + | |
| 440 | + mutex_lock(&priv->mcp_lock); | |
| 441 | + mcp251x_write_bits(priv->spi, BFPCTRL, val, val); | |
| 442 | + mutex_unlock(&priv->mcp_lock); | |
| 443 | + | |
| 444 | + priv->reg_bfpctrl |= val; | |
| 445 | + | |
| 446 | + return 0; | |
| 447 | +} | |
| 448 | + | |
| 449 | +static void mcp251x_gpio_free(struct gpio_chip *chip, | |
| 450 | + unsigned int offset) | |
| 451 | +{ | |
| 452 | + struct mcp251x_priv *priv = gpiochip_get_data(chip); | |
| 453 | + u8 val; | |
| 454 | + | |
| 455 | + /* nothing to be done for inputs */ | |
| 456 | + if (mcp251x_gpio_is_input(offset)) | |
| 457 | + return; | |
| 458 | + | |
| 459 | + val = BFPCTRL_BFE(offset - MCP251X_GPIO_RX0BF); | |
| 460 | + | |
| 461 | + mutex_lock(&priv->mcp_lock); | |
| 462 | + mcp251x_write_bits(priv->spi, BFPCTRL, val, 0); | |
| 463 | + mutex_unlock(&priv->mcp_lock); | |
| 464 | + | |
| 465 | + priv->reg_bfpctrl &= ~val; | |
| 466 | +} | |
| 467 | + | |
| 468 | +static int mcp251x_gpio_get_direction(struct gpio_chip *chip, | |
| 469 | + unsigned int offset) | |
| 470 | +{ | |
| 471 | + if (mcp251x_gpio_is_input(offset)) | |
| 472 | + return GPIOF_DIR_IN; | |
| 473 | + | |
| 474 | + return GPIOF_DIR_OUT; | |
| 475 | +} | |
| 476 | + | |
| 477 | +static int mcp251x_gpio_get(struct gpio_chip *chip, unsigned int offset) | |
| 478 | +{ | |
| 479 | + struct mcp251x_priv *priv = gpiochip_get_data(chip); | |
| 480 | + u8 reg, mask, val; | |
| 481 | + | |
| 482 | + if (mcp251x_gpio_is_input(offset)) { | |
| 483 | + reg = TXRTSCTRL; | |
| 484 | + mask = TXRTSCTRL_RTS(offset); | |
| 485 | + } else { | |
| 486 | + reg = BFPCTRL; | |
| 487 | + mask = BFPCTRL_BFS(offset - MCP251X_GPIO_RX0BF); | |
| 488 | + } | |
| 489 | + | |
| 490 | + mutex_lock(&priv->mcp_lock); | |
| 491 | + val = mcp251x_read_reg(priv->spi, reg); | |
| 492 | + mutex_unlock(&priv->mcp_lock); | |
| 493 | + | |
| 494 | + return !!(val & mask); | |
| 495 | +} | |
| 496 | + | |
| 497 | +static int mcp251x_gpio_get_multiple(struct gpio_chip *chip, | |
| 498 | + unsigned long *maskp, unsigned long *bitsp) | |
| 499 | +{ | |
| 500 | + struct mcp251x_priv *priv = gpiochip_get_data(chip); | |
| 501 | + unsigned long bits = 0; | |
| 502 | + u8 val; | |
| 503 | + | |
| 504 | + mutex_lock(&priv->mcp_lock); | |
| 505 | + if (maskp[0] & MCP251X_GPIO_INPUT_MASK) { | |
| 506 | + val = mcp251x_read_reg(priv->spi, TXRTSCTRL); | |
| 507 | + val = FIELD_GET(TXRTSCTRL_RTS_MASK, val); | |
| 508 | + bits |= FIELD_PREP(MCP251X_GPIO_INPUT_MASK, val); | |
| 509 | + } | |
| 510 | + if (maskp[0] & MCP251X_GPIO_OUTPUT_MASK) { | |
| 511 | + val = mcp251x_read_reg(priv->spi, BFPCTRL); | |
| 512 | + val = FIELD_GET(BFPCTRL_BFS_MASK, val); | |
| 513 | + bits |= FIELD_PREP(MCP251X_GPIO_OUTPUT_MASK, val); | |
| 514 | + } | |
| 515 | + mutex_unlock(&priv->mcp_lock); | |
| 516 | + | |
| 517 | + bitsp[0] = bits; | |
| 518 | + return 0; | |
| 519 | +} | |
| 520 | + | |
| 521 | +static void mcp251x_gpio_set(struct gpio_chip *chip, unsigned int offset, | |
| 522 | + int value) | |
| 523 | +{ | |
| 524 | + struct mcp251x_priv *priv = gpiochip_get_data(chip); | |
| 525 | + u8 mask, val; | |
| 526 | + | |
| 527 | + mask = BFPCTRL_BFS(offset - MCP251X_GPIO_RX0BF); | |
| 528 | + val = value ? mask : 0; | |
| 529 | + | |
| 530 | + mutex_lock(&priv->mcp_lock); | |
| 531 | + mcp251x_write_bits(priv->spi, BFPCTRL, mask, val); | |
| 532 | + mutex_unlock(&priv->mcp_lock); | |
| 533 | + | |
| 534 | + priv->reg_bfpctrl &= ~mask; | |
| 535 | + priv->reg_bfpctrl |= val; | |
| 536 | +} | |
| 537 | + | |
| 538 | +static void | |
| 539 | +mcp251x_gpio_set_multiple(struct gpio_chip *chip, | |
| 540 | + unsigned long *maskp, unsigned long *bitsp) | |
| 541 | +{ | |
| 542 | + struct mcp251x_priv *priv = gpiochip_get_data(chip); | |
| 543 | + u8 mask, val; | |
| 544 | + | |
| 545 | + mask = FIELD_GET(MCP251X_GPIO_OUTPUT_MASK, maskp[0]); | |
| 546 | + mask = FIELD_PREP(BFPCTRL_BFS_MASK, mask); | |
| 547 | + | |
| 548 | + val = FIELD_GET(MCP251X_GPIO_OUTPUT_MASK, bitsp[0]); | |
| 549 | + val = FIELD_PREP(BFPCTRL_BFS_MASK, val); | |
| 550 | + | |
| 551 | + if (!mask) | |
| 552 | + return; | |
| 553 | + | |
| 554 | + mutex_lock(&priv->mcp_lock); | |
| 555 | + mcp251x_write_bits(priv->spi, BFPCTRL, mask, val); | |
| 556 | + mutex_unlock(&priv->mcp_lock); | |
| 557 | + | |
| 558 | + priv->reg_bfpctrl &= ~mask; | |
| 559 | + priv->reg_bfpctrl |= val; | |
| 560 | +} | |
| 561 | + | |
| 562 | +static void mcp251x_gpio_restore(struct spi_device *spi) | |
| 563 | +{ | |
| 564 | + struct mcp251x_priv *priv = spi_get_drvdata(spi); | |
| 565 | + | |
| 566 | + mcp251x_write_reg(spi, BFPCTRL, priv->reg_bfpctrl); | |
| 567 | +} | |
| 568 | + | |
| 569 | +static int mcp251x_gpio_setup(struct mcp251x_priv *priv) | |
| 570 | +{ | |
| 571 | + struct gpio_chip *gpio = &priv->gpio; | |
| 572 | + | |
| 573 | + if (!device_property_present(&priv->spi->dev, "gpio-controller")) | |
| 574 | + return 0; | |
| 575 | + | |
| 576 | + /* gpiochip handles TX[0..2]RTS and RX[0..1]BF */ | |
| 577 | + gpio->label = priv->spi->modalias; | |
| 578 | + gpio->parent = &priv->spi->dev; | |
| 579 | + gpio->owner = THIS_MODULE; | |
| 580 | + gpio->request = mcp251x_gpio_request; | |
| 581 | + gpio->free = mcp251x_gpio_free; | |
| 582 | + gpio->get_direction = mcp251x_gpio_get_direction; | |
| 583 | + gpio->get = mcp251x_gpio_get; | |
| 584 | + gpio->get_multiple = mcp251x_gpio_get_multiple; | |
| 585 | + gpio->set = mcp251x_gpio_set; | |
| 586 | + gpio->set_multiple = mcp251x_gpio_set_multiple; | |
| 587 | + gpio->base = -1; | |
| 588 | + gpio->ngpio = ARRAY_SIZE(mcp251x_gpio_names); | |
| 589 | + gpio->names = mcp251x_gpio_names; | |
| 590 | + gpio->can_sleep = true; | |
| 591 | +#ifdef CONFIG_OF_GPIO | |
| 592 | + gpio->of_node = priv->spi->dev.of_node; | |
| 593 | +#endif | |
| 594 | + | |
| 595 | + return devm_gpiochip_add_data(&priv->spi->dev, gpio, priv); | |
| 596 | +} | |
| 597 | +#else | |
| 598 | +static inline void mcp251x_gpio_restore(struct spi_device *spi) | |
| 599 | +{ | |
| 600 | +} | |
| 601 | + | |
| 602 | +static inline int mcp251x_gpio_setup(struct mcp251x_priv *priv) | |
| 603 | +{ | |
| 604 | + return 0; | |
| 605 | +} | |
| 606 | +#endif | |
| 607 | + | |
| 348 | 608 | static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf, |
| 349 | 609 | int len, int tx_buf_idx) |
| 350 | 610 | { |
| @@ -409,8 +669,16 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf, · 58 unmodified lines | ||
| 409 | 669 | buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i); |
| 410 | 670 | } else { |
| 411 | 671 | priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx); |
| 412 | − mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN); | |
| 413 | − memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN); | |
| 672 | + if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) { | |
| 673 | + spi_write_then_read(spi, priv->spi_tx_buf, 1, | |
| 674 | + priv->spi_rx_buf, | |
| 675 | + SPI_TRANSFER_BUF_LEN); | |
| 676 | + memcpy(buf + 1, priv->spi_rx_buf, | |
| 677 | + SPI_TRANSFER_BUF_LEN - 1); | |
| 678 | + } else { | |
| 679 | + mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN); | |
| 680 | + memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN); | |
| 681 | + } | |
| 414 | 682 | } |
| 415 | 683 | } |
| 416 | 684 | |
| @@ -471,7 +739,8 @@ static void mcp251x_hw_sleep(struct spi_device *spi) · 54 unmodified lines | ||
| 471 | 739 | /* May only be called when device is sleeping! */ |
| 472 | 740 | static int mcp251x_hw_wake(struct spi_device *spi) |
| 473 | 741 | { |
| 474 | − unsigned long timeout; | |
| 742 | + u8 value; | |
| 743 | + int ret; | |
| 475 | 744 | |
| 476 | 745 | /* Force wakeup interrupt to wake device, but don't execute IST */ |
| 477 | 746 | disable_irq(spi->irq); |
| @@ -484,14 +753,12 @@ static int mcp251x_hw_wake(struct spi_device *spi) · 6 unmodified lines | ||
| 484 | 753 | mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_CONF); |
| 485 | 754 | |
| 486 | 755 | /* Wait for the device to enter config mode */ |
| 487 | − timeout = jiffies + HZ; | |
| 488 | − while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) != | |
| 489 | − CANCTRL_REQOP_CONF) { | |
| 490 | − schedule(); | |
| 491 | − if (time_after(jiffies, timeout)) { | |
| 492 | − dev_err(&spi->dev, "MCP251x didn't enter in config mode\n"); | |
| 493 | − return -EBUSY; | |
| 494 | − } | |
| 756 | + ret = mcp251x_read_stat_poll_timeout(spi, value, value == CANCTRL_REQOP_CONF, | |
| 757 | + MCP251X_OST_DELAY_MS * 1000, | |
| 758 | + USEC_PER_SEC); | |
| 759 | + if (ret) { | |
| 760 | + dev_err(&spi->dev, "MCP251x didn't enter in config mode\n"); | |
| 761 | + return ret; | |
| 495 | 762 | } |
| 496 | 763 | |
| 497 | 764 | /* Disable and clear pending interrupts */ |
| @@ -546,7 +813,8 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode) · 48 unmodified lines | ||
| 546 | 813 | static int mcp251x_set_normal_mode(struct spi_device *spi) |
| 547 | 814 | { |
| 548 | 815 | struct mcp251x_priv *priv = spi_get_drvdata(spi); |
| 549 | − unsigned long timeout; | |
| 816 | + u8 value; | |
| 817 | + int ret; | |
| 550 | 818 | |
| 551 | 819 | /* Enable interrupts */ |
| 552 | 820 | mcp251x_write_reg(spi, CANINTE, |
| @@ -564,13 +832,12 @@ static int mcp251x_set_normal_mode(struct spi_device *spi) · 11 unmodified lines | ||
| 564 | 832 | mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); |
| 565 | 833 | |
| 566 | 834 | /* Wait for the device to enter normal mode */ |
| 567 | − timeout = jiffies + HZ; | |
| 568 | − while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) { | |
| 569 | − schedule(); | |
| 570 | − if (time_after(jiffies, timeout)) { | |
| 571 | − dev_err(&spi->dev, "MCP251x didn't enter in normal mode\n"); | |
| 572 | − return -EBUSY; | |
| 573 | − } | |
| 835 | + ret = mcp251x_read_stat_poll_timeout(spi, value, value == 0, | |
| 836 | + MCP251X_OST_DELAY_MS * 1000, | |
| 837 | + USEC_PER_SEC); | |
| 838 | + if (ret) { | |
| 839 | + dev_err(&spi->dev, "MCP251x didn't enter in normal mode\n"); | |
| 840 | + return ret; | |
| 574 | 841 | } |
| 575 | 842 | } |
| 576 | 843 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
| @@ -614,7 +881,7 @@ static int mcp251x_setup(struct net_device *net, struct spi_device *spi) · 37 unmodified lines | ||
| 614 | 881 | static int mcp251x_hw_reset(struct spi_device *spi) |
| 615 | 882 | { |
| 616 | 883 | struct mcp251x_priv *priv = spi_get_drvdata(spi); |
| 617 | − unsigned long timeout; | |
| 884 | + u8 value; | |
| 618 | 885 | int ret; |
| 619 | 886 | |
| 620 | 887 | /* Wait for oscillator startup timer after power up */ |
| @@ -629,19 +896,12 @@ static int mcp251x_hw_reset(struct spi_device *spi) · 8 unmodified lines | ||
| 629 | 896 | mdelay(MCP251X_OST_DELAY_MS); |
| 630 | 897 | |
| 631 | 898 | /* Wait for reset to finish */ |
| 632 | − timeout = jiffies + HZ; | |
| 633 | − while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) != | |
| 634 | − CANCTRL_REQOP_CONF) { | |
| 635 | − usleep_range(MCP251X_OST_DELAY_MS * 1000, | |
| 636 | − MCP251X_OST_DELAY_MS * 1000 * 2); | |
| 637 | − | |
| 638 | − if (time_after(jiffies, timeout)) { | |
| 639 | − dev_err(&spi->dev, | |
| 640 | − "MCP251x didn't enter in conf mode after reset\n"); | |
| 641 | − return -EBUSY; | |
| 642 | − } | |
| 643 | − } | |
| 644 | − return 0; | |
| 899 | + ret = mcp251x_read_stat_poll_timeout(spi, value, value == CANCTRL_REQOP_CONF, | |
| 900 | + MCP251X_OST_DELAY_MS * 1000, | |
| 901 | + USEC_PER_SEC); | |
| 902 | + if (ret) | |
| 903 | + dev_err(&spi->dev, "MCP251x didn't enter in conf mode after reset\n"); | |
| 904 | + return ret; | |
| 645 | 905 | } |
| 646 | 906 | |
| 647 | 907 | static int mcp251x_hw_probe(struct spi_device *spi) |
| @@ -761,6 +1021,7 @@ static void mcp251x_restart_work_handler(struct work_struct *ws) · 113 unmodified lines | ||
| 761 | 1021 | if (priv->after_suspend & AFTER_SUSPEND_POWER) { |
| 762 | 1022 | mcp251x_hw_reset(spi); |
| 763 | 1023 | mcp251x_setup(net, spi); |
| 1024 | + mcp251x_gpio_restore(spi); | |
| 764 | 1025 | } else { |
| 765 | 1026 | mcp251x_hw_wake(spi); |
| 766 | 1027 | } |
| @@ -1136,6 +1397,10 @@ static int mcp251x_can_probe(struct spi_device *spi) · 369 unmodified lines | ||
| 1136 | 1397 | |
| 1137 | 1398 | devm_can_led_init(net); |
| 1138 | 1399 | |
| 1400 | + ret = mcp251x_gpio_setup(priv); | |
| 1401 | + if (ret) | |
| 1402 | + goto error_probe; | |
| 1403 | + | |
| 1139 | 1404 | netdev_info(net, "MCP%x successfully initialized.\n", priv->model); |
| 1140 | 1405 | return 0; |
| 1141 | 1406 | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | + | |
| 3 | +config CAN_MCP251XFD | |
| 4 | + tristate "Microchip MCP251xFD SPI CAN controllers" | |
| 5 | + select REGMAP | |
| 6 | + help | |
| 7 | + Driver for the Microchip MCP251XFD SPI FD-CAN controller | |
| 8 | + family. | |
| 9 | + | |
| 10 | +config CAN_MCP251XFD_SANITY | |
| 11 | + depends on CAN_MCP251XFD | |
| 12 | + bool "Additional Sanity Checks" | |
| 13 | + help | |
| 14 | + This option enables additional sanity checks in the driver, | |
| 15 | + that compares various internal counters with the in chip | |
| 16 | + variants. This comes with a runtime overhead. | |
| 17 | + Disable if unsure. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | + | |
| 3 | +obj-$(CONFIG_CAN_MCP251XFD) += mcp251xfd.o | |
| 4 | + | |
| 5 | +mcp251xfd-objs := | |
| 6 | +mcp251xfd-objs += mcp251xfd-core.o | |
| 7 | +mcp251xfd-objs += mcp251xfd-crc16.o | |
| 8 | +mcp251xfd-objs += mcp251xfd-regmap.o | |
| @@ -0,0 +1,2927 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// | |
| 3 | +// mcp251xfd - Microchip MCP251xFD Family CAN controller driver | |
| 4 | +// | |
| 5 | +// Copyright (c) 2019, 2020 Pengutronix, | |
| 6 | +// Marc Kleine-Budde <kernel@pengutronix.de> | |
| 7 | +// | |
| 8 | +// Based on: | |
| 9 | +// | |
| 10 | +// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface | |
| 11 | +// | |
| 12 | +// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> | |
| 13 | +// | |
| 14 | + | |
| 15 | +#include <linux/bitfield.h> | |
| 16 | +#include <linux/clk.h> | |
| 17 | +#include <linux/device.h> | |
| 18 | +#include <linux/module.h> | |
| 19 | +#include <linux/netdevice.h> | |
| 20 | +#include <linux/of.h> | |
| 21 | +#include <linux/of_device.h> | |
| 22 | +#include <linux/pm_runtime.h> | |
| 23 | + | |
| 24 | +#include <asm/unaligned.h> | |
| 25 | + | |
| 26 | +#include "mcp251xfd.h" | |
| 27 | + | |
| 28 | +#define DEVICE_NAME "mcp251xfd" | |
| 29 | + | |
| 30 | +static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp2517fd = { | |
| 31 | + .quirks = MCP251XFD_QUIRK_MAB_NO_WARN | MCP251XFD_QUIRK_CRC_REG | | |
| 32 | + MCP251XFD_QUIRK_CRC_RX | MCP251XFD_QUIRK_CRC_TX | | |
| 33 | + MCP251XFD_QUIRK_ECC, | |
| 34 | + .model = MCP251XFD_MODEL_MCP2517FD, | |
| 35 | +}; | |
| 36 | + | |
| 37 | +static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp2518fd = { | |
| 38 | + .quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX | | |
| 39 | + MCP251XFD_QUIRK_CRC_TX | MCP251XFD_QUIRK_ECC, | |
| 40 | + .model = MCP251XFD_MODEL_MCP2518FD, | |
| 41 | +}; | |
| 42 | + | |
| 43 | +/* Autodetect model, start with CRC enabled. */ | |
| 44 | +static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251xfd = { | |
| 45 | + .quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX | | |
| 46 | + MCP251XFD_QUIRK_CRC_TX | MCP251XFD_QUIRK_ECC, | |
| 47 | + .model = MCP251XFD_MODEL_MCP251XFD, | |
| 48 | +}; | |
| 49 | + | |
| 50 | +static const struct can_bittiming_const mcp251xfd_bittiming_const = { | |
| 51 | + .name = DEVICE_NAME, | |
| 52 | + .tseg1_min = 2, | |
| 53 | + .tseg1_max = 256, | |
| 54 | + .tseg2_min = 1, | |
| 55 | + .tseg2_max = 128, | |
| 56 | + .sjw_max = 128, | |
| 57 | + .brp_min = 1, | |
| 58 | + .brp_max = 256, | |
| 59 | + .brp_inc = 1, | |
| 60 | +}; | |
| 61 | + | |
| 62 | +static const struct can_bittiming_const mcp251xfd_data_bittiming_const = { | |
| 63 | + .name = DEVICE_NAME, | |
| 64 | + .tseg1_min = 1, | |
| 65 | + .tseg1_max = 32, | |
| 66 | + .tseg2_min = 1, | |
| 67 | + .tseg2_max = 16, | |
| 68 | + .sjw_max = 16, | |
| 69 | + .brp_min = 1, | |
| 70 | + .brp_max = 256, | |
| 71 | + .brp_inc = 1, | |
| 72 | +}; | |
| 73 | + | |
| 74 | +static const char *__mcp251xfd_get_model_str(enum mcp251xfd_model model) | |
| 75 | +{ | |
| 76 | + switch (model) { | |
| 77 | + case MCP251XFD_MODEL_MCP2517FD: | |
| 78 | + return "MCP2517FD"; break; | |
| 79 | + case MCP251XFD_MODEL_MCP2518FD: | |
| 80 | + return "MCP2518FD"; break; | |
| 81 | + case MCP251XFD_MODEL_MCP251XFD: | |
| 82 | + return "MCP251xFD"; break; | |
| 83 | + } | |
| 84 | + | |
| 85 | + return "<unknown>"; | |
| 86 | +} | |
| 87 | + | |
| 88 | +static inline const char * | |
| 89 | +mcp251xfd_get_model_str(const struct mcp251xfd_priv *priv) | |
| 90 | +{ | |
| 91 | + return __mcp251xfd_get_model_str(priv->devtype_data.model); | |
| 92 | +} | |
| 93 | + | |
| 94 | +static const char *mcp251xfd_get_mode_str(const u8 mode) | |
| 95 | +{ | |
| 96 | + switch (mode) { | |
| 97 | + case MCP251XFD_REG_CON_MODE_MIXED: | |
| 98 | + return "Mixed (CAN FD/CAN 2.0)"; break; | |
| 99 | + case MCP251XFD_REG_CON_MODE_SLEEP: | |
| 100 | + return "Sleep"; break; | |
| 101 | + case MCP251XFD_REG_CON_MODE_INT_LOOPBACK: | |
| 102 | + return "Internal Loopback"; break; | |
| 103 | + case MCP251XFD_REG_CON_MODE_LISTENONLY: | |
| 104 | + return "Listen Only"; break; | |
| 105 | + case MCP251XFD_REG_CON_MODE_CONFIG: | |
| 106 | + return "Configuration"; break; | |
| 107 | + case MCP251XFD_REG_CON_MODE_EXT_LOOPBACK: | |
| 108 | + return "External Loopback"; break; | |
| 109 | + case MCP251XFD_REG_CON_MODE_CAN2_0: | |
| 110 | + return "CAN 2.0"; break; | |
| 111 | + case MCP251XFD_REG_CON_MODE_RESTRICTED: | |
| 112 | + return "Restricted Operation"; break; | |
| 113 | + } | |
| 114 | + | |
| 115 | + return "<unknown>"; | |
| 116 | +} | |
| 117 | + | |
| 118 | +static inline int mcp251xfd_vdd_enable(const struct mcp251xfd_priv *priv) | |
| 119 | +{ | |
| 120 | + if (!priv->reg_vdd) | |
| 121 | + return 0; | |
| 122 | + | |
| 123 | + return regulator_enable(priv->reg_vdd); | |
| 124 | +} | |
| 125 | + | |
| 126 | +static inline int mcp251xfd_vdd_disable(const struct mcp251xfd_priv *priv) | |
| 127 | +{ | |
| 128 | + if (!priv->reg_vdd) | |
| 129 | + return 0; | |
| 130 | + | |
| 131 | + return regulator_disable(priv->reg_vdd); | |
| 132 | +} | |
| 133 | + | |
| 134 | +static inline int | |
| 135 | +mcp251xfd_transceiver_enable(const struct mcp251xfd_priv *priv) | |
| 136 | +{ | |
| 137 | + if (!priv->reg_xceiver) | |
| 138 | + return 0; | |
| 139 | + | |
| 140 | + return regulator_enable(priv->reg_xceiver); | |
| 141 | +} | |
| 142 | + | |
| 143 | +static inline int | |
| 144 | +mcp251xfd_transceiver_disable(const struct mcp251xfd_priv *priv) | |
| 145 | +{ | |
| 146 | + if (!priv->reg_xceiver) | |
| 147 | + return 0; | |
| 148 | + | |
| 149 | + return regulator_disable(priv->reg_xceiver); | |
| 150 | +} | |
| 151 | + | |
| 152 | +static int mcp251xfd_clks_and_vdd_enable(const struct mcp251xfd_priv *priv) | |
| 153 | +{ | |
| 154 | + int err; | |
| 155 | + | |
| 156 | + err = clk_prepare_enable(priv->clk); | |
| 157 | + if (err) | |
| 158 | + return err; | |
| 159 | + | |
| 160 | + err = mcp251xfd_vdd_enable(priv); | |
| 161 | + if (err) | |
| 162 | + clk_disable_unprepare(priv->clk); | |
| 163 | + | |
| 164 | + /* Wait for oscillator stabilisation time after power up */ | |
| 165 | + usleep_range(MCP251XFD_OSC_STAB_SLEEP_US, | |
| 166 | + 2 * MCP251XFD_OSC_STAB_SLEEP_US); | |
| 167 | + | |
| 168 | + return err; | |
| 169 | +} | |
| 170 | + | |
| 171 | +static int mcp251xfd_clks_and_vdd_disable(const struct mcp251xfd_priv *priv) | |
| 172 | +{ | |
| 173 | + int err; | |
| 174 | + | |
| 175 | + err = mcp251xfd_vdd_disable(priv); | |
| 176 | + if (err) | |
| 177 | + return err; | |
| 178 | + | |
| 179 | + clk_disable_unprepare(priv->clk); | |
| 180 | + | |
| 181 | + return 0; | |
| 182 | +} | |
| 183 | + | |
| 184 | +static inline u8 | |
| 185 | +mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv, | |
| 186 | + union mcp251xfd_write_reg_buf *write_reg_buf, | |
| 187 | + const u16 reg, const u32 mask, const u32 val) | |
| 188 | +{ | |
| 189 | + u8 first_byte, last_byte, len; | |
| 190 | + u8 *data; | |
| 191 | + __le32 val_le32; | |
| 192 | + | |
| 193 | + first_byte = mcp251xfd_first_byte_set(mask); | |
| 194 | + last_byte = mcp251xfd_last_byte_set(mask); | |
| 195 | + len = last_byte - first_byte + 1; | |
| 196 | + | |
| 197 | + data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte); | |
| 198 | + val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte); | |
| 199 | + memcpy(data, &val_le32, len); | |
| 200 | + | |
| 201 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) { | |
| 202 | + u16 crc; | |
| 203 | + | |
| 204 | + mcp251xfd_spi_cmd_crc_set_len_in_reg(&write_reg_buf->crc.cmd, | |
| 205 | + len); | |
| 206 | + /* CRC */ | |
| 207 | + len += sizeof(write_reg_buf->crc.cmd); | |
| 208 | + crc = mcp251xfd_crc16_compute(&write_reg_buf->crc, len); | |
| 209 | + put_unaligned_be16(crc, (void *)write_reg_buf + len); | |
| 210 | + | |
| 211 | + /* Total length */ | |
| 212 | + len += sizeof(write_reg_buf->crc.crc); | |
| 213 | + } else { | |
| 214 | + len += sizeof(write_reg_buf->nocrc.cmd); | |
| 215 | + } | |
| 216 | + | |
| 217 | + return len; | |
| 218 | +} | |
| 219 | + | |
| 220 | +static inline int | |
| 221 | +mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv, | |
| 222 | + u8 *tef_tail) | |
| 223 | +{ | |
| 224 | + u32 tef_ua; | |
| 225 | + int err; | |
| 226 | + | |
| 227 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFUA, &tef_ua); | |
| 228 | + if (err) | |
| 229 | + return err; | |
| 230 | + | |
| 231 | + *tef_tail = tef_ua / sizeof(struct mcp251xfd_hw_tef_obj); | |
| 232 | + | |
| 233 | + return 0; | |
| 234 | +} | |
| 235 | + | |
| 236 | +static inline int | |
| 237 | +mcp251xfd_tx_tail_get_from_chip(const struct mcp251xfd_priv *priv, | |
| 238 | + u8 *tx_tail) | |
| 239 | +{ | |
| 240 | + u32 fifo_sta; | |
| 241 | + int err; | |
| 242 | + | |
| 243 | + err = regmap_read(priv->map_reg, | |
| 244 | + MCP251XFD_REG_FIFOSTA(MCP251XFD_TX_FIFO), | |
| 245 | + &fifo_sta); | |
| 246 | + if (err) | |
| 247 | + return err; | |
| 248 | + | |
| 249 | + *tx_tail = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta); | |
| 250 | + | |
| 251 | + return 0; | |
| 252 | +} | |
| 253 | + | |
| 254 | +static inline int | |
| 255 | +mcp251xfd_rx_head_get_from_chip(const struct mcp251xfd_priv *priv, | |
| 256 | + const struct mcp251xfd_rx_ring *ring, | |
| 257 | + u8 *rx_head) | |
| 258 | +{ | |
| 259 | + u32 fifo_sta; | |
| 260 | + int err; | |
| 261 | + | |
| 262 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr), | |
| 263 | + &fifo_sta); | |
| 264 | + if (err) | |
| 265 | + return err; | |
| 266 | + | |
| 267 | + *rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta); | |
| 268 | + | |
| 269 | + return 0; | |
| 270 | +} | |
| 271 | + | |
| 272 | +static inline int | |
| 273 | +mcp251xfd_rx_tail_get_from_chip(const struct mcp251xfd_priv *priv, | |
| 274 | + const struct mcp251xfd_rx_ring *ring, | |
| 275 | + u8 *rx_tail) | |
| 276 | +{ | |
| 277 | + u32 fifo_ua; | |
| 278 | + int err; | |
| 279 | + | |
| 280 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr), | |
| 281 | + &fifo_ua); | |
| 282 | + if (err) | |
| 283 | + return err; | |
| 284 | + | |
| 285 | + fifo_ua -= ring->base - MCP251XFD_RAM_START; | |
| 286 | + *rx_tail = fifo_ua / ring->obj_size; | |
| 287 | + | |
| 288 | + return 0; | |
| 289 | +} | |
| 290 | + | |
| 291 | +static void | |
| 292 | +mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv, | |
| 293 | + const struct mcp251xfd_tx_ring *ring, | |
| 294 | + struct mcp251xfd_tx_obj *tx_obj, | |
| 295 | + const u8 rts_buf_len, | |
| 296 | + const u8 n) | |
| 297 | +{ | |
| 298 | + struct spi_transfer *xfer; | |
| 299 | + u16 addr; | |
| 300 | + | |
| 301 | + /* FIFO load */ | |
| 302 | + addr = mcp251xfd_get_tx_obj_addr(ring, n); | |
| 303 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) | |
| 304 | + mcp251xfd_spi_cmd_write_crc_set_addr(&tx_obj->buf.crc.cmd, | |
| 305 | + addr); | |
| 306 | + else | |
| 307 | + mcp251xfd_spi_cmd_write_nocrc(&tx_obj->buf.nocrc.cmd, | |
| 308 | + addr); | |
| 309 | + | |
| 310 | + xfer = &tx_obj->xfer[0]; | |
| 311 | + xfer->tx_buf = &tx_obj->buf; | |
| 312 | + xfer->len = 0; /* actual len is assigned on the fly */ | |
| 313 | + xfer->cs_change = 1; | |
| 314 | + xfer->cs_change_delay.value = 0; | |
| 315 | + xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; | |
| 316 | + | |
| 317 | + /* FIFO request to send */ | |
| 318 | + xfer = &tx_obj->xfer[1]; | |
| 319 | + xfer->tx_buf = &ring->rts_buf; | |
| 320 | + xfer->len = rts_buf_len; | |
| 321 | + | |
| 322 | + /* SPI message */ | |
| 323 | + spi_message_init_with_transfers(&tx_obj->msg, tx_obj->xfer, | |
| 324 | + ARRAY_SIZE(tx_obj->xfer)); | |
| 325 | +} | |
| 326 | + | |
| 327 | +static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) | |
| 328 | +{ | |
| 329 | + struct mcp251xfd_tx_ring *tx_ring; | |
| 330 | + struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL; | |
| 331 | + struct mcp251xfd_tx_obj *tx_obj; | |
| 332 | + u32 val; | |
| 333 | + u16 addr; | |
| 334 | + u8 len; | |
| 335 | + int i; | |
| 336 | + | |
| 337 | + /* TEF */ | |
| 338 | + priv->tef.head = 0; | |
| 339 | + priv->tef.tail = 0; | |
| 340 | + | |
| 341 | + /* TX */ | |
| 342 | + tx_ring = priv->tx; | |
| 343 | + tx_ring->head = 0; | |
| 344 | + tx_ring->tail = 0; | |
| 345 | + tx_ring->base = mcp251xfd_get_tef_obj_addr(tx_ring->obj_num); | |
| 346 | + | |
| 347 | + /* FIFO request to send */ | |
| 348 | + addr = MCP251XFD_REG_FIFOCON(MCP251XFD_TX_FIFO); | |
| 349 | + val = MCP251XFD_REG_FIFOCON_TXREQ | MCP251XFD_REG_FIFOCON_UINC; | |
| 350 | + len = mcp251xfd_cmd_prepare_write_reg(priv, &tx_ring->rts_buf, | |
| 351 | + addr, val, val); | |
| 352 | + | |
| 353 | + mcp251xfd_for_each_tx_obj(tx_ring, tx_obj, i) | |
| 354 | + mcp251xfd_tx_ring_init_tx_obj(priv, tx_ring, tx_obj, len, i); | |
| 355 | + | |
| 356 | + /* RX */ | |
| 357 | + mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { | |
| 358 | + rx_ring->head = 0; | |
| 359 | + rx_ring->tail = 0; | |
| 360 | + rx_ring->nr = i; | |
| 361 | + rx_ring->fifo_nr = MCP251XFD_RX_FIFO(i); | |
| 362 | + | |
| 363 | + if (!prev_rx_ring) | |
| 364 | + rx_ring->base = | |
| 365 | + mcp251xfd_get_tx_obj_addr(tx_ring, | |
| 366 | + tx_ring->obj_num); | |
| 367 | + else | |
| 368 | + rx_ring->base = prev_rx_ring->base + | |
| 369 | + prev_rx_ring->obj_size * | |
| 370 | + prev_rx_ring->obj_num; | |
| 371 | + | |
| 372 | + prev_rx_ring = rx_ring; | |
| 373 | + } | |
| 374 | +} | |
| 375 | + | |
| 376 | +static void mcp251xfd_ring_free(struct mcp251xfd_priv *priv) | |
| 377 | +{ | |
| 378 | + int i; | |
| 379 | + | |
| 380 | + for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) { | |
| 381 | + kfree(priv->rx[i]); | |
| 382 | + priv->rx[i] = NULL; | |
| 383 | + } | |
| 384 | +} | |
| 385 | + | |
| 386 | +static int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) | |
| 387 | +{ | |
| 388 | + struct mcp251xfd_tx_ring *tx_ring; | |
| 389 | + struct mcp251xfd_rx_ring *rx_ring; | |
| 390 | + int tef_obj_size, tx_obj_size, rx_obj_size; | |
| 391 | + int tx_obj_num; | |
| 392 | + int ram_free, i; | |
| 393 | + | |
| 394 | + tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj); | |
| 395 | + /* listen-only mode works like FD mode */ | |
| 396 | + if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD)) { | |
| 397 | + tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD; | |
| 398 | + tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd); | |
| 399 | + rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd); | |
| 400 | + } else { | |
| 401 | + tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN; | |
| 402 | + tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can); | |
| 403 | + rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can); | |
| 404 | + } | |
| 405 | + | |
| 406 | + tx_ring = priv->tx; | |
| 407 | + tx_ring->obj_num = tx_obj_num; | |
| 408 | + tx_ring->obj_size = tx_obj_size; | |
| 409 | + | |
| 410 | + ram_free = MCP251XFD_RAM_SIZE - tx_obj_num * | |
| 411 | + (tef_obj_size + tx_obj_size); | |
| 412 | + | |
| 413 | + for (i = 0; | |
| 414 | + i < ARRAY_SIZE(priv->rx) && ram_free >= rx_obj_size; | |
| 415 | + i++) { | |
| 416 | + int rx_obj_num; | |
| 417 | + | |
| 418 | + rx_obj_num = ram_free / rx_obj_size; | |
| 419 | + rx_obj_num = min(1 << (fls(rx_obj_num) - 1), 32); | |
| 420 | + | |
| 421 | + rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num, | |
| 422 | + GFP_KERNEL); | |
| 423 | + if (!rx_ring) { | |
| 424 | + mcp251xfd_ring_free(priv); | |
| 425 | + return -ENOMEM; | |
| 426 | + } | |
| 427 | + rx_ring->obj_num = rx_obj_num; | |
| 428 | + rx_ring->obj_size = rx_obj_size; | |
| 429 | + priv->rx[i] = rx_ring; | |
| 430 | + | |
| 431 | + ram_free -= rx_ring->obj_num * rx_ring->obj_size; | |
| 432 | + } | |
| 433 | + priv->rx_ring_num = i; | |
| 434 | + | |
| 435 | + netdev_dbg(priv->ndev, | |
| 436 | + "FIFO setup: TEF: %d*%d bytes = %d bytes, TX: %d*%d bytes = %d bytes\n", | |
| 437 | + tx_obj_num, tef_obj_size, tef_obj_size * tx_obj_num, | |
| 438 | + tx_obj_num, tx_obj_size, tx_obj_size * tx_obj_num); | |
| 439 | + | |
| 440 | + mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { | |
| 441 | + netdev_dbg(priv->ndev, | |
| 442 | + "FIFO setup: RX-%d: %d*%d bytes = %d bytes\n", | |
| 443 | + i, rx_ring->obj_num, rx_ring->obj_size, | |
| 444 | + rx_ring->obj_size * rx_ring->obj_num); | |
| 445 | + } | |
| 446 | + | |
| 447 | + netdev_dbg(priv->ndev, | |
| 448 | + "FIFO setup: free: %d bytes\n", | |
| 449 | + ram_free); | |
| 450 | + | |
| 451 | + return 0; | |
| 452 | +} | |
| 453 | + | |
| 454 | +static inline int | |
| 455 | +mcp251xfd_chip_get_mode(const struct mcp251xfd_priv *priv, u8 *mode) | |
| 456 | +{ | |
| 457 | + u32 val; | |
| 458 | + int err; | |
| 459 | + | |
| 460 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_CON, &val); | |
| 461 | + if (err) | |
| 462 | + return err; | |
| 463 | + | |
| 464 | + *mode = FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK, val); | |
| 465 | + | |
| 466 | + return 0; | |
| 467 | +} | |
| 468 | + | |
| 469 | +static int | |
| 470 | +__mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv, | |
| 471 | + const u8 mode_req, bool nowait) | |
| 472 | +{ | |
| 473 | + u32 con, con_reqop; | |
| 474 | + int err; | |
| 475 | + | |
| 476 | + con_reqop = FIELD_PREP(MCP251XFD_REG_CON_REQOP_MASK, mode_req); | |
| 477 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_CON, | |
| 478 | + MCP251XFD_REG_CON_REQOP_MASK, con_reqop); | |
| 479 | + if (err) | |
| 480 | + return err; | |
| 481 | + | |
| 482 | + if (mode_req == MCP251XFD_REG_CON_MODE_SLEEP || nowait) | |
| 483 | + return 0; | |
| 484 | + | |
| 485 | + err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_CON, con, | |
| 486 | + FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK, | |
| 487 | + con) == mode_req, | |
| 488 | + MCP251XFD_POLL_SLEEP_US, | |
| 489 | + MCP251XFD_POLL_TIMEOUT_US); | |
| 490 | + if (err) { | |
| 491 | + u8 mode = FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK, con); | |
| 492 | + | |
| 493 | + netdev_err(priv->ndev, | |
| 494 | + "Controller failed to enter mode %s Mode (%u) and stays in %s Mode (%u).\n", | |
| 495 | + mcp251xfd_get_mode_str(mode_req), mode_req, | |
| 496 | + mcp251xfd_get_mode_str(mode), mode); | |
| 497 | + return err; | |
| 498 | + } | |
| 499 | + | |
| 500 | + return 0; | |
| 501 | +} | |
| 502 | + | |
| 503 | +static inline int | |
| 504 | +mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv, | |
| 505 | + const u8 mode_req) | |
| 506 | +{ | |
| 507 | + return __mcp251xfd_chip_set_mode(priv, mode_req, false); | |
| 508 | +} | |
| 509 | + | |
| 510 | +static inline int | |
| 511 | +mcp251xfd_chip_set_mode_nowait(const struct mcp251xfd_priv *priv, | |
| 512 | + const u8 mode_req) | |
| 513 | +{ | |
| 514 | + return __mcp251xfd_chip_set_mode(priv, mode_req, true); | |
| 515 | +} | |
| 516 | + | |
| 517 | +static inline bool mcp251xfd_osc_invalid(u32 reg) | |
| 518 | +{ | |
| 519 | + return reg == 0x0 || reg == 0xffffffff; | |
| 520 | +} | |
| 521 | + | |
| 522 | +static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv) | |
| 523 | +{ | |
| 524 | + u32 osc, osc_reference, osc_mask; | |
| 525 | + int err; | |
| 526 | + | |
| 527 | + /* Set Power On Defaults for "Clock Output Divisor" and remove | |
| 528 | + * "Oscillator Disable" bit. | |
| 529 | + */ | |
| 530 | + osc = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, | |
| 531 | + MCP251XFD_REG_OSC_CLKODIV_10); | |
| 532 | + osc_reference = MCP251XFD_REG_OSC_OSCRDY; | |
| 533 | + osc_mask = MCP251XFD_REG_OSC_OSCRDY | MCP251XFD_REG_OSC_PLLRDY; | |
| 534 | + | |
| 535 | + /* Note: | |
| 536 | + * | |
| 537 | + * If the controller is in Sleep Mode the following write only | |
| 538 | + * removes the "Oscillator Disable" bit and powers it up. All | |
| 539 | + * other bits are unaffected. | |
| 540 | + */ | |
| 541 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_OSC, osc); | |
| 542 | + if (err) | |
| 543 | + return err; | |
| 544 | + | |
| 545 | + /* Wait for "Oscillator Ready" bit */ | |
| 546 | + err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_OSC, osc, | |
| 547 | + (osc & osc_mask) == osc_reference, | |
| 548 | + MCP251XFD_OSC_STAB_SLEEP_US, | |
| 549 | + MCP251XFD_OSC_STAB_TIMEOUT_US); | |
| 550 | + if (mcp251xfd_osc_invalid(osc)) { | |
| 551 | + netdev_err(priv->ndev, | |
| 552 | + "Failed to detect %s (osc=0x%08x).\n", | |
| 553 | + mcp251xfd_get_model_str(priv), osc); | |
| 554 | + return -ENODEV; | |
| 555 | + } else if (err == -ETIMEDOUT) { | |
| 556 | + netdev_err(priv->ndev, | |
| 557 | + "Timeout waiting for Oscillator Ready (osc=0x%08x, osc_reference=0x%08x)\n", | |
| 558 | + osc, osc_reference); | |
| 559 | + return -ETIMEDOUT; | |
| 560 | + } else if (err) { | |
| 561 | + return err; | |
| 562 | + } | |
| 563 | + | |
| 564 | + return 0; | |
| 565 | +} | |
| 566 | + | |
| 567 | +static int mcp251xfd_chip_softreset_do(const struct mcp251xfd_priv *priv) | |
| 568 | +{ | |
| 569 | + const __be16 cmd = mcp251xfd_cmd_reset(); | |
| 570 | + int err; | |
| 571 | + | |
| 572 | + /* The Set Mode and SPI Reset command only seems to works if | |
| 573 | + * the controller is not in Sleep Mode. | |
| 574 | + */ | |
| 575 | + err = mcp251xfd_chip_clock_enable(priv); | |
| 576 | + if (err) | |
| 577 | + return err; | |
| 578 | + | |
| 579 | + err = mcp251xfd_chip_set_mode(priv, MCP251XFD_REG_CON_MODE_CONFIG); | |
| 580 | + if (err) | |
| 581 | + return err; | |
| 582 | + | |
| 583 | + /* spi_write_then_read() works with non DMA-safe buffers */ | |
| 584 | + return spi_write_then_read(priv->spi, &cmd, sizeof(cmd), NULL, 0); | |
| 585 | +} | |
| 586 | + | |
| 587 | +static int mcp251xfd_chip_softreset_check(const struct mcp251xfd_priv *priv) | |
| 588 | +{ | |
| 589 | + u32 osc, osc_reference; | |
| 590 | + u8 mode; | |
| 591 | + int err; | |
| 592 | + | |
| 593 | + err = mcp251xfd_chip_get_mode(priv, &mode); | |
| 594 | + if (err) | |
| 595 | + return err; | |
| 596 | + | |
| 597 | + if (mode != MCP251XFD_REG_CON_MODE_CONFIG) { | |
| 598 | + netdev_info(priv->ndev, | |
| 599 | + "Controller not in Config Mode after reset, but in %s Mode (%u).\n", | |
| 600 | + mcp251xfd_get_mode_str(mode), mode); | |
| 601 | + return -ETIMEDOUT; | |
| 602 | + } | |
| 603 | + | |
| 604 | + osc_reference = MCP251XFD_REG_OSC_OSCRDY | | |
| 605 | + FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, | |
| 606 | + MCP251XFD_REG_OSC_CLKODIV_10); | |
| 607 | + | |
| 608 | + /* check reset defaults of OSC reg */ | |
| 609 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_OSC, &osc); | |
| 610 | + if (err) | |
| 611 | + return err; | |
| 612 | + | |
| 613 | + if (osc != osc_reference) { | |
| 614 | + netdev_info(priv->ndev, | |
| 615 | + "Controller failed to reset. osc=0x%08x, reference value=0x%08x\n", | |
| 616 | + osc, osc_reference); | |
| 617 | + return -ETIMEDOUT; | |
| 618 | + } | |
| 619 | + | |
| 620 | + return 0; | |
| 621 | +} | |
| 622 | + | |
| 623 | +static int mcp251xfd_chip_softreset(const struct mcp251xfd_priv *priv) | |
| 624 | +{ | |
| 625 | + int err, i; | |
| 626 | + | |
| 627 | + for (i = 0; i < MCP251XFD_SOFTRESET_RETRIES_MAX; i++) { | |
| 628 | + if (i) | |
| 629 | + netdev_info(priv->ndev, | |
| 630 | + "Retrying to reset Controller.\n"); | |
| 631 | + | |
| 632 | + err = mcp251xfd_chip_softreset_do(priv); | |
| 633 | + if (err == -ETIMEDOUT) | |
| 634 | + continue; | |
| 635 | + if (err) | |
| 636 | + return err; | |
| 637 | + | |
| 638 | + err = mcp251xfd_chip_softreset_check(priv); | |
| 639 | + if (err == -ETIMEDOUT) | |
| 640 | + continue; | |
| 641 | + if (err) | |
| 642 | + return err; | |
| 643 | + | |
| 644 | + return 0; | |
| 645 | + } | |
| 646 | + | |
| 647 | + if (err) | |
| 648 | + return err; | |
| 649 | + | |
| 650 | + return -ETIMEDOUT; | |
| 651 | +} | |
| 652 | + | |
| 653 | +static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv) | |
| 654 | +{ | |
| 655 | + u32 osc; | |
| 656 | + int err; | |
| 657 | + | |
| 658 | + /* Activate Low Power Mode on Oscillator Disable. This only | |
| 659 | + * works on the MCP2518FD. The MCP2517FD will go into normal | |
| 660 | + * Sleep Mode instead. | |
| 661 | + */ | |
| 662 | + osc = MCP251XFD_REG_OSC_LPMEN | | |
| 663 | + FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, | |
| 664 | + MCP251XFD_REG_OSC_CLKODIV_10); | |
| 665 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_OSC, osc); | |
| 666 | + if (err) | |
| 667 | + return err; | |
| 668 | + | |
| 669 | + /* Set Time Base Counter Prescaler to 1. | |
| 670 | + * | |
| 671 | + * This means an overflow of the 32 bit Time Base Counter | |
| 672 | + * register at 40 MHz every 107 seconds. | |
| 673 | + */ | |
| 674 | + return regmap_write(priv->map_reg, MCP251XFD_REG_TSCON, | |
| 675 | + MCP251XFD_REG_TSCON_TBCEN); | |
| 676 | +} | |
| 677 | + | |
| 678 | +static int mcp251xfd_set_bittiming(const struct mcp251xfd_priv *priv) | |
| 679 | +{ | |
| 680 | + const struct can_bittiming *bt = &priv->can.bittiming; | |
| 681 | + const struct can_bittiming *dbt = &priv->can.data_bittiming; | |
| 682 | + u32 val = 0; | |
| 683 | + s8 tdco; | |
| 684 | + int err; | |
| 685 | + | |
| 686 | + /* CAN Control Register | |
| 687 | + * | |
| 688 | + * - no transmit bandwidth sharing | |
| 689 | + * - config mode | |
| 690 | + * - disable transmit queue | |
| 691 | + * - store in transmit FIFO event | |
| 692 | + * - transition to restricted operation mode on system error | |
| 693 | + * - ESI is transmitted recessive when ESI of message is high or | |
| 694 | + * CAN controller error passive | |
| 695 | + * - restricted retransmission attempts, | |
| 696 | + * use TQXCON_TXAT and FIFOCON_TXAT | |
| 697 | + * - wake-up filter bits T11FILTER | |
| 698 | + * - use CAN bus line filter for wakeup | |
| 699 | + * - protocol exception is treated as a form error | |
| 700 | + * - Do not compare data bytes | |
| 701 | + */ | |
| 702 | + val = FIELD_PREP(MCP251XFD_REG_CON_REQOP_MASK, | |
| 703 | + MCP251XFD_REG_CON_MODE_CONFIG) | | |
| 704 | + MCP251XFD_REG_CON_STEF | | |
| 705 | + MCP251XFD_REG_CON_ESIGM | | |
| 706 | + MCP251XFD_REG_CON_RTXAT | | |
| 707 | + FIELD_PREP(MCP251XFD_REG_CON_WFT_MASK, | |
| 708 | + MCP251XFD_REG_CON_WFT_T11FILTER) | | |
| 709 | + MCP251XFD_REG_CON_WAKFIL | | |
| 710 | + MCP251XFD_REG_CON_PXEDIS; | |
| 711 | + | |
| 712 | + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) | |
| 713 | + val |= MCP251XFD_REG_CON_ISOCRCEN; | |
| 714 | + | |
| 715 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_CON, val); | |
| 716 | + if (err) | |
| 717 | + return err; | |
| 718 | + | |
| 719 | + /* Nominal Bit Time */ | |
| 720 | + val = FIELD_PREP(MCP251XFD_REG_NBTCFG_BRP_MASK, bt->brp - 1) | | |
| 721 | + FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG1_MASK, | |
| 722 | + bt->prop_seg + bt->phase_seg1 - 1) | | |
| 723 | + FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG2_MASK, | |
| 724 | + bt->phase_seg2 - 1) | | |
| 725 | + FIELD_PREP(MCP251XFD_REG_NBTCFG_SJW_MASK, bt->sjw - 1); | |
| 726 | + | |
| 727 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_NBTCFG, val); | |
| 728 | + if (err) | |
| 729 | + return err; | |
| 730 | + | |
| 731 | + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD)) | |
| 732 | + return 0; | |
| 733 | + | |
| 734 | + /* Data Bit Time */ | |
| 735 | + val = FIELD_PREP(MCP251XFD_REG_DBTCFG_BRP_MASK, dbt->brp - 1) | | |
| 736 | + FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG1_MASK, | |
| 737 | + dbt->prop_seg + dbt->phase_seg1 - 1) | | |
| 738 | + FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG2_MASK, | |
| 739 | + dbt->phase_seg2 - 1) | | |
| 740 | + FIELD_PREP(MCP251XFD_REG_DBTCFG_SJW_MASK, dbt->sjw - 1); | |
| 741 | + | |
| 742 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_DBTCFG, val); | |
| 743 | + if (err) | |
| 744 | + return err; | |
| 745 | + | |
| 746 | + /* Transmitter Delay Compensation */ | |
| 747 | + tdco = clamp_t(int, dbt->brp * (dbt->prop_seg + dbt->phase_seg1), | |
| 748 | + -64, 63); | |
| 749 | + val = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, | |
| 750 | + MCP251XFD_REG_TDC_TDCMOD_AUTO) | | |
| 751 | + FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdco); | |
| 752 | + | |
| 753 | + return regmap_write(priv->map_reg, MCP251XFD_REG_TDC, val); | |
| 754 | +} | |
| 755 | + | |
| 756 | +static int mcp251xfd_chip_rx_int_enable(const struct mcp251xfd_priv *priv) | |
| 757 | +{ | |
| 758 | + u32 val; | |
| 759 | + | |
| 760 | + if (!priv->rx_int) | |
| 761 | + return 0; | |
| 762 | + | |
| 763 | + /* Configure GPIOs: | |
| 764 | + * - PIN0: GPIO Input | |
| 765 | + * - PIN1: GPIO Input/RX Interrupt | |
| 766 | + * | |
| 767 | + * PIN1 must be Input, otherwise there is a glitch on the | |
| 768 | + * rx-INT line. It happens between setting the PIN as output | |
| 769 | + * (in the first byte of the SPI transfer) and configuring the | |
| 770 | + * PIN as interrupt (in the last byte of the SPI transfer). | |
| 771 | + */ | |
| 772 | + val = MCP251XFD_REG_IOCON_PM0 | MCP251XFD_REG_IOCON_TRIS1 | | |
| 773 | + MCP251XFD_REG_IOCON_TRIS0; | |
| 774 | + return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val); | |
| 775 | +} | |
| 776 | + | |
| 777 | +static int mcp251xfd_chip_rx_int_disable(const struct mcp251xfd_priv *priv) | |
| 778 | +{ | |
| 779 | + u32 val; | |
| 780 | + | |
| 781 | + if (!priv->rx_int) | |
| 782 | + return 0; | |
| 783 | + | |
| 784 | + /* Configure GPIOs: | |
| 785 | + * - PIN0: GPIO Input | |
| 786 | + * - PIN1: GPIO Input | |
| 787 | + */ | |
| 788 | + val = MCP251XFD_REG_IOCON_PM1 | MCP251XFD_REG_IOCON_PM0 | | |
| 789 | + MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_TRIS0; | |
| 790 | + return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val); | |
| 791 | +} | |
| 792 | + | |
| 793 | +static int | |
| 794 | +mcp251xfd_chip_rx_fifo_init_one(const struct mcp251xfd_priv *priv, | |
| 795 | + const struct mcp251xfd_rx_ring *ring) | |
| 796 | +{ | |
| 797 | + u32 fifo_con; | |
| 798 | + | |
| 799 | + /* Enable RXOVIE on _all_ RX FIFOs, not just the last one. | |
| 800 | + * | |
| 801 | + * FIFOs hit by a RX MAB overflow and RXOVIE enabled will | |
| 802 | + * generate a RXOVIF, use this to properly detect RX MAB | |
| 803 | + * overflows. | |
| 804 | + */ | |
| 805 | + fifo_con = FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, | |
| 806 | + ring->obj_num - 1) | | |
| 807 | + MCP251XFD_REG_FIFOCON_RXTSEN | | |
| 808 | + MCP251XFD_REG_FIFOCON_RXOVIE | | |
| 809 | + MCP251XFD_REG_FIFOCON_TFNRFNIE; | |
| 810 | + | |
| 811 | + if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD)) | |
| 812 | + fifo_con |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, | |
| 813 | + MCP251XFD_REG_FIFOCON_PLSIZE_64); | |
| 814 | + else | |
| 815 | + fifo_con |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, | |
| 816 | + MCP251XFD_REG_FIFOCON_PLSIZE_8); | |
| 817 | + | |
| 818 | + return regmap_write(priv->map_reg, | |
| 819 | + MCP251XFD_REG_FIFOCON(ring->fifo_nr), fifo_con); | |
| 820 | +} | |
| 821 | + | |
| 822 | +static int | |
| 823 | +mcp251xfd_chip_rx_filter_init_one(const struct mcp251xfd_priv *priv, | |
| 824 | + const struct mcp251xfd_rx_ring *ring) | |
| 825 | +{ | |
| 826 | + u32 fltcon; | |
| 827 | + | |
| 828 | + fltcon = MCP251XFD_REG_FLTCON_FLTEN(ring->nr) | | |
| 829 | + MCP251XFD_REG_FLTCON_FBP(ring->nr, ring->fifo_nr); | |
| 830 | + | |
| 831 | + return regmap_update_bits(priv->map_reg, | |
| 832 | + MCP251XFD_REG_FLTCON(ring->nr >> 2), | |
| 833 | + MCP251XFD_REG_FLTCON_FLT_MASK(ring->nr), | |
| 834 | + fltcon); | |
| 835 | +} | |
| 836 | + | |
| 837 | +static int mcp251xfd_chip_fifo_init(const struct mcp251xfd_priv *priv) | |
| 838 | +{ | |
| 839 | + const struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 840 | + const struct mcp251xfd_rx_ring *rx_ring; | |
| 841 | + u32 val; | |
| 842 | + int err, n; | |
| 843 | + | |
| 844 | + /* TEF */ | |
| 845 | + val = FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK, | |
| 846 | + tx_ring->obj_num - 1) | | |
| 847 | + MCP251XFD_REG_TEFCON_TEFTSEN | | |
| 848 | + MCP251XFD_REG_TEFCON_TEFOVIE | | |
| 849 | + MCP251XFD_REG_TEFCON_TEFNEIE; | |
| 850 | + | |
| 851 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_TEFCON, val); | |
| 852 | + if (err) | |
| 853 | + return err; | |
| 854 | + | |
| 855 | + /* FIFO 1 - TX */ | |
| 856 | + val = FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, | |
| 857 | + tx_ring->obj_num - 1) | | |
| 858 | + MCP251XFD_REG_FIFOCON_TXEN | | |
| 859 | + MCP251XFD_REG_FIFOCON_TXATIE; | |
| 860 | + | |
| 861 | + if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD)) | |
| 862 | + val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, | |
| 863 | + MCP251XFD_REG_FIFOCON_PLSIZE_64); | |
| 864 | + else | |
| 865 | + val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, | |
| 866 | + MCP251XFD_REG_FIFOCON_PLSIZE_8); | |
| 867 | + | |
| 868 | + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) | |
| 869 | + val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_TXAT_MASK, | |
| 870 | + MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT); | |
| 871 | + else | |
| 872 | + val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_TXAT_MASK, | |
| 873 | + MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED); | |
| 874 | + | |
| 875 | + err = regmap_write(priv->map_reg, | |
| 876 | + MCP251XFD_REG_FIFOCON(MCP251XFD_TX_FIFO), | |
| 877 | + val); | |
| 878 | + if (err) | |
| 879 | + return err; | |
| 880 | + | |
| 881 | + /* RX FIFOs */ | |
| 882 | + mcp251xfd_for_each_rx_ring(priv, rx_ring, n) { | |
| 883 | + err = mcp251xfd_chip_rx_fifo_init_one(priv, rx_ring); | |
| 884 | + if (err) | |
| 885 | + return err; | |
| 886 | + | |
| 887 | + err = mcp251xfd_chip_rx_filter_init_one(priv, rx_ring); | |
| 888 | + if (err) | |
| 889 | + return err; | |
| 890 | + } | |
| 891 | + | |
| 892 | + return 0; | |
| 893 | +} | |
| 894 | + | |
| 895 | +static int mcp251xfd_chip_ecc_init(struct mcp251xfd_priv *priv) | |
| 896 | +{ | |
| 897 | + struct mcp251xfd_ecc *ecc = &priv->ecc; | |
| 898 | + void *ram; | |
| 899 | + u32 val = 0; | |
| 900 | + int err; | |
| 901 | + | |
| 902 | + ecc->ecc_stat = 0; | |
| 903 | + | |
| 904 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_ECC) | |
| 905 | + val = MCP251XFD_REG_ECCCON_ECCEN; | |
| 906 | + | |
| 907 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_ECCCON, | |
| 908 | + MCP251XFD_REG_ECCCON_ECCEN, val); | |
| 909 | + if (err) | |
| 910 | + return err; | |
| 911 | + | |
| 912 | + ram = kzalloc(MCP251XFD_RAM_SIZE, GFP_KERNEL); | |
| 913 | + if (!ram) | |
| 914 | + return -ENOMEM; | |
| 915 | + | |
| 916 | + err = regmap_raw_write(priv->map_reg, MCP251XFD_RAM_START, ram, | |
| 917 | + MCP251XFD_RAM_SIZE); | |
| 918 | + kfree(ram); | |
| 919 | + | |
| 920 | + return err; | |
| 921 | +} | |
| 922 | + | |
| 923 | +static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv) | |
| 924 | +{ | |
| 925 | + struct mcp251xfd_ecc *ecc = &priv->ecc; | |
| 926 | + | |
| 927 | + ecc->ecc_stat = 0; | |
| 928 | +} | |
| 929 | + | |
| 930 | +static u8 mcp251xfd_get_normal_mode(const struct mcp251xfd_priv *priv) | |
| 931 | +{ | |
| 932 | + u8 mode; | |
| 933 | + | |
| 934 | + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) | |
| 935 | + mode = MCP251XFD_REG_CON_MODE_LISTENONLY; | |
| 936 | + else if (priv->can.ctrlmode & CAN_CTRLMODE_FD) | |
| 937 | + mode = MCP251XFD_REG_CON_MODE_MIXED; | |
| 938 | + else | |
| 939 | + mode = MCP251XFD_REG_CON_MODE_CAN2_0; | |
| 940 | + | |
| 941 | + return mode; | |
| 942 | +} | |
| 943 | + | |
| 944 | +static int | |
| 945 | +__mcp251xfd_chip_set_normal_mode(const struct mcp251xfd_priv *priv, | |
| 946 | + bool nowait) | |
| 947 | +{ | |
| 948 | + u8 mode; | |
| 949 | + | |
| 950 | + mode = mcp251xfd_get_normal_mode(priv); | |
| 951 | + | |
| 952 | + return __mcp251xfd_chip_set_mode(priv, mode, nowait); | |
| 953 | +} | |
| 954 | + | |
| 955 | +static inline int | |
| 956 | +mcp251xfd_chip_set_normal_mode(const struct mcp251xfd_priv *priv) | |
| 957 | +{ | |
| 958 | + return __mcp251xfd_chip_set_normal_mode(priv, false); | |
| 959 | +} | |
| 960 | + | |
| 961 | +static inline int | |
| 962 | +mcp251xfd_chip_set_normal_mode_nowait(const struct mcp251xfd_priv *priv) | |
| 963 | +{ | |
| 964 | + return __mcp251xfd_chip_set_normal_mode(priv, true); | |
| 965 | +} | |
| 966 | + | |
| 967 | +static int mcp251xfd_chip_interrupts_enable(const struct mcp251xfd_priv *priv) | |
| 968 | +{ | |
| 969 | + u32 val; | |
| 970 | + int err; | |
| 971 | + | |
| 972 | + val = MCP251XFD_REG_CRC_FERRIE | MCP251XFD_REG_CRC_CRCERRIE; | |
| 973 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_CRC, val); | |
| 974 | + if (err) | |
| 975 | + return err; | |
| 976 | + | |
| 977 | + val = MCP251XFD_REG_ECCCON_DEDIE | MCP251XFD_REG_ECCCON_SECIE; | |
| 978 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_ECCCON, val, val); | |
| 979 | + if (err) | |
| 980 | + return err; | |
| 981 | + | |
| 982 | + val = MCP251XFD_REG_INT_CERRIE | | |
| 983 | + MCP251XFD_REG_INT_SERRIE | | |
| 984 | + MCP251XFD_REG_INT_RXOVIE | | |
| 985 | + MCP251XFD_REG_INT_TXATIE | | |
| 986 | + MCP251XFD_REG_INT_SPICRCIE | | |
| 987 | + MCP251XFD_REG_INT_ECCIE | | |
| 988 | + MCP251XFD_REG_INT_TEFIE | | |
| 989 | + MCP251XFD_REG_INT_MODIE | | |
| 990 | + MCP251XFD_REG_INT_RXIE; | |
| 991 | + | |
| 992 | + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) | |
| 993 | + val |= MCP251XFD_REG_INT_IVMIE; | |
| 994 | + | |
| 995 | + return regmap_write(priv->map_reg, MCP251XFD_REG_INT, val); | |
| 996 | +} | |
| 997 | + | |
| 998 | +static int mcp251xfd_chip_interrupts_disable(const struct mcp251xfd_priv *priv) | |
| 999 | +{ | |
| 1000 | + int err; | |
| 1001 | + u32 mask; | |
| 1002 | + | |
| 1003 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_INT, 0); | |
| 1004 | + if (err) | |
| 1005 | + return err; | |
| 1006 | + | |
| 1007 | + mask = MCP251XFD_REG_ECCCON_DEDIE | MCP251XFD_REG_ECCCON_SECIE; | |
| 1008 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_ECCCON, | |
| 1009 | + mask, 0x0); | |
| 1010 | + if (err) | |
| 1011 | + return err; | |
| 1012 | + | |
| 1013 | + return regmap_write(priv->map_reg, MCP251XFD_REG_CRC, 0); | |
| 1014 | +} | |
| 1015 | + | |
| 1016 | +static int mcp251xfd_chip_stop(struct mcp251xfd_priv *priv, | |
| 1017 | + const enum can_state state) | |
| 1018 | +{ | |
| 1019 | + priv->can.state = state; | |
| 1020 | + | |
| 1021 | + mcp251xfd_chip_interrupts_disable(priv); | |
| 1022 | + mcp251xfd_chip_rx_int_disable(priv); | |
| 1023 | + return mcp251xfd_chip_set_mode(priv, MCP251XFD_REG_CON_MODE_SLEEP); | |
| 1024 | +} | |
| 1025 | + | |
| 1026 | +static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv) | |
| 1027 | +{ | |
| 1028 | + int err; | |
| 1029 | + | |
| 1030 | + err = mcp251xfd_chip_softreset(priv); | |
| 1031 | + if (err) | |
| 1032 | + goto out_chip_stop; | |
| 1033 | + | |
| 1034 | + err = mcp251xfd_chip_clock_init(priv); | |
| 1035 | + if (err) | |
| 1036 | + goto out_chip_stop; | |
| 1037 | + | |
| 1038 | + err = mcp251xfd_set_bittiming(priv); | |
| 1039 | + if (err) | |
| 1040 | + goto out_chip_stop; | |
| 1041 | + | |
| 1042 | + err = mcp251xfd_chip_rx_int_enable(priv); | |
| 1043 | + if (err) | |
| 1044 | + return err; | |
| 1045 | + | |
| 1046 | + err = mcp251xfd_chip_ecc_init(priv); | |
| 1047 | + if (err) | |
| 1048 | + goto out_chip_stop; | |
| 1049 | + | |
| 1050 | + mcp251xfd_ring_init(priv); | |
| 1051 | + | |
| 1052 | + err = mcp251xfd_chip_fifo_init(priv); | |
| 1053 | + if (err) | |
| 1054 | + goto out_chip_stop; | |
| 1055 | + | |
| 1056 | + priv->can.state = CAN_STATE_ERROR_ACTIVE; | |
| 1057 | + | |
| 1058 | + err = mcp251xfd_chip_set_normal_mode(priv); | |
| 1059 | + if (err) | |
| 1060 | + goto out_chip_stop; | |
| 1061 | + | |
| 1062 | + return 0; | |
| 1063 | + | |
| 1064 | + out_chip_stop: | |
| 1065 | + mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); | |
| 1066 | + | |
| 1067 | + return err; | |
| 1068 | +} | |
| 1069 | + | |
| 1070 | +static int mcp251xfd_set_mode(struct net_device *ndev, enum can_mode mode) | |
| 1071 | +{ | |
| 1072 | + struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
| 1073 | + int err; | |
| 1074 | + | |
| 1075 | + switch (mode) { | |
| 1076 | + case CAN_MODE_START: | |
| 1077 | + err = mcp251xfd_chip_start(priv); | |
| 1078 | + if (err) | |
| 1079 | + return err; | |
| 1080 | + | |
| 1081 | + err = mcp251xfd_chip_interrupts_enable(priv); | |
| 1082 | + if (err) { | |
| 1083 | + mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); | |
| 1084 | + return err; | |
| 1085 | + } | |
| 1086 | + | |
| 1087 | + netif_wake_queue(ndev); | |
| 1088 | + break; | |
| 1089 | + | |
| 1090 | + default: | |
| 1091 | + return -EOPNOTSUPP; | |
| 1092 | + } | |
| 1093 | + | |
| 1094 | + return 0; | |
| 1095 | +} | |
| 1096 | + | |
| 1097 | +static int __mcp251xfd_get_berr_counter(const struct net_device *ndev, | |
| 1098 | + struct can_berr_counter *bec) | |
| 1099 | +{ | |
| 1100 | + const struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
| 1101 | + u32 trec; | |
| 1102 | + int err; | |
| 1103 | + | |
| 1104 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_TREC, &trec); | |
| 1105 | + if (err) | |
| 1106 | + return err; | |
| 1107 | + | |
| 1108 | + if (trec & MCP251XFD_REG_TREC_TXBO) | |
| 1109 | + bec->txerr = 256; | |
| 1110 | + else | |
| 1111 | + bec->txerr = FIELD_GET(MCP251XFD_REG_TREC_TEC_MASK, trec); | |
| 1112 | + bec->rxerr = FIELD_GET(MCP251XFD_REG_TREC_REC_MASK, trec); | |
| 1113 | + | |
| 1114 | + return 0; | |
| 1115 | +} | |
| 1116 | + | |
| 1117 | +static int mcp251xfd_get_berr_counter(const struct net_device *ndev, | |
| 1118 | + struct can_berr_counter *bec) | |
| 1119 | +{ | |
| 1120 | + const struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
| 1121 | + | |
| 1122 | + /* Avoid waking up the controller if the interface is down */ | |
| 1123 | + if (!(ndev->flags & IFF_UP)) | |
| 1124 | + return 0; | |
| 1125 | + | |
| 1126 | + /* The controller is powered down during Bus Off, use saved | |
| 1127 | + * bec values. | |
| 1128 | + */ | |
| 1129 | + if (priv->can.state == CAN_STATE_BUS_OFF) { | |
| 1130 | + *bec = priv->bec; | |
| 1131 | + return 0; | |
| 1132 | + } | |
| 1133 | + | |
| 1134 | + return __mcp251xfd_get_berr_counter(ndev, bec); | |
| 1135 | +} | |
| 1136 | + | |
| 1137 | +static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv) | |
| 1138 | +{ | |
| 1139 | + u8 tef_tail_chip, tef_tail; | |
| 1140 | + int err; | |
| 1141 | + | |
| 1142 | + if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY)) | |
| 1143 | + return 0; | |
| 1144 | + | |
| 1145 | + err = mcp251xfd_tef_tail_get_from_chip(priv, &tef_tail_chip); | |
| 1146 | + if (err) | |
| 1147 | + return err; | |
| 1148 | + | |
| 1149 | + tef_tail = mcp251xfd_get_tef_tail(priv); | |
| 1150 | + if (tef_tail_chip != tef_tail) { | |
| 1151 | + netdev_err(priv->ndev, | |
| 1152 | + "TEF tail of chip (0x%02x) and ours (0x%08x) inconsistent.\n", | |
| 1153 | + tef_tail_chip, tef_tail); | |
| 1154 | + return -EILSEQ; | |
| 1155 | + } | |
| 1156 | + | |
| 1157 | + return 0; | |
| 1158 | +} | |
| 1159 | + | |
| 1160 | +static int | |
| 1161 | +mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv, | |
| 1162 | + const struct mcp251xfd_rx_ring *ring) | |
| 1163 | +{ | |
| 1164 | + u8 rx_tail_chip, rx_tail; | |
| 1165 | + int err; | |
| 1166 | + | |
| 1167 | + if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY)) | |
| 1168 | + return 0; | |
| 1169 | + | |
| 1170 | + err = mcp251xfd_rx_tail_get_from_chip(priv, ring, &rx_tail_chip); | |
| 1171 | + if (err) | |
| 1172 | + return err; | |
| 1173 | + | |
| 1174 | + rx_tail = mcp251xfd_get_rx_tail(ring); | |
| 1175 | + if (rx_tail_chip != rx_tail) { | |
| 1176 | + netdev_err(priv->ndev, | |
| 1177 | + "RX tail of chip (%d) and ours (%d) inconsistent.\n", | |
| 1178 | + rx_tail_chip, rx_tail); | |
| 1179 | + return -EILSEQ; | |
| 1180 | + } | |
| 1181 | + | |
| 1182 | + return 0; | |
| 1183 | +} | |
| 1184 | + | |
| 1185 | +static int | |
| 1186 | +mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq) | |
| 1187 | +{ | |
| 1188 | + const struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 1189 | + u32 tef_sta; | |
| 1190 | + int err; | |
| 1191 | + | |
| 1192 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFSTA, &tef_sta); | |
| 1193 | + if (err) | |
| 1194 | + return err; | |
| 1195 | + | |
| 1196 | + if (tef_sta & MCP251XFD_REG_TEFSTA_TEFOVIF) { | |
| 1197 | + netdev_err(priv->ndev, | |
| 1198 | + "Transmit Event FIFO buffer overflow.\n"); | |
| 1199 | + return -ENOBUFS; | |
| 1200 | + } | |
| 1201 | + | |
| 1202 | + netdev_info(priv->ndev, | |
| 1203 | + "Transmit Event FIFO buffer %s. (seq=0x%08x, tef_tail=0x%08x, tef_head=0x%08x, tx_head=0x%08x)\n", | |
| 1204 | + tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ? | |
| 1205 | + "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ? | |
| 1206 | + "not empty" : "empty", | |
| 1207 | + seq, priv->tef.tail, priv->tef.head, tx_ring->head); | |
| 1208 | + | |
| 1209 | + /* The Sequence Number in the TEF doesn't match our tef_tail. */ | |
| 1210 | + return -EAGAIN; | |
| 1211 | +} | |
| 1212 | + | |
| 1213 | +static int | |
| 1214 | +mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, | |
| 1215 | + const struct mcp251xfd_hw_tef_obj *hw_tef_obj) | |
| 1216 | +{ | |
| 1217 | + struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 1218 | + struct net_device_stats *stats = &priv->ndev->stats; | |
| 1219 | + u32 seq, seq_masked, tef_tail_masked; | |
| 1220 | + int err; | |
| 1221 | + | |
| 1222 | + seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, | |
| 1223 | + hw_tef_obj->flags); | |
| 1224 | + | |
| 1225 | + /* Use the MCP2517FD mask on the MCP2518FD, too. We only | |
| 1226 | + * compare 7 bits, this should be enough to detect | |
| 1227 | + * net-yet-completed, i.e. old TEF objects. | |
| 1228 | + */ | |
| 1229 | + seq_masked = seq & | |
| 1230 | + field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK); | |
| 1231 | + tef_tail_masked = priv->tef.tail & | |
| 1232 | + field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK); | |
| 1233 | + if (seq_masked != tef_tail_masked) | |
| 1234 | + return mcp251xfd_handle_tefif_recover(priv, seq); | |
| 1235 | + | |
| 1236 | + stats->tx_bytes += | |
| 1237 | + can_rx_offload_get_echo_skb(&priv->offload, | |
| 1238 | + mcp251xfd_get_tef_tail(priv), | |
| 1239 | + hw_tef_obj->ts); | |
| 1240 | + stats->tx_packets++; | |
| 1241 | + | |
| 1242 | + /* finally increment the TEF pointer */ | |
| 1243 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_TEFCON, | |
| 1244 | + GENMASK(15, 8), | |
| 1245 | + MCP251XFD_REG_TEFCON_UINC); | |
| 1246 | + if (err) | |
| 1247 | + return err; | |
| 1248 | + | |
| 1249 | + priv->tef.tail++; | |
| 1250 | + tx_ring->tail++; | |
| 1251 | + | |
| 1252 | + return mcp251xfd_check_tef_tail(priv); | |
| 1253 | +} | |
| 1254 | + | |
| 1255 | +static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv) | |
| 1256 | +{ | |
| 1257 | + const struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 1258 | + unsigned int new_head; | |
| 1259 | + u8 chip_tx_tail; | |
| 1260 | + int err; | |
| 1261 | + | |
| 1262 | + err = mcp251xfd_tx_tail_get_from_chip(priv, &chip_tx_tail); | |
| 1263 | + if (err) | |
| 1264 | + return err; | |
| 1265 | + | |
| 1266 | + /* chip_tx_tail, is the next TX-Object send by the HW. | |
| 1267 | + * The new TEF head must be >= the old head, ... | |
| 1268 | + */ | |
| 1269 | + new_head = round_down(priv->tef.head, tx_ring->obj_num) + chip_tx_tail; | |
| 1270 | + if (new_head <= priv->tef.head) | |
| 1271 | + new_head += tx_ring->obj_num; | |
| 1272 | + | |
| 1273 | + /* ... but it cannot exceed the TX head. */ | |
| 1274 | + priv->tef.head = min(new_head, tx_ring->head); | |
| 1275 | + | |
| 1276 | + return mcp251xfd_check_tef_tail(priv); | |
| 1277 | +} | |
| 1278 | + | |
| 1279 | +static inline int | |
| 1280 | +mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv, | |
| 1281 | + struct mcp251xfd_hw_tef_obj *hw_tef_obj, | |
| 1282 | + const u8 offset, const u8 len) | |
| 1283 | +{ | |
| 1284 | + const struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 1285 | + | |
| 1286 | + if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && | |
| 1287 | + (offset > tx_ring->obj_num || | |
| 1288 | + len > tx_ring->obj_num || | |
| 1289 | + offset + len > tx_ring->obj_num)) { | |
| 1290 | + netdev_err(priv->ndev, | |
| 1291 | + "Trying to read to many TEF objects (max=%d, offset=%d, len=%d).\n", | |
| 1292 | + tx_ring->obj_num, offset, len); | |
| 1293 | + return -ERANGE; | |
| 1294 | + } | |
| 1295 | + | |
| 1296 | + return regmap_bulk_read(priv->map_rx, | |
| 1297 | + mcp251xfd_get_tef_obj_addr(offset), | |
| 1298 | + hw_tef_obj, | |
| 1299 | + sizeof(*hw_tef_obj) / sizeof(u32) * len); | |
| 1300 | +} | |
| 1301 | + | |
| 1302 | +static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) | |
| 1303 | +{ | |
| 1304 | + struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX]; | |
| 1305 | + u8 tef_tail, len, l; | |
| 1306 | + int err, i; | |
| 1307 | + | |
| 1308 | + err = mcp251xfd_tef_ring_update(priv); | |
| 1309 | + if (err) | |
| 1310 | + return err; | |
| 1311 | + | |
| 1312 | + tef_tail = mcp251xfd_get_tef_tail(priv); | |
| 1313 | + len = mcp251xfd_get_tef_len(priv); | |
| 1314 | + l = mcp251xfd_get_tef_linear_len(priv); | |
| 1315 | + err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l); | |
| 1316 | + if (err) | |
| 1317 | + return err; | |
| 1318 | + | |
| 1319 | + if (l < len) { | |
| 1320 | + err = mcp251xfd_tef_obj_read(priv, &hw_tef_obj[l], 0, len - l); | |
| 1321 | + if (err) | |
| 1322 | + return err; | |
| 1323 | + } | |
| 1324 | + | |
| 1325 | + for (i = 0; i < len; i++) { | |
| 1326 | + err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i]); | |
| 1327 | + /* -EAGAIN means the Sequence Number in the TEF | |
| 1328 | + * doesn't match our tef_tail. This can happen if we | |
| 1329 | + * read the TEF objects too early. Leave loop let the | |
| 1330 | + * interrupt handler call us again. | |
| 1331 | + */ | |
| 1332 | + if (err == -EAGAIN) | |
| 1333 | + goto out_netif_wake_queue; | |
| 1334 | + if (err) | |
| 1335 | + return err; | |
| 1336 | + } | |
| 1337 | + | |
| 1338 | + out_netif_wake_queue: | |
| 1339 | + mcp251xfd_ecc_tefif_successful(priv); | |
| 1340 | + | |
| 1341 | + if (mcp251xfd_get_tx_free(priv->tx)) { | |
| 1342 | + /* Make sure that anybody stopping the queue after | |
| 1343 | + * this sees the new tx_ring->tail. | |
| 1344 | + */ | |
| 1345 | + smp_mb(); | |
| 1346 | + netif_wake_queue(priv->ndev); | |
| 1347 | + } | |
| 1348 | + | |
| 1349 | + return 0; | |
| 1350 | +} | |
| 1351 | + | |
| 1352 | +static int | |
| 1353 | +mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv, | |
| 1354 | + struct mcp251xfd_rx_ring *ring) | |
| 1355 | +{ | |
| 1356 | + u32 new_head; | |
| 1357 | + u8 chip_rx_head; | |
| 1358 | + int err; | |
| 1359 | + | |
| 1360 | + err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head); | |
| 1361 | + if (err) | |
| 1362 | + return err; | |
| 1363 | + | |
| 1364 | + /* chip_rx_head, is the next RX-Object filled by the HW. | |
| 1365 | + * The new RX head must be >= the old head. | |
| 1366 | + */ | |
| 1367 | + new_head = round_down(ring->head, ring->obj_num) + chip_rx_head; | |
| 1368 | + if (new_head <= ring->head) | |
| 1369 | + new_head += ring->obj_num; | |
| 1370 | + | |
| 1371 | + ring->head = new_head; | |
| 1372 | + | |
| 1373 | + return mcp251xfd_check_rx_tail(priv, ring); | |
| 1374 | +} | |
| 1375 | + | |
| 1376 | +static void | |
| 1377 | +mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv, | |
| 1378 | + const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj, | |
| 1379 | + struct sk_buff *skb) | |
| 1380 | +{ | |
| 1381 | + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; | |
| 1382 | + | |
| 1383 | + if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_IDE) { | |
| 1384 | + u32 sid, eid; | |
| 1385 | + | |
| 1386 | + eid = FIELD_GET(MCP251XFD_OBJ_ID_EID_MASK, hw_rx_obj->id); | |
| 1387 | + sid = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, hw_rx_obj->id); | |
| 1388 | + | |
| 1389 | + cfd->can_id = CAN_EFF_FLAG | | |
| 1390 | + FIELD_PREP(MCP251XFD_REG_FRAME_EFF_EID_MASK, eid) | | |
| 1391 | + FIELD_PREP(MCP251XFD_REG_FRAME_EFF_SID_MASK, sid); | |
| 1392 | + } else { | |
| 1393 | + cfd->can_id = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, | |
| 1394 | + hw_rx_obj->id); | |
| 1395 | + } | |
| 1396 | + | |
| 1397 | + /* CANFD */ | |
| 1398 | + if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) { | |
| 1399 | + u8 dlc; | |
| 1400 | + | |
| 1401 | + if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_ESI) | |
| 1402 | + cfd->flags |= CANFD_ESI; | |
| 1403 | + | |
| 1404 | + if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_BRS) | |
| 1405 | + cfd->flags |= CANFD_BRS; | |
| 1406 | + | |
| 1407 | + dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags); | |
| 1408 | + cfd->len = can_dlc2len(get_canfd_dlc(dlc)); | |
| 1409 | + } else { | |
| 1410 | + if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR) | |
| 1411 | + cfd->can_id |= CAN_RTR_FLAG; | |
| 1412 | + | |
| 1413 | + cfd->len = get_can_dlc(FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, | |
| 1414 | + hw_rx_obj->flags)); | |
| 1415 | + } | |
| 1416 | + | |
| 1417 | + memcpy(cfd->data, hw_rx_obj->data, cfd->len); | |
| 1418 | +} | |
| 1419 | + | |
| 1420 | +static int | |
| 1421 | +mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv, | |
| 1422 | + struct mcp251xfd_rx_ring *ring, | |
| 1423 | + const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj) | |
| 1424 | +{ | |
| 1425 | + struct net_device_stats *stats = &priv->ndev->stats; | |
| 1426 | + struct sk_buff *skb; | |
| 1427 | + struct canfd_frame *cfd; | |
| 1428 | + int err; | |
| 1429 | + | |
| 1430 | + if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) | |
| 1431 | + skb = alloc_canfd_skb(priv->ndev, &cfd); | |
| 1432 | + else | |
| 1433 | + skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd); | |
| 1434 | + | |
| 1435 | + if (!cfd) { | |
| 1436 | + stats->rx_dropped++; | |
| 1437 | + return 0; | |
| 1438 | + } | |
| 1439 | + | |
| 1440 | + mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb); | |
| 1441 | + err = can_rx_offload_queue_sorted(&priv->offload, skb, hw_rx_obj->ts); | |
| 1442 | + if (err) | |
| 1443 | + stats->rx_fifo_errors++; | |
| 1444 | + | |
| 1445 | + ring->tail++; | |
| 1446 | + | |
| 1447 | + /* finally increment the RX pointer */ | |
| 1448 | + return regmap_update_bits(priv->map_reg, | |
| 1449 | + MCP251XFD_REG_FIFOCON(ring->fifo_nr), | |
| 1450 | + GENMASK(15, 8), | |
| 1451 | + MCP251XFD_REG_FIFOCON_UINC); | |
| 1452 | +} | |
| 1453 | + | |
| 1454 | +static inline int | |
| 1455 | +mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv, | |
| 1456 | + const struct mcp251xfd_rx_ring *ring, | |
| 1457 | + struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj, | |
| 1458 | + const u8 offset, const u8 len) | |
| 1459 | +{ | |
| 1460 | + int err; | |
| 1461 | + | |
| 1462 | + err = regmap_bulk_read(priv->map_rx, | |
| 1463 | + mcp251xfd_get_rx_obj_addr(ring, offset), | |
| 1464 | + hw_rx_obj, | |
| 1465 | + len * ring->obj_size / sizeof(u32)); | |
| 1466 | + | |
| 1467 | + return err; | |
| 1468 | +} | |
| 1469 | + | |
| 1470 | +static int | |
| 1471 | +mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, | |
| 1472 | + struct mcp251xfd_rx_ring *ring) | |
| 1473 | +{ | |
| 1474 | + struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj; | |
| 1475 | + u8 rx_tail, len; | |
| 1476 | + int err, i; | |
| 1477 | + | |
| 1478 | + err = mcp251xfd_rx_ring_update(priv, ring); | |
| 1479 | + if (err) | |
| 1480 | + return err; | |
| 1481 | + | |
| 1482 | + while ((len = mcp251xfd_get_rx_linear_len(ring))) { | |
| 1483 | + rx_tail = mcp251xfd_get_rx_tail(ring); | |
| 1484 | + | |
| 1485 | + err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj, | |
| 1486 | + rx_tail, len); | |
| 1487 | + if (err) | |
| 1488 | + return err; | |
| 1489 | + | |
| 1490 | + for (i = 0; i < len; i++) { | |
| 1491 | + err = mcp251xfd_handle_rxif_one(priv, ring, | |
| 1492 | + (void *)hw_rx_obj + | |
| 1493 | + i * ring->obj_size); | |
| 1494 | + if (err) | |
| 1495 | + return err; | |
| 1496 | + } | |
| 1497 | + } | |
| 1498 | + | |
| 1499 | + return 0; | |
| 1500 | +} | |
| 1501 | + | |
| 1502 | +static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv) | |
| 1503 | +{ | |
| 1504 | + struct mcp251xfd_rx_ring *ring; | |
| 1505 | + int err, n; | |
| 1506 | + | |
| 1507 | + mcp251xfd_for_each_rx_ring(priv, ring, n) { | |
| 1508 | + err = mcp251xfd_handle_rxif_ring(priv, ring); | |
| 1509 | + if (err) | |
| 1510 | + return err; | |
| 1511 | + } | |
| 1512 | + | |
| 1513 | + return 0; | |
| 1514 | +} | |
| 1515 | + | |
| 1516 | +static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv, | |
| 1517 | + u32 *timestamp) | |
| 1518 | +{ | |
| 1519 | + return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp); | |
| 1520 | +} | |
| 1521 | + | |
| 1522 | +static struct sk_buff * | |
| 1523 | +mcp251xfd_alloc_can_err_skb(const struct mcp251xfd_priv *priv, | |
| 1524 | + struct can_frame **cf, u32 *timestamp) | |
| 1525 | +{ | |
| 1526 | + int err; | |
| 1527 | + | |
| 1528 | + err = mcp251xfd_get_timestamp(priv, timestamp); | |
| 1529 | + if (err) | |
| 1530 | + return NULL; | |
| 1531 | + | |
| 1532 | + return alloc_can_err_skb(priv->ndev, cf); | |
| 1533 | +} | |
| 1534 | + | |
| 1535 | +static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv) | |
| 1536 | +{ | |
| 1537 | + struct net_device_stats *stats = &priv->ndev->stats; | |
| 1538 | + struct mcp251xfd_rx_ring *ring; | |
| 1539 | + struct sk_buff *skb; | |
| 1540 | + struct can_frame *cf; | |
| 1541 | + u32 timestamp, rxovif; | |
| 1542 | + int err, i; | |
| 1543 | + | |
| 1544 | + stats->rx_over_errors++; | |
| 1545 | + stats->rx_errors++; | |
| 1546 | + | |
| 1547 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_RXOVIF, &rxovif); | |
| 1548 | + if (err) | |
| 1549 | + return err; | |
| 1550 | + | |
| 1551 | + mcp251xfd_for_each_rx_ring(priv, ring, i) { | |
| 1552 | + if (!(rxovif & BIT(ring->fifo_nr))) | |
| 1553 | + continue; | |
| 1554 | + | |
| 1555 | + /* If SERRIF is active, there was a RX MAB overflow. */ | |
| 1556 | + if (priv->regs_status.intf & MCP251XFD_REG_INT_SERRIF) { | |
| 1557 | + netdev_info(priv->ndev, | |
| 1558 | + "RX-%d: MAB overflow detected.\n", | |
| 1559 | + ring->nr); | |
| 1560 | + } else { | |
| 1561 | + netdev_info(priv->ndev, | |
| 1562 | + "RX-%d: FIFO overflow.\n", ring->nr); | |
| 1563 | + } | |
| 1564 | + | |
| 1565 | + err = regmap_update_bits(priv->map_reg, | |
| 1566 | + MCP251XFD_REG_FIFOSTA(ring->fifo_nr), | |
| 1567 | + MCP251XFD_REG_FIFOSTA_RXOVIF, | |
| 1568 | + 0x0); | |
| 1569 | + if (err) | |
| 1570 | + return err; | |
| 1571 | + } | |
| 1572 | + | |
| 1573 | + skb = mcp251xfd_alloc_can_err_skb(priv, &cf, ×tamp); | |
| 1574 | + if (!skb) | |
| 1575 | + return 0; | |
| 1576 | + | |
| 1577 | + cf->can_id |= CAN_ERR_CRTL; | |
| 1578 | + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; | |
| 1579 | + | |
| 1580 | + err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); | |
| 1581 | + if (err) | |
| 1582 | + stats->rx_fifo_errors++; | |
| 1583 | + | |
| 1584 | + return 0; | |
| 1585 | +} | |
| 1586 | + | |
| 1587 | +static int mcp251xfd_handle_txatif(struct mcp251xfd_priv *priv) | |
| 1588 | +{ | |
| 1589 | + netdev_info(priv->ndev, "%s\n", __func__); | |
| 1590 | + | |
| 1591 | + return 0; | |
| 1592 | +} | |
| 1593 | + | |
| 1594 | +static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv) | |
| 1595 | +{ | |
| 1596 | + struct net_device_stats *stats = &priv->ndev->stats; | |
| 1597 | + u32 bdiag1, timestamp; | |
| 1598 | + struct sk_buff *skb; | |
| 1599 | + struct can_frame *cf = NULL; | |
| 1600 | + int err; | |
| 1601 | + | |
| 1602 | + err = mcp251xfd_get_timestamp(priv, ×tamp); | |
| 1603 | + if (err) | |
| 1604 | + return err; | |
| 1605 | + | |
| 1606 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_BDIAG1, &bdiag1); | |
| 1607 | + if (err) | |
| 1608 | + return err; | |
| 1609 | + | |
| 1610 | + /* Write 0s to clear error bits, don't write 1s to non active | |
| 1611 | + * bits, as they will be set. | |
| 1612 | + */ | |
| 1613 | + err = regmap_write(priv->map_reg, MCP251XFD_REG_BDIAG1, 0x0); | |
| 1614 | + if (err) | |
| 1615 | + return err; | |
| 1616 | + | |
| 1617 | + priv->can.can_stats.bus_error++; | |
| 1618 | + | |
| 1619 | + skb = alloc_can_err_skb(priv->ndev, &cf); | |
| 1620 | + if (cf) | |
| 1621 | + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; | |
| 1622 | + | |
| 1623 | + /* Controller misconfiguration */ | |
| 1624 | + if (WARN_ON(bdiag1 & MCP251XFD_REG_BDIAG1_DLCMM)) | |
| 1625 | + netdev_err(priv->ndev, | |
| 1626 | + "recv'd DLC is larger than PLSIZE of FIFO element."); | |
| 1627 | + | |
| 1628 | + /* RX errors */ | |
| 1629 | + if (bdiag1 & (MCP251XFD_REG_BDIAG1_DCRCERR | | |
| 1630 | + MCP251XFD_REG_BDIAG1_NCRCERR)) { | |
| 1631 | + netdev_dbg(priv->ndev, "CRC error\n"); | |
| 1632 | + | |
| 1633 | + stats->rx_errors++; | |
| 1634 | + if (cf) | |
| 1635 | + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; | |
| 1636 | + } | |
| 1637 | + if (bdiag1 & (MCP251XFD_REG_BDIAG1_DSTUFERR | | |
| 1638 | + MCP251XFD_REG_BDIAG1_NSTUFERR)) { | |
| 1639 | + netdev_dbg(priv->ndev, "Stuff error\n"); | |
| 1640 | + | |
| 1641 | + stats->rx_errors++; | |
| 1642 | + if (cf) | |
| 1643 | + cf->data[2] |= CAN_ERR_PROT_STUFF; | |
| 1644 | + } | |
| 1645 | + if (bdiag1 & (MCP251XFD_REG_BDIAG1_DFORMERR | | |
| 1646 | + MCP251XFD_REG_BDIAG1_NFORMERR)) { | |
| 1647 | + netdev_dbg(priv->ndev, "Format error\n"); | |
| 1648 | + | |
| 1649 | + stats->rx_errors++; | |
| 1650 | + if (cf) | |
| 1651 | + cf->data[2] |= CAN_ERR_PROT_FORM; | |
| 1652 | + } | |
| 1653 | + | |
| 1654 | + /* TX errors */ | |
| 1655 | + if (bdiag1 & MCP251XFD_REG_BDIAG1_NACKERR) { | |
| 1656 | + netdev_dbg(priv->ndev, "NACK error\n"); | |
| 1657 | + | |
| 1658 | + stats->tx_errors++; | |
| 1659 | + if (cf) { | |
| 1660 | + cf->can_id |= CAN_ERR_ACK; | |
| 1661 | + cf->data[2] |= CAN_ERR_PROT_TX; | |
| 1662 | + } | |
| 1663 | + } | |
| 1664 | + if (bdiag1 & (MCP251XFD_REG_BDIAG1_DBIT1ERR | | |
| 1665 | + MCP251XFD_REG_BDIAG1_NBIT1ERR)) { | |
| 1666 | + netdev_dbg(priv->ndev, "Bit1 error\n"); | |
| 1667 | + | |
| 1668 | + stats->tx_errors++; | |
| 1669 | + if (cf) | |
| 1670 | + cf->data[2] |= CAN_ERR_PROT_TX | CAN_ERR_PROT_BIT1; | |
| 1671 | + } | |
| 1672 | + if (bdiag1 & (MCP251XFD_REG_BDIAG1_DBIT0ERR | | |
| 1673 | + MCP251XFD_REG_BDIAG1_NBIT0ERR)) { | |
| 1674 | + netdev_dbg(priv->ndev, "Bit0 error\n"); | |
| 1675 | + | |
| 1676 | + stats->tx_errors++; | |
| 1677 | + if (cf) | |
| 1678 | + cf->data[2] |= CAN_ERR_PROT_TX | CAN_ERR_PROT_BIT0; | |
| 1679 | + } | |
| 1680 | + | |
| 1681 | + if (!cf) | |
| 1682 | + return 0; | |
| 1683 | + | |
| 1684 | + err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); | |
| 1685 | + if (err) | |
| 1686 | + stats->rx_fifo_errors++; | |
| 1687 | + | |
| 1688 | + return 0; | |
| 1689 | +} | |
| 1690 | + | |
| 1691 | +static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv) | |
| 1692 | +{ | |
| 1693 | + struct net_device_stats *stats = &priv->ndev->stats; | |
| 1694 | + struct sk_buff *skb; | |
| 1695 | + struct can_frame *cf = NULL; | |
| 1696 | + enum can_state new_state, rx_state, tx_state; | |
| 1697 | + u32 trec, timestamp; | |
| 1698 | + int err; | |
| 1699 | + | |
| 1700 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_TREC, &trec); | |
| 1701 | + if (err) | |
| 1702 | + return err; | |
| 1703 | + | |
| 1704 | + if (trec & MCP251XFD_REG_TREC_TXBO) | |
| 1705 | + tx_state = CAN_STATE_BUS_OFF; | |
| 1706 | + else if (trec & MCP251XFD_REG_TREC_TXBP) | |
| 1707 | + tx_state = CAN_STATE_ERROR_PASSIVE; | |
| 1708 | + else if (trec & MCP251XFD_REG_TREC_TXWARN) | |
| 1709 | + tx_state = CAN_STATE_ERROR_WARNING; | |
| 1710 | + else | |
| 1711 | + tx_state = CAN_STATE_ERROR_ACTIVE; | |
| 1712 | + | |
| 1713 | + if (trec & MCP251XFD_REG_TREC_RXBP) | |
| 1714 | + rx_state = CAN_STATE_ERROR_PASSIVE; | |
| 1715 | + else if (trec & MCP251XFD_REG_TREC_RXWARN) | |
| 1716 | + rx_state = CAN_STATE_ERROR_WARNING; | |
| 1717 | + else | |
| 1718 | + rx_state = CAN_STATE_ERROR_ACTIVE; | |
| 1719 | + | |
| 1720 | + new_state = max(tx_state, rx_state); | |
| 1721 | + if (new_state == priv->can.state) | |
| 1722 | + return 0; | |
| 1723 | + | |
| 1724 | + /* The skb allocation might fail, but can_change_state() | |
| 1725 | + * handles cf == NULL. | |
| 1726 | + */ | |
| 1727 | + skb = mcp251xfd_alloc_can_err_skb(priv, &cf, ×tamp); | |
| 1728 | + can_change_state(priv->ndev, cf, tx_state, rx_state); | |
| 1729 | + | |
| 1730 | + if (new_state == CAN_STATE_BUS_OFF) { | |
| 1731 | + /* As we're going to switch off the chip now, let's | |
| 1732 | + * save the error counters and return them to | |
| 1733 | + * userspace, if do_get_berr_counter() is called while | |
| 1734 | + * the chip is in Bus Off. | |
| 1735 | + */ | |
| 1736 | + err = __mcp251xfd_get_berr_counter(priv->ndev, &priv->bec); | |
| 1737 | + if (err) | |
| 1738 | + return err; | |
| 1739 | + | |
| 1740 | + mcp251xfd_chip_stop(priv, CAN_STATE_BUS_OFF); | |
| 1741 | + can_bus_off(priv->ndev); | |
| 1742 | + } | |
| 1743 | + | |
| 1744 | + if (!skb) | |
| 1745 | + return 0; | |
| 1746 | + | |
| 1747 | + if (new_state != CAN_STATE_BUS_OFF) { | |
| 1748 | + struct can_berr_counter bec; | |
| 1749 | + | |
| 1750 | + err = mcp251xfd_get_berr_counter(priv->ndev, &bec); | |
| 1751 | + if (err) | |
| 1752 | + return err; | |
| 1753 | + cf->data[6] = bec.txerr; | |
| 1754 | + cf->data[7] = bec.rxerr; | |
| 1755 | + } | |
| 1756 | + | |
| 1757 | + err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); | |
| 1758 | + if (err) | |
| 1759 | + stats->rx_fifo_errors++; | |
| 1760 | + | |
| 1761 | + return 0; | |
| 1762 | +} | |
| 1763 | + | |
| 1764 | +static int | |
| 1765 | +mcp251xfd_handle_modif(const struct mcp251xfd_priv *priv, bool *set_normal_mode) | |
| 1766 | +{ | |
| 1767 | + const u8 mode_reference = mcp251xfd_get_normal_mode(priv); | |
| 1768 | + u8 mode; | |
| 1769 | + int err; | |
| 1770 | + | |
| 1771 | + err = mcp251xfd_chip_get_mode(priv, &mode); | |
| 1772 | + if (err) | |
| 1773 | + return err; | |
| 1774 | + | |
| 1775 | + if (mode == mode_reference) { | |
| 1776 | + netdev_dbg(priv->ndev, | |
| 1777 | + "Controller changed into %s Mode (%u).\n", | |
| 1778 | + mcp251xfd_get_mode_str(mode), mode); | |
| 1779 | + return 0; | |
| 1780 | + } | |
| 1781 | + | |
| 1782 | + /* According to MCP2517FD errata DS80000792B 1., during a TX | |
| 1783 | + * MAB underflow, the controller will transition to Restricted | |
| 1784 | + * Operation Mode or Listen Only Mode (depending on SERR2LOM). | |
| 1785 | + * | |
| 1786 | + * However this is not always the case. If SERR2LOM is | |
| 1787 | + * configured for Restricted Operation Mode (SERR2LOM not set) | |
| 1788 | + * the MCP2517FD will sometimes transition to Listen Only Mode | |
| 1789 | + * first. When polling this bit we see that it will transition | |
| 1790 | + * to Restricted Operation Mode shortly after. | |
| 1791 | + */ | |
| 1792 | + if ((priv->devtype_data.quirks & MCP251XFD_QUIRK_MAB_NO_WARN) && | |
| 1793 | + (mode == MCP251XFD_REG_CON_MODE_RESTRICTED || | |
| 1794 | + mode == MCP251XFD_REG_CON_MODE_LISTENONLY)) | |
| 1795 | + netdev_dbg(priv->ndev, | |
| 1796 | + "Controller changed into %s Mode (%u).\n", | |
| 1797 | + mcp251xfd_get_mode_str(mode), mode); | |
| 1798 | + else | |
| 1799 | + netdev_err(priv->ndev, | |
| 1800 | + "Controller changed into %s Mode (%u).\n", | |
| 1801 | + mcp251xfd_get_mode_str(mode), mode); | |
| 1802 | + | |
| 1803 | + /* After the application requests Normal mode, the Controller | |
| 1804 | + * will automatically attempt to retransmit the message that | |
| 1805 | + * caused the TX MAB underflow. | |
| 1806 | + * | |
| 1807 | + * However, if there is an ECC error in the TX-RAM, we first | |
| 1808 | + * have to reload the tx-object before requesting Normal | |
| 1809 | + * mode. This is done later in mcp251xfd_handle_eccif(). | |
| 1810 | + */ | |
| 1811 | + if (priv->regs_status.intf & MCP251XFD_REG_INT_ECCIF) { | |
| 1812 | + *set_normal_mode = true; | |
| 1813 | + return 0; | |
| 1814 | + } | |
| 1815 | + | |
| 1816 | + return mcp251xfd_chip_set_normal_mode_nowait(priv); | |
| 1817 | +} | |
| 1818 | + | |
| 1819 | +static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv) | |
| 1820 | +{ | |
| 1821 | + struct mcp251xfd_ecc *ecc = &priv->ecc; | |
| 1822 | + struct net_device_stats *stats = &priv->ndev->stats; | |
| 1823 | + bool handled = false; | |
| 1824 | + | |
| 1825 | + /* TX MAB underflow | |
| 1826 | + * | |
| 1827 | + * According to MCP2517FD Errata DS80000792B 1. a TX MAB | |
| 1828 | + * underflow is indicated by SERRIF and MODIF. | |
| 1829 | + * | |
| 1830 | + * In addition to the effects mentioned in the Errata, there | |
| 1831 | + * are Bus Errors due to the aborted CAN frame, so a IVMIF | |
| 1832 | + * will be seen as well. | |
| 1833 | + * | |
| 1834 | + * Sometimes there is an ECC error in the TX-RAM, which leads | |
| 1835 | + * to a TX MAB underflow. | |
| 1836 | + * | |
| 1837 | + * However, probably due to a race condition, there is no | |
| 1838 | + * associated MODIF pending. | |
| 1839 | + * | |
| 1840 | + * Further, there are situations, where the SERRIF is caused | |
| 1841 | + * by an ECC error in the TX-RAM, but not even the ECCIF is | |
| 1842 | + * set. This only seems to happen _after_ the first occurrence | |
| 1843 | + * of a ECCIF (which is tracked in ecc->cnt). | |
| 1844 | + * | |
| 1845 | + * Treat all as a known system errors.. | |
| 1846 | + */ | |
| 1847 | + if ((priv->regs_status.intf & MCP251XFD_REG_INT_MODIF && | |
| 1848 | + priv->regs_status.intf & MCP251XFD_REG_INT_IVMIF) || | |
| 1849 | + priv->regs_status.intf & MCP251XFD_REG_INT_ECCIF || | |
| 1850 | + ecc->cnt) { | |
| 1851 | + const char *msg; | |
| 1852 | + | |
| 1853 | + if (priv->regs_status.intf & MCP251XFD_REG_INT_ECCIF || | |
| 1854 | + ecc->cnt) | |
| 1855 | + msg = "TX MAB underflow due to ECC error detected."; | |
| 1856 | + else | |
| 1857 | + msg = "TX MAB underflow detected."; | |
| 1858 | + | |
| 1859 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_MAB_NO_WARN) | |
| 1860 | + netdev_dbg(priv->ndev, "%s\n", msg); | |
| 1861 | + else | |
| 1862 | + netdev_info(priv->ndev, "%s\n", msg); | |
| 1863 | + | |
| 1864 | + stats->tx_aborted_errors++; | |
| 1865 | + stats->tx_errors++; | |
| 1866 | + handled = true; | |
| 1867 | + } | |
| 1868 | + | |
| 1869 | + /* RX MAB overflow | |
| 1870 | + * | |
| 1871 | + * According to MCP2517FD Errata DS80000792B 1. a RX MAB | |
| 1872 | + * overflow is indicated by SERRIF. | |
| 1873 | + * | |
| 1874 | + * In addition to the effects mentioned in the Errata, (most | |
| 1875 | + * of the times) a RXOVIF is raised, if the FIFO that is being | |
| 1876 | + * received into has the RXOVIE activated (and we have enabled | |
| 1877 | + * RXOVIE on all FIFOs). | |
| 1878 | + * | |
| 1879 | + * Sometimes there is no RXOVIF just a RXIF is pending. | |
| 1880 | + * | |
| 1881 | + * Treat all as a known system errors.. | |
| 1882 | + */ | |
| 1883 | + if (priv->regs_status.intf & MCP251XFD_REG_INT_RXOVIF || | |
| 1884 | + priv->regs_status.intf & MCP251XFD_REG_INT_RXIF) { | |
| 1885 | + stats->rx_dropped++; | |
| 1886 | + handled = true; | |
| 1887 | + } | |
| 1888 | + | |
| 1889 | + if (!handled) | |
| 1890 | + netdev_err(priv->ndev, | |
| 1891 | + "Unhandled System Error Interrupt (intf=0x%08x)!\n", | |
| 1892 | + priv->regs_status.intf); | |
| 1893 | + | |
| 1894 | + return 0; | |
| 1895 | +} | |
| 1896 | + | |
| 1897 | +static int | |
| 1898 | +mcp251xfd_handle_eccif_recover(struct mcp251xfd_priv *priv, u8 nr) | |
| 1899 | +{ | |
| 1900 | + struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 1901 | + struct mcp251xfd_ecc *ecc = &priv->ecc; | |
| 1902 | + struct mcp251xfd_tx_obj *tx_obj; | |
| 1903 | + u8 chip_tx_tail, tx_tail, offset; | |
| 1904 | + u16 addr; | |
| 1905 | + int err; | |
| 1906 | + | |
| 1907 | + addr = FIELD_GET(MCP251XFD_REG_ECCSTAT_ERRADDR_MASK, ecc->ecc_stat); | |
| 1908 | + | |
| 1909 | + err = mcp251xfd_tx_tail_get_from_chip(priv, &chip_tx_tail); | |
| 1910 | + if (err) | |
| 1911 | + return err; | |
| 1912 | + | |
| 1913 | + tx_tail = mcp251xfd_get_tx_tail(tx_ring); | |
| 1914 | + offset = (nr - chip_tx_tail) & (tx_ring->obj_num - 1); | |
| 1915 | + | |
| 1916 | + /* Bail out if one of the following is met: | |
| 1917 | + * - tx_tail information is inconsistent | |
| 1918 | + * - for mcp2517fd: offset not 0 | |
| 1919 | + * - for mcp2518fd: offset not 0 or 1 | |
| 1920 | + */ | |
| 1921 | + if (chip_tx_tail != tx_tail || | |
| 1922 | + !(offset == 0 || (offset == 1 && mcp251xfd_is_2518(priv)))) { | |
| 1923 | + netdev_err(priv->ndev, | |
| 1924 | + "ECC Error information inconsistent (addr=0x%04x, nr=%d, tx_tail=0x%08x(%d), chip_tx_tail=%d, offset=%d).\n", | |
| 1925 | + addr, nr, tx_ring->tail, tx_tail, chip_tx_tail, | |
| 1926 | + offset); | |
| 1927 | + return -EINVAL; | |
| 1928 | + } | |
| 1929 | + | |
| 1930 | + netdev_info(priv->ndev, | |
| 1931 | + "Recovering %s ECC Error at address 0x%04x (in TX-RAM, tx_obj=%d, tx_tail=0x%08x(%d), offset=%d).\n", | |
| 1932 | + ecc->ecc_stat & MCP251XFD_REG_ECCSTAT_SECIF ? | |
| 1933 | + "Single" : "Double", | |
| 1934 | + addr, nr, tx_ring->tail, tx_tail, offset); | |
| 1935 | + | |
| 1936 | + /* reload tx_obj into controller RAM ... */ | |
| 1937 | + tx_obj = &tx_ring->obj[nr]; | |
| 1938 | + err = spi_sync_transfer(priv->spi, tx_obj->xfer, 1); | |
| 1939 | + if (err) | |
| 1940 | + return err; | |
| 1941 | + | |
| 1942 | + /* ... and trigger retransmit */ | |
| 1943 | + return mcp251xfd_chip_set_normal_mode(priv); | |
| 1944 | +} | |
| 1945 | + | |
| 1946 | +static int | |
| 1947 | +mcp251xfd_handle_eccif(struct mcp251xfd_priv *priv, bool set_normal_mode) | |
| 1948 | +{ | |
| 1949 | + struct mcp251xfd_ecc *ecc = &priv->ecc; | |
| 1950 | + const char *msg; | |
| 1951 | + bool in_tx_ram; | |
| 1952 | + u32 ecc_stat; | |
| 1953 | + u16 addr; | |
| 1954 | + u8 nr; | |
| 1955 | + int err; | |
| 1956 | + | |
| 1957 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_ECCSTAT, &ecc_stat); | |
| 1958 | + if (err) | |
| 1959 | + return err; | |
| 1960 | + | |
| 1961 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_ECCSTAT, | |
| 1962 | + MCP251XFD_REG_ECCSTAT_IF_MASK, ~ecc_stat); | |
| 1963 | + if (err) | |
| 1964 | + return err; | |
| 1965 | + | |
| 1966 | + /* Check if ECC error occurred in TX-RAM */ | |
| 1967 | + addr = FIELD_GET(MCP251XFD_REG_ECCSTAT_ERRADDR_MASK, ecc_stat); | |
| 1968 | + err = mcp251xfd_get_tx_nr_by_addr(priv->tx, &nr, addr); | |
| 1969 | + if (!err) | |
| 1970 | + in_tx_ram = true; | |
| 1971 | + else if (err == -ENOENT) | |
| 1972 | + in_tx_ram = false; | |
| 1973 | + else | |
| 1974 | + return err; | |
| 1975 | + | |
| 1976 | + /* Errata Reference: | |
| 1977 | + * mcp2517fd: DS80000789B, mcp2518fd: DS80000792C 2. | |
| 1978 | + * | |
| 1979 | + * ECC single error correction does not work in all cases: | |
| 1980 | + * | |
| 1981 | + * Fix/Work Around: | |
| 1982 | + * Enable single error correction and double error detection | |
| 1983 | + * interrupts by setting SECIE and DEDIE. Handle SECIF as a | |
| 1984 | + * detection interrupt and do not rely on the error | |
| 1985 | + * correction. Instead, handle both interrupts as a | |
| 1986 | + * notification that the RAM word at ERRADDR was corrupted. | |
| 1987 | + */ | |
| 1988 | + if (ecc_stat & MCP251XFD_REG_ECCSTAT_SECIF) | |
| 1989 | + msg = "Single ECC Error detected at address"; | |
| 1990 | + else if (ecc_stat & MCP251XFD_REG_ECCSTAT_DEDIF) | |
| 1991 | + msg = "Double ECC Error detected at address"; | |
| 1992 | + else | |
| 1993 | + return -EINVAL; | |
| 1994 | + | |
| 1995 | + if (!in_tx_ram) { | |
| 1996 | + ecc->ecc_stat = 0; | |
| 1997 | + | |
| 1998 | + netdev_notice(priv->ndev, "%s 0x%04x.\n", msg, addr); | |
| 1999 | + } else { | |
| 2000 | + /* Re-occurring error? */ | |
| 2001 | + if (ecc->ecc_stat == ecc_stat) { | |
| 2002 | + ecc->cnt++; | |
| 2003 | + } else { | |
| 2004 | + ecc->ecc_stat = ecc_stat; | |
| 2005 | + ecc->cnt = 1; | |
| 2006 | + } | |
| 2007 | + | |
| 2008 | + netdev_info(priv->ndev, | |
| 2009 | + "%s 0x%04x (in TX-RAM, tx_obj=%d), occurred %d time%s.\n", | |
| 2010 | + msg, addr, nr, ecc->cnt, ecc->cnt > 1 ? "s" : ""); | |
| 2011 | + | |
| 2012 | + if (ecc->cnt >= MCP251XFD_ECC_CNT_MAX) | |
| 2013 | + return mcp251xfd_handle_eccif_recover(priv, nr); | |
| 2014 | + } | |
| 2015 | + | |
| 2016 | + if (set_normal_mode) | |
| 2017 | + return mcp251xfd_chip_set_normal_mode_nowait(priv); | |
| 2018 | + | |
| 2019 | + return 0; | |
| 2020 | +} | |
| 2021 | + | |
| 2022 | +static int mcp251xfd_handle_spicrcif(struct mcp251xfd_priv *priv) | |
| 2023 | +{ | |
| 2024 | + int err; | |
| 2025 | + u32 crc; | |
| 2026 | + | |
| 2027 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_CRC, &crc); | |
| 2028 | + if (err) | |
| 2029 | + return err; | |
| 2030 | + | |
| 2031 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_CRC, | |
| 2032 | + MCP251XFD_REG_CRC_IF_MASK, | |
| 2033 | + ~crc); | |
| 2034 | + if (err) | |
| 2035 | + return err; | |
| 2036 | + | |
| 2037 | + if (crc & MCP251XFD_REG_CRC_FERRIF) | |
| 2038 | + netdev_notice(priv->ndev, "CRC write command format error.\n"); | |
| 2039 | + else if (crc & MCP251XFD_REG_CRC_CRCERRIF) | |
| 2040 | + netdev_notice(priv->ndev, | |
| 2041 | + "CRC write error detected. CRC=0x%04lx.\n", | |
| 2042 | + FIELD_GET(MCP251XFD_REG_CRC_MASK, crc)); | |
| 2043 | + | |
| 2044 | + return 0; | |
| 2045 | +} | |
| 2046 | + | |
| 2047 | +#define mcp251xfd_handle(priv, irq, ...) \ | |
| 2048 | +({ \ | |
| 2049 | + struct mcp251xfd_priv *_priv = (priv); \ | |
| 2050 | + int err; \ | |
| 2051 | +\ | |
| 2052 | + err = mcp251xfd_handle_##irq(_priv, ## __VA_ARGS__); \ | |
| 2053 | + if (err) \ | |
| 2054 | + netdev_err(_priv->ndev, \ | |
| 2055 | + "IRQ handler mcp251xfd_handle_%s() returned %d.\n", \ | |
| 2056 | + __stringify(irq), err); \ | |
| 2057 | + err; \ | |
| 2058 | +}) | |
| 2059 | + | |
| 2060 | +static irqreturn_t mcp251xfd_irq(int irq, void *dev_id) | |
| 2061 | +{ | |
| 2062 | + struct mcp251xfd_priv *priv = dev_id; | |
| 2063 | + irqreturn_t handled = IRQ_NONE; | |
| 2064 | + int err; | |
| 2065 | + | |
| 2066 | + if (priv->rx_int) | |
| 2067 | + do { | |
| 2068 | + int rx_pending; | |
| 2069 | + | |
| 2070 | + rx_pending = gpiod_get_value_cansleep(priv->rx_int); | |
| 2071 | + if (!rx_pending) | |
| 2072 | + break; | |
| 2073 | + | |
| 2074 | + err = mcp251xfd_handle(priv, rxif); | |
| 2075 | + if (err) | |
| 2076 | + goto out_fail; | |
| 2077 | + | |
| 2078 | + handled = IRQ_HANDLED; | |
| 2079 | + } while (1); | |
| 2080 | + | |
| 2081 | + do { | |
| 2082 | + u32 intf_pending, intf_pending_clearable; | |
| 2083 | + bool set_normal_mode = false; | |
| 2084 | + | |
| 2085 | + err = regmap_bulk_read(priv->map_reg, MCP251XFD_REG_INT, | |
| 2086 | + &priv->regs_status, | |
| 2087 | + sizeof(priv->regs_status) / | |
| 2088 | + sizeof(u32)); | |
| 2089 | + if (err) | |
| 2090 | + goto out_fail; | |
| 2091 | + | |
| 2092 | + intf_pending = FIELD_GET(MCP251XFD_REG_INT_IF_MASK, | |
| 2093 | + priv->regs_status.intf) & | |
| 2094 | + FIELD_GET(MCP251XFD_REG_INT_IE_MASK, | |
| 2095 | + priv->regs_status.intf); | |
| 2096 | + | |
| 2097 | + if (!(intf_pending)) | |
| 2098 | + return handled; | |
| 2099 | + | |
| 2100 | + /* Some interrupts must be ACKed in the | |
| 2101 | + * MCP251XFD_REG_INT register. | |
| 2102 | + * - First ACK then handle, to avoid lost-IRQ race | |
| 2103 | + * condition on fast re-occurring interrupts. | |
| 2104 | + * - Write "0" to clear active IRQs, "1" to all other, | |
| 2105 | + * to avoid r/m/w race condition on the | |
| 2106 | + * MCP251XFD_REG_INT register. | |
| 2107 | + */ | |
| 2108 | + intf_pending_clearable = intf_pending & | |
| 2109 | + MCP251XFD_REG_INT_IF_CLEARABLE_MASK; | |
| 2110 | + if (intf_pending_clearable) { | |
| 2111 | + err = regmap_update_bits(priv->map_reg, | |
| 2112 | + MCP251XFD_REG_INT, | |
| 2113 | + MCP251XFD_REG_INT_IF_MASK, | |
| 2114 | + ~intf_pending_clearable); | |
| 2115 | + if (err) | |
| 2116 | + goto out_fail; | |
| 2117 | + } | |
| 2118 | + | |
| 2119 | + if (intf_pending & MCP251XFD_REG_INT_MODIF) { | |
| 2120 | + err = mcp251xfd_handle(priv, modif, &set_normal_mode); | |
| 2121 | + if (err) | |
| 2122 | + goto out_fail; | |
| 2123 | + } | |
| 2124 | + | |
| 2125 | + if (intf_pending & MCP251XFD_REG_INT_RXIF) { | |
| 2126 | + err = mcp251xfd_handle(priv, rxif); | |
| 2127 | + if (err) | |
| 2128 | + goto out_fail; | |
| 2129 | + } | |
| 2130 | + | |
| 2131 | + if (intf_pending & MCP251XFD_REG_INT_TEFIF) { | |
| 2132 | + err = mcp251xfd_handle(priv, tefif); | |
| 2133 | + if (err) | |
| 2134 | + goto out_fail; | |
| 2135 | + } | |
| 2136 | + | |
| 2137 | + if (intf_pending & MCP251XFD_REG_INT_RXOVIF) { | |
| 2138 | + err = mcp251xfd_handle(priv, rxovif); | |
| 2139 | + if (err) | |
| 2140 | + goto out_fail; | |
| 2141 | + } | |
| 2142 | + | |
| 2143 | + if (intf_pending & MCP251XFD_REG_INT_TXATIF) { | |
| 2144 | + err = mcp251xfd_handle(priv, txatif); | |
| 2145 | + if (err) | |
| 2146 | + goto out_fail; | |
| 2147 | + } | |
| 2148 | + | |
| 2149 | + if (intf_pending & MCP251XFD_REG_INT_IVMIF) { | |
| 2150 | + err = mcp251xfd_handle(priv, ivmif); | |
| 2151 | + if (err) | |
| 2152 | + goto out_fail; | |
| 2153 | + } | |
| 2154 | + | |
| 2155 | + if (intf_pending & MCP251XFD_REG_INT_SERRIF) { | |
| 2156 | + err = mcp251xfd_handle(priv, serrif); | |
| 2157 | + if (err) | |
| 2158 | + goto out_fail; | |
| 2159 | + } | |
| 2160 | + | |
| 2161 | + if (intf_pending & MCP251XFD_REG_INT_ECCIF) { | |
| 2162 | + err = mcp251xfd_handle(priv, eccif, set_normal_mode); | |
| 2163 | + if (err) | |
| 2164 | + goto out_fail; | |
| 2165 | + } | |
| 2166 | + | |
| 2167 | + if (intf_pending & MCP251XFD_REG_INT_SPICRCIF) { | |
| 2168 | + err = mcp251xfd_handle(priv, spicrcif); | |
| 2169 | + if (err) | |
| 2170 | + goto out_fail; | |
| 2171 | + } | |
| 2172 | + | |
| 2173 | + /* On the MCP2527FD and MCP2518FD, we don't get a | |
| 2174 | + * CERRIF IRQ on the transition TX ERROR_WARNING -> TX | |
| 2175 | + * ERROR_ACTIVE. | |
| 2176 | + */ | |
| 2177 | + if (intf_pending & MCP251XFD_REG_INT_CERRIF || | |
| 2178 | + priv->can.state > CAN_STATE_ERROR_ACTIVE) { | |
| 2179 | + err = mcp251xfd_handle(priv, cerrif); | |
| 2180 | + if (err) | |
| 2181 | + goto out_fail; | |
| 2182 | + | |
| 2183 | + /* In Bus Off we completely shut down the | |
| 2184 | + * controller. Every subsequent register read | |
| 2185 | + * will read bogus data, and if | |
| 2186 | + * MCP251XFD_QUIRK_CRC_REG is enabled the CRC | |
| 2187 | + * check will fail, too. So leave IRQ handler | |
| 2188 | + * directly. | |
| 2189 | + */ | |
| 2190 | + if (priv->can.state == CAN_STATE_BUS_OFF) | |
| 2191 | + return IRQ_HANDLED; | |
| 2192 | + } | |
| 2193 | + | |
| 2194 | + handled = IRQ_HANDLED; | |
| 2195 | + } while (1); | |
| 2196 | + | |
| 2197 | + out_fail: | |
| 2198 | + netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n", | |
| 2199 | + err, priv->regs_status.intf); | |
| 2200 | + mcp251xfd_chip_interrupts_disable(priv); | |
| 2201 | + | |
| 2202 | + return handled; | |
| 2203 | +} | |
| 2204 | + | |
| 2205 | +static inline struct | |
| 2206 | +mcp251xfd_tx_obj *mcp251xfd_get_tx_obj_next(struct mcp251xfd_tx_ring *tx_ring) | |
| 2207 | +{ | |
| 2208 | + u8 tx_head; | |
| 2209 | + | |
| 2210 | + tx_head = mcp251xfd_get_tx_head(tx_ring); | |
| 2211 | + | |
| 2212 | + return &tx_ring->obj[tx_head]; | |
| 2213 | +} | |
| 2214 | + | |
| 2215 | +static void | |
| 2216 | +mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv, | |
| 2217 | + struct mcp251xfd_tx_obj *tx_obj, | |
| 2218 | + const struct sk_buff *skb, | |
| 2219 | + unsigned int seq) | |
| 2220 | +{ | |
| 2221 | + const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; | |
| 2222 | + struct mcp251xfd_hw_tx_obj_raw *hw_tx_obj; | |
| 2223 | + union mcp251xfd_tx_obj_load_buf *load_buf; | |
| 2224 | + u8 dlc; | |
| 2225 | + u32 id, flags; | |
| 2226 | + int offset, len; | |
| 2227 | + | |
| 2228 | + if (cfd->can_id & CAN_EFF_FLAG) { | |
| 2229 | + u32 sid, eid; | |
| 2230 | + | |
| 2231 | + sid = FIELD_GET(MCP251XFD_REG_FRAME_EFF_SID_MASK, cfd->can_id); | |
| 2232 | + eid = FIELD_GET(MCP251XFD_REG_FRAME_EFF_EID_MASK, cfd->can_id); | |
| 2233 | + | |
| 2234 | + id = FIELD_PREP(MCP251XFD_OBJ_ID_EID_MASK, eid) | | |
| 2235 | + FIELD_PREP(MCP251XFD_OBJ_ID_SID_MASK, sid); | |
| 2236 | + | |
| 2237 | + flags = MCP251XFD_OBJ_FLAGS_IDE; | |
| 2238 | + } else { | |
| 2239 | + id = FIELD_PREP(MCP251XFD_OBJ_ID_SID_MASK, cfd->can_id); | |
| 2240 | + flags = 0; | |
| 2241 | + } | |
| 2242 | + | |
| 2243 | + /* Use the MCP2518FD mask even on the MCP2517FD. It doesn't | |
| 2244 | + * harm, only the lower 7 bits will be transferred into the | |
| 2245 | + * TEF object. | |
| 2246 | + */ | |
| 2247 | + dlc = can_len2dlc(cfd->len); | |
| 2248 | + flags |= FIELD_PREP(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, seq) | | |
| 2249 | + FIELD_PREP(MCP251XFD_OBJ_FLAGS_DLC, dlc); | |
| 2250 | + | |
| 2251 | + if (cfd->can_id & CAN_RTR_FLAG) | |
| 2252 | + flags |= MCP251XFD_OBJ_FLAGS_RTR; | |
| 2253 | + | |
| 2254 | + /* CANFD */ | |
| 2255 | + if (can_is_canfd_skb(skb)) { | |
| 2256 | + if (cfd->flags & CANFD_ESI) | |
| 2257 | + flags |= MCP251XFD_OBJ_FLAGS_ESI; | |
| 2258 | + | |
| 2259 | + flags |= MCP251XFD_OBJ_FLAGS_FDF; | |
| 2260 | + | |
| 2261 | + if (cfd->flags & CANFD_BRS) | |
| 2262 | + flags |= MCP251XFD_OBJ_FLAGS_BRS; | |
| 2263 | + } | |
| 2264 | + | |
| 2265 | + load_buf = &tx_obj->buf; | |
| 2266 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) | |
| 2267 | + hw_tx_obj = &load_buf->crc.hw_tx_obj; | |
| 2268 | + else | |
| 2269 | + hw_tx_obj = &load_buf->nocrc.hw_tx_obj; | |
| 2270 | + | |
| 2271 | + put_unaligned_le32(id, &hw_tx_obj->id); | |
| 2272 | + put_unaligned_le32(flags, &hw_tx_obj->flags); | |
| 2273 | + | |
| 2274 | + /* Clear data at end of CAN frame */ | |
| 2275 | + offset = round_down(cfd->len, sizeof(u32)); | |
| 2276 | + len = round_up(can_dlc2len(dlc), sizeof(u32)) - offset; | |
| 2277 | + if (MCP251XFD_SANITIZE_CAN && len) | |
| 2278 | + memset(hw_tx_obj->data + offset, 0x0, len); | |
| 2279 | + memcpy(hw_tx_obj->data, cfd->data, cfd->len); | |
| 2280 | + | |
| 2281 | + /* Number of bytes to be written into the RAM of the controller */ | |
| 2282 | + len = sizeof(hw_tx_obj->id) + sizeof(hw_tx_obj->flags); | |
| 2283 | + if (MCP251XFD_SANITIZE_CAN) | |
| 2284 | + len += round_up(can_dlc2len(dlc), sizeof(u32)); | |
| 2285 | + else | |
| 2286 | + len += round_up(cfd->len, sizeof(u32)); | |
| 2287 | + | |
| 2288 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) { | |
| 2289 | + u16 crc; | |
| 2290 | + | |
| 2291 | + mcp251xfd_spi_cmd_crc_set_len_in_ram(&load_buf->crc.cmd, | |
| 2292 | + len); | |
| 2293 | + /* CRC */ | |
| 2294 | + len += sizeof(load_buf->crc.cmd); | |
| 2295 | + crc = mcp251xfd_crc16_compute(&load_buf->crc, len); | |
| 2296 | + put_unaligned_be16(crc, (void *)load_buf + len); | |
| 2297 | + | |
| 2298 | + /* Total length */ | |
| 2299 | + len += sizeof(load_buf->crc.crc); | |
| 2300 | + } else { | |
| 2301 | + len += sizeof(load_buf->nocrc.cmd); | |
| 2302 | + } | |
| 2303 | + | |
| 2304 | + tx_obj->xfer[0].len = len; | |
| 2305 | +} | |
| 2306 | + | |
| 2307 | +static int mcp251xfd_tx_obj_write(const struct mcp251xfd_priv *priv, | |
| 2308 | + struct mcp251xfd_tx_obj *tx_obj) | |
| 2309 | +{ | |
| 2310 | + return spi_async(priv->spi, &tx_obj->msg); | |
| 2311 | +} | |
| 2312 | + | |
| 2313 | +static bool mcp251xfd_tx_busy(const struct mcp251xfd_priv *priv, | |
| 2314 | + struct mcp251xfd_tx_ring *tx_ring) | |
| 2315 | +{ | |
| 2316 | + if (mcp251xfd_get_tx_free(tx_ring) > 0) | |
| 2317 | + return false; | |
| 2318 | + | |
| 2319 | + netif_stop_queue(priv->ndev); | |
| 2320 | + | |
| 2321 | + /* Memory barrier before checking tx_free (head and tail) */ | |
| 2322 | + smp_mb(); | |
| 2323 | + | |
| 2324 | + if (mcp251xfd_get_tx_free(tx_ring) == 0) { | |
| 2325 | + netdev_dbg(priv->ndev, | |
| 2326 | + "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n", | |
| 2327 | + tx_ring->head, tx_ring->tail, | |
| 2328 | + tx_ring->head - tx_ring->tail); | |
| 2329 | + | |
| 2330 | + return true; | |
| 2331 | + } | |
| 2332 | + | |
| 2333 | + netif_start_queue(priv->ndev); | |
| 2334 | + | |
| 2335 | + return false; | |
| 2336 | +} | |
| 2337 | + | |
| 2338 | +static netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb, | |
| 2339 | + struct net_device *ndev) | |
| 2340 | +{ | |
| 2341 | + struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
| 2342 | + struct mcp251xfd_tx_ring *tx_ring = priv->tx; | |
| 2343 | + struct mcp251xfd_tx_obj *tx_obj; | |
| 2344 | + u8 tx_head; | |
| 2345 | + int err; | |
| 2346 | + | |
| 2347 | + if (can_dropped_invalid_skb(ndev, skb)) | |
| 2348 | + return NETDEV_TX_OK; | |
| 2349 | + | |
| 2350 | + if (mcp251xfd_tx_busy(priv, tx_ring)) | |
| 2351 | + return NETDEV_TX_BUSY; | |
| 2352 | + | |
| 2353 | + tx_obj = mcp251xfd_get_tx_obj_next(tx_ring); | |
| 2354 | + mcp251xfd_tx_obj_from_skb(priv, tx_obj, skb, tx_ring->head); | |
| 2355 | + | |
| 2356 | + /* Stop queue if we occupy the complete TX FIFO */ | |
| 2357 | + tx_head = mcp251xfd_get_tx_head(tx_ring); | |
| 2358 | + tx_ring->head++; | |
| 2359 | + if (tx_ring->head - tx_ring->tail >= tx_ring->obj_num) | |
| 2360 | + netif_stop_queue(ndev); | |
| 2361 | + | |
| 2362 | + can_put_echo_skb(skb, ndev, tx_head); | |
| 2363 | + | |
| 2364 | + err = mcp251xfd_tx_obj_write(priv, tx_obj); | |
| 2365 | + if (err) | |
| 2366 | + goto out_err; | |
| 2367 | + | |
| 2368 | + return NETDEV_TX_OK; | |
| 2369 | + | |
| 2370 | + out_err: | |
| 2371 | + netdev_err(priv->ndev, "ERROR in %s: %d\n", __func__, err); | |
| 2372 | + | |
| 2373 | + return NETDEV_TX_OK; | |
| 2374 | +} | |
| 2375 | + | |
| 2376 | +static int mcp251xfd_open(struct net_device *ndev) | |
| 2377 | +{ | |
| 2378 | + struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
| 2379 | + const struct spi_device *spi = priv->spi; | |
| 2380 | + int err; | |
| 2381 | + | |
| 2382 | + err = pm_runtime_get_sync(ndev->dev.parent); | |
| 2383 | + if (err < 0) { | |
| 2384 | + pm_runtime_put_noidle(ndev->dev.parent); | |
| 2385 | + return err; | |
| 2386 | + } | |
| 2387 | + | |
| 2388 | + err = open_candev(ndev); | |
| 2389 | + if (err) | |
| 2390 | + goto out_pm_runtime_put; | |
| 2391 | + | |
| 2392 | + err = mcp251xfd_ring_alloc(priv); | |
| 2393 | + if (err) | |
| 2394 | + goto out_close_candev; | |
| 2395 | + | |
| 2396 | + err = mcp251xfd_transceiver_enable(priv); | |
| 2397 | + if (err) | |
| 2398 | + goto out_mcp251xfd_ring_free; | |
| 2399 | + | |
| 2400 | + err = mcp251xfd_chip_start(priv); | |
| 2401 | + if (err) | |
| 2402 | + goto out_transceiver_disable; | |
| 2403 | + | |
| 2404 | + can_rx_offload_enable(&priv->offload); | |
| 2405 | + | |
| 2406 | + err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq, | |
| 2407 | + IRQF_ONESHOT, dev_name(&spi->dev), | |
| 2408 | + priv); | |
| 2409 | + if (err) | |
| 2410 | + goto out_can_rx_offload_disable; | |
| 2411 | + | |
| 2412 | + err = mcp251xfd_chip_interrupts_enable(priv); | |
| 2413 | + if (err) | |
| 2414 | + goto out_free_irq; | |
| 2415 | + | |
| 2416 | + netif_start_queue(ndev); | |
| 2417 | + | |
| 2418 | + return 0; | |
| 2419 | + | |
| 2420 | + out_free_irq: | |
| 2421 | + free_irq(spi->irq, priv); | |
| 2422 | + out_can_rx_offload_disable: | |
| 2423 | + can_rx_offload_disable(&priv->offload); | |
| 2424 | + out_transceiver_disable: | |
| 2425 | + mcp251xfd_transceiver_disable(priv); | |
| 2426 | + out_mcp251xfd_ring_free: | |
| 2427 | + mcp251xfd_ring_free(priv); | |
| 2428 | + out_close_candev: | |
| 2429 | + close_candev(ndev); | |
| 2430 | + out_pm_runtime_put: | |
| 2431 | + mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); | |
| 2432 | + pm_runtime_put(ndev->dev.parent); | |
| 2433 | + | |
| 2434 | + return err; | |
| 2435 | +} | |
| 2436 | + | |
| 2437 | +static int mcp251xfd_stop(struct net_device *ndev) | |
| 2438 | +{ | |
| 2439 | + struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
| 2440 | + | |
| 2441 | + netif_stop_queue(ndev); | |
| 2442 | + mcp251xfd_chip_interrupts_disable(priv); | |
| 2443 | + free_irq(ndev->irq, priv); | |
| 2444 | + can_rx_offload_disable(&priv->offload); | |
| 2445 | + mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); | |
| 2446 | + mcp251xfd_transceiver_disable(priv); | |
| 2447 | + mcp251xfd_ring_free(priv); | |
| 2448 | + close_candev(ndev); | |
| 2449 | + | |
| 2450 | + pm_runtime_put(ndev->dev.parent); | |
| 2451 | + | |
| 2452 | + return 0; | |
| 2453 | +} | |
| 2454 | + | |
| 2455 | +static const struct net_device_ops mcp251xfd_netdev_ops = { | |
| 2456 | + .ndo_open = mcp251xfd_open, | |
| 2457 | + .ndo_stop = mcp251xfd_stop, | |
| 2458 | + .ndo_start_xmit = mcp251xfd_start_xmit, | |
| 2459 | + .ndo_change_mtu = can_change_mtu, | |
| 2460 | +}; | |
| 2461 | + | |
| 2462 | +static void | |
| 2463 | +mcp251xfd_register_quirks(struct mcp251xfd_priv *priv) | |
| 2464 | +{ | |
| 2465 | + const struct spi_device *spi = priv->spi; | |
| 2466 | + const struct spi_controller *ctlr = spi->controller; | |
| 2467 | + | |
| 2468 | + if (ctlr->flags & SPI_CONTROLLER_HALF_DUPLEX) | |
| 2469 | + priv->devtype_data.quirks |= MCP251XFD_QUIRK_HALF_DUPLEX; | |
| 2470 | +} | |
| 2471 | + | |
| 2472 | +static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv) | |
| 2473 | +{ | |
| 2474 | + const struct net_device *ndev = priv->ndev; | |
| 2475 | + const struct mcp251xfd_devtype_data *devtype_data; | |
| 2476 | + u32 osc; | |
| 2477 | + int err; | |
| 2478 | + | |
| 2479 | + /* The OSC_LPMEN is only supported on MCP2518FD, so use it to | |
| 2480 | + * autodetect the model. | |
| 2481 | + */ | |
| 2482 | + err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_OSC, | |
| 2483 | + MCP251XFD_REG_OSC_LPMEN, | |
| 2484 | + MCP251XFD_REG_OSC_LPMEN); | |
| 2485 | + if (err) | |
| 2486 | + return err; | |
| 2487 | + | |
| 2488 | + err = regmap_read(priv->map_reg, MCP251XFD_REG_OSC, &osc); | |
| 2489 | + if (err) | |
| 2490 | + return err; | |
| 2491 | + | |
| 2492 | + if (osc & MCP251XFD_REG_OSC_LPMEN) | |
| 2493 | + devtype_data = &mcp251xfd_devtype_data_mcp2518fd; | |
| 2494 | + else | |
| 2495 | + devtype_data = &mcp251xfd_devtype_data_mcp2517fd; | |
| 2496 | + | |
| 2497 | + if (!mcp251xfd_is_251X(priv) && | |
| 2498 | + priv->devtype_data.model != devtype_data->model) { | |
| 2499 | + netdev_info(ndev, | |
| 2500 | + "Detected %s, but firmware specifies a %s. Fixing up.", | |
| 2501 | + __mcp251xfd_get_model_str(devtype_data->model), | |
| 2502 | + mcp251xfd_get_model_str(priv)); | |
| 2503 | + } | |
| 2504 | + priv->devtype_data = *devtype_data; | |
| 2505 | + | |
| 2506 | + /* We need to preserve the Half Duplex Quirk. */ | |
| 2507 | + mcp251xfd_register_quirks(priv); | |
| 2508 | + | |
| 2509 | + /* Re-init regmap with quirks of detected model. */ | |
| 2510 | + return mcp251xfd_regmap_init(priv); | |
| 2511 | +} | |
| 2512 | + | |
| 2513 | +static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv) | |
| 2514 | +{ | |
| 2515 | + int err, rx_pending; | |
| 2516 | + | |
| 2517 | + if (!priv->rx_int) | |
| 2518 | + return 0; | |
| 2519 | + | |
| 2520 | + err = mcp251xfd_chip_rx_int_enable(priv); | |
| 2521 | + if (err) | |
| 2522 | + return err; | |
| 2523 | + | |
| 2524 | + /* Check if RX_INT is properly working. The RX_INT should not | |
| 2525 | + * be active after a softreset. | |
| 2526 | + */ | |
| 2527 | + rx_pending = gpiod_get_value_cansleep(priv->rx_int); | |
| 2528 | + | |
| 2529 | + err = mcp251xfd_chip_rx_int_disable(priv); | |
| 2530 | + if (err) | |
| 2531 | + return err; | |
| 2532 | + | |
| 2533 | + if (!rx_pending) | |
| 2534 | + return 0; | |
| 2535 | + | |
| 2536 | + netdev_info(priv->ndev, | |
| 2537 | + "RX_INT active after softreset, disabling RX_INT support."); | |
| 2538 | + devm_gpiod_put(&priv->spi->dev, priv->rx_int); | |
| 2539 | + priv->rx_int = NULL; | |
| 2540 | + | |
| 2541 | + return 0; | |
| 2542 | +} | |
| 2543 | + | |
| 2544 | +static int | |
| 2545 | +mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, | |
| 2546 | + u32 *dev_id, u32 *effective_speed_hz) | |
| 2547 | +{ | |
| 2548 | + struct mcp251xfd_map_buf_nocrc *buf_rx; | |
| 2549 | + struct mcp251xfd_map_buf_nocrc *buf_tx; | |
| 2550 | + struct spi_transfer xfer[2] = { }; | |
| 2551 | + int err; | |
| 2552 | + | |
| 2553 | + buf_rx = kzalloc(sizeof(*buf_rx), GFP_KERNEL); | |
| 2554 | + if (!buf_rx) | |
| 2555 | + return -ENOMEM; | |
| 2556 | + | |
| 2557 | + buf_tx = kzalloc(sizeof(*buf_tx), GFP_KERNEL); | |
| 2558 | + if (!buf_tx) { | |
| 2559 | + err = -ENOMEM; | |
| 2560 | + goto out_kfree_buf_rx; | |
| 2561 | + } | |
| 2562 | + | |
| 2563 | + xfer[0].tx_buf = buf_tx; | |
| 2564 | + xfer[0].len = sizeof(buf_tx->cmd); | |
| 2565 | + xfer[1].rx_buf = buf_rx->data; | |
| 2566 | + xfer[1].len = sizeof(dev_id); | |
| 2567 | + | |
| 2568 | + mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, MCP251XFD_REG_DEVID); | |
| 2569 | + err = spi_sync_transfer(priv->spi, xfer, ARRAY_SIZE(xfer)); | |
| 2570 | + if (err) | |
| 2571 | + goto out_kfree_buf_tx; | |
| 2572 | + | |
| 2573 | + *dev_id = be32_to_cpup((__be32 *)buf_rx->data); | |
| 2574 | + *effective_speed_hz = xfer->effective_speed_hz; | |
| 2575 | + | |
| 2576 | + out_kfree_buf_tx: | |
| 2577 | + kfree(buf_tx); | |
| 2578 | + out_kfree_buf_rx: | |
| 2579 | + kfree(buf_rx); | |
| 2580 | + | |
| 2581 | + return 0; | |
| 2582 | +} | |
| 2583 | + | |
| 2584 | +#define MCP251XFD_QUIRK_ACTIVE(quirk) \ | |
| 2585 | + (priv->devtype_data.quirks & MCP251XFD_QUIRK_##quirk ? '+' : '-') | |
| 2586 | + | |
| 2587 | +static int | |
| 2588 | +mcp251xfd_register_done(const struct mcp251xfd_priv *priv) | |
| 2589 | +{ | |
| 2590 | + u32 dev_id, effective_speed_hz; | |
| 2591 | + int err; | |
| 2592 | + | |
| 2593 | + err = mcp251xfd_register_get_dev_id(priv, &dev_id, | |
| 2594 | + &effective_speed_hz); | |
| 2595 | + if (err) | |
| 2596 | + return err; | |
| 2597 | + | |
| 2598 | + netdev_info(priv->ndev, | |
| 2599 | + "%s rev%lu.%lu (%cRX_INT %cMAB_NO_WARN %cCRC_REG %cCRC_RX %cCRC_TX %cECC %cHD c:%u.%02uMHz m:%u.%02uMHz r:%u.%02uMHz e:%u.%02uMHz) successfully initialized.\n", | |
| 2600 | + mcp251xfd_get_model_str(priv), | |
| 2601 | + FIELD_GET(MCP251XFD_REG_DEVID_ID_MASK, dev_id), | |
| 2602 | + FIELD_GET(MCP251XFD_REG_DEVID_REV_MASK, dev_id), | |
| 2603 | + priv->rx_int ? '+' : '-', | |
| 2604 | + MCP251XFD_QUIRK_ACTIVE(MAB_NO_WARN), | |
| 2605 | + MCP251XFD_QUIRK_ACTIVE(CRC_REG), | |
| 2606 | + MCP251XFD_QUIRK_ACTIVE(CRC_RX), | |
| 2607 | + MCP251XFD_QUIRK_ACTIVE(CRC_TX), | |
| 2608 | + MCP251XFD_QUIRK_ACTIVE(ECC), | |
| 2609 | + MCP251XFD_QUIRK_ACTIVE(HALF_DUPLEX), | |
| 2610 | + priv->can.clock.freq / 1000000, | |
| 2611 | + priv->can.clock.freq % 1000000 / 1000 / 10, | |
| 2612 | + priv->spi_max_speed_hz_orig / 1000000, | |
| 2613 | + priv->spi_max_speed_hz_orig % 1000000 / 1000 / 10, | |
| 2614 | + priv->spi->max_speed_hz / 1000000, | |
| 2615 | + priv->spi->max_speed_hz % 1000000 / 1000 / 10, | |
| 2616 | + effective_speed_hz / 1000000, | |
| 2617 | + effective_speed_hz % 1000000 / 1000 / 10); | |
| 2618 | + | |
| 2619 | + return 0; | |
| 2620 | +} | |
| 2621 | + | |
| 2622 | +static int mcp251xfd_register(struct mcp251xfd_priv *priv) | |
| 2623 | +{ | |
| 2624 | + struct net_device *ndev = priv->ndev; | |
| 2625 | + int err; | |
| 2626 | + | |
| 2627 | + err = mcp251xfd_clks_and_vdd_enable(priv); | |
| 2628 | + if (err) | |
| 2629 | + return err; | |
| 2630 | + | |
| 2631 | + pm_runtime_get_noresume(ndev->dev.parent); | |
| 2632 | + err = pm_runtime_set_active(ndev->dev.parent); | |
| 2633 | + if (err) | |
| 2634 | + goto out_runtime_put_noidle; | |
| 2635 | + pm_runtime_enable(ndev->dev.parent); | |
| 2636 | + | |
| 2637 | + mcp251xfd_register_quirks(priv); | |
| 2638 | + | |
| 2639 | + err = mcp251xfd_chip_softreset(priv); | |
| 2640 | + if (err == -ENODEV) | |
| 2641 | + goto out_runtime_disable; | |
| 2642 | + if (err) | |
| 2643 | + goto out_chip_set_mode_sleep; | |
| 2644 | + | |
| 2645 | + err = mcp251xfd_register_chip_detect(priv); | |
| 2646 | + if (err) | |
| 2647 | + goto out_chip_set_mode_sleep; | |
| 2648 | + | |
| 2649 | + err = mcp251xfd_register_check_rx_int(priv); | |
| 2650 | + if (err) | |
| 2651 | + goto out_chip_set_mode_sleep; | |
| 2652 | + | |
| 2653 | + err = register_candev(ndev); | |
| 2654 | + if (err) | |
| 2655 | + goto out_chip_set_mode_sleep; | |
| 2656 | + | |
| 2657 | + err = mcp251xfd_register_done(priv); | |
| 2658 | + if (err) | |
| 2659 | + goto out_unregister_candev; | |
| 2660 | + | |
| 2661 | + /* Put controller into sleep mode and let pm_runtime_put() | |
| 2662 | + * disable the clocks and vdd. If CONFIG_PM is not enabled, | |
| 2663 | + * the clocks and vdd will stay powered. | |
| 2664 | + */ | |
| 2665 | + err = mcp251xfd_chip_set_mode(priv, MCP251XFD_REG_CON_MODE_SLEEP); | |
| 2666 | + if (err) | |
| 2667 | + goto out_unregister_candev; | |
| 2668 | + | |
| 2669 | + pm_runtime_put(ndev->dev.parent); | |
| 2670 | + | |
| 2671 | + return 0; | |
| 2672 | + | |
| 2673 | + out_unregister_candev: | |
| 2674 | + unregister_candev(ndev); | |
| 2675 | + out_chip_set_mode_sleep: | |
| 2676 | + mcp251xfd_chip_set_mode(priv, MCP251XFD_REG_CON_MODE_SLEEP); | |
| 2677 | + out_runtime_disable: | |
| 2678 | + pm_runtime_disable(ndev->dev.parent); | |
| 2679 | + out_runtime_put_noidle: | |
| 2680 | + pm_runtime_put_noidle(ndev->dev.parent); | |
| 2681 | + mcp251xfd_clks_and_vdd_disable(priv); | |
| 2682 | + | |
| 2683 | + return err; | |
| 2684 | +} | |
| 2685 | + | |
| 2686 | +static inline void mcp251xfd_unregister(struct mcp251xfd_priv *priv) | |
| 2687 | +{ | |
| 2688 | + struct net_device *ndev = priv->ndev; | |
| 2689 | + | |
| 2690 | + unregister_candev(ndev); | |
| 2691 | + | |
| 2692 | + pm_runtime_get_sync(ndev->dev.parent); | |
| 2693 | + pm_runtime_put_noidle(ndev->dev.parent); | |
| 2694 | + mcp251xfd_clks_and_vdd_disable(priv); | |
| 2695 | + pm_runtime_disable(ndev->dev.parent); | |
| 2696 | +} | |
| 2697 | + | |
| 2698 | +static const struct of_device_id mcp251xfd_of_match[] = { | |
| 2699 | + { | |
| 2700 | + .compatible = "microchip,mcp2517fd", | |
| 2701 | + .data = &mcp251xfd_devtype_data_mcp2517fd, | |
| 2702 | + }, { | |
| 2703 | + .compatible = "microchip,mcp2518fd", | |
| 2704 | + .data = &mcp251xfd_devtype_data_mcp2518fd, | |
| 2705 | + }, { | |
| 2706 | + .compatible = "microchip,mcp251xfd", | |
| 2707 | + .data = &mcp251xfd_devtype_data_mcp251xfd, | |
| 2708 | + }, { | |
| 2709 | + /* sentinel */ | |
| 2710 | + }, | |
| 2711 | +}; | |
| 2712 | +MODULE_DEVICE_TABLE(of, mcp251xfd_of_match); | |
| 2713 | + | |
| 2714 | +static const struct spi_device_id mcp251xfd_id_table[] = { | |
| 2715 | + { | |
| 2716 | + .name = "mcp2517fd", | |
| 2717 | + .driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp2517fd, | |
| 2718 | + }, { | |
| 2719 | + .name = "mcp2518fd", | |
| 2720 | + .driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp2518fd, | |
| 2721 | + }, { | |
| 2722 | + .name = "mcp251xfd", | |
| 2723 | + .driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251xfd, | |
| 2724 | + }, { | |
| 2725 | + /* sentinel */ | |
| 2726 | + }, | |
| 2727 | +}; | |
| 2728 | +MODULE_DEVICE_TABLE(spi, mcp251xfd_id_table); | |
| 2729 | + | |
| 2730 | +static int mcp251xfd_probe(struct spi_device *spi) | |
| 2731 | +{ | |
| 2732 | + const void *match; | |
| 2733 | + struct net_device *ndev; | |
| 2734 | + struct mcp251xfd_priv *priv; | |
| 2735 | + struct gpio_desc *rx_int; | |
| 2736 | + struct regulator *reg_vdd, *reg_xceiver; | |
| 2737 | + struct clk *clk; | |
| 2738 | + u32 freq; | |
| 2739 | + int err; | |
| 2740 | + | |
| 2741 | + rx_int = devm_gpiod_get_optional(&spi->dev, "microchip,rx-int", | |
| 2742 | + GPIOD_IN); | |
| 2743 | + if (PTR_ERR(rx_int) == -EPROBE_DEFER) | |
| 2744 | + return -EPROBE_DEFER; | |
| 2745 | + else if (IS_ERR(rx_int)) | |
| 2746 | + return PTR_ERR(rx_int); | |
| 2747 | + | |
| 2748 | + reg_vdd = devm_regulator_get_optional(&spi->dev, "vdd"); | |
| 2749 | + if (PTR_ERR(reg_vdd) == -EPROBE_DEFER) | |
| 2750 | + return -EPROBE_DEFER; | |
| 2751 | + else if (PTR_ERR(reg_vdd) == -ENODEV) | |
| 2752 | + reg_vdd = NULL; | |
| 2753 | + else if (IS_ERR(reg_vdd)) | |
| 2754 | + return PTR_ERR(reg_vdd); | |
| 2755 | + | |
| 2756 | + reg_xceiver = devm_regulator_get_optional(&spi->dev, "xceiver"); | |
| 2757 | + if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER) | |
| 2758 | + return -EPROBE_DEFER; | |
| 2759 | + else if (PTR_ERR(reg_xceiver) == -ENODEV) | |
| 2760 | + reg_xceiver = NULL; | |
| 2761 | + else if (IS_ERR(reg_xceiver)) | |
| 2762 | + return PTR_ERR(reg_xceiver); | |
| 2763 | + | |
| 2764 | + clk = devm_clk_get(&spi->dev, NULL); | |
| 2765 | + if (IS_ERR(clk)) { | |
| 2766 | + dev_err(&spi->dev, "No Oscillator (clock) defined.\n"); | |
| 2767 | + return PTR_ERR(clk); | |
| 2768 | + } | |
| 2769 | + freq = clk_get_rate(clk); | |
| 2770 | + | |
| 2771 | + /* Sanity check */ | |
| 2772 | + if (freq < MCP251XFD_SYSCLOCK_HZ_MIN || | |
| 2773 | + freq > MCP251XFD_SYSCLOCK_HZ_MAX) { | |
| 2774 | + dev_err(&spi->dev, | |
| 2775 | + "Oscillator frequency (%u Hz) is too low or high.\n", | |
| 2776 | + freq); | |
| 2777 | + return -ERANGE; | |
| 2778 | + } | |
| 2779 | + | |
| 2780 | + if (freq <= MCP251XFD_SYSCLOCK_HZ_MAX / MCP251XFD_OSC_PLL_MULTIPLIER) { | |
| 2781 | + dev_err(&spi->dev, | |
| 2782 | + "Oscillator frequency (%u Hz) is too low and PLL is not supported.\n", | |
| 2783 | + freq); | |
| 2784 | + return -ERANGE; | |
| 2785 | + } | |
| 2786 | + | |
| 2787 | + ndev = alloc_candev(sizeof(struct mcp251xfd_priv), | |
| 2788 | + MCP251XFD_TX_OBJ_NUM_MAX); | |
| 2789 | + if (!ndev) | |
| 2790 | + return -ENOMEM; | |
| 2791 | + | |
| 2792 | + SET_NETDEV_DEV(ndev, &spi->dev); | |
| 2793 | + | |
| 2794 | + ndev->netdev_ops = &mcp251xfd_netdev_ops; | |
| 2795 | + ndev->irq = spi->irq; | |
| 2796 | + ndev->flags |= IFF_ECHO; | |
| 2797 | + | |
| 2798 | + priv = netdev_priv(ndev); | |
| 2799 | + spi_set_drvdata(spi, priv); | |
| 2800 | + priv->can.clock.freq = freq; | |
| 2801 | + priv->can.do_set_mode = mcp251xfd_set_mode; | |
| 2802 | + priv->can.do_get_berr_counter = mcp251xfd_get_berr_counter; | |
| 2803 | + priv->can.bittiming_const = &mcp251xfd_bittiming_const; | |
| 2804 | + priv->can.data_bittiming_const = &mcp251xfd_data_bittiming_const; | |
| 2805 | + priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | | |
| 2806 | + CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_FD | | |
| 2807 | + CAN_CTRLMODE_FD_NON_ISO; | |
| 2808 | + priv->ndev = ndev; | |
| 2809 | + priv->spi = spi; | |
| 2810 | + priv->rx_int = rx_int; | |
| 2811 | + priv->clk = clk; | |
| 2812 | + priv->reg_vdd = reg_vdd; | |
| 2813 | + priv->reg_xceiver = reg_xceiver; | |
| 2814 | + | |
| 2815 | + match = device_get_match_data(&spi->dev); | |
| 2816 | + if (match) | |
| 2817 | + priv->devtype_data = *(struct mcp251xfd_devtype_data *)match; | |
| 2818 | + else | |
| 2819 | + priv->devtype_data = *(struct mcp251xfd_devtype_data *) | |
| 2820 | + spi_get_device_id(spi)->driver_data; | |
| 2821 | + | |
| 2822 | + /* Errata Reference: | |
| 2823 | + * mcp2517fd: DS80000789B, mcp2518fd: DS80000792C 4. | |
| 2824 | + * | |
| 2825 | + * The SPI can write corrupted data to the RAM at fast SPI | |
| 2826 | + * speeds: | |
| 2827 | + * | |
| 2828 | + * Simultaneous activity on the CAN bus while writing data to | |
| 2829 | + * RAM via the SPI interface, with high SCK frequency, can | |
| 2830 | + * lead to corrupted data being written to RAM. | |
| 2831 | + * | |
| 2832 | + * Fix/Work Around: | |
| 2833 | + * Ensure that FSCK is less than or equal to 0.85 * | |
| 2834 | + * (FSYSCLK/2). | |
| 2835 | + * | |
| 2836 | + * Known good and bad combinations are: | |
| 2837 | + * | |
| 2838 | + * MCP ext-clk SoC SPI SPI-clk max-clk parent-clk Status config | |
| 2839 | + * | |
| 2840 | + * 2518 20 MHz allwinner,sun8i-h3 allwinner,sun8i-h3-spi 8333333 Hz 83.33% 600000000 Hz good assigned-clocks = <&ccu CLK_SPIx> | |
| 2841 | + * 2518 20 MHz allwinner,sun8i-h3 allwinner,sun8i-h3-spi 9375000 Hz 93.75% 600000000 Hz bad assigned-clocks = <&ccu CLK_SPIx> | |
| 2842 | + * 2518 40 MHz allwinner,sun8i-h3 allwinner,sun8i-h3-spi 16666667 Hz 83.33% 600000000 Hz good assigned-clocks = <&ccu CLK_SPIx> | |
| 2843 | + * 2518 40 MHz allwinner,sun8i-h3 allwinner,sun8i-h3-spi 18750000 Hz 93.75% 600000000 Hz bad assigned-clocks = <&ccu CLK_SPIx> | |
| 2844 | + * 2517 20 MHz fsl,imx8mm fsl,imx51-ecspi 8333333 Hz 83.33% 16666667 Hz good assigned-clocks = <&clk IMX8MM_CLK_ECSPIx_ROOT> | |
| 2845 | + * 2517 20 MHz fsl,imx8mm fsl,imx51-ecspi 9523809 Hz 95.34% 28571429 Hz bad assigned-clocks = <&clk IMX8MM_CLK_ECSPIx_ROOT> | |
| 2846 | + * 2517 40 MHz atmel,sama5d27 atmel,at91rm9200-spi 16400000 Hz 82.00% 82000000 Hz good default | |
| 2847 | + * 2518 40 MHz atmel,sama5d27 atmel,at91rm9200-spi 16400000 Hz 82.00% 82000000 Hz good default | |
| 2848 | + * | |
| 2849 | + */ | |
| 2850 | + priv->spi_max_speed_hz_orig = spi->max_speed_hz; | |
| 2851 | + spi->max_speed_hz = min(spi->max_speed_hz, freq / 2 / 1000 * 850); | |
| 2852 | + spi->bits_per_word = 8; | |
| 2853 | + spi->rt = true; | |
| 2854 | + err = spi_setup(spi); | |
| 2855 | + if (err) | |
| 2856 | + goto out_free_candev; | |
| 2857 | + | |
| 2858 | + err = mcp251xfd_regmap_init(priv); | |
| 2859 | + if (err) | |
| 2860 | + goto out_free_candev; | |
| 2861 | + | |
| 2862 | + err = can_rx_offload_add_manual(ndev, &priv->offload, | |
| 2863 | + MCP251XFD_NAPI_WEIGHT); | |
| 2864 | + if (err) | |
| 2865 | + goto out_free_candev; | |
| 2866 | + | |
| 2867 | + err = mcp251xfd_register(priv); | |
| 2868 | + if (err) | |
| 2869 | + goto out_free_candev; | |
| 2870 | + | |
| 2871 | + return 0; | |
| 2872 | + | |
| 2873 | + out_free_candev: | |
| 2874 | + spi->max_speed_hz = priv->spi_max_speed_hz_orig; | |
| 2875 | + | |
| 2876 | + free_candev(ndev); | |
| 2877 | + | |
| 2878 | + return err; | |
| 2879 | +} | |
| 2880 | + | |
| 2881 | +static int mcp251xfd_remove(struct spi_device *spi) | |
| 2882 | +{ | |
| 2883 | + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); | |
| 2884 | + struct net_device *ndev = priv->ndev; | |
| 2885 | + | |
| 2886 | + can_rx_offload_del(&priv->offload); | |
| 2887 | + mcp251xfd_unregister(priv); | |
| 2888 | + spi->max_speed_hz = priv->spi_max_speed_hz_orig; | |
| 2889 | + free_candev(ndev); | |
| 2890 | + | |
| 2891 | + return 0; | |
| 2892 | +} | |
| 2893 | + | |
| 2894 | +static int __maybe_unused mcp251xfd_runtime_suspend(struct device *device) | |
| 2895 | +{ | |
| 2896 | + const struct mcp251xfd_priv *priv = dev_get_drvdata(device); | |
| 2897 | + | |
| 2898 | + return mcp251xfd_clks_and_vdd_disable(priv); | |
| 2899 | +} | |
| 2900 | + | |
| 2901 | +static int __maybe_unused mcp251xfd_runtime_resume(struct device *device) | |
| 2902 | +{ | |
| 2903 | + const struct mcp251xfd_priv *priv = dev_get_drvdata(device); | |
| 2904 | + | |
| 2905 | + return mcp251xfd_clks_and_vdd_enable(priv); | |
| 2906 | +} | |
| 2907 | + | |
| 2908 | +static const struct dev_pm_ops mcp251xfd_pm_ops = { | |
| 2909 | + SET_RUNTIME_PM_OPS(mcp251xfd_runtime_suspend, | |
| 2910 | + mcp251xfd_runtime_resume, NULL) | |
| 2911 | +}; | |
| 2912 | + | |
| 2913 | +static struct spi_driver mcp251xfd_driver = { | |
| 2914 | + .driver = { | |
| 2915 | + .name = DEVICE_NAME, | |
| 2916 | + .pm = &mcp251xfd_pm_ops, | |
| 2917 | + .of_match_table = mcp251xfd_of_match, | |
| 2918 | + }, | |
| 2919 | + .probe = mcp251xfd_probe, | |
| 2920 | + .remove = mcp251xfd_remove, | |
| 2921 | + .id_table = mcp251xfd_id_table, | |
| 2922 | +}; | |
| 2923 | +module_spi_driver(mcp251xfd_driver); | |
| 2924 | + | |
| 2925 | +MODULE_AUTHOR("Marc Kleine-Budde <mkl@pengutronix.de>"); | |
| 2926 | +MODULE_DESCRIPTION("Microchip MCP251xFD Family CAN controller driver"); | |
| 2927 | +MODULE_LICENSE("GPL v2"); | |
| @@ -0,0 +1,89 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// | |
| 3 | +// mcp251xfd - Microchip MCP251xFD Family CAN controller driver | |
| 4 | +// | |
| 5 | +// Copyright (c) 2020 Pengutronix, | |
| 6 | +// Marc Kleine-Budde <kernel@pengutronix.de> | |
| 7 | +// | |
| 8 | +// Based on: | |
| 9 | +// | |
| 10 | +// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface | |
| 11 | +// | |
| 12 | +// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> | |
| 13 | +// | |
| 14 | + | |
| 15 | +#include "mcp251xfd.h" | |
| 16 | + | |
| 17 | +/* The standard crc16 in linux/crc16.h is unfortunately not computing | |
| 18 | + * the correct results (left shift vs. right shift). So here an | |
| 19 | + * implementation with a table generated with the help of: | |
| 20 | + * | |
| 21 | + * http://lkml.iu.edu/hypermail/linux/kernel/0508.1/1085.html | |
| 22 | + */ | |
| 23 | +static const u16 mcp251xfd_crc16_table[] = { | |
| 24 | + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, | |
| 25 | + 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, | |
| 26 | + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, | |
| 27 | + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, | |
| 28 | + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, | |
| 29 | + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, | |
| 30 | + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, | |
| 31 | + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, | |
| 32 | + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, | |
| 33 | + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, | |
| 34 | + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, | |
| 35 | + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, | |
| 36 | + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, | |
| 37 | + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, | |
| 38 | + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, | |
| 39 | + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, | |
| 40 | + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, | |
| 41 | + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, | |
| 42 | + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, | |
| 43 | + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, | |
| 44 | + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, | |
| 45 | + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, | |
| 46 | + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, | |
| 47 | + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, | |
| 48 | + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, | |
| 49 | + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, | |
| 50 | + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, | |
| 51 | + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, | |
| 52 | + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, | |
| 53 | + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, | |
| 54 | + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, | |
| 55 | + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 | |
| 56 | +}; | |
| 57 | + | |
| 58 | +static inline u16 mcp251xfd_crc16_byte(u16 crc, const u8 data) | |
| 59 | +{ | |
| 60 | + u8 index = (crc >> 8) ^ data; | |
| 61 | + | |
| 62 | + return (crc << 8) ^ mcp251xfd_crc16_table[index]; | |
| 63 | +} | |
| 64 | + | |
| 65 | +static u16 mcp251xfd_crc16(u16 crc, u8 const *buffer, size_t len) | |
| 66 | +{ | |
| 67 | + while (len--) | |
| 68 | + crc = mcp251xfd_crc16_byte(crc, *buffer++); | |
| 69 | + | |
| 70 | + return crc; | |
| 71 | +} | |
| 72 | + | |
| 73 | +u16 mcp251xfd_crc16_compute(const void *data, size_t data_size) | |
| 74 | +{ | |
| 75 | + u16 crc = 0xffff; | |
| 76 | + | |
| 77 | + return mcp251xfd_crc16(crc, data, data_size); | |
| 78 | +} | |
| 79 | + | |
| 80 | +u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size, | |
| 81 | + const void *data, size_t data_size) | |
| 82 | +{ | |
| 83 | + u16 crc; | |
| 84 | + | |
| 85 | + crc = mcp251xfd_crc16_compute(cmd, cmd_size); | |
| 86 | + crc = mcp251xfd_crc16(crc, data, data_size); | |
| 87 | + | |
| 88 | + return crc; | |
| 89 | +} | |
| @@ -0,0 +1,556 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +// | |
| 3 | +// mcp251xfd - Microchip MCP251xFD Family CAN controller driver | |
| 4 | +// | |
| 5 | +// Copyright (c) 2019, 2020 Pengutronix, | |
| 6 | +// Marc Kleine-Budde <kernel@pengutronix.de> | |
| 7 | +// | |
| 8 | + | |
| 9 | +#include "mcp251xfd.h" | |
| 10 | + | |
| 11 | +#include <asm/unaligned.h> | |
| 12 | + | |
| 13 | +static const struct regmap_config mcp251xfd_regmap_crc; | |
| 14 | + | |
| 15 | +static int | |
| 16 | +mcp251xfd_regmap_nocrc_write(void *context, const void *data, size_t count) | |
| 17 | +{ | |
| 18 | + struct spi_device *spi = context; | |
| 19 | + | |
| 20 | + return spi_write(spi, data, count); | |
| 21 | +} | |
| 22 | + | |
| 23 | +static int | |
| 24 | +mcp251xfd_regmap_nocrc_gather_write(void *context, | |
| 25 | + const void *reg, size_t reg_len, | |
| 26 | + const void *val, size_t val_len) | |
| 27 | +{ | |
| 28 | + struct spi_device *spi = context; | |
| 29 | + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); | |
| 30 | + struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; | |
| 31 | + struct spi_transfer xfer[] = { | |
| 32 | + { | |
| 33 | + .tx_buf = buf_tx, | |
| 34 | + .len = sizeof(buf_tx->cmd) + val_len, | |
| 35 | + }, | |
| 36 | + }; | |
| 37 | + | |
| 38 | + BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); | |
| 39 | + | |
| 40 | + if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && | |
| 41 | + reg_len != sizeof(buf_tx->cmd.cmd)) | |
| 42 | + return -EINVAL; | |
| 43 | + | |
| 44 | + memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd)); | |
| 45 | + memcpy(buf_tx->data, val, val_len); | |
| 46 | + | |
| 47 | + return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); | |
| 48 | +} | |
| 49 | + | |
| 50 | +static inline bool mcp251xfd_update_bits_read_reg(unsigned int reg) | |
| 51 | +{ | |
| 52 | + switch (reg) { | |
| 53 | + case MCP251XFD_REG_INT: | |
| 54 | + case MCP251XFD_REG_TEFCON: | |
| 55 | + case MCP251XFD_REG_FIFOCON(MCP251XFD_RX_FIFO(0)): | |
| 56 | + case MCP251XFD_REG_FLTCON(0): | |
| 57 | + case MCP251XFD_REG_ECCSTAT: | |
| 58 | + case MCP251XFD_REG_CRC: | |
| 59 | + return false; | |
| 60 | + case MCP251XFD_REG_CON: | |
| 61 | + case MCP251XFD_REG_FIFOSTA(MCP251XFD_RX_FIFO(0)): | |
| 62 | + case MCP251XFD_REG_OSC: | |
| 63 | + case MCP251XFD_REG_ECCCON: | |
| 64 | + return true; | |
| 65 | + default: | |
| 66 | + WARN(1, "Status of reg 0x%04x unknown.\n", reg); | |
| 67 | + } | |
| 68 | + | |
| 69 | + return true; | |
| 70 | +} | |
| 71 | + | |
| 72 | +static int | |
| 73 | +mcp251xfd_regmap_nocrc_update_bits(void *context, unsigned int reg, | |
| 74 | + unsigned int mask, unsigned int val) | |
| 75 | +{ | |
| 76 | + struct spi_device *spi = context; | |
| 77 | + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); | |
| 78 | + struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx; | |
| 79 | + struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; | |
| 80 | + __le32 orig_le32 = 0, mask_le32, val_le32, tmp_le32; | |
| 81 | + u8 first_byte, last_byte, len; | |
| 82 | + int err; | |
| 83 | + | |
| 84 | + BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16)); | |
| 85 | + BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); | |
| 86 | + | |
| 87 | + if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && | |
| 88 | + mask == 0) | |
| 89 | + return -EINVAL; | |
| 90 | + | |
| 91 | + first_byte = mcp251xfd_first_byte_set(mask); | |
| 92 | + last_byte = mcp251xfd_last_byte_set(mask); | |
| 93 | + len = last_byte - first_byte + 1; | |
| 94 | + | |
| 95 | + if (mcp251xfd_update_bits_read_reg(reg)) { | |
| 96 | + struct spi_transfer xfer[2] = { }; | |
| 97 | + struct spi_message msg; | |
| 98 | + | |
| 99 | + spi_message_init(&msg); | |
| 100 | + spi_message_add_tail(&xfer[0], &msg); | |
| 101 | + | |
| 102 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { | |
| 103 | + xfer[0].tx_buf = buf_tx; | |
| 104 | + xfer[0].len = sizeof(buf_tx->cmd); | |
| 105 | + | |
| 106 | + xfer[1].rx_buf = buf_rx->data; | |
| 107 | + xfer[1].len = len; | |
| 108 | + spi_message_add_tail(&xfer[1], &msg); | |
| 109 | + } else { | |
| 110 | + xfer[0].tx_buf = buf_tx; | |
| 111 | + xfer[0].rx_buf = buf_rx; | |
| 112 | + xfer[0].len = sizeof(buf_tx->cmd) + len; | |
| 113 | + | |
| 114 | + if (MCP251XFD_SANITIZE_SPI) | |
| 115 | + memset(buf_tx->data, 0x0, len); | |
| 116 | + } | |
| 117 | + | |
| 118 | + mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, reg + first_byte); | |
| 119 | + err = spi_sync(spi, &msg); | |
| 120 | + if (err) | |
| 121 | + return err; | |
| 122 | + | |
| 123 | + memcpy(&orig_le32, buf_rx->data, len); | |
| 124 | + } | |
| 125 | + | |
| 126 | + mask_le32 = cpu_to_le32(mask >> BITS_PER_BYTE * first_byte); | |
| 127 | + val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte); | |
| 128 | + | |
| 129 | + tmp_le32 = orig_le32 & ~mask_le32; | |
| 130 | + tmp_le32 |= val_le32 & mask_le32; | |
| 131 | + | |
| 132 | + mcp251xfd_spi_cmd_write_nocrc(&buf_tx->cmd, reg + first_byte); | |
| 133 | + memcpy(buf_tx->data, &tmp_le32, len); | |
| 134 | + | |
| 135 | + return spi_write(spi, buf_tx, sizeof(buf_tx->cmd) + len); | |
| 136 | +} | |
| 137 | + | |
| 138 | +static int | |
| 139 | +mcp251xfd_regmap_nocrc_read(void *context, | |
| 140 | + const void *reg, size_t reg_len, | |
| 141 | + void *val_buf, size_t val_len) | |
| 142 | +{ | |
| 143 | + struct spi_device *spi = context; | |
| 144 | + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); | |
| 145 | + struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx; | |
| 146 | + struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; | |
| 147 | + struct spi_transfer xfer[2] = { }; | |
| 148 | + struct spi_message msg; | |
| 149 | + int err; | |
| 150 | + | |
| 151 | + BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16)); | |
| 152 | + BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); | |
| 153 | + | |
| 154 | + if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && | |
| 155 | + reg_len != sizeof(buf_tx->cmd.cmd)) | |
| 156 | + return -EINVAL; | |
| 157 | + | |
| 158 | + spi_message_init(&msg); | |
| 159 | + spi_message_add_tail(&xfer[0], &msg); | |
| 160 | + | |
| 161 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { | |
| 162 | + xfer[0].tx_buf = reg; | |
| 163 | + xfer[0].len = sizeof(buf_tx->cmd); | |
| 164 | + | |
| 165 | + xfer[1].rx_buf = val_buf; | |
| 166 | + xfer[1].len = val_len; | |
| 167 | + spi_message_add_tail(&xfer[1], &msg); | |
| 168 | + } else { | |
| 169 | + xfer[0].tx_buf = buf_tx; | |
| 170 | + xfer[0].rx_buf = buf_rx; | |
| 171 | + xfer[0].len = sizeof(buf_tx->cmd) + val_len; | |
| 172 | + | |
| 173 | + memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd)); | |
| 174 | + if (MCP251XFD_SANITIZE_SPI) | |
| 175 | + memset(buf_tx->data, 0x0, val_len); | |
| 176 | + }; | |
| 177 | + | |
| 178 | + err = spi_sync(spi, &msg); | |
| 179 | + if (err) | |
| 180 | + return err; | |
| 181 | + | |
| 182 | + if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX)) | |
| 183 | + memcpy(val_buf, buf_rx->data, val_len); | |
| 184 | + | |
| 185 | + return 0; | |
| 186 | +} | |
| 187 | + | |
| 188 | +static int | |
| 189 | +mcp251xfd_regmap_crc_gather_write(void *context, | |
| 190 | + const void *reg_p, size_t reg_len, | |
| 191 | + const void *val, size_t val_len) | |
| 192 | +{ | |
| 193 | + struct spi_device *spi = context; | |
| 194 | + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); | |
| 195 | + struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; | |
| 196 | + struct spi_transfer xfer[] = { | |
| 197 | + { | |
| 198 | + .tx_buf = buf_tx, | |
| 199 | + .len = sizeof(buf_tx->cmd) + val_len + | |
| 200 | + sizeof(buf_tx->crc), | |
| 201 | + }, | |
| 202 | + }; | |
| 203 | + u16 reg = *(u16 *)reg_p; | |
| 204 | + u16 crc; | |
| 205 | + | |
| 206 | + BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); | |
| 207 | + | |
| 208 | + if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && | |
| 209 | + reg_len != sizeof(buf_tx->cmd.cmd) + | |
| 210 | + mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE) | |
| 211 | + return -EINVAL; | |
| 212 | + | |
| 213 | + mcp251xfd_spi_cmd_write_crc(&buf_tx->cmd, reg, val_len); | |
| 214 | + memcpy(buf_tx->data, val, val_len); | |
| 215 | + | |
| 216 | + crc = mcp251xfd_crc16_compute(buf_tx, sizeof(buf_tx->cmd) + val_len); | |
| 217 | + put_unaligned_be16(crc, buf_tx->data + val_len); | |
| 218 | + | |
| 219 | + return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); | |
| 220 | +} | |
| 221 | + | |
| 222 | +static int | |
| 223 | +mcp251xfd_regmap_crc_write(void *context, | |
| 224 | + const void *data, size_t count) | |
| 225 | +{ | |
| 226 | + const size_t data_offset = sizeof(__be16) + | |
| 227 | + mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE; | |
| 228 | + | |
| 229 | + return mcp251xfd_regmap_crc_gather_write(context, | |
| 230 | + data, data_offset, | |
| 231 | + data + data_offset, | |
| 232 | + count - data_offset); | |
| 233 | +} | |
| 234 | + | |
| 235 | +static int | |
| 236 | +mcp251xfd_regmap_crc_read_one(struct mcp251xfd_priv *priv, | |
| 237 | + struct spi_message *msg, unsigned int data_len) | |
| 238 | +{ | |
| 239 | + const struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx; | |
| 240 | + const struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; | |
| 241 | + u16 crc_received, crc_calculated; | |
| 242 | + int err; | |
| 243 | + | |
| 244 | + BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8)); | |
| 245 | + BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); | |
| 246 | + | |
| 247 | + err = spi_sync(priv->spi, msg); | |
| 248 | + if (err) | |
| 249 | + return err; | |
| 250 | + | |
| 251 | + crc_received = get_unaligned_be16(buf_rx->data + data_len); | |
| 252 | + crc_calculated = mcp251xfd_crc16_compute2(&buf_tx->cmd, | |
| 253 | + sizeof(buf_tx->cmd), | |
| 254 | + buf_rx->data, | |
| 255 | + data_len); | |
| 256 | + if (crc_received != crc_calculated) | |
| 257 | + return -EBADMSG; | |
| 258 | + | |
| 259 | + return 0; | |
| 260 | +} | |
| 261 | + | |
| 262 | +static int | |
| 263 | +mcp251xfd_regmap_crc_read(void *context, | |
| 264 | + const void *reg_p, size_t reg_len, | |
| 265 | + void *val_buf, size_t val_len) | |
| 266 | +{ | |
| 267 | + struct spi_device *spi = context; | |
| 268 | + struct mcp251xfd_priv *priv = spi_get_drvdata(spi); | |
| 269 | + struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx; | |
| 270 | + struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; | |
| 271 | + struct spi_transfer xfer[2] = { }; | |
| 272 | + struct spi_message msg; | |
| 273 | + u16 reg = *(u16 *)reg_p; | |
| 274 | + int i, err; | |
| 275 | + | |
| 276 | + BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8)); | |
| 277 | + BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); | |
| 278 | + | |
| 279 | + if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && | |
| 280 | + reg_len != sizeof(buf_tx->cmd.cmd) + | |
| 281 | + mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE) | |
| 282 | + return -EINVAL; | |
| 283 | + | |
| 284 | + spi_message_init(&msg); | |
| 285 | + spi_message_add_tail(&xfer[0], &msg); | |
| 286 | + | |
| 287 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { | |
| 288 | + xfer[0].tx_buf = buf_tx; | |
| 289 | + xfer[0].len = sizeof(buf_tx->cmd); | |
| 290 | + | |
| 291 | + xfer[1].rx_buf = buf_rx->data; | |
| 292 | + xfer[1].len = val_len + sizeof(buf_tx->crc); | |
| 293 | + spi_message_add_tail(&xfer[1], &msg); | |
| 294 | + } else { | |
| 295 | + xfer[0].tx_buf = buf_tx; | |
| 296 | + xfer[0].rx_buf = buf_rx; | |
| 297 | + xfer[0].len = sizeof(buf_tx->cmd) + val_len + | |
| 298 | + sizeof(buf_tx->crc); | |
| 299 | + | |
| 300 | + if (MCP251XFD_SANITIZE_SPI) | |
| 301 | + memset(buf_tx->data, 0x0, val_len + | |
| 302 | + sizeof(buf_tx->crc)); | |
| 303 | + } | |
| 304 | + | |
| 305 | + mcp251xfd_spi_cmd_read_crc(&buf_tx->cmd, reg, val_len); | |
| 306 | + | |
| 307 | + for (i = 0; i < MCP251XFD_READ_CRC_RETRIES_MAX; i++) { | |
| 308 | + err = mcp251xfd_regmap_crc_read_one(priv, &msg, val_len); | |
| 309 | + if (!err) | |
| 310 | + goto out; | |
| 311 | + if (err != -EBADMSG) | |
| 312 | + return err; | |
| 313 | + | |
| 314 | + /* MCP251XFD_REG_OSC is the first ever reg we read from. | |
| 315 | + * | |
| 316 | + * The chip may be in deep sleep and this SPI transfer | |
| 317 | + * (i.e. the assertion of the CS) will wake the chip | |
| 318 | + * up. This takes about 3ms. The CRC of this transfer | |
| 319 | + * is wrong. | |
| 320 | + * | |
| 321 | + * Or there isn't a chip at all, in this case the CRC | |
| 322 | + * will be wrong, too. | |
| 323 | + * | |
| 324 | + * In both cases ignore the CRC and copy the read data | |
| 325 | + * to the caller. It will take care of both cases. | |
| 326 | + * | |
| 327 | + */ | |
| 328 | + if (reg == MCP251XFD_REG_OSC) { | |
| 329 | + err = 0; | |
| 330 | + goto out; | |
| 331 | + } | |
| 332 | + | |
| 333 | + netdev_dbg(priv->ndev, | |
| 334 | + "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x) retrying.\n", | |
| 335 | + reg, val_len, (int)val_len, buf_rx->data, | |
| 336 | + get_unaligned_be16(buf_rx->data + val_len)); | |
| 337 | + } | |
| 338 | + | |
| 339 | + if (err) { | |
| 340 | + netdev_info(priv->ndev, | |
| 341 | + "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x).\n", | |
| 342 | + reg, val_len, (int)val_len, buf_rx->data, | |
| 343 | + get_unaligned_be16(buf_rx->data + val_len)); | |
| 344 | + | |
| 345 | + return err; | |
| 346 | + } | |
| 347 | + out: | |
| 348 | + memcpy(val_buf, buf_rx->data, val_len); | |
| 349 | + | |
| 350 | + return 0; | |
| 351 | +} | |
| 352 | + | |
| 353 | +static const struct regmap_range mcp251xfd_reg_table_yes_range[] = { | |
| 354 | + regmap_reg_range(0x000, 0x2ec), /* CAN FD Controller Module SFR */ | |
| 355 | + regmap_reg_range(0x400, 0xbfc), /* RAM */ | |
| 356 | + regmap_reg_range(0xe00, 0xe14), /* MCP2517/18FD SFR */ | |
| 357 | +}; | |
| 358 | + | |
| 359 | +static const struct regmap_access_table mcp251xfd_reg_table = { | |
| 360 | + .yes_ranges = mcp251xfd_reg_table_yes_range, | |
| 361 | + .n_yes_ranges = ARRAY_SIZE(mcp251xfd_reg_table_yes_range), | |
| 362 | +}; | |
| 363 | + | |
| 364 | +static const struct regmap_config mcp251xfd_regmap_nocrc = { | |
| 365 | + .name = "nocrc", | |
| 366 | + .reg_bits = 16, | |
| 367 | + .reg_stride = 4, | |
| 368 | + .pad_bits = 0, | |
| 369 | + .val_bits = 32, | |
| 370 | + .max_register = 0xffc, | |
| 371 | + .wr_table = &mcp251xfd_reg_table, | |
| 372 | + .rd_table = &mcp251xfd_reg_table, | |
| 373 | + .cache_type = REGCACHE_NONE, | |
| 374 | + .read_flag_mask = (__force unsigned long) | |
| 375 | + cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ), | |
| 376 | + .write_flag_mask = (__force unsigned long) | |
| 377 | + cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE), | |
| 378 | +}; | |
| 379 | + | |
| 380 | +static const struct regmap_bus mcp251xfd_bus_nocrc = { | |
| 381 | + .write = mcp251xfd_regmap_nocrc_write, | |
| 382 | + .gather_write = mcp251xfd_regmap_nocrc_gather_write, | |
| 383 | + .reg_update_bits = mcp251xfd_regmap_nocrc_update_bits, | |
| 384 | + .read = mcp251xfd_regmap_nocrc_read, | |
| 385 | + .reg_format_endian_default = REGMAP_ENDIAN_BIG, | |
| 386 | + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, | |
| 387 | + .max_raw_read = sizeof_field(struct mcp251xfd_map_buf_nocrc, data), | |
| 388 | + .max_raw_write = sizeof_field(struct mcp251xfd_map_buf_nocrc, data), | |
| 389 | +}; | |
| 390 | + | |
| 391 | +static const struct regmap_config mcp251xfd_regmap_crc = { | |
| 392 | + .name = "crc", | |
| 393 | + .reg_bits = 16, | |
| 394 | + .reg_stride = 4, | |
| 395 | + .pad_bits = 16, /* keep data bits aligned */ | |
| 396 | + .val_bits = 32, | |
| 397 | + .max_register = 0xffc, | |
| 398 | + .wr_table = &mcp251xfd_reg_table, | |
| 399 | + .rd_table = &mcp251xfd_reg_table, | |
| 400 | + .cache_type = REGCACHE_NONE, | |
| 401 | +}; | |
| 402 | + | |
| 403 | +static const struct regmap_bus mcp251xfd_bus_crc = { | |
| 404 | + .write = mcp251xfd_regmap_crc_write, | |
| 405 | + .gather_write = mcp251xfd_regmap_crc_gather_write, | |
| 406 | + .read = mcp251xfd_regmap_crc_read, | |
| 407 | + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, | |
| 408 | + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, | |
| 409 | + .max_raw_read = sizeof_field(struct mcp251xfd_map_buf_crc, data), | |
| 410 | + .max_raw_write = sizeof_field(struct mcp251xfd_map_buf_crc, data), | |
| 411 | +}; | |
| 412 | + | |
| 413 | +static inline bool | |
| 414 | +mcp251xfd_regmap_use_nocrc(struct mcp251xfd_priv *priv) | |
| 415 | +{ | |
| 416 | + return (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) || | |
| 417 | + (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)); | |
| 418 | +} | |
| 419 | + | |
| 420 | +static inline bool | |
| 421 | +mcp251xfd_regmap_use_crc(struct mcp251xfd_priv *priv) | |
| 422 | +{ | |
| 423 | + return (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) || | |
| 424 | + (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX); | |
| 425 | +} | |
| 426 | + | |
| 427 | +static int | |
| 428 | +mcp251xfd_regmap_init_nocrc(struct mcp251xfd_priv *priv) | |
| 429 | +{ | |
| 430 | + if (!priv->map_nocrc) { | |
| 431 | + struct regmap *map; | |
| 432 | + | |
| 433 | + map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_nocrc, | |
| 434 | + priv->spi, &mcp251xfd_regmap_nocrc); | |
| 435 | + if (IS_ERR(map)) | |
| 436 | + return PTR_ERR(map); | |
| 437 | + | |
| 438 | + priv->map_nocrc = map; | |
| 439 | + } | |
| 440 | + | |
| 441 | + if (!priv->map_buf_nocrc_rx) { | |
| 442 | + priv->map_buf_nocrc_rx = | |
| 443 | + devm_kzalloc(&priv->spi->dev, | |
| 444 | + sizeof(*priv->map_buf_nocrc_rx), | |
| 445 | + GFP_KERNEL); | |
| 446 | + if (!priv->map_buf_nocrc_rx) | |
| 447 | + return -ENOMEM; | |
| 448 | + } | |
| 449 | + | |
| 450 | + if (!priv->map_buf_nocrc_tx) { | |
| 451 | + priv->map_buf_nocrc_tx = | |
| 452 | + devm_kzalloc(&priv->spi->dev, | |
| 453 | + sizeof(*priv->map_buf_nocrc_tx), | |
| 454 | + GFP_KERNEL); | |
| 455 | + if (!priv->map_buf_nocrc_tx) | |
| 456 | + return -ENOMEM; | |
| 457 | + } | |
| 458 | + | |
| 459 | + if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) | |
| 460 | + priv->map_reg = priv->map_nocrc; | |
| 461 | + | |
| 462 | + if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)) | |
| 463 | + priv->map_rx = priv->map_nocrc; | |
| 464 | + | |
| 465 | + return 0; | |
| 466 | +} | |
| 467 | + | |
| 468 | +static void mcp251xfd_regmap_destroy_nocrc(struct mcp251xfd_priv *priv) | |
| 469 | +{ | |
| 470 | + if (priv->map_buf_nocrc_rx) { | |
| 471 | + devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_rx); | |
| 472 | + priv->map_buf_nocrc_rx = NULL; | |
| 473 | + } | |
| 474 | + if (priv->map_buf_nocrc_tx) { | |
| 475 | + devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_tx); | |
| 476 | + priv->map_buf_nocrc_tx = NULL; | |
| 477 | + } | |
| 478 | +} | |
| 479 | + | |
| 480 | +static int | |
| 481 | +mcp251xfd_regmap_init_crc(struct mcp251xfd_priv *priv) | |
| 482 | +{ | |
| 483 | + if (!priv->map_crc) { | |
| 484 | + struct regmap *map; | |
| 485 | + | |
| 486 | + map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_crc, | |
| 487 | + priv->spi, &mcp251xfd_regmap_crc); | |
| 488 | + if (IS_ERR(map)) | |
| 489 | + return PTR_ERR(map); | |
| 490 | + | |
| 491 | + priv->map_crc = map; | |
| 492 | + } | |
| 493 | + | |
| 494 | + if (!priv->map_buf_crc_rx) { | |
| 495 | + priv->map_buf_crc_rx = | |
| 496 | + devm_kzalloc(&priv->spi->dev, | |
| 497 | + sizeof(*priv->map_buf_crc_rx), | |
| 498 | + GFP_KERNEL); | |
| 499 | + if (!priv->map_buf_crc_rx) | |
| 500 | + return -ENOMEM; | |
| 501 | + } | |
| 502 | + | |
| 503 | + if (!priv->map_buf_crc_tx) { | |
| 504 | + priv->map_buf_crc_tx = | |
| 505 | + devm_kzalloc(&priv->spi->dev, | |
| 506 | + sizeof(*priv->map_buf_crc_tx), | |
| 507 | + GFP_KERNEL); | |
| 508 | + if (!priv->map_buf_crc_tx) | |
| 509 | + return -ENOMEM; | |
| 510 | + } | |
| 511 | + | |
| 512 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) | |
| 513 | + priv->map_reg = priv->map_crc; | |
| 514 | + | |
| 515 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX) | |
| 516 | + priv->map_rx = priv->map_crc; | |
| 517 | + | |
| 518 | + return 0; | |
| 519 | +} | |
| 520 | + | |
| 521 | +static void mcp251xfd_regmap_destroy_crc(struct mcp251xfd_priv *priv) | |
| 522 | +{ | |
| 523 | + if (priv->map_buf_crc_rx) { | |
| 524 | + devm_kfree(&priv->spi->dev, priv->map_buf_crc_rx); | |
| 525 | + priv->map_buf_crc_rx = NULL; | |
| 526 | + } | |
| 527 | + if (priv->map_buf_crc_tx) { | |
| 528 | + devm_kfree(&priv->spi->dev, priv->map_buf_crc_tx); | |
| 529 | + priv->map_buf_crc_tx = NULL; | |
| 530 | + } | |
| 531 | +} | |
| 532 | + | |
| 533 | +int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv) | |
| 534 | +{ | |
| 535 | + int err; | |
| 536 | + | |
| 537 | + if (mcp251xfd_regmap_use_nocrc(priv)) { | |
| 538 | + err = mcp251xfd_regmap_init_nocrc(priv); | |
| 539 | + | |
| 540 | + if (err) | |
| 541 | + return err; | |
| 542 | + } else { | |
| 543 | + mcp251xfd_regmap_destroy_nocrc(priv); | |
| 544 | + } | |
| 545 | + | |
| 546 | + if (mcp251xfd_regmap_use_crc(priv)) { | |
| 547 | + err = mcp251xfd_regmap_init_crc(priv); | |
| 548 | + | |
| 549 | + if (err) | |
| 550 | + return err; | |
| 551 | + } else { | |
| 552 | + mcp251xfd_regmap_destroy_crc(priv); | |
| 553 | + } | |
| 554 | + | |
| 555 | + return 0; | |
| 556 | +} | |
| @@ -0,0 +1,835 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 | |
| 2 | + * | |
| 3 | + * mcp251xfd - Microchip MCP251xFD Family CAN controller driver | |
| 4 | + * | |
| 5 | + * Copyright (c) 2019 Pengutronix, | |
| 6 | + * Marc Kleine-Budde <kernel@pengutronix.de> | |
| 7 | + * Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#ifndef _MCP251XFD_H | |
| 11 | +#define _MCP251XFD_H | |
| 12 | + | |
| 13 | +#include <linux/can/core.h> | |
| 14 | +#include <linux/can/dev.h> | |
| 15 | +#include <linux/can/rx-offload.h> | |
| 16 | +#include <linux/gpio/consumer.h> | |
| 17 | +#include <linux/kernel.h> | |
| 18 | +#include <linux/regmap.h> | |
| 19 | +#include <linux/regulator/consumer.h> | |
| 20 | +#include <linux/spi/spi.h> | |
| 21 | + | |
| 22 | +/* MPC251x registers */ | |
| 23 | + | |
| 24 | +/* CAN FD Controller Module SFR */ | |
| 25 | +#define MCP251XFD_REG_CON 0x00 | |
| 26 | +#define MCP251XFD_REG_CON_TXBWS_MASK GENMASK(31, 28) | |
| 27 | +#define MCP251XFD_REG_CON_ABAT BIT(27) | |
| 28 | +#define MCP251XFD_REG_CON_REQOP_MASK GENMASK(26, 24) | |
| 29 | +#define MCP251XFD_REG_CON_MODE_MIXED 0 | |
| 30 | +#define MCP251XFD_REG_CON_MODE_SLEEP 1 | |
| 31 | +#define MCP251XFD_REG_CON_MODE_INT_LOOPBACK 2 | |
| 32 | +#define MCP251XFD_REG_CON_MODE_LISTENONLY 3 | |
| 33 | +#define MCP251XFD_REG_CON_MODE_CONFIG 4 | |
| 34 | +#define MCP251XFD_REG_CON_MODE_EXT_LOOPBACK 5 | |
| 35 | +#define MCP251XFD_REG_CON_MODE_CAN2_0 6 | |
| 36 | +#define MCP251XFD_REG_CON_MODE_RESTRICTED 7 | |
| 37 | +#define MCP251XFD_REG_CON_OPMOD_MASK GENMASK(23, 21) | |
| 38 | +#define MCP251XFD_REG_CON_TXQEN BIT(20) | |
| 39 | +#define MCP251XFD_REG_CON_STEF BIT(19) | |
| 40 | +#define MCP251XFD_REG_CON_SERR2LOM BIT(18) | |
| 41 | +#define MCP251XFD_REG_CON_ESIGM BIT(17) | |
| 42 | +#define MCP251XFD_REG_CON_RTXAT BIT(16) | |
| 43 | +#define MCP251XFD_REG_CON_BRSDIS BIT(12) | |
| 44 | +#define MCP251XFD_REG_CON_BUSY BIT(11) | |
| 45 | +#define MCP251XFD_REG_CON_WFT_MASK GENMASK(10, 9) | |
| 46 | +#define MCP251XFD_REG_CON_WFT_T00FILTER 0x0 | |
| 47 | +#define MCP251XFD_REG_CON_WFT_T01FILTER 0x1 | |
| 48 | +#define MCP251XFD_REG_CON_WFT_T10FILTER 0x2 | |
| 49 | +#define MCP251XFD_REG_CON_WFT_T11FILTER 0x3 | |
| 50 | +#define MCP251XFD_REG_CON_WAKFIL BIT(8) | |
| 51 | +#define MCP251XFD_REG_CON_PXEDIS BIT(6) | |
| 52 | +#define MCP251XFD_REG_CON_ISOCRCEN BIT(5) | |
| 53 | +#define MCP251XFD_REG_CON_DNCNT_MASK GENMASK(4, 0) | |
| 54 | + | |
| 55 | +#define MCP251XFD_REG_NBTCFG 0x04 | |
| 56 | +#define MCP251XFD_REG_NBTCFG_BRP_MASK GENMASK(31, 24) | |
| 57 | +#define MCP251XFD_REG_NBTCFG_TSEG1_MASK GENMASK(23, 16) | |
| 58 | +#define MCP251XFD_REG_NBTCFG_TSEG2_MASK GENMASK(14, 8) | |
| 59 | +#define MCP251XFD_REG_NBTCFG_SJW_MASK GENMASK(6, 0) | |
| 60 | + | |
| 61 | +#define MCP251XFD_REG_DBTCFG 0x08 | |
| 62 | +#define MCP251XFD_REG_DBTCFG_BRP_MASK GENMASK(31, 24) | |
| 63 | +#define MCP251XFD_REG_DBTCFG_TSEG1_MASK GENMASK(20, 16) | |
| 64 | +#define MCP251XFD_REG_DBTCFG_TSEG2_MASK GENMASK(11, 8) | |
| 65 | +#define MCP251XFD_REG_DBTCFG_SJW_MASK GENMASK(3, 0) | |
| 66 | + | |
| 67 | +#define MCP251XFD_REG_TDC 0x0c | |
| 68 | +#define MCP251XFD_REG_TDC_EDGFLTEN BIT(25) | |
| 69 | +#define MCP251XFD_REG_TDC_SID11EN BIT(24) | |
| 70 | +#define MCP251XFD_REG_TDC_TDCMOD_MASK GENMASK(17, 16) | |
| 71 | +#define MCP251XFD_REG_TDC_TDCMOD_AUTO 2 | |
| 72 | +#define MCP251XFD_REG_TDC_TDCMOD_MANUAL 1 | |
| 73 | +#define MCP251XFD_REG_TDC_TDCMOD_DISABLED 0 | |
| 74 | +#define MCP251XFD_REG_TDC_TDCO_MASK GENMASK(14, 8) | |
| 75 | +#define MCP251XFD_REG_TDC_TDCV_MASK GENMASK(5, 0) | |
| 76 | + | |
| 77 | +#define MCP251XFD_REG_TBC 0x10 | |
| 78 | + | |
| 79 | +#define MCP251XFD_REG_TSCON 0x14 | |
| 80 | +#define MCP251XFD_REG_TSCON_TSRES BIT(18) | |
| 81 | +#define MCP251XFD_REG_TSCON_TSEOF BIT(17) | |
| 82 | +#define MCP251XFD_REG_TSCON_TBCEN BIT(16) | |
| 83 | +#define MCP251XFD_REG_TSCON_TBCPRE_MASK GENMASK(9, 0) | |
| 84 | + | |
| 85 | +#define MCP251XFD_REG_VEC 0x18 | |
| 86 | +#define MCP251XFD_REG_VEC_RXCODE_MASK GENMASK(30, 24) | |
| 87 | +#define MCP251XFD_REG_VEC_TXCODE_MASK GENMASK(22, 16) | |
| 88 | +#define MCP251XFD_REG_VEC_FILHIT_MASK GENMASK(12, 8) | |
| 89 | +#define MCP251XFD_REG_VEC_ICODE_MASK GENMASK(6, 0) | |
| 90 | + | |
| 91 | +#define MCP251XFD_REG_INT 0x1c | |
| 92 | +#define MCP251XFD_REG_INT_IF_MASK GENMASK(15, 0) | |
| 93 | +#define MCP251XFD_REG_INT_IE_MASK GENMASK(31, 16) | |
| 94 | +#define MCP251XFD_REG_INT_IVMIE BIT(31) | |
| 95 | +#define MCP251XFD_REG_INT_WAKIE BIT(30) | |
| 96 | +#define MCP251XFD_REG_INT_CERRIE BIT(29) | |
| 97 | +#define MCP251XFD_REG_INT_SERRIE BIT(28) | |
| 98 | +#define MCP251XFD_REG_INT_RXOVIE BIT(27) | |
| 99 | +#define MCP251XFD_REG_INT_TXATIE BIT(26) | |
| 100 | +#define MCP251XFD_REG_INT_SPICRCIE BIT(25) | |
| 101 | +#define MCP251XFD_REG_INT_ECCIE BIT(24) | |
| 102 | +#define MCP251XFD_REG_INT_TEFIE BIT(20) | |
| 103 | +#define MCP251XFD_REG_INT_MODIE BIT(19) | |
| 104 | +#define MCP251XFD_REG_INT_TBCIE BIT(18) | |
| 105 | +#define MCP251XFD_REG_INT_RXIE BIT(17) | |
| 106 | +#define MCP251XFD_REG_INT_TXIE BIT(16) | |
| 107 | +#define MCP251XFD_REG_INT_IVMIF BIT(15) | |
| 108 | +#define MCP251XFD_REG_INT_WAKIF BIT(14) | |
| 109 | +#define MCP251XFD_REG_INT_CERRIF BIT(13) | |
| 110 | +#define MCP251XFD_REG_INT_SERRIF BIT(12) | |
| 111 | +#define MCP251XFD_REG_INT_RXOVIF BIT(11) | |
| 112 | +#define MCP251XFD_REG_INT_TXATIF BIT(10) | |
| 113 | +#define MCP251XFD_REG_INT_SPICRCIF BIT(9) | |
| 114 | +#define MCP251XFD_REG_INT_ECCIF BIT(8) | |
| 115 | +#define MCP251XFD_REG_INT_TEFIF BIT(4) | |
| 116 | +#define MCP251XFD_REG_INT_MODIF BIT(3) | |
| 117 | +#define MCP251XFD_REG_INT_TBCIF BIT(2) | |
| 118 | +#define MCP251XFD_REG_INT_RXIF BIT(1) | |
| 119 | +#define MCP251XFD_REG_INT_TXIF BIT(0) | |
| 120 | +/* These IRQ flags must be cleared by SW in the CAN_INT register */ | |
| 121 | +#define MCP251XFD_REG_INT_IF_CLEARABLE_MASK \ | |
| 122 | + (MCP251XFD_REG_INT_IVMIF | MCP251XFD_REG_INT_WAKIF | \ | |
| 123 | + MCP251XFD_REG_INT_CERRIF | MCP251XFD_REG_INT_SERRIF | \ | |
| 124 | + MCP251XFD_REG_INT_MODIF) | |
| 125 | + | |
| 126 | +#define MCP251XFD_REG_RXIF 0x20 | |
| 127 | +#define MCP251XFD_REG_TXIF 0x24 | |
| 128 | +#define MCP251XFD_REG_RXOVIF 0x28 | |
| 129 | +#define MCP251XFD_REG_TXATIF 0x2c | |
| 130 | +#define MCP251XFD_REG_TXREQ 0x30 | |
| 131 | + | |
| 132 | +#define MCP251XFD_REG_TREC 0x34 | |
| 133 | +#define MCP251XFD_REG_TREC_TXBO BIT(21) | |
| 134 | +#define MCP251XFD_REG_TREC_TXBP BIT(20) | |
| 135 | +#define MCP251XFD_REG_TREC_RXBP BIT(19) | |
| 136 | +#define MCP251XFD_REG_TREC_TXWARN BIT(18) | |
| 137 | +#define MCP251XFD_REG_TREC_RXWARN BIT(17) | |
| 138 | +#define MCP251XFD_REG_TREC_EWARN BIT(16) | |
| 139 | +#define MCP251XFD_REG_TREC_TEC_MASK GENMASK(15, 8) | |
| 140 | +#define MCP251XFD_REG_TREC_REC_MASK GENMASK(7, 0) | |
| 141 | + | |
| 142 | +#define MCP251XFD_REG_BDIAG0 0x38 | |
| 143 | +#define MCP251XFD_REG_BDIAG0_DTERRCNT_MASK GENMASK(31, 24) | |
| 144 | +#define MCP251XFD_REG_BDIAG0_DRERRCNT_MASK GENMASK(23, 16) | |
| 145 | +#define MCP251XFD_REG_BDIAG0_NTERRCNT_MASK GENMASK(15, 8) | |
| 146 | +#define MCP251XFD_REG_BDIAG0_NRERRCNT_MASK GENMASK(7, 0) | |
| 147 | + | |
| 148 | +#define MCP251XFD_REG_BDIAG1 0x3c | |
| 149 | +#define MCP251XFD_REG_BDIAG1_DLCMM BIT(31) | |
| 150 | +#define MCP251XFD_REG_BDIAG1_ESI BIT(30) | |
| 151 | +#define MCP251XFD_REG_BDIAG1_DCRCERR BIT(29) | |
| 152 | +#define MCP251XFD_REG_BDIAG1_DSTUFERR BIT(28) | |
| 153 | +#define MCP251XFD_REG_BDIAG1_DFORMERR BIT(27) | |
| 154 | +#define MCP251XFD_REG_BDIAG1_DBIT1ERR BIT(25) | |
| 155 | +#define MCP251XFD_REG_BDIAG1_DBIT0ERR BIT(24) | |
| 156 | +#define MCP251XFD_REG_BDIAG1_TXBOERR BIT(23) | |
| 157 | +#define MCP251XFD_REG_BDIAG1_NCRCERR BIT(21) | |
| 158 | +#define MCP251XFD_REG_BDIAG1_NSTUFERR BIT(20) | |
| 159 | +#define MCP251XFD_REG_BDIAG1_NFORMERR BIT(19) | |
| 160 | +#define MCP251XFD_REG_BDIAG1_NACKERR BIT(18) | |
| 161 | +#define MCP251XFD_REG_BDIAG1_NBIT1ERR BIT(17) | |
| 162 | +#define MCP251XFD_REG_BDIAG1_NBIT0ERR BIT(16) | |
| 163 | +#define MCP251XFD_REG_BDIAG1_BERR_MASK \ | |
| 164 | + (MCP251XFD_REG_BDIAG1_DLCMM | MCP251XFD_REG_BDIAG1_ESI | \ | |
| 165 | + MCP251XFD_REG_BDIAG1_DCRCERR | MCP251XFD_REG_BDIAG1_DSTUFERR | \ | |
| 166 | + MCP251XFD_REG_BDIAG1_DFORMERR | MCP251XFD_REG_BDIAG1_DBIT1ERR | \ | |
| 167 | + MCP251XFD_REG_BDIAG1_DBIT0ERR | MCP251XFD_REG_BDIAG1_TXBOERR | \ | |
| 168 | + MCP251XFD_REG_BDIAG1_NCRCERR | MCP251XFD_REG_BDIAG1_NSTUFERR | \ | |
| 169 | + MCP251XFD_REG_BDIAG1_NFORMERR | MCP251XFD_REG_BDIAG1_NACKERR | \ | |
| 170 | + MCP251XFD_REG_BDIAG1_NBIT1ERR | MCP251XFD_REG_BDIAG1_NBIT0ERR) | |
| 171 | +#define MCP251XFD_REG_BDIAG1_EFMSGCNT_MASK GENMASK(15, 0) | |
| 172 | + | |
| 173 | +#define MCP251XFD_REG_TEFCON 0x40 | |
| 174 | +#define MCP251XFD_REG_TEFCON_FSIZE_MASK GENMASK(28, 24) | |
| 175 | +#define MCP251XFD_REG_TEFCON_FRESET BIT(10) | |
| 176 | +#define MCP251XFD_REG_TEFCON_UINC BIT(8) | |
| 177 | +#define MCP251XFD_REG_TEFCON_TEFTSEN BIT(5) | |
| 178 | +#define MCP251XFD_REG_TEFCON_TEFOVIE BIT(3) | |
| 179 | +#define MCP251XFD_REG_TEFCON_TEFFIE BIT(2) | |
| 180 | +#define MCP251XFD_REG_TEFCON_TEFHIE BIT(1) | |
| 181 | +#define MCP251XFD_REG_TEFCON_TEFNEIE BIT(0) | |
| 182 | + | |
| 183 | +#define MCP251XFD_REG_TEFSTA 0x44 | |
| 184 | +#define MCP251XFD_REG_TEFSTA_TEFOVIF BIT(3) | |
| 185 | +#define MCP251XFD_REG_TEFSTA_TEFFIF BIT(2) | |
| 186 | +#define MCP251XFD_REG_TEFSTA_TEFHIF BIT(1) | |
| 187 | +#define MCP251XFD_REG_TEFSTA_TEFNEIF BIT(0) | |
| 188 | + | |
| 189 | +#define MCP251XFD_REG_TEFUA 0x48 | |
| 190 | + | |
| 191 | +#define MCP251XFD_REG_TXQCON 0x50 | |
| 192 | +#define MCP251XFD_REG_TXQCON_PLSIZE_MASK GENMASK(31, 29) | |
| 193 | +#define MCP251XFD_REG_TXQCON_PLSIZE_8 0 | |
| 194 | +#define MCP251XFD_REG_TXQCON_PLSIZE_12 1 | |
| 195 | +#define MCP251XFD_REG_TXQCON_PLSIZE_16 2 | |
| 196 | +#define MCP251XFD_REG_TXQCON_PLSIZE_20 3 | |
| 197 | +#define MCP251XFD_REG_TXQCON_PLSIZE_24 4 | |
| 198 | +#define MCP251XFD_REG_TXQCON_PLSIZE_32 5 | |
| 199 | +#define MCP251XFD_REG_TXQCON_PLSIZE_48 6 | |
| 200 | +#define MCP251XFD_REG_TXQCON_PLSIZE_64 7 | |
| 201 | +#define MCP251XFD_REG_TXQCON_FSIZE_MASK GENMASK(28, 24) | |
| 202 | +#define MCP251XFD_REG_TXQCON_TXAT_UNLIMITED 3 | |
| 203 | +#define MCP251XFD_REG_TXQCON_TXAT_THREE_SHOT 1 | |
| 204 | +#define MCP251XFD_REG_TXQCON_TXAT_ONE_SHOT 0 | |
| 205 | +#define MCP251XFD_REG_TXQCON_TXAT_MASK GENMASK(22, 21) | |
| 206 | +#define MCP251XFD_REG_TXQCON_TXPRI_MASK GENMASK(20, 16) | |
| 207 | +#define MCP251XFD_REG_TXQCON_FRESET BIT(10) | |
| 208 | +#define MCP251XFD_REG_TXQCON_TXREQ BIT(9) | |
| 209 | +#define MCP251XFD_REG_TXQCON_UINC BIT(8) | |
| 210 | +#define MCP251XFD_REG_TXQCON_TXEN BIT(7) | |
| 211 | +#define MCP251XFD_REG_TXQCON_TXATIE BIT(4) | |
| 212 | +#define MCP251XFD_REG_TXQCON_TXQEIE BIT(2) | |
| 213 | +#define MCP251XFD_REG_TXQCON_TXQNIE BIT(0) | |
| 214 | + | |
| 215 | +#define MCP251XFD_REG_TXQSTA 0x54 | |
| 216 | +#define MCP251XFD_REG_TXQSTA_TXQCI_MASK GENMASK(12, 8) | |
| 217 | +#define MCP251XFD_REG_TXQSTA_TXABT BIT(7) | |
| 218 | +#define MCP251XFD_REG_TXQSTA_TXLARB BIT(6) | |
| 219 | +#define MCP251XFD_REG_TXQSTA_TXERR BIT(5) | |
| 220 | +#define MCP251XFD_REG_TXQSTA_TXATIF BIT(4) | |
| 221 | +#define MCP251XFD_REG_TXQSTA_TXQEIF BIT(2) | |
| 222 | +#define MCP251XFD_REG_TXQSTA_TXQNIF BIT(0) | |
| 223 | + | |
| 224 | +#define MCP251XFD_REG_TXQUA 0x58 | |
| 225 | + | |
| 226 | +#define MCP251XFD_REG_FIFOCON(x) (0x50 + 0xc * (x)) | |
| 227 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_MASK GENMASK(31, 29) | |
| 228 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_8 0 | |
| 229 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_12 1 | |
| 230 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_16 2 | |
| 231 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_20 3 | |
| 232 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_24 4 | |
| 233 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_32 5 | |
| 234 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_48 6 | |
| 235 | +#define MCP251XFD_REG_FIFOCON_PLSIZE_64 7 | |
| 236 | +#define MCP251XFD_REG_FIFOCON_FSIZE_MASK GENMASK(28, 24) | |
| 237 | +#define MCP251XFD_REG_FIFOCON_TXAT_MASK GENMASK(22, 21) | |
| 238 | +#define MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT 0 | |
| 239 | +#define MCP251XFD_REG_FIFOCON_TXAT_THREE_SHOT 1 | |
| 240 | +#define MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED 3 | |
| 241 | +#define MCP251XFD_REG_FIFOCON_TXPRI_MASK GENMASK(20, 16) | |
| 242 | +#define MCP251XFD_REG_FIFOCON_FRESET BIT(10) | |
| 243 | +#define MCP251XFD_REG_FIFOCON_TXREQ BIT(9) | |
| 244 | +#define MCP251XFD_REG_FIFOCON_UINC BIT(8) | |
| 245 | +#define MCP251XFD_REG_FIFOCON_TXEN BIT(7) | |
| 246 | +#define MCP251XFD_REG_FIFOCON_RTREN BIT(6) | |
| 247 | +#define MCP251XFD_REG_FIFOCON_RXTSEN BIT(5) | |
| 248 | +#define MCP251XFD_REG_FIFOCON_TXATIE BIT(4) | |
| 249 | +#define MCP251XFD_REG_FIFOCON_RXOVIE BIT(3) | |
| 250 | +#define MCP251XFD_REG_FIFOCON_TFERFFIE BIT(2) | |
| 251 | +#define MCP251XFD_REG_FIFOCON_TFHRFHIE BIT(1) | |
| 252 | +#define MCP251XFD_REG_FIFOCON_TFNRFNIE BIT(0) | |
| 253 | + | |
| 254 | +#define MCP251XFD_REG_FIFOSTA(x) (0x54 + 0xc * (x)) | |
| 255 | +#define MCP251XFD_REG_FIFOSTA_FIFOCI_MASK GENMASK(12, 8) | |
| 256 | +#define MCP251XFD_REG_FIFOSTA_TXABT BIT(7) | |
| 257 | +#define MCP251XFD_REG_FIFOSTA_TXLARB BIT(6) | |
| 258 | +#define MCP251XFD_REG_FIFOSTA_TXERR BIT(5) | |
| 259 | +#define MCP251XFD_REG_FIFOSTA_TXATIF BIT(4) | |
| 260 | +#define MCP251XFD_REG_FIFOSTA_RXOVIF BIT(3) | |
| 261 | +#define MCP251XFD_REG_FIFOSTA_TFERFFIF BIT(2) | |
| 262 | +#define MCP251XFD_REG_FIFOSTA_TFHRFHIF BIT(1) | |
| 263 | +#define MCP251XFD_REG_FIFOSTA_TFNRFNIF BIT(0) | |
| 264 | + | |
| 265 | +#define MCP251XFD_REG_FIFOUA(x) (0x58 + 0xc * (x)) | |
| 266 | + | |
| 267 | +#define MCP251XFD_REG_FLTCON(x) (0x1d0 + 0x4 * (x)) | |
| 268 | +#define MCP251XFD_REG_FLTCON_FLTEN3 BIT(31) | |
| 269 | +#define MCP251XFD_REG_FLTCON_F3BP_MASK GENMASK(28, 24) | |
| 270 | +#define MCP251XFD_REG_FLTCON_FLTEN2 BIT(23) | |
| 271 | +#define MCP251XFD_REG_FLTCON_F2BP_MASK GENMASK(20, 16) | |
| 272 | +#define MCP251XFD_REG_FLTCON_FLTEN1 BIT(15) | |
| 273 | +#define MCP251XFD_REG_FLTCON_F1BP_MASK GENMASK(12, 8) | |
| 274 | +#define MCP251XFD_REG_FLTCON_FLTEN0 BIT(7) | |
| 275 | +#define MCP251XFD_REG_FLTCON_F0BP_MASK GENMASK(4, 0) | |
| 276 | +#define MCP251XFD_REG_FLTCON_FLTEN(x) (BIT(7) << 8 * ((x) & 0x3)) | |
| 277 | +#define MCP251XFD_REG_FLTCON_FLT_MASK(x) (GENMASK(7, 0) << (8 * ((x) & 0x3))) | |
| 278 | +#define MCP251XFD_REG_FLTCON_FBP(x, fifo) ((fifo) << 8 * ((x) & 0x3)) | |
| 279 | + | |
| 280 | +#define MCP251XFD_REG_FLTOBJ(x) (0x1f0 + 0x8 * (x)) | |
| 281 | +#define MCP251XFD_REG_FLTOBJ_EXIDE BIT(30) | |
| 282 | +#define MCP251XFD_REG_FLTOBJ_SID11 BIT(29) | |
| 283 | +#define MCP251XFD_REG_FLTOBJ_EID_MASK GENMASK(28, 11) | |
| 284 | +#define MCP251XFD_REG_FLTOBJ_SID_MASK GENMASK(10, 0) | |
| 285 | + | |
| 286 | +#define MCP251XFD_REG_FLTMASK(x) (0x1f4 + 0x8 * (x)) | |
| 287 | +#define MCP251XFD_REG_MASK_MIDE BIT(30) | |
| 288 | +#define MCP251XFD_REG_MASK_MSID11 BIT(29) | |
| 289 | +#define MCP251XFD_REG_MASK_MEID_MASK GENMASK(28, 11) | |
| 290 | +#define MCP251XFD_REG_MASK_MSID_MASK GENMASK(10, 0) | |
| 291 | + | |
| 292 | +/* RAM */ | |
| 293 | +#define MCP251XFD_RAM_START 0x400 | |
| 294 | +#define MCP251XFD_RAM_SIZE SZ_2K | |
| 295 | + | |
| 296 | +/* Message Object */ | |
| 297 | +#define MCP251XFD_OBJ_ID_SID11 BIT(29) | |
| 298 | +#define MCP251XFD_OBJ_ID_EID_MASK GENMASK(28, 11) | |
| 299 | +#define MCP251XFD_OBJ_ID_SID_MASK GENMASK(10, 0) | |
| 300 | +#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK GENMASK(31, 9) | |
| 301 | +#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK GENMASK(15, 9) | |
| 302 | +#define MCP251XFD_OBJ_FLAGS_SEQ_MASK MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK | |
| 303 | +#define MCP251XFD_OBJ_FLAGS_ESI BIT(8) | |
| 304 | +#define MCP251XFD_OBJ_FLAGS_FDF BIT(7) | |
| 305 | +#define MCP251XFD_OBJ_FLAGS_BRS BIT(6) | |
| 306 | +#define MCP251XFD_OBJ_FLAGS_RTR BIT(5) | |
| 307 | +#define MCP251XFD_OBJ_FLAGS_IDE BIT(4) | |
| 308 | +#define MCP251XFD_OBJ_FLAGS_DLC GENMASK(3, 0) | |
| 309 | + | |
| 310 | +#define MCP251XFD_REG_FRAME_EFF_SID_MASK GENMASK(28, 18) | |
| 311 | +#define MCP251XFD_REG_FRAME_EFF_EID_MASK GENMASK(17, 0) | |
| 312 | + | |
| 313 | +/* MCP2517/18FD SFR */ | |
| 314 | +#define MCP251XFD_REG_OSC 0xe00 | |
| 315 | +#define MCP251XFD_REG_OSC_SCLKRDY BIT(12) | |
| 316 | +#define MCP251XFD_REG_OSC_OSCRDY BIT(10) | |
| 317 | +#define MCP251XFD_REG_OSC_PLLRDY BIT(8) | |
| 318 | +#define MCP251XFD_REG_OSC_CLKODIV_10 3 | |
| 319 | +#define MCP251XFD_REG_OSC_CLKODIV_4 2 | |
| 320 | +#define MCP251XFD_REG_OSC_CLKODIV_2 1 | |
| 321 | +#define MCP251XFD_REG_OSC_CLKODIV_1 0 | |
| 322 | +#define MCP251XFD_REG_OSC_CLKODIV_MASK GENMASK(6, 5) | |
| 323 | +#define MCP251XFD_REG_OSC_SCLKDIV BIT(4) | |
| 324 | +#define MCP251XFD_REG_OSC_LPMEN BIT(3) /* MCP2518FD only */ | |
| 325 | +#define MCP251XFD_REG_OSC_OSCDIS BIT(2) | |
| 326 | +#define MCP251XFD_REG_OSC_PLLEN BIT(0) | |
| 327 | + | |
| 328 | +#define MCP251XFD_REG_IOCON 0xe04 | |
| 329 | +#define MCP251XFD_REG_IOCON_INTOD BIT(30) | |
| 330 | +#define MCP251XFD_REG_IOCON_SOF BIT(29) | |
| 331 | +#define MCP251XFD_REG_IOCON_TXCANOD BIT(28) | |
| 332 | +#define MCP251XFD_REG_IOCON_PM1 BIT(25) | |
| 333 | +#define MCP251XFD_REG_IOCON_PM0 BIT(24) | |
| 334 | +#define MCP251XFD_REG_IOCON_GPIO1 BIT(17) | |
| 335 | +#define MCP251XFD_REG_IOCON_GPIO0 BIT(16) | |
| 336 | +#define MCP251XFD_REG_IOCON_LAT1 BIT(9) | |
| 337 | +#define MCP251XFD_REG_IOCON_LAT0 BIT(8) | |
| 338 | +#define MCP251XFD_REG_IOCON_XSTBYEN BIT(6) | |
| 339 | +#define MCP251XFD_REG_IOCON_TRIS1 BIT(1) | |
| 340 | +#define MCP251XFD_REG_IOCON_TRIS0 BIT(0) | |
| 341 | + | |
| 342 | +#define MCP251XFD_REG_CRC 0xe08 | |
| 343 | +#define MCP251XFD_REG_CRC_FERRIE BIT(25) | |
| 344 | +#define MCP251XFD_REG_CRC_CRCERRIE BIT(24) | |
| 345 | +#define MCP251XFD_REG_CRC_FERRIF BIT(17) | |
| 346 | +#define MCP251XFD_REG_CRC_CRCERRIF BIT(16) | |
| 347 | +#define MCP251XFD_REG_CRC_IF_MASK GENMASK(17, 16) | |
| 348 | +#define MCP251XFD_REG_CRC_MASK GENMASK(15, 0) | |
| 349 | + | |
| 350 | +#define MCP251XFD_REG_ECCCON 0xe0c | |
| 351 | +#define MCP251XFD_REG_ECCCON_PARITY_MASK GENMASK(14, 8) | |
| 352 | +#define MCP251XFD_REG_ECCCON_DEDIE BIT(2) | |
| 353 | +#define MCP251XFD_REG_ECCCON_SECIE BIT(1) | |
| 354 | +#define MCP251XFD_REG_ECCCON_ECCEN BIT(0) | |
| 355 | + | |
| 356 | +#define MCP251XFD_REG_ECCSTAT 0xe10 | |
| 357 | +#define MCP251XFD_REG_ECCSTAT_ERRADDR_MASK GENMASK(27, 16) | |
| 358 | +#define MCP251XFD_REG_ECCSTAT_IF_MASK GENMASK(2, 1) | |
| 359 | +#define MCP251XFD_REG_ECCSTAT_DEDIF BIT(2) | |
| 360 | +#define MCP251XFD_REG_ECCSTAT_SECIF BIT(1) | |
| 361 | + | |
| 362 | +#define MCP251XFD_REG_DEVID 0xe14 /* MCP2518FD only */ | |
| 363 | +#define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4) | |
| 364 | +#define MCP251XFD_REG_DEVID_REV_MASK GENMASK(3, 0) | |
| 365 | + | |
| 366 | +/* number of TX FIFO objects, depending on CAN mode | |
| 367 | + * | |
| 368 | + * FIFO setup: tef: 8*12 bytes = 96 bytes, tx: 8*16 bytes = 128 bytes | |
| 369 | + * FIFO setup: tef: 4*12 bytes = 48 bytes, tx: 4*72 bytes = 288 bytes | |
| 370 | + */ | |
| 371 | +#define MCP251XFD_TX_OBJ_NUM_CAN 8 | |
| 372 | +#define MCP251XFD_TX_OBJ_NUM_CANFD 4 | |
| 373 | + | |
| 374 | +#if MCP251XFD_TX_OBJ_NUM_CAN > MCP251XFD_TX_OBJ_NUM_CANFD | |
| 375 | +#define MCP251XFD_TX_OBJ_NUM_MAX MCP251XFD_TX_OBJ_NUM_CAN | |
| 376 | +#else | |
| 377 | +#define MCP251XFD_TX_OBJ_NUM_MAX MCP251XFD_TX_OBJ_NUM_CANFD | |
| 378 | +#endif | |
| 379 | + | |
| 380 | +#define MCP251XFD_NAPI_WEIGHT 32 | |
| 381 | +#define MCP251XFD_TX_FIFO 1 | |
| 382 | +#define MCP251XFD_RX_FIFO(x) (MCP251XFD_TX_FIFO + 1 + (x)) | |
| 383 | + | |
| 384 | +/* SPI commands */ | |
| 385 | +#define MCP251XFD_SPI_INSTRUCTION_RESET 0x0000 | |
| 386 | +#define MCP251XFD_SPI_INSTRUCTION_WRITE 0x2000 | |
| 387 | +#define MCP251XFD_SPI_INSTRUCTION_READ 0x3000 | |
| 388 | +#define MCP251XFD_SPI_INSTRUCTION_WRITE_CRC 0xa000 | |
| 389 | +#define MCP251XFD_SPI_INSTRUCTION_READ_CRC 0xb000 | |
| 390 | +#define MCP251XFD_SPI_INSTRUCTION_WRITE_CRC_SAFE 0xc000 | |
| 391 | +#define MCP251XFD_SPI_ADDRESS_MASK GENMASK(11, 0) | |
| 392 | + | |
| 393 | +#define MCP251XFD_SYSCLOCK_HZ_MAX 40000000 | |
| 394 | +#define MCP251XFD_SYSCLOCK_HZ_MIN 1000000 | |
| 395 | +#define MCP251XFD_SPICLOCK_HZ_MAX 20000000 | |
| 396 | +#define MCP251XFD_OSC_PLL_MULTIPLIER 10 | |
| 397 | +#define MCP251XFD_OSC_STAB_SLEEP_US (3 * USEC_PER_MSEC) | |
| 398 | +#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US) | |
| 399 | +#define MCP251XFD_POLL_SLEEP_US (10) | |
| 400 | +#define MCP251XFD_POLL_TIMEOUT_US (USEC_PER_MSEC) | |
| 401 | +#define MCP251XFD_SOFTRESET_RETRIES_MAX 3 | |
| 402 | +#define MCP251XFD_READ_CRC_RETRIES_MAX 3 | |
| 403 | +#define MCP251XFD_ECC_CNT_MAX 2 | |
| 404 | +#define MCP251XFD_SANITIZE_SPI 1 | |
| 405 | +#define MCP251XFD_SANITIZE_CAN 1 | |
| 406 | + | |
| 407 | +/* Silence TX MAB overflow warnings */ | |
| 408 | +#define MCP251XFD_QUIRK_MAB_NO_WARN BIT(0) | |
| 409 | +/* Use CRC to access registers */ | |
| 410 | +#define MCP251XFD_QUIRK_CRC_REG BIT(1) | |
| 411 | +/* Use CRC to access RX/TEF-RAM */ | |
| 412 | +#define MCP251XFD_QUIRK_CRC_RX BIT(2) | |
| 413 | +/* Use CRC to access TX-RAM */ | |
| 414 | +#define MCP251XFD_QUIRK_CRC_TX BIT(3) | |
| 415 | +/* Enable ECC for RAM */ | |
| 416 | +#define MCP251XFD_QUIRK_ECC BIT(4) | |
| 417 | +/* Use Half Duplex SPI transfers */ | |
| 418 | +#define MCP251XFD_QUIRK_HALF_DUPLEX BIT(5) | |
| 419 | + | |
| 420 | +struct mcp251xfd_hw_tef_obj { | |
| 421 | + u32 id; | |
| 422 | + u32 flags; | |
| 423 | + u32 ts; | |
| 424 | +}; | |
| 425 | + | |
| 426 | +/* The tx_obj_raw version is used in spi async, i.e. without | |
| 427 | + * regmap. We have to take care of endianness ourselves. | |
| 428 | + */ | |
| 429 | +struct mcp251xfd_hw_tx_obj_raw { | |
| 430 | + __le32 id; | |
| 431 | + __le32 flags; | |
| 432 | + u8 data[sizeof_field(struct canfd_frame, data)]; | |
| 433 | +}; | |
| 434 | + | |
| 435 | +struct mcp251xfd_hw_tx_obj_can { | |
| 436 | + u32 id; | |
| 437 | + u32 flags; | |
| 438 | + u8 data[sizeof_field(struct can_frame, data)]; | |
| 439 | +}; | |
| 440 | + | |
| 441 | +struct mcp251xfd_hw_tx_obj_canfd { | |
| 442 | + u32 id; | |
| 443 | + u32 flags; | |
| 444 | + u8 data[sizeof_field(struct canfd_frame, data)]; | |
| 445 | +}; | |
| 446 | + | |
| 447 | +struct mcp251xfd_hw_rx_obj_can { | |
| 448 | + u32 id; | |
| 449 | + u32 flags; | |
| 450 | + u32 ts; | |
| 451 | + u8 data[sizeof_field(struct can_frame, data)]; | |
| 452 | +}; | |
| 453 | + | |
| 454 | +struct mcp251xfd_hw_rx_obj_canfd { | |
| 455 | + u32 id; | |
| 456 | + u32 flags; | |
| 457 | + u32 ts; | |
| 458 | + u8 data[sizeof_field(struct canfd_frame, data)]; | |
| 459 | +}; | |
| 460 | + | |
| 461 | +struct mcp251xfd_tef_ring { | |
| 462 | + unsigned int head; | |
| 463 | + unsigned int tail; | |
| 464 | + | |
| 465 | + /* u8 obj_num equals tx_ring->obj_num */ | |
| 466 | + /* u8 obj_size equals sizeof(struct mcp251xfd_hw_tef_obj) */ | |
| 467 | +}; | |
| 468 | + | |
| 469 | +struct __packed mcp251xfd_buf_cmd { | |
| 470 | + __be16 cmd; | |
| 471 | +}; | |
| 472 | + | |
| 473 | +struct __packed mcp251xfd_buf_cmd_crc { | |
| 474 | + __be16 cmd; | |
| 475 | + u8 len; | |
| 476 | +}; | |
| 477 | + | |
| 478 | +union mcp251xfd_tx_obj_load_buf { | |
| 479 | + struct __packed { | |
| 480 | + struct mcp251xfd_buf_cmd cmd; | |
| 481 | + struct mcp251xfd_hw_tx_obj_raw hw_tx_obj; | |
| 482 | + } nocrc; | |
| 483 | + struct __packed { | |
| 484 | + struct mcp251xfd_buf_cmd_crc cmd; | |
| 485 | + struct mcp251xfd_hw_tx_obj_raw hw_tx_obj; | |
| 486 | + __be16 crc; | |
| 487 | + } crc; | |
| 488 | +} ____cacheline_aligned; | |
| 489 | + | |
| 490 | +union mcp251xfd_write_reg_buf { | |
| 491 | + struct __packed { | |
| 492 | + struct mcp251xfd_buf_cmd cmd; | |
| 493 | + u8 data[4]; | |
| 494 | + } nocrc; | |
| 495 | + struct __packed { | |
| 496 | + struct mcp251xfd_buf_cmd_crc cmd; | |
| 497 | + u8 data[4]; | |
| 498 | + __be16 crc; | |
| 499 | + } crc; | |
| 500 | +} ____cacheline_aligned; | |
| 501 | + | |
| 502 | +struct mcp251xfd_tx_obj { | |
| 503 | + struct spi_message msg; | |
| 504 | + struct spi_transfer xfer[2]; | |
| 505 | + union mcp251xfd_tx_obj_load_buf buf; | |
| 506 | +}; | |
| 507 | + | |
| 508 | +struct mcp251xfd_tx_ring { | |
| 509 | + unsigned int head; | |
| 510 | + unsigned int tail; | |
| 511 | + | |
| 512 | + u16 base; | |
| 513 | + u8 obj_num; | |
| 514 | + u8 obj_size; | |
| 515 | + | |
| 516 | + struct mcp251xfd_tx_obj obj[MCP251XFD_TX_OBJ_NUM_MAX]; | |
| 517 | + union mcp251xfd_write_reg_buf rts_buf; | |
| 518 | +}; | |
| 519 | + | |
| 520 | +struct mcp251xfd_rx_ring { | |
| 521 | + unsigned int head; | |
| 522 | + unsigned int tail; | |
| 523 | + | |
| 524 | + u16 base; | |
| 525 | + u8 nr; | |
| 526 | + u8 fifo_nr; | |
| 527 | + u8 obj_num; | |
| 528 | + u8 obj_size; | |
| 529 | + | |
| 530 | + struct mcp251xfd_hw_rx_obj_canfd obj[]; | |
| 531 | +}; | |
| 532 | + | |
| 533 | +struct __packed mcp251xfd_map_buf_nocrc { | |
| 534 | + struct mcp251xfd_buf_cmd cmd; | |
| 535 | + u8 data[256]; | |
| 536 | +} ____cacheline_aligned; | |
| 537 | + | |
| 538 | +struct __packed mcp251xfd_map_buf_crc { | |
| 539 | + struct mcp251xfd_buf_cmd_crc cmd; | |
| 540 | + u8 data[256 - 4]; | |
| 541 | + __be16 crc; | |
| 542 | +} ____cacheline_aligned; | |
| 543 | + | |
| 544 | +struct mcp251xfd_ecc { | |
| 545 | + u32 ecc_stat; | |
| 546 | + int cnt; | |
| 547 | +}; | |
| 548 | + | |
| 549 | +struct mcp251xfd_regs_status { | |
| 550 | + u32 intf; | |
| 551 | +}; | |
| 552 | + | |
| 553 | +enum mcp251xfd_model { | |
| 554 | + MCP251XFD_MODEL_MCP2517FD = 0x2517, | |
| 555 | + MCP251XFD_MODEL_MCP2518FD = 0x2518, | |
| 556 | + MCP251XFD_MODEL_MCP251XFD = 0xffff, /* autodetect model */ | |
| 557 | +}; | |
| 558 | + | |
| 559 | +struct mcp251xfd_devtype_data { | |
| 560 | + enum mcp251xfd_model model; | |
| 561 | + u32 quirks; | |
| 562 | +}; | |
| 563 | + | |
| 564 | +struct mcp251xfd_priv { | |
| 565 | + struct can_priv can; | |
| 566 | + struct can_rx_offload offload; | |
| 567 | + struct net_device *ndev; | |
| 568 | + | |
| 569 | + struct regmap *map_reg; /* register access */ | |
| 570 | + struct regmap *map_rx; /* RX/TEF RAM access */ | |
| 571 | + | |
| 572 | + struct regmap *map_nocrc; | |
| 573 | + struct mcp251xfd_map_buf_nocrc *map_buf_nocrc_rx; | |
| 574 | + struct mcp251xfd_map_buf_nocrc *map_buf_nocrc_tx; | |
| 575 | + | |
| 576 | + struct regmap *map_crc; | |
| 577 | + struct mcp251xfd_map_buf_crc *map_buf_crc_rx; | |
| 578 | + struct mcp251xfd_map_buf_crc *map_buf_crc_tx; | |
| 579 | + | |
| 580 | + struct spi_device *spi; | |
| 581 | + u32 spi_max_speed_hz_orig; | |
| 582 | + | |
| 583 | + struct mcp251xfd_tef_ring tef; | |
| 584 | + struct mcp251xfd_tx_ring tx[1]; | |
| 585 | + struct mcp251xfd_rx_ring *rx[1]; | |
| 586 | + | |
| 587 | + u8 rx_ring_num; | |
| 588 | + | |
| 589 | + struct mcp251xfd_ecc ecc; | |
| 590 | + struct mcp251xfd_regs_status regs_status; | |
| 591 | + | |
| 592 | + struct gpio_desc *rx_int; | |
| 593 | + struct clk *clk; | |
| 594 | + struct regulator *reg_vdd; | |
| 595 | + struct regulator *reg_xceiver; | |
| 596 | + | |
| 597 | + struct mcp251xfd_devtype_data devtype_data; | |
| 598 | + struct can_berr_counter bec; | |
| 599 | +}; | |
| 600 | + | |
| 601 | +#define MCP251XFD_IS(_model) \ | |
| 602 | +static inline bool \ | |
| 603 | +mcp251xfd_is_##_model(const struct mcp251xfd_priv *priv) \ | |
| 604 | +{ \ | |
| 605 | + return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model##FD; \ | |
| 606 | +} | |
| 607 | + | |
| 608 | +MCP251XFD_IS(2517); | |
| 609 | +MCP251XFD_IS(2518); | |
| 610 | +MCP251XFD_IS(251X); | |
| 611 | + | |
| 612 | +static inline u8 mcp251xfd_first_byte_set(u32 mask) | |
| 613 | +{ | |
| 614 | + return (mask & 0x0000ffff) ? | |
| 615 | + ((mask & 0x000000ff) ? 0 : 1) : | |
| 616 | + ((mask & 0x00ff0000) ? 2 : 3); | |
| 617 | +} | |
| 618 | + | |
| 619 | +static inline u8 mcp251xfd_last_byte_set(u32 mask) | |
| 620 | +{ | |
| 621 | + return (mask & 0xffff0000) ? | |
| 622 | + ((mask & 0xff000000) ? 3 : 2) : | |
| 623 | + ((mask & 0x0000ff00) ? 1 : 0); | |
| 624 | +} | |
| 625 | + | |
| 626 | +static inline __be16 mcp251xfd_cmd_reset(void) | |
| 627 | +{ | |
| 628 | + return cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_RESET); | |
| 629 | +} | |
| 630 | + | |
| 631 | +static inline void | |
| 632 | +mcp251xfd_spi_cmd_read_nocrc(struct mcp251xfd_buf_cmd *cmd, u16 addr) | |
| 633 | +{ | |
| 634 | + cmd->cmd = cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ | addr); | |
| 635 | +} | |
| 636 | + | |
| 637 | +static inline void | |
| 638 | +mcp251xfd_spi_cmd_write_nocrc(struct mcp251xfd_buf_cmd *cmd, u16 addr) | |
| 639 | +{ | |
| 640 | + cmd->cmd = cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE | addr); | |
| 641 | +} | |
| 642 | + | |
| 643 | +static inline bool mcp251xfd_reg_in_ram(unsigned int reg) | |
| 644 | +{ | |
| 645 | + static const struct regmap_range range = | |
| 646 | + regmap_reg_range(MCP251XFD_RAM_START, | |
| 647 | + MCP251XFD_RAM_START + MCP251XFD_RAM_SIZE - 4); | |
| 648 | + | |
| 649 | + return regmap_reg_in_range(reg, &range); | |
| 650 | +} | |
| 651 | + | |
| 652 | +static inline void | |
| 653 | +__mcp251xfd_spi_cmd_crc_set_len(struct mcp251xfd_buf_cmd_crc *cmd, | |
| 654 | + u16 len, bool in_ram) | |
| 655 | +{ | |
| 656 | + /* Number of u32 for RAM access, number of u8 otherwise. */ | |
| 657 | + if (in_ram) | |
| 658 | + cmd->len = len >> 2; | |
| 659 | + else | |
| 660 | + cmd->len = len; | |
| 661 | +} | |
| 662 | + | |
| 663 | +static inline void | |
| 664 | +mcp251xfd_spi_cmd_crc_set_len_in_ram(struct mcp251xfd_buf_cmd_crc *cmd, u16 len) | |
| 665 | +{ | |
| 666 | + __mcp251xfd_spi_cmd_crc_set_len(cmd, len, true); | |
| 667 | +} | |
| 668 | + | |
| 669 | +static inline void | |
| 670 | +mcp251xfd_spi_cmd_crc_set_len_in_reg(struct mcp251xfd_buf_cmd_crc *cmd, u16 len) | |
| 671 | +{ | |
| 672 | + __mcp251xfd_spi_cmd_crc_set_len(cmd, len, false); | |
| 673 | +} | |
| 674 | + | |
| 675 | +static inline void | |
| 676 | +mcp251xfd_spi_cmd_read_crc_set_addr(struct mcp251xfd_buf_cmd_crc *cmd, u16 addr) | |
| 677 | +{ | |
| 678 | + cmd->cmd = cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ_CRC | addr); | |
| 679 | +} | |
| 680 | + | |
| 681 | +static inline void | |
| 682 | +mcp251xfd_spi_cmd_read_crc(struct mcp251xfd_buf_cmd_crc *cmd, | |
| 683 | + u16 addr, u16 len) | |
| 684 | +{ | |
| 685 | + mcp251xfd_spi_cmd_read_crc_set_addr(cmd, addr); | |
| 686 | + __mcp251xfd_spi_cmd_crc_set_len(cmd, len, mcp251xfd_reg_in_ram(addr)); | |
| 687 | +} | |
| 688 | + | |
| 689 | +static inline void | |
| 690 | +mcp251xfd_spi_cmd_write_crc_set_addr(struct mcp251xfd_buf_cmd_crc *cmd, | |
| 691 | + u16 addr) | |
| 692 | +{ | |
| 693 | + cmd->cmd = cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE_CRC | addr); | |
| 694 | +} | |
| 695 | + | |
| 696 | +static inline void | |
| 697 | +mcp251xfd_spi_cmd_write_crc(struct mcp251xfd_buf_cmd_crc *cmd, | |
| 698 | + u16 addr, u16 len) | |
| 699 | +{ | |
| 700 | + mcp251xfd_spi_cmd_write_crc_set_addr(cmd, addr); | |
| 701 | + __mcp251xfd_spi_cmd_crc_set_len(cmd, len, mcp251xfd_reg_in_ram(addr)); | |
| 702 | +} | |
| 703 | + | |
| 704 | +static inline u8 * | |
| 705 | +mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv, | |
| 706 | + union mcp251xfd_write_reg_buf *write_reg_buf, | |
| 707 | + u16 addr) | |
| 708 | +{ | |
| 709 | + u8 *data; | |
| 710 | + | |
| 711 | + if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) { | |
| 712 | + mcp251xfd_spi_cmd_write_crc_set_addr(&write_reg_buf->crc.cmd, | |
| 713 | + addr); | |
| 714 | + data = write_reg_buf->crc.data; | |
| 715 | + } else { | |
| 716 | + mcp251xfd_spi_cmd_write_nocrc(&write_reg_buf->nocrc.cmd, | |
| 717 | + addr); | |
| 718 | + data = write_reg_buf->nocrc.data; | |
| 719 | + } | |
| 720 | + | |
| 721 | + return data; | |
| 722 | +} | |
| 723 | + | |
| 724 | +static inline u16 mcp251xfd_get_tef_obj_addr(u8 n) | |
| 725 | +{ | |
| 726 | + return MCP251XFD_RAM_START + | |
| 727 | + sizeof(struct mcp251xfd_hw_tef_obj) * n; | |
| 728 | +} | |
| 729 | + | |
| 730 | +static inline u16 | |
| 731 | +mcp251xfd_get_tx_obj_addr(const struct mcp251xfd_tx_ring *ring, u8 n) | |
| 732 | +{ | |
| 733 | + return ring->base + ring->obj_size * n; | |
| 734 | +} | |
| 735 | + | |
| 736 | +static inline u16 | |
| 737 | +mcp251xfd_get_rx_obj_addr(const struct mcp251xfd_rx_ring *ring, u8 n) | |
| 738 | +{ | |
| 739 | + return ring->base + ring->obj_size * n; | |
| 740 | +} | |
| 741 | + | |
| 742 | +static inline u8 mcp251xfd_get_tef_head(const struct mcp251xfd_priv *priv) | |
| 743 | +{ | |
| 744 | + return priv->tef.head & (priv->tx->obj_num - 1); | |
| 745 | +} | |
| 746 | + | |
| 747 | +static inline u8 mcp251xfd_get_tef_tail(const struct mcp251xfd_priv *priv) | |
| 748 | +{ | |
| 749 | + return priv->tef.tail & (priv->tx->obj_num - 1); | |
| 750 | +} | |
| 751 | + | |
| 752 | +static inline u8 mcp251xfd_get_tef_len(const struct mcp251xfd_priv *priv) | |
| 753 | +{ | |
| 754 | + return priv->tef.head - priv->tef.tail; | |
| 755 | +} | |
| 756 | + | |
| 757 | +static inline u8 mcp251xfd_get_tef_linear_len(const struct mcp251xfd_priv *priv) | |
| 758 | +{ | |
| 759 | + u8 len; | |
| 760 | + | |
| 761 | + len = mcp251xfd_get_tef_len(priv); | |
| 762 | + | |
| 763 | + return min_t(u8, len, priv->tx->obj_num - mcp251xfd_get_tef_tail(priv)); | |
| 764 | +} | |
| 765 | + | |
| 766 | +static inline u8 mcp251xfd_get_tx_head(const struct mcp251xfd_tx_ring *ring) | |
| 767 | +{ | |
| 768 | + return ring->head & (ring->obj_num - 1); | |
| 769 | +} | |
| 770 | + | |
| 771 | +static inline u8 mcp251xfd_get_tx_tail(const struct mcp251xfd_tx_ring *ring) | |
| 772 | +{ | |
| 773 | + return ring->tail & (ring->obj_num - 1); | |
| 774 | +} | |
| 775 | + | |
| 776 | +static inline u8 mcp251xfd_get_tx_free(const struct mcp251xfd_tx_ring *ring) | |
| 777 | +{ | |
| 778 | + return ring->obj_num - (ring->head - ring->tail); | |
| 779 | +} | |
| 780 | + | |
| 781 | +static inline int | |
| 782 | +mcp251xfd_get_tx_nr_by_addr(const struct mcp251xfd_tx_ring *tx_ring, u8 *nr, | |
| 783 | + u16 addr) | |
| 784 | +{ | |
| 785 | + if (addr < mcp251xfd_get_tx_obj_addr(tx_ring, 0) || | |
| 786 | + addr >= mcp251xfd_get_tx_obj_addr(tx_ring, tx_ring->obj_num)) | |
| 787 | + return -ENOENT; | |
| 788 | + | |
| 789 | + *nr = (addr - mcp251xfd_get_tx_obj_addr(tx_ring, 0)) / | |
| 790 | + tx_ring->obj_size; | |
| 791 | + | |
| 792 | + return 0; | |
| 793 | +} | |
| 794 | + | |
| 795 | +static inline u8 mcp251xfd_get_rx_head(const struct mcp251xfd_rx_ring *ring) | |
| 796 | +{ | |
| 797 | + return ring->head & (ring->obj_num - 1); | |
| 798 | +} | |
| 799 | + | |
| 800 | +static inline u8 mcp251xfd_get_rx_tail(const struct mcp251xfd_rx_ring *ring) | |
| 801 | +{ | |
| 802 | + return ring->tail & (ring->obj_num - 1); | |
| 803 | +} | |
| 804 | + | |
| 805 | +static inline u8 mcp251xfd_get_rx_len(const struct mcp251xfd_rx_ring *ring) | |
| 806 | +{ | |
| 807 | + return ring->head - ring->tail; | |
| 808 | +} | |
| 809 | + | |
| 810 | +static inline u8 | |
| 811 | +mcp251xfd_get_rx_linear_len(const struct mcp251xfd_rx_ring *ring) | |
| 812 | +{ | |
| 813 | + u8 len; | |
| 814 | + | |
| 815 | + len = mcp251xfd_get_rx_len(ring); | |
| 816 | + | |
| 817 | + return min_t(u8, len, ring->obj_num - mcp251xfd_get_rx_tail(ring)); | |
| 818 | +} | |
| 819 | + | |
| 820 | +#define mcp251xfd_for_each_tx_obj(ring, _obj, n) \ | |
| 821 | + for ((n) = 0, (_obj) = &(ring)->obj[(n)]; \ | |
| 822 | + (n) < (ring)->obj_num; \ | |
| 823 | + (n)++, (_obj) = &(ring)->obj[(n)]) | |
| 824 | + | |
| 825 | +#define mcp251xfd_for_each_rx_ring(priv, ring, n) \ | |
| 826 | + for ((n) = 0, (ring) = *((priv)->rx + (n)); \ | |
| 827 | + (n) < (priv)->rx_ring_num; \ | |
| 828 | + (n)++, (ring) = *((priv)->rx + (n))) | |
| 829 | + | |
| 830 | +int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv); | |
| 831 | +u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size, | |
| 832 | + const void *data, size_t data_size); | |
| 833 | +u16 mcp251xfd_crc16_compute(const void *data, size_t data_size); | |
| 834 | + | |
| 835 | +#endif | |
| @@ -454,7 +454,7 @@ static int ti_hecc_get_berr_counter(const struct net_device *ndev, · 453 unmodified lines | ||
| 454 | 454 | /* ti_hecc_xmit: HECC Transmit |
| 455 | 455 | * |
| 456 | 456 | * The transmit mailboxes start from 0 to HECC_MAX_TX_MBOX. In HECC the |
| 457 | − * priority of the mailbox for tranmission is dependent upon priority setting | |
| 457 | + * priority of the mailbox for transmission is dependent upon priority setting | |
| 458 | 458 | * field in mailbox registers. The mailbox with highest value in priority field |
| 459 | 459 | * is transmitted first. Only when two mailboxes have the same value in |
| 460 | 460 | * priority field the highest numbered mailbox is transmitted first. |
| @@ -857,7 +857,7 @@ static int ti_hecc_probe(struct platform_device *pdev) · 396 unmodified lines | ||
| 857 | 857 | struct net_device *ndev = (struct net_device *)0; |
| 858 | 858 | struct ti_hecc_priv *priv; |
| 859 | 859 | struct device_node *np = pdev->dev.of_node; |
| 860 | − struct resource *res, *irq; | |
| 860 | + struct resource *irq; | |
| 861 | 861 | struct regulator *reg_xceiver; |
| 862 | 862 | int err = -ENODEV; |
| 863 | 863 | |
| @@ -878,39 +878,22 @@ static int ti_hecc_probe(struct platform_device *pdev) · 14 unmodified lines | ||
| 878 | 878 | priv = netdev_priv(ndev); |
| 879 | 879 | |
| 880 | 880 | /* handle hecc memory */ |
| 881 | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hecc"); | |
| 882 | − if (!res) { | |
| 883 | − dev_err(&pdev->dev, "can't get IORESOURCE_MEM hecc\n"); | |
| 884 | − return -EINVAL; | |
| 885 | − } | |
| 886 | − | |
| 887 | − priv->base = devm_ioremap_resource(&pdev->dev, res); | |
| 881 | + priv->base = devm_platform_ioremap_resource_byname(pdev, "hecc"); | |
| 888 | 882 | if (IS_ERR(priv->base)) { |
| 889 | 883 | dev_err(&pdev->dev, "hecc ioremap failed\n"); |
| 890 | 884 | return PTR_ERR(priv->base); |
| 891 | 885 | } |
| 892 | 886 | |
| 893 | 887 | /* handle hecc-ram memory */ |
| 894 | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hecc-ram"); | |
| 895 | − if (!res) { | |
| 896 | − dev_err(&pdev->dev, "can't get IORESOURCE_MEM hecc-ram\n"); | |
| 897 | − return -EINVAL; | |
| 898 | − } | |
| 899 | − | |
| 900 | − priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res); | |
| 888 | + priv->hecc_ram = devm_platform_ioremap_resource_byname(pdev, | |
| 889 | + "hecc-ram"); | |
| 901 | 890 | if (IS_ERR(priv->hecc_ram)) { |
| 902 | 891 | dev_err(&pdev->dev, "hecc-ram ioremap failed\n"); |
| 903 | 892 | return PTR_ERR(priv->hecc_ram); |
| 904 | 893 | } |
| 905 | 894 | |
| 906 | 895 | /* handle mbx memory */ |
| 907 | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mbx"); | |
| 908 | − if (!res) { | |
| 909 | − dev_err(&pdev->dev, "can't get IORESOURCE_MEM mbx\n"); | |
| 910 | − return -EINVAL; | |
| 911 | − } | |
| 912 | − | |
| 913 | − priv->mbx = devm_ioremap_resource(&pdev->dev, res); | |
| 896 | + priv->mbx = devm_platform_ioremap_resource_byname(pdev, "mbx"); | |
| 914 | 897 | if (IS_ERR(priv->mbx)) { |
| 915 | 898 | dev_err(&pdev->dev, "mbx ioremap failed\n"); |
| 916 | 899 | return PTR_ERR(priv->mbx); |
| @@ -90,7 +90,7 @@ config CAN_PEAK_USB · 89 unmodified lines | ||
| 90 | 90 | tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD" |
| 91 | 91 | help |
| 92 | 92 | This driver supports the PEAK-System Technik USB adapters that enable |
| 93 | − access to the CAN bus, with repect to the CAN 2.0b and/or CAN-FD | |
| 93 | + access to the CAN bus, with respect to the CAN 2.0b and/or CAN-FD | |
| 94 | 94 | standards, that is: |
| 95 | 95 | |
| 96 | 96 | PCAN-USB single CAN 2.0b channel USB adapter |
| @@ -828,7 +828,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, · 827 unmodified lines | ||
| 828 | 828 | |
| 829 | 829 | netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ |
| 830 | 830 | |
| 831 | − /* dev settup */ | |
| 831 | + /* dev setup */ | |
| 832 | 832 | strcpy(dev->bt_const.name, "gs_usb"); |
| 833 | 833 | dev->bt_const.tseg1_min = bt_const->tseg1_min; |
| 834 | 834 | dev->bt_const.tseg1_max = bt_const->tseg1_max; |
| @@ -852,7 +852,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, · 17 unmodified lines | ||
| 852 | 852 | dev->tx_context[rc].echo_id = GS_MAX_TX_URBS; |
| 853 | 853 | } |
| 854 | 854 | |
| 855 | − /* can settup */ | |
| 855 | + /* can setup */ | |
| 856 | 856 | dev->can.state = CAN_STATE_STOPPED; |
| 857 | 857 | dev->can.clock.freq = bt_const->fclk_can; |
| 858 | 858 | dev->can.bittiming_const = &dev->bt_const; |
| @@ -28,7 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #define MCBA_CTX_FREE MCBA_MAX_TX_URBS |
| 29 | 29 | |
| 30 | 30 | /* RX buffer must be bigger than msg size since at the |
| 31 | − * beggining USB messages are stacked. | |
| 31 | + * beginning USB messages are stacked. | |
| 32 | 32 | */ |
| 33 | 33 | #define MCBA_USB_RX_BUFF_SIZE 64 |
| 34 | 34 | #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg)) |
| @@ -793,7 +793,7 @@ static int mcba_usb_probe(struct usb_interface *intf, · 758 unmodified lines | ||
| 793 | 793 | { |
| 794 | 794 | struct net_device *netdev; |
| 795 | 795 | struct mcba_priv *priv; |
| 796 | − int err = -ENOMEM; | |
| 796 | + int err; | |
| 797 | 797 | struct usb_device *usbdev = interface_to_usbdev(intf); |
| 798 | 798 | |
| 799 | 799 | netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS); |
| @@ -34,6 +34,23 @@ MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter"); · 33 unmodified lines | ||
| 34 | 34 | #define PCAN_USB_CMD_LEN (PCAN_USB_CMD_ARGS + \ |
| 35 | 35 | PCAN_USB_CMD_ARGS_LEN) |
| 36 | 36 | |
| 37 | +/* PCAN-USB commands */ | |
| 38 | +#define PCAN_USB_CMD_BITRATE 1 | |
| 39 | +#define PCAN_USB_CMD_SET_BUS 3 | |
| 40 | +#define PCAN_USB_CMD_DEVID 4 | |
| 41 | +#define PCAN_USB_CMD_SN 6 | |
| 42 | +#define PCAN_USB_CMD_REGISTER 9 | |
| 43 | +#define PCAN_USB_CMD_EXT_VCC 10 | |
| 44 | +#define PCAN_USB_CMD_ERR_FR 11 | |
| 45 | + | |
| 46 | +/* PCAN_USB_CMD_SET_BUS number arg */ | |
| 47 | +#define PCAN_USB_BUS_XCVER 2 | |
| 48 | +#define PCAN_USB_BUS_SILENT_MODE 3 | |
| 49 | + | |
| 50 | +/* PCAN_USB_CMD_xxx functions */ | |
| 51 | +#define PCAN_USB_GET 1 | |
| 52 | +#define PCAN_USB_SET 2 | |
| 53 | + | |
| 37 | 54 | /* PCAN-USB command timeout (ms.) */ |
| 38 | 55 | #define PCAN_USB_COMMAND_TIMEOUT 1000 |
| 39 | 56 | |
| @@ -66,6 +83,10 @@ MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter"); · 26 unmodified lines | ||
| 66 | 83 | #define PCAN_USB_ERROR_QOVR 0x40 |
| 67 | 84 | #define PCAN_USB_ERROR_TXQFULL 0x80 |
| 68 | 85 | |
| 86 | +#define PCAN_USB_ERROR_BUS (PCAN_USB_ERROR_BUS_LIGHT | \ | |
| 87 | + PCAN_USB_ERROR_BUS_HEAVY | \ | |
| 88 | + PCAN_USB_ERROR_BUS_OFF) | |
| 89 | + | |
| 69 | 90 | /* SJA1000 modes */ |
| 70 | 91 | #define SJA1000_MODE_NORMAL 0x00 |
| 71 | 92 | #define SJA1000_MODE_INIT 0x01 |
| @@ -85,11 +106,25 @@ MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter"); · 13 unmodified lines | ||
| 85 | 106 | #define PCAN_USB_REC_TS 4 |
| 86 | 107 | #define PCAN_USB_REC_BUSEVT 5 |
| 87 | 108 | |
| 109 | +/* CAN bus events notifications selection mask */ | |
| 110 | +#define PCAN_USB_ERR_RXERR 0x02 /* ask for rxerr counter */ | |
| 111 | +#define PCAN_USB_ERR_TXERR 0x04 /* ask for txerr counter */ | |
| 112 | + | |
| 113 | +/* This mask generates an usb packet each time the state of the bus changes. | |
| 114 | + * In other words, its interest is to know which side among rx and tx is | |
| 115 | + * responsible of the change of the bus state. | |
| 116 | + */ | |
| 117 | +#define PCAN_USB_BERR_MASK (PCAN_USB_ERR_RXERR | PCAN_USB_ERR_TXERR) | |
| 118 | + | |
| 119 | +/* identify bus event packets with rx/tx error counters */ | |
| 120 | +#define PCAN_USB_ERR_CNT 0x80 | |
| 121 | + | |
| 88 | 122 | /* private to PCAN-USB adapter */ |
| 89 | 123 | struct pcan_usb { |
| 90 | 124 | struct peak_usb_device dev; |
| 91 | 125 | struct peak_time_ref time_ref; |
| 92 | 126 | struct timer_list restart_timer; |
| 127 | + struct can_berr_counter bec; | |
| 93 | 128 | }; |
| 94 | 129 | |
| 95 | 130 | /* incoming message context for decoding */ |
| @@ -172,7 +207,8 @@ static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode) · 76 unmodified lines | ||
| 172 | 207 | [1] = mode, |
| 173 | 208 | }; |
| 174 | 209 | |
| 175 | − return pcan_usb_send_cmd(dev, 9, 2, args); | |
| 210 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_REGISTER, PCAN_USB_SET, | |
| 211 | + args); | |
| 176 | 212 | } |
| 177 | 213 | |
| 178 | 214 | static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff) |
| @@ -181,7 +217,8 @@ static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff) · 2 unmodified lines | ||
| 181 | 217 | [0] = !!onoff, |
| 182 | 218 | }; |
| 183 | 219 | |
| 184 | − return pcan_usb_send_cmd(dev, 3, 2, args); | |
| 220 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_SET_BUS, PCAN_USB_BUS_XCVER, | |
| 221 | + args); | |
| 185 | 222 | } |
| 186 | 223 | |
| 187 | 224 | static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff) |
| @@ -190,7 +227,18 @@ static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff) · 2 unmodified lines | ||
| 190 | 227 | [0] = !!onoff, |
| 191 | 228 | }; |
| 192 | 229 | |
| 193 | − return pcan_usb_send_cmd(dev, 3, 3, args); | |
| 230 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_SET_BUS, | |
| 231 | + PCAN_USB_BUS_SILENT_MODE, args); | |
| 232 | +} | |
| 233 | + | |
| 234 | +/* send the cmd to be notified from bus errors */ | |
| 235 | +static int pcan_usb_set_err_frame(struct peak_usb_device *dev, u8 err_mask) | |
| 236 | +{ | |
| 237 | + u8 args[PCAN_USB_CMD_ARGS_LEN] = { | |
| 238 | + [0] = err_mask, | |
| 239 | + }; | |
| 240 | + | |
| 241 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_ERR_FR, PCAN_USB_SET, args); | |
| 194 | 242 | } |
| 195 | 243 | |
| 196 | 244 | static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) |
| @@ -199,7 +247,7 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) · 2 unmodified lines | ||
| 199 | 247 | [0] = !!onoff, |
| 200 | 248 | }; |
| 201 | 249 | |
| 202 | − return pcan_usb_send_cmd(dev, 10, 2, args); | |
| 250 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args); | |
| 203 | 251 | } |
| 204 | 252 | |
| 205 | 253 | /* |
| @@ -223,7 +271,7 @@ static int pcan_usb_set_bittiming(struct peak_usb_device *dev, · 17 unmodified lines | ||
| 223 | 271 | args[0] = btr1; |
| 224 | 272 | args[1] = btr0; |
| 225 | 273 | |
| 226 | − return pcan_usb_send_cmd(dev, 1, 2, args); | |
| 274 | + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_BITRATE, PCAN_USB_SET, args); | |
| 227 | 275 | } |
| 228 | 276 | |
| 229 | 277 | /* |
| @@ -307,7 +355,7 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number) · 77 unmodified lines | ||
| 307 | 355 | u8 args[PCAN_USB_CMD_ARGS_LEN]; |
| 308 | 356 | int err; |
| 309 | 357 | |
| 310 | − err = pcan_usb_wait_rsp(dev, 6, 1, args); | |
| 358 | + err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_SN, PCAN_USB_GET, args); | |
| 311 | 359 | if (err) { |
| 312 | 360 | netdev_err(dev->netdev, "getting serial failure: %d\n", err); |
| 313 | 361 | } else if (serial_number) { |
| @@ -328,7 +376,7 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id) · 14 unmodified lines | ||
| 328 | 376 | u8 args[PCAN_USB_CMD_ARGS_LEN]; |
| 329 | 377 | int err; |
| 330 | 378 | |
| 331 | − err = pcan_usb_wait_rsp(dev, 4, 1, args); | |
| 379 | + err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args); | |
| 332 | 380 | if (err) |
| 333 | 381 | netdev_err(dev->netdev, "getting device id failure: %d\n", err); |
| 334 | 382 | else if (device_id) |
| @@ -426,7 +474,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, · 91 unmodified lines | ||
| 426 | 474 | new_state = CAN_STATE_BUS_OFF; |
| 427 | 475 | break; |
| 428 | 476 | } |
| 429 | − if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) { | |
| 477 | + if (n & ~PCAN_USB_ERROR_BUS) { | |
| 430 | 478 | /* |
| 431 | 479 | * trick to bypass next comparison and process other |
| 432 | 480 | * errors |
| @@ -450,7 +498,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, · 17 unmodified lines | ||
| 450 | 498 | new_state = CAN_STATE_ERROR_WARNING; |
| 451 | 499 | break; |
| 452 | 500 | } |
| 453 | − if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) { | |
| 501 | + if (n & ~PCAN_USB_ERROR_BUS) { | |
| 454 | 502 | /* |
| 455 | 503 | * trick to bypass next comparison and process other |
| 456 | 504 | * errors |
| @@ -489,29 +537,50 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, · 32 unmodified lines | ||
| 489 | 537 | |
| 490 | 538 | case CAN_STATE_ERROR_PASSIVE: |
| 491 | 539 | cf->can_id |= CAN_ERR_CRTL; |
| 492 | − cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE | | |
| 493 | − CAN_ERR_CRTL_RX_PASSIVE; | |
| 540 | + cf->data[1] = (mc->pdev->bec.txerr > mc->pdev->bec.rxerr) ? | |
| 541 | + CAN_ERR_CRTL_TX_PASSIVE : | |
| 542 | + CAN_ERR_CRTL_RX_PASSIVE; | |
| 543 | + cf->data[6] = mc->pdev->bec.txerr; | |
| 544 | + cf->data[7] = mc->pdev->bec.rxerr; | |
| 545 | + | |
| 494 | 546 | mc->pdev->dev.can.can_stats.error_passive++; |
| 495 | 547 | break; |
| 496 | 548 | |
| 497 | 549 | case CAN_STATE_ERROR_WARNING: |
| 498 | 550 | cf->can_id |= CAN_ERR_CRTL; |
| 499 | − cf->data[1] |= CAN_ERR_CRTL_TX_WARNING | | |
| 500 | − CAN_ERR_CRTL_RX_WARNING; | |
| 551 | + cf->data[1] = (mc->pdev->bec.txerr > mc->pdev->bec.rxerr) ? | |
| 552 | + CAN_ERR_CRTL_TX_WARNING : | |
| 553 | + CAN_ERR_CRTL_RX_WARNING; | |
| 554 | + cf->data[6] = mc->pdev->bec.txerr; | |
| 555 | + cf->data[7] = mc->pdev->bec.rxerr; | |
| 556 | + | |
| 501 | 557 | mc->pdev->dev.can.can_stats.error_warning++; |
| 502 | 558 | break; |
| 503 | 559 | |
| 504 | 560 | case CAN_STATE_ERROR_ACTIVE: |
| 505 | 561 | cf->can_id |= CAN_ERR_CRTL; |
| 506 | 562 | cf->data[1] = CAN_ERR_CRTL_ACTIVE; |
| 563 | + | |
| 564 | + /* sync local copies of rxerr/txerr counters */ | |
| 565 | + mc->pdev->bec.txerr = 0; | |
| 566 | + mc->pdev->bec.rxerr = 0; | |
| 507 | 567 | break; |
| 508 | 568 | |
| 509 | 569 | default: |
| 510 | 570 | /* CAN_STATE_MAX (trick to handle other errors) */ |
| 511 | − cf->can_id |= CAN_ERR_CRTL; | |
| 512 | − cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; | |
| 513 | − mc->netdev->stats.rx_over_errors++; | |
| 514 | − mc->netdev->stats.rx_errors++; | |
| 571 | + if (n & PCAN_USB_ERROR_TXQFULL) | |
| 572 | + netdev_dbg(mc->netdev, "device Tx queue full)\n"); | |
| 573 | + | |
| 574 | + if (n & PCAN_USB_ERROR_RXQOVR) { | |
| 575 | + netdev_dbg(mc->netdev, "data overrun interrupt\n"); | |
| 576 | + cf->can_id |= CAN_ERR_CRTL; | |
| 577 | + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; | |
| 578 | + mc->netdev->stats.rx_over_errors++; | |
| 579 | + mc->netdev->stats.rx_errors++; | |
| 580 | + } | |
| 581 | + | |
| 582 | + cf->data[6] = mc->pdev->bec.txerr; | |
| 583 | + cf->data[7] = mc->pdev->bec.rxerr; | |
| 515 | 584 | |
| 516 | 585 | new_state = mc->pdev->dev.can.state; |
| 517 | 586 | break; |
| @@ -533,6 +602,30 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, · 15 unmodified lines | ||
| 533 | 602 | return 0; |
| 534 | 603 | } |
| 535 | 604 | |
| 605 | +/* decode bus event usb packet: first byte contains rxerr while 2nd one contains | |
| 606 | + * txerr. | |
| 607 | + */ | |
| 608 | +static int pcan_usb_handle_bus_evt(struct pcan_usb_msg_context *mc, u8 ir) | |
| 609 | +{ | |
| 610 | + struct pcan_usb *pdev = mc->pdev; | |
| 611 | + | |
| 612 | + /* acccording to the content of the packet */ | |
| 613 | + switch (ir) { | |
| 614 | + case PCAN_USB_ERR_CNT: | |
| 615 | + | |
| 616 | + /* save rx/tx error counters from in the device context */ | |
| 617 | + pdev->bec.rxerr = mc->ptr[0]; | |
| 618 | + pdev->bec.txerr = mc->ptr[1]; | |
| 619 | + break; | |
| 620 | + | |
| 621 | + default: | |
| 622 | + /* reserved */ | |
| 623 | + break; | |
| 624 | + } | |
| 625 | + | |
| 626 | + return 0; | |
| 627 | +} | |
| 628 | + | |
| 536 | 629 | /* |
| 537 | 630 | * decode non-data usb message |
| 538 | 631 | */ |
| @@ -587,9 +680,10 @@ static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc, · 48 unmodified lines | ||
| 587 | 680 | break; |
| 588 | 681 | |
| 589 | 682 | case PCAN_USB_REC_BUSEVT: |
| 590 | − /* error frame/bus event */ | |
| 591 | − if (n & PCAN_USB_ERROR_TXQFULL) | |
| 592 | − netdev_dbg(mc->netdev, "device Tx queue full)\n"); | |
| 683 | + /* bus event notifications (get rxerr/txerr) */ | |
| 684 | + err = pcan_usb_handle_bus_evt(mc, n); | |
| 685 | + if (err) | |
| 686 | + return err; | |
| 593 | 687 | break; |
| 594 | 688 | default: |
| 595 | 689 | netdev_err(mc->netdev, "unexpected function %u\n", f); |
| @@ -773,20 +867,44 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb, · 177 unmodified lines | ||
| 773 | 867 | return 0; |
| 774 | 868 | } |
| 775 | 869 | |
| 870 | +/* socket callback used to copy berr counters values received through USB */ | |
| 871 | +static int pcan_usb_get_berr_counter(const struct net_device *netdev, | |
| 872 | + struct can_berr_counter *bec) | |
| 873 | +{ | |
| 874 | + struct peak_usb_device *dev = netdev_priv(netdev); | |
| 875 | + struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); | |
| 876 | + | |
| 877 | + *bec = pdev->bec; | |
| 878 | + | |
| 879 | + /* must return 0 */ | |
| 880 | + return 0; | |
| 881 | +} | |
| 882 | + | |
| 776 | 883 | /* |
| 777 | 884 | * start interface |
| 778 | 885 | */ |
| 779 | 886 | static int pcan_usb_start(struct peak_usb_device *dev) |
| 780 | 887 | { |
| 781 | 888 | struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); |
| 889 | + int err; | |
| 782 | 890 | |
| 783 | 891 | /* number of bits used in timestamps read from adapter struct */ |
| 784 | 892 | peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb); |
| 785 | 893 | |
| 894 | + pdev->bec.rxerr = 0; | |
| 895 | + pdev->bec.txerr = 0; | |
| 896 | + | |
| 897 | + /* be notified on error counter changes (if requested by user) */ | |
| 898 | + if (dev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { | |
| 899 | + err = pcan_usb_set_err_frame(dev, PCAN_USB_BERR_MASK); | |
| 900 | + if (err) | |
| 901 | + netdev_warn(dev->netdev, | |
| 902 | + "Asking for BERR reporting error %u\n", | |
| 903 | + err); | |
| 904 | + } | |
| 905 | + | |
| 786 | 906 | /* if revision greater than 3, can put silent mode on/off */ |
| 787 | 907 | if (dev->device_rev > 3) { |
| 788 | − int err; | |
| 789 | − | |
| 790 | 908 | err = pcan_usb_set_silent(dev, |
| 791 | 909 | dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY); |
| 792 | 910 | if (err) |
| @@ -873,7 +991,8 @@ const struct peak_usb_adapter pcan_usb = { · 80 unmodified lines | ||
| 873 | 991 | .name = "PCAN-USB", |
| 874 | 992 | .device_id = PCAN_USB_PRODUCT_ID, |
| 875 | 993 | .ctrl_count = 1, |
| 876 | − .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, | |
| 994 | + .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | | |
| 995 | + CAN_CTRLMODE_BERR_REPORTING, | |
| 877 | 996 | .clock = { |
| 878 | 997 | .freq = PCAN_USB_CRYSTAL_HZ / 2 , |
| 879 | 998 | }, |
| @@ -906,4 +1025,5 @@ const struct peak_usb_adapter pcan_usb = { · 26 unmodified lines | ||
| 906 | 1025 | .dev_encode_msg = pcan_usb_encode_msg, |
| 907 | 1026 | .dev_start = pcan_usb_start, |
| 908 | 1027 | .dev_restart_async = pcan_usb_restart_async, |
| 1028 | + .do_get_berr_counter = pcan_usb_get_berr_counter, | |
| 909 | 1029 | }; |
| @@ -35,7 +35,7 @@ MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter"); · 34 unmodified lines | ||
| 35 | 35 | #define PCAN_UFD_RX_BUFFER_SIZE 2048 |
| 36 | 36 | #define PCAN_UFD_TX_BUFFER_SIZE 512 |
| 37 | 37 | |
| 38 | −/* read some versions info from the hw devcie */ | |
| 38 | +/* read some versions info from the hw device */ | |
| 39 | 39 | struct __packed pcan_ufd_fw_info { |
| 40 | 40 | __le16 size_of; /* sizeof this */ |
| 41 | 41 | __le16 type; /* type of this structure */ |
| @@ -796,7 +796,7 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev) · 754 unmodified lines | ||
| 796 | 796 | return err; |
| 797 | 797 | } |
| 798 | 798 | |
| 799 | −/* socket callback used to copy berr counters values receieved through USB */ | |
| 799 | +/* socket callback used to copy berr counters values received through USB */ | |
| 800 | 800 | static int pcan_usb_fd_get_berr_counter(const struct net_device *netdev, |
| 801 | 801 | struct can_berr_counter *bec) |
| 802 | 802 | { |
| @@ -186,7 +186,7 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, int id, ...) · 185 unmodified lines | ||
| 186 | 186 | |
| 187 | 187 | len = pc - pm->rec_ptr; |
| 188 | 188 | if (len > 0) { |
| 189 | − *pm->u.rec_cnt = cpu_to_le32(le32_to_cpu(*pm->u.rec_cnt) + 1); | |
| 189 | + le32_add_cpu(pm->u.rec_cnt, 1); | |
| 190 | 190 | *pm->rec_ptr = id; |
| 191 | 191 | |
| 192 | 192 | pm->rec_ptr = pc; |
| @@ -973,7 +973,7 @@ int pcan_usb_pro_probe(struct usb_interface *intf) · 780 unmodified lines | ||
| 973 | 973 | struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc; |
| 974 | 974 | |
| 975 | 975 | /* |
| 976 | − * below is the list of valid ep addreses. Any other ep address | |
| 976 | + * below is the list of valid ep addresses. Any other ep address | |
| 977 | 977 | * is considered as not-CAN interface address => no dev created |
| 978 | 978 | */ |
| 979 | 979 | switch (ep->bEndpointAddress) { |
| @@ -1445,7 +1445,7 @@ static int ucan_probe(struct usb_interface *intf, · 1444 unmodified lines | ||
| 1445 | 1445 | |
| 1446 | 1446 | /* request the device information and store it in ctl_msg_buffer |
| 1447 | 1447 | * |
| 1448 | − * note: ucan_ctrl_command_* wrappers connot be used yet | |
| 1448 | + * note: ucan_ctrl_command_* wrappers cannot be used yet | |
| 1449 | 1449 | * because `up` is initialised in Stage 3 |
| 1450 | 1450 | */ |
| 1451 | 1451 | ret = usb_control_msg(udev, |
| @@ -1494,7 +1494,7 @@ static int ucan_probe(struct usb_interface *intf, · 42 unmodified lines | ||
| 1494 | 1494 | |
| 1495 | 1495 | up = netdev_priv(netdev); |
| 1496 | 1496 | |
| 1497 | − /* initialze data */ | |
| 1497 | + /* initialize data */ | |
| 1498 | 1498 | up->udev = udev; |
| 1499 | 1499 | up->intf = intf; |
| 1500 | 1500 | up->netdev = netdev; |
| @@ -88,7 +88,7 @@ enum usb_8dev_cmd { · 87 unmodified lines | ||
| 88 | 88 | |
| 89 | 89 | /* status */ |
| 90 | 90 | #define USB_8DEV_STATUSMSG_OK 0x00 /* Normal condition. */ |
| 91 | −#define USB_8DEV_STATUSMSG_OVERRUN 0x01 /* Overrun occured when sending */ | |
| 91 | +#define USB_8DEV_STATUSMSG_OVERRUN 0x01 /* Overrun occurred when sending */ | |
| 92 | 92 | #define USB_8DEV_STATUSMSG_BUSLIGHT 0x02 /* Error counter has reached 96 */ |
| 93 | 93 | #define USB_8DEV_STATUSMSG_BUSHEAVY 0x03 /* Error count. has reached 128 */ |
| 94 | 94 | #define USB_8DEV_STATUSMSG_BUSOFF 0x04 /* Device is in BUSOFF */ |
| @@ -165,7 +165,7 @@ struct __packed usb_8dev_rx_msg { · 70 unmodified lines | ||
| 165 | 165 | /* command frame */ |
| 166 | 166 | struct __packed usb_8dev_cmd_msg { |
| 167 | 167 | u8 begin; |
| 168 | − u8 channel; /* unkown - always 0 */ | |
| 168 | + u8 channel; /* unknown - always 0 */ | |
| 169 | 169 | u8 command; /* command to execute */ |
| 170 | 170 | u8 opt1; /* optional parameter / return value */ |
| 171 | 171 | u8 opt2; /* optional parameter 2 */ |
| @@ -259,7 +259,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = { · 258 unmodified lines | ||
| 259 | 259 | .tseg2_min = 1, |
| 260 | 260 | .tseg2_max = 128, |
| 261 | 261 | .sjw_max = 128, |
| 262 | − .brp_min = 1, | |
| 262 | + .brp_min = 2, | |
| 263 | 263 | .brp_max = 256, |
| 264 | 264 | .brp_inc = 1, |
| 265 | 265 | }; |
| @@ -272,7 +272,7 @@ static struct can_bittiming_const xcan_data_bittiming_const_canfd2 = { · 6 unmodified lines | ||
| 272 | 272 | .tseg2_min = 1, |
| 273 | 273 | .tseg2_max = 16, |
| 274 | 274 | .sjw_max = 16, |
| 275 | − .brp_min = 1, | |
| 275 | + .brp_min = 2, | |
| 276 | 276 | .brp_max = 256, |
| 277 | 277 | .brp_inc = 1, |
| 278 | 278 | }; |
| @@ -1308,7 +1308,7 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) · 1029 unmodified lines | ||
| 1308 | 1308 | /** |
| 1309 | 1309 | * xcan_interrupt - CAN Isr |
| 1310 | 1310 | * @irq: irq number |
| 1311 | − * @dev_id: device id poniter | |
| 1311 | + * @dev_id: device id pointer | |
| 1312 | 1312 | * |
| 1313 | 1313 | * This is the xilinx CAN Isr. It checks for the type of interrupt |
| 1314 | 1314 | * and invokes the corresponding ISR. |
| @@ -1369,9 +1369,13 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) · 54 unmodified lines | ||
| 1369 | 1369 | static void xcan_chip_stop(struct net_device *ndev) |
| 1370 | 1370 | { |
| 1371 | 1371 | struct xcan_priv *priv = netdev_priv(ndev); |
| 1372 | + int ret; | |
| 1372 | 1373 | |
| 1373 | 1374 | /* Disable interrupts and leave the can in configuration mode */ |
| 1374 | − set_reset_mode(ndev); | |
| 1375 | + ret = set_reset_mode(ndev); | |
| 1376 | + if (ret < 0) | |
| 1377 | + netdev_dbg(ndev, "set_reset_mode() Failed\n"); | |
| 1378 | + | |
| 1375 | 1379 | priv->can.state = CAN_STATE_STOPPED; |
| 1376 | 1380 | } |
| 1377 | 1381 | |
| @@ -1667,7 +1671,7 @@ static int xcan_probe(struct platform_device *pdev) · 289 unmodified lines | ||
| 1667 | 1671 | void __iomem *addr; |
| 1668 | 1672 | int ret; |
| 1669 | 1673 | int rx_max, tx_max; |
| 1670 | − int hw_tx_max, hw_rx_max; | |
| 1674 | + u32 hw_tx_max = 0, hw_rx_max = 0; | |
| 1671 | 1675 | const char *hw_tx_max_property; |
| 1672 | 1676 | |
| 1673 | 1677 | /* Get the virtual base address for the device */ |
| @@ -1720,7 +1724,7 @@ static int xcan_probe(struct platform_device *pdev) · 46 unmodified lines | ||
| 1720 | 1724 | */ |
| 1721 | 1725 | if (!(devtype->flags & XCAN_FLAG_TX_MAILBOXES) && |
| 1722 | 1726 | (devtype->flags & XCAN_FLAG_TXFEMP)) |
| 1723 | − tx_max = min(hw_tx_max, 2); | |
| 1727 | + tx_max = min(hw_tx_max, 2U); | |
| 1724 | 1728 | else |
| 1725 | 1729 | tx_max = 1; |
| 1726 | 1730 | |
| @@ -33,12 +33,12 @@ config NET_DSA_LANTIQ_GSWIP · 32 unmodified lines | ||
| 33 | 33 | the xrx200 / VR9 SoC. |
| 34 | 34 | |
| 35 | 35 | config NET_DSA_MT7530 |
| 36 | − tristate "Mediatek MT7530 Ethernet switch support" | |
| 36 | + tristate "MediaTek MT753x and MT7621 Ethernet switch support" | |
| 37 | 37 | depends on NET_DSA |
| 38 | 38 | select NET_DSA_TAG_MTK |
| 39 | 39 | help |
| 40 | − This enables support for the Mediatek MT7530 Ethernet switch | |
| 41 | − chip. | |
| 40 | + This enables support for the MediaTek MT7530, MT7531, and MT7621 | |
| 41 | + Ethernet switch chips. | |
| 42 | 42 | |
| 43 | 43 | config NET_DSA_MV88E6060 |
| 44 | 44 | tristate "Marvell 88E6060 ethernet switch chip support" |
| @@ -17,8 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 18 | 18 | */ |
| 19 | 19 | |
| 20 | −#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 21 | − | |
| 22 | 20 | #include <linux/delay.h> |
| 23 | 21 | #include <linux/export.h> |
| 24 | 22 | #include <linux/gpio.h> |
| @@ -767,8 +765,11 @@ static int b53_switch_reset(struct b53_device *dev) · 742 unmodified lines | ||
| 767 | 765 | usleep_range(1000, 2000); |
| 768 | 766 | } while (timeout-- > 0); |
| 769 | 767 | |
| 770 | − if (timeout == 0) | |
| 768 | + if (timeout == 0) { | |
| 769 | + dev_err(dev->dev, | |
| 770 | + "Timeout waiting for SW_RST to clear!\n"); | |
| 771 | 771 | return -ETIMEDOUT; |
| 772 | + } | |
| 772 | 773 | } |
| 773 | 774 | |
| 774 | 775 | b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); |
| @@ -976,6 +977,54 @@ int b53_get_sset_count(struct dsa_switch *ds, int port, int sset) · 201 unmodified lines | ||
| 976 | 977 | } |
| 977 | 978 | EXPORT_SYMBOL(b53_get_sset_count); |
| 978 | 979 | |
| 980 | +enum b53_devlink_resource_id { | |
| 981 | + B53_DEVLINK_PARAM_ID_VLAN_TABLE, | |
| 982 | +}; | |
| 983 | + | |
| 984 | +static u64 b53_devlink_vlan_table_get(void *priv) | |
| 985 | +{ | |
| 986 | + struct b53_device *dev = priv; | |
| 987 | + struct b53_vlan *vl; | |
| 988 | + unsigned int i; | |
| 989 | + u64 count = 0; | |
| 990 | + | |
| 991 | + for (i = 0; i < dev->num_vlans; i++) { | |
| 992 | + vl = &dev->vlans[i]; | |
| 993 | + if (vl->members) | |
| 994 | + count++; | |
| 995 | + } | |
| 996 | + | |
| 997 | + return count; | |
| 998 | +} | |
| 999 | + | |
| 1000 | +int b53_setup_devlink_resources(struct dsa_switch *ds) | |
| 1001 | +{ | |
| 1002 | + struct devlink_resource_size_params size_params; | |
| 1003 | + struct b53_device *dev = ds->priv; | |
| 1004 | + int err; | |
| 1005 | + | |
| 1006 | + devlink_resource_size_params_init(&size_params, dev->num_vlans, | |
| 1007 | + dev->num_vlans, | |
| 1008 | + 1, DEVLINK_RESOURCE_UNIT_ENTRY); | |
| 1009 | + | |
| 1010 | + err = dsa_devlink_resource_register(ds, "VLAN", dev->num_vlans, | |
| 1011 | + B53_DEVLINK_PARAM_ID_VLAN_TABLE, | |
| 1012 | + DEVLINK_RESOURCE_ID_PARENT_TOP, | |
| 1013 | + &size_params); | |
| 1014 | + if (err) | |
| 1015 | + goto out; | |
| 1016 | + | |
| 1017 | + dsa_devlink_resource_occ_get_register(ds, | |
| 1018 | + B53_DEVLINK_PARAM_ID_VLAN_TABLE, | |
| 1019 | + b53_devlink_vlan_table_get, dev); | |
| 1020 | + | |
| 1021 | + return 0; | |
| 1022 | +out: | |
| 1023 | + dsa_devlink_resources_unregister(ds); | |
| 1024 | + return err; | |
| 1025 | +} | |
| 1026 | +EXPORT_SYMBOL(b53_setup_devlink_resources); | |
| 1027 | + | |
| 979 | 1028 | static int b53_setup(struct dsa_switch *ds) |
| 980 | 1029 | { |
| 981 | 1030 | struct b53_device *dev = ds->priv; |
| @@ -991,8 +1040,10 @@ static int b53_setup(struct dsa_switch *ds) · 9 unmodified lines | ||
| 991 | 1040 | b53_reset_mib(dev); |
| 992 | 1041 | |
| 993 | 1042 | ret = b53_apply_config(dev); |
| 994 | − if (ret) | |
| 1043 | + if (ret) { | |
| 995 | 1044 | dev_err(ds->dev, "failed to apply configuration\n"); |
| 1045 | + return ret; | |
| 1046 | + } | |
| 996 | 1047 | |
| 997 | 1048 | /* Configure IMP/CPU port, disable all other ports. Enabled |
| 998 | 1049 | * ports will be configured with .port_enable |
| @@ -1011,7 +1062,12 @@ static int b53_setup(struct dsa_switch *ds) · 12 unmodified lines | ||
| 1011 | 1062 | */ |
| 1012 | 1063 | ds->vlan_filtering_is_global = true; |
| 1013 | 1064 | |
| 1014 | − return ret; | |
| 1065 | + return b53_setup_devlink_resources(ds); | |
| 1066 | +} | |
| 1067 | + | |
| 1068 | +static void b53_teardown(struct dsa_switch *ds) | |
| 1069 | +{ | |
| 1070 | + dsa_devlink_resources_unregister(ds); | |
| 1015 | 1071 | } |
| 1016 | 1072 | |
| 1017 | 1073 | static void b53_force_link(struct b53_device *dev, int port, int link) |
| @@ -1318,26 +1374,13 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port, · 300 unmodified lines | ||
| 1318 | 1374 | } |
| 1319 | 1375 | EXPORT_SYMBOL(b53_phylink_mac_link_up); |
| 1320 | 1376 | |
| 1321 | −int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) | |
| 1377 | +int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, | |
| 1378 | + struct switchdev_trans *trans) | |
| 1322 | 1379 | { |
| 1323 | 1380 | struct b53_device *dev = ds->priv; |
| 1324 | − u16 pvid, new_pvid; | |
| 1325 | 1381 | |
| 1326 | − b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid); | |
| 1327 | − if (!vlan_filtering) { | |
| 1328 | − /* Filtering is currently enabled, use the default PVID since | |
| 1329 | − * the bridge does not expect tagging anymore | |
| 1330 | − */ | |
| 1331 | − dev->ports[port].pvid = pvid; | |
| 1332 | − new_pvid = b53_default_pvid(dev); | |
| 1333 | − } else { | |
| 1334 | − /* Filtering is currently disabled, restore the previous PVID */ | |
| 1335 | − new_pvid = dev->ports[port].pvid; | |
| 1336 | − } | |
| 1337 | − | |
| 1338 | − if (pvid != new_pvid) | |
| 1339 | − b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), | |
| 1340 | − new_pvid); | |
| 1382 | + if (switchdev_trans_ph_prepare(trans)) | |
| 1383 | + return 0; | |
| 1341 | 1384 | |
| 1342 | 1385 | b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering); |
| 1343 | 1386 | |
| @@ -2140,6 +2183,7 @@ static int b53_get_max_mtu(struct dsa_switch *ds, int port) · 796 unmodified lines | ||
| 2140 | 2183 | static const struct dsa_switch_ops b53_switch_ops = { |
| 2141 | 2184 | .get_tag_protocol = b53_get_tag_protocol, |
| 2142 | 2185 | .setup = b53_setup, |
| 2186 | + .teardown = b53_teardown, | |
| 2143 | 2187 | .get_strings = b53_get_strings, |
| 2144 | 2188 | .get_ethtool_stats = b53_get_ethtool_stats, |
| 2145 | 2189 | .get_sset_count = b53_get_sset_count, |
| @@ -2562,6 +2606,9 @@ struct b53_device *b53_switch_alloc(struct device *base, · 416 unmodified lines | ||
| 2562 | 2606 | dev->priv = priv; |
| 2563 | 2607 | dev->ops = ops; |
| 2564 | 2608 | ds->ops = &b53_switch_ops; |
| 2609 | + ds->configure_vlan_while_not_filtering = true; | |
| 2610 | + ds->untag_bridge_pvid = true; | |
| 2611 | + dev->vlan_enabled = ds->configure_vlan_while_not_filtering; | |
| 2565 | 2612 | mutex_init(&dev->reg_mutex); |
| 2566 | 2613 | mutex_init(&dev->stats_mutex); |
| 2567 | 2614 | |
| @@ -2620,8 +2667,9 @@ int b53_switch_detect(struct b53_device *dev) · 52 unmodified lines | ||
| 2620 | 2667 | dev->chip_id = id32; |
| 2621 | 2668 | break; |
| 2622 | 2669 | default: |
| 2623 | − pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", | |
| 2624 | − id8, id32); | |
| 2670 | + dev_err(dev->dev, | |
| 2671 | + "unsupported switch detected (BCM53%02x/BCM%x)\n", | |
| 2672 | + id8, id32); | |
| 2625 | 2673 | return -ENODEV; |
| 2626 | 2674 | } |
| 2627 | 2675 | } |
| @@ -2651,7 +2699,8 @@ int b53_switch_register(struct b53_device *dev) · 23 unmodified lines | ||
| 2651 | 2699 | if (ret) |
| 2652 | 2700 | return ret; |
| 2653 | 2701 | |
| 2654 | − pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); | |
| 2702 | + dev_info(dev->dev, "found switch: %s, rev %i\n", | |
| 2703 | + dev->name, dev->core_rev); | |
| 2655 | 2704 | |
| 2656 | 2705 | return dsa_register_switch(dev->ds); |
| 2657 | 2706 | } |
| @@ -91,7 +91,6 @@ enum { · 90 unmodified lines | ||
| 91 | 91 | struct b53_port { |
| 92 | 92 | u16 vlan_ctl_mask; |
| 93 | 93 | struct ethtool_eee eee; |
| 94 | − u16 pvid; | |
| 95 | 94 | }; |
| 96 | 95 | |
| 97 | 96 | struct b53_vlan { |
| @@ -328,6 +327,7 @@ void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state); · 230 unmodified lines | ||
| 328 | 327 | void b53_br_fast_age(struct dsa_switch *ds, int port); |
| 329 | 328 | int b53_br_egress_floods(struct dsa_switch *ds, int port, |
| 330 | 329 | bool unicast, bool multicast); |
| 330 | +int b53_setup_devlink_resources(struct dsa_switch *ds); | |
| 331 | 331 | void b53_port_event(struct dsa_switch *ds, int port); |
| 332 | 332 | void b53_phylink_validate(struct dsa_switch *ds, int port, |
| 333 | 333 | unsigned long *supported, |
| @@ -347,7 +347,8 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port, · 13 unmodified lines | ||
| 347 | 347 | struct phy_device *phydev, |
| 348 | 348 | int speed, int duplex, |
| 349 | 349 | bool tx_pause, bool rx_pause); |
| 350 | −int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering); | |
| 350 | +int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, | |
| 351 | + struct switchdev_trans *trans); | |
| 351 | 352 | int b53_vlan_prepare(struct dsa_switch *ds, int port, |
| 352 | 353 | const struct switchdev_obj_port_vlan *vlan); |
| 353 | 354 | void b53_vlan_add(struct dsa_switch *ds, int port, |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/phy_fixed.h> |
| 15 | 15 | #include <linux/phylink.h> |
| 16 | 16 | #include <linux/mii.h> |
| 17 | +#include <linux/clk.h> | |
| 17 | 18 | #include <linux/of.h> |
| 18 | 19 | #include <linux/of_irq.h> |
| 19 | 20 | #include <linux/of_address.h> |
| @@ -31,6 +32,49 @@ · 11 unmodified lines | ||
| 31 | 32 | #include "b53/b53_priv.h" |
| 32 | 33 | #include "b53/b53_regs.h" |
| 33 | 34 | |
| 35 | +/* Return the number of active ports, not counting the IMP (CPU) port */ | |
| 36 | +static unsigned int bcm_sf2_num_active_ports(struct dsa_switch *ds) | |
| 37 | +{ | |
| 38 | + struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); | |
| 39 | + unsigned int port, count = 0; | |
| 40 | + | |
| 41 | + for (port = 0; port < ARRAY_SIZE(priv->port_sts); port++) { | |
| 42 | + if (dsa_is_cpu_port(ds, port)) | |
| 43 | + continue; | |
| 44 | + if (priv->port_sts[port].enabled) | |
| 45 | + count++; | |
| 46 | + } | |
| 47 | + | |
| 48 | + return count; | |
| 49 | +} | |
| 50 | + | |
| 51 | +static void bcm_sf2_recalc_clock(struct dsa_switch *ds) | |
| 52 | +{ | |
| 53 | + struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); | |
| 54 | + unsigned long new_rate; | |
| 55 | + unsigned int ports_active; | |
| 56 | + /* Frequenty in Mhz */ | |
| 57 | + const unsigned long rate_table[] = { | |
| 58 | + 59220000, | |
| 59 | + 60820000, | |
| 60 | + 62500000, | |
| 61 | + 62500000, | |
| 62 | + }; | |
| 63 | + | |
| 64 | + ports_active = bcm_sf2_num_active_ports(ds); | |
| 65 | + if (ports_active == 0 || !priv->clk_mdiv) | |
| 66 | + return; | |
| 67 | + | |
| 68 | + /* If we overflow our table, just use the recommended operational | |
| 69 | + * frequency | |
| 70 | + */ | |
| 71 | + if (ports_active > ARRAY_SIZE(rate_table)) | |
| 72 | + new_rate = 90000000; | |
| 73 | + else | |
| 74 | + new_rate = rate_table[ports_active - 1]; | |
| 75 | + clk_set_rate(priv->clk_mdiv, new_rate); | |
| 76 | +} | |
| 77 | + | |
| 34 | 78 | static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) |
| 35 | 79 | { |
| 36 | 80 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); |
| @@ -82,6 +126,8 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) · 45 unmodified lines | ||
| 82 | 126 | reg &= ~(RX_DIS | TX_DIS); |
| 83 | 127 | core_writel(priv, reg, CORE_G_PCTL_PORT(port)); |
| 84 | 128 | } |
| 129 | + | |
| 130 | + priv->port_sts[port].enabled = true; | |
| 85 | 131 | } |
| 86 | 132 | |
| 87 | 133 | static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable) |
| @@ -167,6 +213,10 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, · 79 unmodified lines | ||
| 167 | 213 | if (!dsa_is_user_port(ds, port)) |
| 168 | 214 | return 0; |
| 169 | 215 | |
| 216 | + priv->port_sts[port].enabled = true; | |
| 217 | + | |
| 218 | + bcm_sf2_recalc_clock(ds); | |
| 219 | + | |
| 170 | 220 | /* Clear the memory power down */ |
| 171 | 221 | reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); |
| 172 | 222 | reg &= ~P_TXQ_PSM_VDD(port); |
| @@ -260,6 +310,10 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) · 87 unmodified lines | ||
| 260 | 310 | reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); |
| 261 | 311 | reg |= P_TXQ_PSM_VDD(port); |
| 262 | 312 | core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); |
| 313 | + | |
| 314 | + priv->port_sts[port].enabled = false; | |
| 315 | + | |
| 316 | + bcm_sf2_recalc_clock(ds); | |
| 263 | 317 | } |
| 264 | 318 | |
| 265 | 319 | |
| @@ -403,6 +457,7 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, · 137 unmodified lines | ||
| 403 | 457 | { |
| 404 | 458 | struct device_node *port; |
| 405 | 459 | unsigned int port_num; |
| 460 | + struct property *prop; | |
| 406 | 461 | phy_interface_t mode; |
| 407 | 462 | int err; |
| 408 | 463 | |
| @@ -429,15 +484,27 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, · 20 unmodified lines | ||
| 429 | 484 | |
| 430 | 485 | if (of_property_read_bool(port, "brcm,use-bcm-hdr")) |
| 431 | 486 | priv->brcm_tag_mask |= 1 << port_num; |
| 487 | + | |
| 488 | + /* Ensure that port 5 is not picked up as a DSA CPU port | |
| 489 | + * flavour but a regular port instead. We should be using | |
| 490 | + * devlink to be able to set the port flavour. | |
| 491 | + */ | |
| 492 | + if (port_num == 5 && priv->type == BCM7278_DEVICE_ID) { | |
| 493 | + prop = of_find_property(port, "ethernet", NULL); | |
| 494 | + if (prop) | |
| 495 | + of_remove_property(port, prop); | |
| 496 | + } | |
| 432 | 497 | } |
| 433 | 498 | } |
| 434 | 499 | |
| 435 | 500 | static int bcm_sf2_mdio_register(struct dsa_switch *ds) |
| 436 | 501 | { |
| 437 | 502 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); |
| 438 | − struct device_node *dn; | |
| 503 | + struct device_node *dn, *child; | |
| 504 | + struct phy_device *phydev; | |
| 505 | + struct property *prop; | |
| 439 | 506 | static int index; |
| 440 | − int err; | |
| 507 | + int err, reg; | |
| 441 | 508 | |
| 442 | 509 | /* Find our integrated MDIO bus node */ |
| 443 | 510 | dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio"); |
| @@ -471,7 +538,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds) · 27 unmodified lines | ||
| 471 | 538 | * driver. |
| 472 | 539 | */ |
| 473 | 540 | if (of_machine_is_compatible("brcm,bcm7445d0")) |
| 474 | − priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR); | |
| 541 | + priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0); | |
| 475 | 542 | else |
| 476 | 543 | priv->indir_phy_mask = 0; |
| 477 | 544 | |
| @@ -480,6 +547,31 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds) · 2 unmodified lines | ||
| 480 | 547 | priv->slave_mii_bus->parent = ds->dev->parent; |
| 481 | 548 | priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask; |
| 482 | 549 | |
| 550 | + /* We need to make sure that of_phy_connect() will not work by | |
| 551 | + * removing the 'phandle' and 'linux,phandle' properties and | |
| 552 | + * unregister the existing PHY device that was already registered. | |
| 553 | + */ | |
| 554 | + for_each_available_child_of_node(dn, child) { | |
| 555 | + if (of_property_read_u32(child, "reg", ®) || | |
| 556 | + reg >= PHY_MAX_ADDR) | |
| 557 | + continue; | |
| 558 | + | |
| 559 | + if (!(priv->indir_phy_mask & BIT(reg))) | |
| 560 | + continue; | |
| 561 | + | |
| 562 | + prop = of_find_property(child, "phandle", NULL); | |
| 563 | + if (prop) | |
| 564 | + of_remove_property(child, prop); | |
| 565 | + | |
| 566 | + prop = of_find_property(child, "linux,phandle", NULL); | |
| 567 | + if (prop) | |
| 568 | + of_remove_property(child, prop); | |
| 569 | + | |
| 570 | + phydev = of_phy_find_device(child); | |
| 571 | + if (phydev) | |
| 572 | + phy_device_remove(phydev); | |
| 573 | + } | |
| 574 | + | |
| 483 | 575 | err = mdiobus_register(priv->slave_mii_bus); |
| 484 | 576 | if (err && dn) |
| 485 | 577 | of_node_put(dn); |
| @@ -750,6 +842,9 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) · 264 unmodified lines | ||
| 750 | 842 | bcm_sf2_port_disable(ds, port); |
| 751 | 843 | } |
| 752 | 844 | |
| 845 | + if (!priv->wol_ports_mask) | |
| 846 | + clk_disable_unprepare(priv->clk); | |
| 847 | + | |
| 753 | 848 | return 0; |
| 754 | 849 | } |
| 755 | 850 | |
| @@ -758,6 +853,9 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) · 2 unmodified lines | ||
| 758 | 853 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); |
| 759 | 854 | int ret; |
| 760 | 855 | |
| 856 | + if (!priv->wol_ports_mask) | |
| 857 | + clk_prepare_enable(priv->clk); | |
| 858 | + | |
| 761 | 859 | ret = bcm_sf2_sw_rst(priv); |
| 762 | 860 | if (ret) { |
| 763 | 861 | pr_err("%s: failed to software reset switch\n", __func__); |
| @@ -849,7 +947,12 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) · 85 unmodified lines | ||
| 849 | 947 | b53_configure_vlan(ds); |
| 850 | 948 | bcm_sf2_enable_acb(ds); |
| 851 | 949 | |
| 852 | − return 0; | |
| 950 | + return b53_setup_devlink_resources(ds); | |
| 951 | +} | |
| 952 | + | |
| 953 | +static void bcm_sf2_sw_teardown(struct dsa_switch *ds) | |
| 954 | +{ | |
| 955 | + dsa_devlink_resources_unregister(ds); | |
| 853 | 956 | } |
| 854 | 957 | |
| 855 | 958 | /* The SWITCH_CORE register space is managed by b53 but operates on a page + |
| @@ -986,6 +1089,7 @@ static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds, int port, · 130 unmodified lines | ||
| 986 | 1089 | static const struct dsa_switch_ops bcm_sf2_ops = { |
| 987 | 1090 | .get_tag_protocol = b53_get_tag_protocol, |
| 988 | 1091 | .setup = bcm_sf2_sw_setup, |
| 1092 | + .teardown = bcm_sf2_sw_teardown, | |
| 989 | 1093 | .get_strings = bcm_sf2_sw_get_strings, |
| 990 | 1094 | .get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats, |
| 991 | 1095 | .get_sset_count = bcm_sf2_sw_get_sset_count, |
| @@ -1189,10 +1293,24 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) · 197 unmodified lines | ||
| 1189 | 1293 | base++; |
| 1190 | 1294 | } |
| 1191 | 1295 | |
| 1296 | + priv->clk = devm_clk_get_optional(&pdev->dev, "sw_switch"); | |
| 1297 | + if (IS_ERR(priv->clk)) | |
| 1298 | + return PTR_ERR(priv->clk); | |
| 1299 | + | |
| 1300 | + clk_prepare_enable(priv->clk); | |
| 1301 | + | |
| 1302 | + priv->clk_mdiv = devm_clk_get_optional(&pdev->dev, "sw_switch_mdiv"); | |
| 1303 | + if (IS_ERR(priv->clk_mdiv)) { | |
| 1304 | + ret = PTR_ERR(priv->clk_mdiv); | |
| 1305 | + goto out_clk; | |
| 1306 | + } | |
| 1307 | + | |
| 1308 | + clk_prepare_enable(priv->clk_mdiv); | |
| 1309 | + | |
| 1192 | 1310 | ret = bcm_sf2_sw_rst(priv); |
| 1193 | 1311 | if (ret) { |
| 1194 | 1312 | pr_err("unable to software reset switch: %d\n", ret); |
| 1195 | − return ret; | |
| 1313 | + goto out_clk_mdiv; | |
| 1196 | 1314 | } |
| 1197 | 1315 | |
| 1198 | 1316 | bcm_sf2_gphy_enable_set(priv->dev->ds, true); |
| @@ -1200,7 +1318,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 1200 | 1318 | ret = bcm_sf2_mdio_register(ds); |
| 1201 | 1319 | if (ret) { |
| 1202 | 1320 | pr_err("failed to register MDIO bus\n"); |
| 1203 | − return ret; | |
| 1321 | + goto out_clk_mdiv; | |
| 1204 | 1322 | } |
| 1205 | 1323 | |
| 1206 | 1324 | bcm_sf2_gphy_enable_set(priv->dev->ds, false); |
| @@ -1267,6 +1385,10 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) · 60 unmodified lines | ||
| 1267 | 1385 | |
| 1268 | 1386 | out_mdio: |
| 1269 | 1387 | bcm_sf2_mdio_unregister(priv); |
| 1388 | +out_clk_mdiv: | |
| 1389 | + clk_disable_unprepare(priv->clk_mdiv); | |
| 1390 | +out_clk: | |
| 1391 | + clk_disable_unprepare(priv->clk); | |
| 1270 | 1392 | return ret; |
| 1271 | 1393 | } |
| 1272 | 1394 | |
| @@ -1280,6 +1402,8 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 1280 | 1402 | dsa_unregister_switch(priv->dev->ds); |
| 1281 | 1403 | bcm_sf2_cfp_exit(priv->dev->ds); |
| 1282 | 1404 | bcm_sf2_mdio_unregister(priv); |
| 1405 | + clk_disable_unprepare(priv->clk_mdiv); | |
| 1406 | + clk_disable_unprepare(priv->clk); | |
| 1283 | 1407 | if (priv->type == BCM7278_DEVICE_ID && !IS_ERR(priv->rcdev)) |
| 1284 | 1408 | reset_control_assert(priv->rcdev); |
| 1285 | 1409 | |
| @@ -45,6 +45,7 @@ struct bcm_sf2_hw_params { · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | struct bcm_sf2_port_status { |
| 47 | 47 | unsigned int link; |
| 48 | + bool enabled; | |
| 48 | 49 | }; |
| 49 | 50 | |
| 50 | 51 | struct bcm_sf2_cfp_priv { |
| @@ -93,6 +94,9 @@ struct bcm_sf2_priv { · 42 unmodified lines | ||
| 93 | 94 | /* Mask of ports enabled for Wake-on-LAN */ |
| 94 | 95 | u32 wol_ports_mask; |
| 95 | 96 | |
| 97 | + struct clk *clk; | |
| 98 | + struct clk *clk_mdiv; | |
| 99 | + | |
| 96 | 100 | /* MoCA port location */ |
| 97 | 101 | int moca_port; |
| 98 | 102 | |
| @@ -28,6 +28,53 @@ static struct dsa_loop_mib_entry dsa_loop_mibs[] = { · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | static struct phy_device *phydevs[PHY_MAX_ADDR]; |
| 30 | 30 | |
| 31 | +enum dsa_loop_devlink_resource_id { | |
| 32 | + DSA_LOOP_DEVLINK_PARAM_ID_VTU, | |
| 33 | +}; | |
| 34 | + | |
| 35 | +static u64 dsa_loop_devlink_vtu_get(void *priv) | |
| 36 | +{ | |
| 37 | + struct dsa_loop_priv *ps = priv; | |
| 38 | + unsigned int i, count = 0; | |
| 39 | + struct dsa_loop_vlan *vl; | |
| 40 | + | |
| 41 | + for (i = 0; i < ARRAY_SIZE(ps->vlans); i++) { | |
| 42 | + vl = &ps->vlans[i]; | |
| 43 | + if (vl->members) | |
| 44 | + count++; | |
| 45 | + } | |
| 46 | + | |
| 47 | + return count; | |
| 48 | +} | |
| 49 | + | |
| 50 | +static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds) | |
| 51 | +{ | |
| 52 | + struct devlink_resource_size_params size_params; | |
| 53 | + struct dsa_loop_priv *ps = ds->priv; | |
| 54 | + int err; | |
| 55 | + | |
| 56 | + devlink_resource_size_params_init(&size_params, ARRAY_SIZE(ps->vlans), | |
| 57 | + ARRAY_SIZE(ps->vlans), | |
| 58 | + 1, DEVLINK_RESOURCE_UNIT_ENTRY); | |
| 59 | + | |
| 60 | + err = dsa_devlink_resource_register(ds, "VTU", ARRAY_SIZE(ps->vlans), | |
| 61 | + DSA_LOOP_DEVLINK_PARAM_ID_VTU, | |
| 62 | + DEVLINK_RESOURCE_ID_PARENT_TOP, | |
| 63 | + &size_params); | |
| 64 | + if (err) | |
| 65 | + goto out; | |
| 66 | + | |
| 67 | + dsa_devlink_resource_occ_get_register(ds, | |
| 68 | + DSA_LOOP_DEVLINK_PARAM_ID_VTU, | |
| 69 | + dsa_loop_devlink_vtu_get, ps); | |
| 70 | + | |
| 71 | + return 0; | |
| 72 | + | |
| 73 | +out: | |
| 74 | + dsa_devlink_resources_unregister(ds); | |
| 75 | + return err; | |
| 76 | +} | |
| 77 | + | |
| 31 | 78 | static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds, |
| 32 | 79 | int port, |
| 33 | 80 | enum dsa_tag_protocol mp) |
| @@ -48,7 +95,12 @@ static int dsa_loop_setup(struct dsa_switch *ds) · 14 unmodified lines | ||
| 48 | 95 | |
| 49 | 96 | dev_dbg(ds->dev, "%s\n", __func__); |
| 50 | 97 | |
| 51 | − return 0; | |
| 98 | + return dsa_loop_setup_devlink_resources(ds); | |
| 99 | +} | |
| 100 | + | |
| 101 | +static void dsa_loop_teardown(struct dsa_switch *ds) | |
| 102 | +{ | |
| 103 | + dsa_devlink_resources_unregister(ds); | |
| 52 | 104 | } |
| 53 | 105 | |
| 54 | 106 | static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset) |
| @@ -138,7 +190,8 @@ static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port, · 83 unmodified lines | ||
| 138 | 190 | } |
| 139 | 191 | |
| 140 | 192 | static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port, |
| 141 | − bool vlan_filtering) | |
| 193 | + bool vlan_filtering, | |
| 194 | + struct switchdev_trans *trans) | |
| 142 | 195 | { |
| 143 | 196 | dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n", |
| 144 | 197 | __func__, port, vlan_filtering); |
| @@ -243,6 +296,7 @@ static int dsa_loop_port_max_mtu(struct dsa_switch *ds, int port) · 98 unmodified lines | ||
| 243 | 296 | static const struct dsa_switch_ops dsa_loop_driver = { |
| 244 | 297 | .get_tag_protocol = dsa_loop_get_protocol, |
| 245 | 298 | .setup = dsa_loop_setup, |
| 299 | + .teardown = dsa_loop_teardown, | |
| 246 | 300 | .get_strings = dsa_loop_get_strings, |
| 247 | 301 | .get_ethtool_stats = dsa_loop_get_ethtool_stats, |
| 248 | 302 | .get_sset_count = dsa_loop_get_sset_count, |
| @@ -290,6 +344,7 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) · 41 unmodified lines | ||
| 290 | 344 | ds->dev = &mdiodev->dev; |
| 291 | 345 | ds->ops = &dsa_loop_driver; |
| 292 | 346 | ds->priv = ps; |
| 347 | + ds->configure_vlan_while_not_filtering = true; | |
| 293 | 348 | ps->bus = mdiodev->bus; |
| 294 | 349 | |
| 295 | 350 | dev_set_drvdata(&mdiodev->dev, ds); |
| @@ -736,14 +736,23 @@ static int gswip_pce_load_microcode(struct gswip_priv *priv) · 735 unmodified lines | ||
| 736 | 736 | } |
| 737 | 737 | |
| 738 | 738 | static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port, |
| 739 | − bool vlan_filtering) | |
| 739 | + bool vlan_filtering, | |
| 740 | + struct switchdev_trans *trans) | |
| 740 | 741 | { |
| 741 | 742 | struct gswip_priv *priv = ds->priv; |
| 742 | − struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev; | |
| 743 | 743 | |
| 744 | 744 | /* Do not allow changing the VLAN filtering options while in bridge */ |
| 745 | − if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering && bridge) | |
| 746 | − return -EIO; | |
| 745 | + if (switchdev_trans_ph_prepare(trans)) { | |
| 746 | + struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev; | |
| 747 | + | |
| 748 | + if (!bridge) | |
| 749 | + return 0; | |
| 750 | + | |
| 751 | + if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering) | |
| 752 | + return -EIO; | |
| 753 | + | |
| 754 | + return 0; | |
| 755 | + } | |
| 747 | 756 | |
| 748 | 757 | if (vlan_filtering) { |
| 749 | 758 | /* Use port based VLAN tag */ |
| @@ -781,8 +790,15 @@ static int gswip_setup(struct dsa_switch *ds) · 31 unmodified lines | ||
| 781 | 790 | |
| 782 | 791 | /* disable port fetch/store dma on all ports */ |
| 783 | 792 | for (i = 0; i < priv->hw_info->max_ports; i++) { |
| 793 | + struct switchdev_trans trans; | |
| 794 | + | |
| 795 | + /* Skip the prepare phase, this shouldn't return an error | |
| 796 | + * during setup. | |
| 797 | + */ | |
| 798 | + trans.ph_prepare = false; | |
| 799 | + | |
| 784 | 800 | gswip_port_disable(ds, i); |
| 785 | − gswip_port_vlan_filtering(ds, i, false); | |
| 801 | + gswip_port_vlan_filtering(ds, i, false, &trans); | |
| 786 | 802 | } |
| 787 | 803 | |
| 788 | 804 | /* enable Switch */ |
| @@ -782,10 +782,14 @@ static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port) · 781 unmodified lines | ||
| 782 | 782 | } |
| 783 | 783 | |
| 784 | 784 | static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port, |
| 785 | − bool flag) | |
| 785 | + bool flag, | |
| 786 | + struct switchdev_trans *trans) | |
| 786 | 787 | { |
| 787 | 788 | struct ksz_device *dev = ds->priv; |
| 788 | 789 | |
| 790 | + if (switchdev_trans_ph_prepare(trans)) | |
| 791 | + return 0; | |
| 792 | + | |
| 789 | 793 | ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag); |
| 790 | 794 | |
| 791 | 795 | return 0; |
| @@ -493,10 +493,14 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) · 492 unmodified lines | ||
| 493 | 493 | } |
| 494 | 494 | |
| 495 | 495 | static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, |
| 496 | − bool flag) | |
| 496 | + bool flag, | |
| 497 | + struct switchdev_trans *trans) | |
| 497 | 498 | { |
| 498 | 499 | struct ksz_device *dev = ds->priv; |
| 499 | 500 | |
| 501 | + if (switchdev_trans_ph_prepare(trans)) | |
| 502 | + return 0; | |
| 503 | + | |
| 500 | 504 | if (flag) { |
| 501 | 505 | ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, |
| 502 | 506 | PORT_VLAN_LOOKUP_VID_0, true); |
| @@ -1235,6 +1239,9 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) · 732 unmodified lines | ||
| 1235 | 1239 | if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || |
| 1236 | 1240 | p->interface == PHY_INTERFACE_MODE_RGMII_TXID) |
| 1237 | 1241 | data8 |= PORT_RGMII_ID_EG_ENABLE; |
| 1242 | + /* On KSZ9893, disable RGMII in-band status support */ | |
| 1243 | + if (dev->features & IS_9893) | |
| 1244 | + data8 &= ~PORT_MII_MAC_MODE; | |
| 1238 | 1245 | p->phydev.speed = SPEED_1000; |
| 1239 | 1246 | break; |
| 1240 | 1247 | } |
| @@ -1265,6 +1272,8 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds) · 24 unmodified lines | ||
| 1265 | 1272 | for (i = 0; i < dev->port_cnt; i++) { |
| 1266 | 1273 | if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) { |
| 1267 | 1274 | phy_interface_t interface; |
| 1275 | + const char *prev_msg; | |
| 1276 | + const char *prev_mode; | |
| 1268 | 1277 | |
| 1269 | 1278 | dev->cpu_port = i; |
| 1270 | 1279 | dev->host_mask = (1 << dev->cpu_port); |
| @@ -1287,11 +1296,19 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds) · 16 unmodified lines | ||
| 1287 | 1296 | p->interface = interface; |
| 1288 | 1297 | } |
| 1289 | 1298 | } |
| 1290 | − if (interface && interface != p->interface) | |
| 1291 | − dev_info(dev->dev, | |
| 1292 | − "use %s instead of %s\n", | |
| 1293 | − phy_modes(p->interface), | |
| 1294 | − phy_modes(interface)); | |
| 1299 | + if (interface && interface != p->interface) { | |
| 1300 | + prev_msg = " instead of "; | |
| 1301 | + prev_mode = phy_modes(interface); | |
| 1302 | + } else { | |
| 1303 | + prev_msg = ""; | |
| 1304 | + prev_mode = ""; | |
| 1305 | + } | |
| 1306 | + dev_info(dev->dev, | |
| 1307 | + "Port%d: using phy mode %s%s%s\n", | |
| 1308 | + i, | |
| 1309 | + phy_modes(p->interface), | |
| 1310 | + prev_msg, | |
| 1311 | + prev_mode); | |
| 1295 | 1312 | |
| 1296 | 1313 | /* enable cpu port */ |
| 1297 | 1314 | ksz9477_port_setup(dev, i, true); |
| @@ -1435,10 +1452,12 @@ static int ksz9477_switch_detect(struct ksz_device *dev) · 137 unmodified lines | ||
| 1435 | 1452 | /* Default capability is gigabit capable. */ |
| 1436 | 1453 | dev->features = GBIT_SUPPORT; |
| 1437 | 1454 | |
| 1455 | + dev_dbg(dev->dev, "Switch detect: ID=%08x%02x\n", id32, data8); | |
| 1438 | 1456 | id_hi = (u8)(id32 >> 16); |
| 1439 | 1457 | id_lo = (u8)(id32 >> 8); |
| 1440 | 1458 | if ((id_lo & 0xf) == 3) { |
| 1441 | 1459 | /* Chip is from KSZ9893 design. */ |
| 1460 | + dev_info(dev->dev, "Found KSZ9893\n"); | |
| 1442 | 1461 | dev->features |= IS_9893; |
| 1443 | 1462 | |
| 1444 | 1463 | /* Chip does not support gigabit. */ |
| @@ -1447,6 +1466,7 @@ static int ksz9477_switch_detect(struct ksz_device *dev) · 2 unmodified lines | ||
| 1447 | 1466 | dev->mib_port_cnt = 3; |
| 1448 | 1467 | dev->phy_port_cnt = 2; |
| 1449 | 1468 | } else { |
| 1469 | + dev_info(dev->dev, "Found KSZ9477 or compatible\n"); | |
| 1450 | 1470 | /* Chip uses new XMII register definitions. */ |
| 1451 | 1471 | dev->features |= NEW_XMII; |
| 1452 | 1472 | |
| @@ -80,6 +80,7 @@ static const struct of_device_id ksz9477_dt_ids[] = { · 79 unmodified lines | ||
| 80 | 80 | { .compatible = "microchip,ksz9477" }, |
| 81 | 81 | { .compatible = "microchip,ksz9897" }, |
| 82 | 82 | { .compatible = "microchip,ksz9893" }, |
| 83 | + { .compatible = "microchip,ksz9563" }, | |
| 83 | 84 | { .compatible = "microchip,ksz9567" }, |
| 84 | 85 | {}, |
| 85 | 86 | }; |
| @@ -103,14 +103,8 @@ void ksz_init_mib_timer(struct ksz_device *dev) · 102 unmodified lines | ||
| 103 | 103 | |
| 104 | 104 | INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work); |
| 105 | 105 | |
| 106 | − /* Read MIB counters every 30 seconds to avoid overflow. */ | |
| 107 | − dev->mib_read_interval = msecs_to_jiffies(30000); | |
| 108 | − | |
| 109 | 106 | for (i = 0; i < dev->mib_port_cnt; i++) |
| 110 | 107 | dev->dev_ops->port_init_cnt(dev, i); |
| 111 | − | |
| 112 | − /* Start the timer 2 seconds later. */ | |
| 113 | − schedule_delayed_work(&dev->mib_read, msecs_to_jiffies(2000)); | |
| 114 | 108 | } |
| 115 | 109 | EXPORT_SYMBOL_GPL(ksz_init_mib_timer); |
| 116 | 110 | |
| @@ -143,7 +137,9 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, · 26 unmodified lines | ||
| 143 | 137 | |
| 144 | 138 | /* Read all MIB counters when the link is going down. */ |
| 145 | 139 | p->read = true; |
| 146 | − schedule_delayed_work(&dev->mib_read, 0); | |
| 140 | + /* timer started */ | |
| 141 | + if (dev->mib_read_interval) | |
| 142 | + schedule_delayed_work(&dev->mib_read, 0); | |
| 147 | 143 | } |
| 148 | 144 | EXPORT_SYMBOL_GPL(ksz_mac_link_down); |
| 149 | 145 | |
| @@ -402,8 +398,9 @@ int ksz_switch_register(struct ksz_device *dev, · 252 unmodified lines | ||
| 402 | 398 | |
| 403 | 399 | if (dev->reset_gpio) { |
| 404 | 400 | gpiod_set_value_cansleep(dev->reset_gpio, 1); |
| 405 | − mdelay(10); | |
| 401 | + usleep_range(10000, 12000); | |
| 406 | 402 | gpiod_set_value_cansleep(dev->reset_gpio, 0); |
| 403 | + usleep_range(100, 1000); | |
| 407 | 404 | } |
| 408 | 405 | |
| 409 | 406 | mutex_init(&dev->dev_mutex); |
| @@ -450,6 +447,12 @@ int ksz_switch_register(struct ksz_device *dev, · 40 unmodified lines | ||
| 450 | 447 | return ret; |
| 451 | 448 | } |
| 452 | 449 | |
| 450 | + /* Read MIB counters every 30 seconds to avoid overflow. */ | |
| 451 | + dev->mib_read_interval = msecs_to_jiffies(30000); | |
| 452 | + | |
| 453 | + /* Start the MIB timer. */ | |
| 454 | + schedule_delayed_work(&dev->mib_read, 0); | |
| 455 | + | |
| 453 | 456 | return 0; |
| 454 | 457 | } |
| 455 | 458 | EXPORT_SYMBOL(ksz_switch_register); |
| @@ -233,6 +233,12 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val) · 232 unmodified lines | ||
| 233 | 233 | mutex_unlock(&bus->mdio_lock); |
| 234 | 234 | } |
| 235 | 235 | |
| 236 | +static u32 | |
| 237 | +_mt7530_unlocked_read(struct mt7530_dummy_poll *p) | |
| 238 | +{ | |
| 239 | + return mt7530_mii_read(p->priv, p->reg); | |
| 240 | +} | |
| 241 | + | |
| 236 | 242 | static u32 |
| 237 | 243 | _mt7530_read(struct mt7530_dummy_poll *p) |
| 238 | 244 | { |
| @@ -372,8 +378,9 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid, · 133 unmodified lines | ||
| 372 | 378 | mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]); |
| 373 | 379 | } |
| 374 | 380 | |
| 381 | +/* Setup TX circuit including relevant PAD and driving */ | |
| 375 | 382 | static int |
| 376 | −mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) | |
| 383 | +mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) | |
| 377 | 384 | { |
| 378 | 385 | struct mt7530_priv *priv = ds->priv; |
| 379 | 386 | u32 ncpo1, ssc_delta, trgint, i, xtal; |
| @@ -387,7 +394,7 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) · 7 unmodified lines | ||
| 387 | 394 | return -EINVAL; |
| 388 | 395 | } |
| 389 | 396 | |
| 390 | − switch (mode) { | |
| 397 | + switch (interface) { | |
| 391 | 398 | case PHY_INTERFACE_MODE_RGMII: |
| 392 | 399 | trgint = 0; |
| 393 | 400 | /* PLL frequency: 125MHz */ |
| @@ -409,7 +416,8 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) · 15 unmodified lines | ||
| 409 | 416 | } |
| 410 | 417 | break; |
| 411 | 418 | default: |
| 412 | − dev_err(priv->dev, "xMII mode %d not supported\n", mode); | |
| 419 | + dev_err(priv->dev, "xMII interface %d not supported\n", | |
| 420 | + interface); | |
| 413 | 421 | return -EINVAL; |
| 414 | 422 | } |
| 415 | 423 | |
| @@ -481,6 +489,108 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) · 65 unmodified lines | ||
| 481 | 489 | return 0; |
| 482 | 490 | } |
| 483 | 491 | |
| 492 | +static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv) | |
| 493 | +{ | |
| 494 | + u32 val; | |
| 495 | + | |
| 496 | + val = mt7530_read(priv, MT7531_TOP_SIG_SR); | |
| 497 | + | |
| 498 | + return (val & PAD_DUAL_SGMII_EN) != 0; | |
| 499 | +} | |
| 500 | + | |
| 501 | +static int | |
| 502 | +mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface) | |
| 503 | +{ | |
| 504 | + struct mt7530_priv *priv = ds->priv; | |
| 505 | + u32 top_sig; | |
| 506 | + u32 hwstrap; | |
| 507 | + u32 xtal; | |
| 508 | + u32 val; | |
| 509 | + | |
| 510 | + if (mt7531_dual_sgmii_supported(priv)) | |
| 511 | + return 0; | |
| 512 | + | |
| 513 | + val = mt7530_read(priv, MT7531_CREV); | |
| 514 | + top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR); | |
| 515 | + hwstrap = mt7530_read(priv, MT7531_HWTRAP); | |
| 516 | + if ((val & CHIP_REV_M) > 0) | |
| 517 | + xtal = (top_sig & PAD_MCM_SMI_EN) ? HWTRAP_XTAL_FSEL_40MHZ : | |
| 518 | + HWTRAP_XTAL_FSEL_25MHZ; | |
| 519 | + else | |
| 520 | + xtal = hwstrap & HWTRAP_XTAL_FSEL_MASK; | |
| 521 | + | |
| 522 | + /* Step 1 : Disable MT7531 COREPLL */ | |
| 523 | + val = mt7530_read(priv, MT7531_PLLGP_EN); | |
| 524 | + val &= ~EN_COREPLL; | |
| 525 | + mt7530_write(priv, MT7531_PLLGP_EN, val); | |
| 526 | + | |
| 527 | + /* Step 2: switch to XTAL output */ | |
| 528 | + val = mt7530_read(priv, MT7531_PLLGP_EN); | |
| 529 | + val |= SW_CLKSW; | |
| 530 | + mt7530_write(priv, MT7531_PLLGP_EN, val); | |
| 531 | + | |
| 532 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 533 | + val &= ~RG_COREPLL_EN; | |
| 534 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 535 | + | |
| 536 | + /* Step 3: disable PLLGP and enable program PLLGP */ | |
| 537 | + val = mt7530_read(priv, MT7531_PLLGP_EN); | |
| 538 | + val |= SW_PLLGP; | |
| 539 | + mt7530_write(priv, MT7531_PLLGP_EN, val); | |
| 540 | + | |
| 541 | + /* Step 4: program COREPLL output frequency to 500MHz */ | |
| 542 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 543 | + val &= ~RG_COREPLL_POSDIV_M; | |
| 544 | + val |= 2 << RG_COREPLL_POSDIV_S; | |
| 545 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 546 | + usleep_range(25, 35); | |
| 547 | + | |
| 548 | + switch (xtal) { | |
| 549 | + case HWTRAP_XTAL_FSEL_25MHZ: | |
| 550 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 551 | + val &= ~RG_COREPLL_SDM_PCW_M; | |
| 552 | + val |= 0x140000 << RG_COREPLL_SDM_PCW_S; | |
| 553 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 554 | + break; | |
| 555 | + case HWTRAP_XTAL_FSEL_40MHZ: | |
| 556 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 557 | + val &= ~RG_COREPLL_SDM_PCW_M; | |
| 558 | + val |= 0x190000 << RG_COREPLL_SDM_PCW_S; | |
| 559 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 560 | + break; | |
| 561 | + }; | |
| 562 | + | |
| 563 | + /* Set feedback divide ratio update signal to high */ | |
| 564 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 565 | + val |= RG_COREPLL_SDM_PCW_CHG; | |
| 566 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 567 | + /* Wait for at least 16 XTAL clocks */ | |
| 568 | + usleep_range(10, 20); | |
| 569 | + | |
| 570 | + /* Step 5: set feedback divide ratio update signal to low */ | |
| 571 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 572 | + val &= ~RG_COREPLL_SDM_PCW_CHG; | |
| 573 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 574 | + | |
| 575 | + /* Enable 325M clock for SGMII */ | |
| 576 | + mt7530_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000); | |
| 577 | + | |
| 578 | + /* Enable 250SSC clock for RGMII */ | |
| 579 | + mt7530_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000); | |
| 580 | + | |
| 581 | + /* Step 6: Enable MT7531 PLL */ | |
| 582 | + val = mt7530_read(priv, MT7531_PLLGP_CR0); | |
| 583 | + val |= RG_COREPLL_EN; | |
| 584 | + mt7530_write(priv, MT7531_PLLGP_CR0, val); | |
| 585 | + | |
| 586 | + val = mt7530_read(priv, MT7531_PLLGP_EN); | |
| 587 | + val |= EN_COREPLL; | |
| 588 | + mt7530_write(priv, MT7531_PLLGP_EN, val); | |
| 589 | + usleep_range(25, 35); | |
| 590 | + | |
| 591 | + return 0; | |
| 592 | +} | |
| 593 | + | |
| 484 | 594 | static void |
| 485 | 595 | mt7530_mib_reset(struct dsa_switch *ds) |
| 486 | 596 | { |
| @@ -505,6 +615,217 @@ static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, · 18 unmodified lines | ||
| 505 | 615 | return mdiobus_write_nested(priv->bus, port, regnum, val); |
| 506 | 616 | } |
| 507 | 617 | |
| 618 | +static int | |
| 619 | +mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad, | |
| 620 | + int regnum) | |
| 621 | +{ | |
| 622 | + struct mii_bus *bus = priv->bus; | |
| 623 | + struct mt7530_dummy_poll p; | |
| 624 | + u32 reg, val; | |
| 625 | + int ret; | |
| 626 | + | |
| 627 | + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); | |
| 628 | + | |
| 629 | + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); | |
| 630 | + | |
| 631 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 632 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 633 | + if (ret < 0) { | |
| 634 | + dev_err(priv->dev, "poll timeout\n"); | |
| 635 | + goto out; | |
| 636 | + } | |
| 637 | + | |
| 638 | + reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) | | |
| 639 | + MT7531_MDIO_DEV_ADDR(devad) | regnum; | |
| 640 | + mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST); | |
| 641 | + | |
| 642 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 643 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 644 | + if (ret < 0) { | |
| 645 | + dev_err(priv->dev, "poll timeout\n"); | |
| 646 | + goto out; | |
| 647 | + } | |
| 648 | + | |
| 649 | + reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) | | |
| 650 | + MT7531_MDIO_DEV_ADDR(devad); | |
| 651 | + mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST); | |
| 652 | + | |
| 653 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 654 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 655 | + if (ret < 0) { | |
| 656 | + dev_err(priv->dev, "poll timeout\n"); | |
| 657 | + goto out; | |
| 658 | + } | |
| 659 | + | |
| 660 | + ret = val & MT7531_MDIO_RW_DATA_MASK; | |
| 661 | +out: | |
| 662 | + mutex_unlock(&bus->mdio_lock); | |
| 663 | + | |
| 664 | + return ret; | |
| 665 | +} | |
| 666 | + | |
| 667 | +static int | |
| 668 | +mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad, | |
| 669 | + int regnum, u32 data) | |
| 670 | +{ | |
| 671 | + struct mii_bus *bus = priv->bus; | |
| 672 | + struct mt7530_dummy_poll p; | |
| 673 | + u32 val, reg; | |
| 674 | + int ret; | |
| 675 | + | |
| 676 | + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); | |
| 677 | + | |
| 678 | + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); | |
| 679 | + | |
| 680 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 681 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 682 | + if (ret < 0) { | |
| 683 | + dev_err(priv->dev, "poll timeout\n"); | |
| 684 | + goto out; | |
| 685 | + } | |
| 686 | + | |
| 687 | + reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) | | |
| 688 | + MT7531_MDIO_DEV_ADDR(devad) | regnum; | |
| 689 | + mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST); | |
| 690 | + | |
| 691 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 692 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 693 | + if (ret < 0) { | |
| 694 | + dev_err(priv->dev, "poll timeout\n"); | |
| 695 | + goto out; | |
| 696 | + } | |
| 697 | + | |
| 698 | + reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) | | |
| 699 | + MT7531_MDIO_DEV_ADDR(devad) | data; | |
| 700 | + mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST); | |
| 701 | + | |
| 702 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 703 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 704 | + if (ret < 0) { | |
| 705 | + dev_err(priv->dev, "poll timeout\n"); | |
| 706 | + goto out; | |
| 707 | + } | |
| 708 | + | |
| 709 | +out: | |
| 710 | + mutex_unlock(&bus->mdio_lock); | |
| 711 | + | |
| 712 | + return ret; | |
| 713 | +} | |
| 714 | + | |
| 715 | +static int | |
| 716 | +mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum) | |
| 717 | +{ | |
| 718 | + struct mii_bus *bus = priv->bus; | |
| 719 | + struct mt7530_dummy_poll p; | |
| 720 | + int ret; | |
| 721 | + u32 val; | |
| 722 | + | |
| 723 | + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); | |
| 724 | + | |
| 725 | + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); | |
| 726 | + | |
| 727 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 728 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 729 | + if (ret < 0) { | |
| 730 | + dev_err(priv->dev, "poll timeout\n"); | |
| 731 | + goto out; | |
| 732 | + } | |
| 733 | + | |
| 734 | + val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) | | |
| 735 | + MT7531_MDIO_REG_ADDR(regnum); | |
| 736 | + | |
| 737 | + mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST); | |
| 738 | + | |
| 739 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, | |
| 740 | + !(val & MT7531_PHY_ACS_ST), 20, 100000); | |
| 741 | + if (ret < 0) { | |
| 742 | + dev_err(priv->dev, "poll timeout\n"); | |
| 743 | + goto out; | |
| 744 | + } | |
| 745 | + | |
| 746 | + ret = val & MT7531_MDIO_RW_DATA_MASK; | |
| 747 | +out: | |
| 748 | + mutex_unlock(&bus->mdio_lock); | |
| 749 | + | |
| 750 | + return ret; | |
| 751 | +} | |
| 752 | + | |
| 753 | +static int | |
| 754 | +mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum, | |
| 755 | + u16 data) | |
| 756 | +{ | |
| 757 | + struct mii_bus *bus = priv->bus; | |
| 758 | + struct mt7530_dummy_poll p; | |
| 759 | + int ret; | |
| 760 | + u32 reg; | |
| 761 | + | |
| 762 | + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); | |
| 763 | + | |
| 764 | + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); | |
| 765 | + | |
| 766 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg, | |
| 767 | + !(reg & MT7531_PHY_ACS_ST), 20, 100000); | |
| 768 | + if (ret < 0) { | |
| 769 | + dev_err(priv->dev, "poll timeout\n"); | |
| 770 | + goto out; | |
| 771 | + } | |
| 772 | + | |
| 773 | + reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) | | |
| 774 | + MT7531_MDIO_REG_ADDR(regnum) | data; | |
| 775 | + | |
| 776 | + mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST); | |
| 777 | + | |
| 778 | + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg, | |
| 779 | + !(reg & MT7531_PHY_ACS_ST), 20, 100000); | |
| 780 | + if (ret < 0) { | |
| 781 | + dev_err(priv->dev, "poll timeout\n"); | |
| 782 | + goto out; | |
| 783 | + } | |
| 784 | + | |
| 785 | +out: | |
| 786 | + mutex_unlock(&bus->mdio_lock); | |
| 787 | + | |
| 788 | + return ret; | |
| 789 | +} | |
| 790 | + | |
| 791 | +static int | |
| 792 | +mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum) | |
| 793 | +{ | |
| 794 | + struct mt7530_priv *priv = ds->priv; | |
| 795 | + int devad; | |
| 796 | + int ret; | |
| 797 | + | |
| 798 | + if (regnum & MII_ADDR_C45) { | |
| 799 | + devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f; | |
| 800 | + ret = mt7531_ind_c45_phy_read(priv, port, devad, | |
| 801 | + regnum & MII_REGADDR_C45_MASK); | |
| 802 | + } else { | |
| 803 | + ret = mt7531_ind_c22_phy_read(priv, port, regnum); | |
| 804 | + } | |
| 805 | + | |
| 806 | + return ret; | |
| 807 | +} | |
| 808 | + | |
| 809 | +static int | |
| 810 | +mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum, | |
| 811 | + u16 data) | |
| 812 | +{ | |
| 813 | + struct mt7530_priv *priv = ds->priv; | |
| 814 | + int devad; | |
| 815 | + int ret; | |
| 816 | + | |
| 817 | + if (regnum & MII_ADDR_C45) { | |
| 818 | + devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f; | |
| 819 | + ret = mt7531_ind_c45_phy_write(priv, port, devad, | |
| 820 | + regnum & MII_REGADDR_C45_MASK, | |
| 821 | + data); | |
| 822 | + } else { | |
| 823 | + ret = mt7531_ind_c22_phy_write(priv, port, regnum, data); | |
| 824 | + } | |
| 825 | + | |
| 826 | + return ret; | |
| 827 | +} | |
| 828 | + | |
| 508 | 829 | static void |
| 509 | 830 | mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset, |
| 510 | 831 | uint8_t *data) |
| @@ -621,9 +942,18 @@ unlock_exit: · 110 unmodified lines | ||
| 621 | 942 | } |
| 622 | 943 | |
| 623 | 944 | static int |
| 624 | −mt7530_cpu_port_enable(struct mt7530_priv *priv, | |
| 625 | − int port) | |
| 945 | +mt753x_cpu_port_enable(struct dsa_switch *ds, int port) | |
| 626 | 946 | { |
| 947 | + struct mt7530_priv *priv = ds->priv; | |
| 948 | + int ret; | |
| 949 | + | |
| 950 | + /* Setup max capability of CPU port at first */ | |
| 951 | + if (priv->info->cpu_port_config) { | |
| 952 | + ret = priv->info->cpu_port_config(ds, port); | |
| 953 | + if (ret) | |
| 954 | + return ret; | |
| 955 | + } | |
| 956 | + | |
| 627 | 957 | /* Enable Mediatek header mode on the cpu port */ |
| 628 | 958 | mt7530_write(priv, MT7530_PVC_P(port), |
| 629 | 959 | PORT_SPEC_TAG); |
| @@ -636,7 +966,7 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv, · 6 unmodified lines | ||
| 636 | 966 | mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port)); |
| 637 | 967 | |
| 638 | 968 | /* CPU port gets connected to all user ports of |
| 639 | − * the switch | |
| 969 | + * the switch. | |
| 640 | 970 | */ |
| 641 | 971 | mt7530_write(priv, MT7530_PCR_P(port), |
| 642 | 972 | PCR_MATRIX(dsa_user_ports(priv->ds))); |
| @@ -959,8 +1289,12 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid) · 316 unmodified lines | ||
| 959 | 1289 | |
| 960 | 1290 | static int |
| 961 | 1291 | mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, |
| 962 | − bool vlan_filtering) | |
| 1292 | + bool vlan_filtering, | |
| 1293 | + struct switchdev_trans *trans) | |
| 963 | 1294 | { |
| 1295 | + if (switchdev_trans_ph_prepare(trans)) | |
| 1296 | + return 0; | |
| 1297 | + | |
| 964 | 1298 | if (vlan_filtering) { |
| 965 | 1299 | /* The port is being kept as VLAN-unaware port when bridge is |
| 966 | 1300 | * set up with vlan_filtering not being set, Otherwise, the |
| @@ -1130,27 +1464,42 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port, · 163 unmodified lines | ||
| 1130 | 1464 | return 0; |
| 1131 | 1465 | } |
| 1132 | 1466 | |
| 1133 | −static int mt7530_port_mirror_add(struct dsa_switch *ds, int port, | |
| 1467 | +static int mt753x_mirror_port_get(unsigned int id, u32 val) | |
| 1468 | +{ | |
| 1469 | + return (id == ID_MT7531) ? MT7531_MIRROR_PORT_GET(val) : | |
| 1470 | + MIRROR_PORT(val); | |
| 1471 | +} | |
| 1472 | + | |
| 1473 | +static int mt753x_mirror_port_set(unsigned int id, u32 val) | |
| 1474 | +{ | |
| 1475 | + return (id == ID_MT7531) ? MT7531_MIRROR_PORT_SET(val) : | |
| 1476 | + MIRROR_PORT(val); | |
| 1477 | +} | |
| 1478 | + | |
| 1479 | +static int mt753x_port_mirror_add(struct dsa_switch *ds, int port, | |
| 1134 | 1480 | struct dsa_mall_mirror_tc_entry *mirror, |
| 1135 | 1481 | bool ingress) |
| 1136 | 1482 | { |
| 1137 | 1483 | struct mt7530_priv *priv = ds->priv; |
| 1484 | + int monitor_port; | |
| 1138 | 1485 | u32 val; |
| 1139 | 1486 | |
| 1140 | 1487 | /* Check for existent entry */ |
| 1141 | 1488 | if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) |
| 1142 | 1489 | return -EEXIST; |
| 1143 | 1490 | |
| 1144 | − val = mt7530_read(priv, MT7530_MFC); | |
| 1491 | + val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id)); | |
| 1145 | 1492 | |
| 1146 | 1493 | /* MT7530 only supports one monitor port */ |
| 1147 | − if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port) | |
| 1494 | + monitor_port = mt753x_mirror_port_get(priv->id, val); | |
| 1495 | + if (val & MT753X_MIRROR_EN(priv->id) && | |
| 1496 | + monitor_port != mirror->to_local_port) | |
| 1148 | 1497 | return -EEXIST; |
| 1149 | 1498 | |
| 1150 | − val |= MIRROR_EN; | |
| 1151 | − val &= ~MIRROR_MASK; | |
| 1152 | − val |= mirror->to_local_port; | |
| 1153 | − mt7530_write(priv, MT7530_MFC, val); | |
| 1499 | + val |= MT753X_MIRROR_EN(priv->id); | |
| 1500 | + val &= ~MT753X_MIRROR_MASK(priv->id); | |
| 1501 | + val |= mt753x_mirror_port_set(priv->id, mirror->to_local_port); | |
| 1502 | + mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val); | |
| 1154 | 1503 | |
| 1155 | 1504 | val = mt7530_read(priv, MT7530_PCR_P(port)); |
| 1156 | 1505 | if (ingress) { |
| @@ -1165,7 +1514,7 @@ static int mt7530_port_mirror_add(struct dsa_switch *ds, int port, · 8 unmodified lines | ||
| 1165 | 1514 | return 0; |
| 1166 | 1515 | } |
| 1167 | 1516 | |
| 1168 | −static void mt7530_port_mirror_del(struct dsa_switch *ds, int port, | |
| 1517 | +static void mt753x_port_mirror_del(struct dsa_switch *ds, int port, | |
| 1169 | 1518 | struct dsa_mall_mirror_tc_entry *mirror) |
| 1170 | 1519 | { |
| 1171 | 1520 | struct mt7530_priv *priv = ds->priv; |
| @@ -1182,9 +1531,9 @@ static void mt7530_port_mirror_del(struct dsa_switch *ds, int port, · 10 unmodified lines | ||
| 1182 | 1531 | mt7530_write(priv, MT7530_PCR_P(port), val); |
| 1183 | 1532 | |
| 1184 | 1533 | if (!priv->mirror_rx && !priv->mirror_tx) { |
| 1185 | − val = mt7530_read(priv, MT7530_MFC); | |
| 1186 | − val &= ~MIRROR_EN; | |
| 1187 | − mt7530_write(priv, MT7530_MFC, val); | |
| 1534 | + val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id)); | |
| 1535 | + val &= ~MT753X_MIRROR_EN(priv->id); | |
| 1536 | + mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val); | |
| 1188 | 1537 | } |
| 1189 | 1538 | } |
| 1190 | 1539 | |
| @@ -1290,9 +1639,11 @@ mt7530_setup(struct dsa_switch *ds) · 99 unmodified lines | ||
| 1290 | 1639 | mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, |
| 1291 | 1640 | PCR_MATRIX_CLR); |
| 1292 | 1641 | |
| 1293 | − if (dsa_is_cpu_port(ds, i)) | |
| 1294 | − mt7530_cpu_port_enable(priv, i); | |
| 1295 | − else | |
| 1642 | + if (dsa_is_cpu_port(ds, i)) { | |
| 1643 | + ret = mt753x_cpu_port_enable(ds, i); | |
| 1644 | + if (ret) | |
| 1645 | + return ret; | |
| 1646 | + } else | |
| 1296 | 1647 | mt7530_port_disable(ds, i); |
| 1297 | 1648 | |
| 1298 | 1649 | /* Enable consistent egress tag */ |
| @@ -1352,82 +1703,546 @@ mt7530_setup(struct dsa_switch *ds) · 53 unmodified lines | ||
| 1352 | 1703 | return 0; |
| 1353 | 1704 | } |
| 1354 | 1705 | |
| 1355 | −static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port, | |
| 1356 | − unsigned int mode, | |
| 1357 | − const struct phylink_link_state *state) | |
| 1706 | +static int | |
| 1707 | +mt7531_setup(struct dsa_switch *ds) | |
| 1358 | 1708 | { |
| 1359 | 1709 | struct mt7530_priv *priv = ds->priv; |
| 1360 | − u32 mcr_cur, mcr_new; | |
| 1361 | − | |
| 1362 | − switch (port) { | |
| 1363 | − case 0: /* Internal phy */ | |
| 1364 | − case 1: | |
| 1365 | − case 2: | |
| 1366 | − case 3: | |
| 1367 | − case 4: | |
| 1368 | − if (state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1369 | − return; | |
| 1370 | − break; | |
| 1371 | − case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ | |
| 1372 | − if (priv->p5_interface == state->interface) | |
| 1373 | − break; | |
| 1374 | − if (!phy_interface_mode_is_rgmii(state->interface) && | |
| 1375 | − state->interface != PHY_INTERFACE_MODE_MII && | |
| 1376 | − state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1377 | − return; | |
| 1710 | + struct mt7530_dummy_poll p; | |
| 1711 | + u32 val, id; | |
| 1712 | + int ret, i; | |
| 1378 | 1713 | |
| 1379 | − mt7530_setup_port5(ds, state->interface); | |
| 1380 | − break; | |
| 1381 | − case 6: /* 1st cpu port */ | |
| 1382 | − if (priv->p6_interface == state->interface) | |
| 1383 | − break; | |
| 1714 | + /* Reset whole chip through gpio pin or memory-mapped registers for | |
| 1715 | + * different type of hardware | |
| 1716 | + */ | |
| 1717 | + if (priv->mcm) { | |
| 1718 | + reset_control_assert(priv->rstc); | |
| 1719 | + usleep_range(1000, 1100); | |
| 1720 | + reset_control_deassert(priv->rstc); | |
| 1721 | + } else { | |
| 1722 | + gpiod_set_value_cansleep(priv->reset, 0); | |
| 1723 | + usleep_range(1000, 1100); | |
| 1724 | + gpiod_set_value_cansleep(priv->reset, 1); | |
| 1725 | + } | |
| 1384 | 1726 | |
| 1385 | − if (state->interface != PHY_INTERFACE_MODE_RGMII && | |
| 1386 | − state->interface != PHY_INTERFACE_MODE_TRGMII) | |
| 1387 | − return; | |
| 1727 | + /* Waiting for MT7530 got to stable */ | |
| 1728 | + INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP); | |
| 1729 | + ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0, | |
| 1730 | + 20, 1000000); | |
| 1731 | + if (ret < 0) { | |
| 1732 | + dev_err(priv->dev, "reset timeout\n"); | |
| 1733 | + return ret; | |
| 1734 | + } | |
| 1388 | 1735 | |
| 1389 | − /* Setup TX circuit incluing relevant PAD and driving */ | |
| 1390 | − mt7530_pad_clk_setup(ds, state->interface); | |
| 1736 | + id = mt7530_read(priv, MT7531_CREV); | |
| 1737 | + id >>= CHIP_NAME_SHIFT; | |
| 1391 | 1738 | |
| 1392 | − priv->p6_interface = state->interface; | |
| 1393 | − break; | |
| 1394 | − default: | |
| 1395 | − dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); | |
| 1396 | − return; | |
| 1739 | + if (id != MT7531_ID) { | |
| 1740 | + dev_err(priv->dev, "chip %x can't be supported\n", id); | |
| 1741 | + return -ENODEV; | |
| 1397 | 1742 | } |
| 1398 | 1743 | |
| 1399 | − if (phylink_autoneg_inband(mode)) { | |
| 1400 | − dev_err(ds->dev, "%s: in-band negotiation unsupported\n", | |
| 1401 | − __func__); | |
| 1402 | − return; | |
| 1744 | + /* Reset the switch through internal reset */ | |
| 1745 | + mt7530_write(priv, MT7530_SYS_CTRL, | |
| 1746 | + SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | | |
| 1747 | + SYS_CTRL_REG_RST); | |
| 1748 | + | |
| 1749 | + if (mt7531_dual_sgmii_supported(priv)) { | |
| 1750 | + priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII; | |
| 1751 | + | |
| 1752 | + /* Let ds->slave_mii_bus be able to access external phy. */ | |
| 1753 | + mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK, | |
| 1754 | + MT7531_EXT_P_MDC_11); | |
| 1755 | + mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK, | |
| 1756 | + MT7531_EXT_P_MDIO_12); | |
| 1757 | + } else { | |
| 1758 | + priv->p5_intf_sel = P5_INTF_SEL_GMAC5; | |
| 1403 | 1759 | } |
| 1760 | + dev_dbg(ds->dev, "P5 support %s interface\n", | |
| 1761 | + p5_intf_modes(priv->p5_intf_sel)); | |
| 1404 | 1762 | |
| 1405 | − mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); | |
| 1406 | − mcr_new = mcr_cur; | |
| 1407 | − mcr_new &= ~PMCR_LINK_SETTINGS_MASK; | |
| 1408 | − mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN | | |
| 1409 | − PMCR_BACKPR_EN | PMCR_FORCE_MODE; | |
| 1763 | + mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK, | |
| 1764 | + MT7531_GPIO0_INTERRUPT); | |
| 1410 | 1765 | |
| 1411 | − /* Are we connected to external phy */ | |
| 1412 | − if (port == 5 && dsa_is_user_port(ds, 5)) | |
| 1413 | − mcr_new |= PMCR_EXT_PHY; | |
| 1766 | + /* Let phylink decide the interface later. */ | |
| 1767 | + priv->p5_interface = PHY_INTERFACE_MODE_NA; | |
| 1768 | + priv->p6_interface = PHY_INTERFACE_MODE_NA; | |
| 1414 | 1769 | |
| 1415 | − if (mcr_new != mcr_cur) | |
| 1416 | − mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); | |
| 1417 | −} | |
| 1770 | + /* Enable PHY core PLL, since phy_device has not yet been created | |
| 1771 | + * provided for phy_[read,write]_mmd_indirect is called, we provide | |
| 1772 | + * our own mt7531_ind_mmd_phy_[read,write] to complete this | |
| 1773 | + * function. | |
| 1774 | + */ | |
| 1775 | + val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR, | |
| 1776 | + MDIO_MMD_VEND2, CORE_PLL_GROUP4); | |
| 1777 | + val |= MT7531_PHY_PLL_BYPASS_MODE; | |
| 1778 | + val &= ~MT7531_PHY_PLL_OFF; | |
| 1779 | + mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2, | |
| 1780 | + CORE_PLL_GROUP4, val); | |
| 1781 | + | |
| 1782 | + /* BPDU to CPU port */ | |
| 1783 | + mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, | |
| 1784 | + BIT(MT7530_CPU_PORT)); | |
| 1785 | + mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, | |
| 1786 | + MT753X_BPDU_CPU_ONLY); | |
| 1418 | 1787 | |
| 1419 | −static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port, | |
| 1420 | − unsigned int mode, | |
| 1421 | − phy_interface_t interface) | |
| 1422 | −{ | |
| 1423 | − struct mt7530_priv *priv = ds->priv; | |
| 1788 | + /* Enable and reset MIB counters */ | |
| 1789 | + mt7530_mib_reset(ds); | |
| 1424 | 1790 | |
| 1425 | − mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); | |
| 1426 | −} | |
| 1791 | + for (i = 0; i < MT7530_NUM_PORTS; i++) { | |
| 1792 | + /* Disable forwarding by default on all ports */ | |
| 1793 | + mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, | |
| 1794 | + PCR_MATRIX_CLR); | |
| 1427 | 1795 | |
| 1428 | −static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port, | |
| 1429 | − unsigned int mode, | |
| 1430 | − phy_interface_t interface, | |
| 1796 | + mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR); | |
| 1797 | + | |
| 1798 | + if (dsa_is_cpu_port(ds, i)) { | |
| 1799 | + ret = mt753x_cpu_port_enable(ds, i); | |
| 1800 | + if (ret) | |
| 1801 | + return ret; | |
| 1802 | + } else | |
| 1803 | + mt7530_port_disable(ds, i); | |
| 1804 | + | |
| 1805 | + /* Enable consistent egress tag */ | |
| 1806 | + mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, | |
| 1807 | + PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); | |
| 1808 | + } | |
| 1809 | + | |
| 1810 | + ds->configure_vlan_while_not_filtering = true; | |
| 1811 | + | |
| 1812 | + /* Flush the FDB table */ | |
| 1813 | + ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); | |
| 1814 | + if (ret < 0) | |
| 1815 | + return ret; | |
| 1816 | + | |
| 1817 | + return 0; | |
| 1818 | +} | |
| 1819 | + | |
| 1820 | +static bool | |
| 1821 | +mt7530_phy_mode_supported(struct dsa_switch *ds, int port, | |
| 1822 | + const struct phylink_link_state *state) | |
| 1823 | +{ | |
| 1824 | + struct mt7530_priv *priv = ds->priv; | |
| 1825 | + | |
| 1826 | + switch (port) { | |
| 1827 | + case 0 ... 4: /* Internal phy */ | |
| 1828 | + if (state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1829 | + return false; | |
| 1830 | + break; | |
| 1831 | + case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ | |
| 1832 | + if (!phy_interface_mode_is_rgmii(state->interface) && | |
| 1833 | + state->interface != PHY_INTERFACE_MODE_MII && | |
| 1834 | + state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1835 | + return false; | |
| 1836 | + break; | |
| 1837 | + case 6: /* 1st cpu port */ | |
| 1838 | + if (state->interface != PHY_INTERFACE_MODE_RGMII && | |
| 1839 | + state->interface != PHY_INTERFACE_MODE_TRGMII) | |
| 1840 | + return false; | |
| 1841 | + break; | |
| 1842 | + default: | |
| 1843 | + dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, | |
| 1844 | + port); | |
| 1845 | + return false; | |
| 1846 | + } | |
| 1847 | + | |
| 1848 | + return true; | |
| 1849 | +} | |
| 1850 | + | |
| 1851 | +static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) | |
| 1852 | +{ | |
| 1853 | + return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); | |
| 1854 | +} | |
| 1855 | + | |
| 1856 | +static bool | |
| 1857 | +mt7531_phy_mode_supported(struct dsa_switch *ds, int port, | |
| 1858 | + const struct phylink_link_state *state) | |
| 1859 | +{ | |
| 1860 | + struct mt7530_priv *priv = ds->priv; | |
| 1861 | + | |
| 1862 | + switch (port) { | |
| 1863 | + case 0 ... 4: /* Internal phy */ | |
| 1864 | + if (state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1865 | + return false; | |
| 1866 | + break; | |
| 1867 | + case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ | |
| 1868 | + if (mt7531_is_rgmii_port(priv, port)) | |
| 1869 | + return phy_interface_mode_is_rgmii(state->interface); | |
| 1870 | + fallthrough; | |
| 1871 | + case 6: /* 1st cpu port supports sgmii/8023z only */ | |
| 1872 | + if (state->interface != PHY_INTERFACE_MODE_SGMII && | |
| 1873 | + !phy_interface_mode_is_8023z(state->interface)) | |
| 1874 | + return false; | |
| 1875 | + break; | |
| 1876 | + default: | |
| 1877 | + dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, | |
| 1878 | + port); | |
| 1879 | + return false; | |
| 1880 | + } | |
| 1881 | + | |
| 1882 | + return true; | |
| 1883 | +} | |
| 1884 | + | |
| 1885 | +static bool | |
| 1886 | +mt753x_phy_mode_supported(struct dsa_switch *ds, int port, | |
| 1887 | + const struct phylink_link_state *state) | |
| 1888 | +{ | |
| 1889 | + struct mt7530_priv *priv = ds->priv; | |
| 1890 | + | |
| 1891 | + return priv->info->phy_mode_supported(ds, port, state); | |
| 1892 | +} | |
| 1893 | + | |
| 1894 | +static int | |
| 1895 | +mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state) | |
| 1896 | +{ | |
| 1897 | + struct mt7530_priv *priv = ds->priv; | |
| 1898 | + | |
| 1899 | + return priv->info->pad_setup(ds, state->interface); | |
| 1900 | +} | |
| 1901 | + | |
| 1902 | +static int | |
| 1903 | +mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode, | |
| 1904 | + phy_interface_t interface) | |
| 1905 | +{ | |
| 1906 | + struct mt7530_priv *priv = ds->priv; | |
| 1907 | + | |
| 1908 | + /* Only need to setup port5. */ | |
| 1909 | + if (port != 5) | |
| 1910 | + return 0; | |
| 1911 | + | |
| 1912 | + mt7530_setup_port5(priv->ds, interface); | |
| 1913 | + | |
| 1914 | + return 0; | |
| 1915 | +} | |
| 1916 | + | |
| 1917 | +static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, | |
| 1918 | + phy_interface_t interface, | |
| 1919 | + struct phy_device *phydev) | |
| 1920 | +{ | |
| 1921 | + u32 val; | |
| 1922 | + | |
| 1923 | + if (!mt7531_is_rgmii_port(priv, port)) { | |
| 1924 | + dev_err(priv->dev, "RGMII mode is not available for port %d\n", | |
| 1925 | + port); | |
| 1926 | + return -EINVAL; | |
| 1927 | + } | |
| 1928 | + | |
| 1929 | + val = mt7530_read(priv, MT7531_CLKGEN_CTRL); | |
| 1930 | + val |= GP_CLK_EN; | |
| 1931 | + val &= ~GP_MODE_MASK; | |
| 1932 | + val |= GP_MODE(MT7531_GP_MODE_RGMII); | |
| 1933 | + val &= ~CLK_SKEW_IN_MASK; | |
| 1934 | + val |= CLK_SKEW_IN(MT7531_CLK_SKEW_NO_CHG); | |
| 1935 | + val &= ~CLK_SKEW_OUT_MASK; | |
| 1936 | + val |= CLK_SKEW_OUT(MT7531_CLK_SKEW_NO_CHG); | |
| 1937 | + val |= TXCLK_NO_REVERSE | RXCLK_NO_DELAY; | |
| 1938 | + | |
| 1939 | + /* Do not adjust rgmii delay when vendor phy driver presents. */ | |
| 1940 | + if (!phydev || phy_driver_is_genphy(phydev)) { | |
| 1941 | + val &= ~(TXCLK_NO_REVERSE | RXCLK_NO_DELAY); | |
| 1942 | + switch (interface) { | |
| 1943 | + case PHY_INTERFACE_MODE_RGMII: | |
| 1944 | + val |= TXCLK_NO_REVERSE; | |
| 1945 | + val |= RXCLK_NO_DELAY; | |
| 1946 | + break; | |
| 1947 | + case PHY_INTERFACE_MODE_RGMII_RXID: | |
| 1948 | + val |= TXCLK_NO_REVERSE; | |
| 1949 | + break; | |
| 1950 | + case PHY_INTERFACE_MODE_RGMII_TXID: | |
| 1951 | + val |= RXCLK_NO_DELAY; | |
| 1952 | + break; | |
| 1953 | + case PHY_INTERFACE_MODE_RGMII_ID: | |
| 1954 | + break; | |
| 1955 | + default: | |
| 1956 | + return -EINVAL; | |
| 1957 | + } | |
| 1958 | + } | |
| 1959 | + mt7530_write(priv, MT7531_CLKGEN_CTRL, val); | |
| 1960 | + | |
| 1961 | + return 0; | |
| 1962 | +} | |
| 1963 | + | |
| 1964 | +static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, | |
| 1965 | + unsigned long *supported) | |
| 1966 | +{ | |
| 1967 | + /* Port5 supports ethier RGMII or SGMII. | |
| 1968 | + * Port6 supports SGMII only. | |
| 1969 | + */ | |
| 1970 | + switch (port) { | |
| 1971 | + case 5: | |
| 1972 | + if (mt7531_is_rgmii_port(priv, port)) | |
| 1973 | + break; | |
| 1974 | + fallthrough; | |
| 1975 | + case 6: | |
| 1976 | + phylink_set(supported, 1000baseX_Full); | |
| 1977 | + phylink_set(supported, 2500baseX_Full); | |
| 1978 | + phylink_set(supported, 2500baseT_Full); | |
| 1979 | + } | |
| 1980 | +} | |
| 1981 | + | |
| 1982 | +static void | |
| 1983 | +mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, | |
| 1984 | + unsigned int mode, phy_interface_t interface, | |
| 1985 | + int speed, int duplex) | |
| 1986 | +{ | |
| 1987 | + struct mt7530_priv *priv = ds->priv; | |
| 1988 | + unsigned int val; | |
| 1989 | + | |
| 1990 | + /* For adjusting speed and duplex of SGMII force mode. */ | |
| 1991 | + if (interface != PHY_INTERFACE_MODE_SGMII || | |
| 1992 | + phylink_autoneg_inband(mode)) | |
| 1993 | + return; | |
| 1994 | + | |
| 1995 | + /* SGMII force mode setting */ | |
| 1996 | + val = mt7530_read(priv, MT7531_SGMII_MODE(port)); | |
| 1997 | + val &= ~MT7531_SGMII_IF_MODE_MASK; | |
| 1998 | + | |
| 1999 | + switch (speed) { | |
| 2000 | + case SPEED_10: | |
| 2001 | + val |= MT7531_SGMII_FORCE_SPEED_10; | |
| 2002 | + break; | |
| 2003 | + case SPEED_100: | |
| 2004 | + val |= MT7531_SGMII_FORCE_SPEED_100; | |
| 2005 | + break; | |
| 2006 | + case SPEED_1000: | |
| 2007 | + val |= MT7531_SGMII_FORCE_SPEED_1000; | |
| 2008 | + break; | |
| 2009 | + } | |
| 2010 | + | |
| 2011 | + /* MT7531 SGMII 1G force mode can only work in full duplex mode, | |
| 2012 | + * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. | |
| 2013 | + */ | |
| 2014 | + if ((speed == SPEED_10 || speed == SPEED_100) && | |
| 2015 | + duplex != DUPLEX_FULL) | |
| 2016 | + val |= MT7531_SGMII_FORCE_HALF_DUPLEX; | |
| 2017 | + | |
| 2018 | + mt7530_write(priv, MT7531_SGMII_MODE(port), val); | |
| 2019 | +} | |
| 2020 | + | |
| 2021 | +static bool mt753x_is_mac_port(u32 port) | |
| 2022 | +{ | |
| 2023 | + return (port == 5 || port == 6); | |
| 2024 | +} | |
| 2025 | + | |
| 2026 | +static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port, | |
| 2027 | + phy_interface_t interface) | |
| 2028 | +{ | |
| 2029 | + u32 val; | |
| 2030 | + | |
| 2031 | + if (!mt753x_is_mac_port(port)) | |
| 2032 | + return -EINVAL; | |
| 2033 | + | |
| 2034 | + mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), | |
| 2035 | + MT7531_SGMII_PHYA_PWD); | |
| 2036 | + | |
| 2037 | + val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port)); | |
| 2038 | + val &= ~MT7531_RG_TPHY_SPEED_MASK; | |
| 2039 | + /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B | |
| 2040 | + * encoding. | |
| 2041 | + */ | |
| 2042 | + val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ? | |
| 2043 | + MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G; | |
| 2044 | + mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val); | |
| 2045 | + | |
| 2046 | + mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); | |
| 2047 | + | |
| 2048 | + /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex | |
| 2049 | + * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. | |
| 2050 | + */ | |
| 2051 | + mt7530_rmw(priv, MT7531_SGMII_MODE(port), | |
| 2052 | + MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS, | |
| 2053 | + MT7531_SGMII_FORCE_SPEED_1000); | |
| 2054 | + | |
| 2055 | + mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); | |
| 2056 | + | |
| 2057 | + return 0; | |
| 2058 | +} | |
| 2059 | + | |
| 2060 | +static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port, | |
| 2061 | + phy_interface_t interface) | |
| 2062 | +{ | |
| 2063 | + if (!mt753x_is_mac_port(port)) | |
| 2064 | + return -EINVAL; | |
| 2065 | + | |
| 2066 | + mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), | |
| 2067 | + MT7531_SGMII_PHYA_PWD); | |
| 2068 | + | |
| 2069 | + mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), | |
| 2070 | + MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G); | |
| 2071 | + | |
| 2072 | + mt7530_set(priv, MT7531_SGMII_MODE(port), | |
| 2073 | + MT7531_SGMII_REMOTE_FAULT_DIS | | |
| 2074 | + MT7531_SGMII_SPEED_DUPLEX_AN); | |
| 2075 | + | |
| 2076 | + mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port), | |
| 2077 | + MT7531_SGMII_TX_CONFIG_MASK, 1); | |
| 2078 | + | |
| 2079 | + mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); | |
| 2080 | + | |
| 2081 | + mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART); | |
| 2082 | + | |
| 2083 | + mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); | |
| 2084 | + | |
| 2085 | + return 0; | |
| 2086 | +} | |
| 2087 | + | |
| 2088 | +static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port) | |
| 2089 | +{ | |
| 2090 | + struct mt7530_priv *priv = ds->priv; | |
| 2091 | + u32 val; | |
| 2092 | + | |
| 2093 | + /* Only restart AN when AN is enabled */ | |
| 2094 | + val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); | |
| 2095 | + if (val & MT7531_SGMII_AN_ENABLE) { | |
| 2096 | + val |= MT7531_SGMII_AN_RESTART; | |
| 2097 | + mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val); | |
| 2098 | + } | |
| 2099 | +} | |
| 2100 | + | |
| 2101 | +static int | |
| 2102 | +mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, | |
| 2103 | + phy_interface_t interface) | |
| 2104 | +{ | |
| 2105 | + struct mt7530_priv *priv = ds->priv; | |
| 2106 | + struct phy_device *phydev; | |
| 2107 | + struct dsa_port *dp; | |
| 2108 | + | |
| 2109 | + if (!mt753x_is_mac_port(port)) { | |
| 2110 | + dev_err(priv->dev, "port %d is not a MAC port\n", port); | |
| 2111 | + return -EINVAL; | |
| 2112 | + } | |
| 2113 | + | |
| 2114 | + switch (interface) { | |
| 2115 | + case PHY_INTERFACE_MODE_RGMII: | |
| 2116 | + case PHY_INTERFACE_MODE_RGMII_ID: | |
| 2117 | + case PHY_INTERFACE_MODE_RGMII_RXID: | |
| 2118 | + case PHY_INTERFACE_MODE_RGMII_TXID: | |
| 2119 | + dp = dsa_to_port(ds, port); | |
| 2120 | + phydev = dp->slave->phydev; | |
| 2121 | + return mt7531_rgmii_setup(priv, port, interface, phydev); | |
| 2122 | + case PHY_INTERFACE_MODE_SGMII: | |
| 2123 | + return mt7531_sgmii_setup_mode_an(priv, port, interface); | |
| 2124 | + case PHY_INTERFACE_MODE_NA: | |
| 2125 | + case PHY_INTERFACE_MODE_1000BASEX: | |
| 2126 | + case PHY_INTERFACE_MODE_2500BASEX: | |
| 2127 | + if (phylink_autoneg_inband(mode)) | |
| 2128 | + return -EINVAL; | |
| 2129 | + | |
| 2130 | + return mt7531_sgmii_setup_mode_force(priv, port, interface); | |
| 2131 | + default: | |
| 2132 | + return -EINVAL; | |
| 2133 | + } | |
| 2134 | + | |
| 2135 | + return -EINVAL; | |
| 2136 | +} | |
| 2137 | + | |
| 2138 | +static int | |
| 2139 | +mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode, | |
| 2140 | + const struct phylink_link_state *state) | |
| 2141 | +{ | |
| 2142 | + struct mt7530_priv *priv = ds->priv; | |
| 2143 | + | |
| 2144 | + return priv->info->mac_port_config(ds, port, mode, state->interface); | |
| 2145 | +} | |
| 2146 | + | |
| 2147 | +static void | |
| 2148 | +mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, | |
| 2149 | + const struct phylink_link_state *state) | |
| 2150 | +{ | |
| 2151 | + struct mt7530_priv *priv = ds->priv; | |
| 2152 | + u32 mcr_cur, mcr_new; | |
| 2153 | + | |
| 2154 | + if (!mt753x_phy_mode_supported(ds, port, state)) | |
| 2155 | + goto unsupported; | |
| 2156 | + | |
| 2157 | + switch (port) { | |
| 2158 | + case 0 ... 4: /* Internal phy */ | |
| 2159 | + if (state->interface != PHY_INTERFACE_MODE_GMII) | |
| 2160 | + goto unsupported; | |
| 2161 | + break; | |
| 2162 | + case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ | |
| 2163 | + if (priv->p5_interface == state->interface) | |
| 2164 | + break; | |
| 2165 | + | |
| 2166 | + if (mt753x_mac_config(ds, port, mode, state) < 0) | |
| 2167 | + goto unsupported; | |
| 2168 | + | |
| 2169 | + if (priv->p5_intf_sel != P5_DISABLED) | |
| 2170 | + priv->p5_interface = state->interface; | |
| 2171 | + break; | |
| 2172 | + case 6: /* 1st cpu port */ | |
| 2173 | + if (priv->p6_interface == state->interface) | |
| 2174 | + break; | |
| 2175 | + | |
| 2176 | + mt753x_pad_setup(ds, state); | |
| 2177 | + | |
| 2178 | + if (mt753x_mac_config(ds, port, mode, state) < 0) | |
| 2179 | + goto unsupported; | |
| 2180 | + | |
| 2181 | + priv->p6_interface = state->interface; | |
| 2182 | + break; | |
| 2183 | + default: | |
| 2184 | +unsupported: | |
| 2185 | + dev_err(ds->dev, "%s: unsupported %s port: %i\n", | |
| 2186 | + __func__, phy_modes(state->interface), port); | |
| 2187 | + return; | |
| 2188 | + } | |
| 2189 | + | |
| 2190 | + if (phylink_autoneg_inband(mode) && | |
| 2191 | + state->interface != PHY_INTERFACE_MODE_SGMII) { | |
| 2192 | + dev_err(ds->dev, "%s: in-band negotiation unsupported\n", | |
| 2193 | + __func__); | |
| 2194 | + return; | |
| 2195 | + } | |
| 2196 | + | |
| 2197 | + mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); | |
| 2198 | + mcr_new = mcr_cur; | |
| 2199 | + mcr_new &= ~PMCR_LINK_SETTINGS_MASK; | |
| 2200 | + mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN | | |
| 2201 | + PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id); | |
| 2202 | + | |
| 2203 | + /* Are we connected to external phy */ | |
| 2204 | + if (port == 5 && dsa_is_user_port(ds, 5)) | |
| 2205 | + mcr_new |= PMCR_EXT_PHY; | |
| 2206 | + | |
| 2207 | + if (mcr_new != mcr_cur) | |
| 2208 | + mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); | |
| 2209 | +} | |
| 2210 | + | |
| 2211 | +static void | |
| 2212 | +mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port) | |
| 2213 | +{ | |
| 2214 | + struct mt7530_priv *priv = ds->priv; | |
| 2215 | + | |
| 2216 | + if (!priv->info->mac_pcs_an_restart) | |
| 2217 | + return; | |
| 2218 | + | |
| 2219 | + priv->info->mac_pcs_an_restart(ds, port); | |
| 2220 | +} | |
| 2221 | + | |
| 2222 | +static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, | |
| 2223 | + unsigned int mode, | |
| 2224 | + phy_interface_t interface) | |
| 2225 | +{ | |
| 2226 | + struct mt7530_priv *priv = ds->priv; | |
| 2227 | + | |
| 2228 | + mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); | |
| 2229 | +} | |
| 2230 | + | |
| 2231 | +static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port, | |
| 2232 | + unsigned int mode, phy_interface_t interface, | |
| 2233 | + int speed, int duplex) | |
| 2234 | +{ | |
| 2235 | + struct mt7530_priv *priv = ds->priv; | |
| 2236 | + | |
| 2237 | + if (!priv->info->mac_pcs_link_up) | |
| 2238 | + return; | |
| 2239 | + | |
| 2240 | + priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex); | |
| 2241 | +} | |
| 2242 | + | |
| 2243 | +static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, | |
| 2244 | + unsigned int mode, | |
| 2245 | + phy_interface_t interface, | |
| 1431 | 2246 | struct phy_device *phydev, |
| 1432 | 2247 | int speed, int duplex, |
| 1433 | 2248 | bool tx_pause, bool rx_pause) |
| @@ -1435,8 +2250,19 @@ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port, · 1 unmodified line | ||
| 1435 | 2250 | struct mt7530_priv *priv = ds->priv; |
| 1436 | 2251 | u32 mcr; |
| 1437 | 2252 | |
| 2253 | + mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex); | |
| 2254 | + | |
| 1438 | 2255 | mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; |
| 1439 | 2256 | |
| 2257 | + /* MT753x MAC works in 1G full duplex mode for all up-clocked | |
| 2258 | + * variants. | |
| 2259 | + */ | |
| 2260 | + if (interface == PHY_INTERFACE_MODE_TRGMII || | |
| 2261 | + (phy_interface_mode_is_8023z(interface))) { | |
| 2262 | + speed = SPEED_1000; | |
| 2263 | + duplex = DUPLEX_FULL; | |
| 2264 | + } | |
| 2265 | + | |
| 1440 | 2266 | switch (speed) { |
| 1441 | 2267 | case SPEED_1000: |
| 1442 | 2268 | mcr |= PMCR_FORCE_SPEED_1000; |
| @@ -1456,66 +2282,107 @@ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port, · 13 unmodified lines | ||
| 1456 | 2282 | mt7530_set(priv, MT7530_PMCR_P(port), mcr); |
| 1457 | 2283 | } |
| 1458 | 2284 | |
| 1459 | −static void mt7530_phylink_validate(struct dsa_switch *ds, int port, | |
| 1460 | − unsigned long *supported, | |
| 1461 | − struct phylink_link_state *state) | |
| 2285 | +static int | |
| 2286 | +mt7531_cpu_port_config(struct dsa_switch *ds, int port) | |
| 1462 | 2287 | { |
| 1463 | − __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; | |
| 2288 | + struct mt7530_priv *priv = ds->priv; | |
| 2289 | + phy_interface_t interface; | |
| 2290 | + int speed; | |
| 2291 | + int ret; | |
| 1464 | 2292 | |
| 1465 | 2293 | switch (port) { |
| 1466 | − case 0: /* Internal phy */ | |
| 1467 | − case 1: | |
| 1468 | − case 2: | |
| 1469 | − case 3: | |
| 1470 | − case 4: | |
| 1471 | − if (state->interface != PHY_INTERFACE_MODE_NA && | |
| 1472 | − state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1473 | − goto unsupported; | |
| 1474 | − break; | |
| 1475 | − case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ | |
| 1476 | − if (state->interface != PHY_INTERFACE_MODE_NA && | |
| 1477 | − !phy_interface_mode_is_rgmii(state->interface) && | |
| 1478 | − state->interface != PHY_INTERFACE_MODE_MII && | |
| 1479 | − state->interface != PHY_INTERFACE_MODE_GMII) | |
| 1480 | − goto unsupported; | |
| 2294 | + case 5: | |
| 2295 | + if (mt7531_is_rgmii_port(priv, port)) | |
| 2296 | + interface = PHY_INTERFACE_MODE_RGMII; | |
| 2297 | + else | |
| 2298 | + interface = PHY_INTERFACE_MODE_2500BASEX; | |
| 2299 | + | |
| 2300 | + priv->p5_interface = interface; | |
| 1481 | 2301 | break; |
| 1482 | − case 6: /* 1st cpu port */ | |
| 1483 | − if (state->interface != PHY_INTERFACE_MODE_NA && | |
| 1484 | − state->interface != PHY_INTERFACE_MODE_RGMII && | |
| 1485 | − state->interface != PHY_INTERFACE_MODE_TRGMII) | |
| 1486 | − goto unsupported; | |
| 2302 | + case 6: | |
| 2303 | + interface = PHY_INTERFACE_MODE_2500BASEX; | |
| 2304 | + | |
| 2305 | + mt7531_pad_setup(ds, interface); | |
| 2306 | + | |
| 2307 | + priv->p6_interface = interface; | |
| 1487 | 2308 | break; |
| 1488 | 2309 | default: |
| 1489 | − dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); | |
| 1490 | −unsupported: | |
| 2310 | + return -EINVAL; | |
| 2311 | + } | |
| 2312 | + | |
| 2313 | + if (interface == PHY_INTERFACE_MODE_2500BASEX) | |
| 2314 | + speed = SPEED_2500; | |
| 2315 | + else | |
| 2316 | + speed = SPEED_1000; | |
| 2317 | + | |
| 2318 | + ret = mt7531_mac_config(ds, port, MLO_AN_FIXED, interface); | |
| 2319 | + if (ret) | |
| 2320 | + return ret; | |
| 2321 | + mt7530_write(priv, MT7530_PMCR_P(port), | |
| 2322 | + PMCR_CPU_PORT_SETTING(priv->id)); | |
| 2323 | + mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, | |
| 2324 | + speed, DUPLEX_FULL, true, true); | |
| 2325 | + | |
| 2326 | + return 0; | |
| 2327 | +} | |
| 2328 | + | |
| 2329 | +static void | |
| 2330 | +mt7530_mac_port_validate(struct dsa_switch *ds, int port, | |
| 2331 | + unsigned long *supported) | |
| 2332 | +{ | |
| 2333 | + if (port == 5) | |
| 2334 | + phylink_set(supported, 1000baseX_Full); | |
| 2335 | +} | |
| 2336 | + | |
| 2337 | +static void mt7531_mac_port_validate(struct dsa_switch *ds, int port, | |
| 2338 | + unsigned long *supported) | |
| 2339 | +{ | |
| 2340 | + struct mt7530_priv *priv = ds->priv; | |
| 2341 | + | |
| 2342 | + mt7531_sgmii_validate(priv, port, supported); | |
| 2343 | +} | |
| 2344 | + | |
| 2345 | +static void | |
| 2346 | +mt753x_phylink_validate(struct dsa_switch *ds, int port, | |
| 2347 | + unsigned long *supported, | |
| 2348 | + struct phylink_link_state *state) | |
| 2349 | +{ | |
| 2350 | + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; | |
| 2351 | + struct mt7530_priv *priv = ds->priv; | |
| 2352 | + | |
| 2353 | + if (state->interface != PHY_INTERFACE_MODE_NA && | |
| 2354 | + !mt753x_phy_mode_supported(ds, port, state)) { | |
| 1491 | 2355 | linkmode_zero(supported); |
| 1492 | 2356 | return; |
| 1493 | 2357 | } |
| 1494 | 2358 | |
| 1495 | 2359 | phylink_set_port_modes(mask); |
| 1496 | − phylink_set(mask, Autoneg); | |
| 1497 | 2360 | |
| 1498 | − if (state->interface == PHY_INTERFACE_MODE_TRGMII) { | |
| 1499 | − phylink_set(mask, 1000baseT_Full); | |
| 1500 | − } else { | |
| 2361 | + if (state->interface != PHY_INTERFACE_MODE_TRGMII || | |
| 2362 | + !phy_interface_mode_is_8023z(state->interface)) { | |
| 1501 | 2363 | phylink_set(mask, 10baseT_Half); |
| 1502 | 2364 | phylink_set(mask, 10baseT_Full); |
| 1503 | 2365 | phylink_set(mask, 100baseT_Half); |
| 1504 | 2366 | phylink_set(mask, 100baseT_Full); |
| 1505 | − | |
| 1506 | − if (state->interface != PHY_INTERFACE_MODE_MII) { | |
| 1507 | − /* This switch only supports 1G full-duplex. */ | |
| 1508 | − phylink_set(mask, 1000baseT_Full); | |
| 1509 | − if (port == 5) | |
| 1510 | − phylink_set(mask, 1000baseX_Full); | |
| 1511 | − } | |
| 2367 | + phylink_set(mask, Autoneg); | |
| 1512 | 2368 | } |
| 1513 | 2369 | |
| 2370 | + /* This switch only supports 1G full-duplex. */ | |
| 2371 | + if (state->interface != PHY_INTERFACE_MODE_MII) | |
| 2372 | + phylink_set(mask, 1000baseT_Full); | |
| 2373 | + | |
| 2374 | + priv->info->mac_port_validate(ds, port, mask); | |
| 2375 | + | |
| 1514 | 2376 | phylink_set(mask, Pause); |
| 1515 | 2377 | phylink_set(mask, Asym_Pause); |
| 1516 | 2378 | |
| 1517 | 2379 | linkmode_and(supported, supported, mask); |
| 1518 | 2380 | linkmode_and(state->advertising, state->advertising, mask); |
| 2381 | + | |
| 2382 | + /* We can only operate at 2500BaseX or 1000BaseX. If requested | |
| 2383 | + * to advertise both, only report advertising at 2500BaseX. | |
| 2384 | + */ | |
| 2385 | + phylink_helper_basex_speed(state); | |
| 1519 | 2386 | } |
| 1520 | 2387 | |
| 1521 | 2388 | static int |
| @@ -1558,12 +2425,96 @@ mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port, · 36 unmodified lines | ||
| 1558 | 2425 | return 1; |
| 1559 | 2426 | } |
| 1560 | 2427 | |
| 2428 | +static int | |
| 2429 | +mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, | |
| 2430 | + struct phylink_link_state *state) | |
| 2431 | +{ | |
| 2432 | + u32 status, val; | |
| 2433 | + u16 config_reg; | |
| 2434 | + | |
| 2435 | + status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); | |
| 2436 | + state->link = !!(status & MT7531_SGMII_LINK_STATUS); | |
| 2437 | + if (state->interface == PHY_INTERFACE_MODE_SGMII && | |
| 2438 | + (status & MT7531_SGMII_AN_ENABLE)) { | |
| 2439 | + val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); | |
| 2440 | + config_reg = val >> 16; | |
| 2441 | + | |
| 2442 | + switch (config_reg & LPA_SGMII_SPD_MASK) { | |
| 2443 | + case LPA_SGMII_1000: | |
| 2444 | + state->speed = SPEED_1000; | |
| 2445 | + break; | |
| 2446 | + case LPA_SGMII_100: | |
| 2447 | + state->speed = SPEED_100; | |
| 2448 | + break; | |
| 2449 | + case LPA_SGMII_10: | |
| 2450 | + state->speed = SPEED_10; | |
| 2451 | + break; | |
| 2452 | + default: | |
| 2453 | + dev_err(priv->dev, "invalid sgmii PHY speed\n"); | |
| 2454 | + state->link = false; | |
| 2455 | + return -EINVAL; | |
| 2456 | + } | |
| 2457 | + | |
| 2458 | + if (config_reg & LPA_SGMII_FULL_DUPLEX) | |
| 2459 | + state->duplex = DUPLEX_FULL; | |
| 2460 | + else | |
| 2461 | + state->duplex = DUPLEX_HALF; | |
| 2462 | + } | |
| 2463 | + | |
| 2464 | + return 0; | |
| 2465 | +} | |
| 2466 | + | |
| 2467 | +static int | |
| 2468 | +mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port, | |
| 2469 | + struct phylink_link_state *state) | |
| 2470 | +{ | |
| 2471 | + struct mt7530_priv *priv = ds->priv; | |
| 2472 | + | |
| 2473 | + if (state->interface == PHY_INTERFACE_MODE_SGMII) | |
| 2474 | + return mt7531_sgmii_pcs_get_state_an(priv, port, state); | |
| 2475 | + | |
| 2476 | + return -EOPNOTSUPP; | |
| 2477 | +} | |
| 2478 | + | |
| 2479 | +static int | |
| 2480 | +mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port, | |
| 2481 | + struct phylink_link_state *state) | |
| 2482 | +{ | |
| 2483 | + struct mt7530_priv *priv = ds->priv; | |
| 2484 | + | |
| 2485 | + return priv->info->mac_port_get_state(ds, port, state); | |
| 2486 | +} | |
| 2487 | + | |
| 2488 | +static int | |
| 2489 | +mt753x_setup(struct dsa_switch *ds) | |
| 2490 | +{ | |
| 2491 | + struct mt7530_priv *priv = ds->priv; | |
| 2492 | + | |
| 2493 | + return priv->info->sw_setup(ds); | |
| 2494 | +} | |
| 2495 | + | |
| 2496 | +static int | |
| 2497 | +mt753x_phy_read(struct dsa_switch *ds, int port, int regnum) | |
| 2498 | +{ | |
| 2499 | + struct mt7530_priv *priv = ds->priv; | |
| 2500 | + | |
| 2501 | + return priv->info->phy_read(ds, port, regnum); | |
| 2502 | +} | |
| 2503 | + | |
| 2504 | +static int | |
| 2505 | +mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) | |
| 2506 | +{ | |
| 2507 | + struct mt7530_priv *priv = ds->priv; | |
| 2508 | + | |
| 2509 | + return priv->info->phy_write(ds, port, regnum, val); | |
| 2510 | +} | |
| 2511 | + | |
| 1561 | 2512 | static const struct dsa_switch_ops mt7530_switch_ops = { |
| 1562 | 2513 | .get_tag_protocol = mtk_get_tag_protocol, |
| 1563 | − .setup = mt7530_setup, | |
| 2514 | + .setup = mt753x_setup, | |
| 1564 | 2515 | .get_strings = mt7530_get_strings, |
| 1565 | − .phy_read = mt7530_phy_read, | |
| 1566 | − .phy_write = mt7530_phy_write, | |
| 2516 | + .phy_read = mt753x_phy_read, | |
| 2517 | + .phy_write = mt753x_phy_write, | |
| 1567 | 2518 | .get_ethtool_stats = mt7530_get_ethtool_stats, |
| 1568 | 2519 | .get_sset_count = mt7530_get_sset_count, |
| 1569 | 2520 | .port_enable = mt7530_port_enable, |
| @@ -1578,18 +2529,59 @@ static const struct dsa_switch_ops mt7530_switch_ops = { · 8 unmodified lines | ||
| 1578 | 2529 | .port_vlan_prepare = mt7530_port_vlan_prepare, |
| 1579 | 2530 | .port_vlan_add = mt7530_port_vlan_add, |
| 1580 | 2531 | .port_vlan_del = mt7530_port_vlan_del, |
| 1581 | − .port_mirror_add = mt7530_port_mirror_add, | |
| 1582 | − .port_mirror_del = mt7530_port_mirror_del, | |
| 1583 | − .phylink_validate = mt7530_phylink_validate, | |
| 1584 | − .phylink_mac_link_state = mt7530_phylink_mac_link_state, | |
| 1585 | − .phylink_mac_config = mt7530_phylink_mac_config, | |
| 1586 | − .phylink_mac_link_down = mt7530_phylink_mac_link_down, | |
| 1587 | − .phylink_mac_link_up = mt7530_phylink_mac_link_up, | |
| 2532 | + .port_mirror_add = mt753x_port_mirror_add, | |
| 2533 | + .port_mirror_del = mt753x_port_mirror_del, | |
| 2534 | + .phylink_validate = mt753x_phylink_validate, | |
| 2535 | + .phylink_mac_link_state = mt753x_phylink_mac_link_state, | |
| 2536 | + .phylink_mac_config = mt753x_phylink_mac_config, | |
| 2537 | + .phylink_mac_an_restart = mt753x_phylink_mac_an_restart, | |
| 2538 | + .phylink_mac_link_down = mt753x_phylink_mac_link_down, | |
| 2539 | + .phylink_mac_link_up = mt753x_phylink_mac_link_up, | |
| 2540 | +}; | |
| 2541 | + | |
| 2542 | +static const struct mt753x_info mt753x_table[] = { | |
| 2543 | + [ID_MT7621] = { | |
| 2544 | + .id = ID_MT7621, | |
| 2545 | + .sw_setup = mt7530_setup, | |
| 2546 | + .phy_read = mt7530_phy_read, | |
| 2547 | + .phy_write = mt7530_phy_write, | |
| 2548 | + .pad_setup = mt7530_pad_clk_setup, | |
| 2549 | + .phy_mode_supported = mt7530_phy_mode_supported, | |
| 2550 | + .mac_port_validate = mt7530_mac_port_validate, | |
| 2551 | + .mac_port_get_state = mt7530_phylink_mac_link_state, | |
| 2552 | + .mac_port_config = mt7530_mac_config, | |
| 2553 | + }, | |
| 2554 | + [ID_MT7530] = { | |
| 2555 | + .id = ID_MT7530, | |
| 2556 | + .sw_setup = mt7530_setup, | |
| 2557 | + .phy_read = mt7530_phy_read, | |
| 2558 | + .phy_write = mt7530_phy_write, | |
| 2559 | + .pad_setup = mt7530_pad_clk_setup, | |
| 2560 | + .phy_mode_supported = mt7530_phy_mode_supported, | |
| 2561 | + .mac_port_validate = mt7530_mac_port_validate, | |
| 2562 | + .mac_port_get_state = mt7530_phylink_mac_link_state, | |
| 2563 | + .mac_port_config = mt7530_mac_config, | |
| 2564 | + }, | |
| 2565 | + [ID_MT7531] = { | |
| 2566 | + .id = ID_MT7531, | |
| 2567 | + .sw_setup = mt7531_setup, | |
| 2568 | + .phy_read = mt7531_ind_phy_read, | |
| 2569 | + .phy_write = mt7531_ind_phy_write, | |
| 2570 | + .pad_setup = mt7531_pad_setup, | |
| 2571 | + .cpu_port_config = mt7531_cpu_port_config, | |
| 2572 | + .phy_mode_supported = mt7531_phy_mode_supported, | |
| 2573 | + .mac_port_validate = mt7531_mac_port_validate, | |
| 2574 | + .mac_port_get_state = mt7531_phylink_mac_link_state, | |
| 2575 | + .mac_port_config = mt7531_mac_config, | |
| 2576 | + .mac_pcs_an_restart = mt7531_sgmii_restart_an, | |
| 2577 | + .mac_pcs_link_up = mt7531_sgmii_link_up_force, | |
| 2578 | + }, | |
| 1588 | 2579 | }; |
| 1589 | 2580 | |
| 1590 | 2581 | static const struct of_device_id mt7530_of_match[] = { |
| 1591 | − { .compatible = "mediatek,mt7621", .data = (void *)ID_MT7621, }, | |
| 1592 | − { .compatible = "mediatek,mt7530", .data = (void *)ID_MT7530, }, | |
| 2582 | + { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], }, | |
| 2583 | + { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], }, | |
| 2584 | + { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], }, | |
| 1593 | 2585 | { /* sentinel */ }, |
| 1594 | 2586 | }; |
| 1595 | 2587 | MODULE_DEVICE_TABLE(of, mt7530_of_match); |
| @@ -1630,8 +2622,21 @@ mt7530_probe(struct mdio_device *mdiodev) · 34 unmodified lines | ||
| 1630 | 2622 | /* Get the hardware identifier from the devicetree node. |
| 1631 | 2623 | * We will need it for some of the clock and regulator setup. |
| 1632 | 2624 | */ |
| 1633 | − priv->id = (unsigned int)(unsigned long) | |
| 1634 | − of_device_get_match_data(&mdiodev->dev); | |
| 2625 | + priv->info = of_device_get_match_data(&mdiodev->dev); | |
| 2626 | + if (!priv->info) | |
| 2627 | + return -EINVAL; | |
| 2628 | + | |
| 2629 | + /* Sanity check if these required device operations are filled | |
| 2630 | + * properly. | |
| 2631 | + */ | |
| 2632 | + if (!priv->info->sw_setup || !priv->info->pad_setup || | |
| 2633 | + !priv->info->phy_read || !priv->info->phy_write || | |
| 2634 | + !priv->info->phy_mode_supported || | |
| 2635 | + !priv->info->mac_port_validate || | |
| 2636 | + !priv->info->mac_port_get_state || !priv->info->mac_port_config) | |
| 2637 | + return -EINVAL; | |
| 2638 | + | |
| 2639 | + priv->id = priv->info->id; | |
| 1635 | 2640 | |
| 1636 | 2641 | if (priv->id == ID_MT7530) { |
| 1637 | 2642 | priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); |
| @@ -11,9 +11,10 @@ · 10 unmodified lines | ||
| 11 | 11 | #define MT7530_NUM_FDB_RECORDS 2048 |
| 12 | 12 | #define MT7530_ALL_MEMBERS 0xff |
| 13 | 13 | |
| 14 | −enum { | |
| 14 | +enum mt753x_id { | |
| 15 | 15 | ID_MT7530 = 0, |
| 16 | 16 | ID_MT7621 = 1, |
| 17 | + ID_MT7531 = 2, | |
| 17 | 18 | }; |
| 18 | 19 | |
| 19 | 20 | #define NUM_TRGMII_CTRL 5 |
| @@ -41,6 +42,33 @@ enum { · 21 unmodified lines | ||
| 41 | 42 | #define MIRROR_PORT(x) ((x) & 0x7) |
| 42 | 43 | #define MIRROR_MASK 0x7 |
| 43 | 44 | |
| 45 | +/* Registers for CPU forward control */ | |
| 46 | +#define MT7531_CFC 0x4 | |
| 47 | +#define MT7531_MIRROR_EN BIT(19) | |
| 48 | +#define MT7531_MIRROR_MASK (MIRROR_MASK << 16) | |
| 49 | +#define MT7531_MIRROR_PORT_GET(x) (((x) >> 16) & MIRROR_MASK) | |
| 50 | +#define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16) | |
| 51 | +#define MT7531_CPU_PMAP_MASK GENMASK(7, 0) | |
| 52 | + | |
| 53 | +#define MT753X_MIRROR_REG(id) (((id) == ID_MT7531) ? \ | |
| 54 | + MT7531_CFC : MT7530_MFC) | |
| 55 | +#define MT753X_MIRROR_EN(id) (((id) == ID_MT7531) ? \ | |
| 56 | + MT7531_MIRROR_EN : MIRROR_EN) | |
| 57 | +#define MT753X_MIRROR_MASK(id) (((id) == ID_MT7531) ? \ | |
| 58 | + MT7531_MIRROR_MASK : MIRROR_MASK) | |
| 59 | + | |
| 60 | +/* Registers for BPDU and PAE frame control*/ | |
| 61 | +#define MT753X_BPC 0x24 | |
| 62 | +#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0) | |
| 63 | + | |
| 64 | +enum mt753x_bpdu_port_fw { | |
| 65 | + MT753X_BPDU_FOLLOW_MFC, | |
| 66 | + MT753X_BPDU_CPU_EXCLUDE = 4, | |
| 67 | + MT753X_BPDU_CPU_INCLUDE = 5, | |
| 68 | + MT753X_BPDU_CPU_ONLY = 6, | |
| 69 | + MT753X_BPDU_DROP = 7, | |
| 70 | +}; | |
| 71 | + | |
| 44 | 72 | /* Registers for address table access */ |
| 45 | 73 | #define MT7530_ATA1 0x74 |
| 46 | 74 | #define STATIC_EMP 0 |
| @@ -220,10 +248,30 @@ enum mt7530_vlan_port_attr { · 173 unmodified lines | ||
| 220 | 248 | #define PMCR_FORCE_LNK BIT(0) |
| 221 | 249 | #define PMCR_SPEED_MASK (PMCR_FORCE_SPEED_100 | \ |
| 222 | 250 | PMCR_FORCE_SPEED_1000) |
| 251 | +#define MT7531_FORCE_LNK BIT(31) | |
| 252 | +#define MT7531_FORCE_SPD BIT(30) | |
| 253 | +#define MT7531_FORCE_DPX BIT(29) | |
| 254 | +#define MT7531_FORCE_RX_FC BIT(28) | |
| 255 | +#define MT7531_FORCE_TX_FC BIT(27) | |
| 256 | +#define MT7531_FORCE_MODE (MT7531_FORCE_LNK | \ | |
| 257 | + MT7531_FORCE_SPD | \ | |
| 258 | + MT7531_FORCE_DPX | \ | |
| 259 | + MT7531_FORCE_RX_FC | \ | |
| 260 | + MT7531_FORCE_TX_FC) | |
| 261 | +#define PMCR_FORCE_MODE_ID(id) (((id) == ID_MT7531) ? \ | |
| 262 | + MT7531_FORCE_MODE : \ | |
| 263 | + PMCR_FORCE_MODE) | |
| 223 | 264 | #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \ |
| 224 | 265 | PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \ |
| 225 | 266 | PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ |
| 226 | 267 | PMCR_FORCE_FDX | PMCR_FORCE_LNK) |
| 268 | +#define PMCR_CPU_PORT_SETTING(id) (PMCR_FORCE_MODE_ID((id)) | \ | |
| 269 | + PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ | |
| 270 | + PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \ | |
| 271 | + PMCR_TX_EN | PMCR_RX_EN | \ | |
| 272 | + PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ | |
| 273 | + PMCR_FORCE_SPEED_1000 | \ | |
| 274 | + PMCR_FORCE_FDX | PMCR_FORCE_LNK) | |
| 227 | 275 | |
| 228 | 276 | #define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100) |
| 229 | 277 | #define PMSR_EEE1G BIT(7) |
| @@ -237,6 +285,10 @@ enum mt7530_vlan_port_attr { · 7 unmodified lines | ||
| 237 | 285 | #define PMSR_DPX BIT(1) |
| 238 | 286 | #define PMSR_LINK BIT(0) |
| 239 | 287 | |
| 288 | +/* Register for port debug count */ | |
| 289 | +#define MT7531_DBG_CNT(x) (0x3018 + (x) * 0x100) | |
| 290 | +#define MT7531_DIS_CLR BIT(31) | |
| 291 | + | |
| 240 | 292 | /* Register for MIB */ |
| 241 | 293 | #define MT7530_PORT_MIB_COUNTER(x) (0x4000 + (x) * 0x100) |
| 242 | 294 | #define MT7530_MIB_CCR 0x4fe0 |
| @@ -254,12 +306,118 @@ enum mt7530_vlan_port_attr { · 11 unmodified lines | ||
| 254 | 306 | CCR_RX_OCT_CNT_BAD | \ |
| 255 | 307 | CCR_TX_OCT_CNT_GOOD | \ |
| 256 | 308 | CCR_TX_OCT_CNT_BAD) |
| 309 | + | |
| 310 | +/* MT7531 SGMII register group */ | |
| 311 | +#define MT7531_SGMII_REG_BASE 0x5000 | |
| 312 | +#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ | |
| 313 | + ((p) - 5) * 0x1000 + (r)) | |
| 314 | + | |
| 315 | +/* Register forSGMII PCS_CONTROL_1 */ | |
| 316 | +#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00) | |
| 317 | +#define MT7531_SGMII_LINK_STATUS BIT(18) | |
| 318 | +#define MT7531_SGMII_AN_ENABLE BIT(12) | |
| 319 | +#define MT7531_SGMII_AN_RESTART BIT(9) | |
| 320 | + | |
| 321 | +/* Register for SGMII PCS_SPPED_ABILITY */ | |
| 322 | +#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) | |
| 323 | +#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0) | |
| 324 | +#define MT7531_SGMII_TX_CONFIG BIT(0) | |
| 325 | + | |
| 326 | +/* Register for SGMII_MODE */ | |
| 327 | +#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20) | |
| 328 | +#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8) | |
| 329 | +#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1) | |
| 330 | +#define MT7531_SGMII_FORCE_DUPLEX BIT(4) | |
| 331 | +#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2) | |
| 332 | +#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3) | |
| 333 | +#define MT7531_SGMII_FORCE_SPEED_100 BIT(2) | |
| 334 | +#define MT7531_SGMII_FORCE_SPEED_10 0 | |
| 335 | +#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1) | |
| 336 | + | |
| 337 | +enum mt7531_sgmii_force_duplex { | |
| 338 | + MT7531_SGMII_FORCE_FULL_DUPLEX = 0, | |
| 339 | + MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10, | |
| 340 | +}; | |
| 341 | + | |
| 342 | +/* Fields of QPHY_PWR_STATE_CTRL */ | |
| 343 | +#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8) | |
| 344 | +#define MT7531_SGMII_PHYA_PWD BIT(4) | |
| 345 | + | |
| 346 | +/* Values of SGMII SPEED */ | |
| 347 | +#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128) | |
| 348 | +#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3)) | |
| 349 | +#define MT7531_RG_TPHY_SPEED_1_25G 0x0 | |
| 350 | +#define MT7531_RG_TPHY_SPEED_3_125G BIT(2) | |
| 351 | + | |
| 257 | 352 | /* Register for system reset */ |
| 258 | 353 | #define MT7530_SYS_CTRL 0x7000 |
| 259 | 354 | #define SYS_CTRL_PHY_RST BIT(2) |
| 260 | 355 | #define SYS_CTRL_SW_RST BIT(1) |
| 261 | 356 | #define SYS_CTRL_REG_RST BIT(0) |
| 262 | 357 | |
| 358 | +/* Register for PHY Indirect Access Control */ | |
| 359 | +#define MT7531_PHY_IAC 0x701C | |
| 360 | +#define MT7531_PHY_ACS_ST BIT(31) | |
| 361 | +#define MT7531_MDIO_REG_ADDR_MASK (0x1f << 25) | |
| 362 | +#define MT7531_MDIO_PHY_ADDR_MASK (0x1f << 20) | |
| 363 | +#define MT7531_MDIO_CMD_MASK (0x3 << 18) | |
| 364 | +#define MT7531_MDIO_ST_MASK (0x3 << 16) | |
| 365 | +#define MT7531_MDIO_RW_DATA_MASK (0xffff) | |
| 366 | +#define MT7531_MDIO_REG_ADDR(x) (((x) & 0x1f) << 25) | |
| 367 | +#define MT7531_MDIO_DEV_ADDR(x) (((x) & 0x1f) << 25) | |
| 368 | +#define MT7531_MDIO_PHY_ADDR(x) (((x) & 0x1f) << 20) | |
| 369 | +#define MT7531_MDIO_CMD(x) (((x) & 0x3) << 18) | |
| 370 | +#define MT7531_MDIO_ST(x) (((x) & 0x3) << 16) | |
| 371 | + | |
| 372 | +enum mt7531_phy_iac_cmd { | |
| 373 | + MT7531_MDIO_ADDR = 0, | |
| 374 | + MT7531_MDIO_WRITE = 1, | |
| 375 | + MT7531_MDIO_READ = 2, | |
| 376 | + MT7531_MDIO_READ_CL45 = 3, | |
| 377 | +}; | |
| 378 | + | |
| 379 | +/* MDIO_ST: MDIO start field */ | |
| 380 | +enum mt7531_mdio_st { | |
| 381 | + MT7531_MDIO_ST_CL45 = 0, | |
| 382 | + MT7531_MDIO_ST_CL22 = 1, | |
| 383 | +}; | |
| 384 | + | |
| 385 | +#define MT7531_MDIO_CL22_READ (MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \ | |
| 386 | + MT7531_MDIO_CMD(MT7531_MDIO_READ)) | |
| 387 | +#define MT7531_MDIO_CL22_WRITE (MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \ | |
| 388 | + MT7531_MDIO_CMD(MT7531_MDIO_WRITE)) | |
| 389 | +#define MT7531_MDIO_CL45_ADDR (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \ | |
| 390 | + MT7531_MDIO_CMD(MT7531_MDIO_ADDR)) | |
| 391 | +#define MT7531_MDIO_CL45_READ (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \ | |
| 392 | + MT7531_MDIO_CMD(MT7531_MDIO_READ)) | |
| 393 | +#define MT7531_MDIO_CL45_WRITE (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \ | |
| 394 | + MT7531_MDIO_CMD(MT7531_MDIO_WRITE)) | |
| 395 | + | |
| 396 | +/* Register for RGMII clock phase */ | |
| 397 | +#define MT7531_CLKGEN_CTRL 0x7500 | |
| 398 | +#define CLK_SKEW_OUT(x) (((x) & 0x3) << 8) | |
| 399 | +#define CLK_SKEW_OUT_MASK GENMASK(9, 8) | |
| 400 | +#define CLK_SKEW_IN(x) (((x) & 0x3) << 6) | |
| 401 | +#define CLK_SKEW_IN_MASK GENMASK(7, 6) | |
| 402 | +#define RXCLK_NO_DELAY BIT(5) | |
| 403 | +#define TXCLK_NO_REVERSE BIT(4) | |
| 404 | +#define GP_MODE(x) (((x) & 0x3) << 1) | |
| 405 | +#define GP_MODE_MASK GENMASK(2, 1) | |
| 406 | +#define GP_CLK_EN BIT(0) | |
| 407 | + | |
| 408 | +enum mt7531_gp_mode { | |
| 409 | + MT7531_GP_MODE_RGMII = 0, | |
| 410 | + MT7531_GP_MODE_MII = 1, | |
| 411 | + MT7531_GP_MODE_REV_MII = 2 | |
| 412 | +}; | |
| 413 | + | |
| 414 | +enum mt7531_clk_skew { | |
| 415 | + MT7531_CLK_SKEW_NO_CHG = 0, | |
| 416 | + MT7531_CLK_SKEW_DLY_100PPS = 1, | |
| 417 | + MT7531_CLK_SKEW_DLY_200PPS = 2, | |
| 418 | + MT7531_CLK_SKEW_REVERSE = 3, | |
| 419 | +}; | |
| 420 | + | |
| 263 | 421 | /* Register for hw trap status */ |
| 264 | 422 | #define MT7530_HWTRAP 0x7800 |
| 265 | 423 | #define HWTRAP_XTAL_MASK (BIT(10) | BIT(9)) |
| @@ -267,6 +425,16 @@ enum mt7530_vlan_port_attr { · 1 unmodified line | ||
| 267 | 425 | #define HWTRAP_XTAL_40MHZ (BIT(10)) |
| 268 | 426 | #define HWTRAP_XTAL_20MHZ (BIT(9)) |
| 269 | 427 | |
| 428 | +#define MT7531_HWTRAP 0x7800 | |
| 429 | +#define HWTRAP_XTAL_FSEL_MASK BIT(7) | |
| 430 | +#define HWTRAP_XTAL_FSEL_25MHZ BIT(7) | |
| 431 | +#define HWTRAP_XTAL_FSEL_40MHZ 0 | |
| 432 | +/* Unique fields of (M)HWSTRAP for MT7531 */ | |
| 433 | +#define XTAL_FSEL_S 7 | |
| 434 | +#define XTAL_FSEL_M BIT(7) | |
| 435 | +#define PHY_EN BIT(6) | |
| 436 | +#define CHG_STRAP BIT(8) | |
| 437 | + | |
| 270 | 438 | /* Register for hw trap modification */ |
| 271 | 439 | #define MT7530_MHWTRAP 0x7804 |
| 272 | 440 | #define MHWTRAP_PHY0_SEL BIT(20) |
| @@ -281,14 +449,37 @@ enum mt7530_vlan_port_attr { · 8 unmodified lines | ||
| 281 | 449 | #define MT7530_TOP_SIG_CTRL 0x7808 |
| 282 | 450 | #define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) |
| 283 | 451 | |
| 452 | +#define MT7531_TOP_SIG_SR 0x780c | |
| 453 | +#define PAD_DUAL_SGMII_EN BIT(1) | |
| 454 | +#define PAD_MCM_SMI_EN BIT(0) | |
| 455 | + | |
| 284 | 456 | #define MT7530_IO_DRV_CR 0x7810 |
| 285 | 457 | #define P5_IO_CLK_DRV(x) ((x) & 0x3) |
| 286 | 458 | #define P5_IO_DATA_DRV(x) (((x) & 0x3) << 4) |
| 287 | 459 | |
| 460 | +#define MT7531_CHIP_REV 0x781C | |
| 461 | + | |
| 462 | +#define MT7531_PLLGP_EN 0x7820 | |
| 463 | +#define EN_COREPLL BIT(2) | |
| 464 | +#define SW_CLKSW BIT(1) | |
| 465 | +#define SW_PLLGP BIT(0) | |
| 466 | + | |
| 288 | 467 | #define MT7530_P6ECR 0x7830 |
| 289 | 468 | #define P6_INTF_MODE_MASK 0x3 |
| 290 | 469 | #define P6_INTF_MODE(x) ((x) & 0x3) |
| 291 | 470 | |
| 471 | +#define MT7531_PLLGP_CR0 0x78a8 | |
| 472 | +#define RG_COREPLL_EN BIT(22) | |
| 473 | +#define RG_COREPLL_POSDIV_S 23 | |
| 474 | +#define RG_COREPLL_POSDIV_M 0x3800000 | |
| 475 | +#define RG_COREPLL_SDM_PCW_S 1 | |
| 476 | +#define RG_COREPLL_SDM_PCW_M 0x3ffffe | |
| 477 | +#define RG_COREPLL_SDM_PCW_CHG BIT(0) | |
| 478 | + | |
| 479 | +/* Registers for RGMII and SGMII PLL clock */ | |
| 480 | +#define MT7531_ANA_PLLGP_CR2 0x78b0 | |
| 481 | +#define MT7531_ANA_PLLGP_CR5 0x78bc | |
| 482 | + | |
| 292 | 483 | /* Registers for TRGMII on the both side */ |
| 293 | 484 | #define MT7530_TRGMII_RCK_CTRL 0x7a00 |
| 294 | 485 | #define RX_RST BIT(31) |
| @@ -327,10 +518,25 @@ enum mt7530_vlan_port_attr { · 32 unmodified lines | ||
| 327 | 518 | #define MT7530_P5RGMIITXCR 0x7b04 |
| 328 | 519 | #define CSR_RGMII_TXC_CFG(x) ((x) & 0x1f) |
| 329 | 520 | |
| 521 | +/* Registers for GPIO mode */ | |
| 522 | +#define MT7531_GPIO_MODE0 0x7c0c | |
| 523 | +#define MT7531_GPIO0_MASK GENMASK(3, 0) | |
| 524 | +#define MT7531_GPIO0_INTERRUPT 1 | |
| 525 | + | |
| 526 | +#define MT7531_GPIO_MODE1 0x7c10 | |
| 527 | +#define MT7531_GPIO11_RG_RXD2_MASK GENMASK(15, 12) | |
| 528 | +#define MT7531_EXT_P_MDC_11 (2 << 12) | |
| 529 | +#define MT7531_GPIO12_RG_RXD3_MASK GENMASK(19, 16) | |
| 530 | +#define MT7531_EXT_P_MDIO_12 (2 << 16) | |
| 531 | + | |
| 330 | 532 | #define MT7530_CREV 0x7ffc |
| 331 | 533 | #define CHIP_NAME_SHIFT 16 |
| 332 | 534 | #define MT7530_ID 0x7530 |
| 333 | 535 | |
| 536 | +#define MT7531_CREV 0x781C | |
| 537 | +#define CHIP_REV_M 0x0f | |
| 538 | +#define MT7531_ID 0x7531 | |
| 539 | + | |
| 334 | 540 | /* Registers for core PLL access through mmd indirect */ |
| 335 | 541 | #define CORE_PLL_GROUP2 0x401 |
| 336 | 542 | #define RG_SYSPLL_EN_NORMAL BIT(15) |
| @@ -347,6 +553,10 @@ enum mt7530_vlan_port_attr { · 10 unmodified lines | ||
| 347 | 553 | #define RG_SYSPLL_DDSFBK_EN BIT(12) |
| 348 | 554 | #define RG_SYSPLL_BIAS_EN BIT(11) |
| 349 | 555 | #define RG_SYSPLL_BIAS_LPF_EN BIT(10) |
| 556 | +#define MT7531_PHY_PLL_OFF BIT(5) | |
| 557 | +#define MT7531_PHY_PLL_BYPASS_MODE BIT(4) | |
| 558 | + | |
| 559 | +#define MT753X_CTRL_PHY_ADDR 0 | |
| 350 | 560 | |
| 351 | 561 | #define CORE_PLL_GROUP5 0x404 |
| 352 | 562 | #define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff) |
| @@ -425,6 +635,7 @@ enum p5_interface_select { · 72 unmodified lines | ||
| 425 | 635 | P5_INTF_SEL_PHY_P0, |
| 426 | 636 | P5_INTF_SEL_PHY_P4, |
| 427 | 637 | P5_INTF_SEL_GMAC5, |
| 638 | + P5_INTF_SEL_GMAC5_SGMII, | |
| 428 | 639 | }; |
| 429 | 640 | |
| 430 | 641 | static const char *p5_intf_modes(unsigned int p5_interface) |
| @@ -438,11 +649,56 @@ static const char *p5_intf_modes(unsigned int p5_interface) · 7 unmodified lines | ||
| 438 | 649 | return "PHY P4"; |
| 439 | 650 | case P5_INTF_SEL_GMAC5: |
| 440 | 651 | return "GMAC5"; |
| 652 | + case P5_INTF_SEL_GMAC5_SGMII: | |
| 653 | + return "GMAC5_SGMII"; | |
| 441 | 654 | default: |
| 442 | 655 | return "unknown"; |
| 443 | 656 | } |
| 444 | 657 | } |
| 445 | 658 | |
| 659 | +/* struct mt753x_info - This is the main data structure for holding the specific | |
| 660 | + * part for each supported device | |
| 661 | + * @sw_setup: Holding the handler to a device initialization | |
| 662 | + * @phy_read: Holding the way reading PHY port | |
| 663 | + * @phy_write: Holding the way writing PHY port | |
| 664 | + * @pad_setup: Holding the way setting up the bus pad for a certain | |
| 665 | + * MAC port | |
| 666 | + * @phy_mode_supported: Check if the PHY type is being supported on a certain | |
| 667 | + * port | |
| 668 | + * @mac_port_validate: Holding the way to set addition validate type for a | |
| 669 | + * certan MAC port | |
| 670 | + * @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain | |
| 671 | + * MAC port | |
| 672 | + * @mac_port_config: Holding the way setting up the PHY attribute to a | |
| 673 | + * certain MAC port | |
| 674 | + * @mac_pcs_an_restart Holding the way restarting PCS autonegotiation for a | |
| 675 | + * certain MAC port | |
| 676 | + * @mac_pcs_link_up: Holding the way setting up the PHY attribute to the pcs | |
| 677 | + * of the certain MAC port | |
| 678 | + */ | |
| 679 | +struct mt753x_info { | |
| 680 | + enum mt753x_id id; | |
| 681 | + | |
| 682 | + int (*sw_setup)(struct dsa_switch *ds); | |
| 683 | + int (*phy_read)(struct dsa_switch *ds, int port, int regnum); | |
| 684 | + int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val); | |
| 685 | + int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface); | |
| 686 | + int (*cpu_port_config)(struct dsa_switch *ds, int port); | |
| 687 | + bool (*phy_mode_supported)(struct dsa_switch *ds, int port, | |
| 688 | + const struct phylink_link_state *state); | |
| 689 | + void (*mac_port_validate)(struct dsa_switch *ds, int port, | |
| 690 | + unsigned long *supported); | |
| 691 | + int (*mac_port_get_state)(struct dsa_switch *ds, int port, | |
| 692 | + struct phylink_link_state *state); | |
| 693 | + int (*mac_port_config)(struct dsa_switch *ds, int port, | |
| 694 | + unsigned int mode, | |
| 695 | + phy_interface_t interface); | |
| 696 | + void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port); | |
| 697 | + void (*mac_pcs_link_up)(struct dsa_switch *ds, int port, | |
| 698 | + unsigned int mode, phy_interface_t interface, | |
| 699 | + int speed, int duplex); | |
| 700 | +}; | |
| 701 | + | |
| 446 | 702 | /* struct mt7530_priv - This is the main data structure for holding the state |
| 447 | 703 | * of the driver |
| 448 | 704 | * @dev: The device pointer |
| @@ -468,6 +724,7 @@ struct mt7530_priv { · 19 unmodified lines | ||
| 468 | 724 | struct regulator *core_pwr; |
| 469 | 725 | struct regulator *io_pwr; |
| 470 | 726 | struct gpio_desc *reset; |
| 727 | + const struct mt753x_info *info; | |
| 471 | 728 | unsigned int id; |
| 472 | 729 | bool mcm; |
| 473 | 730 | phy_interface_t p6_interface; |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o |
| 3 | 3 | mv88e6xxx-objs := chip.o |
| 4 | +mv88e6xxx-objs += devlink.o | |
| 4 | 5 | mv88e6xxx-objs += global1.o |
| 5 | 6 | mv88e6xxx-objs += global1_atu.o |
| 6 | 7 | mv88e6xxx-objs += global1_vtu.o |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include <net/dsa.h> |
| 33 | 33 | |
| 34 | 34 | #include "chip.h" |
| 35 | +#include "devlink.h" | |
| 35 | 36 | #include "global1.h" |
| 36 | 37 | #include "global2.h" |
| 37 | 38 | #include "hwtstamp.h" |
| @@ -1465,21 +1466,21 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, · 1427 unmodified lines | ||
| 1465 | 1466 | return chip->info->ops->vtu_loadpurge(chip, entry); |
| 1466 | 1467 | } |
| 1467 | 1468 | |
| 1468 | −static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) | |
| 1469 | +int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap) | |
| 1469 | 1470 | { |
| 1470 | − DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); | |
| 1471 | 1471 | struct mv88e6xxx_vtu_entry vlan; |
| 1472 | 1472 | int i, err; |
| 1473 | + u16 fid; | |
| 1473 | 1474 | |
| 1474 | 1475 | bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); |
| 1475 | 1476 | |
| 1476 | 1477 | /* Set every FID bit used by the (un)bridged ports */ |
| 1477 | 1478 | for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { |
| 1478 | − err = mv88e6xxx_port_get_fid(chip, i, fid); | |
| 1479 | + err = mv88e6xxx_port_get_fid(chip, i, &fid); | |
| 1479 | 1480 | if (err) |
| 1480 | 1481 | return err; |
| 1481 | 1482 | |
| 1482 | − set_bit(*fid, fid_bitmap); | |
| 1483 | + set_bit(fid, fid_bitmap); | |
| 1483 | 1484 | } |
| 1484 | 1485 | |
| 1485 | 1486 | /* Set every FID bit used by the VLAN entries */ |
| @@ -1497,6 +1498,18 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) · 11 unmodified lines | ||
| 1497 | 1498 | set_bit(vlan.fid, fid_bitmap); |
| 1498 | 1499 | } while (vlan.vid < chip->info->max_vid); |
| 1499 | 1500 | |
| 1501 | + return 0; | |
| 1502 | +} | |
| 1503 | + | |
| 1504 | +static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) | |
| 1505 | +{ | |
| 1506 | + DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); | |
| 1507 | + int err; | |
| 1508 | + | |
| 1509 | + err = mv88e6xxx_fid_map(chip, fid_bitmap); | |
| 1510 | + if (err) | |
| 1511 | + return err; | |
| 1512 | + | |
| 1500 | 1513 | /* The reset value 0x000 is used to indicate that multiple address |
| 1501 | 1514 | * databases are not needed. Return the next positive available. |
| 1502 | 1515 | */ |
| @@ -1508,22 +1521,6 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) · 5 unmodified lines | ||
| 1508 | 1521 | return mv88e6xxx_g1_atu_flush(chip, *fid, true); |
| 1509 | 1522 | } |
| 1510 | 1523 | |
| 1511 | −static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) | |
| 1512 | −{ | |
| 1513 | − if (chip->info->ops->atu_get_hash) | |
| 1514 | − return chip->info->ops->atu_get_hash(chip, hash); | |
| 1515 | − | |
| 1516 | − return -EOPNOTSUPP; | |
| 1517 | −} | |
| 1518 | − | |
| 1519 | −static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) | |
| 1520 | −{ | |
| 1521 | − if (chip->info->ops->atu_set_hash) | |
| 1522 | − return chip->info->ops->atu_set_hash(chip, hash); | |
| 1523 | − | |
| 1524 | − return -EOPNOTSUPP; | |
| 1525 | −} | |
| 1526 | − | |
| 1527 | 1524 | static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, |
| 1528 | 1525 | u16 vid_begin, u16 vid_end) |
| 1529 | 1526 | { |
| @@ -1581,15 +1578,16 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, · 51 unmodified lines | ||
| 1581 | 1578 | } |
| 1582 | 1579 | |
| 1583 | 1580 | static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, |
| 1584 | − bool vlan_filtering) | |
| 1581 | + bool vlan_filtering, | |
| 1582 | + struct switchdev_trans *trans) | |
| 1585 | 1583 | { |
| 1586 | 1584 | struct mv88e6xxx_chip *chip = ds->priv; |
| 1587 | 1585 | u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : |
| 1588 | 1586 | MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; |
| 1589 | 1587 | int err; |
| 1590 | 1588 | |
| 1591 | − if (!chip->info->max_vid) | |
| 1592 | − return -EOPNOTSUPP; | |
| 1589 | + if (switchdev_trans_ph_prepare(trans)) | |
| 1590 | + return chip->info->max_vid ? 0 : -EOPNOTSUPP; | |
| 1593 | 1591 | |
| 1594 | 1592 | mv88e6xxx_reg_lock(chip); |
| 1595 | 1593 | err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); |
| @@ -2837,248 +2835,11 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) · 1241 unmodified lines | ||
| 2837 | 2835 | return mv88e6xxx_software_reset(chip); |
| 2838 | 2836 | } |
| 2839 | 2837 | |
| 2840 | −enum mv88e6xxx_devlink_param_id { | |
| 2841 | − MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, | |
| 2842 | − MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, | |
| 2843 | −}; | |
| 2844 | − | |
| 2845 | −static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, | |
| 2846 | − struct devlink_param_gset_ctx *ctx) | |
| 2847 | −{ | |
| 2848 | − struct mv88e6xxx_chip *chip = ds->priv; | |
| 2849 | − int err; | |
| 2850 | − | |
| 2851 | − mv88e6xxx_reg_lock(chip); | |
| 2852 | − | |
| 2853 | − switch (id) { | |
| 2854 | − case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: | |
| 2855 | − err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8); | |
| 2856 | − break; | |
| 2857 | − default: | |
| 2858 | − err = -EOPNOTSUPP; | |
| 2859 | − break; | |
| 2860 | − } | |
| 2861 | − | |
| 2862 | − mv88e6xxx_reg_unlock(chip); | |
| 2863 | − | |
| 2864 | − return err; | |
| 2865 | −} | |
| 2866 | − | |
| 2867 | −static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, | |
| 2868 | − struct devlink_param_gset_ctx *ctx) | |
| 2869 | −{ | |
| 2870 | − struct mv88e6xxx_chip *chip = ds->priv; | |
| 2871 | − int err; | |
| 2872 | − | |
| 2873 | − mv88e6xxx_reg_lock(chip); | |
| 2874 | − | |
| 2875 | − switch (id) { | |
| 2876 | − case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: | |
| 2877 | − err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8); | |
| 2878 | − break; | |
| 2879 | − default: | |
| 2880 | − err = -EOPNOTSUPP; | |
| 2881 | − break; | |
| 2882 | − } | |
| 2883 | − | |
| 2884 | − mv88e6xxx_reg_unlock(chip); | |
| 2885 | − | |
| 2886 | − return err; | |
| 2887 | −} | |
| 2888 | − | |
| 2889 | −static const struct devlink_param mv88e6xxx_devlink_params[] = { | |
| 2890 | − DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, | |
| 2891 | − "ATU_hash", DEVLINK_PARAM_TYPE_U8, | |
| 2892 | − BIT(DEVLINK_PARAM_CMODE_RUNTIME)), | |
| 2893 | −}; | |
| 2894 | − | |
| 2895 | −static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds) | |
| 2896 | −{ | |
| 2897 | − return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params, | |
| 2898 | − ARRAY_SIZE(mv88e6xxx_devlink_params)); | |
| 2899 | −} | |
| 2900 | − | |
| 2901 | −static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) | |
| 2902 | −{ | |
| 2903 | − dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params, | |
| 2904 | − ARRAY_SIZE(mv88e6xxx_devlink_params)); | |
| 2905 | −} | |
| 2906 | − | |
| 2907 | −enum mv88e6xxx_devlink_resource_id { | |
| 2908 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 2909 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_0, | |
| 2910 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_1, | |
| 2911 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_2, | |
| 2912 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_3, | |
| 2913 | −}; | |
| 2914 | − | |
| 2915 | −static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip, | |
| 2916 | − u16 bin) | |
| 2917 | −{ | |
| 2918 | − u16 occupancy = 0; | |
| 2919 | − int err; | |
| 2920 | − | |
| 2921 | − mv88e6xxx_reg_lock(chip); | |
| 2922 | − | |
| 2923 | − err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL, | |
| 2924 | − bin); | |
| 2925 | − if (err) { | |
| 2926 | − dev_err(chip->dev, "failed to set ATU stats kind/bin\n"); | |
| 2927 | − goto unlock; | |
| 2928 | − } | |
| 2929 | − | |
| 2930 | − err = mv88e6xxx_g1_atu_get_next(chip, 0); | |
| 2931 | − if (err) { | |
| 2932 | − dev_err(chip->dev, "failed to perform ATU get next\n"); | |
| 2933 | − goto unlock; | |
| 2934 | − } | |
| 2935 | − | |
| 2936 | − err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy); | |
| 2937 | − if (err) { | |
| 2938 | − dev_err(chip->dev, "failed to get ATU stats\n"); | |
| 2939 | − goto unlock; | |
| 2940 | − } | |
| 2941 | − | |
| 2942 | − occupancy &= MV88E6XXX_G2_ATU_STATS_MASK; | |
| 2943 | − | |
| 2944 | −unlock: | |
| 2945 | − mv88e6xxx_reg_unlock(chip); | |
| 2946 | − | |
| 2947 | − return occupancy; | |
| 2948 | −} | |
| 2949 | − | |
| 2950 | −static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv) | |
| 2951 | −{ | |
| 2952 | − struct mv88e6xxx_chip *chip = priv; | |
| 2953 | − | |
| 2954 | − return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 2955 | − MV88E6XXX_G2_ATU_STATS_BIN_0); | |
| 2956 | −} | |
| 2957 | − | |
| 2958 | −static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv) | |
| 2959 | −{ | |
| 2960 | − struct mv88e6xxx_chip *chip = priv; | |
| 2961 | − | |
| 2962 | − return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 2963 | − MV88E6XXX_G2_ATU_STATS_BIN_1); | |
| 2964 | −} | |
| 2965 | − | |
| 2966 | −static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv) | |
| 2967 | −{ | |
| 2968 | − struct mv88e6xxx_chip *chip = priv; | |
| 2969 | − | |
| 2970 | − return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 2971 | − MV88E6XXX_G2_ATU_STATS_BIN_2); | |
| 2972 | −} | |
| 2973 | − | |
| 2974 | −static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv) | |
| 2975 | −{ | |
| 2976 | − struct mv88e6xxx_chip *chip = priv; | |
| 2977 | − | |
| 2978 | − return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 2979 | − MV88E6XXX_G2_ATU_STATS_BIN_3); | |
| 2980 | −} | |
| 2981 | − | |
| 2982 | −static u64 mv88e6xxx_devlink_atu_get(void *priv) | |
| 2983 | −{ | |
| 2984 | − return mv88e6xxx_devlink_atu_bin_0_get(priv) + | |
| 2985 | − mv88e6xxx_devlink_atu_bin_1_get(priv) + | |
| 2986 | − mv88e6xxx_devlink_atu_bin_2_get(priv) + | |
| 2987 | − mv88e6xxx_devlink_atu_bin_3_get(priv); | |
| 2988 | −} | |
| 2989 | − | |
| 2990 | −static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds) | |
| 2991 | −{ | |
| 2992 | − struct devlink_resource_size_params size_params; | |
| 2993 | − struct mv88e6xxx_chip *chip = ds->priv; | |
| 2994 | − int err; | |
| 2995 | − | |
| 2996 | − devlink_resource_size_params_init(&size_params, | |
| 2997 | − mv88e6xxx_num_macs(chip), | |
| 2998 | − mv88e6xxx_num_macs(chip), | |
| 2999 | − 1, DEVLINK_RESOURCE_UNIT_ENTRY); | |
| 3000 | − | |
| 3001 | − err = dsa_devlink_resource_register(ds, "ATU", | |
| 3002 | − mv88e6xxx_num_macs(chip), | |
| 3003 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 3004 | − DEVLINK_RESOURCE_ID_PARENT_TOP, | |
| 3005 | − &size_params); | |
| 3006 | − if (err) | |
| 3007 | − goto out; | |
| 3008 | − | |
| 3009 | − devlink_resource_size_params_init(&size_params, | |
| 3010 | − mv88e6xxx_num_macs(chip) / 4, | |
| 3011 | − mv88e6xxx_num_macs(chip) / 4, | |
| 3012 | − 1, DEVLINK_RESOURCE_UNIT_ENTRY); | |
| 3013 | − | |
| 3014 | − err = dsa_devlink_resource_register(ds, "ATU_bin_0", | |
| 3015 | − mv88e6xxx_num_macs(chip) / 4, | |
| 3016 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_0, | |
| 3017 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 3018 | − &size_params); | |
| 3019 | − if (err) | |
| 3020 | − goto out; | |
| 3021 | − | |
| 3022 | − err = dsa_devlink_resource_register(ds, "ATU_bin_1", | |
| 3023 | − mv88e6xxx_num_macs(chip) / 4, | |
| 3024 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_1, | |
| 3025 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 3026 | − &size_params); | |
| 3027 | − if (err) | |
| 3028 | − goto out; | |
| 3029 | − | |
| 3030 | − err = dsa_devlink_resource_register(ds, "ATU_bin_2", | |
| 3031 | − mv88e6xxx_num_macs(chip) / 4, | |
| 3032 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_2, | |
| 3033 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 3034 | − &size_params); | |
| 3035 | − if (err) | |
| 3036 | − goto out; | |
| 3037 | − | |
| 3038 | − err = dsa_devlink_resource_register(ds, "ATU_bin_3", | |
| 3039 | − mv88e6xxx_num_macs(chip) / 4, | |
| 3040 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_3, | |
| 3041 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 3042 | − &size_params); | |
| 3043 | − if (err) | |
| 3044 | − goto out; | |
| 3045 | − | |
| 3046 | − dsa_devlink_resource_occ_get_register(ds, | |
| 3047 | − MV88E6XXX_RESOURCE_ID_ATU, | |
| 3048 | − mv88e6xxx_devlink_atu_get, | |
| 3049 | − chip); | |
| 3050 | − | |
| 3051 | − dsa_devlink_resource_occ_get_register(ds, | |
| 3052 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_0, | |
| 3053 | − mv88e6xxx_devlink_atu_bin_0_get, | |
| 3054 | − chip); | |
| 3055 | − | |
| 3056 | − dsa_devlink_resource_occ_get_register(ds, | |
| 3057 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_1, | |
| 3058 | − mv88e6xxx_devlink_atu_bin_1_get, | |
| 3059 | − chip); | |
| 3060 | − | |
| 3061 | − dsa_devlink_resource_occ_get_register(ds, | |
| 3062 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_2, | |
| 3063 | − mv88e6xxx_devlink_atu_bin_2_get, | |
| 3064 | − chip); | |
| 3065 | − | |
| 3066 | − dsa_devlink_resource_occ_get_register(ds, | |
| 3067 | − MV88E6XXX_RESOURCE_ID_ATU_BIN_3, | |
| 3068 | − mv88e6xxx_devlink_atu_bin_3_get, | |
| 3069 | − chip); | |
| 3070 | − | |
| 3071 | − return 0; | |
| 3072 | − | |
| 3073 | −out: | |
| 3074 | − dsa_devlink_resources_unregister(ds); | |
| 3075 | − return err; | |
| 3076 | −} | |
| 3077 | − | |
| 3078 | 2838 | static void mv88e6xxx_teardown(struct dsa_switch *ds) |
| 3079 | 2839 | { |
| 3080 | 2840 | mv88e6xxx_teardown_devlink_params(ds); |
| 3081 | 2841 | dsa_devlink_resources_unregister(ds); |
| 2842 | + mv88e6xxx_teardown_devlink_regions(ds); | |
| 3082 | 2843 | } |
| 3083 | 2844 | |
| 3084 | 2845 | static int mv88e6xxx_setup(struct dsa_switch *ds) |
| @@ -3211,7 +2972,18 @@ unlock: · 126 unmodified lines | ||
| 3211 | 2972 | |
| 3212 | 2973 | err = mv88e6xxx_setup_devlink_params(ds); |
| 3213 | 2974 | if (err) |
| 3214 | − dsa_devlink_resources_unregister(ds); | |
| 2975 | + goto out_resources; | |
| 2976 | + | |
| 2977 | + err = mv88e6xxx_setup_devlink_regions(ds); | |
| 2978 | + if (err) | |
| 2979 | + goto out_params; | |
| 2980 | + | |
| 2981 | + return 0; | |
| 2982 | + | |
| 2983 | +out_params: | |
| 2984 | + mv88e6xxx_teardown_devlink_params(ds); | |
| 2985 | +out_resources: | |
| 2986 | + dsa_devlink_resources_unregister(ds); | |
| 3215 | 2987 | |
| 3216 | 2988 | return err; |
| 3217 | 2989 | } |
| @@ -3329,12 +3101,6 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip, · 111 unmodified lines | ||
| 3329 | 3101 | return 0; |
| 3330 | 3102 | } |
| 3331 | 3103 | |
| 3332 | −static const struct of_device_id mv88e6xxx_mdio_external_match[] = { | |
| 3333 | − { .compatible = "marvell,mv88e6xxx-mdio-external", | |
| 3334 | − .data = (void *)true }, | |
| 3335 | − { }, | |
| 3336 | −}; | |
| 3337 | − | |
| 3338 | 3104 | static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) |
| 3339 | 3105 | |
| 3340 | 3106 | { |
| @@ -3354,7 +3120,6 @@ static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip) · 13 unmodified lines | ||
| 3354 | 3120 | static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, |
| 3355 | 3121 | struct device_node *np) |
| 3356 | 3122 | { |
| 3357 | − const struct of_device_id *match; | |
| 3358 | 3123 | struct device_node *child; |
| 3359 | 3124 | int err; |
| 3360 | 3125 | |
| @@ -3372,8 +3137,8 @@ static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip, · 11 unmodified lines | ||
| 3372 | 3137 | * bus. |
| 3373 | 3138 | */ |
| 3374 | 3139 | for_each_available_child_of_node(np, child) { |
| 3375 | − match = of_match_node(mv88e6xxx_mdio_external_match, child); | |
| 3376 | − if (match) { | |
| 3140 | + if (of_device_is_compatible( | |
| 3141 | + child, "marvell,mv88e6xxx-mdio-external")) { | |
| 3377 | 3142 | err = mv88e6xxx_mdio_register(chip, child, true); |
| 3378 | 3143 | if (err) { |
| 3379 | 3144 | mv88e6xxx_mdios_unregister(chip); |
| @@ -5614,6 +5379,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { · 2234 unmodified lines | ||
| 5614 | 5379 | .get_ts_info = mv88e6xxx_get_ts_info, |
| 5615 | 5380 | .devlink_param_get = mv88e6xxx_devlink_param_get, |
| 5616 | 5381 | .devlink_param_set = mv88e6xxx_devlink_param_set, |
| 5382 | + .devlink_info_get = mv88e6xxx_devlink_info_get, | |
| 5617 | 5383 | }; |
| 5618 | 5384 | |
| 5619 | 5385 | static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) |
| @@ -238,6 +238,19 @@ struct mv88e6xxx_port { · 237 unmodified lines | ||
| 238 | 238 | bool mirror_egress; |
| 239 | 239 | unsigned int serdes_irq; |
| 240 | 240 | char serdes_irq_name[64]; |
| 241 | + struct devlink_region *region; | |
| 242 | +}; | |
| 243 | + | |
| 244 | +enum mv88e6xxx_region_id { | |
| 245 | + MV88E6XXX_REGION_GLOBAL1 = 0, | |
| 246 | + MV88E6XXX_REGION_GLOBAL2, | |
| 247 | + MV88E6XXX_REGION_ATU, | |
| 248 | + | |
| 249 | + _MV88E6XXX_REGION_MAX, | |
| 250 | +}; | |
| 251 | + | |
| 252 | +struct mv88e6xxx_region_priv { | |
| 253 | + enum mv88e6xxx_region_id id; | |
| 241 | 254 | }; |
| 242 | 255 | |
| 243 | 256 | struct mv88e6xxx_chip { |
| @@ -334,6 +347,9 @@ struct mv88e6xxx_chip { · 90 unmodified lines | ||
| 334 | 347 | |
| 335 | 348 | /* Array of port structures. */ |
| 336 | 349 | struct mv88e6xxx_port ports[DSA_MAX_PORTS]; |
| 350 | + | |
| 351 | + /* devlink regions */ | |
| 352 | + struct devlink_region *regions[_MV88E6XXX_REGION_MAX]; | |
| 337 | 353 | }; |
| 338 | 354 | |
| 339 | 355 | struct mv88e6xxx_bus_ops { |
| @@ -689,4 +705,6 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip) · 349 unmodified lines | ||
| 689 | 705 | mutex_unlock(&chip->reg_lock); |
| 690 | 706 | } |
| 691 | 707 | |
| 708 | +int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap); | |
| 709 | + | |
| 692 | 710 | #endif /* _MV88E6XXX_CHIP_H */ |
| @@ -0,0 +1,633 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +#include <net/dsa.h> | |
| 3 | + | |
| 4 | +#include "chip.h" | |
| 5 | +#include "devlink.h" | |
| 6 | +#include "global1.h" | |
| 7 | +#include "global2.h" | |
| 8 | +#include "port.h" | |
| 9 | + | |
| 10 | +static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) | |
| 11 | +{ | |
| 12 | + if (chip->info->ops->atu_get_hash) | |
| 13 | + return chip->info->ops->atu_get_hash(chip, hash); | |
| 14 | + | |
| 15 | + return -EOPNOTSUPP; | |
| 16 | +} | |
| 17 | + | |
| 18 | +static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) | |
| 19 | +{ | |
| 20 | + if (chip->info->ops->atu_set_hash) | |
| 21 | + return chip->info->ops->atu_set_hash(chip, hash); | |
| 22 | + | |
| 23 | + return -EOPNOTSUPP; | |
| 24 | +} | |
| 25 | + | |
| 26 | +enum mv88e6xxx_devlink_param_id { | |
| 27 | + MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, | |
| 28 | + MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, | |
| 29 | +}; | |
| 30 | + | |
| 31 | +int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, | |
| 32 | + struct devlink_param_gset_ctx *ctx) | |
| 33 | +{ | |
| 34 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 35 | + int err; | |
| 36 | + | |
| 37 | + mv88e6xxx_reg_lock(chip); | |
| 38 | + | |
| 39 | + switch (id) { | |
| 40 | + case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: | |
| 41 | + err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8); | |
| 42 | + break; | |
| 43 | + default: | |
| 44 | + err = -EOPNOTSUPP; | |
| 45 | + break; | |
| 46 | + } | |
| 47 | + | |
| 48 | + mv88e6xxx_reg_unlock(chip); | |
| 49 | + | |
| 50 | + return err; | |
| 51 | +} | |
| 52 | + | |
| 53 | +int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, | |
| 54 | + struct devlink_param_gset_ctx *ctx) | |
| 55 | +{ | |
| 56 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 57 | + int err; | |
| 58 | + | |
| 59 | + mv88e6xxx_reg_lock(chip); | |
| 60 | + | |
| 61 | + switch (id) { | |
| 62 | + case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: | |
| 63 | + err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8); | |
| 64 | + break; | |
| 65 | + default: | |
| 66 | + err = -EOPNOTSUPP; | |
| 67 | + break; | |
| 68 | + } | |
| 69 | + | |
| 70 | + mv88e6xxx_reg_unlock(chip); | |
| 71 | + | |
| 72 | + return err; | |
| 73 | +} | |
| 74 | + | |
| 75 | +static const struct devlink_param mv88e6xxx_devlink_params[] = { | |
| 76 | + DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, | |
| 77 | + "ATU_hash", DEVLINK_PARAM_TYPE_U8, | |
| 78 | + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), | |
| 79 | +}; | |
| 80 | + | |
| 81 | +int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds) | |
| 82 | +{ | |
| 83 | + return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params, | |
| 84 | + ARRAY_SIZE(mv88e6xxx_devlink_params)); | |
| 85 | +} | |
| 86 | + | |
| 87 | +void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) | |
| 88 | +{ | |
| 89 | + dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params, | |
| 90 | + ARRAY_SIZE(mv88e6xxx_devlink_params)); | |
| 91 | +} | |
| 92 | + | |
| 93 | +enum mv88e6xxx_devlink_resource_id { | |
| 94 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 95 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_0, | |
| 96 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_1, | |
| 97 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_2, | |
| 98 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_3, | |
| 99 | +}; | |
| 100 | + | |
| 101 | +static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip, | |
| 102 | + u16 bin) | |
| 103 | +{ | |
| 104 | + u16 occupancy = 0; | |
| 105 | + int err; | |
| 106 | + | |
| 107 | + mv88e6xxx_reg_lock(chip); | |
| 108 | + | |
| 109 | + err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL, | |
| 110 | + bin); | |
| 111 | + if (err) { | |
| 112 | + dev_err(chip->dev, "failed to set ATU stats kind/bin\n"); | |
| 113 | + goto unlock; | |
| 114 | + } | |
| 115 | + | |
| 116 | + err = mv88e6xxx_g1_atu_get_next(chip, 0); | |
| 117 | + if (err) { | |
| 118 | + dev_err(chip->dev, "failed to perform ATU get next\n"); | |
| 119 | + goto unlock; | |
| 120 | + } | |
| 121 | + | |
| 122 | + err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy); | |
| 123 | + if (err) { | |
| 124 | + dev_err(chip->dev, "failed to get ATU stats\n"); | |
| 125 | + goto unlock; | |
| 126 | + } | |
| 127 | + | |
| 128 | + occupancy &= MV88E6XXX_G2_ATU_STATS_MASK; | |
| 129 | + | |
| 130 | +unlock: | |
| 131 | + mv88e6xxx_reg_unlock(chip); | |
| 132 | + | |
| 133 | + return occupancy; | |
| 134 | +} | |
| 135 | + | |
| 136 | +static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv) | |
| 137 | +{ | |
| 138 | + struct mv88e6xxx_chip *chip = priv; | |
| 139 | + | |
| 140 | + return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 141 | + MV88E6XXX_G2_ATU_STATS_BIN_0); | |
| 142 | +} | |
| 143 | + | |
| 144 | +static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv) | |
| 145 | +{ | |
| 146 | + struct mv88e6xxx_chip *chip = priv; | |
| 147 | + | |
| 148 | + return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 149 | + MV88E6XXX_G2_ATU_STATS_BIN_1); | |
| 150 | +} | |
| 151 | + | |
| 152 | +static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv) | |
| 153 | +{ | |
| 154 | + struct mv88e6xxx_chip *chip = priv; | |
| 155 | + | |
| 156 | + return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 157 | + MV88E6XXX_G2_ATU_STATS_BIN_2); | |
| 158 | +} | |
| 159 | + | |
| 160 | +static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv) | |
| 161 | +{ | |
| 162 | + struct mv88e6xxx_chip *chip = priv; | |
| 163 | + | |
| 164 | + return mv88e6xxx_devlink_atu_bin_get(chip, | |
| 165 | + MV88E6XXX_G2_ATU_STATS_BIN_3); | |
| 166 | +} | |
| 167 | + | |
| 168 | +static u64 mv88e6xxx_devlink_atu_get(void *priv) | |
| 169 | +{ | |
| 170 | + return mv88e6xxx_devlink_atu_bin_0_get(priv) + | |
| 171 | + mv88e6xxx_devlink_atu_bin_1_get(priv) + | |
| 172 | + mv88e6xxx_devlink_atu_bin_2_get(priv) + | |
| 173 | + mv88e6xxx_devlink_atu_bin_3_get(priv); | |
| 174 | +} | |
| 175 | + | |
| 176 | +int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds) | |
| 177 | +{ | |
| 178 | + struct devlink_resource_size_params size_params; | |
| 179 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 180 | + int err; | |
| 181 | + | |
| 182 | + devlink_resource_size_params_init(&size_params, | |
| 183 | + mv88e6xxx_num_macs(chip), | |
| 184 | + mv88e6xxx_num_macs(chip), | |
| 185 | + 1, DEVLINK_RESOURCE_UNIT_ENTRY); | |
| 186 | + | |
| 187 | + err = dsa_devlink_resource_register(ds, "ATU", | |
| 188 | + mv88e6xxx_num_macs(chip), | |
| 189 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 190 | + DEVLINK_RESOURCE_ID_PARENT_TOP, | |
| 191 | + &size_params); | |
| 192 | + if (err) | |
| 193 | + goto out; | |
| 194 | + | |
| 195 | + devlink_resource_size_params_init(&size_params, | |
| 196 | + mv88e6xxx_num_macs(chip) / 4, | |
| 197 | + mv88e6xxx_num_macs(chip) / 4, | |
| 198 | + 1, DEVLINK_RESOURCE_UNIT_ENTRY); | |
| 199 | + | |
| 200 | + err = dsa_devlink_resource_register(ds, "ATU_bin_0", | |
| 201 | + mv88e6xxx_num_macs(chip) / 4, | |
| 202 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_0, | |
| 203 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 204 | + &size_params); | |
| 205 | + if (err) | |
| 206 | + goto out; | |
| 207 | + | |
| 208 | + err = dsa_devlink_resource_register(ds, "ATU_bin_1", | |
| 209 | + mv88e6xxx_num_macs(chip) / 4, | |
| 210 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_1, | |
| 211 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 212 | + &size_params); | |
| 213 | + if (err) | |
| 214 | + goto out; | |
| 215 | + | |
| 216 | + err = dsa_devlink_resource_register(ds, "ATU_bin_2", | |
| 217 | + mv88e6xxx_num_macs(chip) / 4, | |
| 218 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_2, | |
| 219 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 220 | + &size_params); | |
| 221 | + if (err) | |
| 222 | + goto out; | |
| 223 | + | |
| 224 | + err = dsa_devlink_resource_register(ds, "ATU_bin_3", | |
| 225 | + mv88e6xxx_num_macs(chip) / 4, | |
| 226 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_3, | |
| 227 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 228 | + &size_params); | |
| 229 | + if (err) | |
| 230 | + goto out; | |
| 231 | + | |
| 232 | + dsa_devlink_resource_occ_get_register(ds, | |
| 233 | + MV88E6XXX_RESOURCE_ID_ATU, | |
| 234 | + mv88e6xxx_devlink_atu_get, | |
| 235 | + chip); | |
| 236 | + | |
| 237 | + dsa_devlink_resource_occ_get_register(ds, | |
| 238 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_0, | |
| 239 | + mv88e6xxx_devlink_atu_bin_0_get, | |
| 240 | + chip); | |
| 241 | + | |
| 242 | + dsa_devlink_resource_occ_get_register(ds, | |
| 243 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_1, | |
| 244 | + mv88e6xxx_devlink_atu_bin_1_get, | |
| 245 | + chip); | |
| 246 | + | |
| 247 | + dsa_devlink_resource_occ_get_register(ds, | |
| 248 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_2, | |
| 249 | + mv88e6xxx_devlink_atu_bin_2_get, | |
| 250 | + chip); | |
| 251 | + | |
| 252 | + dsa_devlink_resource_occ_get_register(ds, | |
| 253 | + MV88E6XXX_RESOURCE_ID_ATU_BIN_3, | |
| 254 | + mv88e6xxx_devlink_atu_bin_3_get, | |
| 255 | + chip); | |
| 256 | + | |
| 257 | + return 0; | |
| 258 | + | |
| 259 | +out: | |
| 260 | + dsa_devlink_resources_unregister(ds); | |
| 261 | + return err; | |
| 262 | +} | |
| 263 | + | |
| 264 | +static int mv88e6xxx_region_global_snapshot(struct devlink *dl, | |
| 265 | + const struct devlink_region_ops *ops, | |
| 266 | + struct netlink_ext_ack *extack, | |
| 267 | + u8 **data) | |
| 268 | +{ | |
| 269 | + struct mv88e6xxx_region_priv *region_priv = ops->priv; | |
| 270 | + struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
| 271 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 272 | + u16 *registers; | |
| 273 | + int i, err; | |
| 274 | + | |
| 275 | + registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL); | |
| 276 | + if (!registers) | |
| 277 | + return -ENOMEM; | |
| 278 | + | |
| 279 | + mv88e6xxx_reg_lock(chip); | |
| 280 | + for (i = 0; i < 32; i++) { | |
| 281 | + switch (region_priv->id) { | |
| 282 | + case MV88E6XXX_REGION_GLOBAL1: | |
| 283 | + err = mv88e6xxx_g1_read(chip, i, ®isters[i]); | |
| 284 | + break; | |
| 285 | + case MV88E6XXX_REGION_GLOBAL2: | |
| 286 | + err = mv88e6xxx_g2_read(chip, i, ®isters[i]); | |
| 287 | + break; | |
| 288 | + default: | |
| 289 | + err = -EOPNOTSUPP; | |
| 290 | + } | |
| 291 | + | |
| 292 | + if (err) { | |
| 293 | + kfree(registers); | |
| 294 | + goto out; | |
| 295 | + } | |
| 296 | + } | |
| 297 | + *data = (u8 *)registers; | |
| 298 | +out: | |
| 299 | + mv88e6xxx_reg_unlock(chip); | |
| 300 | + | |
| 301 | + return err; | |
| 302 | +} | |
| 303 | + | |
| 304 | +/* The ATU entry varies between mv88e6xxx chipset generations. Define | |
| 305 | + * a generic format which covers all the current and hopefully future | |
| 306 | + * mv88e6xxx generations | |
| 307 | + */ | |
| 308 | + | |
| 309 | +struct mv88e6xxx_devlink_atu_entry { | |
| 310 | + /* The FID is scattered over multiple registers. */ | |
| 311 | + u16 fid; | |
| 312 | + u16 atu_op; | |
| 313 | + u16 atu_data; | |
| 314 | + u16 atu_01; | |
| 315 | + u16 atu_23; | |
| 316 | + u16 atu_45; | |
| 317 | +}; | |
| 318 | + | |
| 319 | +static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip, | |
| 320 | + int fid, | |
| 321 | + struct mv88e6xxx_devlink_atu_entry *table, | |
| 322 | + int *count) | |
| 323 | +{ | |
| 324 | + u16 atu_op, atu_data, atu_01, atu_23, atu_45; | |
| 325 | + struct mv88e6xxx_atu_entry addr; | |
| 326 | + int err; | |
| 327 | + | |
| 328 | + addr.state = 0; | |
| 329 | + eth_broadcast_addr(addr.mac); | |
| 330 | + | |
| 331 | + do { | |
| 332 | + err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); | |
| 333 | + if (err) | |
| 334 | + return err; | |
| 335 | + | |
| 336 | + if (!addr.state) | |
| 337 | + break; | |
| 338 | + | |
| 339 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op); | |
| 340 | + if (err) | |
| 341 | + return err; | |
| 342 | + | |
| 343 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data); | |
| 344 | + if (err) | |
| 345 | + return err; | |
| 346 | + | |
| 347 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01); | |
| 348 | + if (err) | |
| 349 | + return err; | |
| 350 | + | |
| 351 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23); | |
| 352 | + if (err) | |
| 353 | + return err; | |
| 354 | + | |
| 355 | + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45); | |
| 356 | + if (err) | |
| 357 | + return err; | |
| 358 | + | |
| 359 | + table[*count].fid = fid; | |
| 360 | + table[*count].atu_op = atu_op; | |
| 361 | + table[*count].atu_data = atu_data; | |
| 362 | + table[*count].atu_01 = atu_01; | |
| 363 | + table[*count].atu_23 = atu_23; | |
| 364 | + table[*count].atu_45 = atu_45; | |
| 365 | + (*count)++; | |
| 366 | + } while (!is_broadcast_ether_addr(addr.mac)); | |
| 367 | + | |
| 368 | + return 0; | |
| 369 | +} | |
| 370 | + | |
| 371 | +static int mv88e6xxx_region_atu_snapshot(struct devlink *dl, | |
| 372 | + const struct devlink_region_ops *ops, | |
| 373 | + struct netlink_ext_ack *extack, | |
| 374 | + u8 **data) | |
| 375 | +{ | |
| 376 | + struct dsa_switch *ds = dsa_devlink_to_ds(dl); | |
| 377 | + DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); | |
| 378 | + struct mv88e6xxx_devlink_atu_entry *table; | |
| 379 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 380 | + int fid = -1, count, err; | |
| 381 | + | |
| 382 | + table = kmalloc_array(mv88e6xxx_num_databases(chip), | |
| 383 | + sizeof(struct mv88e6xxx_devlink_atu_entry), | |
| 384 | + GFP_KERNEL); | |
| 385 | + if (!table) | |
| 386 | + return -ENOMEM; | |
| 387 | + | |
| 388 | + memset(table, 0, mv88e6xxx_num_databases(chip) * | |
| 389 | + sizeof(struct mv88e6xxx_devlink_atu_entry)); | |
| 390 | + | |
| 391 | + count = 0; | |
| 392 | + | |
| 393 | + mv88e6xxx_reg_lock(chip); | |
| 394 | + | |
| 395 | + err = mv88e6xxx_fid_map(chip, fid_bitmap); | |
| 396 | + if (err) | |
| 397 | + goto out; | |
| 398 | + | |
| 399 | + while (1) { | |
| 400 | + fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1); | |
| 401 | + if (fid == MV88E6XXX_N_FID) | |
| 402 | + break; | |
| 403 | + | |
| 404 | + err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table, | |
| 405 | + &count); | |
| 406 | + if (err) { | |
| 407 | + kfree(table); | |
| 408 | + goto out; | |
| 409 | + } | |
| 410 | + } | |
| 411 | + *data = (u8 *)table; | |
| 412 | +out: | |
| 413 | + mv88e6xxx_reg_unlock(chip); | |
| 414 | + | |
| 415 | + return err; | |
| 416 | +} | |
| 417 | + | |
| 418 | +static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port, | |
| 419 | + const struct devlink_port_region_ops *ops, | |
| 420 | + struct netlink_ext_ack *extack, | |
| 421 | + u8 **data) | |
| 422 | +{ | |
| 423 | + struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port); | |
| 424 | + int port = dsa_devlink_port_to_port(devlink_port); | |
| 425 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 426 | + u16 *registers; | |
| 427 | + int i, err; | |
| 428 | + | |
| 429 | + registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL); | |
| 430 | + if (!registers) | |
| 431 | + return -ENOMEM; | |
| 432 | + | |
| 433 | + mv88e6xxx_reg_lock(chip); | |
| 434 | + for (i = 0; i < 32; i++) { | |
| 435 | + err = mv88e6xxx_port_read(chip, port, i, ®isters[i]); | |
| 436 | + if (err) { | |
| 437 | + kfree(registers); | |
| 438 | + goto out; | |
| 439 | + } | |
| 440 | + } | |
| 441 | + *data = (u8 *)registers; | |
| 442 | +out: | |
| 443 | + mv88e6xxx_reg_unlock(chip); | |
| 444 | + | |
| 445 | + return err; | |
| 446 | +} | |
| 447 | + | |
| 448 | +static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = { | |
| 449 | + .id = MV88E6XXX_REGION_GLOBAL1, | |
| 450 | +}; | |
| 451 | + | |
| 452 | +static struct devlink_region_ops mv88e6xxx_region_global1_ops = { | |
| 453 | + .name = "global1", | |
| 454 | + .snapshot = mv88e6xxx_region_global_snapshot, | |
| 455 | + .destructor = kfree, | |
| 456 | + .priv = &mv88e6xxx_region_global1_priv, | |
| 457 | +}; | |
| 458 | + | |
| 459 | +static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = { | |
| 460 | + .id = MV88E6XXX_REGION_GLOBAL2, | |
| 461 | +}; | |
| 462 | + | |
| 463 | +static struct devlink_region_ops mv88e6xxx_region_global2_ops = { | |
| 464 | + .name = "global2", | |
| 465 | + .snapshot = mv88e6xxx_region_global_snapshot, | |
| 466 | + .destructor = kfree, | |
| 467 | + .priv = &mv88e6xxx_region_global2_priv, | |
| 468 | +}; | |
| 469 | + | |
| 470 | +static struct devlink_region_ops mv88e6xxx_region_atu_ops = { | |
| 471 | + .name = "atu", | |
| 472 | + .snapshot = mv88e6xxx_region_atu_snapshot, | |
| 473 | + .destructor = kfree, | |
| 474 | +}; | |
| 475 | + | |
| 476 | +static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = { | |
| 477 | + .name = "port", | |
| 478 | + .snapshot = mv88e6xxx_region_port_snapshot, | |
| 479 | + .destructor = kfree, | |
| 480 | +}; | |
| 481 | + | |
| 482 | +struct mv88e6xxx_region { | |
| 483 | + struct devlink_region_ops *ops; | |
| 484 | + u64 size; | |
| 485 | +}; | |
| 486 | + | |
| 487 | +static struct mv88e6xxx_region mv88e6xxx_regions[] = { | |
| 488 | + [MV88E6XXX_REGION_GLOBAL1] = { | |
| 489 | + .ops = &mv88e6xxx_region_global1_ops, | |
| 490 | + .size = 32 * sizeof(u16) | |
| 491 | + }, | |
| 492 | + [MV88E6XXX_REGION_GLOBAL2] = { | |
| 493 | + .ops = &mv88e6xxx_region_global2_ops, | |
| 494 | + .size = 32 * sizeof(u16) }, | |
| 495 | + [MV88E6XXX_REGION_ATU] = { | |
| 496 | + .ops = &mv88e6xxx_region_atu_ops | |
| 497 | + /* calculated at runtime */ | |
| 498 | + }, | |
| 499 | +}; | |
| 500 | + | |
| 501 | +static void | |
| 502 | +mv88e6xxx_teardown_devlink_regions_global(struct mv88e6xxx_chip *chip) | |
| 503 | +{ | |
| 504 | + int i; | |
| 505 | + | |
| 506 | + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) | |
| 507 | + dsa_devlink_region_destroy(chip->regions[i]); | |
| 508 | +} | |
| 509 | + | |
| 510 | +static void | |
| 511 | +mv88e6xxx_teardown_devlink_regions_port(struct mv88e6xxx_chip *chip, | |
| 512 | + int port) | |
| 513 | +{ | |
| 514 | + dsa_devlink_region_destroy(chip->ports[port].region); | |
| 515 | +} | |
| 516 | + | |
| 517 | +static int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, | |
| 518 | + struct mv88e6xxx_chip *chip, | |
| 519 | + int port) | |
| 520 | +{ | |
| 521 | + struct devlink_region *region; | |
| 522 | + | |
| 523 | + region = dsa_devlink_port_region_create(ds, | |
| 524 | + port, | |
| 525 | + &mv88e6xxx_region_port_ops, 1, | |
| 526 | + 32 * sizeof(u16)); | |
| 527 | + if (IS_ERR(region)) | |
| 528 | + return PTR_ERR(region); | |
| 529 | + | |
| 530 | + chip->ports[port].region = region; | |
| 531 | + | |
| 532 | + return 0; | |
| 533 | +} | |
| 534 | + | |
| 535 | +static void | |
| 536 | +mv88e6xxx_teardown_devlink_regions_ports(struct mv88e6xxx_chip *chip) | |
| 537 | +{ | |
| 538 | + int port; | |
| 539 | + | |
| 540 | + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) | |
| 541 | + mv88e6xxx_teardown_devlink_regions_port(chip, port); | |
| 542 | +} | |
| 543 | + | |
| 544 | +static int mv88e6xxx_setup_devlink_regions_ports(struct dsa_switch *ds, | |
| 545 | + struct mv88e6xxx_chip *chip) | |
| 546 | +{ | |
| 547 | + int port; | |
| 548 | + int err; | |
| 549 | + | |
| 550 | + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { | |
| 551 | + err = mv88e6xxx_setup_devlink_regions_port(ds, chip, port); | |
| 552 | + if (err) | |
| 553 | + goto out; | |
| 554 | + } | |
| 555 | + | |
| 556 | + return 0; | |
| 557 | + | |
| 558 | +out: | |
| 559 | + while (port-- > 0) | |
| 560 | + mv88e6xxx_teardown_devlink_regions_port(chip, port); | |
| 561 | + | |
| 562 | + return err; | |
| 563 | +} | |
| 564 | + | |
| 565 | +static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds, | |
| 566 | + struct mv88e6xxx_chip *chip) | |
| 567 | +{ | |
| 568 | + struct devlink_region_ops *ops; | |
| 569 | + struct devlink_region *region; | |
| 570 | + u64 size; | |
| 571 | + int i, j; | |
| 572 | + | |
| 573 | + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) { | |
| 574 | + ops = mv88e6xxx_regions[i].ops; | |
| 575 | + size = mv88e6xxx_regions[i].size; | |
| 576 | + | |
| 577 | + if (i == MV88E6XXX_REGION_ATU) | |
| 578 | + size = mv88e6xxx_num_databases(chip) * | |
| 579 | + sizeof(struct mv88e6xxx_devlink_atu_entry); | |
| 580 | + | |
| 581 | + region = dsa_devlink_region_create(ds, ops, 1, size); | |
| 582 | + if (IS_ERR(region)) | |
| 583 | + goto out; | |
| 584 | + chip->regions[i] = region; | |
| 585 | + } | |
| 586 | + return 0; | |
| 587 | + | |
| 588 | +out: | |
| 589 | + for (j = 0; j < i; j++) | |
| 590 | + dsa_devlink_region_destroy(chip->regions[j]); | |
| 591 | + | |
| 592 | + return PTR_ERR(region); | |
| 593 | +} | |
| 594 | + | |
| 595 | +int mv88e6xxx_setup_devlink_regions(struct dsa_switch *ds) | |
| 596 | +{ | |
| 597 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 598 | + int err; | |
| 599 | + | |
| 600 | + err = mv88e6xxx_setup_devlink_regions_global(ds, chip); | |
| 601 | + if (err) | |
| 602 | + return err; | |
| 603 | + | |
| 604 | + err = mv88e6xxx_setup_devlink_regions_ports(ds, chip); | |
| 605 | + if (err) | |
| 606 | + mv88e6xxx_teardown_devlink_regions_global(chip); | |
| 607 | + | |
| 608 | + return err; | |
| 609 | +} | |
| 610 | + | |
| 611 | +void mv88e6xxx_teardown_devlink_regions(struct dsa_switch *ds) | |
| 612 | +{ | |
| 613 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 614 | + | |
| 615 | + mv88e6xxx_teardown_devlink_regions_ports(chip); | |
| 616 | + mv88e6xxx_teardown_devlink_regions_global(chip); | |
| 617 | +} | |
| 618 | + | |
| 619 | +int mv88e6xxx_devlink_info_get(struct dsa_switch *ds, | |
| 620 | + struct devlink_info_req *req, | |
| 621 | + struct netlink_ext_ack *extack) | |
| 622 | +{ | |
| 623 | + struct mv88e6xxx_chip *chip = ds->priv; | |
| 624 | + int err; | |
| 625 | + | |
| 626 | + err = devlink_info_driver_name_put(req, "mv88e6xxx"); | |
| 627 | + if (err) | |
| 628 | + return err; | |
| 629 | + | |
| 630 | + return devlink_info_version_fixed_put(req, | |
| 631 | + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, | |
| 632 | + chip->info->name); | |
| 633 | +} | |
| @@ -0,0 +1,21 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | + | |
| 3 | +/* Marvell 88E6xxx Switch devlink support. */ | |
| 4 | + | |
| 5 | +#ifndef _MV88E6XXX_DEVLINK_H | |
| 6 | +#define _MV88E6XXX_DEVLINK_H | |
| 7 | + | |
| 8 | +int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds); | |
| 9 | +void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds); | |
| 10 | +int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds); | |
| 11 | +int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, | |
| 12 | + struct devlink_param_gset_ctx *ctx); | |
| 13 | +int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, | |
| 14 | + struct devlink_param_gset_ctx *ctx); | |
| 15 | +int mv88e6xxx_setup_devlink_regions(struct dsa_switch *ds); | |
| 16 | +void mv88e6xxx_teardown_devlink_regions(struct dsa_switch *ds); | |
| 17 | + | |
| 18 | +int mv88e6xxx_devlink_info_get(struct dsa_switch *ds, | |
| 19 | + struct devlink_info_req *req, | |
| 20 | + struct netlink_ext_ack *extack); | |
| 21 | +#endif /* _MV88E6XXX_DEVLINK_H */ | |
| @@ -211,49 +211,20 @@ int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port, · 210 unmodified lines | ||
| 211 | 211 | -EFAULT : 0; |
| 212 | 212 | } |
| 213 | 213 | |
| 214 | −/* Get the start of the PTP header in this skb */ | |
| 215 | −static u8 *parse_ptp_header(struct sk_buff *skb, unsigned int type) | |
| 216 | −{ | |
| 217 | − u8 *data = skb_mac_header(skb); | |
| 218 | − unsigned int offset = 0; | |
| 219 | − | |
| 220 | − if (type & PTP_CLASS_VLAN) | |
| 221 | − offset += VLAN_HLEN; | |
| 222 | − | |
| 223 | − switch (type & PTP_CLASS_PMASK) { | |
| 224 | − case PTP_CLASS_IPV4: | |
| 225 | − offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; | |
| 226 | − break; | |
| 227 | − case PTP_CLASS_IPV6: | |
| 228 | − offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; | |
| 229 | − break; | |
| 230 | − case PTP_CLASS_L2: | |
| 231 | − offset += ETH_HLEN; | |
| 232 | − break; | |
| 233 | − default: | |
| 234 | − return NULL; | |
| 235 | − } | |
| 236 | − | |
| 237 | − /* Ensure that the entire header is present in this packet. */ | |
| 238 | − if (skb->len + ETH_HLEN < offset + 34) | |
| 239 | − return NULL; | |
| 240 | − | |
| 241 | − return data + offset; | |
| 242 | −} | |
| 243 | − | |
| 244 | 214 | /* Returns a pointer to the PTP header if the caller should time stamp, |
| 245 | 215 | * or NULL if the caller should not. |
| 246 | 216 | */ |
| 247 | −static u8 *mv88e6xxx_should_tstamp(struct mv88e6xxx_chip *chip, int port, | |
| 248 | − struct sk_buff *skb, unsigned int type) | |
| 217 | +static struct ptp_header *mv88e6xxx_should_tstamp(struct mv88e6xxx_chip *chip, | |
| 218 | + int port, struct sk_buff *skb, | |
| 219 | + unsigned int type) | |
| 249 | 220 | { |
| 250 | 221 | struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port]; |
| 251 | − u8 *hdr; | |
| 222 | + struct ptp_header *hdr; | |
| 252 | 223 | |
| 253 | 224 | if (!chip->info->ptp_support) |
| 254 | 225 | return NULL; |
| 255 | 226 | |
| 256 | − hdr = parse_ptp_header(skb, type); | |
| 227 | + hdr = ptp_parse_header(skb, type); | |
| 257 | 228 | if (!hdr) |
| 258 | 229 | return NULL; |
| 259 | 230 | |
| @@ -275,12 +246,11 @@ static int mv88e6xxx_ts_valid(u16 status) · 15 unmodified lines | ||
| 275 | 246 | static int seq_match(struct sk_buff *skb, u16 ts_seqid) |
| 276 | 247 | { |
| 277 | 248 | unsigned int type = SKB_PTP_TYPE(skb); |
| 278 | − u8 *hdr = parse_ptp_header(skb, type); | |
| 279 | − __be16 *seqid; | |
| 249 | + struct ptp_header *hdr; | |
| 280 | 250 | |
| 281 | − seqid = (__be16 *)(hdr + OFF_PTP_SEQUENCE_ID); | |
| 251 | + hdr = ptp_parse_header(skb, type); | |
| 282 | 252 | |
| 283 | − return ts_seqid == ntohs(*seqid); | |
| 253 | + return ts_seqid == ntohs(hdr->sequence_id); | |
| 284 | 254 | } |
| 285 | 255 | |
| 286 | 256 | static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip, |
| @@ -357,9 +327,9 @@ static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip, · 70 unmodified lines | ||
| 357 | 327 | &ps->rx_queue2); |
| 358 | 328 | } |
| 359 | 329 | |
| 360 | −static int is_pdelay_resp(u8 *msgtype) | |
| 330 | +static int is_pdelay_resp(const struct ptp_header *hdr) | |
| 361 | 331 | { |
| 362 | − return (*msgtype & 0xf) == 3; | |
| 332 | + return (hdr->tsmt & 0xf) == 3; | |
| 363 | 333 | } |
| 364 | 334 | |
| 365 | 335 | bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port, |
| @@ -367,7 +337,7 @@ bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port, · 1 unmodified line | ||
| 367 | 337 | { |
| 368 | 338 | struct mv88e6xxx_port_hwtstamp *ps; |
| 369 | 339 | struct mv88e6xxx_chip *chip; |
| 370 | − u8 *hdr; | |
| 340 | + struct ptp_header *hdr; | |
| 371 | 341 | |
| 372 | 342 | chip = ds->priv; |
| 373 | 343 | ps = &chip->port_hwtstamp[port]; |
| @@ -503,8 +473,7 @@ bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port, · 129 unmodified lines | ||
| 503 | 473 | { |
| 504 | 474 | struct mv88e6xxx_chip *chip = ds->priv; |
| 505 | 475 | struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port]; |
| 506 | − __be16 *seq_ptr; | |
| 507 | − u8 *hdr; | |
| 476 | + struct ptp_header *hdr; | |
| 508 | 477 | |
| 509 | 478 | if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP)) |
| 510 | 479 | return false; |
| @@ -513,15 +482,13 @@ bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port, · 2 unmodified lines | ||
| 513 | 482 | if (!hdr) |
| 514 | 483 | return false; |
| 515 | 484 | |
| 516 | − seq_ptr = (__be16 *)(hdr + OFF_PTP_SEQUENCE_ID); | |
| 517 | − | |
| 518 | 485 | if (test_and_set_bit_lock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, |
| 519 | 486 | &ps->state)) |
| 520 | 487 | return false; |
| 521 | 488 | |
| 522 | 489 | ps->tx_skb = clone; |
| 523 | 490 | ps->tx_tstamp_start = jiffies; |
| 524 | − ps->tx_seq_id = be16_to_cpup(seq_ptr); | |
| 491 | + ps->tx_seq_id = be16_to_cpu(hdr->sequence_id); | |
| 525 | 492 | |
| 526 | 493 | ptp_schedule_worker(chip->ptp_clock, 0); |
| 527 | 494 | return true; |
| @@ -8,12 +8,19 @@ config NET_DSA_MSCC_FELIX · 7 unmodified lines | ||
| 8 | 8 | select MSCC_OCELOT_SWITCH_LIB |
| 9 | 9 | select NET_DSA_TAG_OCELOT |
| 10 | 10 | select FSL_ENETC_MDIO |
| 11 | + select PCS_LYNX | |
| 11 | 12 | help |
| 12 | − This driver supports network switches from the Vitesse / | |
| 13 | − Microsemi / Microchip Ocelot family of switching cores that are | |
| 14 | − connected to their host CPU via Ethernet. | |
| 15 | − The following switches are supported: | |
| 16 | − - VSC9959 (Felix): embedded as a PCIe function of the NXP LS1028A | |
| 17 | − ENETC integrated endpoint. | |
| 18 | − - VSC9953 (Seville): embedded as a platform device on the | |
| 19 | − NXP T1040 SoC. | |
| 13 | + This driver supports the VSC9959 (Felix) switch, which is embedded as | |
| 14 | + a PCIe function of the NXP LS1028A ENETC RCiEP. | |
| 15 | + | |
| 16 | +config NET_DSA_MSCC_SEVILLE | |
| 17 | + tristate "Ocelot / Seville Ethernet switch support" | |
| 18 | + depends on NET_DSA | |
| 19 | + depends on NET_VENDOR_MICROSEMI | |
| 20 | + depends on HAS_IOMEM | |
| 21 | + select MSCC_OCELOT_SWITCH_LIB | |
| 22 | + select NET_DSA_TAG_OCELOT | |
| 23 | + select PCS_LYNX | |
| 24 | + help | |
| 25 | + This driver supports the VSC9953 (Seville) switch, which is embedded | |
| 26 | + as a platform device on the NXP T1040 SoC. | |
| @@ -1,7 +1,11 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o |
| 3 | +obj-$(CONFIG_NET_DSA_MSCC_SEVILLE) += mscc_seville.o | |
| 3 | 4 | |
| 4 | 5 | mscc_felix-objs := \ |
| 5 | 6 | felix.o \ |
| 6 | − felix_vsc9959.o \ | |
| 7 | + felix_vsc9959.o | |
| 8 | + | |
| 9 | +mscc_seville-objs := \ | |
| 10 | + felix.o \ | |
| 7 | 11 | seville_vsc9953.o |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/of_net.h> |
| 20 | 20 | #include <linux/pci.h> |
| 21 | 21 | #include <linux/of.h> |
| 22 | +#include <linux/pcs-lynx.h> | |
| 22 | 23 | #include <net/pkt_sched.h> |
| 23 | 24 | #include <net/dsa.h> |
| 24 | 25 | #include "felix.h" |
| @@ -118,13 +119,12 @@ static int felix_vlan_prepare(struct dsa_switch *ds, int port, · 93 unmodified lines | ||
| 118 | 119 | return 0; |
| 119 | 120 | } |
| 120 | 121 | |
| 121 | −static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) | |
| 122 | +static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, | |
| 123 | + struct switchdev_trans *trans) | |
| 122 | 124 | { |
| 123 | 125 | struct ocelot *ocelot = ds->priv; |
| 124 | 126 | |
| 125 | − ocelot_port_vlan_filtering(ocelot, port, enabled); | |
| 126 | − | |
| 127 | − return 0; | |
| 127 | + return ocelot_port_vlan_filtering(ocelot, port, enabled, trans); | |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | 130 | static void felix_vlan_add(struct dsa_switch *ds, int port, |
| @@ -196,27 +196,16 @@ static void felix_phylink_validate(struct dsa_switch *ds, int port, · 65 unmodified lines | ||
| 196 | 196 | felix->info->phylink_validate(ocelot, port, supported, state); |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | −static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, | |
| 200 | − struct phylink_link_state *state) | |
| 201 | −{ | |
| 202 | − struct ocelot *ocelot = ds->priv; | |
| 203 | − struct felix *felix = ocelot_to_felix(ocelot); | |
| 204 | − | |
| 205 | − if (felix->info->pcs_link_state) | |
| 206 | − felix->info->pcs_link_state(ocelot, port, state); | |
| 207 | − | |
| 208 | − return 0; | |
| 209 | −} | |
| 210 | − | |
| 211 | 199 | static void felix_phylink_mac_config(struct dsa_switch *ds, int port, |
| 212 | 200 | unsigned int link_an_mode, |
| 213 | 201 | const struct phylink_link_state *state) |
| 214 | 202 | { |
| 215 | 203 | struct ocelot *ocelot = ds->priv; |
| 216 | 204 | struct felix *felix = ocelot_to_felix(ocelot); |
| 205 | + struct dsa_port *dp = dsa_to_port(ds, port); | |
| 217 | 206 | |
| 218 | − if (felix->info->pcs_config) | |
| 219 | − felix->info->pcs_config(ocelot, port, link_an_mode, state); | |
| 207 | + if (felix->pcs[port]) | |
| 208 | + phylink_set_pcs(dp->pl, &felix->pcs[port]->pcs); | |
| 220 | 209 | } |
| 221 | 210 | |
| 222 | 211 | static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, |
| @@ -306,10 +295,6 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, · 83 unmodified lines | ||
| 306 | 295 | ocelot_fields_write(ocelot, port, |
| 307 | 296 | QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); |
| 308 | 297 | |
| 309 | − if (felix->info->pcs_link_up) | |
| 310 | − felix->info->pcs_link_up(ocelot, port, link_an_mode, interface, | |
| 311 | − speed, duplex); | |
| 312 | − | |
| 313 | 298 | if (felix->info->port_sched_speed_set) |
| 314 | 299 | felix->info->port_sched_speed_set(ocelot, port, speed); |
| 315 | 300 | } |
| @@ -449,10 +434,10 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) · 133 unmodified lines | ||
| 449 | 434 | ocelot->num_stats = felix->info->num_stats; |
| 450 | 435 | ocelot->shared_queue_sz = felix->info->shared_queue_sz; |
| 451 | 436 | ocelot->num_mact_rows = felix->info->num_mact_rows; |
| 452 | − ocelot->vcap_is2_keys = felix->info->vcap_is2_keys; | |
| 453 | − ocelot->vcap_is2_actions= felix->info->vcap_is2_actions; | |
| 454 | 437 | ocelot->vcap = felix->info->vcap; |
| 455 | 438 | ocelot->ops = felix->info->ops; |
| 439 | + ocelot->inj_prefix = OCELOT_TAG_PREFIX_SHORT; | |
| 440 | + ocelot->xtr_prefix = OCELOT_TAG_PREFIX_SHORT; | |
| 456 | 441 | |
| 457 | 442 | port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), |
| 458 | 443 | GFP_KERNEL); |
| @@ -523,7 +508,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) · 64 unmodified lines | ||
| 523 | 508 | return PTR_ERR(target); |
| 524 | 509 | } |
| 525 | 510 | |
| 526 | − template = devm_kzalloc(ocelot->dev, OCELOT_TAG_LEN, | |
| 511 | + template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN, | |
| 527 | 512 | GFP_KERNEL); |
| 528 | 513 | if (!template) { |
| 529 | 514 | dev_err(ocelot->dev, |
| @@ -552,22 +537,27 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) · 22 unmodified lines | ||
| 552 | 537 | return 0; |
| 553 | 538 | } |
| 554 | 539 | |
| 555 | −static struct ptp_clock_info ocelot_ptp_clock_info = { | |
| 556 | − .owner = THIS_MODULE, | |
| 557 | − .name = "felix ptp", | |
| 558 | − .max_adj = 0x7fffffff, | |
| 559 | − .n_alarm = 0, | |
| 560 | − .n_ext_ts = 0, | |
| 561 | − .n_per_out = OCELOT_PTP_PINS_NUM, | |
| 562 | − .n_pins = OCELOT_PTP_PINS_NUM, | |
| 563 | − .pps = 0, | |
| 564 | − .gettime64 = ocelot_ptp_gettime64, | |
| 565 | − .settime64 = ocelot_ptp_settime64, | |
| 566 | − .adjtime = ocelot_ptp_adjtime, | |
| 567 | − .adjfine = ocelot_ptp_adjfine, | |
| 568 | − .verify = ocelot_ptp_verify, | |
| 569 | − .enable = ocelot_ptp_enable, | |
| 570 | −}; | |
| 540 | +/* The CPU port module is connected to the Node Processor Interface (NPI). This | |
| 541 | + * is the mode through which frames can be injected from and extracted to an | |
| 542 | + * external CPU, over Ethernet. | |
| 543 | + */ | |
| 544 | +static void felix_npi_port_init(struct ocelot *ocelot, int port) | |
| 545 | +{ | |
| 546 | + ocelot->npi = port; | |
| 547 | + | |
| 548 | + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | | |
| 549 | + QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port), | |
| 550 | + QSYS_EXT_CPU_CFG); | |
| 551 | + | |
| 552 | + /* NPI port Injection/Extraction configuration */ | |
| 553 | + ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, | |
| 554 | + ocelot->xtr_prefix); | |
| 555 | + ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, | |
| 556 | + ocelot->inj_prefix); | |
| 557 | + | |
| 558 | + /* Disable transmission of pause frames */ | |
| 559 | + ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0); | |
| 560 | +} | |
| 571 | 561 | |
| 572 | 562 | /* Hardware initialization done here so that we can allocate structures with |
| 573 | 563 | * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing |
| @@ -590,7 +580,7 @@ static int felix_setup(struct dsa_switch *ds) · 16 unmodified lines | ||
| 590 | 580 | return err; |
| 591 | 581 | |
| 592 | 582 | if (ocelot->ptp) { |
| 593 | − err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); | |
| 583 | + err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps); | |
| 594 | 584 | if (err) { |
| 595 | 585 | dev_err(ocelot->dev, |
| 596 | 586 | "Timestamp initialization failed\n"); |
| @@ -601,11 +591,8 @@ static int felix_setup(struct dsa_switch *ds) · 4 unmodified lines | ||
| 601 | 591 | for (port = 0; port < ds->num_ports; port++) { |
| 602 | 592 | ocelot_init_port(ocelot, port); |
| 603 | 593 | |
| 604 | − /* Bring up the CPU port module and configure the NPI port */ | |
| 605 | 594 | if (dsa_is_cpu_port(ds, port)) |
| 606 | − ocelot_configure_cpu(ocelot, port, | |
| 607 | − OCELOT_TAG_PREFIX_NONE, | |
| 608 | − OCELOT_TAG_PREFIX_LONG); | |
| 595 | + felix_npi_port_init(ocelot, port); | |
| 609 | 596 | |
| 610 | 597 | /* Set the default QoS Classification based on PCP and DEI |
| 611 | 598 | * bits of vlan tag. |
| @@ -630,11 +617,6 @@ static int felix_setup(struct dsa_switch *ds) · 18 unmodified lines | ||
| 630 | 617 | |
| 631 | 618 | ds->mtu_enforcement_ingress = true; |
| 632 | 619 | ds->configure_vlan_while_not_filtering = true; |
| 633 | − /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040) | |
| 634 | − * isn't instantiated for the Felix PF. | |
| 635 | − * In-band AN may take a few ms to complete, so we need to poll. | |
| 636 | − */ | |
| 637 | − ds->pcs_poll = true; | |
| 638 | 620 | |
| 639 | 621 | return 0; |
| 640 | 622 | } |
| @@ -705,8 +687,11 @@ static bool felix_txtstamp(struct dsa_switch *ds, int port, · 64 unmodified lines | ||
| 705 | 687 | struct ocelot *ocelot = ds->priv; |
| 706 | 688 | struct ocelot_port *ocelot_port = ocelot->ports[port]; |
| 707 | 689 | |
| 708 | − if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone)) | |
| 690 | + if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) && | |
| 691 | + ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { | |
| 692 | + ocelot_port_add_txtstamp_skb(ocelot, port, clone); | |
| 709 | 693 | return true; |
| 694 | + } | |
| 710 | 695 | |
| 711 | 696 | return false; |
| 712 | 697 | } |
| @@ -793,7 +778,6 @@ const struct dsa_switch_ops felix_switch_ops = { · 80 unmodified lines | ||
| 793 | 778 | .get_sset_count = felix_get_sset_count, |
| 794 | 779 | .get_ts_info = felix_get_ts_info, |
| 795 | 780 | .phylink_validate = felix_phylink_validate, |
| 796 | − .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, | |
| 797 | 781 | .phylink_mac_config = felix_phylink_mac_config, |
| 798 | 782 | .phylink_mac_link_down = felix_phylink_mac_link_down, |
| 799 | 783 | .phylink_mac_link_up = felix_phylink_mac_link_up, |
| @@ -823,31 +807,27 @@ const struct dsa_switch_ops felix_switch_ops = { · 23 unmodified lines | ||
| 823 | 807 | .cls_flower_add = felix_cls_flower_add, |
| 824 | 808 | .cls_flower_del = felix_cls_flower_del, |
| 825 | 809 | .cls_flower_stats = felix_cls_flower_stats, |
| 826 | − .port_setup_tc = felix_port_setup_tc, | |
| 810 | + .port_setup_tc = felix_port_setup_tc, | |
| 827 | 811 | }; |
| 828 | 812 | |
| 829 | −static int __init felix_init(void) | |
| 813 | +struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) | |
| 830 | 814 | { |
| 831 | − int err; | |
| 832 | − | |
| 833 | − err = pci_register_driver(&felix_vsc9959_pci_driver); | |
| 834 | − if (err) | |
| 835 | − return err; | |
| 815 | + struct felix *felix = ocelot_to_felix(ocelot); | |
| 816 | + struct dsa_switch *ds = felix->ds; | |
| 836 | 817 | |
| 837 | − err = platform_driver_register(&seville_vsc9953_driver); | |
| 838 | − if (err) | |
| 839 | − return err; | |
| 818 | + if (!dsa_is_user_port(ds, port)) | |
| 819 | + return NULL; | |
| 840 | 820 | |
| 841 | − return 0; | |
| 821 | + return dsa_to_port(ds, port)->slave; | |
| 842 | 822 | } |
| 843 | −module_init(felix_init); | |
| 844 | 823 | |
| 845 | −static void __exit felix_exit(void) | |
| 824 | +int felix_netdev_to_port(struct net_device *dev) | |
| 846 | 825 | { |
| 847 | − pci_unregister_driver(&felix_vsc9959_pci_driver); | |
| 848 | − platform_driver_unregister(&seville_vsc9953_driver); | |
| 849 | −} | |
| 850 | −module_exit(felix_exit); | |
| 826 | + struct dsa_port *dp; | |
| 827 | + | |
| 828 | + dp = dsa_port_from_netdev(dev); | |
| 829 | + if (IS_ERR(dp)) | |
| 830 | + return -EINVAL; | |
| 851 | 831 | |
| 852 | −MODULE_DESCRIPTION("Felix Switch driver"); | |
| 853 | −MODULE_LICENSE("GPL v2"); | |
| 832 | + return dp->index; | |
| 833 | +} | |
| @@ -20,23 +20,13 @@ struct felix_info { · 19 unmodified lines | ||
| 20 | 20 | const struct ocelot_stat_layout *stats_layout; |
| 21 | 21 | unsigned int num_stats; |
| 22 | 22 | int num_ports; |
| 23 | − int num_tx_queues; | |
| 24 | − struct vcap_field *vcap_is2_keys; | |
| 25 | − struct vcap_field *vcap_is2_actions; | |
| 26 | − const struct vcap_props *vcap; | |
| 23 | + int num_tx_queues; | |
| 24 | + struct vcap_props *vcap; | |
| 27 | 25 | int switch_pci_bar; |
| 28 | 26 | int imdio_pci_bar; |
| 27 | + const struct ptp_clock_info *ptp_caps; | |
| 29 | 28 | int (*mdio_bus_alloc)(struct ocelot *ocelot); |
| 30 | 29 | void (*mdio_bus_free)(struct ocelot *ocelot); |
| 31 | − void (*pcs_config)(struct ocelot *ocelot, int port, | |
| 32 | − unsigned int link_an_mode, | |
| 33 | − const struct phylink_link_state *state); | |
| 34 | − void (*pcs_link_up)(struct ocelot *ocelot, int port, | |
| 35 | − unsigned int link_an_mode, | |
| 36 | − phy_interface_t interface, | |
| 37 | − int speed, int duplex); | |
| 38 | − void (*pcs_link_state)(struct ocelot *ocelot, int port, | |
| 39 | − struct phylink_link_state *state); | |
| 40 | 30 | void (*phylink_validate)(struct ocelot *ocelot, int port, |
| 41 | 31 | unsigned long *supported, |
| 42 | 32 | struct phylink_link_state *state); |
| @@ -50,8 +40,6 @@ struct felix_info { · 7 unmodified lines | ||
| 50 | 40 | }; |
| 51 | 41 | |
| 52 | 42 | extern const struct dsa_switch_ops felix_switch_ops; |
| 53 | −extern struct pci_driver felix_vsc9959_pci_driver; | |
| 54 | −extern struct platform_driver seville_vsc9953_driver; | |
| 55 | 43 | |
| 56 | 44 | /* DSA glue / front-end for struct ocelot */ |
| 57 | 45 | struct felix { |
| @@ -59,20 +47,12 @@ struct felix { · 1 unmodified line | ||
| 59 | 47 | const struct felix_info *info; |
| 60 | 48 | struct ocelot ocelot; |
| 61 | 49 | struct mii_bus *imdio; |
| 62 | − struct phy_device **pcs; | |
| 50 | + struct lynx_pcs **pcs; | |
| 63 | 51 | resource_size_t switch_base; |
| 64 | 52 | resource_size_t imdio_base; |
| 65 | 53 | }; |
| 66 | 54 | |
| 67 | −void vsc9959_pcs_link_state(struct ocelot *ocelot, int port, | |
| 68 | − struct phylink_link_state *state); | |
| 69 | −void vsc9959_pcs_config(struct ocelot *ocelot, int port, | |
| 70 | − unsigned int link_an_mode, | |
| 71 | − const struct phylink_link_state *state); | |
| 72 | −void vsc9959_pcs_link_up(struct ocelot *ocelot, int port, | |
| 73 | − unsigned int link_an_mode, | |
| 74 | − phy_interface_t interface, | |
| 75 | − int speed, int duplex); | |
| 76 | −void vsc9959_mdio_bus_free(struct ocelot *ocelot); | |
| 55 | +struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port); | |
| 56 | +int felix_netdev_to_port(struct net_device *dev); | |
| 77 | 57 | |
| 78 | 58 | #endif |
| @@ -9,15 +9,13 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <soc/mscc/ocelot_sys.h> |
| 10 | 10 | #include <soc/mscc/ocelot.h> |
| 11 | 11 | #include <linux/packing.h> |
| 12 | +#include <linux/pcs-lynx.h> | |
| 12 | 13 | #include <net/pkt_sched.h> |
| 13 | 14 | #include <linux/iopoll.h> |
| 14 | 15 | #include <linux/mdio.h> |
| 15 | 16 | #include <linux/pci.h> |
| 16 | 17 | #include "felix.h" |
| 17 | 18 | |
| 18 | −#define VSC9959_VCAP_IS2_CNT 1024 | |
| 19 | −#define VSC9959_VCAP_IS2_ENTRY_WIDTH 376 | |
| 20 | −#define VSC9959_VCAP_PORT_CNT 6 | |
| 21 | 19 | #define VSC9959_TAS_GCL_ENTRY_MAX 63 |
| 22 | 20 | |
| 23 | 21 | static const u32 vsc9959_ana_regmap[] = { |
| @@ -137,14 +135,27 @@ static const u32 vsc9959_qs_regmap[] = { · 113 unmodified lines | ||
| 137 | 135 | REG_RESERVED(QS_INH_DBG), |
| 138 | 136 | }; |
| 139 | 137 | |
| 140 | −static const u32 vsc9959_s2_regmap[] = { | |
| 141 | − REG(S2_CORE_UPDATE_CTRL, 0x000000), | |
| 142 | − REG(S2_CORE_MV_CFG, 0x000004), | |
| 143 | − REG(S2_CACHE_ENTRY_DAT, 0x000008), | |
| 144 | − REG(S2_CACHE_MASK_DAT, 0x000108), | |
| 145 | − REG(S2_CACHE_ACTION_DAT, 0x000208), | |
| 146 | − REG(S2_CACHE_CNT_DAT, 0x000308), | |
| 147 | − REG(S2_CACHE_TG_DAT, 0x000388), | |
| 138 | +static const u32 vsc9959_vcap_regmap[] = { | |
| 139 | + /* VCAP_CORE_CFG */ | |
| 140 | + REG(VCAP_CORE_UPDATE_CTRL, 0x000000), | |
| 141 | + REG(VCAP_CORE_MV_CFG, 0x000004), | |
| 142 | + /* VCAP_CORE_CACHE */ | |
| 143 | + REG(VCAP_CACHE_ENTRY_DAT, 0x000008), | |
| 144 | + REG(VCAP_CACHE_MASK_DAT, 0x000108), | |
| 145 | + REG(VCAP_CACHE_ACTION_DAT, 0x000208), | |
| 146 | + REG(VCAP_CACHE_CNT_DAT, 0x000308), | |
| 147 | + REG(VCAP_CACHE_TG_DAT, 0x000388), | |
| 148 | + /* VCAP_CONST */ | |
| 149 | + REG(VCAP_CONST_VCAP_VER, 0x000398), | |
| 150 | + REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c), | |
| 151 | + REG(VCAP_CONST_ENTRY_CNT, 0x0003a0), | |
| 152 | + REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4), | |
| 153 | + REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8), | |
| 154 | + REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac), | |
| 155 | + REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0), | |
| 156 | + REG(VCAP_CONST_CNT_WIDTH, 0x0003b4), | |
| 157 | + REG(VCAP_CONST_CORE_CNT, 0x0003b8), | |
| 158 | + REG(VCAP_CONST_IF_CNT, 0x0003bc), | |
| 148 | 159 | }; |
| 149 | 160 | |
| 150 | 161 | static const u32 vsc9959_qsys_regmap[] = { |
| @@ -295,15 +306,15 @@ static const u32 vsc9959_sys_regmap[] = { · 144 unmodified lines | ||
| 295 | 306 | }; |
| 296 | 307 | |
| 297 | 308 | static const u32 vsc9959_ptp_regmap[] = { |
| 298 | − REG(PTP_PIN_CFG, 0x000000), | |
| 299 | − REG(PTP_PIN_TOD_SEC_MSB, 0x000004), | |
| 300 | − REG(PTP_PIN_TOD_SEC_LSB, 0x000008), | |
| 301 | − REG(PTP_PIN_TOD_NSEC, 0x00000c), | |
| 302 | − REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), | |
| 303 | − REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), | |
| 304 | − REG(PTP_CFG_MISC, 0x0000a0), | |
| 305 | − REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), | |
| 306 | − REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), | |
| 309 | + REG(PTP_PIN_CFG, 0x000000), | |
| 310 | + REG(PTP_PIN_TOD_SEC_MSB, 0x000004), | |
| 311 | + REG(PTP_PIN_TOD_SEC_LSB, 0x000008), | |
| 312 | + REG(PTP_PIN_TOD_NSEC, 0x00000c), | |
| 313 | + REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014), | |
| 314 | + REG(PTP_PIN_WF_LOW_PERIOD, 0x000018), | |
| 315 | + REG(PTP_CFG_MISC, 0x0000a0), | |
| 316 | + REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), | |
| 317 | + REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), | |
| 307 | 318 | }; |
| 308 | 319 | |
| 309 | 320 | static const u32 vsc9959_gcb_regmap[] = { |
| @@ -358,7 +369,9 @@ static const u32 *vsc9959_regmap[TARGET_MAX] = { · 48 unmodified lines | ||
| 358 | 369 | [QSYS] = vsc9959_qsys_regmap, |
| 359 | 370 | [REW] = vsc9959_rew_regmap, |
| 360 | 371 | [SYS] = vsc9959_sys_regmap, |
| 361 | − [S2] = vsc9959_s2_regmap, | |
| 372 | + [S0] = vsc9959_vcap_regmap, | |
| 373 | + [S1] = vsc9959_vcap_regmap, | |
| 374 | + [S2] = vsc9959_vcap_regmap, | |
| 362 | 375 | [PTP] = vsc9959_ptp_regmap, |
| 363 | 376 | [GCB] = vsc9959_gcb_regmap, |
| 364 | 377 | [DEV_GMII] = vsc9959_dev_gmii_regmap, |
| @@ -391,6 +404,16 @@ static const struct resource vsc9959_target_io_res[TARGET_MAX] = { · 26 unmodified lines | ||
| 391 | 404 | .end = 0x001ffff, |
| 392 | 405 | .name = "sys", |
| 393 | 406 | }, |
| 407 | + [S0] = { | |
| 408 | + .start = 0x0040000, | |
| 409 | + .end = 0x00403ff, | |
| 410 | + .name = "s0", | |
| 411 | + }, | |
| 412 | + [S1] = { | |
| 413 | + .start = 0x0050000, | |
| 414 | + .end = 0x00503ff, | |
| 415 | + .name = "s1", | |
| 416 | + }, | |
| 394 | 417 | [S2] = { |
| 395 | 418 | .start = 0x0060000, |
| 396 | 419 | .end = 0x00603ff, |
| @@ -595,6 +618,113 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = { · 198 unmodified lines | ||
| 595 | 618 | { .offset = 0x111, .name = "drop_green_prio_7", }, |
| 596 | 619 | }; |
| 597 | 620 | |
| 621 | +static const struct vcap_field vsc9959_vcap_es0_keys[] = { | |
| 622 | + [VCAP_ES0_EGR_PORT] = { 0, 3}, | |
| 623 | + [VCAP_ES0_IGR_PORT] = { 3, 3}, | |
| 624 | + [VCAP_ES0_RSV] = { 6, 2}, | |
| 625 | + [VCAP_ES0_L2_MC] = { 8, 1}, | |
| 626 | + [VCAP_ES0_L2_BC] = { 9, 1}, | |
| 627 | + [VCAP_ES0_VID] = { 10, 12}, | |
| 628 | + [VCAP_ES0_DP] = { 22, 1}, | |
| 629 | + [VCAP_ES0_PCP] = { 23, 3}, | |
| 630 | +}; | |
| 631 | + | |
| 632 | +static const struct vcap_field vsc9959_vcap_es0_actions[] = { | |
| 633 | + [VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2}, | |
| 634 | + [VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1}, | |
| 635 | + [VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2}, | |
| 636 | + [VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1}, | |
| 637 | + [VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2}, | |
| 638 | + [VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2}, | |
| 639 | + [VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2}, | |
| 640 | + [VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1}, | |
| 641 | + [VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2}, | |
| 642 | + [VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2}, | |
| 643 | + [VCAP_ES0_ACT_VID_A_VAL] = { 17, 12}, | |
| 644 | + [VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3}, | |
| 645 | + [VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1}, | |
| 646 | + [VCAP_ES0_ACT_VID_B_VAL] = { 33, 12}, | |
| 647 | + [VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3}, | |
| 648 | + [VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1}, | |
| 649 | + [VCAP_ES0_ACT_RSV] = { 49, 23}, | |
| 650 | + [VCAP_ES0_ACT_HIT_STICKY] = { 72, 1}, | |
| 651 | +}; | |
| 652 | + | |
| 653 | +static const struct vcap_field vsc9959_vcap_is1_keys[] = { | |
| 654 | + [VCAP_IS1_HK_TYPE] = { 0, 1}, | |
| 655 | + [VCAP_IS1_HK_LOOKUP] = { 1, 2}, | |
| 656 | + [VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 7}, | |
| 657 | + [VCAP_IS1_HK_RSV] = { 10, 9}, | |
| 658 | + [VCAP_IS1_HK_OAM_Y1731] = { 19, 1}, | |
| 659 | + [VCAP_IS1_HK_L2_MC] = { 20, 1}, | |
| 660 | + [VCAP_IS1_HK_L2_BC] = { 21, 1}, | |
| 661 | + [VCAP_IS1_HK_IP_MC] = { 22, 1}, | |
| 662 | + [VCAP_IS1_HK_VLAN_TAGGED] = { 23, 1}, | |
| 663 | + [VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 24, 1}, | |
| 664 | + [VCAP_IS1_HK_TPID] = { 25, 1}, | |
| 665 | + [VCAP_IS1_HK_VID] = { 26, 12}, | |
| 666 | + [VCAP_IS1_HK_DEI] = { 38, 1}, | |
| 667 | + [VCAP_IS1_HK_PCP] = { 39, 3}, | |
| 668 | + /* Specific Fields for IS1 Half Key S1_NORMAL */ | |
| 669 | + [VCAP_IS1_HK_L2_SMAC] = { 42, 48}, | |
| 670 | + [VCAP_IS1_HK_ETYPE_LEN] = { 90, 1}, | |
| 671 | + [VCAP_IS1_HK_ETYPE] = { 91, 16}, | |
| 672 | + [VCAP_IS1_HK_IP_SNAP] = {107, 1}, | |
| 673 | + [VCAP_IS1_HK_IP4] = {108, 1}, | |
| 674 | + /* Layer-3 Information */ | |
| 675 | + [VCAP_IS1_HK_L3_FRAGMENT] = {109, 1}, | |
| 676 | + [VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {110, 1}, | |
| 677 | + [VCAP_IS1_HK_L3_OPTIONS] = {111, 1}, | |
| 678 | + [VCAP_IS1_HK_L3_DSCP] = {112, 6}, | |
| 679 | + [VCAP_IS1_HK_L3_IP4_SIP] = {118, 32}, | |
| 680 | + /* Layer-4 Information */ | |
| 681 | + [VCAP_IS1_HK_TCP_UDP] = {150, 1}, | |
| 682 | + [VCAP_IS1_HK_TCP] = {151, 1}, | |
| 683 | + [VCAP_IS1_HK_L4_SPORT] = {152, 16}, | |
| 684 | + [VCAP_IS1_HK_L4_RNG] = {168, 8}, | |
| 685 | + /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */ | |
| 686 | + [VCAP_IS1_HK_IP4_INNER_TPID] = { 42, 1}, | |
| 687 | + [VCAP_IS1_HK_IP4_INNER_VID] = { 43, 12}, | |
| 688 | + [VCAP_IS1_HK_IP4_INNER_DEI] = { 55, 1}, | |
| 689 | + [VCAP_IS1_HK_IP4_INNER_PCP] = { 56, 3}, | |
| 690 | + [VCAP_IS1_HK_IP4_IP4] = { 59, 1}, | |
| 691 | + [VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 60, 1}, | |
| 692 | + [VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 61, 1}, | |
| 693 | + [VCAP_IS1_HK_IP4_L3_OPTIONS] = { 62, 1}, | |
| 694 | + [VCAP_IS1_HK_IP4_L3_DSCP] = { 63, 6}, | |
| 695 | + [VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 69, 32}, | |
| 696 | + [VCAP_IS1_HK_IP4_L3_IP4_SIP] = {101, 32}, | |
| 697 | + [VCAP_IS1_HK_IP4_L3_PROTO] = {133, 8}, | |
| 698 | + [VCAP_IS1_HK_IP4_TCP_UDP] = {141, 1}, | |
| 699 | + [VCAP_IS1_HK_IP4_TCP] = {142, 1}, | |
| 700 | + [VCAP_IS1_HK_IP4_L4_RNG] = {143, 8}, | |
| 701 | + [VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {151, 32}, | |
| 702 | +}; | |
| 703 | + | |
| 704 | +static const struct vcap_field vsc9959_vcap_is1_actions[] = { | |
| 705 | + [VCAP_IS1_ACT_DSCP_ENA] = { 0, 1}, | |
| 706 | + [VCAP_IS1_ACT_DSCP_VAL] = { 1, 6}, | |
| 707 | + [VCAP_IS1_ACT_QOS_ENA] = { 7, 1}, | |
| 708 | + [VCAP_IS1_ACT_QOS_VAL] = { 8, 3}, | |
| 709 | + [VCAP_IS1_ACT_DP_ENA] = { 11, 1}, | |
| 710 | + [VCAP_IS1_ACT_DP_VAL] = { 12, 1}, | |
| 711 | + [VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8}, | |
| 712 | + [VCAP_IS1_ACT_PAG_VAL] = { 21, 8}, | |
| 713 | + [VCAP_IS1_ACT_RSV] = { 29, 9}, | |
| 714 | + /* The fields below are incorrectly shifted by 2 in the manual */ | |
| 715 | + [VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1}, | |
| 716 | + [VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12}, | |
| 717 | + [VCAP_IS1_ACT_FID_SEL] = { 51, 2}, | |
| 718 | + [VCAP_IS1_ACT_FID_VAL] = { 53, 13}, | |
| 719 | + [VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1}, | |
| 720 | + [VCAP_IS1_ACT_PCP_VAL] = { 67, 3}, | |
| 721 | + [VCAP_IS1_ACT_DEI_VAL] = { 70, 1}, | |
| 722 | + [VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1}, | |
| 723 | + [VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2}, | |
| 724 | + [VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4}, | |
| 725 | + [VCAP_IS1_ACT_HIT_STICKY] = { 78, 1}, | |
| 726 | +}; | |
| 727 | + | |
| 598 | 728 | static struct vcap_field vsc9959_vcap_is2_keys[] = { |
| 599 | 729 | /* Common: 41 bits */ |
| 600 | 730 | [VCAP_IS2_TYPE] = { 0, 4}, |
| @@ -693,15 +823,32 @@ static struct vcap_field vsc9959_vcap_is2_actions[] = { · 92 unmodified lines | ||
| 693 | 823 | [VCAP_IS2_ACT_HIT_CNT] = { 44, 32}, |
| 694 | 824 | }; |
| 695 | 825 | |
| 696 | −static const struct vcap_props vsc9959_vcap_props[] = { | |
| 826 | +static struct vcap_props vsc9959_vcap_props[] = { | |
| 827 | + [VCAP_ES0] = { | |
| 828 | + .action_type_width = 0, | |
| 829 | + .action_table = { | |
| 830 | + [ES0_ACTION_TYPE_NORMAL] = { | |
| 831 | + .width = 72, /* HIT_STICKY not included */ | |
| 832 | + .count = 1, | |
| 833 | + }, | |
| 834 | + }, | |
| 835 | + .target = S0, | |
| 836 | + .keys = vsc9959_vcap_es0_keys, | |
| 837 | + .actions = vsc9959_vcap_es0_actions, | |
| 838 | + }, | |
| 839 | + [VCAP_IS1] = { | |
| 840 | + .action_type_width = 0, | |
| 841 | + .action_table = { | |
| 842 | + [IS1_ACTION_TYPE_NORMAL] = { | |
| 843 | + .width = 78, /* HIT_STICKY not included */ | |
| 844 | + .count = 4, | |
| 845 | + }, | |
| 846 | + }, | |
| 847 | + .target = S1, | |
| 848 | + .keys = vsc9959_vcap_is1_keys, | |
| 849 | + .actions = vsc9959_vcap_is1_actions, | |
| 850 | + }, | |
| 697 | 851 | [VCAP_IS2] = { |
| 698 | − .tg_width = 2, | |
| 699 | − .sw_count = 4, | |
| 700 | − .entry_count = VSC9959_VCAP_IS2_CNT, | |
| 701 | − .entry_width = VSC9959_VCAP_IS2_ENTRY_WIDTH, | |
| 702 | − .action_count = VSC9959_VCAP_IS2_CNT + | |
| 703 | − VSC9959_VCAP_PORT_CNT + 2, | |
| 704 | − .action_width = 89, | |
| 705 | 852 | .action_type_width = 1, |
| 706 | 853 | .action_table = { |
| 707 | 854 | [IS2_ACTION_TYPE_NORMAL] = { |
| @@ -713,11 +860,29 @@ static const struct vcap_props vsc9959_vcap_props[] = { · 5 unmodified lines | ||
| 713 | 860 | .count = 4 |
| 714 | 861 | }, |
| 715 | 862 | }, |
| 716 | − .counter_words = 4, | |
| 717 | − .counter_width = 32, | |
| 863 | + .target = S2, | |
| 864 | + .keys = vsc9959_vcap_is2_keys, | |
| 865 | + .actions = vsc9959_vcap_is2_actions, | |
| 718 | 866 | }, |
| 719 | 867 | }; |
| 720 | 868 | |
| 869 | +static const struct ptp_clock_info vsc9959_ptp_caps = { | |
| 870 | + .owner = THIS_MODULE, | |
| 871 | + .name = "felix ptp", | |
| 872 | + .max_adj = 0x7fffffff, | |
| 873 | + .n_alarm = 0, | |
| 874 | + .n_ext_ts = 0, | |
| 875 | + .n_per_out = OCELOT_PTP_PINS_NUM, | |
| 876 | + .n_pins = OCELOT_PTP_PINS_NUM, | |
| 877 | + .pps = 0, | |
| 878 | + .gettime64 = ocelot_ptp_gettime64, | |
| 879 | + .settime64 = ocelot_ptp_settime64, | |
| 880 | + .adjtime = ocelot_ptp_adjtime, | |
| 881 | + .adjfine = ocelot_ptp_adjfine, | |
| 882 | + .verify = ocelot_ptp_verify, | |
| 883 | + .enable = ocelot_ptp_enable, | |
| 884 | +}; | |
| 885 | + | |
| 721 | 886 | #define VSC9959_INIT_TIMEOUT 50000 |
| 722 | 887 | #define VSC9959_GCB_RST_SLEEP 100 |
| 723 | 888 | #define VSC9959_SYS_RAMINIT_SLEEP 80 |
| @@ -726,7 +891,7 @@ static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot) · 2 unmodified lines | ||
| 726 | 891 | { |
| 727 | 892 | int val; |
| 728 | 893 | |
| 729 | − regmap_field_read(ocelot->regfields[GCB_SOFT_RST_SWC_RST], &val); | |
| 894 | + ocelot_field_read(ocelot, GCB_SOFT_RST_SWC_RST, &val); | |
| 730 | 895 | |
| 731 | 896 | return val; |
| 732 | 897 | } |
| @@ -736,12 +901,15 @@ static int vsc9959_sys_ram_init_status(struct ocelot *ocelot) · 3 unmodified lines | ||
| 736 | 901 | return ocelot_read(ocelot, SYS_RAM_INIT); |
| 737 | 902 | } |
| 738 | 903 | |
| 904 | +/* CORE_ENA is in SYS:SYSTEM:RESET_CFG | |
| 905 | + * RAM_INIT is in SYS:RAM_CTRL:RAM_INIT | |
| 906 | + */ | |
| 739 | 907 | static int vsc9959_reset(struct ocelot *ocelot) |
| 740 | 908 | { |
| 741 | 909 | int val, err; |
| 742 | 910 | |
| 743 | 911 | /* soft-reset the switch core */ |
| 744 | − regmap_field_write(ocelot->regfields[GCB_SOFT_RST_SWC_RST], 1); | |
| 912 | + ocelot_field_write(ocelot, GCB_SOFT_RST_SWC_RST, 1); | |
| 745 | 913 | |
| 746 | 914 | err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val, |
| 747 | 915 | VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT); |
| @@ -761,352 +929,11 @@ static int vsc9959_reset(struct ocelot *ocelot) · 13 unmodified lines | ||
| 761 | 929 | } |
| 762 | 930 | |
| 763 | 931 | /* enable switch core */ |
| 764 | − regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); | |
| 932 | + ocelot_field_write(ocelot, SYS_RESET_CFG_CORE_ENA, 1); | |
| 765 | 933 | |
| 766 | 934 | return 0; |
| 767 | 935 | } |
| 768 | 936 | |
| 769 | −/* We enable SGMII AN only when the PHY has managed = "in-band-status" in the | |
| 770 | − * device tree. If we are in MLO_AN_PHY mode, we program directly state->speed | |
| 771 | − * into the PCS, which is retrieved out-of-band over MDIO. This also has the | |
| 772 | − * benefit of working with SGMII fixed-links, like downstream switches, where | |
| 773 | − * both link partners attempt to operate as AN slaves and therefore AN never | |
| 774 | − * completes. But it also has the disadvantage that some PHY chips don't pass | |
| 775 | − * traffic if SGMII AN is enabled but not completed (acknowledged by us), so | |
| 776 | − * setting MLO_AN_INBAND is actually required for those. | |
| 777 | − */ | |
| 778 | −static void vsc9959_pcs_config_sgmii(struct phy_device *pcs, | |
| 779 | − unsigned int link_an_mode, | |
| 780 | − const struct phylink_link_state *state) | |
| 781 | −{ | |
| 782 | − int bmsr, bmcr; | |
| 783 | − | |
| 784 | − /* Some PHYs like VSC8234 don't like it when AN restarts on | |
| 785 | − * their system side and they restart line side AN too, going | |
| 786 | − * into an endless link up/down loop. Don't restart PCS AN if | |
| 787 | − * link is up already. | |
| 788 | − * We do check that AN is enabled just in case this is the 1st | |
| 789 | − * call, PCS detects a carrier but AN is disabled from power on | |
| 790 | − * or by boot loader. | |
| 791 | − */ | |
| 792 | − bmcr = phy_read(pcs, MII_BMCR); | |
| 793 | − if (bmcr < 0) | |
| 794 | − return; | |
| 795 | − | |
| 796 | − bmsr = phy_read(pcs, MII_BMSR); | |
| 797 | − if (bmsr < 0) | |
| 798 | − return; | |
| 799 | − | |
| 800 | − if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_LSTATUS)) | |
| 801 | − return; | |
| 802 | − | |
| 803 | − /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001 | |
| 804 | − * for the MAC PCS in order to acknowledge the AN. | |
| 805 | − */ | |
| 806 | − phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | | |
| 807 | − ADVERTISE_LPACK); | |
| 808 | − | |
| 809 | − phy_write(pcs, ENETC_PCS_IF_MODE, | |
| 810 | − ENETC_PCS_IF_MODE_SGMII_EN | | |
| 811 | − ENETC_PCS_IF_MODE_USE_SGMII_AN); | |
| 812 | − | |
| 813 | − /* Adjust link timer for SGMII */ | |
| 814 | − phy_write(pcs, ENETC_PCS_LINK_TIMER1, | |
| 815 | − ENETC_PCS_LINK_TIMER1_VAL); | |
| 816 | − phy_write(pcs, ENETC_PCS_LINK_TIMER2, | |
| 817 | − ENETC_PCS_LINK_TIMER2_VAL); | |
| 818 | − | |
| 819 | − phy_set_bits(pcs, MII_BMCR, BMCR_ANENABLE); | |
| 820 | −} | |
| 821 | − | |
| 822 | −static void vsc9959_pcs_config_usxgmii(struct phy_device *pcs, | |
| 823 | − unsigned int link_an_mode, | |
| 824 | − const struct phylink_link_state *state) | |
| 825 | −{ | |
| 826 | − /* Configure device ability for the USXGMII Replicator */ | |
| 827 | − phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE, | |
| 828 | − MDIO_USXGMII_2500FULL | | |
| 829 | − MDIO_USXGMII_LINK | | |
| 830 | − ADVERTISE_SGMII | | |
| 831 | − ADVERTISE_LPACK); | |
| 832 | −} | |
| 833 | − | |
| 834 | −void vsc9959_pcs_config(struct ocelot *ocelot, int port, | |
| 835 | − unsigned int link_an_mode, | |
| 836 | − const struct phylink_link_state *state) | |
| 837 | −{ | |
| 838 | − struct felix *felix = ocelot_to_felix(ocelot); | |
| 839 | − struct phy_device *pcs = felix->pcs[port]; | |
| 840 | − | |
| 841 | − if (!pcs) | |
| 842 | − return; | |
| 843 | − | |
| 844 | − /* The PCS does not implement the BMSR register fully, so capability | |
| 845 | − * detection via genphy_read_abilities does not work. Since we can get | |
| 846 | − * the PHY config word from the LPA register though, there is still | |
| 847 | − * value in using the generic phy_resolve_aneg_linkmode function. So | |
| 848 | − * populate the supported and advertising link modes manually here. | |
| 849 | − */ | |
| 850 | − linkmode_set_bit_array(phy_basic_ports_array, | |
| 851 | − ARRAY_SIZE(phy_basic_ports_array), | |
| 852 | − pcs->supported); | |
| 853 | − linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, pcs->supported); | |
| 854 | − linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported); | |
| 855 | − linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, pcs->supported); | |
| 856 | − linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported); | |
| 857 | − linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, pcs->supported); | |
| 858 | − linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported); | |
| 859 | − if (pcs->interface == PHY_INTERFACE_MODE_2500BASEX || | |
| 860 | − pcs->interface == PHY_INTERFACE_MODE_USXGMII) | |
| 861 | − linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, | |
| 862 | − pcs->supported); | |
| 863 | − if (pcs->interface != PHY_INTERFACE_MODE_2500BASEX) | |
| 864 | − linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, | |
| 865 | − pcs->supported); | |
| 866 | − phy_advertise_supported(pcs); | |
| 867 | − | |
| 868 | − if (!phylink_autoneg_inband(link_an_mode)) | |
| 869 | − return; | |
| 870 | − | |
| 871 | − switch (pcs->interface) { | |
| 872 | − case PHY_INTERFACE_MODE_SGMII: | |
| 873 | − case PHY_INTERFACE_MODE_QSGMII: | |
| 874 | − vsc9959_pcs_config_sgmii(pcs, link_an_mode, state); | |
| 875 | − break; | |
| 876 | − case PHY_INTERFACE_MODE_2500BASEX: | |
| 877 | − phydev_err(pcs, "AN not supported on 3.125GHz SerDes lane\n"); | |
| 878 | − break; | |
| 879 | − case PHY_INTERFACE_MODE_USXGMII: | |
| 880 | − vsc9959_pcs_config_usxgmii(pcs, link_an_mode, state); | |
| 881 | − break; | |
| 882 | − default: | |
| 883 | − dev_err(ocelot->dev, "Unsupported link mode %s\n", | |
| 884 | − phy_modes(pcs->interface)); | |
| 885 | − } | |
| 886 | −} | |
| 887 | − | |
| 888 | −static void vsc9959_pcs_link_up_sgmii(struct phy_device *pcs, | |
| 889 | − unsigned int link_an_mode, | |
| 890 | − int speed, int duplex) | |
| 891 | −{ | |
| 892 | − u16 if_mode = ENETC_PCS_IF_MODE_SGMII_EN; | |
| 893 | − | |
| 894 | − switch (speed) { | |
| 895 | − case SPEED_1000: | |
| 896 | − if_mode |= ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_1000); | |
| 897 | − break; | |
| 898 | − case SPEED_100: | |
| 899 | − if_mode |= ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_100); | |
| 900 | − break; | |
| 901 | − case SPEED_10: | |
| 902 | − if_mode |= ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_10); | |
| 903 | − break; | |
| 904 | − default: | |
| 905 | − phydev_err(pcs, "Invalid PCS speed %d\n", speed); | |
| 906 | − return; | |
| 907 | − } | |
| 908 | − | |
| 909 | − if (duplex == DUPLEX_HALF) | |
| 910 | − if_mode |= ENETC_PCS_IF_MODE_DUPLEX_HALF; | |
| 911 | − | |
| 912 | − phy_write(pcs, ENETC_PCS_IF_MODE, if_mode); | |
| 913 | − phy_clear_bits(pcs, MII_BMCR, BMCR_ANENABLE); | |
| 914 | −} | |
| 915 | − | |
| 916 | −/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane | |
| 917 | − * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have | |
| 918 | − * auto-negotiation of any link parameters. Electrically it is compatible with | |
| 919 | − * a single lane of XAUI. | |
| 920 | − * The hardware reference manual wants to call this mode SGMII, but it isn't | |
| 921 | − * really, since the fundamental features of SGMII: | |
| 922 | − * - Downgrading the link speed by duplicating symbols | |
| 923 | − * - Auto-negotiation | |
| 924 | − * are not there. | |
| 925 | − * The speed is configured at 1000 in the IF_MODE and BMCR MDIO registers | |
| 926 | − * because the clock frequency is actually given by a PLL configured in the | |
| 927 | − * Reset Configuration Word (RCW). | |
| 928 | − * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o | |
| 929 | − * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a | |
| 930 | − * lower link speed on line side, the system-side interface remains fixed at | |
| 931 | − * 2500 Mbps and we do rate adaptation through pause frames. | |
| 932 | − */ | |
| 933 | −static void vsc9959_pcs_link_up_2500basex(struct phy_device *pcs, | |
| 934 | − unsigned int link_an_mode, | |
| 935 | − int speed, int duplex) | |
| 936 | −{ | |
| 937 | − u16 if_mode = ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500) | | |
| 938 | − ENETC_PCS_IF_MODE_SGMII_EN; | |
| 939 | − | |
| 940 | − if (duplex == DUPLEX_HALF) | |
| 941 | − if_mode |= ENETC_PCS_IF_MODE_DUPLEX_HALF; | |
| 942 | − | |
| 943 | − phy_write(pcs, ENETC_PCS_IF_MODE, if_mode); | |
| 944 | − phy_clear_bits(pcs, MII_BMCR, BMCR_ANENABLE); | |
| 945 | −} | |
| 946 | − | |
| 947 | −void vsc9959_pcs_link_up(struct ocelot *ocelot, int port, | |
| 948 | − unsigned int link_an_mode, | |
| 949 | − phy_interface_t interface, | |
| 950 | − int speed, int duplex) | |
| 951 | −{ | |
| 952 | − struct felix *felix = ocelot_to_felix(ocelot); | |
| 953 | − struct phy_device *pcs = felix->pcs[port]; | |
| 954 | − | |
| 955 | − if (!pcs) | |
| 956 | − return; | |
| 957 | − | |
| 958 | − if (phylink_autoneg_inband(link_an_mode)) | |
| 959 | − return; | |
| 960 | − | |
| 961 | − switch (interface) { | |
| 962 | − case PHY_INTERFACE_MODE_SGMII: | |
| 963 | − case PHY_INTERFACE_MODE_QSGMII: | |
| 964 | − vsc9959_pcs_link_up_sgmii(pcs, link_an_mode, speed, duplex); | |
| 965 | − break; | |
| 966 | − case PHY_INTERFACE_MODE_2500BASEX: | |
| 967 | − vsc9959_pcs_link_up_2500basex(pcs, link_an_mode, speed, | |
| 968 | − duplex); | |
| 969 | − break; | |
| 970 | − case PHY_INTERFACE_MODE_USXGMII: | |
| 971 | − phydev_err(pcs, "USXGMII only supports in-band AN for now\n"); | |
| 972 | − break; | |
| 973 | − default: | |
| 974 | − dev_err(ocelot->dev, "Unsupported link mode %s\n", | |
| 975 | − phy_modes(pcs->interface)); | |
| 976 | − } | |
| 977 | −} | |
| 978 | − | |
| 979 | −static void vsc9959_pcs_link_state_resolve(struct phy_device *pcs, | |
| 980 | − struct phylink_link_state *state) | |
| 981 | −{ | |
| 982 | − state->an_complete = pcs->autoneg_complete; | |
275 more lines aren’t shown here.
This diff is large: its 424 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 44 lines aren’t shown here.
This diff is large: its 365 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 263 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 533 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 260 lines aren’t shown here.
This diff is large: its 652 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 369 lines aren’t shown here.
This diff is large: its 508 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 16 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 64 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 51 lines aren’t shown here.
This diff is large: its 25 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 143 lines aren’t shown here.
This diff is large: its 168 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 29 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 27 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 321 lines aren’t shown here.
This diff is large: its 1168 lines aren’t shown here.
This diff is large: its 294 lines aren’t shown here.
This diff is large: its 270 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 538 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 657 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 51 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 160 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 45 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 841 lines aren’t shown here.
This diff is large: its 385 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 26 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 8 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 38 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 7 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 192 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 38 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 262 lines aren’t shown here.
This diff is large: its 335 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 38 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 96 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 152 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 432 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 770 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
File renamed without changes.
This diff is large: its 95 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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 8 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 178 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 28 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 9 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 310 lines aren’t shown here.
This diff is large: its 1853 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 256 lines aren’t shown here.
This diff is large: its 147 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 19 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 128 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 497 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 80 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 163 lines aren’t shown here.
This diff is large: its 448 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 473 lines aren’t shown here.
This diff is large: its 460 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 96 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 90 lines aren’t shown here.
This diff is large: its 456 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 66 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 57 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 808 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 192 lines aren’t shown here.
This diff is large: its 9 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 10 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 462 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 271 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 346 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 7 lines aren’t shown here.
This diff is large: its 319 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 21 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 42 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 8 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 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 198 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 771 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 261 lines aren’t shown here.
This diff is large: its 132 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 19 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 285 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 12 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 13 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 26 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 598 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 151 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 275 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 76 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 16 lines aren’t shown here.
This diff is large: its 67 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 249 lines aren’t shown here.
This diff is large: its 11 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 363 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 159 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 262 lines aren’t shown here.
This diff is large: its 60 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 9 lines aren’t shown here.
This diff is large: its 328 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 27 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 156 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 754 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 12 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 39 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 76 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 13 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 192 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 101 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 5 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 1184 lines aren’t shown here.
This diff is large: its 458 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 18 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 1100 lines aren’t shown here.
This diff is large: its 276 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 385 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 285 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 186 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 26 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 781 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 1254 lines aren’t shown here.
This diff is large: its 183 lines aren’t shown here.
This diff is large: its 668 lines aren’t shown here.
This diff is large: its 770 lines aren’t shown here.
This diff is large: its 821 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 1278 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 33 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 10 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 90 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 21 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 31 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 1132 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 248 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 36 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 17 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 91 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 16 lines aren’t shown here.
This diff is large: its 251 lines aren’t shown here.
This diff is large: its 139 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 10 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 312 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 1702 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 835 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 945 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 948 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 464 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 912 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 21 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 117 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 475 lines aren’t shown here.
This diff is large: its 73 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 787 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 379 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 295 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 877 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 446 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 368 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 282 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 713 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 1325 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 260 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 187 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 319 lines aren’t shown here.
This diff is large: its 37 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 68 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 63 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 6 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 137 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 291 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 1736 lines aren’t shown here.
This diff is large: its 216 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 420 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 8 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 260 lines aren’t shown here.
This diff is large: its 21 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 46 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 217 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 88 lines aren’t shown here.
This diff is large: its 34 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 9 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 95 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 302 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 75 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 201 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 130 lines aren’t shown here.
This diff is large: its 86 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 122 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 619 lines aren’t shown here.
This diff is large: its 647 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 294 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 75 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 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 222 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 93 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 28 lines aren’t shown here.
This diff is large: its 38 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 42 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 29 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 13 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 21 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 771 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 11 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 9 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 608 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 21 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 117 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 25 lines aren’t shown here.
This diff is large: its 185 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 234 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 22 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This diff is large: its 16 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 129 lines aren’t shown here.
This diff is large: its 65 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 81 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 319 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 499 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 329 lines aren’t shown here.
This diff is large: its 87 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 50 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 80 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 222 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 25 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 373 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 21 lines aren’t shown here.
This diff is large: its 891 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 402 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 225 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 8 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 169 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 462 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 68 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 1087 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 359 lines aren’t shown here.
This diff is large: its 84 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 41 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 118 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 31 lines aren’t shown here.
This diff is large: its 664 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 372 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 475 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 1146 lines aren’t shown here.
This diff is large: its 272 lines aren’t shown here.
This diff is large: its 1098 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 471 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 823 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 366 lines aren’t shown here.
This diff is large: its 586 lines aren’t shown here.
This diff is large: its 273 lines aren’t shown here.
This diff is large: its 54 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 47 lines aren’t shown here.
This diff is large: its 895 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 783 lines aren’t shown here.
This diff is large: its 468 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 1063 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 563 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 269 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 76 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 34 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 9 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 9 lines aren’t shown here.
This diff is large: its 19 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 9 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 21 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 28 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 21 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 67 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 22 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 24 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 19 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 14 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 9 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 256 lines aren’t shown here.
This diff is large: its 455 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 1037 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 367 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 40 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 58 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 70 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 52 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 150 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 111 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 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 90 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 124 lines aren’t shown here.
This diff is large: its 21 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 19 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 275 lines aren’t shown here.
This diff is large: its 2719 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 210 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 140 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 274 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 164 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 22 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 54 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 33 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 342 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 506 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 275 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 55 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 156 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 135 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 526 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 489 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 698 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 286 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 261 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 192 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 289 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 290 lines aren’t shown here.
This diff is large: its 1141 lines aren’t shown here.
This diff is large: its 853 lines aren’t shown here.
This diff is large: its 1530 lines aren’t shown here.
This diff is large: its 231 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 100 lines aren’t shown here.
This diff is large: its 17 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 45 lines aren’t shown here.
This diff is large: its 9 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 236 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 27 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 30 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 15 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 9 lines aren’t shown here.
This diff is large: its 652 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 443 lines aren’t shown here.
This diff is large: its 434 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 25 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 289 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 194 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 34 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 95 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 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 296 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 35 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 9 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 382 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 160 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 70 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 26 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 37 lines aren’t shown here.
This diff is large: its 236 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 485 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 278 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 288 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 545 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 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 13 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 71 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 17 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 479 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 1351 lines aren’t shown here.
This diff is large: its 788 lines aren’t shown here.
This diff is large: its 1412 lines aren’t shown here.
This diff is large: its 1315 lines aren’t shown here.
This diff is large: its 1453 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 679 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 858 lines aren’t shown here.
This diff is large: its 289 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 386 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 511 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 771 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 397 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 522 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 431 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 345 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 569 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 497 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 935 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 243 lines aren’t shown here.
This diff is large: its 512 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 790 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 369 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 500 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 301 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 331 lines aren’t shown here.
This diff is large: its 1325 lines aren’t shown here.
This diff is large: its 516 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 680 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 489 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 677 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 1510 lines aren’t shown here.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 1090 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 1273 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 11 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 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 144 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 9 lines aren’t shown here.
This diff is large: its 18 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 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 6 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 9 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 14 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 103 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 45 lines aren’t shown here.
This diff is large: its 32 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 18 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 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 14 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 139 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 71 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 11 lines aren’t shown here.
This diff is large: its 114 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 21 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 248 lines aren’t shown here.
This diff is large: its 858 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 1159 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 443 lines aren’t shown here.
This diff is large: its 178 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 29 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 32 lines aren’t shown here.
This diff is large: its 357 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 54 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 93 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 286 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 36 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 30 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
This diff is large: its 8 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 24 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 17 lines aren’t shown here.
This diff is large: its 247 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 55 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 22 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 711 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 20 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 67 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 36 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 401 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 38 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 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 377 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 8 lines aren’t shown here.
This diff is large: its 67 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 51 lines aren’t shown here.
This diff is large: its 224 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 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 52 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 9 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 264 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 237 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 903 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 111 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 25 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 266 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 28 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 74 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 356 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 9 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 9 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 222 lines aren’t shown here.
This diff is large: its 273 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 601 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 1715 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 160 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 9 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 133 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 27 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 92 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 413 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 8 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 553 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 2174 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 247 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 18 lines aren’t shown here.
This diff is large: its 48 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 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 8 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 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 9 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 19 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 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 123 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 29 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 936 lines aren’t shown here.
This diff is large: its 2492 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 182 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 8 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 1425 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 1144 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 337 lines aren’t shown here.
This diff is large: its 1484 lines aren’t shown here.
This diff is large: its 350 lines aren’t shown here.
This diff is large: its 1455 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 11 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 45 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 324 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 662 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 29 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 328 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 304 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 21 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 127 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 74 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 67 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 369 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 73 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 78 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 42 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 8 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 38 lines aren’t shown here.
This diff is large: its 72 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 26 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 46 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 31 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 406 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 321 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 8 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 24 lines aren’t shown here.
This diff is large: its 167 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 9 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 13 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 694 lines aren’t shown here.
This diff is large: its 109 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 39 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 212 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 218 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 34 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 1769 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 20 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 575 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 353 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 495 lines aren’t shown here.
This diff is large: its 239 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 16 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 475 lines aren’t shown here.
This diff is large: its 911 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 244 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 181 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 33 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 41 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 97 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 40 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 391 lines aren’t shown here.
This diff is large: its 34 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 157 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 56 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 38 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 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 570 lines aren’t shown here.
This diff is large: its 412 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 215 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 55 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 83 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 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 14 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 87 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.