Merge 169e77764a ("Merge tag 'net-next-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next") into android-mainline
Steps on the way to 5.18-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ie66ee2ad1facc13146b747aeb08ca65dcb5a6636
This commit is contained in:
@@ -37,8 +37,15 @@ Description: (RO) Set of available destinations (sinks) for a SMA
|
||||
PPS2 signal is sent to the PPS2 selector
|
||||
TS1 signal is sent to timestamper 1
|
||||
TS2 signal is sent to timestamper 2
|
||||
TS3 signal is sent to timestamper 3
|
||||
TS4 signal is sent to timestamper 4
|
||||
IRIG signal is sent to the IRIG-B module
|
||||
DCF signal is sent to the DCF module
|
||||
FREQ1 signal is sent to frequency counter 1
|
||||
FREQ2 signal is sent to frequency counter 2
|
||||
FREQ3 signal is sent to frequency counter 3
|
||||
FREQ4 signal is sent to frequency counter 4
|
||||
None signal input is disabled
|
||||
===== ================================================
|
||||
|
||||
What: /sys/class/timecard/ocpN/available_sma_outputs
|
||||
@@ -50,10 +57,16 @@ Description: (RO) Set of available sources for a SMA output signal.
|
||||
10Mhz output is from the 10Mhz reference clock
|
||||
PHC output PPS is from the PHC clock
|
||||
MAC output PPS is from the Miniature Atomic Clock
|
||||
GNSS output PPS is from the GNSS module
|
||||
GNSS1 output PPS is from the first GNSS module
|
||||
GNSS2 output PPS is from the second GNSS module
|
||||
IRIG output is from the PHC, in IRIG-B format
|
||||
DCF output is from the PHC, in DCF format
|
||||
GEN1 output is from frequency generator 1
|
||||
GEN2 output is from frequency generator 2
|
||||
GEN3 output is from frequency generator 3
|
||||
GEN4 output is from frequency generator 4
|
||||
GND output is GND
|
||||
VCC output is VCC
|
||||
===== ================================================
|
||||
|
||||
What: /sys/class/timecard/ocpN/clock_source
|
||||
@@ -63,6 +76,97 @@ Description: (RW) Contains the current synchronization source used by
|
||||
the PHC. May be changed by writing one of the listed
|
||||
values from the available_clock_sources attribute set.
|
||||
|
||||
What: /sys/class/timecard/ocpN/clock_status_drift
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Contains the current drift value used by the firmware
|
||||
for internal disciplining of the atomic clock.
|
||||
|
||||
What: /sys/class/timecard/ocpN/clock_status_offset
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Contains the current offset value used by the firmware
|
||||
for internal disciplining of the atomic clock.
|
||||
|
||||
What: /sys/class/timecard/ocpN/freqX
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Optional directory containing the sysfs nodes for
|
||||
frequency counter <X>.
|
||||
|
||||
What: /sys/class/timecard/ocpN/freqX/frequency
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Contains the measured frequency over the specified
|
||||
measurement period.
|
||||
|
||||
What: /sys/class/timecard/ocpN/freqX/seconds
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) Specifies the number of seconds from 0-255 that the
|
||||
frequency should be measured over. Write 0 to disable.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Optional directory containing the sysfs nodes for
|
||||
frequency generator <X>.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/duty
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Specifies the signal duty cycle as a percentage from 1-99.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/period
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Specifies the signal period in nanoseconds.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/phase
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Specifies the signal phase offset in nanoseconds.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/polarity
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Specifies the signal polarity, either 1 or 0.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/running
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Either 0 or 1, showing if the signal generator is running.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/start
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RO) Shows the time in <sec>.<nsec> that the signal generator
|
||||
started running.
|
||||
|
||||
What: /sys/class/timecard/ocpN/genX/signal
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) Used to start the signal generator, and summarize
|
||||
the current status.
|
||||
|
||||
The signal generator may be started by writing the signal
|
||||
period, followed by the optional signal values. If the
|
||||
optional values are not provided, they default to the current
|
||||
settings, which may be obtained from the other sysfs nodes.
|
||||
|
||||
period [duty [phase [polarity]]]
|
||||
|
||||
echo 500000000 > signal # 1/2 second period
|
||||
echo 1000000 40 100 > signal
|
||||
echo 0 > signal # turn off generator
|
||||
|
||||
Period and phase are specified in nanoseconds. Duty cycle is
|
||||
a percentage from 1-99. Polarity is 1 or 0.
|
||||
|
||||
Reading this node will return:
|
||||
|
||||
period duty phase polarity start_time
|
||||
|
||||
What: /sys/class/timecard/ocpN/gnss_sync
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
@@ -126,6 +230,16 @@ Description: (RW) These attributes specify the direction of the signal
|
||||
The 10Mhz reference clock input is currently only valid
|
||||
on SMA1 and may not be combined with other destination sinks.
|
||||
|
||||
What: /sys/class/timecard/ocpN/tod_correction
|
||||
Date: March 2022
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
Description: (RW) The incoming GNSS signal is in UTC time, and the NMEA
|
||||
format messages do not provide a TAI offset. This sets the
|
||||
correction value for the incoming time.
|
||||
|
||||
If UBX_LS is enabled, this should be 0, and the offset is
|
||||
taken from the UBX-NAV-TIMELS message.
|
||||
|
||||
What: /sys/class/timecard/ocpN/ts_window_adjust
|
||||
Date: September 2021
|
||||
Contact: Jonathan Lemon <jonathan.lemon@gmail.com>
|
||||
|
||||
@@ -365,6 +365,15 @@ new netns has been created.
|
||||
|
||||
Default : 0 (for compatibility reasons)
|
||||
|
||||
txrehash
|
||||
--------
|
||||
|
||||
Controls default hash rethink behaviour on listening socket when SO_TXREHASH
|
||||
option is set to SOCK_TXREHASH_DEFAULT (i. e. not overridden by setsockopt).
|
||||
|
||||
If set to 1 (default), hash rethink is performed on listening socket.
|
||||
If set to 0, hash rethink is not performed.
|
||||
|
||||
2. /proc/sys/net/unix - Parameters for Unix domain sockets
|
||||
----------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===================================
|
||||
Running BPF programs from userspace
|
||||
===================================
|
||||
|
||||
This document describes the ``BPF_PROG_RUN`` facility for running BPF programs
|
||||
from userspace.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ``BPF_PROG_RUN`` command can be used through the ``bpf()`` syscall to
|
||||
execute a BPF program in the kernel and return the results to userspace. This
|
||||
can be used to unit test BPF programs against user-supplied context objects, and
|
||||
as way to explicitly execute programs in the kernel for their side effects. The
|
||||
command was previously named ``BPF_PROG_TEST_RUN``, and both constants continue
|
||||
to be defined in the UAPI header, aliased to the same value.
|
||||
|
||||
The ``BPF_PROG_RUN`` command can be used to execute BPF programs of the
|
||||
following types:
|
||||
|
||||
- ``BPF_PROG_TYPE_SOCKET_FILTER``
|
||||
- ``BPF_PROG_TYPE_SCHED_CLS``
|
||||
- ``BPF_PROG_TYPE_SCHED_ACT``
|
||||
- ``BPF_PROG_TYPE_XDP``
|
||||
- ``BPF_PROG_TYPE_SK_LOOKUP``
|
||||
- ``BPF_PROG_TYPE_CGROUP_SKB``
|
||||
- ``BPF_PROG_TYPE_LWT_IN``
|
||||
- ``BPF_PROG_TYPE_LWT_OUT``
|
||||
- ``BPF_PROG_TYPE_LWT_XMIT``
|
||||
- ``BPF_PROG_TYPE_LWT_SEG6LOCAL``
|
||||
- ``BPF_PROG_TYPE_FLOW_DISSECTOR``
|
||||
- ``BPF_PROG_TYPE_STRUCT_OPS``
|
||||
- ``BPF_PROG_TYPE_RAW_TRACEPOINT``
|
||||
- ``BPF_PROG_TYPE_SYSCALL``
|
||||
|
||||
When using the ``BPF_PROG_RUN`` command, userspace supplies an input context
|
||||
object and (for program types operating on network packets) a buffer containing
|
||||
the packet data that the BPF program will operate on. The kernel will then
|
||||
execute the program and return the results to userspace. Note that programs will
|
||||
not have any side effects while being run in this mode; in particular, packets
|
||||
will not actually be redirected or dropped, the program return code will just be
|
||||
returned to userspace. A separate mode for live execution of XDP programs is
|
||||
provided, documented separately below.
|
||||
|
||||
Running XDP programs in "live frame mode"
|
||||
-----------------------------------------
|
||||
|
||||
The ``BPF_PROG_RUN`` command has a separate mode for running live XDP programs,
|
||||
which can be used to execute XDP programs in a way where packets will actually
|
||||
be processed by the kernel after the execution of the XDP program as if they
|
||||
arrived on a physical interface. This mode is activated by setting the
|
||||
``BPF_F_TEST_XDP_LIVE_FRAMES`` flag when supplying an XDP program to
|
||||
``BPF_PROG_RUN``.
|
||||
|
||||
The live packet mode is optimised for high performance execution of the supplied
|
||||
XDP program many times (suitable for, e.g., running as a traffic generator),
|
||||
which means the semantics are not quite as straight-forward as the regular test
|
||||
run mode. Specifically:
|
||||
|
||||
- When executing an XDP program in live frame mode, the result of the execution
|
||||
will not be returned to userspace; instead, the kernel will perform the
|
||||
operation indicated by the program's return code (drop the packet, redirect
|
||||
it, etc). For this reason, setting the ``data_out`` or ``ctx_out`` attributes
|
||||
in the syscall parameters when running in this mode will be rejected. In
|
||||
addition, not all failures will be reported back to userspace directly;
|
||||
specifically, only fatal errors in setup or during execution (like memory
|
||||
allocation errors) will halt execution and return an error. If an error occurs
|
||||
in packet processing, like a failure to redirect to a given interface,
|
||||
execution will continue with the next repetition; these errors can be detected
|
||||
via the same trace points as for regular XDP programs.
|
||||
|
||||
- Userspace can supply an ifindex as part of the context object, just like in
|
||||
the regular (non-live) mode. The XDP program will be executed as though the
|
||||
packet arrived on this interface; i.e., the ``ingress_ifindex`` of the context
|
||||
object will point to that interface. Furthermore, if the XDP program returns
|
||||
``XDP_PASS``, the packet will be injected into the kernel networking stack as
|
||||
though it arrived on that ifindex, and if it returns ``XDP_TX``, the packet
|
||||
will be transmitted *out* of that same interface. Do note, though, that
|
||||
because the program execution is not happening in driver context, an
|
||||
``XDP_TX`` is actually turned into the same action as an ``XDP_REDIRECT`` to
|
||||
that same interface (i.e., it will only work if the driver has support for the
|
||||
``ndo_xdp_xmit`` driver op).
|
||||
|
||||
- When running the program with multiple repetitions, the execution will happen
|
||||
in batches. The batch size defaults to 64 packets (which is same as the
|
||||
maximum NAPI receive batch size), but can be specified by userspace through
|
||||
the ``batch_size`` parameter, up to a maximum of 256 packets. For each batch,
|
||||
the kernel executes the XDP program repeatedly, each invocation getting a
|
||||
separate copy of the packet data. For each repetition, if the program drops
|
||||
the packet, the data page is immediately recycled (see below). Otherwise, the
|
||||
packet is buffered until the end of the batch, at which point all packets
|
||||
buffered this way during the batch are transmitted at once.
|
||||
|
||||
- When setting up the test run, the kernel will initialise a pool of memory
|
||||
pages of the same size as the batch size. Each memory page will be initialised
|
||||
with the initial packet data supplied by userspace at ``BPF_PROG_RUN``
|
||||
invocation. When possible, the pages will be recycled on future program
|
||||
invocations, to improve performance. Pages will generally be recycled a full
|
||||
batch at a time, except when a packet is dropped (by return code or because
|
||||
of, say, a redirection error), in which case that page will be recycled
|
||||
immediately. If a packet ends up being passed to the regular networking stack
|
||||
(because the XDP program returns ``XDP_PASS``, or because it ends up being
|
||||
redirected to an interface that injects it into the stack), the page will be
|
||||
released and a new one will be allocated when the pool is empty.
|
||||
|
||||
When recycling, the page content is not rewritten; only the packet boundary
|
||||
pointers (``data``, ``data_end`` and ``data_meta``) in the context object will
|
||||
be reset to the original values. This means that if a program rewrites the
|
||||
packet contents, it has to be prepared to see either the original content or
|
||||
the modified version on subsequent invocations.
|
||||
+27
-18
@@ -503,6 +503,19 @@ valid index (starting from 0) pointing to a member or an argument.
|
||||
* ``info.vlen``: 0
|
||||
* ``type``: the type with ``btf_type_tag`` attribute
|
||||
|
||||
Currently, ``BTF_KIND_TYPE_TAG`` is only emitted for pointer types.
|
||||
It has the following btf type chain:
|
||||
::
|
||||
|
||||
ptr -> [type_tag]*
|
||||
-> [const | volatile | restrict | typedef]*
|
||||
-> base_type
|
||||
|
||||
Basically, a pointer type points to zero or more
|
||||
type_tag, then zero or more const/volatile/restrict/typedef
|
||||
and finally the base type. The base type is one of
|
||||
int, ptr, array, struct, union, enum, func_proto and float types.
|
||||
|
||||
3. BTF Kernel API
|
||||
=================
|
||||
|
||||
@@ -565,18 +578,15 @@ A map can be created with ``btf_fd`` and specified key/value type id.::
|
||||
In libbpf, the map can be defined with extra annotation like below:
|
||||
::
|
||||
|
||||
struct bpf_map_def SEC("maps") btf_map = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(struct ipv_counts),
|
||||
.max_entries = 4,
|
||||
};
|
||||
BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts);
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__type(key, int);
|
||||
__type(value, struct ipv_counts);
|
||||
__uint(max_entries, 4);
|
||||
} btf_map SEC(".maps");
|
||||
|
||||
Here, the parameters for macro BPF_ANNOTATE_KV_PAIR are map name, key and
|
||||
value types for the map. During ELF parsing, libbpf is able to extract
|
||||
key/value type_id's and assign them to BPF_MAP_CREATE attributes
|
||||
automatically.
|
||||
During ELF parsing, libbpf is able to extract key/value type_id's and assign
|
||||
them to BPF_MAP_CREATE attributes automatically.
|
||||
|
||||
.. _BPF_Prog_Load:
|
||||
|
||||
@@ -824,13 +834,12 @@ structure has bitfields. For example, for the following map,::
|
||||
___A b1:4;
|
||||
enum A b2:4;
|
||||
};
|
||||
struct bpf_map_def SEC("maps") tmpmap = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(struct tmp_t),
|
||||
.max_entries = 1,
|
||||
};
|
||||
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__type(key, int);
|
||||
__type(value, struct tmp_t);
|
||||
__uint(max_entries, 1);
|
||||
} tmpmap SEC(".maps");
|
||||
|
||||
bpftool is able to pretty print like below:
|
||||
::
|
||||
|
||||
@@ -21,6 +21,7 @@ that goes into great technical depth about the BPF Architecture.
|
||||
helpers
|
||||
programs
|
||||
maps
|
||||
bpf_prog_run
|
||||
classic_vs_extended.rst
|
||||
bpf_licensing
|
||||
test_debug
|
||||
|
||||
@@ -22,7 +22,13 @@ necessary across calls.
|
||||
Instruction encoding
|
||||
====================
|
||||
|
||||
eBPF uses 64-bit instructions with the following encoding:
|
||||
eBPF has two instruction encodings:
|
||||
|
||||
* the basic instruction encoding, which uses 64 bits to encode an instruction
|
||||
* the wide instruction encoding, which appends a second 64-bit immediate value
|
||||
(imm64) after the basic instruction for a total of 128 bits.
|
||||
|
||||
The basic instruction encoding looks as follows:
|
||||
|
||||
============= ======= =============== ==================== ============
|
||||
32 bits (MSB) 16 bits 4 bits 4 bits 8 bits (LSB)
|
||||
@@ -82,9 +88,9 @@ BPF_ALU uses 32-bit wide operands while BPF_ALU64 uses 64-bit wide operands for
|
||||
otherwise identical operations.
|
||||
The code field encodes the operation as below:
|
||||
|
||||
======== ===== ==========================
|
||||
======== ===== =================================================
|
||||
code value description
|
||||
======== ===== ==========================
|
||||
======== ===== =================================================
|
||||
BPF_ADD 0x00 dst += src
|
||||
BPF_SUB 0x10 dst -= src
|
||||
BPF_MUL 0x20 dst \*= src
|
||||
@@ -98,8 +104,8 @@ The code field encodes the operation as below:
|
||||
BPF_XOR 0xa0 dst ^= src
|
||||
BPF_MOV 0xb0 dst = src
|
||||
BPF_ARSH 0xc0 sign extending shift right
|
||||
BPF_END 0xd0 endianness conversion
|
||||
======== ===== ==========================
|
||||
BPF_END 0xd0 byte swap operations (see separate section below)
|
||||
======== ===== =================================================
|
||||
|
||||
BPF_ADD | BPF_X | BPF_ALU means::
|
||||
|
||||
@@ -118,6 +124,42 @@ BPF_XOR | BPF_K | BPF_ALU64 means::
|
||||
src_reg = src_reg ^ imm32
|
||||
|
||||
|
||||
Byte swap instructions
|
||||
----------------------
|
||||
|
||||
The byte swap instructions use an instruction class of ``BFP_ALU`` and a 4-bit
|
||||
code field of ``BPF_END``.
|
||||
|
||||
The byte swap instructions instructions operate on the destination register
|
||||
only and do not use a separate source register or immediate value.
|
||||
|
||||
The 1-bit source operand field in the opcode is used to to select what byte
|
||||
order the operation convert from or to:
|
||||
|
||||
========= ===== =================================================
|
||||
source value description
|
||||
========= ===== =================================================
|
||||
BPF_TO_LE 0x00 convert between host byte order and little endian
|
||||
BPF_TO_BE 0x08 convert between host byte order and big endian
|
||||
========= ===== =================================================
|
||||
|
||||
The imm field encodes the width of the swap operations. The following widths
|
||||
are supported: 16, 32 and 64.
|
||||
|
||||
Examples:
|
||||
|
||||
``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16 means::
|
||||
|
||||
dst_reg = htole16(dst_reg)
|
||||
|
||||
``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 64 means::
|
||||
|
||||
dst_reg = htobe64(dst_reg)
|
||||
|
||||
``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and
|
||||
``BPF_TO_LE`` respetively.
|
||||
|
||||
|
||||
Jump instructions
|
||||
-----------------
|
||||
|
||||
@@ -176,63 +218,96 @@ The mode modifier is one of:
|
||||
============= ===== ====================================
|
||||
mode modifier value description
|
||||
============= ===== ====================================
|
||||
BPF_IMM 0x00 used for 64-bit mov
|
||||
BPF_ABS 0x20 legacy BPF packet access
|
||||
BPF_IND 0x40 legacy BPF packet access
|
||||
BPF_MEM 0x60 all normal load and store operations
|
||||
BPF_IMM 0x00 64-bit immediate instructions
|
||||
BPF_ABS 0x20 legacy BPF packet access (absolute)
|
||||
BPF_IND 0x40 legacy BPF packet access (indirect)
|
||||
BPF_MEM 0x60 regular load and store operations
|
||||
BPF_ATOMIC 0xc0 atomic operations
|
||||
============= ===== ====================================
|
||||
|
||||
BPF_MEM | <size> | BPF_STX means::
|
||||
|
||||
Regular load and store operations
|
||||
---------------------------------
|
||||
|
||||
The ``BPF_MEM`` mode modifier is used to encode regular load and store
|
||||
instructions that transfer data between a register and memory.
|
||||
|
||||
``BPF_MEM | <size> | BPF_STX`` means::
|
||||
|
||||
*(size *) (dst_reg + off) = src_reg
|
||||
|
||||
BPF_MEM | <size> | BPF_ST means::
|
||||
``BPF_MEM | <size> | BPF_ST`` means::
|
||||
|
||||
*(size *) (dst_reg + off) = imm32
|
||||
|
||||
BPF_MEM | <size> | BPF_LDX means::
|
||||
``BPF_MEM | <size> | BPF_LDX`` means::
|
||||
|
||||
dst_reg = *(size *) (src_reg + off)
|
||||
|
||||
Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW.
|
||||
Where size is one of: ``BPF_B``, ``BPF_H``, ``BPF_W``, or ``BPF_DW``.
|
||||
|
||||
Atomic operations
|
||||
-----------------
|
||||
|
||||
eBPF includes atomic operations, which use the immediate field for extra
|
||||
encoding::
|
||||
Atomic operations are operations that operate on memory and can not be
|
||||
interrupted or corrupted by other access to the same memory region
|
||||
by other eBPF programs or means outside of this specification.
|
||||
|
||||
.imm = BPF_ADD, .code = BPF_ATOMIC | BPF_W | BPF_STX: lock xadd *(u32 *)(dst_reg + off16) += src_reg
|
||||
.imm = BPF_ADD, .code = BPF_ATOMIC | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
|
||||
All atomic operations supported by eBPF are encoded as store operations
|
||||
that use the ``BPF_ATOMIC`` mode modifier as follows:
|
||||
|
||||
The basic atomic operations supported are::
|
||||
* ``BPF_ATOMIC | BPF_W | BPF_STX`` for 32-bit operations
|
||||
* ``BPF_ATOMIC | BPF_DW | BPF_STX`` for 64-bit operations
|
||||
* 8-bit and 16-bit wide atomic operations are not supported.
|
||||
|
||||
BPF_ADD
|
||||
BPF_AND
|
||||
BPF_OR
|
||||
BPF_XOR
|
||||
The imm field is used to encode the actual atomic operation.
|
||||
Simple atomic operation use a subset of the values defined to encode
|
||||
arithmetic operations in the imm field to encode the atomic operation:
|
||||
|
||||
Each having equivalent semantics with the ``BPF_ADD`` example, that is: the
|
||||
memory location addresed by ``dst_reg + off`` is atomically modified, with
|
||||
``src_reg`` as the other operand. If the ``BPF_FETCH`` flag is set in the
|
||||
immediate, then these operations also overwrite ``src_reg`` with the
|
||||
value that was in memory before it was modified.
|
||||
======== ===== ===========
|
||||
imm value description
|
||||
======== ===== ===========
|
||||
BPF_ADD 0x00 atomic add
|
||||
BPF_OR 0x40 atomic or
|
||||
BPF_AND 0x50 atomic and
|
||||
BPF_XOR 0xa0 atomic xor
|
||||
======== ===== ===========
|
||||
|
||||
The more special operations are::
|
||||
|
||||
BPF_XCHG
|
||||
``BPF_ATOMIC | BPF_W | BPF_STX`` with imm = BPF_ADD means::
|
||||
|
||||
This atomically exchanges ``src_reg`` with the value addressed by ``dst_reg +
|
||||
off``. ::
|
||||
*(u32 *)(dst_reg + off16) += src_reg
|
||||
|
||||
BPF_CMPXCHG
|
||||
``BPF_ATOMIC | BPF_DW | BPF_STX`` with imm = BPF ADD means::
|
||||
|
||||
This atomically compares the value addressed by ``dst_reg + off`` with
|
||||
``R0``. If they match it is replaced with ``src_reg``. In either case, the
|
||||
value that was there before is zero-extended and loaded back to ``R0``.
|
||||
*(u64 *)(dst_reg + off16) += src_reg
|
||||
|
||||
Note that 1 and 2 byte atomic operations are not supported.
|
||||
``BPF_XADD`` is a deprecated name for ``BPF_ATOMIC | BPF_ADD``.
|
||||
|
||||
In addition to the simple atomic operations, there also is a modifier and
|
||||
two complex atomic operations:
|
||||
|
||||
=========== ================ ===========================
|
||||
imm value description
|
||||
=========== ================ ===========================
|
||||
BPF_FETCH 0x01 modifier: return old value
|
||||
BPF_XCHG 0xe0 | BPF_FETCH atomic exchange
|
||||
BPF_CMPXCHG 0xf0 | BPF_FETCH atomic compare and exchange
|
||||
=========== ================ ===========================
|
||||
|
||||
The ``BPF_FETCH`` modifier is optional for simple atomic operations, and
|
||||
always set for the complex atomic operations. If the ``BPF_FETCH`` flag
|
||||
is set, then the operation also overwrites ``src_reg`` with the value that
|
||||
was in memory before it was modified.
|
||||
|
||||
The ``BPF_XCHG`` operation atomically exchanges ``src_reg`` with the value
|
||||
addressed by ``dst_reg + off``.
|
||||
|
||||
The ``BPF_CMPXCHG`` operation atomically compares the value addressed by
|
||||
``dst_reg + off`` with ``R0``. If they match, the value addressed by
|
||||
``dst_reg + off`` is replaced with ``src_reg``. In either case, the
|
||||
value that was at ``dst_reg + off`` before the operation is zero-extended
|
||||
and loaded back to ``R0``.
|
||||
|
||||
Clang can generate atomic instructions by default when ``-mcpu=v3`` is
|
||||
enabled. If a lower version for ``-mcpu`` is set, the only atomic instruction
|
||||
@@ -240,40 +315,52 @@ Clang can generate is ``BPF_ADD`` *without* ``BPF_FETCH``. If you need to enable
|
||||
the atomics features, while keeping a lower ``-mcpu`` version, you can use
|
||||
``-Xclang -target-feature -Xclang +alu32``.
|
||||
|
||||
You may encounter ``BPF_XADD`` - this is a legacy name for ``BPF_ATOMIC``,
|
||||
referring to the exclusive-add operation encoded when the immediate field is
|
||||
zero.
|
||||
64-bit immediate instructions
|
||||
-----------------------------
|
||||
|
||||
16-byte instructions
|
||||
--------------------
|
||||
Instructions with the ``BPF_IMM`` mode modifier use the wide instruction
|
||||
encoding for an extra imm64 value.
|
||||
|
||||
eBPF has one 16-byte instruction: ``BPF_LD | BPF_DW | BPF_IMM`` which consists
|
||||
of two consecutive ``struct bpf_insn`` 8-byte blocks and interpreted as single
|
||||
instruction that loads 64-bit immediate value into a dst_reg.
|
||||
There is currently only one such instruction.
|
||||
|
||||
Packet access instructions
|
||||
--------------------------
|
||||
``BPF_LD | BPF_DW | BPF_IMM`` means::
|
||||
|
||||
eBPF has two non-generic instructions: (BPF_ABS | <size> | BPF_LD) and
|
||||
(BPF_IND | <size> | BPF_LD) which are used to access packet data.
|
||||
dst_reg = imm64
|
||||
|
||||
They had to be carried over from classic BPF to have strong performance of
|
||||
socket filters running in eBPF interpreter. These instructions can only
|
||||
be used when interpreter context is a pointer to ``struct sk_buff`` and
|
||||
have seven implicit operands. Register R6 is an implicit input that must
|
||||
contain pointer to sk_buff. Register R0 is an implicit output which contains
|
||||
the data fetched from the packet. Registers R1-R5 are scratch registers
|
||||
and must not be used to store the data across BPF_ABS | BPF_LD or
|
||||
BPF_IND | BPF_LD instructions.
|
||||
|
||||
These instructions have implicit program exit condition as well. When
|
||||
eBPF program is trying to access the data beyond the packet boundary,
|
||||
the interpreter will abort the execution of the program. JIT compilers
|
||||
therefore must preserve this property. src_reg and imm32 fields are
|
||||
explicit inputs to these instructions.
|
||||
Legacy BPF Packet access instructions
|
||||
-------------------------------------
|
||||
|
||||
For example, BPF_IND | BPF_W | BPF_LD means::
|
||||
eBPF has special instructions for access to packet data that have been
|
||||
carried over from classic BPF to retain the performance of legacy socket
|
||||
filters running in the eBPF interpreter.
|
||||
|
||||
The instructions come in two forms: ``BPF_ABS | <size> | BPF_LD`` and
|
||||
``BPF_IND | <size> | BPF_LD``.
|
||||
|
||||
These instructions are used to access packet data and can only be used when
|
||||
the program context is a pointer to networking packet. ``BPF_ABS``
|
||||
accesses packet data at an absolute offset specified by the immediate data
|
||||
and ``BPF_IND`` access packet data at an offset that includes the value of
|
||||
a register in addition to the immediate data.
|
||||
|
||||
These instructions have seven implicit operands:
|
||||
|
||||
* Register R6 is an implicit input that must contain pointer to a
|
||||
struct sk_buff.
|
||||
* Register R0 is an implicit output which contains the data fetched from
|
||||
the packet.
|
||||
* Registers R1-R5 are scratch registers that are clobbered after a call to
|
||||
``BPF_ABS | BPF_LD`` or ``BPF_IND`` | BPF_LD instructions.
|
||||
|
||||
These instructions have an implicit program exit condition as well. When an
|
||||
eBPF program is trying to access the data beyond the packet boundary, the
|
||||
program execution will be aborted.
|
||||
|
||||
``BPF_ABS | BPF_W | BPF_LD`` means::
|
||||
|
||||
R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + imm32))
|
||||
|
||||
``BPF_IND | BPF_W | BPF_LD`` means::
|
||||
|
||||
R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + src_reg + imm32))
|
||||
|
||||
and R1 - R5 are clobbered.
|
||||
|
||||
@@ -329,7 +329,7 @@ Program with unreachable instructions::
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
|
||||
Error:
|
||||
Error::
|
||||
|
||||
unreachable insn 1
|
||||
|
||||
|
||||
@@ -95,6 +95,10 @@ wants to support one of the below features, it should adapt these bindings.
|
||||
- smbus-alert
|
||||
states that the optional SMBus-Alert feature apply to this bus.
|
||||
|
||||
- mctp-controller
|
||||
indicates that the system is accessible via this bus as an endpoint for
|
||||
MCTP over I2C transport.
|
||||
|
||||
Required properties (per child device)
|
||||
--------------------------------------
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
|
||||
@@ -9,7 +9,10 @@ title: Bosch MCAN controller Bindings
|
||||
description: Bosch MCAN controller for CAN bus
|
||||
|
||||
maintainers:
|
||||
- Sriram Dash <sriram.dash@samsung.com>
|
||||
- Chandrasekar Ramakrishnan <rcsekar@samsung.com>
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -66,8 +69,8 @@ properties:
|
||||
M_CAN includes the following elements according to user manual:
|
||||
11-bit Filter 0-128 elements / 0-128 words
|
||||
29-bit Filter 0-64 elements / 0-128 words
|
||||
Rx FIFO 0 0-64 elements / 0-1152 words
|
||||
Rx FIFO 1 0-64 elements / 0-1152 words
|
||||
Rx FIFO 0 0-64 elements / 0-1152 words
|
||||
Rx FIFO 1 0-64 elements / 0-1152 words
|
||||
Rx Buffers 0-64 elements / 0-1152 words
|
||||
Tx Event FIFO 0-32 elements / 0-64 words
|
||||
Tx Buffers 0-32 elements / 0-576 words
|
||||
|
||||
@@ -11,6 +11,9 @@ title:
|
||||
maintainers:
|
||||
- Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
|
||||
@@ -35,6 +35,8 @@ properties:
|
||||
- renesas,r9a07g044-canfd # RZ/G2{L,LC}
|
||||
- const: renesas,rzg2l-canfd # RZ/G2L family
|
||||
|
||||
- const: renesas,r8a779a0-canfd # R-Car V3U
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/can/xilinx,can.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title:
|
||||
Xilinx Axi CAN/Zynq CANPS controller
|
||||
|
||||
maintainers:
|
||||
- Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- xlnx,zynq-can-1.0
|
||||
- xlnx,axi-can-1.00.a
|
||||
- xlnx,canfd-1.0
|
||||
- xlnx,canfd-2.0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
tx-fifo-depth:
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
description: CAN Tx fifo depth (Zynq, Axi CAN).
|
||||
|
||||
rx-fifo-depth:
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
description: CAN Rx fifo depth (Zynq, Axi CAN, CAN FD in sequential Rx mode)
|
||||
|
||||
tx-mailbox-count:
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
description: CAN Tx mailbox buffer count (CAN FD)
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- xlnx,zynq-can-1.0
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-names:
|
||||
items:
|
||||
- const: can_clk
|
||||
- const: pclk
|
||||
required:
|
||||
- tx-fifo-depth
|
||||
- rx-fifo-depth
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- xlnx,axi-can-1.00.a
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-names:
|
||||
items:
|
||||
- const: can_clk
|
||||
- const: s_axi_aclk
|
||||
required:
|
||||
- tx-fifo-depth
|
||||
- rx-fifo-depth
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- xlnx,canfd-1.0
|
||||
- xlnx,canfd-2.0
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-names:
|
||||
items:
|
||||
- const: can_clk
|
||||
- const: s_axi_aclk
|
||||
required:
|
||||
- tx-mailbox-count
|
||||
- rx-fifo-depth
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
can@e0008000 {
|
||||
compatible = "xlnx,zynq-can-1.0";
|
||||
reg = <0xe0008000 0x1000>;
|
||||
clocks = <&clkc 19>, <&clkc 36>;
|
||||
clock-names = "can_clk", "pclk";
|
||||
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&intc>;
|
||||
tx-fifo-depth = <0x40>;
|
||||
rx-fifo-depth = <0x40>;
|
||||
};
|
||||
|
||||
- |
|
||||
can@40000000 {
|
||||
compatible = "xlnx,axi-can-1.00.a";
|
||||
reg = <0x40000000 0x10000>;
|
||||
clocks = <&clkc 0>, <&clkc 1>;
|
||||
clock-names = "can_clk", "s_axi_aclk";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <GIC_SPI 59 IRQ_TYPE_EDGE_RISING>;
|
||||
tx-fifo-depth = <0x40>;
|
||||
rx-fifo-depth = <0x40>;
|
||||
};
|
||||
|
||||
- |
|
||||
can@40000000 {
|
||||
compatible = "xlnx,canfd-1.0";
|
||||
reg = <0x40000000 0x2000>;
|
||||
clocks = <&clkc 0>, <&clkc 1>;
|
||||
clock-names = "can_clk", "s_axi_aclk";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <GIC_SPI 59 IRQ_TYPE_EDGE_RISING>;
|
||||
tx-mailbox-count = <0x20>;
|
||||
rx-fifo-depth = <0x20>;
|
||||
};
|
||||
|
||||
- |
|
||||
can@ff060000 {
|
||||
compatible = "xlnx,canfd-2.0";
|
||||
reg = <0xff060000 0x6000>;
|
||||
clocks = <&clkc 0>, <&clkc 1>;
|
||||
clock-names = "can_clk", "s_axi_aclk";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <GIC_SPI 59 IRQ_TYPE_EDGE_RISING>;
|
||||
tx-mailbox-count = <0x20>;
|
||||
rx-fifo-depth = <0x40>;
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
Xilinx Axi CAN/Zynq CANPS controller Device Tree Bindings
|
||||
---------------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be:
|
||||
- "xlnx,zynq-can-1.0" for Zynq CAN controllers
|
||||
- "xlnx,axi-can-1.00.a" for Axi CAN controllers
|
||||
- "xlnx,canfd-1.0" for CAN FD controllers
|
||||
- "xlnx,canfd-2.0" for CAN FD 2.0 controllers
|
||||
- reg : Physical base address and size of the controller
|
||||
registers map.
|
||||
- interrupts : Property with a value describing the interrupt
|
||||
number.
|
||||
- clock-names : List of input clock names
|
||||
- "can_clk", "pclk" (For CANPS),
|
||||
- "can_clk", "s_axi_aclk" (For AXI CAN and CAN FD).
|
||||
(See clock bindings for details).
|
||||
- clocks : Clock phandles (see clock bindings for details).
|
||||
- tx-fifo-depth : Can Tx fifo depth (Zynq, Axi CAN).
|
||||
- rx-fifo-depth : Can Rx fifo depth (Zynq, Axi CAN, CAN FD in
|
||||
sequential Rx mode).
|
||||
- tx-mailbox-count : Can Tx mailbox buffer count (CAN FD).
|
||||
- rx-mailbox-count : Can Rx mailbox buffer count (CAN FD in mailbox Rx
|
||||
mode).
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
For Zynq CANPS Dts file:
|
||||
zynq_can_0: can@e0008000 {
|
||||
compatible = "xlnx,zynq-can-1.0";
|
||||
clocks = <&clkc 19>, <&clkc 36>;
|
||||
clock-names = "can_clk", "pclk";
|
||||
reg = <0xe0008000 0x1000>;
|
||||
interrupts = <0 28 4>;
|
||||
interrupt-parent = <&intc>;
|
||||
tx-fifo-depth = <0x40>;
|
||||
rx-fifo-depth = <0x40>;
|
||||
};
|
||||
For Axi CAN Dts file:
|
||||
axi_can_0: axi-can@40000000 {
|
||||
compatible = "xlnx,axi-can-1.00.a";
|
||||
clocks = <&clkc 0>, <&clkc 1>;
|
||||
clock-names = "can_clk","s_axi_aclk" ;
|
||||
reg = <0x40000000 0x10000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 59 1>;
|
||||
tx-fifo-depth = <0x40>;
|
||||
rx-fifo-depth = <0x40>;
|
||||
};
|
||||
For CAN FD Dts file:
|
||||
canfd_0: canfd@40000000 {
|
||||
compatible = "xlnx,canfd-1.0";
|
||||
clocks = <&clkc 0>, <&clkc 1>;
|
||||
clock-names = "can_clk", "s_axi_aclk";
|
||||
reg = <0x40000000 0x2000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 59 1>;
|
||||
tx-mailbox-count = <0x20>;
|
||||
rx-fifo-depth = <0x20>;
|
||||
};
|
||||
@@ -81,6 +81,25 @@ properties:
|
||||
|
||||
phy-handle: true
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: sgmii-phy
|
||||
description:
|
||||
Required with ZynqMP SoC when in SGMII mode.
|
||||
Should reference PS-GTR generic PHY device for this controller
|
||||
instance. See ZynqMP example.
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
description:
|
||||
Recommended with ZynqMP, specify reset control for this
|
||||
controller instance with zynqmp-reset driver.
|
||||
|
||||
reset-names:
|
||||
maxItems: 1
|
||||
|
||||
fixed-link: true
|
||||
|
||||
iommus:
|
||||
@@ -157,3 +176,40 @@ examples:
|
||||
reset-gpios = <&pioE 6 1>;
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/clock/xlnx-zynqmp-clk.h>
|
||||
#include <dt-bindings/power/xlnx-zynqmp-power.h>
|
||||
#include <dt-bindings/reset/xlnx-zynqmp-resets.h>
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
|
||||
bus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
gem1: ethernet@ff0c0000 {
|
||||
compatible = "cdns,zynqmp-gem", "cdns,gem";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 59 4>, <0 59 4>;
|
||||
reg = <0x0 0xff0c0000 0x0 0x1000>;
|
||||
clocks = <&zynqmp_clk LPD_LSBUS>, <&zynqmp_clk GEM1_REF>,
|
||||
<&zynqmp_clk GEM1_TX>, <&zynqmp_clk GEM1_RX>,
|
||||
<&zynqmp_clk GEM_TSU>;
|
||||
clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#stream-id-cells = <1>;
|
||||
iommus = <&smmu 0x875>;
|
||||
power-domains = <&zynqmp_firmware PD_ETH_1>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_GEM1>;
|
||||
reset-names = "gem1_rst";
|
||||
status = "okay";
|
||||
phy-mode = "sgmii";
|
||||
phy-names = "sgmii-phy";
|
||||
phys = <&psgtr 1 PHY_TYPE_SGMII 1 1>;
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
pause;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/davicom,dm9051.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Davicom DM9051 SPI Ethernet Controller
|
||||
|
||||
maintainers:
|
||||
- Joseph CHANG <josright123@gmail.com>
|
||||
|
||||
description: |
|
||||
The DM9051 is a fully integrated and cost-effective low pin count single
|
||||
chip Fast Ethernet controller with a Serial Peripheral Interface (SPI).
|
||||
|
||||
allOf:
|
||||
- $ref: ethernet-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: davicom,dm9051
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 45000000
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
local-mac-address: true
|
||||
|
||||
mac-address: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- spi-max-frequency
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Raspberry Pi platform
|
||||
- |
|
||||
/* for Raspberry Pi with pin control stuff for GPIO irq */
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet@0 {
|
||||
compatible = "davicom,dm9051";
|
||||
reg = <0>; /* spi chip select */
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
|
||||
spi-max-frequency = <31200000>;
|
||||
};
|
||||
};
|
||||
@@ -51,6 +51,8 @@ properties:
|
||||
- edsa
|
||||
- ocelot
|
||||
- ocelot-8021q
|
||||
- rtl8_4
|
||||
- rtl8_4t
|
||||
- seville
|
||||
|
||||
phy-handle: true
|
||||
|
||||
@@ -42,6 +42,12 @@ properties:
|
||||
description:
|
||||
Set if the output SYNCLKO frequency should be set to 125MHz instead of 25MHz.
|
||||
|
||||
microchip,synclko-disable:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Set if the output SYNCLKO clock should be disabled. Do not mix with
|
||||
microchip,synclko-125.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
Realtek SMI-based Switches
|
||||
==========================
|
||||
|
||||
The SMI "Simple Management Interface" is a two-wire protocol using
|
||||
bit-banged GPIO that while it reuses the MDIO lines MCK and MDIO does
|
||||
not use the MDIO protocol. This binding defines how to specify the
|
||||
SMI-based Realtek devices.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: must be exactly one of:
|
||||
"realtek,rtl8365mb" (4+1 ports)
|
||||
"realtek,rtl8366"
|
||||
"realtek,rtl8366rb" (4+1 ports)
|
||||
"realtek,rtl8366s" (4+1 ports)
|
||||
"realtek,rtl8367"
|
||||
"realtek,rtl8367b"
|
||||
"realtek,rtl8368s" (8 port)
|
||||
"realtek,rtl8369"
|
||||
"realtek,rtl8370" (8 port)
|
||||
|
||||
Required properties:
|
||||
- mdc-gpios: GPIO line for the MDC clock line.
|
||||
- mdio-gpios: GPIO line for the MDIO data line.
|
||||
- reset-gpios: GPIO line for the reset signal.
|
||||
|
||||
Optional properties:
|
||||
- realtek,disable-leds: if the LED drivers are not used in the
|
||||
hardware design this will disable them so they are not turned on
|
||||
and wasting power.
|
||||
|
||||
Required subnodes:
|
||||
|
||||
- interrupt-controller
|
||||
|
||||
This defines an interrupt controller with an IRQ line (typically
|
||||
a GPIO) that will demultiplex and handle the interrupt from the single
|
||||
interrupt line coming out of one of the SMI-based chips. It most
|
||||
importantly provides link up/down interrupts to the PHY blocks inside
|
||||
the ASIC.
|
||||
|
||||
Required properties of interrupt-controller:
|
||||
|
||||
- interrupt: parent interrupt, see interrupt-controller/interrupts.txt
|
||||
- interrupt-controller: see interrupt-controller/interrupts.txt
|
||||
- #address-cells: should be <0>
|
||||
- #interrupt-cells: should be <1>
|
||||
|
||||
- mdio
|
||||
|
||||
This defines the internal MDIO bus of the SMI device, mostly for the
|
||||
purpose of being able to hook the interrupts to the right PHY and
|
||||
the right PHY to the corresponding port.
|
||||
|
||||
Required properties of mdio:
|
||||
|
||||
- compatible: should be set to "realtek,smi-mdio" for all SMI devices
|
||||
|
||||
See net/mdio.txt for additional MDIO bus properties.
|
||||
|
||||
See net/dsa/dsa.txt for a list of additional required and optional properties
|
||||
and subnodes of DSA switches.
|
||||
|
||||
Examples:
|
||||
|
||||
An example for the RTL8366RB:
|
||||
|
||||
switch {
|
||||
compatible = "realtek,rtl8366rb";
|
||||
/* 22 = MDIO (has input reads), 21 = MDC (clock, output only) */
|
||||
mdc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
|
||||
mdio-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
|
||||
|
||||
switch_intc: interrupt-controller {
|
||||
/* GPIO 15 provides the interrupt */
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan0";
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan1";
|
||||
phy-handle = <&phy1>;
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
phy-handle = <&phy2>;
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan3";
|
||||
phy-handle = <&phy3>;
|
||||
};
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "wan";
|
||||
phy-handle = <&phy4>;
|
||||
};
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "cpu";
|
||||
ethernet = <&gmac0>;
|
||||
phy-mode = "rgmii";
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdio {
|
||||
compatible = "realtek,smi-mdio", "dsa-mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy0: phy@0 {
|
||||
reg = <0>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <0>;
|
||||
};
|
||||
phy1: phy@1 {
|
||||
reg = <1>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <1>;
|
||||
};
|
||||
phy2: phy@2 {
|
||||
reg = <2>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <2>;
|
||||
};
|
||||
phy3: phy@3 {
|
||||
reg = <3>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <3>;
|
||||
};
|
||||
phy4: phy@4 {
|
||||
reg = <4>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <12>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
An example for the RTL8365MB-VC:
|
||||
|
||||
switch {
|
||||
compatible = "realtek,rtl8365mb";
|
||||
mdc-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
|
||||
mdio-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
switch_intc: interrupt-controller {
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "swp0";
|
||||
phy-handle = <ðphy0>;
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "swp1";
|
||||
phy-handle = <ðphy1>;
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "swp2";
|
||||
phy-handle = <ðphy2>;
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "swp3";
|
||||
phy-handle = <ðphy3>;
|
||||
};
|
||||
port@6 {
|
||||
reg = <6>;
|
||||
label = "cpu";
|
||||
ethernet = <&fec1>;
|
||||
phy-mode = "rgmii";
|
||||
tx-internal-delay-ps = <2000>;
|
||||
rx-internal-delay-ps = <2000>;
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
pause;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdio {
|
||||
compatible = "realtek,smi-mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethphy0: phy@0 {
|
||||
reg = <0>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <0>;
|
||||
};
|
||||
ethphy1: phy@1 {
|
||||
reg = <1>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <1>;
|
||||
};
|
||||
ethphy2: phy@2 {
|
||||
reg = <2>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <2>;
|
||||
};
|
||||
ethphy3: phy@3 {
|
||||
reg = <3>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,394 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/dsa/realtek.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Realtek switches for unmanaged switches
|
||||
|
||||
allOf:
|
||||
- $ref: dsa.yaml#
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
description:
|
||||
Realtek advertises these chips as fast/gigabit switches or unmanaged
|
||||
switches. They can be controlled using different interfaces, like SMI,
|
||||
MDIO or SPI.
|
||||
|
||||
The SMI "Simple Management Interface" is a two-wire protocol using
|
||||
bit-banged GPIO that while it reuses the MDIO lines MCK and MDIO does
|
||||
not use the MDIO protocol. This binding defines how to specify the
|
||||
SMI-based Realtek devices. The realtek-smi driver is a platform driver
|
||||
and it must be inserted inside a platform node.
|
||||
|
||||
The MDIO-connected switches use MDIO protocol to access their registers.
|
||||
The realtek-mdio driver is an MDIO driver and it must be inserted inside
|
||||
an MDIO node.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- realtek,rtl8365mb
|
||||
- realtek,rtl8366
|
||||
- realtek,rtl8366rb
|
||||
- realtek,rtl8366s
|
||||
- realtek,rtl8367
|
||||
- realtek,rtl8367b
|
||||
- realtek,rtl8367rb
|
||||
- realtek,rtl8367s
|
||||
- realtek,rtl8368s
|
||||
- realtek,rtl8369
|
||||
- realtek,rtl8370
|
||||
description: |
|
||||
realtek,rtl8365mb: 4+1 ports
|
||||
realtek,rtl8366: 5+1 ports
|
||||
realtek,rtl8366rb: 5+1 ports
|
||||
realtek,rtl8366s: 5+1 ports
|
||||
realtek,rtl8367:
|
||||
realtek,rtl8367b:
|
||||
realtek,rtl8367rb: 5+2 ports
|
||||
realtek,rtl8367s: 5+2 ports
|
||||
realtek,rtl8368s: 8 ports
|
||||
realtek,rtl8369: 8+1 ports
|
||||
realtek,rtl8370: 8+2 ports
|
||||
|
||||
mdc-gpios:
|
||||
description: GPIO line for the MDC clock line.
|
||||
maxItems: 1
|
||||
|
||||
mdio-gpios:
|
||||
description: GPIO line for the MDIO data line.
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: GPIO to be used to reset the whole device
|
||||
maxItems: 1
|
||||
|
||||
realtek,disable-leds:
|
||||
type: boolean
|
||||
description: |
|
||||
if the LED drivers are not used in the hardware design,
|
||||
this will disable them so they are not turned on
|
||||
and wasting power.
|
||||
|
||||
interrupt-controller:
|
||||
type: object
|
||||
description: |
|
||||
This defines an interrupt controller with an IRQ line (typically
|
||||
a GPIO) that will demultiplex and handle the interrupt from the single
|
||||
interrupt line coming out of one of the Realtek switch chips. It most
|
||||
importantly provides link up/down interrupts to the PHY blocks inside
|
||||
the ASIC.
|
||||
|
||||
properties:
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description:
|
||||
A single IRQ line from the switch, either active LOW or HIGH
|
||||
|
||||
'#address-cells':
|
||||
const: 0
|
||||
|
||||
'#interrupt-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- interrupt-controller
|
||||
- '#address-cells'
|
||||
- '#interrupt-cells'
|
||||
|
||||
mdio:
|
||||
$ref: /schemas/net/mdio.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: realtek,smi-mdio
|
||||
|
||||
if:
|
||||
required:
|
||||
- reg
|
||||
|
||||
then:
|
||||
not:
|
||||
required:
|
||||
- mdc-gpios
|
||||
- mdio-gpios
|
||||
- mdio
|
||||
|
||||
properties:
|
||||
mdc-gpios: false
|
||||
mdio-gpios: false
|
||||
mdio: false
|
||||
|
||||
else:
|
||||
required:
|
||||
- mdc-gpios
|
||||
- mdio-gpios
|
||||
- mdio
|
||||
- reset-gpios
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
# - mdc-gpios
|
||||
# - mdio-gpios
|
||||
# - reset-gpios
|
||||
# - mdio
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
platform {
|
||||
switch {
|
||||
compatible = "realtek,rtl8366rb";
|
||||
/* 22 = MDIO (has input reads), 21 = MDC (clock, output only) */
|
||||
mdc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
|
||||
mdio-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
|
||||
|
||||
switch_intc1: interrupt-controller {
|
||||
/* GPIO 15 provides the interrupt */
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan0";
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan1";
|
||||
phy-handle = <&phy1>;
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
phy-handle = <&phy2>;
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan3";
|
||||
phy-handle = <&phy3>;
|
||||
};
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "wan";
|
||||
phy-handle = <&phy4>;
|
||||
};
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "cpu";
|
||||
ethernet = <&gmac0>;
|
||||
phy-mode = "rgmii";
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdio {
|
||||
compatible = "realtek,smi-mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
interrupt-parent = <&switch_intc1>;
|
||||
interrupts = <0>;
|
||||
};
|
||||
phy1: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
interrupt-parent = <&switch_intc1>;
|
||||
interrupts = <1>;
|
||||
};
|
||||
phy2: ethernet-phy@2 {
|
||||
reg = <2>;
|
||||
interrupt-parent = <&switch_intc1>;
|
||||
interrupts = <2>;
|
||||
};
|
||||
phy3: ethernet-phy@3 {
|
||||
reg = <3>;
|
||||
interrupt-parent = <&switch_intc1>;
|
||||
interrupts = <3>;
|
||||
};
|
||||
phy4: ethernet-phy@4 {
|
||||
reg = <4>;
|
||||
interrupt-parent = <&switch_intc1>;
|
||||
interrupts = <12>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
platform {
|
||||
switch {
|
||||
compatible = "realtek,rtl8365mb";
|
||||
mdc-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
|
||||
mdio-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
switch_intc2: interrupt-controller {
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "swp0";
|
||||
phy-handle = <ðphy0>;
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "swp1";
|
||||
phy-handle = <ðphy1>;
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "swp2";
|
||||
phy-handle = <ðphy2>;
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "swp3";
|
||||
phy-handle = <ðphy3>;
|
||||
};
|
||||
port@6 {
|
||||
reg = <6>;
|
||||
label = "cpu";
|
||||
ethernet = <&fec1>;
|
||||
phy-mode = "rgmii";
|
||||
tx-internal-delay-ps = <2000>;
|
||||
rx-internal-delay-ps = <2000>;
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
pause;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdio {
|
||||
compatible = "realtek,smi-mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethphy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
interrupt-parent = <&switch_intc2>;
|
||||
interrupts = <0>;
|
||||
};
|
||||
ethphy1: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
interrupt-parent = <&switch_intc2>;
|
||||
interrupts = <1>;
|
||||
};
|
||||
ethphy2: ethernet-phy@2 {
|
||||
reg = <2>;
|
||||
interrupt-parent = <&switch_intc2>;
|
||||
interrupts = <2>;
|
||||
};
|
||||
ethphy3: ethernet-phy@3 {
|
||||
reg = <3>;
|
||||
interrupt-parent = <&switch_intc2>;
|
||||
interrupts = <3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
switch@29 {
|
||||
compatible = "realtek,rtl8367s";
|
||||
reg = <29>;
|
||||
|
||||
reset-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>;
|
||||
|
||||
switch_intc3: interrupt-controller {
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan4";
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan3";
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan1";
|
||||
};
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "wan";
|
||||
};
|
||||
|
||||
port@7 {
|
||||
reg = <7>;
|
||||
ethernet = <ðernet>;
|
||||
phy-mode = "rgmii";
|
||||
tx-internal-delay-ps = <2000>;
|
||||
rx-internal-delay-ps = <0>;
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -388,14 +388,24 @@ PROPERTIES
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: A standard property.
|
||||
|
||||
- bus-frequency
|
||||
- clocks
|
||||
Usage: optional
|
||||
Value type: <phandle>
|
||||
Definition: A reference to the input clock of the controller
|
||||
from which the MDC frequency is derived.
|
||||
|
||||
- clock-frequency
|
||||
Usage: optional
|
||||
Value type: <u32>
|
||||
Definition: Specifies the external MDIO bus clock speed to
|
||||
be used, if different from the standard 2.5 MHz.
|
||||
This may be due to the standard speed being unsupported (e.g.
|
||||
due to a hardware problem), or to advertise that all relevant
|
||||
components in the system support a faster speed.
|
||||
Definition: Specifies the external MDC frequency, in Hertz, to
|
||||
be used. Requires that the input clock is specified in the
|
||||
"clocks" property. See also: mdio.yaml.
|
||||
|
||||
- suppress-preamble
|
||||
Usage: optional
|
||||
Value type: <boolean>
|
||||
Definition: Disable generation of preamble bits. See also:
|
||||
mdio.yaml.
|
||||
|
||||
- interrupts
|
||||
Usage: required for external MDIO
|
||||
|
||||
@@ -5,6 +5,7 @@ Required properties:
|
||||
"marvell,armada-370-neta"
|
||||
"marvell,armada-xp-neta"
|
||||
"marvell,armada-3700-neta"
|
||||
"marvell,armada-ac5-neta"
|
||||
- reg: address and length of the register set for the device.
|
||||
- interrupts: interrupt for the device
|
||||
- phy: See ethernet.txt file in the same directory.
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/mctp-i2c-controller.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MCTP I2C transport binding
|
||||
|
||||
maintainers:
|
||||
- Matt Johnston <matt@codeconstruct.com.au>
|
||||
|
||||
description: |
|
||||
An mctp-i2c-controller defines a local MCTP endpoint on an I2C controller.
|
||||
MCTP I2C is specified by DMTF DSP0237.
|
||||
|
||||
An mctp-i2c-controller must be attached to an I2C adapter which supports
|
||||
slave functionality. I2C busses (either directly or as subordinate mux
|
||||
busses) are attached to the mctp-i2c-controller with a 'mctp-controller'
|
||||
property on each used bus. Each mctp-controller I2C bus will be presented
|
||||
to the host system as a separate MCTP I2C instance.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mctp-i2c-controller
|
||||
|
||||
reg:
|
||||
minimum: 0x40000000
|
||||
maximum: 0x4000007f
|
||||
description: |
|
||||
7 bit I2C address of the local endpoint.
|
||||
I2C_OWN_SLAVE_ADDRESS (1<<30) flag must be set.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
// Basic case of a single I2C bus
|
||||
#include <dt-bindings/i2c/i2c.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
mctp-controller;
|
||||
|
||||
mctp@30 {
|
||||
compatible = "mctp-i2c-controller";
|
||||
reg = <(0x30 | I2C_OWN_SLAVE_ADDRESS)>;
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
// Mux topology with multiple MCTP-handling busses under
|
||||
// a single mctp-i2c-controller.
|
||||
// i2c1 and i2c6 can have MCTP devices, i2c5 does not.
|
||||
#include <dt-bindings/i2c/i2c.h>
|
||||
|
||||
i2c1: i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
mctp-controller;
|
||||
|
||||
mctp@50 {
|
||||
compatible = "mctp-i2c-controller";
|
||||
reg = <(0x50 | I2C_OWN_SLAVE_ADDRESS)>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c-mux {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
i2c-parent = <&i2c1>;
|
||||
|
||||
i2c5: i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
eeprom@33 {
|
||||
reg = <0x33>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c6: i2c@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
mctp-controller;
|
||||
};
|
||||
};
|
||||
@@ -1,91 +0,0 @@
|
||||
MediaTek DWMAC glue layer controller
|
||||
|
||||
This file documents platform glue layer for stmmac.
|
||||
Please see stmmac.txt for the other unchanged properties.
|
||||
|
||||
The device node has following properties.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "mediatek,mt2712-gmac" for MT2712 SoC
|
||||
- reg: Address and length of the register set for the device
|
||||
- interrupts: Should contain the MAC interrupts
|
||||
- interrupt-names: Should contain a list of interrupt names corresponding to
|
||||
the interrupts in the interrupts property, if available.
|
||||
Should be "macirq" for the main MAC IRQ
|
||||
- clocks: Must contain a phandle for each entry in clock-names.
|
||||
- clock-names: The name of the clock listed in the clocks property. These are
|
||||
"axi", "apb", "mac_main", "ptp_ref", "rmii_internal" for MT2712 SoC.
|
||||
- mac-address: See ethernet.txt in the same directory
|
||||
- phy-mode: See ethernet.txt in the same directory
|
||||
- mediatek,pericfg: A phandle to the syscon node that control ethernet
|
||||
interface and timing delay.
|
||||
|
||||
Optional properties:
|
||||
- mediatek,tx-delay-ps: TX clock delay macro value. Default is 0.
|
||||
It should be defined for RGMII/MII interface.
|
||||
It should be defined for RMII interface when the reference clock is from MT2712 SoC.
|
||||
- mediatek,rx-delay-ps: RX clock delay macro value. Default is 0.
|
||||
It should be defined for RGMII/MII interface.
|
||||
It should be defined for RMII interface.
|
||||
Both delay properties need to be a multiple of 170 for RGMII interface,
|
||||
or will round down. Range 0~31*170.
|
||||
Both delay properties need to be a multiple of 550 for MII/RMII interface,
|
||||
or will round down. Range 0~31*550.
|
||||
|
||||
- mediatek,rmii-rxc: boolean property, if present indicates that the RMII
|
||||
reference clock, which is from external PHYs, is connected to RXC pin
|
||||
on MT2712 SoC.
|
||||
Otherwise, is connected to TXC pin.
|
||||
- mediatek,rmii-clk-from-mac: boolean property, if present indicates that
|
||||
MT2712 SoC provides the RMII reference clock, which outputs to TXC pin only.
|
||||
- mediatek,txc-inverse: boolean property, if present indicates that
|
||||
1. tx clock will be inversed in MII/RGMII case,
|
||||
2. tx clock inside MAC will be inversed relative to reference clock
|
||||
which is from external PHYs in RMII case, and it rarely happen.
|
||||
3. the reference clock, which outputs to TXC pin will be inversed in RMII case
|
||||
when the reference clock is from MT2712 SoC.
|
||||
- mediatek,rxc-inverse: boolean property, if present indicates that
|
||||
1. rx clock will be inversed in MII/RGMII case.
|
||||
2. reference clock will be inversed when arrived at MAC in RMII case, when
|
||||
the reference clock is from external PHYs.
|
||||
3. the inside clock, which be sent to MAC, will be inversed in RMII case when
|
||||
the reference clock is from MT2712 SoC.
|
||||
- assigned-clocks: mac_main and ptp_ref clocks
|
||||
- assigned-clock-parents: parent clocks of the assigned clocks
|
||||
|
||||
Example:
|
||||
eth: ethernet@1101c000 {
|
||||
compatible = "mediatek,mt2712-gmac";
|
||||
reg = <0 0x1101c000 0 0x1300>;
|
||||
interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-names = "macirq";
|
||||
phy-mode ="rgmii-rxid";
|
||||
mac-address = [00 55 7b b5 7d f7];
|
||||
clock-names = "axi",
|
||||
"apb",
|
||||
"mac_main",
|
||||
"ptp_ref",
|
||||
"rmii_internal";
|
||||
clocks = <&pericfg CLK_PERI_GMAC>,
|
||||
<&pericfg CLK_PERI_GMAC_PCLK>,
|
||||
<&topckgen CLK_TOP_ETHER_125M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_RMII_SEL>;
|
||||
assigned-clocks = <&topckgen CLK_TOP_ETHER_125M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_RMII_SEL>;
|
||||
assigned-clock-parents = <&topckgen CLK_TOP_ETHERPLL_125M>,
|
||||
<&topckgen CLK_TOP_APLL1_D3>,
|
||||
<&topckgen CLK_TOP_ETHERPLL_50M>;
|
||||
power-domains = <&scpsys MT2712_POWER_DOMAIN_AUDIO>;
|
||||
mediatek,pericfg = <&pericfg>;
|
||||
mediatek,tx-delay-ps = <1530>;
|
||||
mediatek,rx-delay-ps = <1530>;
|
||||
mediatek,rmii-rxc;
|
||||
mediatek,txc-inverse;
|
||||
mediatek,rxc-inverse;
|
||||
snps,txpbl = <1>;
|
||||
snps,rxpbl = <1>;
|
||||
snps,reset-gpio = <&pio 87 GPIO_ACTIVE_LOW>;
|
||||
snps,reset-active-low;
|
||||
};
|
||||
@@ -0,0 +1,175 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/mediatek-dwmac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek DWMAC glue layer controller
|
||||
|
||||
maintainers:
|
||||
- Biao Huang <biao.huang@mediatek.com>
|
||||
|
||||
description:
|
||||
This file documents platform glue layer for stmmac.
|
||||
|
||||
# We need a select here so we don't match all nodes with 'snps,dwmac'
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt2712-gmac
|
||||
- mediatek,mt8195-gmac
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: "snps,dwmac.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2712-gmac
|
||||
- const: snps,dwmac-4.20a
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8195-gmac
|
||||
- const: snps,dwmac-5.10a
|
||||
|
||||
clocks:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: AXI clock
|
||||
- description: APB clock
|
||||
- description: MAC Main clock
|
||||
- description: PTP clock
|
||||
- description: RMII reference clock provided by MAC
|
||||
- description: MAC clock gate
|
||||
|
||||
clock-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: axi
|
||||
- const: apb
|
||||
- const: mac_main
|
||||
- const: ptp_ref
|
||||
- const: rmii_internal
|
||||
- const: mac_cg
|
||||
|
||||
mediatek,pericfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
The phandle to the syscon node that control ethernet
|
||||
interface and timing delay.
|
||||
|
||||
mediatek,tx-delay-ps:
|
||||
description:
|
||||
The internal TX clock delay (provided by this driver) in nanoseconds.
|
||||
For MT2712 RGMII interface, Allowed value need to be a multiple of 170,
|
||||
or will round down. Range 0~31*170.
|
||||
For MT2712 RMII/MII interface, Allowed value need to be a multiple of 550,
|
||||
or will round down. Range 0~31*550.
|
||||
For MT8195 RGMII/RMII/MII interface, Allowed value need to be a multiple of 290,
|
||||
or will round down. Range 0~31*290.
|
||||
|
||||
mediatek,rx-delay-ps:
|
||||
description:
|
||||
The internal RX clock delay (provided by this driver) in nanoseconds.
|
||||
For MT2712 RGMII interface, Allowed value need to be a multiple of 170,
|
||||
or will round down. Range 0~31*170.
|
||||
For MT2712 RMII/MII interface, Allowed value need to be a multiple of 550,
|
||||
or will round down. Range 0~31*550.
|
||||
For MT8195 RGMII/RMII/MII interface, Allowed value need to be a multiple
|
||||
of 290, or will round down. Range 0~31*290.
|
||||
|
||||
mediatek,rmii-rxc:
|
||||
type: boolean
|
||||
description:
|
||||
If present, indicates that the RMII reference clock, which is from external
|
||||
PHYs, is connected to RXC pin. Otherwise, is connected to TXC pin.
|
||||
|
||||
mediatek,rmii-clk-from-mac:
|
||||
type: boolean
|
||||
description:
|
||||
If present, indicates that MAC provides the RMII reference clock, which
|
||||
outputs to TXC pin only.
|
||||
|
||||
mediatek,txc-inverse:
|
||||
type: boolean
|
||||
description:
|
||||
If present, indicates that
|
||||
1. tx clock will be inversed in MII/RGMII case,
|
||||
2. tx clock inside MAC will be inversed relative to reference clock
|
||||
which is from external PHYs in RMII case, and it rarely happen.
|
||||
3. the reference clock, which outputs to TXC pin will be inversed in RMII case
|
||||
when the reference clock is from MAC.
|
||||
|
||||
mediatek,rxc-inverse:
|
||||
type: boolean
|
||||
description:
|
||||
If present, indicates that
|
||||
1. rx clock will be inversed in MII/RGMII case.
|
||||
2. reference clock will be inversed when arrived at MAC in RMII case, when
|
||||
the reference clock is from external PHYs.
|
||||
3. the inside clock, which be sent to MAC, will be inversed in RMII case when
|
||||
the reference clock is from MAC.
|
||||
|
||||
mediatek,mac-wol:
|
||||
type: boolean
|
||||
description:
|
||||
If present, indicates that MAC supports WOL(Wake-On-LAN), and MAC WOL will be enabled.
|
||||
Otherwise, PHY WOL is perferred.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- phy-mode
|
||||
- mediatek,pericfg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt2712-clk.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/power/mt2712-power.h>
|
||||
|
||||
eth: ethernet@1101c000 {
|
||||
compatible = "mediatek,mt2712-gmac", "snps,dwmac-4.20a";
|
||||
reg = <0x1101c000 0x1300>;
|
||||
interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-names = "macirq";
|
||||
phy-mode ="rgmii-rxid";
|
||||
mac-address = [00 55 7b b5 7d f7];
|
||||
clock-names = "axi",
|
||||
"apb",
|
||||
"mac_main",
|
||||
"ptp_ref",
|
||||
"rmii_internal";
|
||||
clocks = <&pericfg CLK_PERI_GMAC>,
|
||||
<&pericfg CLK_PERI_GMAC_PCLK>,
|
||||
<&topckgen CLK_TOP_ETHER_125M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_RMII_SEL>;
|
||||
assigned-clocks = <&topckgen CLK_TOP_ETHER_125M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_RMII_SEL>;
|
||||
assigned-clock-parents = <&topckgen CLK_TOP_ETHERPLL_125M>,
|
||||
<&topckgen CLK_TOP_APLL1_D3>,
|
||||
<&topckgen CLK_TOP_ETHERPLL_50M>;
|
||||
power-domains = <&scpsys MT2712_POWER_DOMAIN_AUDIO>;
|
||||
mediatek,pericfg = <&pericfg>;
|
||||
mediatek,tx-delay-ps = <1530>;
|
||||
snps,txpbl = <1>;
|
||||
snps,rxpbl = <1>;
|
||||
snps,reset-gpio = <&pio 87 GPIO_ACTIVE_LOW>;
|
||||
snps,reset-delays-us = <0 10000 10000>;
|
||||
};
|
||||
@@ -45,3 +45,20 @@ Optional properties:
|
||||
|
||||
In fiber mode, auto-negotiation is disabled and the PHY can only work in
|
||||
100base-fx (full and half duplex) modes.
|
||||
|
||||
- lan8814,ignore-ts: If present the PHY will not support timestamping.
|
||||
|
||||
This option acts as check whether Timestamping is supported by
|
||||
hardware or not. LAN8814 phy support hardware tmestamping.
|
||||
|
||||
- lan8814,latency_rx_10: Configures Latency value of phy in ingress at 10 Mbps.
|
||||
|
||||
- lan8814,latency_tx_10: Configures Latency value of phy in egress at 10 Mbps.
|
||||
|
||||
- lan8814,latency_rx_100: Configures Latency value of phy in ingress at 100 Mbps.
|
||||
|
||||
- lan8814,latency_tx_100: Configures Latency value of phy in egress at 100 Mbps.
|
||||
|
||||
- lan8814,latency_rx_1000: Configures Latency value of phy in ingress at 1000 Mbps.
|
||||
|
||||
- lan8814,latency_tx_1000: Configures Latency value of phy in egress at 1000 Mbps.
|
||||
|
||||
@@ -38,6 +38,7 @@ properties:
|
||||
- description: register based extraction
|
||||
- description: frame dma based extraction
|
||||
- description: analyzer interrupt
|
||||
- description: ptp interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
@@ -45,6 +46,7 @@ properties:
|
||||
- const: xtr
|
||||
- const: fdma
|
||||
- const: ana
|
||||
- const: ptp
|
||||
|
||||
resets:
|
||||
items:
|
||||
|
||||
@@ -53,12 +53,14 @@ properties:
|
||||
items:
|
||||
- description: register based extraction
|
||||
- description: frame dma based extraction
|
||||
- description: ptp interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: xtr
|
||||
- const: fdma
|
||||
- const: ptp
|
||||
|
||||
resets:
|
||||
items:
|
||||
|
||||
@@ -2,7 +2,7 @@ Microsemi MII Management Controller (MIIM) / MDIO
|
||||
=================================================
|
||||
|
||||
Properties:
|
||||
- compatible: must be "mscc,ocelot-miim"
|
||||
- compatible: must be "mscc,ocelot-miim" or "microchip,lan966x-miim"
|
||||
- reg: The base address of the MDIO bus controller register bank. Optionally, a
|
||||
second register bank can be defined if there is an associated reset register
|
||||
for internal PHYs
|
||||
|
||||
@@ -45,8 +45,10 @@ properties:
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-gbeth # RZ/G2UL
|
||||
- renesas,r9a07g044-gbeth # RZ/G2{L,LC}
|
||||
- const: renesas,rzg2l-gbeth # RZ/G2L
|
||||
- renesas,r9a07g054-gbeth # RZ/V2L
|
||||
- const: renesas,rzg2l-gbeth # RZ/{G2L,G2UL,V2L} family
|
||||
|
||||
reg: true
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ description: |
|
||||
wireless device. The node is expected to be specified as a child
|
||||
node of the PCI controller to which the wireless chip is connected.
|
||||
Alternatively, it can specify the wireless part of the MT7628/MT7688
|
||||
or MT7622 SoC.
|
||||
or MT7622/MT7986 SoC.
|
||||
|
||||
allOf:
|
||||
- $ref: ieee80211.yaml#
|
||||
@@ -29,9 +29,13 @@ properties:
|
||||
- mediatek,mt76
|
||||
- mediatek,mt7628-wmac
|
||||
- mediatek,mt7622-wmac
|
||||
- mediatek,mt7986-wmac
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
description:
|
||||
MT7986 should contain 3 regions consys, dcm, and sku, in this order.
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
@@ -39,6 +43,17 @@ properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
memory-region:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
description:
|
||||
Specify the consys reset for mt7986.
|
||||
|
||||
reset-name:
|
||||
const: consys
|
||||
|
||||
mediatek,infracfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
@@ -69,6 +84,15 @@ properties:
|
||||
calibration data is generic and specific calibration data should be
|
||||
pulled from the OTP ROM
|
||||
|
||||
mediatek,disable-radar-background:
|
||||
type: boolean
|
||||
description:
|
||||
Disable/enable radar/CAC detection running on a dedicated offchannel
|
||||
chain available on some hw.
|
||||
Background radar/CAC detection allows to avoid the CAC downtime
|
||||
switching on a different channel during CAC detection on the selected
|
||||
radar channel.
|
||||
|
||||
led:
|
||||
type: object
|
||||
$ref: /schemas/leds/common.yaml#
|
||||
@@ -165,7 +189,7 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
@@ -231,3 +255,15 @@ examples:
|
||||
|
||||
power-domains = <&scpsys 3>;
|
||||
};
|
||||
|
||||
- |
|
||||
wifi@18000000 {
|
||||
compatible = "mediatek,mt7986-wmac";
|
||||
resets = <&watchdog 23>;
|
||||
reset-names = "consys";
|
||||
reg = <0x18000000 0x1000000>,
|
||||
<0x10003000 0x1000>,
|
||||
<0x11d10000 0x1000>;
|
||||
interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>;
|
||||
memory-region = <&wmcpu_emi>;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/fsl,lynx-28g.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale Lynx 28G SerDes PHY binding
|
||||
|
||||
maintainers:
|
||||
- Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,lynx-28g
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
serdes_1: phy@1ea0000 {
|
||||
compatible = "fsl,lynx-28g";
|
||||
reg = <0x0 0x1ea0000 0x0 0x1e30>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/transmit-amplitude.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common PHY and network PCS transmit amplitude property binding
|
||||
|
||||
description:
|
||||
Binding describing the peak-to-peak transmit amplitude for common PHYs
|
||||
and network PCSes.
|
||||
|
||||
maintainers:
|
||||
- Marek Behún <kabel@kernel.org>
|
||||
|
||||
properties:
|
||||
tx-p2p-microvolt:
|
||||
description:
|
||||
Transmit amplitude voltages in microvolts, peak-to-peak. If this property
|
||||
contains multiple values for various PHY modes, the
|
||||
'tx-p2p-microvolt-names' property must be provided and contain
|
||||
corresponding mode names.
|
||||
|
||||
tx-p2p-microvolt-names:
|
||||
description: |
|
||||
Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
|
||||
property. Required only if multiple voltages are provided.
|
||||
|
||||
If a value of 'default' is provided, the system should use it for any PHY
|
||||
mode that is otherwise not defined here. If 'default' is not provided, the
|
||||
system should use manufacturer default value.
|
||||
minItems: 1
|
||||
maxItems: 16
|
||||
items:
|
||||
enum:
|
||||
- default
|
||||
|
||||
# ethernet modes
|
||||
- sgmii
|
||||
- qsgmii
|
||||
- xgmii
|
||||
- 1000base-x
|
||||
- 2500base-x
|
||||
- 5gbase-r
|
||||
- rxaui
|
||||
- xaui
|
||||
- 10gbase-kr
|
||||
- usxgmii
|
||||
- 10gbase-r
|
||||
- 25gbase-r
|
||||
|
||||
# PCIe modes
|
||||
- pcie
|
||||
- pcie1
|
||||
- pcie2
|
||||
- pcie3
|
||||
- pcie4
|
||||
- pcie5
|
||||
- pcie6
|
||||
|
||||
# USB modes
|
||||
- usb
|
||||
- usb-ls
|
||||
- usb-fs
|
||||
- usb-hs
|
||||
- usb-ss
|
||||
- usb-ss+
|
||||
- usb-4
|
||||
|
||||
# storage modes
|
||||
- sata
|
||||
- ufs-hs
|
||||
- ufs-hs-a
|
||||
- ufs-hs-b
|
||||
|
||||
# display modes
|
||||
- lvds
|
||||
- dp
|
||||
- dp-rbr
|
||||
- dp-hbr
|
||||
- dp-hbr2
|
||||
- dp-hbr3
|
||||
- dp-uhbr-10
|
||||
- dp-uhbr-13.5
|
||||
- dp-uhbr-20
|
||||
|
||||
# camera modes
|
||||
- mipi-dphy
|
||||
- mipi-dphy-univ
|
||||
- mipi-dphy-v2.5-univ
|
||||
|
||||
dependencies:
|
||||
tx-p2p-microvolt-names: [ tx-p2p-microvolt ]
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
- |
|
||||
phy: phy {
|
||||
#phy-cells = <1>;
|
||||
tx-p2p-microvolt = <915000>, <1100000>, <1200000>;
|
||||
tx-p2p-microvolt-names = "2500base-x", "usb-hs", "usb-ss";
|
||||
};
|
||||
@@ -313,6 +313,17 @@ arp_ip_target
|
||||
maximum number of targets that can be specified is 16. The
|
||||
default value is no IP addresses.
|
||||
|
||||
ns_ip6_target
|
||||
|
||||
Specifies the IPv6 addresses to use as IPv6 monitoring peers when
|
||||
arp_interval is > 0. These are the targets of the NS request
|
||||
sent to determine the health of the link to the targets.
|
||||
Specify these values in ffff:ffff::ffff:ffff format. Multiple IPv6
|
||||
addresses must be separated by a comma. At least one IPv6
|
||||
address must be given for NS/NA monitoring to function. The
|
||||
maximum number of targets that can be specified is 16. The
|
||||
default value is no IPv6 addresses.
|
||||
|
||||
arp_validate
|
||||
|
||||
Specifies whether or not ARP probes and replies should be
|
||||
|
||||
@@ -4,6 +4,22 @@ Linux Devlink Documentation
|
||||
devlink is an API to expose device information and resources not directly
|
||||
related to any device class, such as chip-wide/switch-ASIC-wide configuration.
|
||||
|
||||
Locking
|
||||
-------
|
||||
|
||||
Driver facing APIs are currently transitioning to allow more explicit
|
||||
locking. Drivers can use the existing ``devlink_*`` set of APIs, or
|
||||
new APIs prefixed by ``devl_*``. The older APIs handle all the locking
|
||||
in devlink core, but don't allow registration of most sub-objects once
|
||||
the main devlink object is itself registered. The newer ``devl_*`` APIs assume
|
||||
the devlink instance lock is already held. Drivers can take the instance
|
||||
lock by calling ``devl_lock()``. It is also held in most of the callbacks.
|
||||
Eventually all callbacks will be invoked under the devlink instance lock,
|
||||
refer to the use of the ``DEVLINK_NL_FLAG_NO_LOCK`` flag in devlink core
|
||||
to find out which callbacks are not converted, yet.
|
||||
|
||||
Drivers are encouraged to use the devlink instance lock for their own needs.
|
||||
|
||||
Interface documentation
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -293,6 +293,33 @@ of dropped frames, which is a sum of frames dropped due to timing violations,
|
||||
lack of destination ports and MTU enforcement checks). Byte-level counters are
|
||||
not available.
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
The SJA1105 switch family always performs VLAN processing. When configured as
|
||||
VLAN-unaware, frames carry a different VLAN tag internally, depending on
|
||||
whether the port is standalone or under a VLAN-unaware bridge.
|
||||
|
||||
The virtual link keys are always fixed at {MAC DA, VLAN ID, VLAN PCP}, but the
|
||||
driver asks for the VLAN ID and VLAN PCP when the port is under a VLAN-aware
|
||||
bridge. Otherwise, it fills in the VLAN ID and PCP automatically, based on
|
||||
whether the port is standalone or in a VLAN-unaware bridge, and accepts only
|
||||
"VLAN-unaware" tc-flower keys (MAC DA).
|
||||
|
||||
The existing tc-flower keys that are offloaded using virtual links are no
|
||||
longer operational after one of the following happens:
|
||||
|
||||
- port was standalone and joins a bridge (VLAN-aware or VLAN-unaware)
|
||||
- port is part of a bridge whose VLAN awareness state changes
|
||||
- port was part of a bridge and becomes standalone
|
||||
- port was standalone, but another port joins a VLAN-aware bridge and this
|
||||
changes the global VLAN awareness state of the bridge
|
||||
|
||||
The driver cannot veto all these operations, and it cannot update/remove the
|
||||
existing tc-flower filters either. So for proper operation, the tc-flower
|
||||
filters should be installed only after the forwarding configuration of the port
|
||||
has been made, and removed by user space before making any changes to it.
|
||||
|
||||
Device Tree bindings and board design
|
||||
=====================================
|
||||
|
||||
|
||||
@@ -860,8 +860,17 @@ Kernel response contents:
|
||||
``ETHTOOL_A_RINGS_RX_JUMBO`` u32 size of RX jumbo ring
|
||||
``ETHTOOL_A_RINGS_TX`` u32 size of TX ring
|
||||
``ETHTOOL_A_RINGS_RX_BUF_LEN`` u32 size of buffers on the ring
|
||||
``ETHTOOL_A_RINGS_TCP_DATA_SPLIT`` u8 TCP header / data split
|
||||
``ETHTOOL_A_RINGS_CQE_SIZE`` u32 Size of TX/RX CQE
|
||||
==================================== ====== ===========================
|
||||
|
||||
``ETHTOOL_A_RINGS_TCP_DATA_SPLIT`` indicates whether the device is usable with
|
||||
page-flipping TCP zero-copy receive (``getsockopt(TCP_ZEROCOPY_RECEIVE)``).
|
||||
If enabled the device is configured to place frame headers and data into
|
||||
separate buffers. The device configuration must make it possible to receive
|
||||
full memory pages of data, for example because MTU is high enough or through
|
||||
HW-GRO.
|
||||
|
||||
|
||||
RINGS_SET
|
||||
=========
|
||||
@@ -877,6 +886,7 @@ Request contents:
|
||||
``ETHTOOL_A_RINGS_RX_JUMBO`` u32 size of RX jumbo ring
|
||||
``ETHTOOL_A_RINGS_TX`` u32 size of TX ring
|
||||
``ETHTOOL_A_RINGS_RX_BUF_LEN`` u32 size of buffers on the ring
|
||||
``ETHTOOL_A_RINGS_CQE_SIZE`` u32 Size of TX/RX CQE
|
||||
==================================== ====== ===========================
|
||||
|
||||
Kernel checks that requested ring sizes do not exceed limits reported by
|
||||
@@ -884,6 +894,15 @@ driver. Driver may impose additional constraints and may not suspport all
|
||||
attributes.
|
||||
|
||||
|
||||
``ETHTOOL_A_RINGS_CQE_SIZE`` specifies the completion queue event size.
|
||||
Completion queue events(CQE) are the events posted by NIC to indicate the
|
||||
completion status of a packet when the packet is sent(like send success or
|
||||
error) or received(like pointers to packet fragments). The CQE size parameter
|
||||
enables to modify the CQE size other than default size if NIC supports it.
|
||||
A bigger CQE can have more receive buffer pointers inturn NIC can transfer
|
||||
a bigger frame from wire. Based on the NIC hardware, the overall completion
|
||||
queue size can be adjusted in the driver if CQE size is modified.
|
||||
|
||||
CHANNELS_GET
|
||||
============
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ Contents:
|
||||
sctp
|
||||
secid
|
||||
seg6-sysctl
|
||||
smc-sysctl
|
||||
statistics
|
||||
strparser
|
||||
switchdev
|
||||
|
||||
@@ -878,6 +878,29 @@ tcp_min_tso_segs - INTEGER
|
||||
|
||||
Default: 2
|
||||
|
||||
tcp_tso_rtt_log - INTEGER
|
||||
Adjustment of TSO packet sizes based on min_rtt
|
||||
|
||||
Starting from linux-5.18, TCP autosizing can be tweaked
|
||||
for flows having small RTT.
|
||||
|
||||
Old autosizing was splitting the pacing budget to send 1024 TSO
|
||||
per second.
|
||||
|
||||
tso_packet_size = sk->sk_pacing_rate / 1024;
|
||||
|
||||
With the new mechanism, we increase this TSO sizing using:
|
||||
|
||||
distance = min_rtt_usec / (2^tcp_tso_rtt_log)
|
||||
tso_packet_size += gso_max_size >> distance;
|
||||
|
||||
This means that flows between very close hosts can use bigger
|
||||
TSO packets, reducing their cpu costs.
|
||||
|
||||
If you want to use the old autosizing, set this sysctl to 0.
|
||||
|
||||
Default: 9 (2^9 = 512 usec)
|
||||
|
||||
tcp_pacing_ss_ratio - INTEGER
|
||||
sk->sk_pacing_rate is set by TCP stack using a ratio applied
|
||||
to current rate. (current_rate = cwnd * mss / srtt)
|
||||
|
||||
@@ -212,6 +212,54 @@ remote address is already known, or the message does not require a reply.
|
||||
Like the send calls, sockets will only receive responses to requests they have
|
||||
sent (TO=1) and may only respond (TO=0) to requests they have received.
|
||||
|
||||
``ioctl(SIOCMCTPALLOCTAG)`` and ``ioctl(SIOCMCTPDROPTAG)``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These tags give applications more control over MCTP message tags, by allocating
|
||||
(and dropping) tag values explicitly, rather than the kernel automatically
|
||||
allocating a per-message tag at ``sendmsg()`` time.
|
||||
|
||||
In general, you will only need to use these ioctls if your MCTP protocol does
|
||||
not fit the usual request/response model. For example, if you need to persist
|
||||
tags across multiple requests, or a request may generate more than one response.
|
||||
In these cases, the ioctls allow you to decouple the tag allocation (and
|
||||
release) from individual message send and receive operations.
|
||||
|
||||
Both ioctls are passed a pointer to a ``struct mctp_ioc_tag_ctl``:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct mctp_ioc_tag_ctl {
|
||||
mctp_eid_t peer_addr;
|
||||
__u8 tag;
|
||||
__u16 flags;
|
||||
};
|
||||
|
||||
``SIOCMCTPALLOCTAG`` allocates a tag for a specific peer, which an application
|
||||
can use in future ``sendmsg()`` calls. The application populates the
|
||||
``peer_addr`` member with the remote EID. Other fields must be zero.
|
||||
|
||||
On return, the ``tag`` member will be populated with the allocated tag value.
|
||||
The allocated tag will have the following tag bits set:
|
||||
|
||||
- ``MCTP_TAG_OWNER``: it only makes sense to allocate tags if you're the tag
|
||||
owner
|
||||
|
||||
- ``MCTP_TAG_PREALLOC``: to indicate to ``sendmsg()`` that this is a
|
||||
preallocated tag.
|
||||
|
||||
- ... and the actual tag value, within the least-significant three bits
|
||||
(``MCTP_TAG_MASK``). Note that zero is a valid tag value.
|
||||
|
||||
The tag value should be used as-is for the ``smctp_tag`` member of ``struct
|
||||
sockaddr_mctp``.
|
||||
|
||||
``SIOCMCTPDROPTAG`` releases a tag that has been previously allocated by a
|
||||
``SIOCMCTPALLOCTAG`` ioctl. The ``peer_addr`` must be the same as used for the
|
||||
allocation, and the ``tag`` value must match exactly the tag returned from the
|
||||
allocation (including the ``MCTP_TAG_OWNER`` and ``MCTP_TAG_PREALLOC`` bits).
|
||||
The ``flags`` field must be zero.
|
||||
|
||||
Kernel internals
|
||||
================
|
||||
|
||||
|
||||
@@ -105,6 +105,47 @@ a page will cause no race conditions is enough.
|
||||
Please note the caller must not use data area after running
|
||||
page_pool_put_page_bulk(), as this function overwrites it.
|
||||
|
||||
* page_pool_get_stats(): Retrieve statistics about the page_pool. This API
|
||||
is only available if the kernel has been configured with
|
||||
``CONFIG_PAGE_POOL_STATS=y``. A pointer to a caller allocated ``struct
|
||||
page_pool_stats`` structure is passed to this API which is filled in. The
|
||||
caller can then report those stats to the user (perhaps via ethtool,
|
||||
debugfs, etc.). See below for an example usage of this API.
|
||||
|
||||
Stats API and structures
|
||||
------------------------
|
||||
If the kernel is configured with ``CONFIG_PAGE_POOL_STATS=y``, the API
|
||||
``page_pool_get_stats()`` and structures described below are available. It
|
||||
takes a pointer to a ``struct page_pool`` and a pointer to a ``struct
|
||||
page_pool_stats`` allocated by the caller.
|
||||
|
||||
The API will fill in the provided ``struct page_pool_stats`` with
|
||||
statistics about the page_pool.
|
||||
|
||||
The stats structure has the following fields::
|
||||
|
||||
struct page_pool_stats {
|
||||
struct page_pool_alloc_stats alloc_stats;
|
||||
struct page_pool_recycle_stats recycle_stats;
|
||||
};
|
||||
|
||||
|
||||
The ``struct page_pool_alloc_stats`` has the following fields:
|
||||
* ``fast``: successful fast path allocations
|
||||
* ``slow``: slow path order-0 allocations
|
||||
* ``slow_high_order``: slow path high order allocations
|
||||
* ``empty``: ptr ring is empty, so a slow path allocation was forced.
|
||||
* ``refill``: an allocation which triggered a refill of the cache
|
||||
* ``waive``: pages obtained from the ptr ring that cannot be added to
|
||||
the cache due to a NUMA mismatch.
|
||||
|
||||
The ``struct page_pool_recycle_stats`` has the following fields:
|
||||
* ``cached``: recycling placed page in the page pool cache
|
||||
* ``cache_full``: page pool cache was full
|
||||
* ``ring``: page placed into the ptr ring
|
||||
* ``ring_full``: page released from page pool because the ptr ring was full
|
||||
* ``released_refcnt``: page released (and not recycled) because refcnt > 1
|
||||
|
||||
Coding examples
|
||||
===============
|
||||
|
||||
@@ -157,6 +198,21 @@ NAPI poller
|
||||
}
|
||||
}
|
||||
|
||||
Stats
|
||||
-----
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#ifdef CONFIG_PAGE_POOL_STATS
|
||||
/* retrieve stats */
|
||||
struct page_pool_stats stats = { 0 };
|
||||
if (page_pool_get_stats(page_pool, &stats)) {
|
||||
/* perhaps the driver reports statistics with ethool */
|
||||
ethtool_print_allocation_stats(&stats.alloc_stats);
|
||||
ethtool_print_recycle_stats(&stats.recycle_stats);
|
||||
}
|
||||
#endif
|
||||
|
||||
Driver unload
|
||||
-------------
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
==========
|
||||
SMC Sysctl
|
||||
==========
|
||||
|
||||
/proc/sys/net/smc/* Variables
|
||||
=============================
|
||||
|
||||
autocorking_size - INTEGER
|
||||
Setting SMC auto corking size:
|
||||
SMC auto corking is like TCP auto corking from the application's
|
||||
perspective of view. When applications do consecutive small
|
||||
write()/sendmsg() system calls, we try to coalesce these small writes
|
||||
as much as possible, to lower total amount of CDC and RDMA Write been
|
||||
sent.
|
||||
autocorking_size limits the maximum corked bytes that can be sent to
|
||||
the under device in 1 single sending. If set to 0, the SMC auto corking
|
||||
is disabled.
|
||||
Applications can still use TCP_CORK for optimal behavior when they
|
||||
know how/when to uncork their sockets.
|
||||
|
||||
Default: 64K
|
||||
@@ -668,7 +668,7 @@ timestamping:
|
||||
(through another RX timestamping FIFO). Deferral on RX is typically
|
||||
necessary when retrieving the timestamp needs a sleepable context. In
|
||||
that case, it is the responsibility of the DSA driver to call
|
||||
``netif_rx_ni()`` on the freshly timestamped skb.
|
||||
``netif_rx()`` on the freshly timestamped skb.
|
||||
|
||||
3.2.2 Ethernet PHYs
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
==================================
|
||||
Fprobe - Function entry/exit probe
|
||||
==================================
|
||||
|
||||
.. Author: Masami Hiramatsu <mhiramat@kernel.org>
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Fprobe is a function entry/exit probe mechanism based on ftrace.
|
||||
Instead of using ftrace full feature, if you only want to attach callbacks
|
||||
on function entry and exit, similar to the kprobes and kretprobes, you can
|
||||
use fprobe. Compared with kprobes and kretprobes, fprobe gives faster
|
||||
instrumentation for multiple functions with single handler. This document
|
||||
describes how to use fprobe.
|
||||
|
||||
The usage of fprobe
|
||||
===================
|
||||
|
||||
The fprobe is a wrapper of ftrace (+ kretprobe-like return callback) to
|
||||
attach callbacks to multiple function entry and exit. User needs to set up
|
||||
the `struct fprobe` and pass it to `register_fprobe()`.
|
||||
|
||||
Typically, `fprobe` data structure is initialized with the `entry_handler`
|
||||
and/or `exit_handler` as below.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct fprobe fp = {
|
||||
.entry_handler = my_entry_callback,
|
||||
.exit_handler = my_exit_callback,
|
||||
};
|
||||
|
||||
To enable the fprobe, call one of register_fprobe(), register_fprobe_ips(), and
|
||||
register_fprobe_syms(). These functions register the fprobe with different types
|
||||
of parameters.
|
||||
|
||||
The register_fprobe() enables a fprobe by function-name filters.
|
||||
E.g. this enables @fp on "func*()" function except "func2()".::
|
||||
|
||||
register_fprobe(&fp, "func*", "func2");
|
||||
|
||||
The register_fprobe_ips() enables a fprobe by ftrace-location addresses.
|
||||
E.g.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
unsigned long ips[] = { 0x.... };
|
||||
|
||||
register_fprobe_ips(&fp, ips, ARRAY_SIZE(ips));
|
||||
|
||||
And the register_fprobe_syms() enables a fprobe by symbol names.
|
||||
E.g.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char syms[] = {"func1", "func2", "func3"};
|
||||
|
||||
register_fprobe_syms(&fp, syms, ARRAY_SIZE(syms));
|
||||
|
||||
To disable (remove from functions) this fprobe, call::
|
||||
|
||||
unregister_fprobe(&fp);
|
||||
|
||||
You can temporally (soft) disable the fprobe by::
|
||||
|
||||
disable_fprobe(&fp);
|
||||
|
||||
and resume by::
|
||||
|
||||
enable_fprobe(&fp);
|
||||
|
||||
The above is defined by including the header::
|
||||
|
||||
#include <linux/fprobe.h>
|
||||
|
||||
Same as ftrace, the registered callbacks will start being called some time
|
||||
after the register_fprobe() is called and before it returns. See
|
||||
:file:`Documentation/trace/ftrace.rst`.
|
||||
|
||||
Also, the unregister_fprobe() will guarantee that the both enter and exit
|
||||
handlers are no longer being called by functions after unregister_fprobe()
|
||||
returns as same as unregister_ftrace_function().
|
||||
|
||||
The fprobe entry/exit handler
|
||||
=============================
|
||||
|
||||
The prototype of the entry/exit callback function is as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void callback_func(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs);
|
||||
|
||||
Note that both entry and exit callbacks have same ptototype. The @entry_ip is
|
||||
saved at function entry and passed to exit handler.
|
||||
|
||||
@fp
|
||||
This is the address of `fprobe` data structure related to this handler.
|
||||
You can embed the `fprobe` to your data structure and get it by
|
||||
container_of() macro from @fp. The @fp must not be NULL.
|
||||
|
||||
@entry_ip
|
||||
This is the ftrace address of the traced function (both entry and exit).
|
||||
Note that this may not be the actual entry address of the function but
|
||||
the address where the ftrace is instrumented.
|
||||
|
||||
@regs
|
||||
This is the `pt_regs` data structure at the entry and exit. Note that
|
||||
the instruction pointer of @regs may be different from the @entry_ip
|
||||
in the entry_handler. If you need traced instruction pointer, you need
|
||||
to use @entry_ip. On the other hand, in the exit_handler, the instruction
|
||||
pointer of @regs is set to the currect return address.
|
||||
|
||||
Share the callbacks with kprobes
|
||||
================================
|
||||
|
||||
Since the recursion safeness of the fprobe (and ftrace) is a bit different
|
||||
from the kprobes, this may cause an issue if user wants to run the same
|
||||
code from the fprobe and the kprobes.
|
||||
|
||||
Kprobes has per-cpu 'current_kprobe' variable which protects the kprobe
|
||||
handler from recursion in all cases. On the other hand, fprobe uses
|
||||
only ftrace_test_recursion_trylock(). This allows interrupt context to
|
||||
call another (or same) fprobe while the fprobe user handler is running.
|
||||
|
||||
This is not a matter if the common callback code has its own recursion
|
||||
detection, or it can handle the recursion in the different contexts
|
||||
(normal/interrupt/NMI.)
|
||||
But if it relies on the 'current_kprobe' recursion lock, it has to check
|
||||
kprobe_running() and use kprobe_busy_*() APIs.
|
||||
|
||||
Fprobe has FPROBE_FL_KPROBE_SHARED flag to do this. If your common callback
|
||||
code will be shared with kprobes, please set FPROBE_FL_KPROBE_SHARED
|
||||
*before* registering the fprobe, like:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
fprobe.flags = FPROBE_FL_KPROBE_SHARED;
|
||||
|
||||
register_fprobe(&fprobe, "func*", NULL);
|
||||
|
||||
This will protect your common callback from the nested call.
|
||||
|
||||
The missed counter
|
||||
==================
|
||||
|
||||
The `fprobe` data structure has `fprobe::nmissed` counter field as same as
|
||||
kprobes.
|
||||
This counter counts up when;
|
||||
|
||||
- fprobe fails to take ftrace_recursion lock. This usually means that a function
|
||||
which is traced by other ftrace users is called from the entry_handler.
|
||||
|
||||
- fprobe fails to setup the function exit because of the shortage of rethook
|
||||
(the shadow stack for hooking the function return.)
|
||||
|
||||
The `fprobe::nmissed` field counts up in both cases. Therefore, the former
|
||||
skips both of entry and exit callback and the latter skips the exit
|
||||
callback, but in both case the counter will increase by 1.
|
||||
|
||||
Note that if you set the FTRACE_OPS_FL_RECURSION and/or FTRACE_OPS_FL_RCU to
|
||||
`fprobe::ops::flags` (ftrace_ops::flags) when registering the fprobe, this
|
||||
counter may not work correctly, because ftrace skips the fprobe function which
|
||||
increase the counter.
|
||||
|
||||
|
||||
Functions and structures
|
||||
========================
|
||||
|
||||
.. kernel-doc:: include/linux/fprobe.h
|
||||
.. kernel-doc:: kernel/trace/fprobe.c
|
||||
|
||||
@@ -9,6 +9,7 @@ Linux Tracing Technologies
|
||||
tracepoint-analysis
|
||||
ftrace
|
||||
ftrace-uses
|
||||
fprobe
|
||||
kprobes
|
||||
kprobetrace
|
||||
uprobetracer
|
||||
|
||||
+19
-8
@@ -3538,6 +3538,8 @@ F: net/sched/act_bpf.c
|
||||
F: net/sched/cls_bpf.c
|
||||
F: samples/bpf/
|
||||
F: scripts/bpf_doc.py
|
||||
F: scripts/pahole-flags.sh
|
||||
F: scripts/pahole-version.sh
|
||||
F: tools/bpf/
|
||||
F: tools/lib/bpf/
|
||||
F: tools/testing/selftests/bpf/
|
||||
@@ -3830,9 +3832,6 @@ BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
|
||||
M: Arend van Spriel <aspriel@gmail.com>
|
||||
M: Franky Lin <franky.lin@broadcom.com>
|
||||
M: Hante Meuleman <hante.meuleman@broadcom.com>
|
||||
M: Chi-hsien Lin <chi-hsien.lin@infineon.com>
|
||||
M: Wright Feng <wright.feng@infineon.com>
|
||||
M: Chung-hsien Hsu <chung-hsien.hsu@infineon.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: brcm80211-dev-list.pdl@broadcom.com
|
||||
L: SHA-cyfmac-dev-list@infineon.com
|
||||
@@ -7949,6 +7948,12 @@ L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/fujitsu-tablet.c
|
||||
|
||||
FUNGIBLE ETHERNET DRIVERS
|
||||
M: Dimitris Michailidis <dmichail@fungible.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/fungible/
|
||||
|
||||
FUSE: FILESYSTEM IN USERSPACE
|
||||
M: Miklos Szeredi <miklos@szeredi.hu>
|
||||
L: linux-fsdevel@vger.kernel.org
|
||||
@@ -10816,7 +10821,6 @@ L7 BPF FRAMEWORK
|
||||
M: John Fastabend <john.fastabend@gmail.com>
|
||||
M: Daniel Borkmann <daniel@iogearbox.net>
|
||||
M: Jakub Sitnicki <jakub@cloudflare.com>
|
||||
M: Lorenz Bauer <lmb@cloudflare.com>
|
||||
L: netdev@vger.kernel.org
|
||||
L: bpf@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -11384,6 +11388,13 @@ S: Maintained
|
||||
W: http://linux-test-project.github.io/
|
||||
T: git git://github.com/linux-test-project/ltp.git
|
||||
|
||||
LYNX 28G SERDES PHY DRIVER
|
||||
M: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
|
||||
F: drivers/phy/freescale/phy-fsl-lynx-28g.c
|
||||
|
||||
LYNX PCS MODULE
|
||||
M: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
@@ -12224,6 +12235,7 @@ R: Shayne Chen <shayne.chen@mediatek.com>
|
||||
R: Sean Wang <sean.wang@mediatek.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
|
||||
F: drivers/net/wireless/mediatek/mt76/
|
||||
|
||||
MEDIATEK MT7601U WIRELESS LAN DRIVER
|
||||
@@ -16003,8 +16015,8 @@ M: Kalle Valo <kvalo@kernel.org>
|
||||
L: ath11k@lists.infradead.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
|
||||
F: Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
|
||||
F: drivers/net/wireless/ath/ath11k/
|
||||
F: Documentation/devicetree/bindings/net/wireless/qcom,ath11k.txt
|
||||
|
||||
QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
|
||||
M: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
@@ -16453,9 +16465,8 @@ REALTEK RTL83xx SMI DSA ROUTER CHIPS
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
M: Alvin Šipraga <alsi@bang-olufsen.dk>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/dsa/realtek-smi.txt
|
||||
F: drivers/net/dsa/realtek-smi*
|
||||
F: drivers/net/dsa/rtl83*
|
||||
F: Documentation/devicetree/bindings/net/dsa/realtek.yaml
|
||||
F: drivers/net/dsa/realtek/*
|
||||
|
||||
REALTEK WIRELESS DRIVER (rtlwifi family)
|
||||
M: Ping-Ke Shih <pkshih@realtek.com>
|
||||
|
||||
@@ -133,6 +133,8 @@
|
||||
|
||||
#define SO_RESERVE_MEM 73
|
||||
|
||||
#define SO_TXREHASH 74
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
||||
@@ -1864,7 +1864,7 @@ static int build_body(struct jit_ctx *ctx)
|
||||
if (ctx->target == NULL)
|
||||
ctx->offsets[i] = ctx->idx;
|
||||
|
||||
/* If unsuccesfull, return with error code */
|
||||
/* If unsuccesful, return with error code */
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1973,7 +1973,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
* for jit, although it can decrease the size of the image.
|
||||
*
|
||||
* As each arm instruction is of length 32bit, we are translating
|
||||
* number of JITed intructions into the size required to store these
|
||||
* number of JITed instructions into the size required to store these
|
||||
* JITed code.
|
||||
*/
|
||||
image_size = sizeof(u32) * ctx.idx;
|
||||
|
||||
@@ -63,21 +63,25 @@
|
||||
&dpmac7 {
|
||||
sfp = <&sfp0>;
|
||||
managed = "in-band-status";
|
||||
phys = <&serdes_1 3>;
|
||||
};
|
||||
|
||||
&dpmac8 {
|
||||
sfp = <&sfp1>;
|
||||
managed = "in-band-status";
|
||||
phys = <&serdes_1 2>;
|
||||
};
|
||||
|
||||
&dpmac9 {
|
||||
sfp = <&sfp2>;
|
||||
managed = "in-band-status";
|
||||
phys = <&serdes_1 1>;
|
||||
};
|
||||
|
||||
&dpmac10 {
|
||||
sfp = <&sfp3>;
|
||||
managed = "in-band-status";
|
||||
phys = <&serdes_1 0>;
|
||||
};
|
||||
|
||||
&emdio2 {
|
||||
|
||||
@@ -612,6 +612,12 @@
|
||||
ranges;
|
||||
dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>;
|
||||
|
||||
serdes_1: phy@1ea0000 {
|
||||
compatible = "fsl,lynx-28g";
|
||||
reg = <0x0 0x1ea0000 0x0 0x1e30>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
crypto: crypto@8000000 {
|
||||
compatible = "fsl,sec-v5.0", "fsl,sec-v4.0";
|
||||
fsl,sec-era = <10>;
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
phy-handle = <ðernet_phy0>;
|
||||
mediatek,tx-delay-ps = <1530>;
|
||||
snps,reset-gpio = <&pio 87 GPIO_ACTIVE_LOW>;
|
||||
snps,reset-delays-us = <0 10000 10000>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <ð_default>;
|
||||
pinctrl-1 = <ð_sleep>;
|
||||
|
||||
@@ -726,7 +726,7 @@
|
||||
};
|
||||
|
||||
eth: ethernet@1101c000 {
|
||||
compatible = "mediatek,mt2712-gmac";
|
||||
compatible = "mediatek,mt2712-gmac", "snps,dwmac-4.20a";
|
||||
reg = <0 0x1101c000 0 0x1300>;
|
||||
interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-names = "macirq";
|
||||
@@ -734,15 +734,19 @@
|
||||
clock-names = "axi",
|
||||
"apb",
|
||||
"mac_main",
|
||||
"ptp_ref";
|
||||
"ptp_ref",
|
||||
"rmii_internal";
|
||||
clocks = <&pericfg CLK_PERI_GMAC>,
|
||||
<&pericfg CLK_PERI_GMAC_PCLK>,
|
||||
<&topckgen CLK_TOP_ETHER_125M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>;
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_RMII_SEL>;
|
||||
assigned-clocks = <&topckgen CLK_TOP_ETHER_125M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>;
|
||||
<&topckgen CLK_TOP_ETHER_50M_SEL>,
|
||||
<&topckgen CLK_TOP_ETHER_50M_RMII_SEL>;
|
||||
assigned-clock-parents = <&topckgen CLK_TOP_ETHERPLL_125M>,
|
||||
<&topckgen CLK_TOP_APLL1_D3>;
|
||||
<&topckgen CLK_TOP_APLL1_D3>,
|
||||
<&topckgen CLK_TOP_ETHERPLL_50M>;
|
||||
power-domains = <&scpsys MT2712_POWER_DOMAIN_AUDIO>;
|
||||
mediatek,pericfg = <&pericfg>;
|
||||
snps,axi-config = <&stmmac_axi_setup>;
|
||||
|
||||
@@ -471,9 +471,10 @@
|
||||
<0x6 0x10004000 0x7fc000>,
|
||||
<0x6 0x11010000 0xaf0000>;
|
||||
reg-names = "cpu", "dev", "gcb";
|
||||
interrupt-names = "xtr", "fdma";
|
||||
interrupt-names = "xtr", "fdma", "ptp";
|
||||
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
<GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
|
||||
resets = <&reset 0>;
|
||||
reset-names = "switch";
|
||||
};
|
||||
|
||||
@@ -510,6 +510,8 @@
|
||||
#size-cells = <0>;
|
||||
iommus = <&smmu 0x874>;
|
||||
power-domains = <&zynqmp_firmware PD_ETH_0>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_GEM0>;
|
||||
reset-names = "gem0_rst";
|
||||
};
|
||||
|
||||
gem1: ethernet@ff0c0000 {
|
||||
@@ -523,6 +525,8 @@
|
||||
#size-cells = <0>;
|
||||
iommus = <&smmu 0x875>;
|
||||
power-domains = <&zynqmp_firmware PD_ETH_1>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_GEM1>;
|
||||
reset-names = "gem1_rst";
|
||||
};
|
||||
|
||||
gem2: ethernet@ff0d0000 {
|
||||
@@ -536,6 +540,8 @@
|
||||
#size-cells = <0>;
|
||||
iommus = <&smmu 0x876>;
|
||||
power-domains = <&zynqmp_firmware PD_ETH_2>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_GEM2>;
|
||||
reset-names = "gem2_rst";
|
||||
};
|
||||
|
||||
gem3: ethernet@ff0e0000 {
|
||||
@@ -549,6 +555,8 @@
|
||||
#size-cells = <0>;
|
||||
iommus = <&smmu 0x877>;
|
||||
power-domains = <&zynqmp_firmware PD_ETH_3>;
|
||||
resets = <&zynqmp_reset ZYNQMP_RESET_GEM3>;
|
||||
reset-names = "gem3_rst";
|
||||
};
|
||||
|
||||
gpio: gpio@ff0a0000 {
|
||||
|
||||
@@ -88,17 +88,42 @@
|
||||
/* [Rn] = Rt; (atomic) Rs = [state] */
|
||||
#define A64_STXR(sf, Rt, Rn, Rs) \
|
||||
A64_LSX(sf, Rt, Rn, Rs, STORE_EX)
|
||||
/* [Rn] = Rt (store release); (atomic) Rs = [state] */
|
||||
#define A64_STLXR(sf, Rt, Rn, Rs) \
|
||||
aarch64_insn_gen_load_store_ex(Rt, Rn, Rs, A64_SIZE(sf), \
|
||||
AARCH64_INSN_LDST_STORE_REL_EX)
|
||||
|
||||
/*
|
||||
* LSE atomics
|
||||
*
|
||||
* STADD is simply encoded as an alias for LDADD with XZR as
|
||||
* the destination register.
|
||||
* ST{ADD,CLR,SET,EOR} is simply encoded as an alias for
|
||||
* LDD{ADD,CLR,SET,EOR} with XZR as the destination register.
|
||||
*/
|
||||
#define A64_STADD(sf, Rn, Rs) \
|
||||
#define A64_ST_OP(sf, Rn, Rs, op) \
|
||||
aarch64_insn_gen_atomic_ld_op(A64_ZR, Rn, Rs, \
|
||||
A64_SIZE(sf), AARCH64_INSN_MEM_ATOMIC_ADD, \
|
||||
A64_SIZE(sf), AARCH64_INSN_MEM_ATOMIC_##op, \
|
||||
AARCH64_INSN_MEM_ORDER_NONE)
|
||||
/* [Rn] <op>= Rs */
|
||||
#define A64_STADD(sf, Rn, Rs) A64_ST_OP(sf, Rn, Rs, ADD)
|
||||
#define A64_STCLR(sf, Rn, Rs) A64_ST_OP(sf, Rn, Rs, CLR)
|
||||
#define A64_STEOR(sf, Rn, Rs) A64_ST_OP(sf, Rn, Rs, EOR)
|
||||
#define A64_STSET(sf, Rn, Rs) A64_ST_OP(sf, Rn, Rs, SET)
|
||||
|
||||
#define A64_LD_OP_AL(sf, Rt, Rn, Rs, op) \
|
||||
aarch64_insn_gen_atomic_ld_op(Rt, Rn, Rs, \
|
||||
A64_SIZE(sf), AARCH64_INSN_MEM_ATOMIC_##op, \
|
||||
AARCH64_INSN_MEM_ORDER_ACQREL)
|
||||
/* Rt = [Rn] (load acquire); [Rn] <op>= Rs (store release) */
|
||||
#define A64_LDADDAL(sf, Rt, Rn, Rs) A64_LD_OP_AL(sf, Rt, Rn, Rs, ADD)
|
||||
#define A64_LDCLRAL(sf, Rt, Rn, Rs) A64_LD_OP_AL(sf, Rt, Rn, Rs, CLR)
|
||||
#define A64_LDEORAL(sf, Rt, Rn, Rs) A64_LD_OP_AL(sf, Rt, Rn, Rs, EOR)
|
||||
#define A64_LDSETAL(sf, Rt, Rn, Rs) A64_LD_OP_AL(sf, Rt, Rn, Rs, SET)
|
||||
/* Rt = [Rn] (load acquire); [Rn] = Rs (store release) */
|
||||
#define A64_SWPAL(sf, Rt, Rn, Rs) A64_LD_OP_AL(sf, Rt, Rn, Rs, SWP)
|
||||
/* Rs = CAS(Rn, Rs, Rt) (load acquire & store release) */
|
||||
#define A64_CASAL(sf, Rt, Rn, Rs) \
|
||||
aarch64_insn_gen_cas(Rt, Rn, Rs, A64_SIZE(sf), \
|
||||
AARCH64_INSN_MEM_ORDER_ACQREL)
|
||||
|
||||
/* Add/subtract (immediate) */
|
||||
#define A64_ADDSUB_IMM(sf, Rd, Rn, imm12, type) \
|
||||
@@ -203,6 +228,9 @@
|
||||
#define A64_ANDS(sf, Rd, Rn, Rm) A64_LOGIC_SREG(sf, Rd, Rn, Rm, AND_SETFLAGS)
|
||||
/* Rn & Rm; set condition flags */
|
||||
#define A64_TST(sf, Rn, Rm) A64_ANDS(sf, A64_ZR, Rn, Rm)
|
||||
/* Rd = ~Rm (alias of ORN with A64_ZR as Rn) */
|
||||
#define A64_MVN(sf, Rd, Rm) \
|
||||
A64_LOGIC_SREG(sf, Rd, A64_ZR, Rm, ORN)
|
||||
|
||||
/* Logical (immediate) */
|
||||
#define A64_LOGIC_IMM(sf, Rd, Rn, imm, type) ({ \
|
||||
@@ -226,4 +254,7 @@
|
||||
#define A64_BTI_J A64_HINT(AARCH64_INSN_HINT_BTIJ)
|
||||
#define A64_BTI_JC A64_HINT(AARCH64_INSN_HINT_BTIJC)
|
||||
|
||||
/* DMB */
|
||||
#define A64_DMB_ISH aarch64_insn_gen_dmb(AARCH64_INSN_MB_ISH)
|
||||
|
||||
#endif /* _BPF_JIT_H */
|
||||
|
||||
+200
-46
@@ -27,6 +27,17 @@
|
||||
#define TCALL_CNT (MAX_BPF_JIT_REG + 2)
|
||||
#define TMP_REG_3 (MAX_BPF_JIT_REG + 3)
|
||||
|
||||
#define check_imm(bits, imm) do { \
|
||||
if ((((imm) > 0) && ((imm) >> (bits))) || \
|
||||
(((imm) < 0) && (~(imm) >> (bits)))) { \
|
||||
pr_info("[%2d] imm=%d(0x%x) out of range\n", \
|
||||
i, imm, imm); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define check_imm19(imm) check_imm(19, imm)
|
||||
#define check_imm26(imm) check_imm(26, imm)
|
||||
|
||||
/* Map BPF registers to A64 registers */
|
||||
static const int bpf2a64[] = {
|
||||
/* return value from in-kernel function, and exit value from eBPF */
|
||||
@@ -329,6 +340,170 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
|
||||
#undef jmp_offset
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64_LSE_ATOMICS
|
||||
static int emit_lse_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
{
|
||||
const u8 code = insn->code;
|
||||
const u8 dst = bpf2a64[insn->dst_reg];
|
||||
const u8 src = bpf2a64[insn->src_reg];
|
||||
const u8 tmp = bpf2a64[TMP_REG_1];
|
||||
const u8 tmp2 = bpf2a64[TMP_REG_2];
|
||||
const bool isdw = BPF_SIZE(code) == BPF_DW;
|
||||
const s16 off = insn->off;
|
||||
u8 reg;
|
||||
|
||||
if (!off) {
|
||||
reg = dst;
|
||||
} else {
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_ADD(1, tmp, tmp, dst), ctx);
|
||||
reg = tmp;
|
||||
}
|
||||
|
||||
switch (insn->imm) {
|
||||
/* lock *(u32/u64 *)(dst_reg + off) <op>= src_reg */
|
||||
case BPF_ADD:
|
||||
emit(A64_STADD(isdw, reg, src), ctx);
|
||||
break;
|
||||
case BPF_AND:
|
||||
emit(A64_MVN(isdw, tmp2, src), ctx);
|
||||
emit(A64_STCLR(isdw, reg, tmp2), ctx);
|
||||
break;
|
||||
case BPF_OR:
|
||||
emit(A64_STSET(isdw, reg, src), ctx);
|
||||
break;
|
||||
case BPF_XOR:
|
||||
emit(A64_STEOR(isdw, reg, src), ctx);
|
||||
break;
|
||||
/* src_reg = atomic_fetch_<op>(dst_reg + off, src_reg) */
|
||||
case BPF_ADD | BPF_FETCH:
|
||||
emit(A64_LDADDAL(isdw, src, reg, src), ctx);
|
||||
break;
|
||||
case BPF_AND | BPF_FETCH:
|
||||
emit(A64_MVN(isdw, tmp2, src), ctx);
|
||||
emit(A64_LDCLRAL(isdw, src, reg, tmp2), ctx);
|
||||
break;
|
||||
case BPF_OR | BPF_FETCH:
|
||||
emit(A64_LDSETAL(isdw, src, reg, src), ctx);
|
||||
break;
|
||||
case BPF_XOR | BPF_FETCH:
|
||||
emit(A64_LDEORAL(isdw, src, reg, src), ctx);
|
||||
break;
|
||||
/* src_reg = atomic_xchg(dst_reg + off, src_reg); */
|
||||
case BPF_XCHG:
|
||||
emit(A64_SWPAL(isdw, src, reg, src), ctx);
|
||||
break;
|
||||
/* r0 = atomic_cmpxchg(dst_reg + off, r0, src_reg); */
|
||||
case BPF_CMPXCHG:
|
||||
emit(A64_CASAL(isdw, src, reg, bpf2a64[BPF_REG_0]), ctx);
|
||||
break;
|
||||
default:
|
||||
pr_err_once("unknown atomic op code %02x\n", insn->imm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int emit_lse_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int emit_ll_sc_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
{
|
||||
const u8 code = insn->code;
|
||||
const u8 dst = bpf2a64[insn->dst_reg];
|
||||
const u8 src = bpf2a64[insn->src_reg];
|
||||
const u8 tmp = bpf2a64[TMP_REG_1];
|
||||
const u8 tmp2 = bpf2a64[TMP_REG_2];
|
||||
const u8 tmp3 = bpf2a64[TMP_REG_3];
|
||||
const int i = insn - ctx->prog->insnsi;
|
||||
const s32 imm = insn->imm;
|
||||
const s16 off = insn->off;
|
||||
const bool isdw = BPF_SIZE(code) == BPF_DW;
|
||||
u8 reg;
|
||||
s32 jmp_offset;
|
||||
|
||||
if (!off) {
|
||||
reg = dst;
|
||||
} else {
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_ADD(1, tmp, tmp, dst), ctx);
|
||||
reg = tmp;
|
||||
}
|
||||
|
||||
if (imm == BPF_ADD || imm == BPF_AND ||
|
||||
imm == BPF_OR || imm == BPF_XOR) {
|
||||
/* lock *(u32/u64 *)(dst_reg + off) <op>= src_reg */
|
||||
emit(A64_LDXR(isdw, tmp2, reg), ctx);
|
||||
if (imm == BPF_ADD)
|
||||
emit(A64_ADD(isdw, tmp2, tmp2, src), ctx);
|
||||
else if (imm == BPF_AND)
|
||||
emit(A64_AND(isdw, tmp2, tmp2, src), ctx);
|
||||
else if (imm == BPF_OR)
|
||||
emit(A64_ORR(isdw, tmp2, tmp2, src), ctx);
|
||||
else
|
||||
emit(A64_EOR(isdw, tmp2, tmp2, src), ctx);
|
||||
emit(A64_STXR(isdw, tmp2, reg, tmp3), ctx);
|
||||
jmp_offset = -3;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(0, tmp3, jmp_offset), ctx);
|
||||
} else if (imm == (BPF_ADD | BPF_FETCH) ||
|
||||
imm == (BPF_AND | BPF_FETCH) ||
|
||||
imm == (BPF_OR | BPF_FETCH) ||
|
||||
imm == (BPF_XOR | BPF_FETCH)) {
|
||||
/* src_reg = atomic_fetch_<op>(dst_reg + off, src_reg) */
|
||||
const u8 ax = bpf2a64[BPF_REG_AX];
|
||||
|
||||
emit(A64_MOV(isdw, ax, src), ctx);
|
||||
emit(A64_LDXR(isdw, src, reg), ctx);
|
||||
if (imm == (BPF_ADD | BPF_FETCH))
|
||||
emit(A64_ADD(isdw, tmp2, src, ax), ctx);
|
||||
else if (imm == (BPF_AND | BPF_FETCH))
|
||||
emit(A64_AND(isdw, tmp2, src, ax), ctx);
|
||||
else if (imm == (BPF_OR | BPF_FETCH))
|
||||
emit(A64_ORR(isdw, tmp2, src, ax), ctx);
|
||||
else
|
||||
emit(A64_EOR(isdw, tmp2, src, ax), ctx);
|
||||
emit(A64_STLXR(isdw, tmp2, reg, tmp3), ctx);
|
||||
jmp_offset = -3;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(0, tmp3, jmp_offset), ctx);
|
||||
emit(A64_DMB_ISH, ctx);
|
||||
} else if (imm == BPF_XCHG) {
|
||||
/* src_reg = atomic_xchg(dst_reg + off, src_reg); */
|
||||
emit(A64_MOV(isdw, tmp2, src), ctx);
|
||||
emit(A64_LDXR(isdw, src, reg), ctx);
|
||||
emit(A64_STLXR(isdw, tmp2, reg, tmp3), ctx);
|
||||
jmp_offset = -2;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(0, tmp3, jmp_offset), ctx);
|
||||
emit(A64_DMB_ISH, ctx);
|
||||
} else if (imm == BPF_CMPXCHG) {
|
||||
/* r0 = atomic_cmpxchg(dst_reg + off, r0, src_reg); */
|
||||
const u8 r0 = bpf2a64[BPF_REG_0];
|
||||
|
||||
emit(A64_MOV(isdw, tmp2, r0), ctx);
|
||||
emit(A64_LDXR(isdw, r0, reg), ctx);
|
||||
emit(A64_EOR(isdw, tmp3, r0, tmp2), ctx);
|
||||
jmp_offset = 4;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(isdw, tmp3, jmp_offset), ctx);
|
||||
emit(A64_STLXR(isdw, src, reg, tmp3), ctx);
|
||||
jmp_offset = -4;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(0, tmp3, jmp_offset), ctx);
|
||||
emit(A64_DMB_ISH, ctx);
|
||||
} else {
|
||||
pr_err_once("unknown atomic op code %02x\n", imm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void build_epilogue(struct jit_ctx *ctx)
|
||||
{
|
||||
const u8 r0 = bpf2a64[BPF_REG_0];
|
||||
@@ -434,29 +609,16 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
||||
const u8 src = bpf2a64[insn->src_reg];
|
||||
const u8 tmp = bpf2a64[TMP_REG_1];
|
||||
const u8 tmp2 = bpf2a64[TMP_REG_2];
|
||||
const u8 tmp3 = bpf2a64[TMP_REG_3];
|
||||
const s16 off = insn->off;
|
||||
const s32 imm = insn->imm;
|
||||
const int i = insn - ctx->prog->insnsi;
|
||||
const bool is64 = BPF_CLASS(code) == BPF_ALU64 ||
|
||||
BPF_CLASS(code) == BPF_JMP;
|
||||
const bool isdw = BPF_SIZE(code) == BPF_DW;
|
||||
u8 jmp_cond, reg;
|
||||
u8 jmp_cond;
|
||||
s32 jmp_offset;
|
||||
u32 a64_insn;
|
||||
int ret;
|
||||
|
||||
#define check_imm(bits, imm) do { \
|
||||
if ((((imm) > 0) && ((imm) >> (bits))) || \
|
||||
(((imm) < 0) && (~(imm) >> (bits)))) { \
|
||||
pr_info("[%2d] imm=%d(0x%x) out of range\n", \
|
||||
i, imm, imm); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define check_imm19(imm) check_imm(19, imm)
|
||||
#define check_imm26(imm) check_imm(26, imm)
|
||||
|
||||
switch (code) {
|
||||
/* dst = src */
|
||||
case BPF_ALU | BPF_MOV | BPF_X:
|
||||
@@ -891,33 +1053,12 @@ emit_cond_jmp:
|
||||
|
||||
case BPF_STX | BPF_ATOMIC | BPF_W:
|
||||
case BPF_STX | BPF_ATOMIC | BPF_DW:
|
||||
if (insn->imm != BPF_ADD) {
|
||||
pr_err_once("unknown atomic op code %02x\n", insn->imm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* STX XADD: lock *(u32 *)(dst + off) += src
|
||||
* and
|
||||
* STX XADD: lock *(u64 *)(dst + off) += src
|
||||
*/
|
||||
|
||||
if (!off) {
|
||||
reg = dst;
|
||||
} else {
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_ADD(1, tmp, tmp, dst), ctx);
|
||||
reg = tmp;
|
||||
}
|
||||
if (cpus_have_cap(ARM64_HAS_LSE_ATOMICS)) {
|
||||
emit(A64_STADD(isdw, reg, src), ctx);
|
||||
} else {
|
||||
emit(A64_LDXR(isdw, tmp2, reg), ctx);
|
||||
emit(A64_ADD(isdw, tmp2, tmp2, src), ctx);
|
||||
emit(A64_STXR(isdw, tmp2, reg, tmp3), ctx);
|
||||
jmp_offset = -3;
|
||||
check_imm19(jmp_offset);
|
||||
emit(A64_CBNZ(0, tmp3, jmp_offset), ctx);
|
||||
}
|
||||
if (cpus_have_cap(ARM64_HAS_LSE_ATOMICS))
|
||||
ret = emit_lse_atomic(insn, ctx);
|
||||
else
|
||||
ret = emit_ll_sc_atomic(insn, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1049,15 +1190,18 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
/* 1. Initial fake pass to compute ctx->idx. */
|
||||
|
||||
/* Fake pass to fill in ctx->offset. */
|
||||
if (build_body(&ctx, extra_pass)) {
|
||||
/*
|
||||
* 1. Initial fake pass to compute ctx->idx and ctx->offset.
|
||||
*
|
||||
* BPF line info needs ctx->offset[i] to be the offset of
|
||||
* instruction[i] in jited image, so build prologue first.
|
||||
*/
|
||||
if (build_prologue(&ctx, was_classic)) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
if (build_prologue(&ctx, was_classic)) {
|
||||
if (build_body(&ctx, extra_pass)) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
@@ -1130,6 +1274,11 @@ skip_init_ctx:
|
||||
prog->jited_len = prog_size;
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
int i;
|
||||
|
||||
/* offset[prog->len] is the size of program */
|
||||
for (i = 0; i <= prog->len; i++)
|
||||
ctx.offset[i] *= AARCH64_INSN_SIZE;
|
||||
bpf_prog_fill_jited_linfo(prog, ctx.offset + 1);
|
||||
out_off:
|
||||
kfree(ctx.offset);
|
||||
@@ -1143,6 +1292,11 @@ out:
|
||||
return prog;
|
||||
}
|
||||
|
||||
bool bpf_jit_supports_kfunc_call(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 bpf_jit_alloc_exec_limit(void)
|
||||
{
|
||||
return VMALLOC_END - VMALLOC_START;
|
||||
|
||||
@@ -144,6 +144,8 @@
|
||||
|
||||
#define SO_RESERVE_MEM 73
|
||||
|
||||
#define SO_TXREHASH 74
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
||||
@@ -125,6 +125,8 @@
|
||||
|
||||
#define SO_RESERVE_MEM 0x4047
|
||||
|
||||
#define SO_TXREHASH 0x4048
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
||||
@@ -112,6 +112,13 @@ static __always_inline __wsum csum_add(__wsum csum, __wsum addend)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define HAVE_ARCH_CSUM_SHIFT
|
||||
static __always_inline __wsum csum_shift(__wsum sum, int offset)
|
||||
{
|
||||
/* rotate sum to align it with a 16b boundary */
|
||||
return (__force __wsum)rol32((__force u32)sum, (offset & 1) << 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a version of ip_compute_csum() optimized for IP headers,
|
||||
* which always checksum on 4 octet boundaries. ihl is the number
|
||||
|
||||
@@ -264,7 +264,7 @@ skip_codegen_passes:
|
||||
fp->jited = 1;
|
||||
fp->jited_len = proglen + FUNCTION_DESCR_SIZE;
|
||||
|
||||
bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE));
|
||||
bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + bpf_hdr->size);
|
||||
if (!fp->is_func || extra_pass) {
|
||||
bpf_jit_binary_lock_ro(bpf_hdr);
|
||||
bpf_prog_fill_jited_linfo(fp, addrs);
|
||||
|
||||
@@ -126,6 +126,8 @@
|
||||
|
||||
#define SO_RESERVE_MEM 0x0052
|
||||
|
||||
#define SO_TXREHASH 0x0053
|
||||
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
|
||||
@@ -1599,7 +1599,7 @@ skip_init_ctx:
|
||||
if (bpf_jit_enable > 1)
|
||||
bpf_jit_dump(prog->len, image_size, pass, ctx.image);
|
||||
|
||||
bpf_flush_icache(header, (u8 *)header + (header->pages * PAGE_SIZE));
|
||||
bpf_flush_icache(header, (u8 *)header + header->size);
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
bpf_jit_binary_lock_ro(header);
|
||||
|
||||
@@ -161,6 +161,7 @@ config X86
|
||||
select HAVE_ALIGNED_STRUCT_PAGE if SLUB
|
||||
select HAVE_ARCH_AUDITSYSCALL
|
||||
select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE
|
||||
select HAVE_ARCH_HUGE_VMALLOC if X86_64
|
||||
select HAVE_ARCH_JUMP_LABEL
|
||||
select HAVE_ARCH_JUMP_LABEL_RELATIVE
|
||||
select HAVE_ARCH_KASAN if X86_64
|
||||
|
||||
@@ -44,6 +44,7 @@ extern void text_poke_early(void *addr, const void *opcode, size_t len);
|
||||
extern void *text_poke(void *addr, const void *opcode, size_t len);
|
||||
extern void text_poke_sync(void);
|
||||
extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);
|
||||
extern void *text_poke_copy(void *addr, const void *opcode, size_t len);
|
||||
extern int poke_int3_handler(struct pt_regs *regs);
|
||||
extern void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate);
|
||||
|
||||
|
||||
@@ -1102,6 +1102,40 @@ void *text_poke_kgdb(void *addr, const void *opcode, size_t len)
|
||||
return __text_poke(addr, opcode, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* text_poke_copy - Copy instructions into (an unused part of) RX memory
|
||||
* @addr: address to modify
|
||||
* @opcode: source of the copy
|
||||
* @len: length to copy, could be more than 2x PAGE_SIZE
|
||||
*
|
||||
* Not safe against concurrent execution; useful for JITs to dump
|
||||
* new code blocks into unused regions of RX memory. Can be used in
|
||||
* conjunction with synchronize_rcu_tasks() to wait for existing
|
||||
* execution to quiesce after having made sure no existing functions
|
||||
* pointers are live.
|
||||
*/
|
||||
void *text_poke_copy(void *addr, const void *opcode, size_t len)
|
||||
{
|
||||
unsigned long start = (unsigned long)addr;
|
||||
size_t patched = 0;
|
||||
|
||||
if (WARN_ON_ONCE(core_kernel_text(start)))
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&text_mutex);
|
||||
while (patched < len) {
|
||||
unsigned long ptr = start + patched;
|
||||
size_t s;
|
||||
|
||||
s = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(ptr), len - patched);
|
||||
|
||||
__text_poke((void *)ptr, opcode + patched, s);
|
||||
patched += s;
|
||||
}
|
||||
mutex_unlock(&text_mutex);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void do_sync_core(void *info)
|
||||
{
|
||||
sync_core();
|
||||
|
||||
+53
-29
@@ -330,8 +330,7 @@ static int emit_jump(u8 **pprog, void *func, void *ip)
|
||||
}
|
||||
|
||||
static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
|
||||
void *old_addr, void *new_addr,
|
||||
const bool text_live)
|
||||
void *old_addr, void *new_addr)
|
||||
{
|
||||
const u8 *nop_insn = x86_nops[5];
|
||||
u8 old_insn[X86_PATCH_SIZE];
|
||||
@@ -365,10 +364,7 @@ static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
|
||||
goto out;
|
||||
ret = 1;
|
||||
if (memcmp(ip, new_insn, X86_PATCH_SIZE)) {
|
||||
if (text_live)
|
||||
text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
|
||||
else
|
||||
memcpy(ip, new_insn, X86_PATCH_SIZE);
|
||||
text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
|
||||
ret = 0;
|
||||
}
|
||||
out:
|
||||
@@ -384,7 +380,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
|
||||
/* BPF poking in modules is not supported */
|
||||
return -EINVAL;
|
||||
|
||||
return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true);
|
||||
return __bpf_arch_text_poke(ip, t, old_addr, new_addr);
|
||||
}
|
||||
|
||||
#define EMIT_LFENCE() EMIT3(0x0F, 0xAE, 0xE8)
|
||||
@@ -558,24 +554,15 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog)
|
||||
mutex_lock(&array->aux->poke_mutex);
|
||||
target = array->ptrs[poke->tail_call.key];
|
||||
if (target) {
|
||||
/* Plain memcpy is used when image is not live yet
|
||||
* and still not locked as read-only. Once poke
|
||||
* location is active (poke->tailcall_target_stable),
|
||||
* any parallel bpf_arch_text_poke() might occur
|
||||
* still on the read-write image until we finally
|
||||
* locked it as read-only. Both modifications on
|
||||
* the given image are under text_mutex to avoid
|
||||
* interference.
|
||||
*/
|
||||
ret = __bpf_arch_text_poke(poke->tailcall_target,
|
||||
BPF_MOD_JUMP, NULL,
|
||||
(u8 *)target->bpf_func +
|
||||
poke->adj_off, false);
|
||||
poke->adj_off);
|
||||
BUG_ON(ret < 0);
|
||||
ret = __bpf_arch_text_poke(poke->tailcall_bypass,
|
||||
BPF_MOD_JUMP,
|
||||
(u8 *)poke->tailcall_target +
|
||||
X86_PATCH_SIZE, NULL, false);
|
||||
X86_PATCH_SIZE, NULL);
|
||||
BUG_ON(ret < 0);
|
||||
}
|
||||
WRITE_ONCE(poke->tailcall_target_stable, true);
|
||||
@@ -787,7 +774,6 @@ static int emit_atomic(u8 **pprog, u8 atomic_op,
|
||||
/* emit opcode */
|
||||
switch (atomic_op) {
|
||||
case BPF_ADD:
|
||||
case BPF_SUB:
|
||||
case BPF_AND:
|
||||
case BPF_OR:
|
||||
case BPF_XOR:
|
||||
@@ -867,7 +853,7 @@ static void emit_nops(u8 **pprog, int len)
|
||||
|
||||
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
|
||||
|
||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
|
||||
int oldproglen, struct jit_context *ctx, bool jmp_padding)
|
||||
{
|
||||
bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
|
||||
@@ -894,8 +880,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||
push_callee_regs(&prog, callee_regs_used);
|
||||
|
||||
ilen = prog - temp;
|
||||
if (image)
|
||||
memcpy(image + proglen, temp, ilen);
|
||||
if (rw_image)
|
||||
memcpy(rw_image + proglen, temp, ilen);
|
||||
proglen += ilen;
|
||||
addrs[0] = proglen;
|
||||
prog = temp;
|
||||
@@ -1324,6 +1310,9 @@ st: if (is_imm8(insn->off))
|
||||
pr_err("extable->insn doesn't fit into 32-bit\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
/* switch ex to rw buffer for writes */
|
||||
ex = (void *)rw_image + ((void *)ex - (void *)image);
|
||||
|
||||
ex->insn = delta;
|
||||
|
||||
ex->data = EX_TYPE_BPF;
|
||||
@@ -1706,7 +1695,7 @@ emit_jmp:
|
||||
pr_err("bpf_jit: fatal error\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
memcpy(image + proglen, temp, ilen);
|
||||
memcpy(rw_image + proglen, temp, ilen);
|
||||
}
|
||||
proglen += ilen;
|
||||
addrs[i] = proglen;
|
||||
@@ -2247,6 +2236,7 @@ int arch_prepare_bpf_dispatcher(void *image, s64 *funcs, int num_funcs)
|
||||
}
|
||||
|
||||
struct x64_jit_data {
|
||||
struct bpf_binary_header *rw_header;
|
||||
struct bpf_binary_header *header;
|
||||
int *addrs;
|
||||
u8 *image;
|
||||
@@ -2259,6 +2249,7 @@ struct x64_jit_data {
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_binary_header *rw_header = NULL;
|
||||
struct bpf_binary_header *header = NULL;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct x64_jit_data *jit_data;
|
||||
@@ -2267,6 +2258,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
bool tmp_blinded = false;
|
||||
bool extra_pass = false;
|
||||
bool padding = false;
|
||||
u8 *rw_image = NULL;
|
||||
u8 *image = NULL;
|
||||
int *addrs;
|
||||
int pass;
|
||||
@@ -2302,6 +2294,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
oldproglen = jit_data->proglen;
|
||||
image = jit_data->image;
|
||||
header = jit_data->header;
|
||||
rw_header = jit_data->rw_header;
|
||||
rw_image = (void *)rw_header + ((void *)image - (void *)header);
|
||||
extra_pass = true;
|
||||
padding = true;
|
||||
goto skip_init_addrs;
|
||||
@@ -2332,13 +2326,22 @@ skip_init_addrs:
|
||||
for (pass = 0; pass < MAX_PASSES || image; pass++) {
|
||||
if (!padding && pass >= PADDING_PASSES)
|
||||
padding = true;
|
||||
proglen = do_jit(prog, addrs, image, oldproglen, &ctx, padding);
|
||||
proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
|
||||
if (proglen <= 0) {
|
||||
out_image:
|
||||
image = NULL;
|
||||
if (header)
|
||||
bpf_jit_binary_free(header);
|
||||
if (header) {
|
||||
bpf_arch_text_copy(&header->size, &rw_header->size,
|
||||
sizeof(rw_header->size));
|
||||
bpf_jit_binary_pack_free(header, rw_header);
|
||||
}
|
||||
/* Fall back to interpreter mode */
|
||||
prog = orig_prog;
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
}
|
||||
goto out_addrs;
|
||||
}
|
||||
if (image) {
|
||||
@@ -2361,8 +2364,9 @@ out_image:
|
||||
sizeof(struct exception_table_entry);
|
||||
|
||||
/* allocate module memory for x86 insns and extable */
|
||||
header = bpf_jit_binary_alloc(roundup(proglen, align) + extable_size,
|
||||
&image, align, jit_fill_hole);
|
||||
header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
|
||||
&image, align, &rw_header, &rw_image,
|
||||
jit_fill_hole);
|
||||
if (!header) {
|
||||
prog = orig_prog;
|
||||
goto out_addrs;
|
||||
@@ -2378,14 +2382,27 @@ out_image:
|
||||
|
||||
if (image) {
|
||||
if (!prog->is_func || extra_pass) {
|
||||
/*
|
||||
* bpf_jit_binary_pack_finalize fails in two scenarios:
|
||||
* 1) header is not pointing to proper module memory;
|
||||
* 2) the arch doesn't support bpf_arch_text_copy().
|
||||
*
|
||||
* Both cases are serious bugs and justify WARN_ON.
|
||||
*/
|
||||
if (WARN_ON(bpf_jit_binary_pack_finalize(prog, header, rw_header))) {
|
||||
/* header has been freed */
|
||||
header = NULL;
|
||||
goto out_image;
|
||||
}
|
||||
|
||||
bpf_tail_call_direct_fixup(prog);
|
||||
bpf_jit_binary_lock_ro(header);
|
||||
} else {
|
||||
jit_data->addrs = addrs;
|
||||
jit_data->ctx = ctx;
|
||||
jit_data->proglen = proglen;
|
||||
jit_data->image = image;
|
||||
jit_data->header = header;
|
||||
jit_data->rw_header = rw_header;
|
||||
}
|
||||
prog->bpf_func = (void *)image;
|
||||
prog->jited = 1;
|
||||
@@ -2413,3 +2430,10 @@ bool bpf_jit_supports_kfunc_call(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void *bpf_arch_text_copy(void *dst, void *src, size_t len)
|
||||
{
|
||||
if (text_poke_copy(dst, src, len) == NULL)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ static int iss_net_rx(struct net_device *dev)
|
||||
|
||||
lp->stats.rx_bytes += skb->len;
|
||||
lp->stats.rx_packets++;
|
||||
netif_rx_ni(skb);
|
||||
netif_rx(skb);
|
||||
return pkt_len;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
@@ -861,7 +861,6 @@ static void ns_init_card_error(ns_dev *card, int error)
|
||||
static scq_info *get_scq(ns_dev *card, int size, u32 scd)
|
||||
{
|
||||
scq_info *scq;
|
||||
int i;
|
||||
|
||||
if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
|
||||
return NULL;
|
||||
@@ -875,9 +874,8 @@ static scq_info *get_scq(ns_dev *card, int size, u32 scd)
|
||||
kfree(scq);
|
||||
return NULL;
|
||||
}
|
||||
scq->skb = kmalloc_array(size / NS_SCQE_SIZE,
|
||||
sizeof(*scq->skb),
|
||||
GFP_KERNEL);
|
||||
scq->skb = kcalloc(size / NS_SCQE_SIZE, sizeof(*scq->skb),
|
||||
GFP_KERNEL);
|
||||
if (!scq->skb) {
|
||||
dma_free_coherent(&card->pcidev->dev,
|
||||
2 * size, scq->org, scq->dma);
|
||||
@@ -890,15 +888,11 @@ static scq_info *get_scq(ns_dev *card, int size, u32 scd)
|
||||
scq->last = scq->base + (scq->num_entries - 1);
|
||||
scq->tail = scq->last;
|
||||
scq->scd = scd;
|
||||
scq->num_entries = size / NS_SCQE_SIZE;
|
||||
scq->tbd_count = 0;
|
||||
init_waitqueue_head(&scq->scqfull_waitq);
|
||||
scq->full = 0;
|
||||
spin_lock_init(&scq->lock);
|
||||
|
||||
for (i = 0; i < scq->num_entries; i++)
|
||||
scq->skb[i] = NULL;
|
||||
|
||||
return scq;
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
|
||||
|
||||
/*
|
||||
* If the bit is set to 0, chipcommon controlls this GPIO,
|
||||
* If the bit is set to 0, chipcommon controls this GPIO,
|
||||
* if the bit is set to 1, it is used by some part of the chip and not our code.
|
||||
*/
|
||||
u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
||||
|
||||
@@ -206,7 +206,7 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
|
||||
usleep_range(2000, 2500);
|
||||
}
|
||||
|
||||
/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
|
||||
/* Disable to allow reading SPROM. Don't know the advantages of enabling it. */
|
||||
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
@@ -234,7 +234,7 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
|
||||
switch (bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM4313:
|
||||
/*
|
||||
* enable 12 mA drive strenth for 4313 and set chipControl
|
||||
* enable 12 mA drive strength for 4313 and set chipControl
|
||||
* register bit 1
|
||||
*/
|
||||
bcma_chipco_chipctl_maskset(cc, 0,
|
||||
@@ -249,7 +249,7 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
|
||||
case BCMA_CHIP_ID_BCM43224:
|
||||
case BCMA_CHIP_ID_BCM43421:
|
||||
/*
|
||||
* enable 12 mA drive strenth for 43224 and set chipControl
|
||||
* enable 12 mA drive strength for 43224 and set chipControl
|
||||
* register bit 15
|
||||
*/
|
||||
if (bus->chipinfo.rev == 0) {
|
||||
|
||||
@@ -181,7 +181,6 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
|
||||
chip->set = bcma_gpio_set_value;
|
||||
chip->direction_input = bcma_gpio_direction_input;
|
||||
chip->direction_output = bcma_gpio_direction_output;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->parent = bus->dev;
|
||||
#if IS_BUILTIN(CONFIG_OF)
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
|
||||
@@ -61,7 +61,7 @@ static u32 bcma_get_cfgspace_addr(struct bcma_drv_pci *pc, unsigned int dev,
|
||||
{
|
||||
u32 addr = 0;
|
||||
|
||||
/* Issue config commands only when the data link is up (atleast
|
||||
/* Issue config commands only when the data link is up (at least
|
||||
* one external pcie device is present).
|
||||
*/
|
||||
if (dev >= 2 || !(bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_LSREG)
|
||||
@@ -295,7 +295,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev,
|
||||
if (cap_ptr == 0x00)
|
||||
return cap_ptr;
|
||||
|
||||
/* loop thr'u the capability list and see if the requested capabilty
|
||||
/* loop through the capability list and see if the requested capability
|
||||
* exists */
|
||||
bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id, sizeof(u8));
|
||||
while (cap_id != req_cap_id) {
|
||||
@@ -317,7 +317,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev,
|
||||
|
||||
*buflen = 0;
|
||||
|
||||
/* copy the cpability data excluding cap ID and next ptr */
|
||||
/* copy the capability data excluding cap ID and next ptr */
|
||||
cap_data = cap_ptr + 2;
|
||||
if ((bufsize + cap_data) > PCI_CONFIG_SPACE_SIZE)
|
||||
bufsize = PCI_CONFIG_SPACE_SIZE - cap_data;
|
||||
|
||||
+2
-2
@@ -293,7 +293,7 @@ static int bcma_register_devices(struct bcma_bus *bus)
|
||||
int err;
|
||||
|
||||
list_for_each_entry(core, &bus->cores, list) {
|
||||
/* We support that cores ourself */
|
||||
/* We support that core ourselves */
|
||||
switch (core->id.id) {
|
||||
case BCMA_CORE_4706_CHIPCOMMON:
|
||||
case BCMA_CORE_CHIPCOMMON:
|
||||
@@ -369,7 +369,7 @@ void bcma_unregister_cores(struct bcma_bus *bus)
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
platform_device_unregister(bus->drv_cc.watchdog);
|
||||
|
||||
/* Now noone uses internally-handled cores, we can free them */
|
||||
/* Now no one uses internally-handled cores, we can free them */
|
||||
list_for_each_entry_safe(core, tmp, &bus->cores, list) {
|
||||
list_del(&core->list);
|
||||
put_device(&core->dev);
|
||||
|
||||
@@ -28,7 +28,7 @@ static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
|
||||
* callback handler which fills the SPROM data structure. The fallback is
|
||||
* used for PCI based BCMA devices, where no valid SPROM can be found
|
||||
* in the shadow registers and to provide the SPROM for SoCs where BCMA is
|
||||
* to controll the system bus.
|
||||
* to control the system bus.
|
||||
*
|
||||
* This function is useful for weird architectures that have a half-assed
|
||||
* BCMA device hardwired to their PCI bus.
|
||||
@@ -281,7 +281,7 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
|
||||
SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
|
||||
SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
|
||||
|
||||
/* Extract cores power info info */
|
||||
/* Extract core's power info */
|
||||
for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
|
||||
o = pwr_info_offset[i];
|
||||
SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
|
||||
|
||||
@@ -400,6 +400,7 @@ config BT_MTKSDIO
|
||||
config BT_MTKUART
|
||||
tristate "MediaTek HCI UART driver"
|
||||
depends on SERIAL_DEV_BUS
|
||||
select BT_MTK
|
||||
help
|
||||
MediaTek Bluetooth HCI UART driver.
|
||||
This driver is required if you want to use MediaTek Bluetooth
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/usb.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -2428,10 +2428,15 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
||||
|
||||
/* Apply the device specific HCI quirks
|
||||
*
|
||||
* WBS for SdP - SdP and Stp have a same hw_varaint but
|
||||
* different fw_variant
|
||||
* WBS for SdP - For the Legacy ROM products, only SdP
|
||||
* supports the WBS. But the version information is not
|
||||
* enough to use here because the StP2 and SdP have same
|
||||
* hw_variant and fw_variant. So, this flag is set by
|
||||
* the transport driver (btusb) based on the HW info
|
||||
* (idProduct)
|
||||
*/
|
||||
if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22)
|
||||
if (!btintel_test_flag(hdev,
|
||||
INTEL_ROM_LEGACY_NO_WBS_SUPPORT))
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
|
||||
&hdev->quirks);
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ enum {
|
||||
INTEL_BROKEN_INITIAL_NCMD,
|
||||
INTEL_BROKEN_SHUTDOWN_LED,
|
||||
INTEL_ROM_LEGACY,
|
||||
INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
|
||||
|
||||
__INTEL_NUM_FLAGS,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Marvell Bluetooth driver: debugfs related functions
|
||||
*
|
||||
* Copyright (C) 2009, Marvell International Ltd.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Marvell BT-over-SDIO driver: SDIO interface related functions.
|
||||
*
|
||||
* Copyright (C) 2009, Marvell International Ltd.
|
||||
|
||||
@@ -285,6 +285,7 @@ MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
|
||||
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7622);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7663);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7961);
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/* Copyright (C) 2021 MediaTek Inc. */
|
||||
|
||||
#define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin"
|
||||
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
|
||||
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
|
||||
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
|
||||
|
||||
#define HCI_EV_WMT 0xe4
|
||||
#define HCI_WMT_MAX_EVENT_SIZE 64
|
||||
|
||||
#define BTMTK_WMT_REG_WRITE 0x1
|
||||
#define BTMTK_WMT_REG_READ 0x2
|
||||
|
||||
#define MT7921_BTSYS_RST 0x70002610
|
||||
#define MT7921_BTSYS_RST_WITH_GPIO BIT(7)
|
||||
|
||||
#define MT7921_PINMUX_0 0x70005050
|
||||
#define MT7921_PINMUX_1 0x70005054
|
||||
|
||||
#define MT7921_DLSTATUS 0x7c053c10
|
||||
#define BT_DL_STATE BIT(1)
|
||||
|
||||
enum {
|
||||
BTMTK_WMT_PATCH_DWNLD = 0x1,
|
||||
BTMTK_WMT_TEST = 0x2,
|
||||
@@ -68,6 +80,37 @@ struct btmtk_tci_sleep {
|
||||
u8 time_compensation;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_wakeon {
|
||||
u8 mode;
|
||||
u8 gpo;
|
||||
u8 active_high;
|
||||
__le16 enable_delay;
|
||||
__le16 wakeup_delay;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_sco {
|
||||
u8 clock_config;
|
||||
u8 transmit_format_config;
|
||||
u8 channel_format_config;
|
||||
u8 channel_select_config;
|
||||
} __packed;
|
||||
|
||||
struct reg_read_cmd {
|
||||
u8 type;
|
||||
u8 rsv;
|
||||
u8 num;
|
||||
__le32 addr;
|
||||
} __packed;
|
||||
|
||||
struct reg_write_cmd {
|
||||
u8 type;
|
||||
u8 rsv;
|
||||
u8 num;
|
||||
__le32 addr;
|
||||
__le32 data;
|
||||
__le32 mask;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_params {
|
||||
u8 op;
|
||||
u8 flag;
|
||||
|
||||
+404
-67
@@ -12,10 +12,12 @@
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
@@ -31,28 +33,32 @@
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
#define MTKBTSDIO_AUTOSUSPEND_DELAY 8000
|
||||
#define MTKBTSDIO_AUTOSUSPEND_DELAY 1000
|
||||
|
||||
static bool enable_autosuspend;
|
||||
static bool enable_autosuspend = true;
|
||||
|
||||
struct btmtksdio_data {
|
||||
const char *fwname;
|
||||
u16 chipid;
|
||||
bool lp_mbox_supported;
|
||||
};
|
||||
|
||||
static const struct btmtksdio_data mt7663_data = {
|
||||
.fwname = FIRMWARE_MT7663,
|
||||
.chipid = 0x7663,
|
||||
.lp_mbox_supported = false,
|
||||
};
|
||||
|
||||
static const struct btmtksdio_data mt7668_data = {
|
||||
.fwname = FIRMWARE_MT7668,
|
||||
.chipid = 0x7668,
|
||||
.lp_mbox_supported = false,
|
||||
};
|
||||
|
||||
static const struct btmtksdio_data mt7921_data = {
|
||||
.fwname = FIRMWARE_MT7961,
|
||||
.chipid = 0x7921,
|
||||
.lp_mbox_supported = true,
|
||||
};
|
||||
|
||||
static const struct sdio_device_id btmtksdio_table[] = {
|
||||
@@ -79,6 +85,7 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
|
||||
#define MTK_REG_CHCR 0xc
|
||||
#define C_INT_CLR_CTRL BIT(1)
|
||||
#define BT_RST_DONE BIT(8)
|
||||
|
||||
/* CHISR have the same bits field definition with CHIER */
|
||||
#define MTK_REG_CHISR 0x10
|
||||
@@ -87,8 +94,17 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
#define RX_DONE_INT BIT(1)
|
||||
#define TX_EMPTY BIT(2)
|
||||
#define TX_FIFO_OVERFLOW BIT(8)
|
||||
#define FW_MAILBOX_INT BIT(15)
|
||||
#define INT_MASK GENMASK(15, 0)
|
||||
#define RX_PKT_LEN GENMASK(31, 16)
|
||||
|
||||
#define MTK_REG_CSICR 0xc0
|
||||
#define CSICR_CLR_MBOX_ACK BIT(0)
|
||||
#define MTK_REG_PH2DSM0R 0xc4
|
||||
#define PH2DSM0R_DRIVER_OWN BIT(0)
|
||||
#define MTK_REG_PD2HRM0R 0xdc
|
||||
#define PD2HRM0R_DRV_OWN BIT(0)
|
||||
|
||||
#define MTK_REG_CTDR 0x18
|
||||
|
||||
#define MTK_REG_CRDR 0x1c
|
||||
@@ -100,6 +116,8 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
#define BTMTKSDIO_TX_WAIT_VND_EVT 1
|
||||
#define BTMTKSDIO_HW_TX_READY 2
|
||||
#define BTMTKSDIO_FUNC_ENABLED 3
|
||||
#define BTMTKSDIO_PATCH_ENABLED 4
|
||||
#define BTMTKSDIO_HW_RESET_ACTIVE 5
|
||||
|
||||
struct mtkbtsdio_hdr {
|
||||
__le16 len;
|
||||
@@ -119,6 +137,8 @@ struct btmtksdio_dev {
|
||||
struct sk_buff *evt_skb;
|
||||
|
||||
const struct btmtksdio_data *data;
|
||||
|
||||
struct gpio_desc *reset;
|
||||
};
|
||||
|
||||
static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
@@ -278,19 +298,89 @@ static u32 btmtksdio_drv_own_query(struct btmtksdio_dev *bdev)
|
||||
return sdio_readl(bdev->func, MTK_REG_CHLPCR, NULL);
|
||||
}
|
||||
|
||||
static u32 btmtksdio_drv_own_query_79xx(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
return sdio_readl(bdev->func, MTK_REG_PD2HRM0R, NULL);
|
||||
}
|
||||
|
||||
static u32 btmtksdio_chcr_query(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
return sdio_readl(bdev->func, MTK_REG_CHCR, NULL);
|
||||
}
|
||||
|
||||
static int btmtksdio_fw_pmctrl(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
if (bdev->data->lp_mbox_supported &&
|
||||
test_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state)) {
|
||||
sdio_writel(bdev->func, CSICR_CLR_MBOX_ACK, MTK_REG_CSICR,
|
||||
&err);
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query_79xx, bdev,
|
||||
status, !(status & PD2HRM0R_DRV_OWN),
|
||||
2000, 1000000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(bdev->hdev, "mailbox ACK not cleared");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return ownership to the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
!(status & C_COM_DRV_OWN), 2000, 1000000);
|
||||
|
||||
out:
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
if (err < 0)
|
||||
bt_dev_err(bdev->hdev, "Cannot return ownership to device");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_drv_pmctrl(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
/* Get ownership from the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
status & C_COM_DRV_OWN, 2000, 1000000);
|
||||
|
||||
if (!err && bdev->data->lp_mbox_supported &&
|
||||
test_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state))
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query_79xx, bdev,
|
||||
status, status & PD2HRM0R_DRV_OWN,
|
||||
2000, 1000000);
|
||||
|
||||
out:
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
if (err < 0)
|
||||
bt_dev_err(bdev->hdev, "Cannot get ownership from device");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
int err;
|
||||
|
||||
/* Fix up the vendor event id with 0xff for vendor specific instead
|
||||
* of 0xe4 so that event send via monitoring socket can be parsed
|
||||
* properly.
|
||||
*/
|
||||
if (hdr->evt == 0xe4)
|
||||
hdr->evt = HCI_EV_VENDOR;
|
||||
|
||||
/* When someone waits for the WMT event, the skb is being cloned
|
||||
* and being processed the events from there then.
|
||||
*/
|
||||
@@ -306,7 +396,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (err < 0)
|
||||
goto err_free_skb;
|
||||
|
||||
if (hdr->evt == HCI_EV_VENDOR) {
|
||||
if (hdr->evt == HCI_EV_WMT) {
|
||||
if (test_and_clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT,
|
||||
&bdev->tx_state)) {
|
||||
/* Barrier to sync with other CPUs */
|
||||
@@ -480,6 +570,13 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
* FIFO.
|
||||
*/
|
||||
sdio_writel(bdev->func, int_status, MTK_REG_CHISR, NULL);
|
||||
int_status &= INT_MASK;
|
||||
|
||||
if ((int_status & FW_MAILBOX_INT) &&
|
||||
bdev->data->chipid == 0x7921) {
|
||||
sdio_writel(bdev->func, PH2DSM0R_DRIVER_OWN,
|
||||
MTK_REG_PH2DSM0R, 0);
|
||||
}
|
||||
|
||||
if (int_status & FW_OWN_BACK_INT)
|
||||
bt_dev_dbg(bdev->hdev, "Get fw own back");
|
||||
@@ -531,7 +628,7 @@ static void btmtksdio_interrupt(struct sdio_func *func)
|
||||
static int btmtksdio_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
u32 status, val;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
@@ -542,18 +639,10 @@ static int btmtksdio_open(struct hci_dev *hdev)
|
||||
|
||||
set_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
|
||||
|
||||
/* Get ownership from the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
goto err_disable_func;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
status & C_COM_DRV_OWN, 2000, 1000000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(bdev->hdev, "Cannot get ownership from device");
|
||||
goto err_disable_func;
|
||||
}
|
||||
|
||||
/* Disable interrupt & mask out all interrupt sources */
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
@@ -623,8 +712,6 @@ err_release_host:
|
||||
static int btmtksdio_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
@@ -635,13 +722,7 @@ static int btmtksdio_close(struct hci_dev *hdev)
|
||||
|
||||
cancel_work_sync(&bdev->txrx_work);
|
||||
|
||||
/* Return ownership to the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
!(status & C_COM_DRV_OWN), 2000, 1000000);
|
||||
if (err < 0)
|
||||
bt_dev_err(bdev->hdev, "Cannot return ownership to device");
|
||||
btmtksdio_fw_pmctrl(bdev);
|
||||
|
||||
clear_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
|
||||
sdio_disable_func(bdev->func);
|
||||
@@ -686,6 +767,7 @@ static int btmtksdio_func_query(struct hci_dev *hdev)
|
||||
|
||||
static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
struct btmtk_tci_sleep tci_sleep;
|
||||
struct sk_buff *skb;
|
||||
@@ -746,6 +828,8 @@ ignore_setup_fw:
|
||||
return err;
|
||||
}
|
||||
|
||||
set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state);
|
||||
|
||||
ignore_func_on:
|
||||
/* Apply the low power environment setup */
|
||||
tci_sleep.mode = 0x5;
|
||||
@@ -768,6 +852,7 @@ ignore_func_on:
|
||||
|
||||
static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
u8 param = 0x1;
|
||||
int err;
|
||||
@@ -793,19 +878,15 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
|
||||
hci_set_msft_opcode(hdev, 0xFD30);
|
||||
hci_set_aosp_capable(hdev);
|
||||
set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
static int btmtksdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
struct reg_read_cmd {
|
||||
u8 type;
|
||||
u8 rsv;
|
||||
u8 num;
|
||||
__le32 addr;
|
||||
} __packed reg_read = {
|
||||
struct reg_read_cmd reg_read = {
|
||||
.type = 1,
|
||||
.num = 1,
|
||||
};
|
||||
@@ -821,7 +902,7 @@ static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to read reg(%d)", err);
|
||||
bt_dev_err(hdev, "Failed to read reg (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -830,6 +911,151 @@ static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_mtk_reg_write(struct hci_dev *hdev, u32 reg, u32 val, u32 mask)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
const struct reg_write_cmd reg_write = {
|
||||
.type = 1,
|
||||
.num = 1,
|
||||
.addr = cpu_to_le32(reg),
|
||||
.data = cpu_to_le32(val),
|
||||
.mask = cpu_to_le32(mask),
|
||||
};
|
||||
int err, status;
|
||||
|
||||
wmt_params.op = BTMTK_WMT_REGISTER;
|
||||
wmt_params.flag = BTMTK_WMT_REG_WRITE;
|
||||
wmt_params.dlen = sizeof(reg_write);
|
||||
wmt_params.data = ®_write;
|
||||
wmt_params.status = &status;
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Failed to write reg (%d)", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
|
||||
{
|
||||
/* uses 1 as data path id for all the usecases */
|
||||
*data_path_id = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btmtksdio_get_codec_config_data(struct hci_dev *hdev,
|
||||
__u8 link, struct bt_codec *codec,
|
||||
__u8 *ven_len, __u8 **ven_data)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!ven_data || !ven_len)
|
||||
return -EINVAL;
|
||||
|
||||
*ven_len = 0;
|
||||
*ven_data = NULL;
|
||||
|
||||
if (link != ESCO_LINK) {
|
||||
bt_dev_err(hdev, "Invalid link type(%u)", link);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ven_data = kmalloc(sizeof(__u8), GFP_KERNEL);
|
||||
if (!ven_data) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* supports only CVSD and mSBC offload codecs */
|
||||
switch (codec->id) {
|
||||
case 0x02:
|
||||
**ven_data = 0x00;
|
||||
break;
|
||||
case 0x05:
|
||||
**ven_data = 0x01;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
bt_dev_err(hdev, "Invalid codec id(%u)", codec->id);
|
||||
goto error;
|
||||
}
|
||||
/* codec and its capabilities are pre-defined to ids
|
||||
* preset id = 0x00 represents CVSD codec with sampling rate 8K
|
||||
* preset id = 0x01 represents mSBC codec with sampling rate 16K
|
||||
*/
|
||||
*ven_len = sizeof(__u8);
|
||||
return err;
|
||||
|
||||
error:
|
||||
kfree(*ven_data);
|
||||
*ven_data = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_sco_setting(struct hci_dev *hdev)
|
||||
{
|
||||
const struct btmtk_sco sco_setting = {
|
||||
.clock_config = 0x49,
|
||||
.channel_format_config = 0x80,
|
||||
};
|
||||
struct sk_buff *skb;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
/* Enable SCO over I2S/PCM for MediaTek chipset */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc72, sizeof(sco_setting),
|
||||
&sco_setting, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_0, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val |= 0x11000000;
|
||||
err = btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_0, val, ~0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_1, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val |= 0x00000101;
|
||||
err = btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_1, val, ~0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdev->get_data_path_id = btmtksdio_get_data_path_id;
|
||||
hdev->get_codec_config_data = btmtksdio_get_codec_config_data;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_reset_setting(struct hci_dev *hdev)
|
||||
{
|
||||
int err;
|
||||
u32 val;
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_1, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val |= 0x20; /* set the pin (bit field 11:8) work as GPIO mode */
|
||||
err = btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_1, val, ~0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_BTSYS_RST, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val |= MT7921_BTSYS_RST_WITH_GPIO;
|
||||
return btmtksdio_mtk_reg_write(hdev, MT7921_BTSYS_RST, val, ~0);
|
||||
}
|
||||
|
||||
static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
@@ -837,20 +1063,39 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
unsigned long long duration;
|
||||
char fwname[64];
|
||||
int err, dev_id;
|
||||
u32 fw_version = 0;
|
||||
u32 fw_version = 0, val;
|
||||
|
||||
calltime = ktime_get();
|
||||
set_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
|
||||
|
||||
switch (bdev->data->chipid) {
|
||||
case 0x7921:
|
||||
err = btsdio_mtk_reg_read(hdev, 0x70010200, &dev_id);
|
||||
if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state)) {
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_DLSTATUS,
|
||||
&val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val &= ~BT_DL_STATE;
|
||||
err = btmtksdio_mtk_reg_write(hdev, MT7921_DLSTATUS,
|
||||
val, ~0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
btmtksdio_fw_pmctrl(bdev);
|
||||
msleep(20);
|
||||
btmtksdio_drv_pmctrl(bdev);
|
||||
|
||||
clear_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state);
|
||||
}
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, 0x70010200, &dev_id);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to get device id (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = btsdio_mtk_reg_read(hdev, 0x80021004, &fw_version);
|
||||
err = btmtksdio_mtk_reg_read(hdev, 0x80021004, &fw_version);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
|
||||
return err;
|
||||
@@ -862,6 +1107,38 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
err = mt79xx_setup(hdev, fwname);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_fw_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Enable SCO over I2S/PCM */
|
||||
err = btmtksdio_sco_setting(hdev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to enable SCO setting (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Enable WBS with mSBC codec */
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
|
||||
/* Enable GPIO reset mechanism */
|
||||
if (bdev->reset) {
|
||||
err = btmtksdio_reset_setting(hdev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to enable Reset setting (%d)", err);
|
||||
devm_gpiod_put(bdev->dev, bdev->reset);
|
||||
bdev->reset = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Valid LE States quirk for MediaTek 7921 */
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
|
||||
break;
|
||||
case 0x7663:
|
||||
case 0x7668:
|
||||
@@ -958,6 +1235,73 @@ static int btmtksdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btmtksdio_cmd_timeout(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
if (!bdev->reset || bdev->data->chipid != 0x7921)
|
||||
return;
|
||||
|
||||
pm_runtime_get_sync(bdev->dev);
|
||||
|
||||
if (test_and_set_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
|
||||
return;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
|
||||
skb_queue_purge(&bdev->txq);
|
||||
cancel_work_sync(&bdev->txrx_work);
|
||||
|
||||
gpiod_set_value_cansleep(bdev->reset, 1);
|
||||
msleep(100);
|
||||
gpiod_set_value_cansleep(bdev->reset, 0);
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_chcr_query, bdev, status,
|
||||
status & BT_RST_DONE, 100000, 2000000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to reset (%d)", err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
clear_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state);
|
||||
err:
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
pm_runtime_put_noidle(bdev->dev);
|
||||
pm_runtime_disable(bdev->dev);
|
||||
|
||||
hci_reset_dev(hdev);
|
||||
}
|
||||
|
||||
static bool btmtksdio_sdio_wakeup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
bool may_wakeup = device_may_wakeup(bdev->dev);
|
||||
const struct btmtk_wakeon bt_awake = {
|
||||
.mode = 0x1,
|
||||
.gpo = 0,
|
||||
.active_high = 0x1,
|
||||
.enable_delay = cpu_to_le16(0xc80),
|
||||
.wakeup_delay = cpu_to_le16(0x20),
|
||||
};
|
||||
|
||||
if (may_wakeup && bdev->data->chipid == 0x7921) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc27, sizeof(bt_awake),
|
||||
&bt_awake, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
may_wakeup = false;
|
||||
else
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
return may_wakeup;
|
||||
}
|
||||
|
||||
static int btmtksdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
@@ -993,10 +1337,12 @@ static int btmtksdio_probe(struct sdio_func *func,
|
||||
|
||||
hdev->open = btmtksdio_open;
|
||||
hdev->close = btmtksdio_close;
|
||||
hdev->cmd_timeout = btmtksdio_cmd_timeout;
|
||||
hdev->flush = btmtksdio_flush;
|
||||
hdev->setup = btmtksdio_setup;
|
||||
hdev->shutdown = btmtksdio_shutdown;
|
||||
hdev->send = btmtksdio_send_frame;
|
||||
hdev->wakeup = btmtksdio_sdio_wakeup;
|
||||
hdev->set_bdaddr = btmtk_set_bdaddr;
|
||||
|
||||
SET_HCIDEV_DEV(hdev, &func->dev);
|
||||
@@ -1004,6 +1350,8 @@ static int btmtksdio_probe(struct sdio_func *func,
|
||||
hdev->manufacturer = 70;
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
|
||||
|
||||
sdio_set_drvdata(func, bdev);
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
dev_err(&func->dev, "Can't register HCI device\n");
|
||||
@@ -1011,8 +1359,6 @@ static int btmtksdio_probe(struct sdio_func *func,
|
||||
return err;
|
||||
}
|
||||
|
||||
sdio_set_drvdata(func, bdev);
|
||||
|
||||
/* pm_runtime_enable would be done after the firmware is being
|
||||
* downloaded because the core layer probably already enables
|
||||
* runtime PM for this func such as the case host->caps &
|
||||
@@ -1032,7 +1378,18 @@ static int btmtksdio_probe(struct sdio_func *func,
|
||||
*/
|
||||
pm_runtime_put_noidle(bdev->dev);
|
||||
|
||||
return 0;
|
||||
err = device_init_wakeup(bdev->dev, true);
|
||||
if (err)
|
||||
bt_dev_err(hdev, "failed to initialize device wakeup");
|
||||
|
||||
bdev->dev->of_node = of_find_compatible_node(NULL, NULL,
|
||||
"mediatek,mt7921s-bluetooth");
|
||||
bdev->reset = devm_gpiod_get_optional(bdev->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(bdev->reset))
|
||||
err = PTR_ERR(bdev->reset);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void btmtksdio_remove(struct sdio_func *func)
|
||||
@@ -1058,7 +1415,6 @@ static int btmtksdio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct btmtksdio_dev *bdev;
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
bdev = sdio_get_drvdata(func);
|
||||
@@ -1070,18 +1426,9 @@ static int btmtksdio_runtime_suspend(struct device *dev)
|
||||
|
||||
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
err = btmtksdio_fw_pmctrl(bdev);
|
||||
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
!(status & C_COM_DRV_OWN), 2000, 1000000);
|
||||
out:
|
||||
bt_dev_info(bdev->hdev, "status (%d) return ownership to device", err);
|
||||
|
||||
sdio_release_host(bdev->func);
|
||||
bt_dev_dbg(bdev->hdev, "status (%d) return ownership to device", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1090,7 +1437,6 @@ static int btmtksdio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct btmtksdio_dev *bdev;
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
bdev = sdio_get_drvdata(func);
|
||||
@@ -1100,18 +1446,9 @@ static int btmtksdio_runtime_resume(struct device *dev)
|
||||
if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
|
||||
return 0;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
status & C_COM_DRV_OWN, 2000, 1000000);
|
||||
out:
|
||||
bt_dev_info(bdev->hdev, "status (%d) get ownership from device", err);
|
||||
|
||||
sdio_release_host(bdev->func);
|
||||
bt_dev_dbg(bdev->hdev, "status (%d) get ownership from device", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
+31
-167
@@ -28,13 +28,10 @@
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "h4_recv.h"
|
||||
#include "btmtk.h"
|
||||
|
||||
#define VERSION "0.2"
|
||||
|
||||
#define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin"
|
||||
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
|
||||
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
|
||||
|
||||
#define MTK_STP_TLR_SIZE 2
|
||||
|
||||
#define BTMTKUART_TX_STATE_ACTIVE 1
|
||||
@@ -44,25 +41,6 @@
|
||||
|
||||
#define BTMTKUART_FLAG_STANDALONE_HW BIT(0)
|
||||
|
||||
enum {
|
||||
MTK_WMT_PATCH_DWNLD = 0x1,
|
||||
MTK_WMT_TEST = 0x2,
|
||||
MTK_WMT_WAKEUP = 0x3,
|
||||
MTK_WMT_HIF = 0x4,
|
||||
MTK_WMT_FUNC_CTRL = 0x6,
|
||||
MTK_WMT_RST = 0x7,
|
||||
MTK_WMT_SEMAPHORE = 0x17,
|
||||
};
|
||||
|
||||
enum {
|
||||
BTMTK_WMT_INVALID,
|
||||
BTMTK_WMT_PATCH_UNDONE,
|
||||
BTMTK_WMT_PATCH_DONE,
|
||||
BTMTK_WMT_ON_UNDONE,
|
||||
BTMTK_WMT_ON_DONE,
|
||||
BTMTK_WMT_ON_PROGRESS,
|
||||
};
|
||||
|
||||
struct mtk_stp_hdr {
|
||||
u8 prefix;
|
||||
__be16 dlen;
|
||||
@@ -74,44 +52,6 @@ struct btmtkuart_data {
|
||||
const char *fwname;
|
||||
};
|
||||
|
||||
struct mtk_wmt_hdr {
|
||||
u8 dir;
|
||||
u8 op;
|
||||
__le16 dlen;
|
||||
u8 flag;
|
||||
} __packed;
|
||||
|
||||
struct mtk_hci_wmt_cmd {
|
||||
struct mtk_wmt_hdr hdr;
|
||||
u8 data[256];
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_evt {
|
||||
struct hci_event_hdr hhdr;
|
||||
struct mtk_wmt_hdr whdr;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_evt_funcc {
|
||||
struct btmtk_hci_wmt_evt hwhdr;
|
||||
__be16 status;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_tci_sleep {
|
||||
u8 mode;
|
||||
__le16 duration;
|
||||
__le16 host_duration;
|
||||
u8 host_wakeup_pin;
|
||||
u8 time_compensation;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_params {
|
||||
u8 op;
|
||||
u8 flag;
|
||||
u16 dlen;
|
||||
const void *data;
|
||||
u32 *status;
|
||||
};
|
||||
|
||||
struct btmtkuart_dev {
|
||||
struct hci_dev *hdev;
|
||||
struct serdev_device *serdev;
|
||||
@@ -153,29 +93,36 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
|
||||
u32 hlen, status = BTMTK_WMT_INVALID;
|
||||
struct btmtk_hci_wmt_evt *wmt_evt;
|
||||
struct mtk_hci_wmt_cmd wc;
|
||||
struct mtk_wmt_hdr *hdr;
|
||||
struct btmtk_hci_wmt_cmd *wc;
|
||||
struct btmtk_wmt_hdr *hdr;
|
||||
int err;
|
||||
|
||||
/* Send the WMT command and wait until the WMT event returns */
|
||||
hlen = sizeof(*hdr) + wmt_params->dlen;
|
||||
if (hlen > 255) {
|
||||
err = -EINVAL;
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
hdr = (struct mtk_wmt_hdr *)&wc;
|
||||
wc = kzalloc(hlen, GFP_KERNEL);
|
||||
if (!wc) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
hdr = &wc->hdr;
|
||||
hdr->dir = 1;
|
||||
hdr->op = wmt_params->op;
|
||||
hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
|
||||
hdr->flag = wmt_params->flag;
|
||||
memcpy(wc.data, wmt_params->data, wmt_params->dlen);
|
||||
memcpy(wc->data, wmt_params->data, wmt_params->dlen);
|
||||
|
||||
set_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
|
||||
err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc);
|
||||
err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
|
||||
if (err < 0) {
|
||||
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
/* The vendor specific WMT commands are all answered by a vendor
|
||||
@@ -192,14 +139,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Execution of wmt command interrupted");
|
||||
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Execution of wmt command timed out");
|
||||
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
err = -ETIMEDOUT;
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
@@ -208,17 +155,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||
wmt_evt->whdr.op, hdr->op);
|
||||
err = -EIO;
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
switch (wmt_evt->whdr.op) {
|
||||
case MTK_WMT_SEMAPHORE:
|
||||
case BTMTK_WMT_SEMAPHORE:
|
||||
if (wmt_evt->whdr.flag == 2)
|
||||
status = BTMTK_WMT_PATCH_UNDONE;
|
||||
else
|
||||
status = BTMTK_WMT_PATCH_DONE;
|
||||
break;
|
||||
case MTK_WMT_FUNC_CTRL:
|
||||
case BTMTK_WMT_FUNC_CTRL:
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||
status = BTMTK_WMT_ON_DONE;
|
||||
@@ -232,6 +179,8 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
if (wmt_params->status)
|
||||
*wmt_params->status = status;
|
||||
|
||||
err_free_wc:
|
||||
kfree(wc);
|
||||
err_free_skb:
|
||||
kfree_skb(bdev->evt_skb);
|
||||
bdev->evt_skb = NULL;
|
||||
@@ -239,95 +188,12 @@ err_free_skb:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
const struct firmware *fw;
|
||||
const u8 *fw_ptr;
|
||||
size_t fw_size;
|
||||
int err, dlen;
|
||||
u8 flag;
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data;
|
||||
fw_size = fw->size;
|
||||
|
||||
/* The size of patch header is 30 bytes, should be skip */
|
||||
if (fw_size < 30) {
|
||||
err = -EINVAL;
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
fw_size -= 30;
|
||||
fw_ptr += 30;
|
||||
flag = 1;
|
||||
|
||||
wmt_params.op = MTK_WMT_PATCH_DWNLD;
|
||||
wmt_params.status = NULL;
|
||||
|
||||
while (fw_size > 0) {
|
||||
dlen = min_t(int, 250, fw_size);
|
||||
|
||||
/* Tell device the position in sequence */
|
||||
if (fw_size - dlen <= 0)
|
||||
flag = 3;
|
||||
else if (fw_size < fw->size - 30)
|
||||
flag = 2;
|
||||
|
||||
wmt_params.flag = flag;
|
||||
wmt_params.dlen = dlen;
|
||||
wmt_params.data = fw_ptr;
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
|
||||
err);
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
fw_size -= dlen;
|
||||
fw_ptr += dlen;
|
||||
}
|
||||
|
||||
wmt_params.op = MTK_WMT_RST;
|
||||
wmt_params.flag = 4;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
wmt_params.status = NULL;
|
||||
|
||||
/* Activate funciton the firmware providing to */
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
/* Wait a few moments for firmware activation done */
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
free_fw:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
int err;
|
||||
|
||||
/* Fix up the vendor event id with 0xff for vendor specific instead
|
||||
* of 0xe4 so that event send via monitoring socket can be parsed
|
||||
* properly.
|
||||
*/
|
||||
if (hdr->evt == 0xe4)
|
||||
hdr->evt = HCI_EV_VENDOR;
|
||||
|
||||
/* When someone waits for the WMT event, the skb is being cloned
|
||||
* and being processed the events from there then.
|
||||
*/
|
||||
@@ -343,7 +209,7 @@ static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (err < 0)
|
||||
goto err_free_skb;
|
||||
|
||||
if (hdr->evt == HCI_EV_VENDOR) {
|
||||
if (hdr->evt == HCI_EV_WMT) {
|
||||
if (test_and_clear_bit(BTMTKUART_TX_WAIT_VND_EVT,
|
||||
&bdev->tx_state)) {
|
||||
/* Barrier to sync with other CPUs */
|
||||
@@ -645,7 +511,7 @@ static int btmtkuart_func_query(struct hci_dev *hdev)
|
||||
u8 param = 0;
|
||||
|
||||
/* Query whether the function is enabled */
|
||||
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 4;
|
||||
wmt_params.dlen = sizeof(param);
|
||||
wmt_params.data = ¶m;
|
||||
@@ -672,7 +538,7 @@ static int btmtkuart_change_baudrate(struct hci_dev *hdev)
|
||||
* ready to change a new baudrate.
|
||||
*/
|
||||
baudrate = cpu_to_le32(bdev->desired_speed);
|
||||
wmt_params.op = MTK_WMT_HIF;
|
||||
wmt_params.op = BTMTK_WMT_HIF;
|
||||
wmt_params.flag = 1;
|
||||
wmt_params.dlen = 4;
|
||||
wmt_params.data = &baudrate;
|
||||
@@ -706,7 +572,7 @@ static int btmtkuart_change_baudrate(struct hci_dev *hdev)
|
||||
usleep_range(20000, 22000);
|
||||
|
||||
/* Test the new baudrate */
|
||||
wmt_params.op = MTK_WMT_TEST;
|
||||
wmt_params.op = BTMTK_WMT_TEST;
|
||||
wmt_params.flag = 7;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
@@ -741,7 +607,7 @@ static int btmtkuart_setup(struct hci_dev *hdev)
|
||||
* do any setups.
|
||||
*/
|
||||
if (test_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state)) {
|
||||
wmt_params.op = MTK_WMT_WAKEUP;
|
||||
wmt_params.op = BTMTK_WMT_WAKEUP;
|
||||
wmt_params.flag = 3;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
@@ -760,7 +626,7 @@ static int btmtkuart_setup(struct hci_dev *hdev)
|
||||
btmtkuart_change_baudrate(hdev);
|
||||
|
||||
/* Query whether the firmware is already download */
|
||||
wmt_params.op = MTK_WMT_SEMAPHORE;
|
||||
wmt_params.op = BTMTK_WMT_SEMAPHORE;
|
||||
wmt_params.flag = 1;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
@@ -778,7 +644,7 @@ static int btmtkuart_setup(struct hci_dev *hdev)
|
||||
}
|
||||
|
||||
/* Setup a firmware which the device definitely requires */
|
||||
err = mtk_setup_firmware(hdev, bdev->data->fwname);
|
||||
err = btmtk_setup_firmware(hdev, bdev->data->fwname, mtk_hci_wmt_sync);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@@ -801,7 +667,7 @@ ignore_setup_fw:
|
||||
}
|
||||
|
||||
/* Enable Bluetooth protocol */
|
||||
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 0;
|
||||
wmt_params.dlen = sizeof(param);
|
||||
wmt_params.data = ¶m;
|
||||
@@ -846,7 +712,7 @@ static int btmtkuart_shutdown(struct hci_dev *hdev)
|
||||
int err;
|
||||
|
||||
/* Disable the device */
|
||||
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 0;
|
||||
wmt_params.dlen = sizeof(param);
|
||||
wmt_params.data = ¶m;
|
||||
@@ -1007,6 +873,7 @@ static int btmtkuart_probe(struct serdev_device *serdev)
|
||||
hdev->setup = btmtkuart_setup;
|
||||
hdev->shutdown = btmtkuart_shutdown;
|
||||
hdev->send = btmtkuart_send_frame;
|
||||
hdev->set_bdaddr = btmtk_set_bdaddr;
|
||||
SET_HCIDEV_DEV(hdev, &serdev->dev);
|
||||
|
||||
hdev->manufacturer = 70;
|
||||
@@ -1131,6 +998,3 @@ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
|
||||
MODULE_DESCRIPTION("MediaTek Bluetooth Serial driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7622);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7663);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
|
||||
@@ -49,6 +49,7 @@ enum btrtl_chip_id {
|
||||
CHIP_ID_8822C = 13,
|
||||
CHIP_ID_8761B,
|
||||
CHIP_ID_8852A = 18,
|
||||
CHIP_ID_8852B = 20,
|
||||
};
|
||||
|
||||
struct id_table {
|
||||
@@ -148,6 +149,14 @@ static const struct id_table ic_id_table[] = {
|
||||
.fw_name = "rtl_bt/rtl8761bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761bu_config" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
|
||||
.config_needed = true,
|
||||
@@ -179,6 +188,14 @@ static const struct id_table ic_id_table[] = {
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852au_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852au_config" },
|
||||
|
||||
/* 8852B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852bu_config" },
|
||||
};
|
||||
|
||||
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
|
||||
@@ -287,6 +304,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
||||
{ RTL_ROM_LMP_8822B, 13 }, /* 8822C */
|
||||
{ RTL_ROM_LMP_8761A, 14 }, /* 8761B */
|
||||
{ RTL_ROM_LMP_8852A, 18 }, /* 8852A */
|
||||
{ RTL_ROM_LMP_8852A, 20 }, /* 8852B */
|
||||
};
|
||||
|
||||
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
|
||||
@@ -749,6 +767,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
|
||||
switch (btrtl_dev->project_id) {
|
||||
case CHIP_ID_8822C:
|
||||
case CHIP_ID_8852A:
|
||||
case CHIP_ID_8852B:
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
hci_set_aosp_capable(hdev);
|
||||
@@ -926,3 +945,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852au_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852au_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin");
|
||||
|
||||
+61
-39
@@ -36,32 +36,33 @@ static bool reset = true;
|
||||
|
||||
static struct usb_driver btusb_driver;
|
||||
|
||||
#define BTUSB_IGNORE 0x01
|
||||
#define BTUSB_DIGIANSWER 0x02
|
||||
#define BTUSB_CSR 0x04
|
||||
#define BTUSB_SNIFFER 0x08
|
||||
#define BTUSB_BCM92035 0x10
|
||||
#define BTUSB_BROKEN_ISOC 0x20
|
||||
#define BTUSB_WRONG_SCO_MTU 0x40
|
||||
#define BTUSB_ATH3012 0x80
|
||||
#define BTUSB_INTEL_COMBINED 0x100
|
||||
#define BTUSB_INTEL_BOOT 0x200
|
||||
#define BTUSB_BCM_PATCHRAM 0x400
|
||||
#define BTUSB_MARVELL 0x800
|
||||
#define BTUSB_SWAVE 0x1000
|
||||
#define BTUSB_AMP 0x4000
|
||||
#define BTUSB_QCA_ROME 0x8000
|
||||
#define BTUSB_BCM_APPLE 0x10000
|
||||
#define BTUSB_REALTEK 0x20000
|
||||
#define BTUSB_BCM2045 0x40000
|
||||
#define BTUSB_IFNUM_2 0x80000
|
||||
#define BTUSB_CW6622 0x100000
|
||||
#define BTUSB_MEDIATEK 0x200000
|
||||
#define BTUSB_WIDEBAND_SPEECH 0x400000
|
||||
#define BTUSB_VALID_LE_STATES 0x800000
|
||||
#define BTUSB_QCA_WCN6855 0x1000000
|
||||
#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED 0x2000000
|
||||
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD 0x4000000
|
||||
#define BTUSB_IGNORE BIT(0)
|
||||
#define BTUSB_DIGIANSWER BIT(1)
|
||||
#define BTUSB_CSR BIT(2)
|
||||
#define BTUSB_SNIFFER BIT(3)
|
||||
#define BTUSB_BCM92035 BIT(4)
|
||||
#define BTUSB_BROKEN_ISOC BIT(5)
|
||||
#define BTUSB_WRONG_SCO_MTU BIT(6)
|
||||
#define BTUSB_ATH3012 BIT(7)
|
||||
#define BTUSB_INTEL_COMBINED BIT(8)
|
||||
#define BTUSB_INTEL_BOOT BIT(9)
|
||||
#define BTUSB_BCM_PATCHRAM BIT(10)
|
||||
#define BTUSB_MARVELL BIT(11)
|
||||
#define BTUSB_SWAVE BIT(12)
|
||||
#define BTUSB_AMP BIT(13)
|
||||
#define BTUSB_QCA_ROME BIT(14)
|
||||
#define BTUSB_BCM_APPLE BIT(15)
|
||||
#define BTUSB_REALTEK BIT(16)
|
||||
#define BTUSB_BCM2045 BIT(17)
|
||||
#define BTUSB_IFNUM_2 BIT(18)
|
||||
#define BTUSB_CW6622 BIT(19)
|
||||
#define BTUSB_MEDIATEK BIT(20)
|
||||
#define BTUSB_WIDEBAND_SPEECH BIT(21)
|
||||
#define BTUSB_VALID_LE_STATES BIT(22)
|
||||
#define BTUSB_QCA_WCN6855 BIT(23)
|
||||
#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED BIT(24)
|
||||
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25)
|
||||
#define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26)
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
@@ -383,11 +384,14 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
BTUSB_INTEL_NO_WBS_SUPPORT |
|
||||
BTUSB_INTEL_BROKEN_INITIAL_NCMD |
|
||||
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
|
||||
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
BTUSB_INTEL_NO_WBS_SUPPORT |
|
||||
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
|
||||
{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
@@ -405,6 +409,8 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek 8852AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0x385a), .driver_info = BTUSB_REALTEK |
|
||||
@@ -429,6 +435,11 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
/* Additional MediaTek MT7615E Bluetooth devices */
|
||||
{ USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},
|
||||
|
||||
/* Additional MediaTek MT7663 Bluetooth devices */
|
||||
{ USB_DEVICE(0x043e, 0x310c), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional MediaTek MT7668 Bluetooth devices */
|
||||
{ USB_DEVICE(0x043e, 0x3109), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
@@ -444,6 +455,9 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
@@ -463,6 +477,7 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
/* Additional Realtek 8723BE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x04f2, 0xb49f), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
|
||||
@@ -482,6 +497,8 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
/* Additional Realtek 8761BU Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8821AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
|
||||
@@ -2041,6 +2058,8 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
*/
|
||||
set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks);
|
||||
|
||||
/* Clear the reset quirk since this is not an actual
|
||||
* early Bluetooth 1.1 device from CSR.
|
||||
@@ -2051,16 +2070,16 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
/*
|
||||
* Special workaround for these BT 4.0 chip clones, and potentially more:
|
||||
*
|
||||
* - 0x0134: a Barrot 8041a02 (HCI rev: 0x1012 sub: 0x0810)
|
||||
* - 0x0134: a Barrot 8041a02 (HCI rev: 0x0810 sub: 0x1012)
|
||||
* - 0x7558: IC markings FR3191AHAL 749H15143 (HCI rev/sub-version: 0x0709)
|
||||
*
|
||||
* These controllers are really messed-up.
|
||||
*
|
||||
* 1. Their bulk RX endpoint will never report any data unless
|
||||
* the device was suspended at least once (yes, really).
|
||||
* the device was suspended at least once (yes, really).
|
||||
* 2. They will not wakeup when autosuspended and receiving data
|
||||
* on their bulk RX endpoint from e.g. a keyboard or mouse
|
||||
* (IOW remote-wakeup support is broken for the bulk endpoint).
|
||||
* on their bulk RX endpoint from e.g. a keyboard or mouse
|
||||
* (IOW remote-wakeup support is broken for the bulk endpoint).
|
||||
*
|
||||
* To fix 1. enable runtime-suspend, force-suspend the
|
||||
* HCI and then wake-it up by disabling runtime-suspend.
|
||||
@@ -2080,7 +2099,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
if (ret >= 0)
|
||||
msleep(200);
|
||||
else
|
||||
bt_dev_err(hdev, "CSR: Failed to suspend the device for our Barrot 8041a02 receive-issue workaround");
|
||||
bt_dev_warn(hdev, "CSR: Couldn't suspend the device for our Barrot 8041a02 receive-issue workaround");
|
||||
|
||||
pm_runtime_forbid(&data->udev->dev);
|
||||
|
||||
@@ -2245,7 +2264,6 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct hci_event_hdr *hdr;
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
@@ -2265,13 +2283,6 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
|
||||
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
|
||||
skb_put_data(skb, urb->transfer_buffer, urb->actual_length);
|
||||
|
||||
hdr = (void *)skb->data;
|
||||
/* Fix up the vendor event id with 0xff for vendor specific
|
||||
* instead of 0xe4 so that event send via monitoring socket can
|
||||
* be parsed properly.
|
||||
*/
|
||||
hdr->evt = 0xff;
|
||||
|
||||
/* When someone waits for the WMT event, the skb is being cloned
|
||||
* and being processed the events from there then.
|
||||
*/
|
||||
@@ -2988,6 +2999,7 @@ static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
|
||||
#define QCA_PATCH_UPDATED 0x80
|
||||
#define QCA_DFU_TIMEOUT 3000
|
||||
#define QCA_FLAG_MULTI_NVM 0x80
|
||||
#define QCA_BT_RESET_WAIT_MS 100
|
||||
|
||||
#define WCN6855_2_0_RAM_VERSION_GF 0x400c1200
|
||||
#define WCN6855_2_1_RAM_VERSION_GF 0x400c1211
|
||||
@@ -3314,6 +3326,13 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
err = btusb_setup_qca_load_nvm(hdev, &ver, info);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* WCN6855 2.1 will reset to apply firmware downloaded here, so
|
||||
* wait ~100ms for reset Done then go ahead, otherwise, it maybe
|
||||
* cause potential enable failure.
|
||||
*/
|
||||
if (info->rom_version == 0x00130201)
|
||||
msleep(QCA_BT_RESET_WAIT_MS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -3737,6 +3756,9 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->send = btusb_send_frame_intel;
|
||||
hdev->cmd_timeout = btusb_intel_cmd_timeout;
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL_NO_WBS_SUPPORT)
|
||||
btintel_set_flag(hdev, INTEL_ROM_LEGACY_NO_WBS_SUPPORT);
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL_BROKEN_INITIAL_NCMD)
|
||||
btintel_set_flag(hdev, INTEL_BROKEN_INITIAL_NCMD);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dmi.h>
|
||||
@@ -870,7 +871,23 @@ unlock:
|
||||
#endif
|
||||
|
||||
/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */
|
||||
static struct gpiod_lookup_table asus_tf103c_irq_gpios = {
|
||||
.dev_id = "serial0-0",
|
||||
.table = {
|
||||
GPIO_LOOKUP("INT33FC:02", 17, "host-wakeup-alt", GPIO_ACTIVE_HIGH),
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dmi_system_id bcm_broken_irq_dmi_table[] = {
|
||||
{
|
||||
.ident = "Asus TF103C",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"),
|
||||
},
|
||||
.driver_data = &asus_tf103c_irq_gpios,
|
||||
},
|
||||
{
|
||||
.ident = "Meegopad T08",
|
||||
.matches = {
|
||||
@@ -1027,7 +1044,8 @@ static struct clk *bcm_get_txco(struct device *dev)
|
||||
|
||||
static int bcm_get_resources(struct bcm_device *dev)
|
||||
{
|
||||
const struct dmi_system_id *dmi_id;
|
||||
const struct dmi_system_id *broken_irq_dmi_id;
|
||||
const char *irq_con_id = "host-wakeup";
|
||||
int err;
|
||||
|
||||
dev->name = dev_name(dev->dev);
|
||||
@@ -1083,23 +1101,33 @@ static int bcm_get_resources(struct bcm_device *dev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
broken_irq_dmi_id = dmi_first_match(bcm_broken_irq_dmi_table);
|
||||
if (broken_irq_dmi_id && broken_irq_dmi_id->driver_data) {
|
||||
gpiod_add_lookup_table(broken_irq_dmi_id->driver_data);
|
||||
irq_con_id = "host-wakeup-alt";
|
||||
dev->irq_active_low = false;
|
||||
dev->irq = 0;
|
||||
}
|
||||
|
||||
/* IRQ can be declared in ACPI table as Interrupt or GpioInt */
|
||||
if (dev->irq <= 0) {
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
gpio = devm_gpiod_get_optional(dev->dev, "host-wakeup",
|
||||
GPIOD_IN);
|
||||
gpio = devm_gpiod_get_optional(dev->dev, irq_con_id, GPIOD_IN);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
dev->irq = gpiod_to_irq(gpio);
|
||||
}
|
||||
|
||||
dmi_id = dmi_first_match(bcm_broken_irq_dmi_table);
|
||||
if (dmi_id) {
|
||||
dev_info(dev->dev, "%s: Has a broken IRQ config, disabling IRQ support / runtime-pm\n",
|
||||
dmi_id->ident);
|
||||
dev->irq = 0;
|
||||
if (broken_irq_dmi_id) {
|
||||
if (broken_irq_dmi_id->driver_data) {
|
||||
gpiod_remove_lookup_table(broken_irq_dmi_id->driver_data);
|
||||
} else {
|
||||
dev_info(dev->dev, "%s: Has a broken IRQ config, disabling IRQ support / runtime-pm\n",
|
||||
broken_irq_dmi_id->ident);
|
||||
dev->irq = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev->dev, "BCM irq: %d\n", dev->irq);
|
||||
@@ -1513,6 +1541,8 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
|
||||
{ .compatible = "brcm,bcm4330-bt" },
|
||||
{ .compatible = "brcm,bcm4334-bt" },
|
||||
{ .compatible = "brcm,bcm4345c5" },
|
||||
{ .compatible = "brcm,bcm43430a0-bt" },
|
||||
{ .compatible = "brcm,bcm43430a1-bt" },
|
||||
{ .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data },
|
||||
{ .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data },
|
||||
{ .compatible = "brcm,bcm4335a0" },
|
||||
|
||||
@@ -629,9 +629,11 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||
break;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(&hu->serdev->dev);
|
||||
pm_runtime_mark_last_busy(&hu->serdev->dev);
|
||||
pm_runtime_put_autosuspend(&hu->serdev->dev);
|
||||
if (hu->serdev) {
|
||||
pm_runtime_get_sync(&hu->serdev->dev);
|
||||
pm_runtime_mark_last_busy(&hu->serdev->dev);
|
||||
pm_runtime_put_autosuspend(&hu->serdev->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -966,6 +968,11 @@ static void h5_btrtl_open(struct h5 *h5)
|
||||
pm_runtime_enable(&h5->hu->serdev->dev);
|
||||
}
|
||||
|
||||
/* The controller needs reset to startup */
|
||||
gpiod_set_value_cansleep(h5->enable_gpio, 0);
|
||||
gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
|
||||
msleep(100);
|
||||
|
||||
/* The controller needs up to 500ms to wakeup */
|
||||
gpiod_set_value_cansleep(h5->enable_gpio, 1);
|
||||
gpiod_set_value_cansleep(h5->device_wake_gpio, 1);
|
||||
|
||||
@@ -509,7 +509,7 @@ static int send_command_from_firmware(struct ll_device *lldev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* download_firmware -
|
||||
* internal function which parses through the .bts firmware
|
||||
* script file intreprets SEND, DELAY actions only as of now
|
||||
|
||||
@@ -305,6 +305,8 @@ int hci_uart_register_device(struct hci_uart *hu,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
percpu_init_rwsem(&hu->proto_lock);
|
||||
|
||||
err = p->open(hu);
|
||||
if (err)
|
||||
goto err_open;
|
||||
@@ -327,7 +329,6 @@ int hci_uart_register_device(struct hci_uart *hu,
|
||||
|
||||
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||
percpu_init_rwsem(&hu->proto_lock);
|
||||
|
||||
/* Only when vendor specific setup callback is provided, consider
|
||||
* the manufacturer information valid. This avoids filling in the
|
||||
|
||||
@@ -433,8 +433,7 @@ void mlx5_ib_init_cong_debugfs(struct mlx5_ib_dev *dev, u32 port_num)
|
||||
|
||||
dev->port[port_num].dbg_cc_params = dbg_cc_params;
|
||||
|
||||
dbg_cc_params->root = debugfs_create_dir("cc_params",
|
||||
mdev->priv.dbg_root);
|
||||
dbg_cc_params->root = debugfs_create_dir("cc_params", mlx5_debugfs_get_dev_root(mdev));
|
||||
|
||||
for (i = 0; i < MLX5_IB_DBG_CC_MAX; i++) {
|
||||
dbg_cc_params->params[i].offset = i;
|
||||
|
||||
@@ -1055,7 +1055,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(
|
||||
int cmd_out_len = uverbs_attr_get_len(attrs,
|
||||
MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT);
|
||||
void *cmd_out;
|
||||
int err;
|
||||
int err, err2;
|
||||
int uid;
|
||||
|
||||
c = devx_ufile2uctx(attrs);
|
||||
@@ -1076,14 +1076,16 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(
|
||||
return PTR_ERR(cmd_out);
|
||||
|
||||
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
|
||||
err = mlx5_cmd_exec(dev->mdev, cmd_in,
|
||||
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN),
|
||||
cmd_out, cmd_out_len);
|
||||
if (err)
|
||||
err = mlx5_cmd_do(dev->mdev, cmd_in,
|
||||
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN),
|
||||
cmd_out, cmd_out_len);
|
||||
if (err && err != -EREMOTEIO)
|
||||
return err;
|
||||
|
||||
return uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, cmd_out,
|
||||
err2 = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, cmd_out,
|
||||
cmd_out_len);
|
||||
|
||||
return err2 ?: err;
|
||||
}
|
||||
|
||||
static void devx_obj_build_destroy_cmd(void *in, void *out, void *din,
|
||||
@@ -1457,7 +1459,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
|
||||
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
|
||||
struct devx_obj *obj;
|
||||
u16 obj_type = 0;
|
||||
int err;
|
||||
int err, err2 = 0;
|
||||
int uid;
|
||||
u32 obj_id;
|
||||
u16 opcode;
|
||||
@@ -1497,15 +1499,18 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
|
||||
!is_apu_cq(dev, cmd_in)) {
|
||||
obj->flags |= DEVX_OBJ_FLAGS_CQ;
|
||||
obj->core_cq.comp = devx_cq_comp;
|
||||
err = mlx5_core_create_cq(dev->mdev, &obj->core_cq,
|
||||
cmd_in, cmd_in_len, cmd_out,
|
||||
cmd_out_len);
|
||||
err = mlx5_create_cq(dev->mdev, &obj->core_cq,
|
||||
cmd_in, cmd_in_len, cmd_out,
|
||||
cmd_out_len);
|
||||
} else {
|
||||
err = mlx5_cmd_exec(dev->mdev, cmd_in,
|
||||
cmd_in_len,
|
||||
cmd_out, cmd_out_len);
|
||||
err = mlx5_cmd_do(dev->mdev, cmd_in, cmd_in_len,
|
||||
cmd_out, cmd_out_len);
|
||||
}
|
||||
|
||||
if (err == -EREMOTEIO)
|
||||
err2 = uverbs_copy_to(attrs,
|
||||
MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT,
|
||||
cmd_out, cmd_out_len);
|
||||
if (err)
|
||||
goto obj_free;
|
||||
|
||||
@@ -1548,7 +1553,7 @@ obj_destroy:
|
||||
sizeof(out));
|
||||
obj_free:
|
||||
kfree(obj);
|
||||
return err;
|
||||
return err2 ?: err;
|
||||
}
|
||||
|
||||
static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
|
||||
@@ -1563,7 +1568,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
|
||||
&attrs->driver_udata, struct mlx5_ib_ucontext, ibucontext);
|
||||
struct mlx5_ib_dev *mdev = to_mdev(c->ibucontext.device);
|
||||
void *cmd_out;
|
||||
int err;
|
||||
int err, err2;
|
||||
int uid;
|
||||
|
||||
if (MLX5_GET(general_obj_in_cmd_hdr, cmd_in, vhca_tunnel_id))
|
||||
@@ -1586,14 +1591,16 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
|
||||
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
|
||||
devx_set_umem_valid(cmd_in);
|
||||
|
||||
err = mlx5_cmd_exec(mdev->mdev, cmd_in,
|
||||
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN),
|
||||
cmd_out, cmd_out_len);
|
||||
if (err)
|
||||
err = mlx5_cmd_do(mdev->mdev, cmd_in,
|
||||
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN),
|
||||
cmd_out, cmd_out_len);
|
||||
if (err && err != -EREMOTEIO)
|
||||
return err;
|
||||
|
||||
return uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT,
|
||||
err2 = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT,
|
||||
cmd_out, cmd_out_len);
|
||||
|
||||
return err2 ?: err;
|
||||
}
|
||||
|
||||
static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
|
||||
@@ -1607,7 +1614,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
|
||||
struct mlx5_ib_ucontext *c = rdma_udata_to_drv_context(
|
||||
&attrs->driver_udata, struct mlx5_ib_ucontext, ibucontext);
|
||||
void *cmd_out;
|
||||
int err;
|
||||
int err, err2;
|
||||
int uid;
|
||||
struct mlx5_ib_dev *mdev = to_mdev(c->ibucontext.device);
|
||||
|
||||
@@ -1629,14 +1636,16 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
|
||||
return PTR_ERR(cmd_out);
|
||||
|
||||
MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
|
||||
err = mlx5_cmd_exec(mdev->mdev, cmd_in,
|
||||
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN),
|
||||
cmd_out, cmd_out_len);
|
||||
if (err)
|
||||
err = mlx5_cmd_do(mdev->mdev, cmd_in,
|
||||
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN),
|
||||
cmd_out, cmd_out_len);
|
||||
if (err && err != -EREMOTEIO)
|
||||
return err;
|
||||
|
||||
return uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT,
|
||||
err2 = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT,
|
||||
cmd_out, cmd_out_len);
|
||||
|
||||
return err2 ?: err;
|
||||
}
|
||||
|
||||
struct devx_async_event_queue {
|
||||
|
||||
@@ -4178,7 +4178,7 @@ static int mlx5_ib_stage_delay_drop_init(struct mlx5_ib_dev *dev)
|
||||
if (!mlx5_debugfs_root)
|
||||
return 0;
|
||||
|
||||
root = debugfs_create_dir("delay_drop", dev->mdev->priv.dbg_root);
|
||||
root = debugfs_create_dir("delay_drop", mlx5_debugfs_get_dev_root(dev->mdev));
|
||||
dev->delay_drop.dir_debugfs = root;
|
||||
|
||||
debugfs_create_atomic_t("num_timeout_events", 0400, root,
|
||||
|
||||
@@ -140,6 +140,19 @@ static int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
|
||||
return mlx5_core_destroy_mkey(dev->mdev, mr->mmkey.key);
|
||||
}
|
||||
|
||||
static void create_mkey_warn(struct mlx5_ib_dev *dev, int status, void *out)
|
||||
{
|
||||
if (status == -ENXIO) /* core driver is not available */
|
||||
return;
|
||||
|
||||
mlx5_ib_warn(dev, "async reg mr failed. status %d\n", status);
|
||||
if (status != -EREMOTEIO) /* driver specific failure */
|
||||
return;
|
||||
|
||||
/* Failed in FW, print cmd out failure details */
|
||||
mlx5_cmd_out_err(dev->mdev, MLX5_CMD_OP_CREATE_MKEY, 0, out);
|
||||
}
|
||||
|
||||
static void create_mkey_callback(int status, struct mlx5_async_work *context)
|
||||
{
|
||||
struct mlx5_ib_mr *mr =
|
||||
@@ -149,7 +162,7 @@ static void create_mkey_callback(int status, struct mlx5_async_work *context)
|
||||
unsigned long flags;
|
||||
|
||||
if (status) {
|
||||
mlx5_ib_warn(dev, "async reg mr failed. status %d\n", status);
|
||||
create_mkey_warn(dev, status, mr->out);
|
||||
kfree(mr);
|
||||
spin_lock_irqsave(&ent->lock, flags);
|
||||
ent->pending--;
|
||||
@@ -683,7 +696,7 @@ static void mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev)
|
||||
if (!mlx5_debugfs_root || dev->is_rep)
|
||||
return;
|
||||
|
||||
cache->root = debugfs_create_dir("mr_cache", dev->mdev->priv.dbg_root);
|
||||
cache->root = debugfs_create_dir("mr_cache", mlx5_debugfs_get_dev_root(dev->mdev));
|
||||
|
||||
for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
|
||||
ent = &cache->ent[i];
|
||||
|
||||
@@ -4465,6 +4465,7 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr,
|
||||
err = mlx5_core_create_dct(dev, &qp->dct.mdct, qp->dct.in,
|
||||
MLX5_ST_SZ_BYTES(create_dct_in), out,
|
||||
sizeof(out));
|
||||
err = mlx5_cmd_check(dev->mdev, err, qp->dct.in, out);
|
||||
if (err)
|
||||
return err;
|
||||
resp.dctn = qp->dct.mdct.mqp.qpn;
|
||||
|
||||
@@ -220,7 +220,7 @@ int mlx5_core_create_dct(struct mlx5_ib_dev *dev, struct mlx5_core_dct *dct,
|
||||
init_completion(&dct->drained);
|
||||
MLX5_SET(create_dct_in, in, opcode, MLX5_CMD_OP_CREATE_DCT);
|
||||
|
||||
err = mlx5_cmd_exec(dev->mdev, in, inlen, out, outlen);
|
||||
err = mlx5_cmd_do(dev->mdev, in, inlen, out, outlen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -1062,7 +1062,7 @@ ipac_rme(struct hscx_hw *hx)
|
||||
if (!hx->bch.rx_skb)
|
||||
return;
|
||||
if (hx->bch.rx_skb->len < 2) {
|
||||
pr_debug("%s: B%1d frame to short %d\n",
|
||||
pr_debug("%s: B%1d frame too short %d\n",
|
||||
hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);
|
||||
skb_trim(hx->bch.rx_skb, 0);
|
||||
} else {
|
||||
|
||||
@@ -466,7 +466,7 @@ isar_rcv_frame(struct isar_ch *ch)
|
||||
rcv_mbox(ch->is, ptr);
|
||||
if (ch->is->cmsb & HDLC_FED) {
|
||||
if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
|
||||
pr_debug("%s: ISAR frame to short %d\n",
|
||||
pr_debug("%s: ISAR frame too short %d\n",
|
||||
ch->is->name, ch->bch.rx_skb->len);
|
||||
skb_trim(ch->bch.rx_skb, 0);
|
||||
break;
|
||||
@@ -542,7 +542,7 @@ isar_rcv_frame(struct isar_ch *ch)
|
||||
rcv_mbox(ch->is, ptr);
|
||||
if (ch->is->cmsb & HDLC_FED) {
|
||||
if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
|
||||
pr_info("%s: ISAR frame to short %d\n",
|
||||
pr_info("%s: ISAR frame too short %d\n",
|
||||
ch->is->name, ch->bch.rx_skb->len);
|
||||
skb_trim(ch->bch.rx_skb, 0);
|
||||
break;
|
||||
|
||||
@@ -247,7 +247,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
|
||||
xpnet_device->stats.rx_packets++;
|
||||
xpnet_device->stats.rx_bytes += skb->len + ETH_HLEN;
|
||||
|
||||
netif_rx_ni(skb);
|
||||
netif_rx(skb);
|
||||
xpc_received(partid, channel, (void *)msg);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user