Merge v4.20-rc4 into drm-next
Requested by Boris Brezillon for some vc4 fixes that are needed for future vc4 work. Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
4
CREDITS
4
CREDITS
@@ -2204,6 +2204,10 @@ S: Post Office Box 371
|
|||||||
S: North Little Rock, Arkansas 72115
|
S: North Little Rock, Arkansas 72115
|
||||||
S: USA
|
S: USA
|
||||||
|
|
||||||
|
N: Christopher Li
|
||||||
|
E: sparse@chrisli.org
|
||||||
|
D: Sparse maintainer 2009 - 2018
|
||||||
|
|
||||||
N: Stephan Linz
|
N: Stephan Linz
|
||||||
E: linz@mazet.de
|
E: linz@mazet.de
|
||||||
E: Stephan.Linz@gmx.de
|
E: Stephan.Linz@gmx.de
|
||||||
|
@@ -4713,6 +4713,8 @@
|
|||||||
prevent spurious wakeup);
|
prevent spurious wakeup);
|
||||||
n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
|
n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
|
||||||
pause after every control message);
|
pause after every control message);
|
||||||
|
o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra
|
||||||
|
delay after resetting its port);
|
||||||
Example: quirks=0781:5580:bk,0a5c:5834:gij
|
Example: quirks=0781:5580:bk,0a5c:5834:gij
|
||||||
|
|
||||||
usbhid.mousepoll=
|
usbhid.mousepoll=
|
||||||
|
@@ -32,16 +32,17 @@ Disclosure and embargoed information
|
|||||||
The security list is not a disclosure channel. For that, see Coordination
|
The security list is not a disclosure channel. For that, see Coordination
|
||||||
below.
|
below.
|
||||||
|
|
||||||
Once a robust fix has been developed, our preference is to release the
|
Once a robust fix has been developed, the release process starts. Fixes
|
||||||
fix in a timely fashion, treating it no differently than any of the other
|
for publicly known bugs are released immediately.
|
||||||
thousands of changes and fixes the Linux kernel project releases every
|
|
||||||
month.
|
|
||||||
|
|
||||||
However, at the request of the reporter, we will postpone releasing the
|
Although our preference is to release fixes for publicly undisclosed bugs
|
||||||
fix for up to 5 business days after the date of the report or after the
|
as soon as they become available, this may be postponed at the request of
|
||||||
embargo has lifted; whichever comes first. The only exception to that
|
the reporter or an affected party for up to 7 calendar days from the start
|
||||||
rule is if the bug is publicly known, in which case the preference is to
|
of the release process, with an exceptional extension to 14 calendar days
|
||||||
release the fix as soon as it's available.
|
if it is agreed that the criticality of the bug requires more time. The
|
||||||
|
only valid reason for deferring the publication of a fix is to accommodate
|
||||||
|
the logistics of QA and large scale rollouts which require release
|
||||||
|
coordination.
|
||||||
|
|
||||||
Whilst embargoed information may be shared with trusted individuals in
|
Whilst embargoed information may be shared with trusted individuals in
|
||||||
order to develop a fix, such information will not be published alongside
|
order to develop a fix, such information will not be published alongside
|
||||||
|
@@ -74,7 +74,8 @@ using :c:func:`xa_load`. xa_store will overwrite any entry with the
|
|||||||
new entry and return the previous entry stored at that index. You can
|
new entry and return the previous entry stored at that index. You can
|
||||||
use :c:func:`xa_erase` instead of calling :c:func:`xa_store` with a
|
use :c:func:`xa_erase` instead of calling :c:func:`xa_store` with a
|
||||||
``NULL`` entry. There is no difference between an entry that has never
|
``NULL`` entry. There is no difference between an entry that has never
|
||||||
been stored to and one that has most recently had ``NULL`` stored to it.
|
been stored to, one that has been erased and one that has most recently
|
||||||
|
had ``NULL`` stored to it.
|
||||||
|
|
||||||
You can conditionally replace an entry at an index by using
|
You can conditionally replace an entry at an index by using
|
||||||
:c:func:`xa_cmpxchg`. Like :c:func:`cmpxchg`, it will only succeed if
|
:c:func:`xa_cmpxchg`. Like :c:func:`cmpxchg`, it will only succeed if
|
||||||
@@ -105,23 +106,44 @@ may result in the entry being marked at some, but not all of the other
|
|||||||
indices. Storing into one index may result in the entry retrieved by
|
indices. Storing into one index may result in the entry retrieved by
|
||||||
some, but not all of the other indices changing.
|
some, but not all of the other indices changing.
|
||||||
|
|
||||||
|
Sometimes you need to ensure that a subsequent call to :c:func:`xa_store`
|
||||||
|
will not need to allocate memory. The :c:func:`xa_reserve` function
|
||||||
|
will store a reserved entry at the indicated index. Users of the normal
|
||||||
|
API will see this entry as containing ``NULL``. If you do not need to
|
||||||
|
use the reserved entry, you can call :c:func:`xa_release` to remove the
|
||||||
|
unused entry. If another user has stored to the entry in the meantime,
|
||||||
|
:c:func:`xa_release` will do nothing; if instead you want the entry to
|
||||||
|
become ``NULL``, you should use :c:func:`xa_erase`.
|
||||||
|
|
||||||
|
If all entries in the array are ``NULL``, the :c:func:`xa_empty` function
|
||||||
|
will return ``true``.
|
||||||
|
|
||||||
Finally, you can remove all entries from an XArray by calling
|
Finally, you can remove all entries from an XArray by calling
|
||||||
:c:func:`xa_destroy`. If the XArray entries are pointers, you may wish
|
:c:func:`xa_destroy`. If the XArray entries are pointers, you may wish
|
||||||
to free the entries first. You can do this by iterating over all present
|
to free the entries first. You can do this by iterating over all present
|
||||||
entries in the XArray using the :c:func:`xa_for_each` iterator.
|
entries in the XArray using the :c:func:`xa_for_each` iterator.
|
||||||
|
|
||||||
ID assignment
|
Allocating XArrays
|
||||||
-------------
|
------------------
|
||||||
|
|
||||||
|
If you use :c:func:`DEFINE_XARRAY_ALLOC` to define the XArray, or
|
||||||
|
initialise it by passing ``XA_FLAGS_ALLOC`` to :c:func:`xa_init_flags`,
|
||||||
|
the XArray changes to track whether entries are in use or not.
|
||||||
|
|
||||||
You can call :c:func:`xa_alloc` to store the entry at any unused index
|
You can call :c:func:`xa_alloc` to store the entry at any unused index
|
||||||
in the XArray. If you need to modify the array from interrupt context,
|
in the XArray. If you need to modify the array from interrupt context,
|
||||||
you can use :c:func:`xa_alloc_bh` or :c:func:`xa_alloc_irq` to disable
|
you can use :c:func:`xa_alloc_bh` or :c:func:`xa_alloc_irq` to disable
|
||||||
interrupts while allocating the ID. Unlike :c:func:`xa_store`, allocating
|
interrupts while allocating the ID.
|
||||||
a ``NULL`` pointer does not delete an entry. Instead it reserves an
|
|
||||||
entry like :c:func:`xa_reserve` and you can release it using either
|
Using :c:func:`xa_store`, :c:func:`xa_cmpxchg` or :c:func:`xa_insert`
|
||||||
:c:func:`xa_erase` or :c:func:`xa_release`. To use ID assignment, the
|
will mark the entry as being allocated. Unlike a normal XArray, storing
|
||||||
XArray must be defined with :c:func:`DEFINE_XARRAY_ALLOC`, or initialised
|
``NULL`` will mark the entry as being in use, like :c:func:`xa_reserve`.
|
||||||
by passing ``XA_FLAGS_ALLOC`` to :c:func:`xa_init_flags`,
|
To free an entry, use :c:func:`xa_erase` (or :c:func:`xa_release` if
|
||||||
|
you only want to free the entry if it's ``NULL``).
|
||||||
|
|
||||||
|
You cannot use ``XA_MARK_0`` with an allocating XArray as this mark
|
||||||
|
is used to track whether an entry is free or not. The other marks are
|
||||||
|
available for your use.
|
||||||
|
|
||||||
Memory allocation
|
Memory allocation
|
||||||
-----------------
|
-----------------
|
||||||
@@ -158,6 +180,8 @@ Takes RCU read lock:
|
|||||||
|
|
||||||
Takes xa_lock internally:
|
Takes xa_lock internally:
|
||||||
* :c:func:`xa_store`
|
* :c:func:`xa_store`
|
||||||
|
* :c:func:`xa_store_bh`
|
||||||
|
* :c:func:`xa_store_irq`
|
||||||
* :c:func:`xa_insert`
|
* :c:func:`xa_insert`
|
||||||
* :c:func:`xa_erase`
|
* :c:func:`xa_erase`
|
||||||
* :c:func:`xa_erase_bh`
|
* :c:func:`xa_erase_bh`
|
||||||
@@ -167,6 +191,9 @@ Takes xa_lock internally:
|
|||||||
* :c:func:`xa_alloc`
|
* :c:func:`xa_alloc`
|
||||||
* :c:func:`xa_alloc_bh`
|
* :c:func:`xa_alloc_bh`
|
||||||
* :c:func:`xa_alloc_irq`
|
* :c:func:`xa_alloc_irq`
|
||||||
|
* :c:func:`xa_reserve`
|
||||||
|
* :c:func:`xa_reserve_bh`
|
||||||
|
* :c:func:`xa_reserve_irq`
|
||||||
* :c:func:`xa_destroy`
|
* :c:func:`xa_destroy`
|
||||||
* :c:func:`xa_set_mark`
|
* :c:func:`xa_set_mark`
|
||||||
* :c:func:`xa_clear_mark`
|
* :c:func:`xa_clear_mark`
|
||||||
@@ -177,6 +204,7 @@ Assumes xa_lock held on entry:
|
|||||||
* :c:func:`__xa_erase`
|
* :c:func:`__xa_erase`
|
||||||
* :c:func:`__xa_cmpxchg`
|
* :c:func:`__xa_cmpxchg`
|
||||||
* :c:func:`__xa_alloc`
|
* :c:func:`__xa_alloc`
|
||||||
|
* :c:func:`__xa_reserve`
|
||||||
* :c:func:`__xa_set_mark`
|
* :c:func:`__xa_set_mark`
|
||||||
* :c:func:`__xa_clear_mark`
|
* :c:func:`__xa_clear_mark`
|
||||||
|
|
||||||
@@ -234,7 +262,8 @@ Sharing the XArray with interrupt context is also possible, either
|
|||||||
using :c:func:`xa_lock_irqsave` in both the interrupt handler and process
|
using :c:func:`xa_lock_irqsave` in both the interrupt handler and process
|
||||||
context, or :c:func:`xa_lock_irq` in process context and :c:func:`xa_lock`
|
context, or :c:func:`xa_lock_irq` in process context and :c:func:`xa_lock`
|
||||||
in the interrupt handler. Some of the more common patterns have helper
|
in the interrupt handler. Some of the more common patterns have helper
|
||||||
functions such as :c:func:`xa_erase_bh` and :c:func:`xa_erase_irq`.
|
functions such as :c:func:`xa_store_bh`, :c:func:`xa_store_irq`,
|
||||||
|
:c:func:`xa_erase_bh` and :c:func:`xa_erase_irq`.
|
||||||
|
|
||||||
Sometimes you need to protect access to the XArray with a mutex because
|
Sometimes you need to protect access to the XArray with a mutex because
|
||||||
that lock sits above another mutex in the locking hierarchy. That does
|
that lock sits above another mutex in the locking hierarchy. That does
|
||||||
@@ -322,7 +351,8 @@ to :c:func:`xas_retry`, and retry the operation if it returns ``true``.
|
|||||||
- :c:func:`xa_is_zero`
|
- :c:func:`xa_is_zero`
|
||||||
- Zero entries appear as ``NULL`` through the Normal API, but occupy
|
- Zero entries appear as ``NULL`` through the Normal API, but occupy
|
||||||
an entry in the XArray which can be used to reserve the index for
|
an entry in the XArray which can be used to reserve the index for
|
||||||
future use.
|
future use. This is used by allocating XArrays for allocated entries
|
||||||
|
which are ``NULL``.
|
||||||
|
|
||||||
Other internal entries may be added in the future. As far as possible, they
|
Other internal entries may be added in the future. As far as possible, they
|
||||||
will be handled by :c:func:`xas_retry`.
|
will be handled by :c:func:`xas_retry`.
|
||||||
|
@@ -17,7 +17,7 @@ Example:
|
|||||||
reg = <1>;
|
reg = <1>;
|
||||||
clocks = <&clk32m>;
|
clocks = <&clk32m>;
|
||||||
interrupt-parent = <&gpio4>;
|
interrupt-parent = <&gpio4>;
|
||||||
interrupts = <13 IRQ_TYPE_EDGE_RISING>;
|
interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
vdd-supply = <®5v0>;
|
vdd-supply = <®5v0>;
|
||||||
xceiver-supply = <®5v0>;
|
xceiver-supply = <®5v0>;
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ Required properties:
|
|||||||
- compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC.
|
- compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC.
|
||||||
"renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC.
|
"renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC.
|
||||||
"renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC.
|
"renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC.
|
||||||
|
"renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC.
|
||||||
"renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
|
"renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
|
||||||
"renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
|
"renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
|
||||||
"renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
|
"renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
|
||||||
@@ -14,26 +15,32 @@ Required properties:
|
|||||||
"renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC.
|
"renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC.
|
||||||
"renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC.
|
"renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC.
|
||||||
"renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC.
|
"renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC.
|
||||||
|
"renesas,can-r8a77965" if CAN controller is a part of R8A77965 SoC.
|
||||||
"renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device.
|
"renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device.
|
||||||
"renesas,rcar-gen2-can" for a generic R-Car Gen2 or RZ/G1
|
"renesas,rcar-gen2-can" for a generic R-Car Gen2 or RZ/G1
|
||||||
compatible device.
|
compatible device.
|
||||||
"renesas,rcar-gen3-can" for a generic R-Car Gen3 compatible device.
|
"renesas,rcar-gen3-can" for a generic R-Car Gen3 or RZ/G2
|
||||||
|
compatible device.
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
SoC-specific version corresponding to the platform first
|
SoC-specific version corresponding to the platform first
|
||||||
followed by the generic version.
|
followed by the generic version.
|
||||||
|
|
||||||
- reg: physical base address and size of the R-Car CAN register map.
|
- reg: physical base address and size of the R-Car CAN register map.
|
||||||
- interrupts: interrupt specifier for the sole interrupt.
|
- interrupts: interrupt specifier for the sole interrupt.
|
||||||
- clocks: phandles and clock specifiers for 3 CAN clock inputs.
|
- clocks: phandles and clock specifiers for 2 CAN clock inputs for RZ/G2
|
||||||
- clock-names: 3 clock input name strings: "clkp1", "clkp2", "can_clk".
|
devices.
|
||||||
|
phandles and clock specifiers for 3 CAN clock inputs for every other
|
||||||
|
SoC.
|
||||||
|
- clock-names: 2 clock input name strings for RZ/G2: "clkp1", "can_clk".
|
||||||
|
3 clock input name strings for every other SoC: "clkp1", "clkp2",
|
||||||
|
"can_clk".
|
||||||
- pinctrl-0: pin control group to be used for this controller.
|
- pinctrl-0: pin control group to be used for this controller.
|
||||||
- pinctrl-names: must be "default".
|
- pinctrl-names: must be "default".
|
||||||
|
|
||||||
Required properties for "renesas,can-r8a7795" and "renesas,can-r8a7796"
|
Required properties for R8A7795, R8A7796 and R8A77965:
|
||||||
compatible:
|
For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can
|
||||||
In R8A7795 and R8A7796 SoCs, "clkp2" can be CANFD clock. This is a div6 clock
|
be used by both CAN and CAN FD controller at the same time. It needs to be
|
||||||
and can be used by both CAN and CAN FD controller at the same time. It needs to
|
scaled to maximum frequency if any of these controllers use it. This is done
|
||||||
be scaled to maximum frequency if any of these controllers use it. This is done
|
|
||||||
using the below properties:
|
using the below properties:
|
||||||
|
|
||||||
- assigned-clocks: phandle of clkp2(CANFD) clock.
|
- assigned-clocks: phandle of clkp2(CANFD) clock.
|
||||||
@@ -42,8 +49,9 @@ using the below properties:
|
|||||||
Optional properties:
|
Optional properties:
|
||||||
- renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are:
|
- renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are:
|
||||||
<0x0> (default) : Peripheral clock (clkp1)
|
<0x0> (default) : Peripheral clock (clkp1)
|
||||||
<0x1> : Peripheral clock (clkp2)
|
<0x1> : Peripheral clock (clkp2) (not supported by
|
||||||
<0x3> : Externally input clock
|
RZ/G2 devices)
|
||||||
|
<0x3> : External input clock
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
@@ -7,7 +7,7 @@ limitations.
|
|||||||
Current Binding
|
Current Binding
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Switches are true Linux devices and can be probes by any means. Once
|
Switches are true Linux devices and can be probed by any means. Once
|
||||||
probed, they register to the DSA framework, passing a node
|
probed, they register to the DSA framework, passing a node
|
||||||
pointer. This node is expected to fulfil the following binding, and
|
pointer. This node is expected to fulfil the following binding, and
|
||||||
may contain additional properties as required by the device it is
|
may contain additional properties as required by the device it is
|
||||||
|
@@ -190,16 +190,7 @@ A few EV_REL codes have special meanings:
|
|||||||
* REL_WHEEL, REL_HWHEEL:
|
* REL_WHEEL, REL_HWHEEL:
|
||||||
|
|
||||||
- These codes are used for vertical and horizontal scroll wheels,
|
- These codes are used for vertical and horizontal scroll wheels,
|
||||||
respectively. The value is the number of "notches" moved on the wheel, the
|
respectively.
|
||||||
physical size of which varies by device. For high-resolution wheels (which
|
|
||||||
report multiple events for each notch of movement, or do not have notches)
|
|
||||||
this may be an approximation based on the high-resolution scroll events.
|
|
||||||
|
|
||||||
* REL_WHEEL_HI_RES:
|
|
||||||
|
|
||||||
- If a vertical scroll wheel supports high-resolution scrolling, this code
|
|
||||||
will be emitted in addition to REL_WHEEL. The value is the (approximate)
|
|
||||||
distance travelled by the user's finger, in microns.
|
|
||||||
|
|
||||||
EV_ABS
|
EV_ABS
|
||||||
------
|
------
|
||||||
|
@@ -40,7 +40,7 @@ To use the :ref:`format` ioctls applications set the ``type`` field of the
|
|||||||
the desired operation. Both drivers and applications must set the remainder of
|
the desired operation. Both drivers and applications must set the remainder of
|
||||||
the :c:type:`v4l2_format` structure to 0.
|
the :c:type:`v4l2_format` structure to 0.
|
||||||
|
|
||||||
.. _v4l2-meta-format:
|
.. c:type:: v4l2_meta_format
|
||||||
|
|
||||||
.. tabularcolumns:: |p{1.4cm}|p{2.2cm}|p{13.9cm}|
|
.. tabularcolumns:: |p{1.4cm}|p{2.2cm}|p{13.9cm}|
|
||||||
|
|
||||||
|
@@ -132,6 +132,11 @@ The format as returned by :ref:`VIDIOC_TRY_FMT <VIDIOC_G_FMT>` must be identical
|
|||||||
- ``sdr``
|
- ``sdr``
|
||||||
- Definition of a data format, see :ref:`pixfmt`, used by SDR
|
- Definition of a data format, see :ref:`pixfmt`, used by SDR
|
||||||
capture and output devices.
|
capture and output devices.
|
||||||
|
* -
|
||||||
|
- struct :c:type:`v4l2_meta_format`
|
||||||
|
- ``meta``
|
||||||
|
- Definition of a metadata format, see :ref:`meta-formats`, used by
|
||||||
|
metadata capture devices.
|
||||||
* -
|
* -
|
||||||
- __u8
|
- __u8
|
||||||
- ``raw_data``\ [200]
|
- ``raw_data``\ [200]
|
||||||
|
@@ -1056,18 +1056,23 @@ The kernel interface functions are as follows:
|
|||||||
|
|
||||||
u32 rxrpc_kernel_check_life(struct socket *sock,
|
u32 rxrpc_kernel_check_life(struct socket *sock,
|
||||||
struct rxrpc_call *call);
|
struct rxrpc_call *call);
|
||||||
|
void rxrpc_kernel_probe_life(struct socket *sock,
|
||||||
|
struct rxrpc_call *call);
|
||||||
|
|
||||||
This returns a number that is updated when ACKs are received from the peer
|
The first function returns a number that is updated when ACKs are received
|
||||||
(notably including PING RESPONSE ACKs which we can elicit by sending PING
|
from the peer (notably including PING RESPONSE ACKs which we can elicit by
|
||||||
ACKs to see if the call still exists on the server). The caller should
|
sending PING ACKs to see if the call still exists on the server). The
|
||||||
compare the numbers of two calls to see if the call is still alive after
|
caller should compare the numbers of two calls to see if the call is still
|
||||||
waiting for a suitable interval.
|
alive after waiting for a suitable interval.
|
||||||
|
|
||||||
This allows the caller to work out if the server is still contactable and
|
This allows the caller to work out if the server is still contactable and
|
||||||
if the call is still alive on the server whilst waiting for the server to
|
if the call is still alive on the server whilst waiting for the server to
|
||||||
process a client operation.
|
process a client operation.
|
||||||
|
|
||||||
This function may transmit a PING ACK.
|
The second function causes a ping ACK to be transmitted to try to provoke
|
||||||
|
the peer into responding, which would then cause the value returned by the
|
||||||
|
first function to change. Note that this must be called in TASK_RUNNING
|
||||||
|
state.
|
||||||
|
|
||||||
(*) Get reply timestamp.
|
(*) Get reply timestamp.
|
||||||
|
|
||||||
|
48
MAINTAINERS
48
MAINTAINERS
@@ -180,6 +180,7 @@ F: drivers/net/hamradio/6pack.c
|
|||||||
|
|
||||||
8169 10/100/1000 GIGABIT ETHERNET DRIVER
|
8169 10/100/1000 GIGABIT ETHERNET DRIVER
|
||||||
M: Realtek linux nic maintainers <nic_swsd@realtek.com>
|
M: Realtek linux nic maintainers <nic_swsd@realtek.com>
|
||||||
|
M: Heiner Kallweit <hkallweit1@gmail.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/ethernet/realtek/r8169.c
|
F: drivers/net/ethernet/realtek/r8169.c
|
||||||
@@ -717,7 +718,7 @@ F: include/linux/mfd/altera-a10sr.h
|
|||||||
F: include/dt-bindings/reset/altr,rst-mgr-a10sr.h
|
F: include/dt-bindings/reset/altr,rst-mgr-a10sr.h
|
||||||
|
|
||||||
ALTERA TRIPLE SPEED ETHERNET DRIVER
|
ALTERA TRIPLE SPEED ETHERNET DRIVER
|
||||||
M: Vince Bridgers <vbridger@opensource.altera.com>
|
M: Thor Thayer <thor.thayer@linux.intel.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
|
L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@@ -3276,6 +3277,12 @@ F: include/uapi/linux/caif/
|
|||||||
F: include/net/caif/
|
F: include/net/caif/
|
||||||
F: net/caif/
|
F: net/caif/
|
||||||
|
|
||||||
|
CAKE QDISC
|
||||||
|
M: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
|
L: cake@lists.bufferbloat.net (moderated for non-subscribers)
|
||||||
|
S: Maintained
|
||||||
|
F: net/sched/sch_cake.c
|
||||||
|
|
||||||
CALGARY x86-64 IOMMU
|
CALGARY x86-64 IOMMU
|
||||||
M: Muli Ben-Yehuda <mulix@mulix.org>
|
M: Muli Ben-Yehuda <mulix@mulix.org>
|
||||||
M: Jon Mason <jdmason@kudzu.us>
|
M: Jon Mason <jdmason@kudzu.us>
|
||||||
@@ -5541,6 +5548,7 @@ F: net/bridge/
|
|||||||
ETHERNET PHY LIBRARY
|
ETHERNET PHY LIBRARY
|
||||||
M: Andrew Lunn <andrew@lunn.ch>
|
M: Andrew Lunn <andrew@lunn.ch>
|
||||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
M: Heiner Kallweit <hkallweit1@gmail.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/ABI/testing/sysfs-bus-mdio
|
F: Documentation/ABI/testing/sysfs-bus-mdio
|
||||||
@@ -6312,6 +6320,7 @@ F: tools/testing/selftests/gpio/
|
|||||||
|
|
||||||
GPIO SUBSYSTEM
|
GPIO SUBSYSTEM
|
||||||
M: Linus Walleij <linus.walleij@linaro.org>
|
M: Linus Walleij <linus.walleij@linaro.org>
|
||||||
|
M: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||||
L: linux-gpio@vger.kernel.org
|
L: linux-gpio@vger.kernel.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@@ -7449,6 +7458,20 @@ S: Maintained
|
|||||||
F: Documentation/fb/intelfb.txt
|
F: Documentation/fb/intelfb.txt
|
||||||
F: drivers/video/fbdev/intelfb/
|
F: drivers/video/fbdev/intelfb/
|
||||||
|
|
||||||
|
INTEL GPIO DRIVERS
|
||||||
|
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||||
|
L: linux-gpio@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||||
|
F: drivers/gpio/gpio-ich.c
|
||||||
|
F: drivers/gpio/gpio-intel-mid.c
|
||||||
|
F: drivers/gpio/gpio-lynxpoint.c
|
||||||
|
F: drivers/gpio/gpio-merrifield.c
|
||||||
|
F: drivers/gpio/gpio-ml-ioh.c
|
||||||
|
F: drivers/gpio/gpio-pch.c
|
||||||
|
F: drivers/gpio/gpio-sch.c
|
||||||
|
F: drivers/gpio/gpio-sodaville.c
|
||||||
|
|
||||||
INTEL GVT-g DRIVERS (Intel GPU Virtualization)
|
INTEL GVT-g DRIVERS (Intel GPU Virtualization)
|
||||||
M: Zhenyu Wang <zhenyuw@linux.intel.com>
|
M: Zhenyu Wang <zhenyuw@linux.intel.com>
|
||||||
M: Zhi Wang <zhi.a.wang@intel.com>
|
M: Zhi Wang <zhi.a.wang@intel.com>
|
||||||
@@ -7459,12 +7482,6 @@ T: git https://github.com/intel/gvt-linux.git
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/gpu/drm/i915/gvt/
|
F: drivers/gpu/drm/i915/gvt/
|
||||||
|
|
||||||
INTEL PMIC GPIO DRIVER
|
|
||||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|
||||||
S: Maintained
|
|
||||||
F: drivers/gpio/gpio-*cove.c
|
|
||||||
F: drivers/gpio/gpio-msic.c
|
|
||||||
|
|
||||||
INTEL HID EVENT DRIVER
|
INTEL HID EVENT DRIVER
|
||||||
M: Alex Hung <alex.hung@canonical.com>
|
M: Alex Hung <alex.hung@canonical.com>
|
||||||
L: platform-driver-x86@vger.kernel.org
|
L: platform-driver-x86@vger.kernel.org
|
||||||
@@ -7552,12 +7569,6 @@ W: https://01.org/linux-acpi
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/platform/x86/intel_menlow.c
|
F: drivers/platform/x86/intel_menlow.c
|
||||||
|
|
||||||
INTEL MERRIFIELD GPIO DRIVER
|
|
||||||
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|
||||||
L: linux-gpio@vger.kernel.org
|
|
||||||
S: Maintained
|
|
||||||
F: drivers/gpio/gpio-merrifield.c
|
|
||||||
|
|
||||||
INTEL MIC DRIVERS (mic)
|
INTEL MIC DRIVERS (mic)
|
||||||
M: Sudeep Dutt <sudeep.dutt@intel.com>
|
M: Sudeep Dutt <sudeep.dutt@intel.com>
|
||||||
M: Ashutosh Dixit <ashutosh.dixit@intel.com>
|
M: Ashutosh Dixit <ashutosh.dixit@intel.com>
|
||||||
@@ -7590,6 +7601,13 @@ F: drivers/platform/x86/intel_punit_ipc.c
|
|||||||
F: arch/x86/include/asm/intel_pmc_ipc.h
|
F: arch/x86/include/asm/intel_pmc_ipc.h
|
||||||
F: arch/x86/include/asm/intel_punit_ipc.h
|
F: arch/x86/include/asm/intel_punit_ipc.h
|
||||||
|
|
||||||
|
INTEL PMIC GPIO DRIVERS
|
||||||
|
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||||
|
S: Maintained
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||||
|
F: drivers/gpio/gpio-*cove.c
|
||||||
|
F: drivers/gpio/gpio-msic.c
|
||||||
|
|
||||||
INTEL MULTIFUNCTION PMIC DEVICE DRIVERS
|
INTEL MULTIFUNCTION PMIC DEVICE DRIVERS
|
||||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@@ -13991,11 +14009,10 @@ F: drivers/tty/serial/sunzilog.h
|
|||||||
F: drivers/tty/vcc.c
|
F: drivers/tty/vcc.c
|
||||||
|
|
||||||
SPARSE CHECKER
|
SPARSE CHECKER
|
||||||
M: "Christopher Li" <sparse@chrisli.org>
|
M: "Luc Van Oostenryck" <luc.vanoostenryck@gmail.com>
|
||||||
L: linux-sparse@vger.kernel.org
|
L: linux-sparse@vger.kernel.org
|
||||||
W: https://sparse.wiki.kernel.org/
|
W: https://sparse.wiki.kernel.org/
|
||||||
T: git git://git.kernel.org/pub/scm/devel/sparse/sparse.git
|
T: git git://git.kernel.org/pub/scm/devel/sparse/sparse.git
|
||||||
T: git git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/linux/compiler.h
|
F: include/linux/compiler.h
|
||||||
|
|
||||||
@@ -14092,6 +14109,7 @@ F: Documentation/devicetree/bindings/iio/proximity/vl53l0x.txt
|
|||||||
|
|
||||||
STABLE BRANCH
|
STABLE BRANCH
|
||||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
M: Sasha Levin <sashal@kernel.org>
|
||||||
L: stable@vger.kernel.org
|
L: stable@vger.kernel.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: Documentation/process/stable-kernel-rules.rst
|
F: Documentation/process/stable-kernel-rules.rst
|
||||||
|
4
Makefile
4
Makefile
@@ -2,8 +2,8 @@
|
|||||||
VERSION = 4
|
VERSION = 4
|
||||||
PATCHLEVEL = 20
|
PATCHLEVEL = 20
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION = -rc3
|
EXTRAVERSION = -rc4
|
||||||
NAME = "People's Front"
|
NAME = Shy Crocodile
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
# To see a list of typical targets execute "make help"
|
# To see a list of typical targets execute "make help"
|
||||||
|
@@ -468,7 +468,7 @@
|
|||||||
SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_WXN | \
|
SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_WXN | \
|
||||||
SCTLR_ELx_DSSBS | ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0)
|
SCTLR_ELx_DSSBS | ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0)
|
||||||
|
|
||||||
#if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffffffffffff
|
#if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffffffffffffUL
|
||||||
#error "Inconsistent SCTLR_EL2 set/clear bits"
|
#error "Inconsistent SCTLR_EL2 set/clear bits"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -509,7 +509,7 @@
|
|||||||
SCTLR_EL1_UMA | SCTLR_ELx_WXN | ENDIAN_CLEAR_EL1 |\
|
SCTLR_EL1_UMA | SCTLR_ELx_WXN | ENDIAN_CLEAR_EL1 |\
|
||||||
SCTLR_ELx_DSSBS | SCTLR_EL1_NTWI | SCTLR_EL1_RES0)
|
SCTLR_ELx_DSSBS | SCTLR_EL1_NTWI | SCTLR_EL1_RES0)
|
||||||
|
|
||||||
#if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffffffffffff
|
#if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffffffffffffUL
|
||||||
#error "Inconsistent SCTLR_EL1 set/clear bits"
|
#error "Inconsistent SCTLR_EL1 set/clear bits"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -1333,7 +1333,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|||||||
.cpu_enable = cpu_enable_hw_dbm,
|
.cpu_enable = cpu_enable_hw_dbm,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_ARM64_SSBD
|
|
||||||
{
|
{
|
||||||
.desc = "CRC32 instructions",
|
.desc = "CRC32 instructions",
|
||||||
.capability = ARM64_HAS_CRC32,
|
.capability = ARM64_HAS_CRC32,
|
||||||
@@ -1343,6 +1342,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|||||||
.field_pos = ID_AA64ISAR0_CRC32_SHIFT,
|
.field_pos = ID_AA64ISAR0_CRC32_SHIFT,
|
||||||
.min_field_value = 1,
|
.min_field_value = 1,
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_ARM64_SSBD
|
||||||
{
|
{
|
||||||
.desc = "Speculative Store Bypassing Safe (SSBS)",
|
.desc = "Speculative Store Bypassing Safe (SSBS)",
|
||||||
.capability = ARM64_SSBS,
|
.capability = ARM64_SSBS,
|
||||||
|
@@ -140,6 +140,7 @@ CONFIG_RTC_CLASS=y
|
|||||||
CONFIG_RTC_DRV_DS1307=y
|
CONFIG_RTC_DRV_DS1307=y
|
||||||
CONFIG_STAGING=y
|
CONFIG_STAGING=y
|
||||||
CONFIG_OCTEON_ETHERNET=y
|
CONFIG_OCTEON_ETHERNET=y
|
||||||
|
CONFIG_OCTEON_USB=y
|
||||||
# CONFIG_IOMMU_SUPPORT is not set
|
# CONFIG_IOMMU_SUPPORT is not set
|
||||||
CONFIG_RAS=y
|
CONFIG_RAS=y
|
||||||
CONFIG_EXT4_FS=y
|
CONFIG_EXT4_FS=y
|
||||||
|
@@ -794,6 +794,7 @@ static void __init arch_mem_init(char **cmdline_p)
|
|||||||
|
|
||||||
/* call board setup routine */
|
/* call board setup routine */
|
||||||
plat_mem_setup();
|
plat_mem_setup();
|
||||||
|
memblock_set_bottom_up(true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure all kernel memory is in the maps. The "UP" and
|
* Make sure all kernel memory is in the maps. The "UP" and
|
||||||
|
@@ -2260,10 +2260,8 @@ void __init trap_init(void)
|
|||||||
unsigned long size = 0x200 + VECTORSPACING*64;
|
unsigned long size = 0x200 + VECTORSPACING*64;
|
||||||
phys_addr_t ebase_pa;
|
phys_addr_t ebase_pa;
|
||||||
|
|
||||||
memblock_set_bottom_up(true);
|
|
||||||
ebase = (unsigned long)
|
ebase = (unsigned long)
|
||||||
memblock_alloc_from(size, 1 << fls(size), 0);
|
memblock_alloc_from(size, 1 << fls(size), 0);
|
||||||
memblock_set_bottom_up(false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to ensure ebase resides in KSeg0 if possible.
|
* Try to ensure ebase resides in KSeg0 if possible.
|
||||||
@@ -2307,6 +2305,7 @@ void __init trap_init(void)
|
|||||||
if (board_ebase_setup)
|
if (board_ebase_setup)
|
||||||
board_ebase_setup();
|
board_ebase_setup();
|
||||||
per_cpu_trap_init(true);
|
per_cpu_trap_init(true);
|
||||||
|
memblock_set_bottom_up(false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy the generic exception handlers to their final destination.
|
* Copy the generic exception handlers to their final destination.
|
||||||
|
@@ -231,6 +231,8 @@ static __init void prom_meminit(void)
|
|||||||
cpumask_clear(&__node_data[(node)]->cpumask);
|
cpumask_clear(&__node_data[(node)]->cpumask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
|
||||||
|
|
||||||
for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) {
|
for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) {
|
||||||
node = cpu / loongson_sysconf.cores_per_node;
|
node = cpu / loongson_sysconf.cores_per_node;
|
||||||
if (node >= num_online_nodes())
|
if (node >= num_online_nodes())
|
||||||
@@ -248,19 +250,9 @@ static __init void prom_meminit(void)
|
|||||||
|
|
||||||
void __init paging_init(void)
|
void __init paging_init(void)
|
||||||
{
|
{
|
||||||
unsigned node;
|
|
||||||
unsigned long zones_size[MAX_NR_ZONES] = {0, };
|
unsigned long zones_size[MAX_NR_ZONES] = {0, };
|
||||||
|
|
||||||
pagetable_init();
|
pagetable_init();
|
||||||
|
|
||||||
for_each_online_node(node) {
|
|
||||||
unsigned long start_pfn, end_pfn;
|
|
||||||
|
|
||||||
get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
|
|
||||||
|
|
||||||
if (end_pfn > max_low_pfn)
|
|
||||||
max_low_pfn = end_pfn;
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_ZONE_DMA32
|
#ifdef CONFIG_ZONE_DMA32
|
||||||
zones_size[ZONE_DMA32] = MAX_DMA32_PFN;
|
zones_size[ZONE_DMA32] = MAX_DMA32_PFN;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -435,6 +435,7 @@ void __init prom_meminit(void)
|
|||||||
|
|
||||||
mlreset();
|
mlreset();
|
||||||
szmem();
|
szmem();
|
||||||
|
max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
|
||||||
|
|
||||||
for (node = 0; node < MAX_COMPACT_NODES; node++) {
|
for (node = 0; node < MAX_COMPACT_NODES; node++) {
|
||||||
if (node_online(node)) {
|
if (node_online(node)) {
|
||||||
@@ -455,18 +456,8 @@ extern void setup_zero_pages(void);
|
|||||||
void __init paging_init(void)
|
void __init paging_init(void)
|
||||||
{
|
{
|
||||||
unsigned long zones_size[MAX_NR_ZONES] = {0, };
|
unsigned long zones_size[MAX_NR_ZONES] = {0, };
|
||||||
unsigned node;
|
|
||||||
|
|
||||||
pagetable_init();
|
pagetable_init();
|
||||||
|
|
||||||
for_each_online_node(node) {
|
|
||||||
unsigned long start_pfn, end_pfn;
|
|
||||||
|
|
||||||
get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
|
|
||||||
|
|
||||||
if (end_pfn > max_low_pfn)
|
|
||||||
max_low_pfn = end_pfn;
|
|
||||||
}
|
|
||||||
zones_size[ZONE_NORMAL] = max_low_pfn;
|
zones_size[ZONE_NORMAL] = max_low_pfn;
|
||||||
free_area_init_nodes(zones_size);
|
free_area_init_nodes(zones_size);
|
||||||
}
|
}
|
||||||
|
@@ -71,6 +71,10 @@ KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
|
|||||||
# arch specific predefines for sparse
|
# arch specific predefines for sparse
|
||||||
CHECKFLAGS += -D__riscv -D__riscv_xlen=$(BITS)
|
CHECKFLAGS += -D__riscv -D__riscv_xlen=$(BITS)
|
||||||
|
|
||||||
|
# Default target when executing plain make
|
||||||
|
boot := arch/riscv/boot
|
||||||
|
KBUILD_IMAGE := $(boot)/Image.gz
|
||||||
|
|
||||||
head-y := arch/riscv/kernel/head.o
|
head-y := arch/riscv/kernel/head.o
|
||||||
|
|
||||||
core-y += arch/riscv/kernel/ arch/riscv/mm/
|
core-y += arch/riscv/kernel/ arch/riscv/mm/
|
||||||
@@ -81,4 +85,13 @@ PHONY += vdso_install
|
|||||||
vdso_install:
|
vdso_install:
|
||||||
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
|
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
|
||||||
|
|
||||||
all: vmlinux
|
all: Image.gz
|
||||||
|
|
||||||
|
Image: vmlinux
|
||||||
|
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||||
|
|
||||||
|
Image.%: Image
|
||||||
|
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||||
|
|
||||||
|
zinstall install:
|
||||||
|
$(Q)$(MAKE) $(build)=$(boot) $@
|
||||||
|
2
arch/riscv/boot/.gitignore
vendored
Normal file
2
arch/riscv/boot/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Image
|
||||||
|
Image.gz
|
33
arch/riscv/boot/Makefile
Normal file
33
arch/riscv/boot/Makefile
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#
|
||||||
|
# arch/riscv/boot/Makefile
|
||||||
|
#
|
||||||
|
# This file is included by the global makefile so that you can add your own
|
||||||
|
# architecture-specific flags and dependencies.
|
||||||
|
#
|
||||||
|
# This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
# License. See the file "COPYING" in the main directory of this archive
|
||||||
|
# for more details.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018, Anup Patel.
|
||||||
|
# Author: Anup Patel <anup@brainfault.org>
|
||||||
|
#
|
||||||
|
# Based on the ia64 and arm64 boot/Makefile.
|
||||||
|
#
|
||||||
|
|
||||||
|
OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
|
||||||
|
|
||||||
|
targets := Image
|
||||||
|
|
||||||
|
$(obj)/Image: vmlinux FORCE
|
||||||
|
$(call if_changed,objcopy)
|
||||||
|
|
||||||
|
$(obj)/Image.gz: $(obj)/Image FORCE
|
||||||
|
$(call if_changed,gzip)
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
|
||||||
|
$(obj)/Image System.map "$(INSTALL_PATH)"
|
||||||
|
|
||||||
|
zinstall:
|
||||||
|
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
|
||||||
|
$(obj)/Image.gz System.map "$(INSTALL_PATH)"
|
60
arch/riscv/boot/install.sh
Normal file
60
arch/riscv/boot/install.sh
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# arch/riscv/boot/install.sh
|
||||||
|
#
|
||||||
|
# This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
# License. See the file "COPYING" in the main directory of this archive
|
||||||
|
# for more details.
|
||||||
|
#
|
||||||
|
# Copyright (C) 1995 by Linus Torvalds
|
||||||
|
#
|
||||||
|
# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
|
||||||
|
# Adapted from code in arch/i386/boot/install.sh by Russell King
|
||||||
|
#
|
||||||
|
# "make install" script for the RISC-V Linux port
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# $1 - kernel version
|
||||||
|
# $2 - kernel image file
|
||||||
|
# $3 - kernel map file
|
||||||
|
# $4 - default install path (blank if root directory)
|
||||||
|
#
|
||||||
|
|
||||||
|
verify () {
|
||||||
|
if [ ! -f "$1" ]; then
|
||||||
|
echo "" 1>&2
|
||||||
|
echo " *** Missing file: $1" 1>&2
|
||||||
|
echo ' *** You need to run "make" before "make install".' 1>&2
|
||||||
|
echo "" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make sure the files actually exist
|
||||||
|
verify "$2"
|
||||||
|
verify "$3"
|
||||||
|
|
||||||
|
# User may have a custom install script
|
||||||
|
if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
|
||||||
|
if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
|
||||||
|
|
||||||
|
if [ "$(basename $2)" = "Image.gz" ]; then
|
||||||
|
# Compressed install
|
||||||
|
echo "Installing compressed kernel"
|
||||||
|
base=vmlinuz
|
||||||
|
else
|
||||||
|
# Normal install
|
||||||
|
echo "Installing normal kernel"
|
||||||
|
base=vmlinux
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f $4/$base-$1 ]; then
|
||||||
|
mv $4/$base-$1 $4/$base-$1.old
|
||||||
|
fi
|
||||||
|
cat $2 > $4/$base-$1
|
||||||
|
|
||||||
|
# Install system map file
|
||||||
|
if [ -f $4/System.map-$1 ]; then
|
||||||
|
mv $4/System.map-$1 $4/System.map-$1.old
|
||||||
|
fi
|
||||||
|
cp $3 $4/System.map-$1
|
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#define MODULE_ARCH_VERMAGIC "riscv"
|
#define MODULE_ARCH_VERMAGIC "riscv"
|
||||||
|
|
||||||
|
struct module;
|
||||||
u64 module_emit_got_entry(struct module *mod, u64 val);
|
u64 module_emit_got_entry(struct module *mod, u64 val);
|
||||||
u64 module_emit_plt_entry(struct module *mod, u64 val);
|
u64 module_emit_plt_entry(struct module *mod, u64 val);
|
||||||
|
|
||||||
|
@@ -400,13 +400,13 @@ extern unsigned long __must_check __asm_copy_from_user(void *to,
|
|||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||||
{
|
{
|
||||||
return __asm_copy_to_user(to, from, n);
|
return __asm_copy_from_user(to, from, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||||
{
|
{
|
||||||
return __asm_copy_from_user(to, from, n);
|
return __asm_copy_to_user(to, from, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern long strncpy_from_user(char *dest, const char __user *src, long count);
|
extern long strncpy_from_user(char *dest, const char __user *src, long count);
|
||||||
|
@@ -13,10 +13,9 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* There is explicitly no include guard here because this file is expected to
|
* There is explicitly no include guard here because this file is expected to
|
||||||
* be included multiple times. See uapi/asm/syscalls.h for more info.
|
* be included multiple times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __ARCH_WANT_NEW_STAT
|
|
||||||
#define __ARCH_WANT_SYS_CLONE
|
#define __ARCH_WANT_SYS_CLONE
|
||||||
|
|
||||||
#include <uapi/asm/unistd.h>
|
#include <uapi/asm/unistd.h>
|
||||||
#include <uapi/asm/syscalls.h>
|
|
||||||
|
@@ -1,13 +1,25 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017-2018 SiFive
|
* Copyright (C) 2018 David Abdurachmanov <david.abdurachmanov@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
#ifdef __LP64__
|
||||||
* There is explicitly no include guard here because this file is expected to
|
#define __ARCH_WANT_NEW_STAT
|
||||||
* be included multiple times in order to define the syscall macros via
|
#endif /* __LP64__ */
|
||||||
* __SYSCALL.
|
|
||||||
*/
|
#include <asm-generic/unistd.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allows the instruction cache to be flushed from userspace. Despite RISC-V
|
* Allows the instruction cache to be flushed from userspace. Despite RISC-V
|
@@ -64,7 +64,7 @@ int riscv_of_processor_hartid(struct device_node *node)
|
|||||||
|
|
||||||
static void print_isa(struct seq_file *f, const char *orig_isa)
|
static void print_isa(struct seq_file *f, const char *orig_isa)
|
||||||
{
|
{
|
||||||
static const char *ext = "mafdc";
|
static const char *ext = "mafdcsu";
|
||||||
const char *isa = orig_isa;
|
const char *isa = orig_isa;
|
||||||
const char *e;
|
const char *e;
|
||||||
|
|
||||||
@@ -88,11 +88,14 @@ static void print_isa(struct seq_file *f, const char *orig_isa)
|
|||||||
/*
|
/*
|
||||||
* Check the rest of the ISA string for valid extensions, printing those
|
* Check the rest of the ISA string for valid extensions, printing those
|
||||||
* we find. RISC-V ISA strings define an order, so we only print the
|
* we find. RISC-V ISA strings define an order, so we only print the
|
||||||
* extension bits when they're in order.
|
* extension bits when they're in order. Hide the supervisor (S)
|
||||||
|
* extension from userspace as it's not accessible from there.
|
||||||
*/
|
*/
|
||||||
for (e = ext; *e != '\0'; ++e) {
|
for (e = ext; *e != '\0'; ++e) {
|
||||||
if (isa[0] == e[0]) {
|
if (isa[0] == e[0]) {
|
||||||
|
if (isa[0] != 's')
|
||||||
seq_write(f, isa, 1);
|
seq_write(f, isa, 1);
|
||||||
|
|
||||||
isa++;
|
isa++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,6 +44,16 @@ ENTRY(_start)
|
|||||||
amoadd.w a3, a2, (a3)
|
amoadd.w a3, a2, (a3)
|
||||||
bnez a3, .Lsecondary_start
|
bnez a3, .Lsecondary_start
|
||||||
|
|
||||||
|
/* Clear BSS for flat non-ELF images */
|
||||||
|
la a3, __bss_start
|
||||||
|
la a4, __bss_stop
|
||||||
|
ble a4, a3, clear_bss_done
|
||||||
|
clear_bss:
|
||||||
|
REG_S zero, (a3)
|
||||||
|
add a3, a3, RISCV_SZPTR
|
||||||
|
blt a3, a4, clear_bss
|
||||||
|
clear_bss_done:
|
||||||
|
|
||||||
/* Save hart ID and DTB physical address */
|
/* Save hart ID and DTB physical address */
|
||||||
mv s0, a0
|
mv s0, a0
|
||||||
mv s1, a1
|
mv s1, a1
|
||||||
|
@@ -74,7 +74,7 @@ SECTIONS
|
|||||||
*(.sbss*)
|
*(.sbss*)
|
||||||
}
|
}
|
||||||
|
|
||||||
BSS_SECTION(0, 0, 0)
|
BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
|
||||||
|
|
||||||
EXCEPTION_TABLE(0x10)
|
EXCEPTION_TABLE(0x10)
|
||||||
NOTES
|
NOTES
|
||||||
|
@@ -30,6 +30,7 @@ static const struct acpi_device_id forbidden_id_list[] = {
|
|||||||
{"PNP0200", 0}, /* AT DMA Controller */
|
{"PNP0200", 0}, /* AT DMA Controller */
|
||||||
{"ACPI0009", 0}, /* IOxAPIC */
|
{"ACPI0009", 0}, /* IOxAPIC */
|
||||||
{"ACPI000A", 0}, /* IOAPIC */
|
{"ACPI000A", 0}, /* IOAPIC */
|
||||||
|
{"SMB0001", 0}, /* ACPI SMBUS virtual device */
|
||||||
{"", 0},
|
{"", 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -201,19 +201,28 @@ static const struct of_device_id ti_cpufreq_of_match[] = {
|
|||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id *ti_cpufreq_match_node(void)
|
||||||
|
{
|
||||||
|
struct device_node *np;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
|
||||||
|
np = of_find_node_by_path("/");
|
||||||
|
match = of_match_node(ti_cpufreq_of_match, np);
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
static int ti_cpufreq_probe(struct platform_device *pdev)
|
static int ti_cpufreq_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
u32 version[VERSION_COUNT];
|
u32 version[VERSION_COUNT];
|
||||||
struct device_node *np;
|
|
||||||
const struct of_device_id *match;
|
const struct of_device_id *match;
|
||||||
struct opp_table *ti_opp_table;
|
struct opp_table *ti_opp_table;
|
||||||
struct ti_cpufreq_data *opp_data;
|
struct ti_cpufreq_data *opp_data;
|
||||||
const char * const reg_names[] = {"vdd", "vbb"};
|
const char * const reg_names[] = {"vdd", "vbb"};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
np = of_find_node_by_path("/");
|
match = dev_get_platdata(&pdev->dev);
|
||||||
match = of_match_node(ti_cpufreq_of_match, np);
|
|
||||||
of_node_put(np);
|
|
||||||
if (!match)
|
if (!match)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
@@ -290,7 +299,14 @@ fail_put_node:
|
|||||||
|
|
||||||
static int ti_cpufreq_init(void)
|
static int ti_cpufreq_init(void)
|
||||||
{
|
{
|
||||||
platform_device_register_simple("ti-cpufreq", -1, NULL, 0);
|
const struct of_device_id *match;
|
||||||
|
|
||||||
|
/* Check to ensure we are on a compatible platform */
|
||||||
|
match = ti_cpufreq_match_node();
|
||||||
|
if (match)
|
||||||
|
platform_device_register_data(NULL, "ti-cpufreq", -1, match,
|
||||||
|
sizeof(*match));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
module_init(ti_cpufreq_init);
|
module_init(ti_cpufreq_init);
|
||||||
|
@@ -184,6 +184,7 @@ static long udmabuf_create(const struct udmabuf_create_list *head,
|
|||||||
exp_info.ops = &udmabuf_ops;
|
exp_info.ops = &udmabuf_ops;
|
||||||
exp_info.size = ubuf->pagecount << PAGE_SHIFT;
|
exp_info.size = ubuf->pagecount << PAGE_SHIFT;
|
||||||
exp_info.priv = ubuf;
|
exp_info.priv = ubuf;
|
||||||
|
exp_info.flags = O_RDWR;
|
||||||
|
|
||||||
buf = dma_buf_export(&exp_info);
|
buf = dma_buf_export(&exp_info);
|
||||||
if (IS_ERR(buf)) {
|
if (IS_ERR(buf)) {
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
#include <linux/serdev.h>
|
#include <linux/serdev.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ static int gnss_serial_write_raw(struct gnss_device *gdev,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* write is only buffered synchronously */
|
/* write is only buffered synchronously */
|
||||||
ret = serdev_device_write(serdev, buf, count, 0);
|
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
#include <linux/serdev.h>
|
#include <linux/serdev.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
@@ -83,7 +84,7 @@ static int sirf_write_raw(struct gnss_device *gdev, const unsigned char *buf,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* write is only buffered synchronously */
|
/* write is only buffered synchronously */
|
||||||
ret = serdev_device_write(serdev, buf, count, 0);
|
ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@@ -35,8 +35,8 @@
|
|||||||
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
|
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GPIO_MOCKUP_DIR_OUT = 0,
|
GPIO_MOCKUP_DIR_IN = 0,
|
||||||
GPIO_MOCKUP_DIR_IN = 1,
|
GPIO_MOCKUP_DIR_OUT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -131,7 +131,7 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
|
|||||||
{
|
{
|
||||||
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
||||||
|
|
||||||
return chip->lines[offset].dir;
|
return !chip->lines[offset].dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)
|
static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||||
|
@@ -268,8 +268,8 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|||||||
|
|
||||||
if (pxa_gpio_has_pinctrl()) {
|
if (pxa_gpio_has_pinctrl()) {
|
||||||
ret = pinctrl_gpio_direction_input(chip->base + offset);
|
ret = pinctrl_gpio_direction_input(chip->base + offset);
|
||||||
if (!ret)
|
if (ret)
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
|
@@ -1295,7 +1295,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
|||||||
gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
|
gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
|
||||||
if (!gdev->descs) {
|
if (!gdev->descs) {
|
||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
goto err_free_gdev;
|
goto err_free_ida;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->ngpio == 0) {
|
if (chip->ngpio == 0) {
|
||||||
@@ -1427,8 +1427,9 @@ err_free_label:
|
|||||||
kfree_const(gdev->label);
|
kfree_const(gdev->label);
|
||||||
err_free_descs:
|
err_free_descs:
|
||||||
kfree(gdev->descs);
|
kfree(gdev->descs);
|
||||||
err_free_gdev:
|
err_free_ida:
|
||||||
ida_simple_remove(&gpio_ida, gdev->id);
|
ida_simple_remove(&gpio_ida, gdev->id);
|
||||||
|
err_free_gdev:
|
||||||
/* failures here can mean systems won't boot... */
|
/* failures here can mean systems won't boot... */
|
||||||
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
|
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
|
||||||
gdev->base, gdev->base + gdev->ngpio - 1,
|
gdev->base, gdev->base + gdev->ngpio - 1,
|
||||||
|
@@ -501,8 +501,11 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle)
|
|||||||
{
|
{
|
||||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||||
|
|
||||||
|
if (adev->powerplay.pp_funcs &&
|
||||||
|
adev->powerplay.pp_funcs->switch_power_profile)
|
||||||
amdgpu_dpm_switch_power_profile(adev,
|
amdgpu_dpm_switch_power_profile(adev,
|
||||||
PP_SMC_POWER_PROFILE_COMPUTE, !idle);
|
PP_SMC_POWER_PROFILE_COMPUTE,
|
||||||
|
!idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid)
|
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid)
|
||||||
|
@@ -626,6 +626,13 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)
|
|||||||
"dither",
|
"dither",
|
||||||
amdgpu_dither_enum_list, sz);
|
amdgpu_dither_enum_list, sz);
|
||||||
|
|
||||||
|
if (amdgpu_device_has_dc_support(adev)) {
|
||||||
|
adev->mode_info.max_bpc_property =
|
||||||
|
drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16);
|
||||||
|
if (!adev->mode_info.max_bpc_property)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -338,6 +338,8 @@ struct amdgpu_mode_info {
|
|||||||
struct drm_property *audio_property;
|
struct drm_property *audio_property;
|
||||||
/* FMT dithering */
|
/* FMT dithering */
|
||||||
struct drm_property *dither_property;
|
struct drm_property *dither_property;
|
||||||
|
/* maximum number of bits per channel for monitor color */
|
||||||
|
struct drm_property *max_bpc_property;
|
||||||
/* hardcoded DFP edid from BIOS */
|
/* hardcoded DFP edid from BIOS */
|
||||||
struct edid *bios_hardcoded_edid;
|
struct edid *bios_hardcoded_edid;
|
||||||
int bios_hardcoded_edid_size;
|
int bios_hardcoded_edid_size;
|
||||||
|
@@ -46,6 +46,7 @@ MODULE_FIRMWARE("amdgpu/tahiti_mc.bin");
|
|||||||
MODULE_FIRMWARE("amdgpu/pitcairn_mc.bin");
|
MODULE_FIRMWARE("amdgpu/pitcairn_mc.bin");
|
||||||
MODULE_FIRMWARE("amdgpu/verde_mc.bin");
|
MODULE_FIRMWARE("amdgpu/verde_mc.bin");
|
||||||
MODULE_FIRMWARE("amdgpu/oland_mc.bin");
|
MODULE_FIRMWARE("amdgpu/oland_mc.bin");
|
||||||
|
MODULE_FIRMWARE("amdgpu/hainan_mc.bin");
|
||||||
MODULE_FIRMWARE("amdgpu/si58_mc.bin");
|
MODULE_FIRMWARE("amdgpu/si58_mc.bin");
|
||||||
|
|
||||||
#define MC_SEQ_MISC0__MT__MASK 0xf0000000
|
#define MC_SEQ_MISC0__MT__MASK 0xf0000000
|
||||||
|
@@ -65,6 +65,13 @@
|
|||||||
#define mmMP0_MISC_LIGHT_SLEEP_CTRL 0x01ba
|
#define mmMP0_MISC_LIGHT_SLEEP_CTRL 0x01ba
|
||||||
#define mmMP0_MISC_LIGHT_SLEEP_CTRL_BASE_IDX 0
|
#define mmMP0_MISC_LIGHT_SLEEP_CTRL_BASE_IDX 0
|
||||||
|
|
||||||
|
/* for Vega20 register name change */
|
||||||
|
#define mmHDP_MEM_POWER_CTRL 0x00d4
|
||||||
|
#define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK 0x00000001L
|
||||||
|
#define HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK 0x00000002L
|
||||||
|
#define HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK 0x00010000L
|
||||||
|
#define HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK 0x00020000L
|
||||||
|
#define mmHDP_MEM_POWER_CTRL_BASE_IDX 0
|
||||||
/*
|
/*
|
||||||
* Indirect registers accessor
|
* Indirect registers accessor
|
||||||
*/
|
*/
|
||||||
@@ -870,6 +877,23 @@ static void soc15_update_hdp_light_sleep(struct amdgpu_device *adev, bool enable
|
|||||||
{
|
{
|
||||||
uint32_t def, data;
|
uint32_t def, data;
|
||||||
|
|
||||||
|
if (adev->asic_type == CHIP_VEGA20) {
|
||||||
|
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL));
|
||||||
|
|
||||||
|
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
||||||
|
data |= HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK |
|
||||||
|
HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK |
|
||||||
|
HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK |
|
||||||
|
HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK;
|
||||||
|
else
|
||||||
|
data &= ~(HDP_MEM_POWER_CTRL__IPH_MEM_POWER_CTRL_EN_MASK |
|
||||||
|
HDP_MEM_POWER_CTRL__IPH_MEM_POWER_LS_EN_MASK |
|
||||||
|
HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK |
|
||||||
|
HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK);
|
||||||
|
|
||||||
|
if (def != data)
|
||||||
|
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL), data);
|
||||||
|
} else {
|
||||||
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS));
|
def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS));
|
||||||
|
|
||||||
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
|
||||||
@@ -879,6 +903,7 @@ static void soc15_update_hdp_light_sleep(struct amdgpu_device *adev, bool enable
|
|||||||
|
|
||||||
if (def != data)
|
if (def != data)
|
||||||
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS), data);
|
WREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_LS), data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void soc15_update_drm_clock_gating(struct amdgpu_device *adev, bool enable)
|
static void soc15_update_drm_clock_gating(struct amdgpu_device *adev, bool enable)
|
||||||
|
@@ -2422,8 +2422,15 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,
|
|||||||
static enum dc_color_depth
|
static enum dc_color_depth
|
||||||
convert_color_depth_from_display_info(const struct drm_connector *connector)
|
convert_color_depth_from_display_info(const struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
|
struct dm_connector_state *dm_conn_state =
|
||||||
|
to_dm_connector_state(connector->state);
|
||||||
uint32_t bpc = connector->display_info.bpc;
|
uint32_t bpc = connector->display_info.bpc;
|
||||||
|
|
||||||
|
/* TODO: Remove this when there's support for max_bpc in drm */
|
||||||
|
if (dm_conn_state && bpc > dm_conn_state->max_bpc)
|
||||||
|
/* Round down to nearest even number. */
|
||||||
|
bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1);
|
||||||
|
|
||||||
switch (bpc) {
|
switch (bpc) {
|
||||||
case 0:
|
case 0:
|
||||||
/*
|
/*
|
||||||
@@ -3007,6 +3014,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
|
|||||||
} else if (property == adev->mode_info.underscan_property) {
|
} else if (property == adev->mode_info.underscan_property) {
|
||||||
dm_new_state->underscan_enable = val;
|
dm_new_state->underscan_enable = val;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
} else if (property == adev->mode_info.max_bpc_property) {
|
||||||
|
dm_new_state->max_bpc = val;
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -3049,6 +3059,9 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
|
|||||||
} else if (property == adev->mode_info.underscan_property) {
|
} else if (property == adev->mode_info.underscan_property) {
|
||||||
*val = dm_state->underscan_enable;
|
*val = dm_state->underscan_enable;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
} else if (property == adev->mode_info.max_bpc_property) {
|
||||||
|
*val = dm_state->max_bpc;
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -3859,6 +3872,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
|
|||||||
drm_object_attach_property(&aconnector->base.base,
|
drm_object_attach_property(&aconnector->base.base,
|
||||||
adev->mode_info.underscan_vborder_property,
|
adev->mode_info.underscan_vborder_property,
|
||||||
0);
|
0);
|
||||||
|
drm_object_attach_property(&aconnector->base.base,
|
||||||
|
adev->mode_info.max_bpc_property,
|
||||||
|
0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -252,6 +252,7 @@ struct dm_connector_state {
|
|||||||
enum amdgpu_rmx_type scaling;
|
enum amdgpu_rmx_type scaling;
|
||||||
uint8_t underscan_vborder;
|
uint8_t underscan_vborder;
|
||||||
uint8_t underscan_hborder;
|
uint8_t underscan_hborder;
|
||||||
|
uint8_t max_bpc;
|
||||||
bool underscan_enable;
|
bool underscan_enable;
|
||||||
bool freesync_enable;
|
bool freesync_enable;
|
||||||
bool freesync_capable;
|
bool freesync_capable;
|
||||||
|
@@ -4525,12 +4525,12 @@ static int smu7_get_sclk_od(struct pp_hwmgr *hwmgr)
|
|||||||
struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
|
struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
|
||||||
struct smu7_single_dpm_table *golden_sclk_table =
|
struct smu7_single_dpm_table *golden_sclk_table =
|
||||||
&(data->golden_dpm_table.sclk_table);
|
&(data->golden_dpm_table.sclk_table);
|
||||||
int value;
|
int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_sclk_table->dpm_levels
|
||||||
|
[golden_sclk_table->count - 1].value;
|
||||||
|
|
||||||
value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
|
value -= golden_value;
|
||||||
golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
100 /
|
|
||||||
golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -4567,12 +4567,12 @@ static int smu7_get_mclk_od(struct pp_hwmgr *hwmgr)
|
|||||||
struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
|
struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
|
||||||
struct smu7_single_dpm_table *golden_mclk_table =
|
struct smu7_single_dpm_table *golden_mclk_table =
|
||||||
&(data->golden_dpm_table.mclk_table);
|
&(data->golden_dpm_table.mclk_table);
|
||||||
int value;
|
int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_mclk_table->dpm_levels
|
||||||
|
[golden_mclk_table->count - 1].value;
|
||||||
|
|
||||||
value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
|
value -= golden_value;
|
||||||
golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
100 /
|
|
||||||
golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@@ -4522,15 +4522,13 @@ static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr)
|
|||||||
struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
|
struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
|
||||||
struct vega10_single_dpm_table *golden_sclk_table =
|
struct vega10_single_dpm_table *golden_sclk_table =
|
||||||
&(data->golden_dpm_table.gfx_table);
|
&(data->golden_dpm_table.gfx_table);
|
||||||
int value;
|
int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_sclk_table->dpm_levels
|
||||||
value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
|
|
||||||
golden_sclk_table->dpm_levels
|
|
||||||
[golden_sclk_table->count - 1].value) *
|
|
||||||
100 /
|
|
||||||
golden_sclk_table->dpm_levels
|
|
||||||
[golden_sclk_table->count - 1].value;
|
[golden_sclk_table->count - 1].value;
|
||||||
|
|
||||||
|
value -= golden_value;
|
||||||
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4575,16 +4573,13 @@ static int vega10_get_mclk_od(struct pp_hwmgr *hwmgr)
|
|||||||
struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
|
struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
|
||||||
struct vega10_single_dpm_table *golden_mclk_table =
|
struct vega10_single_dpm_table *golden_mclk_table =
|
||||||
&(data->golden_dpm_table.mem_table);
|
&(data->golden_dpm_table.mem_table);
|
||||||
int value;
|
int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_mclk_table->dpm_levels
|
||||||
value = (mclk_table->dpm_levels
|
|
||||||
[mclk_table->count - 1].value -
|
|
||||||
golden_mclk_table->dpm_levels
|
|
||||||
[golden_mclk_table->count - 1].value) *
|
|
||||||
100 /
|
|
||||||
golden_mclk_table->dpm_levels
|
|
||||||
[golden_mclk_table->count - 1].value;
|
[golden_mclk_table->count - 1].value;
|
||||||
|
|
||||||
|
value -= golden_value;
|
||||||
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2243,12 +2243,12 @@ static int vega12_get_sclk_od(struct pp_hwmgr *hwmgr)
|
|||||||
struct vega12_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
|
struct vega12_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table);
|
||||||
struct vega12_single_dpm_table *golden_sclk_table =
|
struct vega12_single_dpm_table *golden_sclk_table =
|
||||||
&(data->golden_dpm_table.gfx_table);
|
&(data->golden_dpm_table.gfx_table);
|
||||||
int value;
|
int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_sclk_table->dpm_levels
|
||||||
|
[golden_sclk_table->count - 1].value;
|
||||||
|
|
||||||
value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
|
value -= golden_value;
|
||||||
golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
100 /
|
|
||||||
golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -2264,16 +2264,13 @@ static int vega12_get_mclk_od(struct pp_hwmgr *hwmgr)
|
|||||||
struct vega12_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
|
struct vega12_single_dpm_table *mclk_table = &(data->dpm_table.mem_table);
|
||||||
struct vega12_single_dpm_table *golden_mclk_table =
|
struct vega12_single_dpm_table *golden_mclk_table =
|
||||||
&(data->golden_dpm_table.mem_table);
|
&(data->golden_dpm_table.mem_table);
|
||||||
int value;
|
int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_mclk_table->dpm_levels
|
||||||
value = (mclk_table->dpm_levels
|
|
||||||
[mclk_table->count - 1].value -
|
|
||||||
golden_mclk_table->dpm_levels
|
|
||||||
[golden_mclk_table->count - 1].value) *
|
|
||||||
100 /
|
|
||||||
golden_mclk_table->dpm_levels
|
|
||||||
[golden_mclk_table->count - 1].value;
|
[golden_mclk_table->count - 1].value;
|
||||||
|
|
||||||
|
value -= golden_value;
|
||||||
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,17 @@ static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
|
|||||||
data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
|
data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
|
||||||
data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
|
data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT;
|
||||||
|
|
||||||
data->registry_data.disallowed_features = 0x0;
|
/*
|
||||||
|
* Disable the following features for now:
|
||||||
|
* GFXCLK DS
|
||||||
|
* SOCLK DS
|
||||||
|
* LCLK DS
|
||||||
|
* DCEFCLK DS
|
||||||
|
* FCLK DS
|
||||||
|
* MP1CLK DS
|
||||||
|
* MP0CLK DS
|
||||||
|
*/
|
||||||
|
data->registry_data.disallowed_features = 0xE0041C00;
|
||||||
data->registry_data.od_state_in_dc_support = 0;
|
data->registry_data.od_state_in_dc_support = 0;
|
||||||
data->registry_data.thermal_support = 1;
|
data->registry_data.thermal_support = 1;
|
||||||
data->registry_data.skip_baco_hardware = 0;
|
data->registry_data.skip_baco_hardware = 0;
|
||||||
@@ -1313,12 +1323,13 @@ static int vega20_get_sclk_od(
|
|||||||
&(data->dpm_table.gfx_table);
|
&(data->dpm_table.gfx_table);
|
||||||
struct vega20_single_dpm_table *golden_sclk_table =
|
struct vega20_single_dpm_table *golden_sclk_table =
|
||||||
&(data->golden_dpm_table.gfx_table);
|
&(data->golden_dpm_table.gfx_table);
|
||||||
int value;
|
int value = sclk_table->dpm_levels[sclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_sclk_table->dpm_levels
|
||||||
|
[golden_sclk_table->count - 1].value;
|
||||||
|
|
||||||
/* od percentage */
|
/* od percentage */
|
||||||
value = DIV_ROUND_UP((sclk_table->dpm_levels[sclk_table->count - 1].value -
|
value -= golden_value;
|
||||||
golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * 100,
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value);
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -1358,12 +1369,13 @@ static int vega20_get_mclk_od(
|
|||||||
&(data->dpm_table.mem_table);
|
&(data->dpm_table.mem_table);
|
||||||
struct vega20_single_dpm_table *golden_mclk_table =
|
struct vega20_single_dpm_table *golden_mclk_table =
|
||||||
&(data->golden_dpm_table.mem_table);
|
&(data->golden_dpm_table.mem_table);
|
||||||
int value;
|
int value = mclk_table->dpm_levels[mclk_table->count - 1].value;
|
||||||
|
int golden_value = golden_mclk_table->dpm_levels
|
||||||
|
[golden_mclk_table->count - 1].value;
|
||||||
|
|
||||||
/* od percentage */
|
/* od percentage */
|
||||||
value = DIV_ROUND_UP((mclk_table->dpm_levels[mclk_table->count - 1].value -
|
value -= golden_value;
|
||||||
golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * 100,
|
value = DIV_ROUND_UP(value * 100, golden_value);
|
||||||
golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value);
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@@ -60,8 +60,29 @@ static const struct pci_device_id pciidlist[] = {
|
|||||||
|
|
||||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||||
|
|
||||||
|
static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct apertures_struct *ap;
|
||||||
|
bool primary = false;
|
||||||
|
|
||||||
|
ap = alloc_apertures(1);
|
||||||
|
if (!ap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ap->ranges[0].base = pci_resource_start(pdev, 0);
|
||||||
|
ap->ranges[0].size = pci_resource_len(pdev, 0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86
|
||||||
|
primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
|
||||||
|
#endif
|
||||||
|
drm_fb_helper_remove_conflicting_framebuffers(ap, "astdrmfb", primary);
|
||||||
|
kfree(ap);
|
||||||
|
}
|
||||||
|
|
||||||
static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
|
ast_kick_out_firmware_fb(pdev);
|
||||||
|
|
||||||
return drm_get_pci_dev(pdev, ent, &driver);
|
return drm_get_pci_dev(pdev, ent, &driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -568,6 +568,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
|
|||||||
}
|
}
|
||||||
ast_bo_unreserve(bo);
|
ast_bo_unreserve(bo);
|
||||||
|
|
||||||
|
ast_set_offset_reg(crtc);
|
||||||
ast_set_start_address_crt1(crtc, (u32)gpu_addr);
|
ast_set_start_address_crt1(crtc, (u32)gpu_addr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1254,7 +1255,7 @@ static int ast_cursor_move(struct drm_crtc *crtc,
|
|||||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
|
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
|
||||||
|
|
||||||
/* dummy write to fire HWC */
|
/* dummy write to fire HWC */
|
||||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00);
|
ast_show_cursor(crtc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -219,6 +219,9 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
|
|||||||
mutex_lock(&fb_helper->lock);
|
mutex_lock(&fb_helper->lock);
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||||
|
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||||
|
continue;
|
||||||
|
|
||||||
ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
|
ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@@ -214,6 +214,12 @@ static int vc4_atomic_commit(struct drm_device *dev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We know for sure we don't want an async update here. Set
|
||||||
|
* state->legacy_cursor_update to false to prevent
|
||||||
|
* drm_atomic_helper_setup_commit() from auto-completing
|
||||||
|
* commit->flip_done.
|
||||||
|
*/
|
||||||
|
state->legacy_cursor_update = false;
|
||||||
ret = drm_atomic_helper_setup_commit(state, nonblock);
|
ret = drm_atomic_helper_setup_commit(state, nonblock);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -854,7 +854,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
|
|||||||
static void vc4_plane_atomic_async_update(struct drm_plane *plane,
|
static void vc4_plane_atomic_async_update(struct drm_plane *plane,
|
||||||
struct drm_plane_state *state)
|
struct drm_plane_state *state)
|
||||||
{
|
{
|
||||||
struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
|
struct vc4_plane_state *vc4_state, *new_vc4_state;
|
||||||
|
|
||||||
if (plane->state->fb != state->fb) {
|
if (plane->state->fb != state->fb) {
|
||||||
vc4_plane_async_set_fb(plane, state->fb);
|
vc4_plane_async_set_fb(plane, state->fb);
|
||||||
@@ -875,7 +875,18 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
|
|||||||
plane->state->src_y = state->src_y;
|
plane->state->src_y = state->src_y;
|
||||||
|
|
||||||
/* Update the display list based on the new crtc_x/y. */
|
/* Update the display list based on the new crtc_x/y. */
|
||||||
vc4_plane_atomic_check(plane, plane->state);
|
vc4_plane_atomic_check(plane, state);
|
||||||
|
|
||||||
|
new_vc4_state = to_vc4_plane_state(state);
|
||||||
|
vc4_state = to_vc4_plane_state(plane->state);
|
||||||
|
|
||||||
|
/* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
|
||||||
|
vc4_state->dlist[vc4_state->pos0_offset] =
|
||||||
|
new_vc4_state->dlist[vc4_state->pos0_offset];
|
||||||
|
vc4_state->dlist[vc4_state->pos2_offset] =
|
||||||
|
new_vc4_state->dlist[vc4_state->pos2_offset];
|
||||||
|
vc4_state->dlist[vc4_state->ptr0_offset] =
|
||||||
|
new_vc4_state->dlist[vc4_state->ptr0_offset];
|
||||||
|
|
||||||
/* Note that we can't just call vc4_plane_write_dlist()
|
/* Note that we can't just call vc4_plane_write_dlist()
|
||||||
* because that would smash the context data that the HVS is
|
* because that would smash the context data that the HVS is
|
||||||
|
@@ -275,6 +275,9 @@
|
|||||||
|
|
||||||
#define USB_VENDOR_ID_CIDC 0x1677
|
#define USB_VENDOR_ID_CIDC 0x1677
|
||||||
|
|
||||||
|
#define I2C_VENDOR_ID_CIRQUE 0x0488
|
||||||
|
#define I2C_PRODUCT_ID_CIRQUE_121F 0x121F
|
||||||
|
|
||||||
#define USB_VENDOR_ID_CJTOUCH 0x24b8
|
#define USB_VENDOR_ID_CJTOUCH 0x24b8
|
||||||
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
|
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
|
||||||
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040
|
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040
|
||||||
@@ -707,6 +710,7 @@
|
|||||||
#define USB_VENDOR_ID_LG 0x1fd2
|
#define USB_VENDOR_ID_LG 0x1fd2
|
||||||
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
|
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
|
||||||
#define USB_DEVICE_ID_LG_MELFAS_MT 0x6007
|
#define USB_DEVICE_ID_LG_MELFAS_MT 0x6007
|
||||||
|
#define I2C_DEVICE_ID_LG_8001 0x8001
|
||||||
|
|
||||||
#define USB_VENDOR_ID_LOGITECH 0x046d
|
#define USB_VENDOR_ID_LOGITECH 0x046d
|
||||||
#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
|
#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
|
||||||
@@ -805,6 +809,7 @@
|
|||||||
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
|
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
|
||||||
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
||||||
#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
|
#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
|
||||||
|
#define USB_DEVICE_ID_MS_PIXART_MOUSE 0x00cb
|
||||||
|
|
||||||
#define USB_VENDOR_ID_MOJO 0x8282
|
#define USB_VENDOR_ID_MOJO 0x8282
|
||||||
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
|
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
|
||||||
@@ -1043,6 +1048,7 @@
|
|||||||
#define USB_VENDOR_ID_SYMBOL 0x05e0
|
#define USB_VENDOR_ID_SYMBOL 0x05e0
|
||||||
#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
|
#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
|
||||||
#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
|
#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
|
||||||
|
#define USB_DEVICE_ID_SYMBOL_SCANNER_3 0x1200
|
||||||
|
|
||||||
#define USB_VENDOR_ID_SYNAPTICS 0x06cb
|
#define USB_VENDOR_ID_SYNAPTICS 0x06cb
|
||||||
#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001
|
#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001
|
||||||
@@ -1204,6 +1210,8 @@
|
|||||||
#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22
|
#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22
|
||||||
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
||||||
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
|
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
|
||||||
|
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
|
||||||
|
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22 0x4e22
|
||||||
|
|
||||||
|
|
||||||
#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */
|
#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */
|
||||||
|
@@ -325,6 +325,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
|
|||||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
|
||||||
USB_DEVICE_ID_ELECOM_BM084),
|
USB_DEVICE_ID_ELECOM_BM084),
|
||||||
HID_BATTERY_QUIRK_IGNORE },
|
HID_BATTERY_QUIRK_IGNORE },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL,
|
||||||
|
USB_DEVICE_ID_SYMBOL_SCANNER_3),
|
||||||
|
HID_BATTERY_QUIRK_IGNORE },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1838,47 +1841,3 @@ void hidinput_disconnect(struct hid_device *hid)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hidinput_disconnect);
|
EXPORT_SYMBOL_GPL(hidinput_disconnect);
|
||||||
|
|
||||||
/**
|
|
||||||
* hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
|
|
||||||
* events given a high-resolution wheel
|
|
||||||
* movement.
|
|
||||||
* @counter: a hid_scroll_counter struct describing the wheel.
|
|
||||||
* @hi_res_value: the movement of the wheel, in the mouse's high-resolution
|
|
||||||
* units.
|
|
||||||
*
|
|
||||||
* Given a high-resolution movement, this function converts the movement into
|
|
||||||
* microns and emits high-resolution scroll events for the input device. It also
|
|
||||||
* uses the multiplier from &struct hid_scroll_counter to emit low-resolution
|
|
||||||
* scroll events when appropriate for backwards-compatibility with userspace
|
|
||||||
* input libraries.
|
|
||||||
*/
|
|
||||||
void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter,
|
|
||||||
int hi_res_value)
|
|
||||||
{
|
|
||||||
int low_res_value, remainder, multiplier;
|
|
||||||
|
|
||||||
input_report_rel(counter->dev, REL_WHEEL_HI_RES,
|
|
||||||
hi_res_value * counter->microns_per_hi_res_unit);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the low-res remainder with the high-res value,
|
|
||||||
* but reset if the direction has changed.
|
|
||||||
*/
|
|
||||||
remainder = counter->remainder;
|
|
||||||
if ((remainder ^ hi_res_value) < 0)
|
|
||||||
remainder = 0;
|
|
||||||
remainder += hi_res_value;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Then just use the resolution multiplier to see if
|
|
||||||
* we should send a low-res (aka regular wheel) event.
|
|
||||||
*/
|
|
||||||
multiplier = counter->resolution_multiplier;
|
|
||||||
low_res_value = remainder / multiplier;
|
|
||||||
remainder -= low_res_value * multiplier;
|
|
||||||
counter->remainder = remainder;
|
|
||||||
|
|
||||||
if (low_res_value)
|
|
||||||
input_report_rel(counter->dev, REL_WHEEL, low_res_value);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll);
|
|
||||||
|
@@ -64,14 +64,6 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
|||||||
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
||||||
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
||||||
#define HIDPP_QUIRK_UNIFYING BIT(25)
|
#define HIDPP_QUIRK_UNIFYING BIT(25)
|
||||||
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26)
|
|
||||||
#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27)
|
|
||||||
#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28)
|
|
||||||
|
|
||||||
/* Convenience constant to check for any high-res support. */
|
|
||||||
#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
|
|
||||||
HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \
|
|
||||||
HIDPP_QUIRK_HI_RES_SCROLL_X2121)
|
|
||||||
|
|
||||||
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
|
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
|
||||||
|
|
||||||
@@ -157,7 +149,6 @@ struct hidpp_device {
|
|||||||
unsigned long capabilities;
|
unsigned long capabilities;
|
||||||
|
|
||||||
struct hidpp_battery battery;
|
struct hidpp_battery battery;
|
||||||
struct hid_scroll_counter vertical_wheel_counter;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* HID++ 1.0 error codes */
|
/* HID++ 1.0 error codes */
|
||||||
@@ -409,15 +400,9 @@ static void hidpp_prefix_name(char **name, int name_length)
|
|||||||
#define HIDPP_SET_LONG_REGISTER 0x82
|
#define HIDPP_SET_LONG_REGISTER 0x82
|
||||||
#define HIDPP_GET_LONG_REGISTER 0x83
|
#define HIDPP_GET_LONG_REGISTER 0x83
|
||||||
|
|
||||||
/**
|
#define HIDPP_REG_GENERAL 0x00
|
||||||
* hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register.
|
|
||||||
* @hidpp_dev: the device to set the register on.
|
static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
|
||||||
* @register_address: the address of the register to modify.
|
|
||||||
* @byte: the byte of the register to modify. Should be less than 3.
|
|
||||||
* Return: 0 if successful, otherwise a negative error code.
|
|
||||||
*/
|
|
||||||
static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev,
|
|
||||||
u8 register_address, u8 byte, u8 bit)
|
|
||||||
{
|
{
|
||||||
struct hidpp_report response;
|
struct hidpp_report response;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -426,38 +411,23 @@ static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev,
|
|||||||
ret = hidpp_send_rap_command_sync(hidpp_dev,
|
ret = hidpp_send_rap_command_sync(hidpp_dev,
|
||||||
REPORT_ID_HIDPP_SHORT,
|
REPORT_ID_HIDPP_SHORT,
|
||||||
HIDPP_GET_REGISTER,
|
HIDPP_GET_REGISTER,
|
||||||
register_address,
|
HIDPP_REG_GENERAL,
|
||||||
NULL, 0, &response);
|
NULL, 0, &response);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
memcpy(params, response.rap.params, 3);
|
memcpy(params, response.rap.params, 3);
|
||||||
|
|
||||||
params[byte] |= BIT(bit);
|
/* Set the battery bit */
|
||||||
|
params[0] |= BIT(4);
|
||||||
|
|
||||||
return hidpp_send_rap_command_sync(hidpp_dev,
|
return hidpp_send_rap_command_sync(hidpp_dev,
|
||||||
REPORT_ID_HIDPP_SHORT,
|
REPORT_ID_HIDPP_SHORT,
|
||||||
HIDPP_SET_REGISTER,
|
HIDPP_SET_REGISTER,
|
||||||
register_address,
|
HIDPP_REG_GENERAL,
|
||||||
params, 3, &response);
|
params, 3, &response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define HIDPP_REG_GENERAL 0x00
|
|
||||||
|
|
||||||
static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
|
|
||||||
{
|
|
||||||
return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define HIDPP_REG_FEATURES 0x01
|
|
||||||
|
|
||||||
/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */
|
|
||||||
static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev)
|
|
||||||
{
|
|
||||||
return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define HIDPP_REG_BATTERY_STATUS 0x07
|
#define HIDPP_REG_BATTERY_STATUS 0x07
|
||||||
|
|
||||||
static int hidpp10_battery_status_map_level(u8 param)
|
static int hidpp10_battery_status_map_level(u8 param)
|
||||||
@@ -1166,100 +1136,6 @@ static int hidpp_battery_get_property(struct power_supply *psy,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
/* 0x2120: Hi-resolution scrolling */
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120
|
|
||||||
|
|
||||||
#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10
|
|
||||||
|
|
||||||
static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp,
|
|
||||||
bool enabled, u8 *multiplier)
|
|
||||||
{
|
|
||||||
u8 feature_index;
|
|
||||||
u8 feature_type;
|
|
||||||
int ret;
|
|
||||||
u8 params[1];
|
|
||||||
struct hidpp_report response;
|
|
||||||
|
|
||||||
ret = hidpp_root_get_feature(hidpp,
|
|
||||||
HIDPP_PAGE_HI_RESOLUTION_SCROLLING,
|
|
||||||
&feature_index,
|
|
||||||
&feature_type);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
params[0] = enabled ? BIT(0) : 0;
|
|
||||||
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
|
||||||
CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE,
|
|
||||||
params, sizeof(params), &response);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
*multiplier = response.fap.params[1];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
/* 0x2121: HiRes Wheel */
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#define HIDPP_PAGE_HIRES_WHEEL 0x2121
|
|
||||||
|
|
||||||
#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00
|
|
||||||
#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20
|
|
||||||
|
|
||||||
static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp,
|
|
||||||
u8 *multiplier)
|
|
||||||
{
|
|
||||||
u8 feature_index;
|
|
||||||
u8 feature_type;
|
|
||||||
int ret;
|
|
||||||
struct hidpp_report response;
|
|
||||||
|
|
||||||
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
|
|
||||||
&feature_index, &feature_type);
|
|
||||||
if (ret)
|
|
||||||
goto return_default;
|
|
||||||
|
|
||||||
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
|
||||||
CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY,
|
|
||||||
NULL, 0, &response);
|
|
||||||
if (ret)
|
|
||||||
goto return_default;
|
|
||||||
|
|
||||||
*multiplier = response.fap.params[0];
|
|
||||||
return 0;
|
|
||||||
return_default:
|
|
||||||
hid_warn(hidpp->hid_dev,
|
|
||||||
"Couldn't get wheel multiplier (error %d), assuming %d.\n",
|
|
||||||
ret, *multiplier);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert,
|
|
||||||
bool high_resolution, bool use_hidpp)
|
|
||||||
{
|
|
||||||
u8 feature_index;
|
|
||||||
u8 feature_type;
|
|
||||||
int ret;
|
|
||||||
u8 params[1];
|
|
||||||
struct hidpp_report response;
|
|
||||||
|
|
||||||
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
|
|
||||||
&feature_index, &feature_type);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
params[0] = (invert ? BIT(2) : 0) |
|
|
||||||
(high_resolution ? BIT(1) : 0) |
|
|
||||||
(use_hidpp ? BIT(0) : 0);
|
|
||||||
|
|
||||||
return hidpp_send_fap_command_sync(hidpp, feature_index,
|
|
||||||
CMD_HIRES_WHEEL_SET_WHEEL_MODE,
|
|
||||||
params, sizeof(params), &response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* 0x4301: Solar Keyboard */
|
/* 0x4301: Solar Keyboard */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@@ -2523,8 +2399,7 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
|
|||||||
input_report_rel(mydata->input, REL_Y, v);
|
input_report_rel(mydata->input, REL_Y, v);
|
||||||
|
|
||||||
v = hid_snto32(data[6], 8);
|
v = hid_snto32(data[6], 8);
|
||||||
hid_scroll_counter_handle_scroll(
|
input_report_rel(mydata->input, REL_WHEEL, v);
|
||||||
&hidpp->vertical_wheel_counter, v);
|
|
||||||
|
|
||||||
input_sync(mydata->input);
|
input_sync(mydata->input);
|
||||||
}
|
}
|
||||||
@@ -2652,72 +2527,6 @@ static int g920_get_config(struct hidpp_device *hidpp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
/* High-resolution scroll wheels */
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel.
|
|
||||||
* @product_id: the HID product ID of the device being described.
|
|
||||||
* @microns_per_hi_res_unit: the distance moved by the user's finger for each
|
|
||||||
* high-resolution unit reported by the device, in
|
|
||||||
* 256ths of a millimetre.
|
|
||||||
*/
|
|
||||||
struct hi_res_scroll_info {
|
|
||||||
__u32 product_id;
|
|
||||||
int microns_per_hi_res_unit;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct hi_res_scroll_info hi_res_scroll_devices[] = {
|
|
||||||
{ /* Anywhere MX */
|
|
||||||
.product_id = 0x1017, .microns_per_hi_res_unit = 445 },
|
|
||||||
{ /* Performance MX */
|
|
||||||
.product_id = 0x101a, .microns_per_hi_res_unit = 406 },
|
|
||||||
{ /* M560 */
|
|
||||||
.product_id = 0x402d, .microns_per_hi_res_unit = 435 },
|
|
||||||
{ /* MX Master 2S */
|
|
||||||
.product_id = 0x4069, .microns_per_hi_res_unit = 406 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static int hi_res_scroll_look_up_microns(__u32 product_id)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int num_devices = sizeof(hi_res_scroll_devices)
|
|
||||||
/ sizeof(hi_res_scroll_devices[0]);
|
|
||||||
for (i = 0; i < num_devices; i++) {
|
|
||||||
if (hi_res_scroll_devices[i].product_id == product_id)
|
|
||||||
return hi_res_scroll_devices[i].microns_per_hi_res_unit;
|
|
||||||
}
|
|
||||||
/* We don't have a value for this device, so use a sensible default. */
|
|
||||||
return 406;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hi_res_scroll_enable(struct hidpp_device *hidpp)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
u8 multiplier = 8;
|
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) {
|
|
||||||
ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
|
|
||||||
hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
|
|
||||||
} else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) {
|
|
||||||
ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true,
|
|
||||||
&multiplier);
|
|
||||||
} else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */
|
|
||||||
ret = hidpp10_enable_scrolling_acceleration(hidpp);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
hidpp->vertical_wheel_counter.resolution_multiplier = multiplier;
|
|
||||||
hidpp->vertical_wheel_counter.microns_per_hi_res_unit =
|
|
||||||
hi_res_scroll_look_up_microns(hidpp->hid_dev->product);
|
|
||||||
hid_info(hidpp->hid_dev, "multiplier = %d, microns = %d\n",
|
|
||||||
multiplier,
|
|
||||||
hidpp->vertical_wheel_counter.microns_per_hi_res_unit);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Generic HID++ devices */
|
/* Generic HID++ devices */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@@ -2763,11 +2572,6 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
|
|||||||
wtp_populate_input(hidpp, input, origin_is_hid_core);
|
wtp_populate_input(hidpp, input, origin_is_hid_core);
|
||||||
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
|
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
|
||||||
m560_populate_input(hidpp, input, origin_is_hid_core);
|
m560_populate_input(hidpp, input, origin_is_hid_core);
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) {
|
|
||||||
input_set_capability(input, EV_REL, REL_WHEEL_HI_RES);
|
|
||||||
hidpp->vertical_wheel_counter.dev = input;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hidpp_input_configured(struct hid_device *hdev,
|
static int hidpp_input_configured(struct hid_device *hdev,
|
||||||
@@ -2886,27 +2690,6 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
|
|
||||||
struct hid_usage *usage, __s32 value)
|
|
||||||
{
|
|
||||||
/* This function will only be called for scroll events, due to the
|
|
||||||
* restriction imposed in hidpp_usages.
|
|
||||||
*/
|
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
|
||||||
struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter;
|
|
||||||
/* A scroll event may occur before the multiplier has been retrieved or
|
|
||||||
* the input device set, or high-res scroll enabling may fail. In such
|
|
||||||
* cases we must return early (falling back to default behaviour) to
|
|
||||||
* avoid a crash in hid_scroll_counter_handle_scroll.
|
|
||||||
*/
|
|
||||||
if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
|
|
||||||
|| counter->dev == NULL || counter->resolution_multiplier == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hid_scroll_counter_handle_scroll(counter, value);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
||||||
{
|
{
|
||||||
static atomic_t battery_no = ATOMIC_INIT(0);
|
static atomic_t battery_no = ATOMIC_INIT(0);
|
||||||
@@ -3118,9 +2901,6 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
|||||||
if (hidpp->battery.ps)
|
if (hidpp->battery.ps)
|
||||||
power_supply_changed(hidpp->battery.ps);
|
power_supply_changed(hidpp->battery.ps);
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
|
|
||||||
hi_res_scroll_enable(hidpp);
|
|
||||||
|
|
||||||
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
|
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
|
||||||
/* if the input nodes are already created, we can stop now */
|
/* if the input nodes are already created, we can stop now */
|
||||||
return;
|
return;
|
||||||
@@ -3306,63 +3086,35 @@ static void hidpp_remove(struct hid_device *hdev)
|
|||||||
mutex_destroy(&hidpp->send_mutex);
|
mutex_destroy(&hidpp->send_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LDJ_DEVICE(product) \
|
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
|
|
||||||
USB_VENDOR_ID_LOGITECH, (product))
|
|
||||||
|
|
||||||
static const struct hid_device_id hidpp_devices[] = {
|
static const struct hid_device_id hidpp_devices[] = {
|
||||||
{ /* wireless touchpad */
|
{ /* wireless touchpad */
|
||||||
LDJ_DEVICE(0x4011),
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
|
USB_VENDOR_ID_LOGITECH, 0x4011),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
|
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
|
||||||
HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
|
HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
|
||||||
{ /* wireless touchpad T650 */
|
{ /* wireless touchpad T650 */
|
||||||
LDJ_DEVICE(0x4101),
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
|
USB_VENDOR_ID_LOGITECH, 0x4101),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
|
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
|
||||||
{ /* wireless touchpad T651 */
|
{ /* wireless touchpad T651 */
|
||||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
|
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||||
USB_DEVICE_ID_LOGITECH_T651),
|
USB_DEVICE_ID_LOGITECH_T651),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_WTP },
|
.driver_data = HIDPP_QUIRK_CLASS_WTP },
|
||||||
{ /* Mouse Logitech Anywhere MX */
|
|
||||||
LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
|
||||||
{ /* Mouse Logitech Cube */
|
|
||||||
LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
|
||||||
{ /* Mouse Logitech M335 */
|
|
||||||
LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech M515 */
|
|
||||||
LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
|
||||||
{ /* Mouse logitech M560 */
|
{ /* Mouse logitech M560 */
|
||||||
LDJ_DEVICE(0x402d),
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
|
USB_VENDOR_ID_LOGITECH, 0x402d),
|
||||||
| HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
|
||||||
{ /* Mouse Logitech M705 (firmware RQM17) */
|
|
||||||
LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
|
||||||
{ /* Mouse Logitech M705 (firmware RQM67) */
|
|
||||||
LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech M720 */
|
|
||||||
LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech MX Anywhere 2 */
|
|
||||||
LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech MX Anywhere 2S */
|
|
||||||
LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech MX Master */
|
|
||||||
LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech MX Master 2S */
|
|
||||||
LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
|
||||||
{ /* Mouse Logitech Performance MX */
|
|
||||||
LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
|
||||||
{ /* Keyboard logitech K400 */
|
{ /* Keyboard logitech K400 */
|
||||||
LDJ_DEVICE(0x4024),
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
|
USB_VENDOR_ID_LOGITECH, 0x4024),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_K400 },
|
.driver_data = HIDPP_QUIRK_CLASS_K400 },
|
||||||
{ /* Solar Keyboard Logitech K750 */
|
{ /* Solar Keyboard Logitech K750 */
|
||||||
LDJ_DEVICE(0x4002),
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
|
USB_VENDOR_ID_LOGITECH, 0x4002),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_K750 },
|
.driver_data = HIDPP_QUIRK_CLASS_K750 },
|
||||||
|
|
||||||
{ LDJ_DEVICE(HID_ANY_ID) },
|
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
|
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
|
||||||
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
|
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
|
||||||
@@ -3371,19 +3123,12 @@ static const struct hid_device_id hidpp_devices[] = {
|
|||||||
|
|
||||||
MODULE_DEVICE_TABLE(hid, hidpp_devices);
|
MODULE_DEVICE_TABLE(hid, hidpp_devices);
|
||||||
|
|
||||||
static const struct hid_usage_id hidpp_usages[] = {
|
|
||||||
{ HID_GD_WHEEL, EV_REL, REL_WHEEL },
|
|
||||||
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct hid_driver hidpp_driver = {
|
static struct hid_driver hidpp_driver = {
|
||||||
.name = "logitech-hidpp-device",
|
.name = "logitech-hidpp-device",
|
||||||
.id_table = hidpp_devices,
|
.id_table = hidpp_devices,
|
||||||
.probe = hidpp_probe,
|
.probe = hidpp_probe,
|
||||||
.remove = hidpp_remove,
|
.remove = hidpp_remove,
|
||||||
.raw_event = hidpp_raw_event,
|
.raw_event = hidpp_raw_event,
|
||||||
.usage_table = hidpp_usages,
|
|
||||||
.event = hidpp_event,
|
|
||||||
.input_configured = hidpp_input_configured,
|
.input_configured = hidpp_input_configured,
|
||||||
.input_mapping = hidpp_input_mapping,
|
.input_mapping = hidpp_input_mapping,
|
||||||
.input_mapped = hidpp_input_mapped,
|
.input_mapped = hidpp_input_mapped,
|
||||||
|
@@ -1814,6 +1814,12 @@ static const struct hid_device_id mt_devices[] = {
|
|||||||
MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
|
MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
|
||||||
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
|
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
|
||||||
|
|
||||||
|
/* Cirque devices */
|
||||||
|
{ .driver_data = MT_CLS_WIN_8_DUAL,
|
||||||
|
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||||
|
I2C_VENDOR_ID_CIRQUE,
|
||||||
|
I2C_PRODUCT_ID_CIRQUE_121F) },
|
||||||
|
|
||||||
/* CJTouch panels */
|
/* CJTouch panels */
|
||||||
{ .driver_data = MT_CLS_NSMU,
|
{ .driver_data = MT_CLS_NSMU,
|
||||||
MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
|
MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
|
||||||
|
@@ -107,6 +107,7 @@ static const struct hid_device_id hid_quirks[] = {
|
|||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
|
||||||
@@ -129,6 +130,8 @@ static const struct hid_device_id hid_quirks[] = {
|
|||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003), HID_QUIRK_NOGET },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003), HID_QUIRK_NOGET },
|
||||||
|
@@ -23,8 +23,9 @@
|
|||||||
* In order to avoid breaking them this driver creates a layered hidraw device,
|
* In order to avoid breaking them this driver creates a layered hidraw device,
|
||||||
* so it can detect when the client is running and then:
|
* so it can detect when the client is running and then:
|
||||||
* - it will not send any command to the controller.
|
* - it will not send any command to the controller.
|
||||||
* - this input device will be disabled, to avoid double input of the same
|
* - this input device will be removed, to avoid double input of the same
|
||||||
* user action.
|
* user action.
|
||||||
|
* When the client is closed, this input device will be created again.
|
||||||
*
|
*
|
||||||
* For additional functions, such as changing the right-pad margin or switching
|
* For additional functions, such as changing the right-pad margin or switching
|
||||||
* the led, you can use the user-space tool at:
|
* the led, you can use the user-space tool at:
|
||||||
@@ -113,7 +114,7 @@ struct steam_device {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct hid_device *hdev, *client_hdev;
|
struct hid_device *hdev, *client_hdev;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
bool client_opened, input_opened;
|
bool client_opened;
|
||||||
struct input_dev __rcu *input;
|
struct input_dev __rcu *input;
|
||||||
unsigned long quirks;
|
unsigned long quirks;
|
||||||
struct work_struct work_connect;
|
struct work_struct work_connect;
|
||||||
@@ -279,18 +280,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void steam_update_lizard_mode(struct steam_device *steam)
|
|
||||||
{
|
|
||||||
mutex_lock(&steam->mutex);
|
|
||||||
if (!steam->client_opened) {
|
|
||||||
if (steam->input_opened)
|
|
||||||
steam_set_lizard_mode(steam, false);
|
|
||||||
else
|
|
||||||
steam_set_lizard_mode(steam, lizard_mode);
|
|
||||||
}
|
|
||||||
mutex_unlock(&steam->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int steam_input_open(struct input_dev *dev)
|
static int steam_input_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct steam_device *steam = input_get_drvdata(dev);
|
struct steam_device *steam = input_get_drvdata(dev);
|
||||||
@@ -301,7 +290,6 @@ static int steam_input_open(struct input_dev *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&steam->mutex);
|
mutex_lock(&steam->mutex);
|
||||||
steam->input_opened = true;
|
|
||||||
if (!steam->client_opened && lizard_mode)
|
if (!steam->client_opened && lizard_mode)
|
||||||
steam_set_lizard_mode(steam, false);
|
steam_set_lizard_mode(steam, false);
|
||||||
mutex_unlock(&steam->mutex);
|
mutex_unlock(&steam->mutex);
|
||||||
@@ -313,7 +301,6 @@ static void steam_input_close(struct input_dev *dev)
|
|||||||
struct steam_device *steam = input_get_drvdata(dev);
|
struct steam_device *steam = input_get_drvdata(dev);
|
||||||
|
|
||||||
mutex_lock(&steam->mutex);
|
mutex_lock(&steam->mutex);
|
||||||
steam->input_opened = false;
|
|
||||||
if (!steam->client_opened && lizard_mode)
|
if (!steam->client_opened && lizard_mode)
|
||||||
steam_set_lizard_mode(steam, true);
|
steam_set_lizard_mode(steam, true);
|
||||||
mutex_unlock(&steam->mutex);
|
mutex_unlock(&steam->mutex);
|
||||||
@@ -400,7 +387,7 @@ static int steam_battery_register(struct steam_device *steam)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int steam_register(struct steam_device *steam)
|
static int steam_input_register(struct steam_device *steam)
|
||||||
{
|
{
|
||||||
struct hid_device *hdev = steam->hdev;
|
struct hid_device *hdev = steam->hdev;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
@@ -414,17 +401,6 @@ static int steam_register(struct steam_device *steam)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Unlikely, but getting the serial could fail, and it is not so
|
|
||||||
* important, so make up a serial number and go on.
|
|
||||||
*/
|
|
||||||
if (steam_get_serial(steam) < 0)
|
|
||||||
strlcpy(steam->serial_no, "XXXXXXXXXX",
|
|
||||||
sizeof(steam->serial_no));
|
|
||||||
|
|
||||||
hid_info(hdev, "Steam Controller '%s' connected",
|
|
||||||
steam->serial_no);
|
|
||||||
|
|
||||||
input = input_allocate_device();
|
input = input_allocate_device();
|
||||||
if (!input)
|
if (!input)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -492,11 +468,6 @@ static int steam_register(struct steam_device *steam)
|
|||||||
goto input_register_fail;
|
goto input_register_fail;
|
||||||
|
|
||||||
rcu_assign_pointer(steam->input, input);
|
rcu_assign_pointer(steam->input, input);
|
||||||
|
|
||||||
/* ignore battery errors, we can live without it */
|
|
||||||
if (steam->quirks & STEAM_QUIRK_WIRELESS)
|
|
||||||
steam_battery_register(steam);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
input_register_fail:
|
input_register_fail:
|
||||||
@@ -504,27 +475,88 @@ input_register_fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void steam_unregister(struct steam_device *steam)
|
static void steam_input_unregister(struct steam_device *steam)
|
||||||
{
|
{
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
|
rcu_read_lock();
|
||||||
|
input = rcu_dereference(steam->input);
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (!input)
|
||||||
|
return;
|
||||||
|
RCU_INIT_POINTER(steam->input, NULL);
|
||||||
|
synchronize_rcu();
|
||||||
|
input_unregister_device(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void steam_battery_unregister(struct steam_device *steam)
|
||||||
|
{
|
||||||
struct power_supply *battery;
|
struct power_supply *battery;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
input = rcu_dereference(steam->input);
|
|
||||||
battery = rcu_dereference(steam->battery);
|
battery = rcu_dereference(steam->battery);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (battery) {
|
if (!battery)
|
||||||
|
return;
|
||||||
RCU_INIT_POINTER(steam->battery, NULL);
|
RCU_INIT_POINTER(steam->battery, NULL);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
power_supply_unregister(battery);
|
power_supply_unregister(battery);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int steam_register(struct steam_device *steam)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function can be called several times in a row with the
|
||||||
|
* wireless adaptor, without steam_unregister() between them, because
|
||||||
|
* another client send a get_connection_status command, for example.
|
||||||
|
* The battery and serial number are set just once per device.
|
||||||
|
*/
|
||||||
|
if (!steam->serial_no[0]) {
|
||||||
|
/*
|
||||||
|
* Unlikely, but getting the serial could fail, and it is not so
|
||||||
|
* important, so make up a serial number and go on.
|
||||||
|
*/
|
||||||
|
if (steam_get_serial(steam) < 0)
|
||||||
|
strlcpy(steam->serial_no, "XXXXXXXXXX",
|
||||||
|
sizeof(steam->serial_no));
|
||||||
|
|
||||||
|
hid_info(steam->hdev, "Steam Controller '%s' connected",
|
||||||
|
steam->serial_no);
|
||||||
|
|
||||||
|
/* ignore battery errors, we can live without it */
|
||||||
|
if (steam->quirks & STEAM_QUIRK_WIRELESS)
|
||||||
|
steam_battery_register(steam);
|
||||||
|
|
||||||
|
mutex_lock(&steam_devices_lock);
|
||||||
|
list_add(&steam->list, &steam_devices);
|
||||||
|
mutex_unlock(&steam_devices_lock);
|
||||||
}
|
}
|
||||||
if (input) {
|
|
||||||
RCU_INIT_POINTER(steam->input, NULL);
|
mutex_lock(&steam->mutex);
|
||||||
synchronize_rcu();
|
if (!steam->client_opened) {
|
||||||
|
steam_set_lizard_mode(steam, lizard_mode);
|
||||||
|
ret = steam_input_register(steam);
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
mutex_unlock(&steam->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void steam_unregister(struct steam_device *steam)
|
||||||
|
{
|
||||||
|
steam_battery_unregister(steam);
|
||||||
|
steam_input_unregister(steam);
|
||||||
|
if (steam->serial_no[0]) {
|
||||||
hid_info(steam->hdev, "Steam Controller '%s' disconnected",
|
hid_info(steam->hdev, "Steam Controller '%s' disconnected",
|
||||||
steam->serial_no);
|
steam->serial_no);
|
||||||
input_unregister_device(input);
|
mutex_lock(&steam_devices_lock);
|
||||||
|
list_del(&steam->list);
|
||||||
|
mutex_unlock(&steam_devices_lock);
|
||||||
|
steam->serial_no[0] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,6 +632,9 @@ static int steam_client_ll_open(struct hid_device *hdev)
|
|||||||
mutex_lock(&steam->mutex);
|
mutex_lock(&steam->mutex);
|
||||||
steam->client_opened = true;
|
steam->client_opened = true;
|
||||||
mutex_unlock(&steam->mutex);
|
mutex_unlock(&steam->mutex);
|
||||||
|
|
||||||
|
steam_input_unregister(steam);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,13 +644,13 @@ static void steam_client_ll_close(struct hid_device *hdev)
|
|||||||
|
|
||||||
mutex_lock(&steam->mutex);
|
mutex_lock(&steam->mutex);
|
||||||
steam->client_opened = false;
|
steam->client_opened = false;
|
||||||
if (steam->input_opened)
|
|
||||||
steam_set_lizard_mode(steam, false);
|
|
||||||
else
|
|
||||||
steam_set_lizard_mode(steam, lizard_mode);
|
|
||||||
mutex_unlock(&steam->mutex);
|
mutex_unlock(&steam->mutex);
|
||||||
|
|
||||||
hid_hw_close(steam->hdev);
|
hid_hw_close(steam->hdev);
|
||||||
|
if (steam->connected) {
|
||||||
|
steam_set_lizard_mode(steam, lizard_mode);
|
||||||
|
steam_input_register(steam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int steam_client_ll_raw_request(struct hid_device *hdev,
|
static int steam_client_ll_raw_request(struct hid_device *hdev,
|
||||||
@@ -744,11 +779,6 @@ static int steam_probe(struct hid_device *hdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&steam_devices_lock);
|
|
||||||
steam_update_lizard_mode(steam);
|
|
||||||
list_add(&steam->list, &steam_devices);
|
|
||||||
mutex_unlock(&steam_devices_lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
hid_hw_open_fail:
|
hid_hw_open_fail:
|
||||||
@@ -774,10 +804,6 @@ static void steam_remove(struct hid_device *hdev)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&steam_devices_lock);
|
|
||||||
list_del(&steam->list);
|
|
||||||
mutex_unlock(&steam_devices_lock);
|
|
||||||
|
|
||||||
hid_destroy_device(steam->client_hdev);
|
hid_destroy_device(steam->client_hdev);
|
||||||
steam->client_opened = false;
|
steam->client_opened = false;
|
||||||
cancel_work_sync(&steam->work_connect);
|
cancel_work_sync(&steam->work_connect);
|
||||||
@@ -792,12 +818,14 @@ static void steam_remove(struct hid_device *hdev)
|
|||||||
static void steam_do_connect_event(struct steam_device *steam, bool connected)
|
static void steam_do_connect_event(struct steam_device *steam, bool connected)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
bool changed;
|
||||||
|
|
||||||
spin_lock_irqsave(&steam->lock, flags);
|
spin_lock_irqsave(&steam->lock, flags);
|
||||||
|
changed = steam->connected != connected;
|
||||||
steam->connected = connected;
|
steam->connected = connected;
|
||||||
spin_unlock_irqrestore(&steam->lock, flags);
|
spin_unlock_irqrestore(&steam->lock, flags);
|
||||||
|
|
||||||
if (schedule_work(&steam->work_connect) == 0)
|
if (changed && schedule_work(&steam->work_connect) == 0)
|
||||||
dbg_hid("%s: connected=%d event already queued\n",
|
dbg_hid("%s: connected=%d event already queued\n",
|
||||||
__func__, connected);
|
__func__, connected);
|
||||||
}
|
}
|
||||||
@@ -1019,13 +1047,8 @@ static int steam_raw_event(struct hid_device *hdev,
|
|||||||
return 0;
|
return 0;
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
input = rcu_dereference(steam->input);
|
input = rcu_dereference(steam->input);
|
||||||
if (likely(input)) {
|
if (likely(input))
|
||||||
steam_do_input_event(steam, input, data);
|
steam_do_input_event(steam, input, data);
|
||||||
} else {
|
|
||||||
dbg_hid("%s: input data without connect event\n",
|
|
||||||
__func__);
|
|
||||||
steam_do_connect_event(steam, true);
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
break;
|
break;
|
||||||
case STEAM_EV_CONNECT:
|
case STEAM_EV_CONNECT:
|
||||||
@@ -1074,7 +1097,10 @@ static int steam_param_set_lizard_mode(const char *val,
|
|||||||
|
|
||||||
mutex_lock(&steam_devices_lock);
|
mutex_lock(&steam_devices_lock);
|
||||||
list_for_each_entry(steam, &steam_devices, list) {
|
list_for_each_entry(steam, &steam_devices, list) {
|
||||||
steam_update_lizard_mode(steam);
|
mutex_lock(&steam->mutex);
|
||||||
|
if (!steam->client_opened)
|
||||||
|
steam_set_lizard_mode(steam, lizard_mode);
|
||||||
|
mutex_unlock(&steam->mutex);
|
||||||
}
|
}
|
||||||
mutex_unlock(&steam_devices_lock);
|
mutex_unlock(&steam_devices_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -177,6 +177,8 @@ static const struct i2c_hid_quirks {
|
|||||||
I2C_HID_QUIRK_NO_RUNTIME_PM },
|
I2C_HID_QUIRK_NO_RUNTIME_PM },
|
||||||
{ I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_4B33,
|
{ I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_4B33,
|
||||||
I2C_HID_QUIRK_DELAY_AFTER_SLEEP },
|
I2C_HID_QUIRK_DELAY_AFTER_SLEEP },
|
||||||
|
{ USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_8001,
|
||||||
|
I2C_HID_QUIRK_NO_RUNTIME_PM },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
|
#include <linux/cred.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/hid.h>
|
#include <linux/hid.h>
|
||||||
@@ -496,12 +497,13 @@ static int uhid_dev_create2(struct uhid_device *uhid,
|
|||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = min(sizeof(hid->name), sizeof(ev->u.create2.name));
|
/* @hid is zero-initialized, strncpy() is correct, strlcpy() not */
|
||||||
strlcpy(hid->name, ev->u.create2.name, len);
|
len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1;
|
||||||
len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys));
|
strncpy(hid->name, ev->u.create2.name, len);
|
||||||
strlcpy(hid->phys, ev->u.create2.phys, len);
|
len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1;
|
||||||
len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq));
|
strncpy(hid->phys, ev->u.create2.phys, len);
|
||||||
strlcpy(hid->uniq, ev->u.create2.uniq, len);
|
len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1;
|
||||||
|
strncpy(hid->uniq, ev->u.create2.uniq, len);
|
||||||
|
|
||||||
hid->ll_driver = &uhid_hid_driver;
|
hid->ll_driver = &uhid_hid_driver;
|
||||||
hid->bus = ev->u.create2.bus;
|
hid->bus = ev->u.create2.bus;
|
||||||
@@ -722,6 +724,17 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
|
|||||||
|
|
||||||
switch (uhid->input_buf.type) {
|
switch (uhid->input_buf.type) {
|
||||||
case UHID_CREATE:
|
case UHID_CREATE:
|
||||||
|
/*
|
||||||
|
* 'struct uhid_create_req' contains a __user pointer which is
|
||||||
|
* copied from, so it's unsafe to allow this with elevated
|
||||||
|
* privileges (e.g. from a setuid binary) or via kernel_write().
|
||||||
|
*/
|
||||||
|
if (file->f_cred != current_cred() || uaccess_kernel()) {
|
||||||
|
pr_err_once("UHID_CREATE from different security context by process %d (%s), this is not allowed.\n",
|
||||||
|
task_tgid_vnr(current), current->comm);
|
||||||
|
ret = -EACCES;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
ret = uhid_dev_create(uhid, &uhid->input_buf);
|
ret = uhid_dev_create(uhid, &uhid->input_buf);
|
||||||
break;
|
break;
|
||||||
case UHID_CREATE2:
|
case UHID_CREATE2:
|
||||||
|
@@ -353,6 +353,9 @@ static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
|
|||||||
|
|
||||||
out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
|
out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
|
||||||
|
|
||||||
|
/* fallthrough */
|
||||||
|
|
||||||
|
case KVP_OP_GET_IP_INFO:
|
||||||
utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
|
utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
|
||||||
MAX_ADAPTER_ID_SIZE,
|
MAX_ADAPTER_ID_SIZE,
|
||||||
UTF16_LITTLE_ENDIAN,
|
UTF16_LITTLE_ENDIAN,
|
||||||
@@ -405,7 +408,11 @@ kvp_send_key(struct work_struct *dummy)
|
|||||||
process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
|
process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
|
||||||
break;
|
break;
|
||||||
case KVP_OP_GET_IP_INFO:
|
case KVP_OP_GET_IP_INFO:
|
||||||
/* We only need to pass on message->kvp_hdr.operation. */
|
/*
|
||||||
|
* We only need to pass on the info of operation, adapter_id
|
||||||
|
* and addr_family to the userland kvp daemon.
|
||||||
|
*/
|
||||||
|
process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
|
||||||
break;
|
break;
|
||||||
case KVP_OP_SET:
|
case KVP_OP_SET:
|
||||||
switch (in_msg->body.kvp_set.data.value_type) {
|
switch (in_msg->body.kvp_set.data.value_type) {
|
||||||
@@ -446,9 +453,9 @@ kvp_send_key(struct work_struct *dummy)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
/*
|
||||||
|
* The key is always a string - utf16 encoding.
|
||||||
case KVP_OP_GET:
|
*/
|
||||||
message->body.kvp_set.data.key_size =
|
message->body.kvp_set.data.key_size =
|
||||||
utf16s_to_utf8s(
|
utf16s_to_utf8s(
|
||||||
(wchar_t *)in_msg->body.kvp_set.data.key,
|
(wchar_t *)in_msg->body.kvp_set.data.key,
|
||||||
@@ -456,6 +463,17 @@ kvp_send_key(struct work_struct *dummy)
|
|||||||
UTF16_LITTLE_ENDIAN,
|
UTF16_LITTLE_ENDIAN,
|
||||||
message->body.kvp_set.data.key,
|
message->body.kvp_set.data.key,
|
||||||
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
|
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KVP_OP_GET:
|
||||||
|
message->body.kvp_get.data.key_size =
|
||||||
|
utf16s_to_utf8s(
|
||||||
|
(wchar_t *)in_msg->body.kvp_get.data.key,
|
||||||
|
in_msg->body.kvp_get.data.key_size,
|
||||||
|
UTF16_LITTLE_ENDIAN,
|
||||||
|
message->body.kvp_get.data.key,
|
||||||
|
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KVP_OP_DELETE:
|
case KVP_OP_DELETE:
|
||||||
|
@@ -797,7 +797,8 @@ static int iommu_init_ga_log(struct amd_iommu *iommu)
|
|||||||
entry = iommu_virt_to_phys(iommu->ga_log) | GA_LOG_SIZE_512;
|
entry = iommu_virt_to_phys(iommu->ga_log) | GA_LOG_SIZE_512;
|
||||||
memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_BASE_OFFSET,
|
memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_BASE_OFFSET,
|
||||||
&entry, sizeof(entry));
|
&entry, sizeof(entry));
|
||||||
entry = (iommu_virt_to_phys(iommu->ga_log) & 0xFFFFFFFFFFFFFULL) & ~7ULL;
|
entry = (iommu_virt_to_phys(iommu->ga_log_tail) &
|
||||||
|
(BIT_ULL(52)-1)) & ~7ULL;
|
||||||
memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_TAIL_OFFSET,
|
memcpy_toio(iommu->mmio_base + MMIO_GA_LOG_TAIL_OFFSET,
|
||||||
&entry, sizeof(entry));
|
&entry, sizeof(entry));
|
||||||
writel(0x00, iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
|
writel(0x00, iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
|
||||||
|
@@ -3075,7 +3075,7 @@ static int copy_context_table(struct intel_iommu *iommu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (old_ce)
|
if (old_ce)
|
||||||
iounmap(old_ce);
|
memunmap(old_ce);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (devfn < 0x80)
|
if (devfn < 0x80)
|
||||||
|
@@ -595,7 +595,7 @@ static irqreturn_t prq_event_thread(int irq, void *d)
|
|||||||
pr_err("%s: Page request without PASID: %08llx %08llx\n",
|
pr_err("%s: Page request without PASID: %08llx %08llx\n",
|
||||||
iommu->name, ((unsigned long long *)req)[0],
|
iommu->name, ((unsigned long long *)req)[0],
|
||||||
((unsigned long long *)req)[1]);
|
((unsigned long long *)req)[1]);
|
||||||
goto bad_req;
|
goto no_pasid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!svm || svm->pasid != req->pasid) {
|
if (!svm || svm->pasid != req->pasid) {
|
||||||
|
@@ -498,6 +498,9 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
|
|||||||
|
|
||||||
static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain)
|
static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain)
|
||||||
{
|
{
|
||||||
|
if (!domain->mmu)
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable the context. Flush the TLB as required when modifying the
|
* Disable the context. Flush the TLB as required when modifying the
|
||||||
* context registers.
|
* context registers.
|
||||||
|
@@ -807,7 +807,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) {
|
if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) {
|
||||||
dprintk(1, "%s: transmit queue full\n", __func__);
|
dprintk(2, "%s: transmit queue full\n", __func__);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1180,6 +1180,8 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|||||||
{
|
{
|
||||||
struct cec_log_addrs *las = &adap->log_addrs;
|
struct cec_log_addrs *las = &adap->log_addrs;
|
||||||
struct cec_msg msg = { };
|
struct cec_msg msg = { };
|
||||||
|
const unsigned int max_retries = 2;
|
||||||
|
unsigned int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (cec_has_log_addr(adap, log_addr))
|
if (cec_has_log_addr(adap, log_addr))
|
||||||
@@ -1188,6 +1190,8 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|||||||
/* Send poll message */
|
/* Send poll message */
|
||||||
msg.len = 1;
|
msg.len = 1;
|
||||||
msg.msg[0] = (log_addr << 4) | log_addr;
|
msg.msg[0] = (log_addr << 4) | log_addr;
|
||||||
|
|
||||||
|
for (i = 0; i < max_retries; i++) {
|
||||||
err = cec_transmit_msg_fh(adap, &msg, NULL, true);
|
err = cec_transmit_msg_fh(adap, &msg, NULL, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1200,8 +1204,31 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The message was aborted due to a disconnect or
|
||||||
|
* unconfigure, just bail out.
|
||||||
|
*/
|
||||||
|
if (msg.tx_status & CEC_TX_STATUS_ABORTED)
|
||||||
|
return -EINTR;
|
||||||
if (msg.tx_status & CEC_TX_STATUS_OK)
|
if (msg.tx_status & CEC_TX_STATUS_OK)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (msg.tx_status & CEC_TX_STATUS_NACK)
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* Retry up to max_retries times if the message was neither
|
||||||
|
* OKed or NACKed. This can happen due to e.g. a Lost
|
||||||
|
* Arbitration condition.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are unable to get an OK or a NACK after max_retries attempts
|
||||||
|
* (and note that each attempt already consists of four polls), then
|
||||||
|
* then we assume that something is really weird and that it is not a
|
||||||
|
* good idea to try and claim this logical address.
|
||||||
|
*/
|
||||||
|
if (i == max_retries)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Message not acknowledged, so this logical
|
* Message not acknowledged, so this logical
|
||||||
|
@@ -1918,7 +1918,6 @@ static int tc358743_probe_of(struct tc358743_state *state)
|
|||||||
ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
|
ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to parse endpoint\n");
|
dev_err(dev, "failed to parse endpoint\n");
|
||||||
ret = ret;
|
|
||||||
goto put_node;
|
goto put_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1844,14 +1844,12 @@ fail_mutex_destroy:
|
|||||||
static void cio2_pci_remove(struct pci_dev *pci_dev)
|
static void cio2_pci_remove(struct pci_dev *pci_dev)
|
||||||
{
|
{
|
||||||
struct cio2_device *cio2 = pci_get_drvdata(pci_dev);
|
struct cio2_device *cio2 = pci_get_drvdata(pci_dev);
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
cio2_notifier_exit(cio2);
|
|
||||||
cio2_fbpt_exit_dummy(cio2);
|
|
||||||
for (i = 0; i < CIO2_QUEUES; i++)
|
|
||||||
cio2_queue_exit(cio2, &cio2->queue[i]);
|
|
||||||
v4l2_device_unregister(&cio2->v4l2_dev);
|
|
||||||
media_device_unregister(&cio2->media_dev);
|
media_device_unregister(&cio2->media_dev);
|
||||||
|
cio2_notifier_exit(cio2);
|
||||||
|
cio2_queues_exit(cio2);
|
||||||
|
cio2_fbpt_exit_dummy(cio2);
|
||||||
|
v4l2_device_unregister(&cio2->v4l2_dev);
|
||||||
media_device_cleanup(&cio2->media_dev);
|
media_device_cleanup(&cio2->media_dev);
|
||||||
mutex_destroy(&cio2->lock);
|
mutex_destroy(&cio2->lock);
|
||||||
}
|
}
|
||||||
|
@@ -1587,6 +1587,8 @@ static void isp_pm_complete(struct device *dev)
|
|||||||
|
|
||||||
static void isp_unregister_entities(struct isp_device *isp)
|
static void isp_unregister_entities(struct isp_device *isp)
|
||||||
{
|
{
|
||||||
|
media_device_unregister(&isp->media_dev);
|
||||||
|
|
||||||
omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
|
omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
|
||||||
omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
|
omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
|
||||||
omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
|
omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
|
||||||
@@ -1597,7 +1599,6 @@ static void isp_unregister_entities(struct isp_device *isp)
|
|||||||
omap3isp_stat_unregister_entities(&isp->isp_hist);
|
omap3isp_stat_unregister_entities(&isp->isp_hist);
|
||||||
|
|
||||||
v4l2_device_unregister(&isp->v4l2_dev);
|
v4l2_device_unregister(&isp->v4l2_dev);
|
||||||
media_device_unregister(&isp->media_dev);
|
|
||||||
media_device_cleanup(&isp->media_dev);
|
media_device_cleanup(&isp->media_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,7 +42,7 @@ MODULE_PARM_DESC(debug, " activates debug info");
|
|||||||
#define MAX_WIDTH 4096U
|
#define MAX_WIDTH 4096U
|
||||||
#define MIN_WIDTH 640U
|
#define MIN_WIDTH 640U
|
||||||
#define MAX_HEIGHT 2160U
|
#define MAX_HEIGHT 2160U
|
||||||
#define MIN_HEIGHT 480U
|
#define MIN_HEIGHT 360U
|
||||||
|
|
||||||
#define dprintk(dev, fmt, arg...) \
|
#define dprintk(dev, fmt, arg...) \
|
||||||
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
|
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
|
||||||
|
@@ -1009,7 +1009,7 @@ static const struct v4l2_m2m_ops m2m_ops = {
|
|||||||
|
|
||||||
static const struct media_device_ops m2m_media_ops = {
|
static const struct media_device_ops m2m_media_ops = {
|
||||||
.req_validate = vb2_request_validate,
|
.req_validate = vb2_request_validate,
|
||||||
.req_queue = vb2_m2m_request_queue,
|
.req_queue = v4l2_m2m_request_queue,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vim2m_probe(struct platform_device *pdev)
|
static int vim2m_probe(struct platform_device *pdev)
|
||||||
|
@@ -1664,6 +1664,11 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
|
|||||||
p_mpeg2_slice_params->forward_ref_index >= VIDEO_MAX_FRAME)
|
p_mpeg2_slice_params->forward_ref_index >= VIDEO_MAX_FRAME)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (p_mpeg2_slice_params->pad ||
|
||||||
|
p_mpeg2_slice_params->picture.pad ||
|
||||||
|
p_mpeg2_slice_params->sequence.pad)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
|
case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
|
||||||
|
@@ -193,6 +193,22 @@ int v4l2_event_pending(struct v4l2_fh *fh)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(v4l2_event_pending);
|
EXPORT_SYMBOL_GPL(v4l2_event_pending);
|
||||||
|
|
||||||
|
static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
|
||||||
|
{
|
||||||
|
struct v4l2_fh *fh = sev->fh;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
lockdep_assert_held(&fh->subscribe_lock);
|
||||||
|
assert_spin_locked(&fh->vdev->fh_lock);
|
||||||
|
|
||||||
|
/* Remove any pending events for this subscription */
|
||||||
|
for (i = 0; i < sev->in_use; i++) {
|
||||||
|
list_del(&sev->events[sev_pos(sev, i)].list);
|
||||||
|
fh->navailable--;
|
||||||
|
}
|
||||||
|
list_del(&sev->list);
|
||||||
|
}
|
||||||
|
|
||||||
int v4l2_event_subscribe(struct v4l2_fh *fh,
|
int v4l2_event_subscribe(struct v4l2_fh *fh,
|
||||||
const struct v4l2_event_subscription *sub, unsigned elems,
|
const struct v4l2_event_subscription *sub, unsigned elems,
|
||||||
const struct v4l2_subscribed_event_ops *ops)
|
const struct v4l2_subscribed_event_ops *ops)
|
||||||
@@ -224,27 +240,23 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
|
|||||||
|
|
||||||
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
||||||
found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
|
found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
|
||||||
|
if (!found_ev)
|
||||||
|
list_add(&sev->list, &fh->subscribed);
|
||||||
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
||||||
|
|
||||||
if (found_ev) {
|
if (found_ev) {
|
||||||
/* Already listening */
|
/* Already listening */
|
||||||
kvfree(sev);
|
kvfree(sev);
|
||||||
goto out_unlock;
|
} else if (sev->ops && sev->ops->add) {
|
||||||
}
|
|
||||||
|
|
||||||
if (sev->ops && sev->ops->add) {
|
|
||||||
ret = sev->ops->add(sev, elems);
|
ret = sev->ops->add(sev, elems);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kvfree(sev);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
||||||
list_add(&sev->list, &fh->subscribed);
|
__v4l2_event_unsubscribe(sev);
|
||||||
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
||||||
|
kvfree(sev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
mutex_unlock(&fh->subscribe_lock);
|
mutex_unlock(&fh->subscribe_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -279,7 +291,6 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
|
|||||||
{
|
{
|
||||||
struct v4l2_subscribed_event *sev;
|
struct v4l2_subscribed_event *sev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sub->type == V4L2_EVENT_ALL) {
|
if (sub->type == V4L2_EVENT_ALL) {
|
||||||
v4l2_event_unsubscribe_all(fh);
|
v4l2_event_unsubscribe_all(fh);
|
||||||
@@ -291,14 +302,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
|
|||||||
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
|
||||||
|
|
||||||
sev = v4l2_event_subscribed(fh, sub->type, sub->id);
|
sev = v4l2_event_subscribed(fh, sub->type, sub->id);
|
||||||
if (sev != NULL) {
|
if (sev != NULL)
|
||||||
/* Remove any pending events for this subscription */
|
__v4l2_event_unsubscribe(sev);
|
||||||
for (i = 0; i < sev->in_use; i++) {
|
|
||||||
list_del(&sev->events[sev_pos(sev, i)].list);
|
|
||||||
fh->navailable--;
|
|
||||||
}
|
|
||||||
list_del(&sev->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
|
||||||
|
|
||||||
|
@@ -953,7 +953,7 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
|
EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
|
||||||
|
|
||||||
void vb2_m2m_request_queue(struct media_request *req)
|
void v4l2_m2m_request_queue(struct media_request *req)
|
||||||
{
|
{
|
||||||
struct media_request_object *obj, *obj_safe;
|
struct media_request_object *obj, *obj_safe;
|
||||||
struct v4l2_m2m_ctx *m2m_ctx = NULL;
|
struct v4l2_m2m_ctx *m2m_ctx = NULL;
|
||||||
@@ -997,7 +997,7 @@ void vb2_m2m_request_queue(struct media_request *req)
|
|||||||
if (m2m_ctx)
|
if (m2m_ctx)
|
||||||
v4l2_m2m_try_schedule(m2m_ctx);
|
v4l2_m2m_try_schedule(m2m_ctx);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vb2_m2m_request_queue);
|
EXPORT_SYMBOL_GPL(v4l2_m2m_request_queue);
|
||||||
|
|
||||||
/* Videobuf2 ioctl helpers */
|
/* Videobuf2 ioctl helpers */
|
||||||
|
|
||||||
|
@@ -132,7 +132,7 @@ static const struct of_device_id atmel_ssc_dt_ids[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids);
|
MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline const struct atmel_ssc_platform_data * __init
|
static inline const struct atmel_ssc_platform_data *
|
||||||
atmel_ssc_get_driver_data(struct platform_device *pdev)
|
atmel_ssc_get_driver_data(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
if (pdev->dev.of_node) {
|
if (pdev->dev.of_node) {
|
||||||
|
@@ -27,6 +27,9 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <asm/uv/uv_hub.h>
|
#include <asm/uv/uv_hub.h>
|
||||||
|
|
||||||
|
#include <linux/nospec.h>
|
||||||
|
|
||||||
#include "gru.h"
|
#include "gru.h"
|
||||||
#include "grutables.h"
|
#include "grutables.h"
|
||||||
#include "gruhandles.h"
|
#include "gruhandles.h"
|
||||||
@@ -196,6 +199,7 @@ int gru_dump_chiplet_request(unsigned long arg)
|
|||||||
/* Currently, only dump by gid is implemented */
|
/* Currently, only dump by gid is implemented */
|
||||||
if (req.gid >= gru_max_gids)
|
if (req.gid >= gru_max_gids)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
req.gid = array_index_nospec(req.gid, gru_max_gids);
|
||||||
|
|
||||||
gru = GID_TO_GRU(req.gid);
|
gru = GID_TO_GRU(req.gid);
|
||||||
ubuf = req.buf;
|
ubuf = req.buf;
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
* - JMicron (hardware and technical support)
|
* - JMicron (hardware and technical support)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/highmem.h>
|
#include <linux/highmem.h>
|
||||||
@@ -462,6 +463,9 @@ struct intel_host {
|
|||||||
u32 dsm_fns;
|
u32 dsm_fns;
|
||||||
int drv_strength;
|
int drv_strength;
|
||||||
bool d3_retune;
|
bool d3_retune;
|
||||||
|
bool rpm_retune_ok;
|
||||||
|
u32 glk_rx_ctrl1;
|
||||||
|
u32 glk_tun_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const guid_t intel_dsm_guid =
|
static const guid_t intel_dsm_guid =
|
||||||
@@ -791,6 +795,77 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
#define GLK_RX_CTRL1 0x834
|
||||||
|
#define GLK_TUN_VAL 0x840
|
||||||
|
#define GLK_PATH_PLL GENMASK(13, 8)
|
||||||
|
#define GLK_DLY GENMASK(6, 0)
|
||||||
|
/* Workaround firmware failing to restore the tuning value */
|
||||||
|
static void glk_rpm_retune_wa(struct sdhci_pci_chip *chip, bool susp)
|
||||||
|
{
|
||||||
|
struct sdhci_pci_slot *slot = chip->slots[0];
|
||||||
|
struct intel_host *intel_host = sdhci_pci_priv(slot);
|
||||||
|
struct sdhci_host *host = slot->host;
|
||||||
|
u32 glk_rx_ctrl1;
|
||||||
|
u32 glk_tun_val;
|
||||||
|
u32 dly;
|
||||||
|
|
||||||
|
if (intel_host->rpm_retune_ok || !mmc_can_retune(host->mmc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
glk_rx_ctrl1 = sdhci_readl(host, GLK_RX_CTRL1);
|
||||||
|
glk_tun_val = sdhci_readl(host, GLK_TUN_VAL);
|
||||||
|
|
||||||
|
if (susp) {
|
||||||
|
intel_host->glk_rx_ctrl1 = glk_rx_ctrl1;
|
||||||
|
intel_host->glk_tun_val = glk_tun_val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!intel_host->glk_tun_val)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (glk_rx_ctrl1 != intel_host->glk_rx_ctrl1) {
|
||||||
|
intel_host->rpm_retune_ok = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dly = FIELD_PREP(GLK_DLY, FIELD_GET(GLK_PATH_PLL, glk_rx_ctrl1) +
|
||||||
|
(intel_host->glk_tun_val << 1));
|
||||||
|
if (dly == FIELD_GET(GLK_DLY, glk_rx_ctrl1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
glk_rx_ctrl1 = (glk_rx_ctrl1 & ~GLK_DLY) | dly;
|
||||||
|
sdhci_writel(host, glk_rx_ctrl1, GLK_RX_CTRL1);
|
||||||
|
|
||||||
|
intel_host->rpm_retune_ok = true;
|
||||||
|
chip->rpm_retune = true;
|
||||||
|
mmc_retune_needed(host->mmc);
|
||||||
|
pr_info("%s: Requiring re-tune after rpm resume", mmc_hostname(host->mmc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void glk_rpm_retune_chk(struct sdhci_pci_chip *chip, bool susp)
|
||||||
|
{
|
||||||
|
if (chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
|
||||||
|
!chip->rpm_retune)
|
||||||
|
glk_rpm_retune_wa(chip, susp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int glk_runtime_suspend(struct sdhci_pci_chip *chip)
|
||||||
|
{
|
||||||
|
glk_rpm_retune_chk(chip, true);
|
||||||
|
|
||||||
|
return sdhci_cqhci_runtime_suspend(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int glk_runtime_resume(struct sdhci_pci_chip *chip)
|
||||||
|
{
|
||||||
|
glk_rpm_retune_chk(chip, false);
|
||||||
|
|
||||||
|
return sdhci_cqhci_runtime_resume(chip);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static int ni_set_max_freq(struct sdhci_pci_slot *slot)
|
static int ni_set_max_freq(struct sdhci_pci_slot *slot)
|
||||||
{
|
{
|
||||||
@@ -879,8 +954,8 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
|
|||||||
.resume = sdhci_cqhci_resume,
|
.resume = sdhci_cqhci_resume,
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.runtime_suspend = sdhci_cqhci_runtime_suspend,
|
.runtime_suspend = glk_runtime_suspend,
|
||||||
.runtime_resume = sdhci_cqhci_runtime_resume,
|
.runtime_resume = glk_runtime_resume,
|
||||||
#endif
|
#endif
|
||||||
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
|
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
|
||||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||||
@@ -1762,8 +1837,13 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
|
|||||||
device_init_wakeup(&pdev->dev, true);
|
device_init_wakeup(&pdev->dev, true);
|
||||||
|
|
||||||
if (slot->cd_idx >= 0) {
|
if (slot->cd_idx >= 0) {
|
||||||
ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx,
|
ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx,
|
||||||
slot->cd_override_level, 0, NULL);
|
slot->cd_override_level, 0, NULL);
|
||||||
|
if (ret && ret != -EPROBE_DEFER)
|
||||||
|
ret = mmc_gpiod_request_cd(host->mmc, NULL,
|
||||||
|
slot->cd_idx,
|
||||||
|
slot->cd_override_level,
|
||||||
|
0, NULL);
|
||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
goto remove;
|
goto remove;
|
||||||
|
|
||||||
|
@@ -2032,8 +2032,7 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nand_np = dev->of_node;
|
nand_np = dev->of_node;
|
||||||
nfc_np = of_find_compatible_node(dev->of_node, NULL,
|
nfc_np = of_get_compatible_child(dev->of_node, "atmel,sama5d3-nfc");
|
||||||
"atmel,sama5d3-nfc");
|
|
||||||
if (!nfc_np) {
|
if (!nfc_np) {
|
||||||
dev_err(dev, "Could not find device node for sama5d3-nfc\n");
|
dev_err(dev, "Could not find device node for sama5d3-nfc\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -2447,15 +2446,19 @@ static int atmel_nand_controller_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (caps->legacy_of_bindings) {
|
if (caps->legacy_of_bindings) {
|
||||||
|
struct device_node *nfc_node;
|
||||||
u32 ale_offs = 21;
|
u32 ale_offs = 21;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are parsing legacy DT props and the DT contains a
|
* If we are parsing legacy DT props and the DT contains a
|
||||||
* valid NFC node, forward the request to the sama5 logic.
|
* valid NFC node, forward the request to the sama5 logic.
|
||||||
*/
|
*/
|
||||||
if (of_find_compatible_node(pdev->dev.of_node, NULL,
|
nfc_node = of_get_compatible_child(pdev->dev.of_node,
|
||||||
"atmel,sama5d3-nfc"))
|
"atmel,sama5d3-nfc");
|
||||||
|
if (nfc_node) {
|
||||||
caps = &atmel_sama5_nand_caps;
|
caps = &atmel_sama5_nand_caps;
|
||||||
|
of_node_put(nfc_node);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Even if the compatible says we are dealing with an
|
* Even if the compatible says we are dealing with an
|
||||||
|
@@ -150,15 +150,15 @@
|
|||||||
#define NAND_VERSION_MINOR_SHIFT 16
|
#define NAND_VERSION_MINOR_SHIFT 16
|
||||||
|
|
||||||
/* NAND OP_CMDs */
|
/* NAND OP_CMDs */
|
||||||
#define PAGE_READ 0x2
|
#define OP_PAGE_READ 0x2
|
||||||
#define PAGE_READ_WITH_ECC 0x3
|
#define OP_PAGE_READ_WITH_ECC 0x3
|
||||||
#define PAGE_READ_WITH_ECC_SPARE 0x4
|
#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
|
||||||
#define PROGRAM_PAGE 0x6
|
#define OP_PROGRAM_PAGE 0x6
|
||||||
#define PAGE_PROGRAM_WITH_ECC 0x7
|
#define OP_PAGE_PROGRAM_WITH_ECC 0x7
|
||||||
#define PROGRAM_PAGE_SPARE 0x9
|
#define OP_PROGRAM_PAGE_SPARE 0x9
|
||||||
#define BLOCK_ERASE 0xa
|
#define OP_BLOCK_ERASE 0xa
|
||||||
#define FETCH_ID 0xb
|
#define OP_FETCH_ID 0xb
|
||||||
#define RESET_DEVICE 0xd
|
#define OP_RESET_DEVICE 0xd
|
||||||
|
|
||||||
/* Default Value for NAND_DEV_CMD_VLD */
|
/* Default Value for NAND_DEV_CMD_VLD */
|
||||||
#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
|
#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
|
||||||
@@ -692,11 +692,11 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
|
|||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
if (host->use_ecc)
|
if (host->use_ecc)
|
||||||
cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
|
cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
|
||||||
else
|
else
|
||||||
cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
|
cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE;
|
||||||
} else {
|
} else {
|
||||||
cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
|
cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host->use_ecc) {
|
if (host->use_ecc) {
|
||||||
@@ -1170,7 +1170,7 @@ static int nandc_param(struct qcom_nand_host *host)
|
|||||||
* in use. we configure the controller to perform a raw read of 512
|
* in use. we configure the controller to perform a raw read of 512
|
||||||
* bytes to read onfi params
|
* bytes to read onfi params
|
||||||
*/
|
*/
|
||||||
nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
|
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ | PAGE_ACC | LAST_PAGE);
|
||||||
nandc_set_reg(nandc, NAND_ADDR0, 0);
|
nandc_set_reg(nandc, NAND_ADDR0, 0);
|
||||||
nandc_set_reg(nandc, NAND_ADDR1, 0);
|
nandc_set_reg(nandc, NAND_ADDR1, 0);
|
||||||
nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
|
nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
|
||||||
@@ -1224,7 +1224,7 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
|
|||||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||||
|
|
||||||
nandc_set_reg(nandc, NAND_FLASH_CMD,
|
nandc_set_reg(nandc, NAND_FLASH_CMD,
|
||||||
BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
|
OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
|
||||||
nandc_set_reg(nandc, NAND_ADDR0, page_addr);
|
nandc_set_reg(nandc, NAND_ADDR0, page_addr);
|
||||||
nandc_set_reg(nandc, NAND_ADDR1, 0);
|
nandc_set_reg(nandc, NAND_ADDR1, 0);
|
||||||
nandc_set_reg(nandc, NAND_DEV0_CFG0,
|
nandc_set_reg(nandc, NAND_DEV0_CFG0,
|
||||||
@@ -1255,7 +1255,7 @@ static int read_id(struct qcom_nand_host *host, int column)
|
|||||||
if (column == -1)
|
if (column == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID);
|
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_FETCH_ID);
|
||||||
nandc_set_reg(nandc, NAND_ADDR0, column);
|
nandc_set_reg(nandc, NAND_ADDR0, column);
|
||||||
nandc_set_reg(nandc, NAND_ADDR1, 0);
|
nandc_set_reg(nandc, NAND_ADDR1, 0);
|
||||||
nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT,
|
nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT,
|
||||||
@@ -1276,7 +1276,7 @@ static int reset(struct qcom_nand_host *host)
|
|||||||
struct nand_chip *chip = &host->chip;
|
struct nand_chip *chip = &host->chip;
|
||||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||||
|
|
||||||
nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE);
|
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_RESET_DEVICE);
|
||||||
nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
|
nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
|
||||||
|
|
||||||
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
|
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
|
||||||
|
@@ -644,9 +644,23 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr,
|
|||||||
ndelay(cqspi->wr_delay);
|
ndelay(cqspi->wr_delay);
|
||||||
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
|
size_t write_words, mod_bytes;
|
||||||
|
|
||||||
write_bytes = remaining > page_size ? page_size : remaining;
|
write_bytes = remaining > page_size ? page_size : remaining;
|
||||||
iowrite32_rep(cqspi->ahb_base, txbuf,
|
write_words = write_bytes / 4;
|
||||||
DIV_ROUND_UP(write_bytes, 4));
|
mod_bytes = write_bytes % 4;
|
||||||
|
/* Write 4 bytes at a time then single bytes. */
|
||||||
|
if (write_words) {
|
||||||
|
iowrite32_rep(cqspi->ahb_base, txbuf, write_words);
|
||||||
|
txbuf += (write_words * 4);
|
||||||
|
}
|
||||||
|
if (mod_bytes) {
|
||||||
|
unsigned int temp = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
memcpy(&temp, txbuf, mod_bytes);
|
||||||
|
iowrite32(temp, cqspi->ahb_base);
|
||||||
|
txbuf += mod_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wait_for_completion_timeout(&cqspi->transfer_complete,
|
if (!wait_for_completion_timeout(&cqspi->transfer_complete,
|
||||||
msecs_to_jiffies(CQSPI_TIMEOUT_MS))) {
|
msecs_to_jiffies(CQSPI_TIMEOUT_MS))) {
|
||||||
@@ -655,7 +669,6 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr,
|
|||||||
goto failwr;
|
goto failwr;
|
||||||
}
|
}
|
||||||
|
|
||||||
txbuf += write_bytes;
|
|
||||||
remaining -= write_bytes;
|
remaining -= write_bytes;
|
||||||
|
|
||||||
if (remaining > 0)
|
if (remaining > 0)
|
||||||
|
@@ -2156,7 +2156,7 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
|
|||||||
* @nor: pointer to a 'struct spi_nor'
|
* @nor: pointer to a 'struct spi_nor'
|
||||||
* @addr: offset in the serial flash memory
|
* @addr: offset in the serial flash memory
|
||||||
* @len: number of bytes to read
|
* @len: number of bytes to read
|
||||||
* @buf: buffer where the data is copied into
|
* @buf: buffer where the data is copied into (dma-safe memory)
|
||||||
*
|
*
|
||||||
* Return: 0 on success, -errno otherwise.
|
* Return: 0 on success, -errno otherwise.
|
||||||
*/
|
*/
|
||||||
@@ -2521,6 +2521,34 @@ static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
|
|||||||
return left->size - right->size;
|
return left->size - right->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spi_nor_sort_erase_mask() - sort erase mask
|
||||||
|
* @map: the erase map of the SPI NOR
|
||||||
|
* @erase_mask: the erase type mask to be sorted
|
||||||
|
*
|
||||||
|
* Replicate the sort done for the map's erase types in BFPT: sort the erase
|
||||||
|
* mask in ascending order with the smallest erase type size starting from
|
||||||
|
* BIT(0) in the sorted erase mask.
|
||||||
|
*
|
||||||
|
* Return: sorted erase mask.
|
||||||
|
*/
|
||||||
|
static u8 spi_nor_sort_erase_mask(struct spi_nor_erase_map *map, u8 erase_mask)
|
||||||
|
{
|
||||||
|
struct spi_nor_erase_type *erase_type = map->erase_type;
|
||||||
|
int i;
|
||||||
|
u8 sorted_erase_mask = 0;
|
||||||
|
|
||||||
|
if (!erase_mask)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Replicate the sort done for the map's erase types. */
|
||||||
|
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
|
||||||
|
if (erase_type[i].size && erase_mask & BIT(erase_type[i].idx))
|
||||||
|
sorted_erase_mask |= BIT(i);
|
||||||
|
|
||||||
|
return sorted_erase_mask;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_nor_regions_sort_erase_types() - sort erase types in each region
|
* spi_nor_regions_sort_erase_types() - sort erase types in each region
|
||||||
* @map: the erase map of the SPI NOR
|
* @map: the erase map of the SPI NOR
|
||||||
@@ -2536,19 +2564,13 @@ static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
|
|||||||
static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map)
|
static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map)
|
||||||
{
|
{
|
||||||
struct spi_nor_erase_region *region = map->regions;
|
struct spi_nor_erase_region *region = map->regions;
|
||||||
struct spi_nor_erase_type *erase_type = map->erase_type;
|
|
||||||
int i;
|
|
||||||
u8 region_erase_mask, sorted_erase_mask;
|
u8 region_erase_mask, sorted_erase_mask;
|
||||||
|
|
||||||
while (region) {
|
while (region) {
|
||||||
region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
|
region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
|
||||||
|
|
||||||
/* Replicate the sort done for the map's erase types. */
|
sorted_erase_mask = spi_nor_sort_erase_mask(map,
|
||||||
sorted_erase_mask = 0;
|
region_erase_mask);
|
||||||
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
|
|
||||||
if (erase_type[i].size &&
|
|
||||||
region_erase_mask & BIT(erase_type[i].idx))
|
|
||||||
sorted_erase_mask |= BIT(i);
|
|
||||||
|
|
||||||
/* Overwrite erase mask. */
|
/* Overwrite erase mask. */
|
||||||
region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
|
region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
|
||||||
@@ -2855,52 +2877,84 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings)
|
|||||||
* spi_nor_get_map_in_use() - get the configuration map in use
|
* spi_nor_get_map_in_use() - get the configuration map in use
|
||||||
* @nor: pointer to a 'struct spi_nor'
|
* @nor: pointer to a 'struct spi_nor'
|
||||||
* @smpt: pointer to the sector map parameter table
|
* @smpt: pointer to the sector map parameter table
|
||||||
|
* @smpt_len: sector map parameter table length
|
||||||
|
*
|
||||||
|
* Return: pointer to the map in use, ERR_PTR(-errno) otherwise.
|
||||||
*/
|
*/
|
||||||
static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
|
static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt,
|
||||||
|
u8 smpt_len)
|
||||||
{
|
{
|
||||||
const u32 *ret = NULL;
|
const u32 *ret;
|
||||||
u32 i, addr;
|
u8 *buf;
|
||||||
|
u32 addr;
|
||||||
int err;
|
int err;
|
||||||
|
u8 i;
|
||||||
u8 addr_width, read_opcode, read_dummy;
|
u8 addr_width, read_opcode, read_dummy;
|
||||||
u8 read_data_mask, data_byte, map_id;
|
u8 read_data_mask, map_id;
|
||||||
|
|
||||||
|
/* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */
|
||||||
|
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
|
||||||
|
if (!buf)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
addr_width = nor->addr_width;
|
addr_width = nor->addr_width;
|
||||||
read_dummy = nor->read_dummy;
|
read_dummy = nor->read_dummy;
|
||||||
read_opcode = nor->read_opcode;
|
read_opcode = nor->read_opcode;
|
||||||
|
|
||||||
map_id = 0;
|
map_id = 0;
|
||||||
i = 0;
|
|
||||||
/* Determine if there are any optional Detection Command Descriptors */
|
/* Determine if there are any optional Detection Command Descriptors */
|
||||||
while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) {
|
for (i = 0; i < smpt_len; i += 2) {
|
||||||
|
if (smpt[i] & SMPT_DESC_TYPE_MAP)
|
||||||
|
break;
|
||||||
|
|
||||||
read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
|
read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
|
||||||
nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]);
|
nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]);
|
||||||
nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
|
nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
|
||||||
nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]);
|
nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]);
|
||||||
addr = smpt[i + 1];
|
addr = smpt[i + 1];
|
||||||
|
|
||||||
err = spi_nor_read_raw(nor, addr, 1, &data_byte);
|
err = spi_nor_read_raw(nor, addr, 1, buf);
|
||||||
if (err)
|
if (err) {
|
||||||
|
ret = ERR_PTR(err);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build an index value that is used to select the Sector Map
|
* Build an index value that is used to select the Sector Map
|
||||||
* Configuration that is currently in use.
|
* Configuration that is currently in use.
|
||||||
*/
|
*/
|
||||||
map_id = map_id << 1 | !!(data_byte & read_data_mask);
|
map_id = map_id << 1 | !!(*buf & read_data_mask);
|
||||||
i = i + 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the matching configuration map */
|
/*
|
||||||
while (SMPT_MAP_ID(smpt[i]) != map_id) {
|
* If command descriptors are provided, they always precede map
|
||||||
|
* descriptors in the table. There is no need to start the iteration
|
||||||
|
* over smpt array all over again.
|
||||||
|
*
|
||||||
|
* Find the matching configuration map.
|
||||||
|
*/
|
||||||
|
ret = ERR_PTR(-EINVAL);
|
||||||
|
while (i < smpt_len) {
|
||||||
|
if (SMPT_MAP_ID(smpt[i]) == map_id) {
|
||||||
|
ret = smpt + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are no more configuration map descriptors and no
|
||||||
|
* configuration ID matched the configuration identifier, the
|
||||||
|
* sector address map is unknown.
|
||||||
|
*/
|
||||||
if (smpt[i] & SMPT_DESC_END)
|
if (smpt[i] & SMPT_DESC_END)
|
||||||
goto out;
|
break;
|
||||||
|
|
||||||
/* increment the table index to the next map */
|
/* increment the table index to the next map */
|
||||||
i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1;
|
i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = smpt + i;
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
out:
|
out:
|
||||||
|
kfree(buf);
|
||||||
nor->addr_width = addr_width;
|
nor->addr_width = addr_width;
|
||||||
nor->read_dummy = read_dummy;
|
nor->read_dummy = read_dummy;
|
||||||
nor->read_opcode = read_opcode;
|
nor->read_opcode = read_opcode;
|
||||||
@@ -2946,7 +3000,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
|
|||||||
u64 offset;
|
u64 offset;
|
||||||
u32 region_count;
|
u32 region_count;
|
||||||
int i, j;
|
int i, j;
|
||||||
u8 erase_type;
|
u8 erase_type, uniform_erase_type;
|
||||||
|
|
||||||
region_count = SMPT_MAP_REGION_COUNT(*smpt);
|
region_count = SMPT_MAP_REGION_COUNT(*smpt);
|
||||||
/*
|
/*
|
||||||
@@ -2959,7 +3013,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
map->regions = region;
|
map->regions = region;
|
||||||
|
|
||||||
map->uniform_erase_type = 0xff;
|
uniform_erase_type = 0xff;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
/* Populate regions. */
|
/* Populate regions. */
|
||||||
for (i = 0; i < region_count; i++) {
|
for (i = 0; i < region_count; i++) {
|
||||||
@@ -2974,12 +3028,15 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
|
|||||||
* Save the erase types that are supported in all regions and
|
* Save the erase types that are supported in all regions and
|
||||||
* can erase the entire flash memory.
|
* can erase the entire flash memory.
|
||||||
*/
|
*/
|
||||||
map->uniform_erase_type &= erase_type;
|
uniform_erase_type &= erase_type;
|
||||||
|
|
||||||
offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
|
offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
|
||||||
region[i].size;
|
region[i].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map->uniform_erase_type = spi_nor_sort_erase_mask(map,
|
||||||
|
uniform_erase_type);
|
||||||
|
|
||||||
spi_nor_region_mark_end(®ion[i - 1]);
|
spi_nor_region_mark_end(®ion[i - 1]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3020,9 +3077,9 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
|
|||||||
for (i = 0; i < smpt_header->length; i++)
|
for (i = 0; i < smpt_header->length; i++)
|
||||||
smpt[i] = le32_to_cpu(smpt[i]);
|
smpt[i] = le32_to_cpu(smpt[i]);
|
||||||
|
|
||||||
sector_map = spi_nor_get_map_in_use(nor, smpt);
|
sector_map = spi_nor_get_map_in_use(nor, smpt, smpt_header->length);
|
||||||
if (!sector_map) {
|
if (IS_ERR(sector_map)) {
|
||||||
ret = -EINVAL;
|
ret = PTR_ERR(sector_map);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3125,7 +3182,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
|
|||||||
if (err)
|
if (err)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
/* Parse other parameter headers. */
|
/* Parse optional parameter tables. */
|
||||||
for (i = 0; i < header.nph; i++) {
|
for (i = 0; i < header.nph; i++) {
|
||||||
param_header = ¶m_headers[i];
|
param_header = ¶m_headers[i];
|
||||||
|
|
||||||
@@ -3138,8 +3195,17 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err) {
|
||||||
goto exit;
|
dev_warn(dev, "Failed to parse optional parameter table: %04x\n",
|
||||||
|
SFDP_PARAM_HEADER_ID(param_header));
|
||||||
|
/*
|
||||||
|
* Let's not drop all information we extracted so far
|
||||||
|
* if optional table parsers fail. In case of failing,
|
||||||
|
* each optional parser is responsible to roll back to
|
||||||
|
* the previously known spi_nor data.
|
||||||
|
*/
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@@ -477,6 +477,34 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
||||||
|
|
||||||
|
struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr)
|
||||||
|
{
|
||||||
|
struct can_priv *priv = netdev_priv(dev);
|
||||||
|
struct sk_buff *skb = priv->echo_skb[idx];
|
||||||
|
struct canfd_frame *cf;
|
||||||
|
|
||||||
|
if (idx >= priv->echo_skb_max) {
|
||||||
|
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
|
||||||
|
__func__, idx, priv->echo_skb_max);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skb) {
|
||||||
|
netdev_err(dev, "%s: BUG! Trying to echo non existing skb: can_priv::echo_skb[%u]\n",
|
||||||
|
__func__, idx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Using "struct canfd_frame::len" for the frame
|
||||||
|
* length is supported on both CAN and CANFD frames.
|
||||||
|
*/
|
||||||
|
cf = (struct canfd_frame *)skb->data;
|
||||||
|
*len_ptr = cf->len;
|
||||||
|
priv->echo_skb[idx] = NULL;
|
||||||
|
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the skb from the stack and loop it back locally
|
* Get the skb from the stack and loop it back locally
|
||||||
*
|
*
|
||||||
@@ -486,22 +514,16 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
|||||||
*/
|
*/
|
||||||
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
|
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
|
||||||
{
|
{
|
||||||
struct can_priv *priv = netdev_priv(dev);
|
struct sk_buff *skb;
|
||||||
|
u8 len;
|
||||||
BUG_ON(idx >= priv->echo_skb_max);
|
|
||||||
|
|
||||||
if (priv->echo_skb[idx]) {
|
|
||||||
struct sk_buff *skb = priv->echo_skb[idx];
|
|
||||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
|
||||||
u8 dlc = cf->can_dlc;
|
|
||||||
|
|
||||||
netif_rx(priv->echo_skb[idx]);
|
|
||||||
priv->echo_skb[idx] = NULL;
|
|
||||||
|
|
||||||
return dlc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
skb = __can_get_echo_skb(dev, idx, &len);
|
||||||
|
if (!skb)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
netif_rx(skb);
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(can_get_echo_skb);
|
EXPORT_SYMBOL_GPL(can_get_echo_skb);
|
||||||
|
|
||||||
|
@@ -136,12 +136,11 @@
|
|||||||
/* FLEXCAN interrupt flag register (IFLAG) bits */
|
/* FLEXCAN interrupt flag register (IFLAG) bits */
|
||||||
/* Errata ERR005829 step7: Reserve first valid MB */
|
/* Errata ERR005829 step7: Reserve first valid MB */
|
||||||
#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
|
#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
|
||||||
#define FLEXCAN_TX_MB_OFF_FIFO 9
|
|
||||||
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
|
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
|
||||||
#define FLEXCAN_TX_MB_OFF_TIMESTAMP 1
|
#define FLEXCAN_TX_MB 63
|
||||||
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_OFF_TIMESTAMP + 1)
|
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
|
||||||
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST 63
|
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST (FLEXCAN_TX_MB - 1)
|
||||||
#define FLEXCAN_IFLAG_MB(x) BIT(x)
|
#define FLEXCAN_IFLAG_MB(x) BIT(x & 0x1f)
|
||||||
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
|
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
|
||||||
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
|
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
|
||||||
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
|
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
|
||||||
@@ -259,9 +258,7 @@ struct flexcan_priv {
|
|||||||
struct can_rx_offload offload;
|
struct can_rx_offload offload;
|
||||||
|
|
||||||
struct flexcan_regs __iomem *regs;
|
struct flexcan_regs __iomem *regs;
|
||||||
struct flexcan_mb __iomem *tx_mb;
|
|
||||||
struct flexcan_mb __iomem *tx_mb_reserved;
|
struct flexcan_mb __iomem *tx_mb_reserved;
|
||||||
u8 tx_mb_idx;
|
|
||||||
u32 reg_ctrl_default;
|
u32 reg_ctrl_default;
|
||||||
u32 reg_imask1_default;
|
u32 reg_imask1_default;
|
||||||
u32 reg_imask2_default;
|
u32 reg_imask2_default;
|
||||||
@@ -515,6 +512,7 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
|
|||||||
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
const struct flexcan_priv *priv = netdev_priv(dev);
|
const struct flexcan_priv *priv = netdev_priv(dev);
|
||||||
|
struct flexcan_regs __iomem *regs = priv->regs;
|
||||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||||
u32 can_id;
|
u32 can_id;
|
||||||
u32 data;
|
u32 data;
|
||||||
@@ -537,17 +535,17 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
|
|||||||
|
|
||||||
if (cf->can_dlc > 0) {
|
if (cf->can_dlc > 0) {
|
||||||
data = be32_to_cpup((__be32 *)&cf->data[0]);
|
data = be32_to_cpup((__be32 *)&cf->data[0]);
|
||||||
priv->write(data, &priv->tx_mb->data[0]);
|
priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[0]);
|
||||||
}
|
}
|
||||||
if (cf->can_dlc > 4) {
|
if (cf->can_dlc > 4) {
|
||||||
data = be32_to_cpup((__be32 *)&cf->data[4]);
|
data = be32_to_cpup((__be32 *)&cf->data[4]);
|
||||||
priv->write(data, &priv->tx_mb->data[1]);
|
priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
can_put_echo_skb(skb, dev, 0);
|
can_put_echo_skb(skb, dev, 0);
|
||||||
|
|
||||||
priv->write(can_id, &priv->tx_mb->can_id);
|
priv->write(can_id, ®s->mb[FLEXCAN_TX_MB].can_id);
|
||||||
priv->write(ctrl, &priv->tx_mb->can_ctrl);
|
priv->write(ctrl, ®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
||||||
|
|
||||||
/* Errata ERR005829 step8:
|
/* Errata ERR005829 step8:
|
||||||
* Write twice INACTIVE(0x8) code to first MB.
|
* Write twice INACTIVE(0x8) code to first MB.
|
||||||
@@ -563,9 +561,13 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
|
|||||||
static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
|
static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
|
||||||
{
|
{
|
||||||
struct flexcan_priv *priv = netdev_priv(dev);
|
struct flexcan_priv *priv = netdev_priv(dev);
|
||||||
|
struct flexcan_regs __iomem *regs = priv->regs;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct can_frame *cf;
|
struct can_frame *cf;
|
||||||
bool rx_errors = false, tx_errors = false;
|
bool rx_errors = false, tx_errors = false;
|
||||||
|
u32 timestamp;
|
||||||
|
|
||||||
|
timestamp = priv->read(®s->timer) << 16;
|
||||||
|
|
||||||
skb = alloc_can_err_skb(dev, &cf);
|
skb = alloc_can_err_skb(dev, &cf);
|
||||||
if (unlikely(!skb))
|
if (unlikely(!skb))
|
||||||
@@ -612,17 +614,21 @@ static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
|
|||||||
if (tx_errors)
|
if (tx_errors)
|
||||||
dev->stats.tx_errors++;
|
dev->stats.tx_errors++;
|
||||||
|
|
||||||
can_rx_offload_irq_queue_err_skb(&priv->offload, skb);
|
can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
||||||
{
|
{
|
||||||
struct flexcan_priv *priv = netdev_priv(dev);
|
struct flexcan_priv *priv = netdev_priv(dev);
|
||||||
|
struct flexcan_regs __iomem *regs = priv->regs;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct can_frame *cf;
|
struct can_frame *cf;
|
||||||
enum can_state new_state, rx_state, tx_state;
|
enum can_state new_state, rx_state, tx_state;
|
||||||
int flt;
|
int flt;
|
||||||
struct can_berr_counter bec;
|
struct can_berr_counter bec;
|
||||||
|
u32 timestamp;
|
||||||
|
|
||||||
|
timestamp = priv->read(®s->timer) << 16;
|
||||||
|
|
||||||
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
|
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
|
||||||
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
|
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
|
||||||
@@ -652,7 +658,7 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
|||||||
if (unlikely(new_state == CAN_STATE_BUS_OFF))
|
if (unlikely(new_state == CAN_STATE_BUS_OFF))
|
||||||
can_bus_off(dev);
|
can_bus_off(dev);
|
||||||
|
|
||||||
can_rx_offload_irq_queue_err_skb(&priv->offload, skb);
|
can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
|
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
|
||||||
@@ -720,9 +726,14 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
|||||||
priv->write(BIT(n - 32), ®s->iflag2);
|
priv->write(BIT(n - 32), ®s->iflag2);
|
||||||
} else {
|
} else {
|
||||||
priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1);
|
priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1);
|
||||||
priv->read(®s->timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read the Free Running Timer. It is optional but recommended
|
||||||
|
* to unlock Mailbox as soon as possible and make it available
|
||||||
|
* for reception.
|
||||||
|
*/
|
||||||
|
priv->read(®s->timer);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,9 +743,9 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
|
|||||||
struct flexcan_regs __iomem *regs = priv->regs;
|
struct flexcan_regs __iomem *regs = priv->regs;
|
||||||
u32 iflag1, iflag2;
|
u32 iflag1, iflag2;
|
||||||
|
|
||||||
iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default;
|
iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default &
|
||||||
iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default &
|
~FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB);
|
||||||
~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default;
|
||||||
|
|
||||||
return (u64)iflag2 << 32 | iflag1;
|
return (u64)iflag2 << 32 | iflag1;
|
||||||
}
|
}
|
||||||
@@ -746,11 +757,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|||||||
struct flexcan_priv *priv = netdev_priv(dev);
|
struct flexcan_priv *priv = netdev_priv(dev);
|
||||||
struct flexcan_regs __iomem *regs = priv->regs;
|
struct flexcan_regs __iomem *regs = priv->regs;
|
||||||
irqreturn_t handled = IRQ_NONE;
|
irqreturn_t handled = IRQ_NONE;
|
||||||
u32 reg_iflag1, reg_esr;
|
u32 reg_iflag2, reg_esr;
|
||||||
enum can_state last_state = priv->can.state;
|
enum can_state last_state = priv->can.state;
|
||||||
|
|
||||||
reg_iflag1 = priv->read(®s->iflag1);
|
|
||||||
|
|
||||||
/* reception interrupt */
|
/* reception interrupt */
|
||||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||||
u64 reg_iflag;
|
u64 reg_iflag;
|
||||||
@@ -764,6 +773,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
u32 reg_iflag1;
|
||||||
|
|
||||||
|
reg_iflag1 = priv->read(®s->iflag1);
|
||||||
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) {
|
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) {
|
||||||
handled = IRQ_HANDLED;
|
handled = IRQ_HANDLED;
|
||||||
can_rx_offload_irq_offload_fifo(&priv->offload);
|
can_rx_offload_irq_offload_fifo(&priv->offload);
|
||||||
@@ -779,17 +791,22 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reg_iflag2 = priv->read(®s->iflag2);
|
||||||
|
|
||||||
/* transmission complete interrupt */
|
/* transmission complete interrupt */
|
||||||
if (reg_iflag1 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
|
if (reg_iflag2 & FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB)) {
|
||||||
|
u32 reg_ctrl = priv->read(®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
||||||
|
|
||||||
handled = IRQ_HANDLED;
|
handled = IRQ_HANDLED;
|
||||||
stats->tx_bytes += can_get_echo_skb(dev, 0);
|
stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload,
|
||||||
|
0, reg_ctrl << 16);
|
||||||
stats->tx_packets++;
|
stats->tx_packets++;
|
||||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||||
|
|
||||||
/* after sending a RTR frame MB is in RX mode */
|
/* after sending a RTR frame MB is in RX mode */
|
||||||
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||||||
&priv->tx_mb->can_ctrl);
|
®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
||||||
priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), ®s->iflag1);
|
priv->write(FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB), ®s->iflag2);
|
||||||
netif_wake_queue(dev);
|
netif_wake_queue(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,15 +948,13 @@ static int flexcan_chip_start(struct net_device *dev)
|
|||||||
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
|
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
|
||||||
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV |
|
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV |
|
||||||
FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_IRMQ |
|
FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_IRMQ |
|
||||||
FLEXCAN_MCR_IDAM_C;
|
FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_MB);
|
||||||
|
|
||||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
||||||
reg_mcr &= ~FLEXCAN_MCR_FEN;
|
reg_mcr &= ~FLEXCAN_MCR_FEN;
|
||||||
reg_mcr |= FLEXCAN_MCR_MAXMB(priv->offload.mb_last);
|
else
|
||||||
} else {
|
reg_mcr |= FLEXCAN_MCR_FEN;
|
||||||
reg_mcr |= FLEXCAN_MCR_FEN |
|
|
||||||
FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
|
|
||||||
}
|
|
||||||
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
|
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
|
||||||
priv->write(reg_mcr, ®s->mcr);
|
priv->write(reg_mcr, ®s->mcr);
|
||||||
|
|
||||||
@@ -982,16 +997,17 @@ static int flexcan_chip_start(struct net_device *dev)
|
|||||||
priv->write(reg_ctrl2, ®s->ctrl2);
|
priv->write(reg_ctrl2, ®s->ctrl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear and invalidate all mailboxes first */
|
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||||
for (i = priv->tx_mb_idx; i < ARRAY_SIZE(regs->mb); i++) {
|
for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) {
|
||||||
|
priv->write(FLEXCAN_MB_CODE_RX_EMPTY,
|
||||||
|
®s->mb[i].can_ctrl);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* clear and invalidate unused mailboxes first */
|
||||||
|
for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= ARRAY_SIZE(regs->mb); i++) {
|
||||||
priv->write(FLEXCAN_MB_CODE_RX_INACTIVE,
|
priv->write(FLEXCAN_MB_CODE_RX_INACTIVE,
|
||||||
®s->mb[i].can_ctrl);
|
®s->mb[i].can_ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
|
||||||
for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++)
|
|
||||||
priv->write(FLEXCAN_MB_CODE_RX_EMPTY,
|
|
||||||
®s->mb[i].can_ctrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Errata ERR005829: mark first TX mailbox as INACTIVE */
|
/* Errata ERR005829: mark first TX mailbox as INACTIVE */
|
||||||
@@ -1000,7 +1016,7 @@ static int flexcan_chip_start(struct net_device *dev)
|
|||||||
|
|
||||||
/* mark TX mailbox as INACTIVE */
|
/* mark TX mailbox as INACTIVE */
|
||||||
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||||||
&priv->tx_mb->can_ctrl);
|
®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
||||||
|
|
||||||
/* acceptance mask/acceptance code (accept everything) */
|
/* acceptance mask/acceptance code (accept everything) */
|
||||||
priv->write(0x0, ®s->rxgmask);
|
priv->write(0x0, ®s->rxgmask);
|
||||||
@@ -1355,17 +1371,13 @@ static int flexcan_probe(struct platform_device *pdev)
|
|||||||
priv->devtype_data = devtype_data;
|
priv->devtype_data = devtype_data;
|
||||||
priv->reg_xceiver = reg_xceiver;
|
priv->reg_xceiver = reg_xceiver;
|
||||||
|
|
||||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
||||||
priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_TIMESTAMP;
|
|
||||||
priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP];
|
priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP];
|
||||||
} else {
|
else
|
||||||
priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_FIFO;
|
|
||||||
priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO];
|
priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO];
|
||||||
}
|
|
||||||
priv->tx_mb = ®s->mb[priv->tx_mb_idx];
|
|
||||||
|
|
||||||
priv->reg_imask1_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
priv->reg_imask1_default = 0;
|
||||||
priv->reg_imask2_default = 0;
|
priv->reg_imask2_default = FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB);
|
||||||
|
|
||||||
priv->offload.mailbox_read = flexcan_mailbox_read;
|
priv->offload.mailbox_read = flexcan_mailbox_read;
|
||||||
|
|
||||||
|
@@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
#define RCAR_CAN_DRV_NAME "rcar_can"
|
#define RCAR_CAN_DRV_NAME "rcar_can"
|
||||||
|
|
||||||
|
#define RCAR_SUPPORTED_CLOCKS (BIT(CLKR_CLKP1) | BIT(CLKR_CLKP2) | \
|
||||||
|
BIT(CLKR_CLKEXT))
|
||||||
|
|
||||||
/* Mailbox configuration:
|
/* Mailbox configuration:
|
||||||
* mailbox 60 - 63 - Rx FIFO mailboxes
|
* mailbox 60 - 63 - Rx FIFO mailboxes
|
||||||
* mailbox 56 - 59 - Tx FIFO mailboxes
|
* mailbox 56 - 59 - Tx FIFO mailboxes
|
||||||
@@ -789,7 +792,7 @@ static int rcar_can_probe(struct platform_device *pdev)
|
|||||||
goto fail_clk;
|
goto fail_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clock_select >= ARRAY_SIZE(clock_names)) {
|
if (!(BIT(clock_select) & RCAR_SUPPORTED_CLOCKS)) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
dev_err(&pdev->dev, "invalid CAN clock selected\n");
|
dev_err(&pdev->dev, "invalid CAN clock selected\n");
|
||||||
goto fail_clk;
|
goto fail_clk;
|
||||||
|
@@ -211,7 +211,54 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
|
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
|
||||||
|
|
||||||
int can_rx_offload_irq_queue_err_skb(struct can_rx_offload *offload, struct sk_buff *skb)
|
int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||||
|
struct sk_buff *skb, u32 timestamp)
|
||||||
|
{
|
||||||
|
struct can_rx_offload_cb *cb;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (skb_queue_len(&offload->skb_queue) >
|
||||||
|
offload->skb_queue_len_max)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cb = can_rx_offload_get_cb(skb);
|
||||||
|
cb->timestamp = timestamp;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
||||||
|
__skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
|
||||||
|
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
||||||
|
|
||||||
|
can_rx_offload_schedule(offload);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
|
||||||
|
|
||||||
|
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||||
|
unsigned int idx, u32 timestamp)
|
||||||
|
{
|
||||||
|
struct net_device *dev = offload->dev;
|
||||||
|
struct net_device_stats *stats = &dev->stats;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
u8 len;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
skb = __can_get_echo_skb(dev, idx, &len);
|
||||||
|
if (!skb)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = can_rx_offload_queue_sorted(offload, skb, timestamp);
|
||||||
|
if (err) {
|
||||||
|
stats->rx_errors++;
|
||||||
|
stats->tx_fifo_errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb);
|
||||||
|
|
||||||
|
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
||||||
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
if (skb_queue_len(&offload->skb_queue) >
|
if (skb_queue_len(&offload->skb_queue) >
|
||||||
offload->skb_queue_len_max)
|
offload->skb_queue_len_max)
|
||||||
@@ -222,7 +269,7 @@ int can_rx_offload_irq_queue_err_skb(struct can_rx_offload *offload, struct sk_b
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(can_rx_offload_irq_queue_err_skb);
|
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
|
||||||
|
|
||||||
static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
|
static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
|
||||||
{
|
{
|
||||||
|
@@ -760,7 +760,7 @@ static int hi3110_open(struct net_device *net)
|
|||||||
{
|
{
|
||||||
struct hi3110_priv *priv = netdev_priv(net);
|
struct hi3110_priv *priv = netdev_priv(net);
|
||||||
struct spi_device *spi = priv->spi;
|
struct spi_device *spi = priv->spi;
|
||||||
unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_RISING;
|
unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_HIGH;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = open_candev(net);
|
ret = open_candev(net);
|
||||||
|
@@ -528,7 +528,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
|
|||||||
context = &priv->tx_contexts[i];
|
context = &priv->tx_contexts[i];
|
||||||
|
|
||||||
context->echo_index = i;
|
context->echo_index = i;
|
||||||
can_put_echo_skb(skb, netdev, context->echo_index);
|
|
||||||
++priv->active_tx_contexts;
|
++priv->active_tx_contexts;
|
||||||
if (priv->active_tx_contexts >= (int)dev->max_tx_urbs)
|
if (priv->active_tx_contexts >= (int)dev->max_tx_urbs)
|
||||||
netif_stop_queue(netdev);
|
netif_stop_queue(netdev);
|
||||||
@@ -553,7 +552,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
|
|||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
|
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
|
||||||
|
|
||||||
can_free_echo_skb(netdev, context->echo_index);
|
|
||||||
context->echo_index = dev->max_tx_urbs;
|
context->echo_index = dev->max_tx_urbs;
|
||||||
--priv->active_tx_contexts;
|
--priv->active_tx_contexts;
|
||||||
netif_wake_queue(netdev);
|
netif_wake_queue(netdev);
|
||||||
@@ -564,6 +562,8 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
|
|||||||
|
|
||||||
context->priv = priv;
|
context->priv = priv;
|
||||||
|
|
||||||
|
can_put_echo_skb(skb, netdev, context->echo_index);
|
||||||
|
|
||||||
usb_fill_bulk_urb(urb, dev->udev,
|
usb_fill_bulk_urb(urb, dev->udev,
|
||||||
usb_sndbulkpipe(dev->udev,
|
usb_sndbulkpipe(dev->udev,
|
||||||
dev->bulk_out->bEndpointAddress),
|
dev->bulk_out->bEndpointAddress),
|
||||||
|
@@ -1019,6 +1019,11 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv,
|
|||||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||||
|
|
||||||
can_change_state(netdev, cf, tx_state, rx_state);
|
can_change_state(netdev, cf, tx_state, rx_state);
|
||||||
|
|
||||||
|
if (priv->can.restart_ms &&
|
||||||
|
old_state >= CAN_STATE_BUS_OFF &&
|
||||||
|
new_state < CAN_STATE_BUS_OFF)
|
||||||
|
cf->can_id |= CAN_ERR_RESTARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_state == CAN_STATE_BUS_OFF) {
|
if (new_state == CAN_STATE_BUS_OFF) {
|
||||||
@@ -1028,11 +1033,6 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv,
|
|||||||
|
|
||||||
can_bus_off(netdev);
|
can_bus_off(netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->can.restart_ms &&
|
|
||||||
old_state >= CAN_STATE_BUS_OFF &&
|
|
||||||
new_state < CAN_STATE_BUS_OFF)
|
|
||||||
cf->can_id |= CAN_ERR_RESTARTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
|
@@ -35,10 +35,6 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
|
|
||||||
#include <linux/can.h>
|
|
||||||
#include <linux/can/dev.h>
|
|
||||||
#include <linux/can/error.h>
|
|
||||||
|
|
||||||
#define UCAN_DRIVER_NAME "ucan"
|
#define UCAN_DRIVER_NAME "ucan"
|
||||||
#define UCAN_MAX_RX_URBS 8
|
#define UCAN_MAX_RX_URBS 8
|
||||||
/* the CAN controller needs a while to enable/disable the bus */
|
/* the CAN controller needs a while to enable/disable the bus */
|
||||||
@@ -1575,11 +1571,8 @@ err_firmware_needs_update:
|
|||||||
/* disconnect the device */
|
/* disconnect the device */
|
||||||
static void ucan_disconnect(struct usb_interface *intf)
|
static void ucan_disconnect(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct usb_device *udev;
|
|
||||||
struct ucan_priv *up = usb_get_intfdata(intf);
|
struct ucan_priv *up = usb_get_intfdata(intf);
|
||||||
|
|
||||||
udev = interface_to_usbdev(intf);
|
|
||||||
|
|
||||||
usb_set_intfdata(intf, NULL);
|
usb_set_intfdata(intf, NULL);
|
||||||
|
|
||||||
if (up) {
|
if (up) {
|
||||||
|
@@ -1848,6 +1848,8 @@ static void ena_down(struct ena_adapter *adapter)
|
|||||||
rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
|
rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
|
||||||
if (rc)
|
if (rc)
|
||||||
dev_err(&adapter->pdev->dev, "Device reset failed\n");
|
dev_err(&adapter->pdev->dev, "Device reset failed\n");
|
||||||
|
/* stop submitting admin commands on a device that was reset */
|
||||||
|
ena_com_set_admin_running_state(adapter->ena_dev, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ena_destroy_all_io_queues(adapter);
|
ena_destroy_all_io_queues(adapter);
|
||||||
@@ -1914,6 +1916,9 @@ static int ena_close(struct net_device *netdev)
|
|||||||
|
|
||||||
netif_dbg(adapter, ifdown, netdev, "%s\n", __func__);
|
netif_dbg(adapter, ifdown, netdev, "%s\n", __func__);
|
||||||
|
|
||||||
|
if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
|
if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
|
||||||
ena_down(adapter);
|
ena_down(adapter);
|
||||||
|
|
||||||
@@ -2613,9 +2618,7 @@ static void ena_destroy_device(struct ena_adapter *adapter, bool graceful)
|
|||||||
ena_down(adapter);
|
ena_down(adapter);
|
||||||
|
|
||||||
/* Stop the device from sending AENQ events (in case reset flag is set
|
/* Stop the device from sending AENQ events (in case reset flag is set
|
||||||
* and device is up, ena_close already reset the device
|
* and device is up, ena_down() already reset the device.
|
||||||
* In case the reset flag is set and the device is up, ena_down()
|
|
||||||
* already perform the reset, so it can be skipped.
|
|
||||||
*/
|
*/
|
||||||
if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up))
|
if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up))
|
||||||
ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
|
ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
|
||||||
@@ -2694,8 +2697,8 @@ err_device_destroy:
|
|||||||
ena_com_abort_admin_commands(ena_dev);
|
ena_com_abort_admin_commands(ena_dev);
|
||||||
ena_com_wait_for_abort_completion(ena_dev);
|
ena_com_wait_for_abort_completion(ena_dev);
|
||||||
ena_com_admin_destroy(ena_dev);
|
ena_com_admin_destroy(ena_dev);
|
||||||
ena_com_mmio_reg_read_request_destroy(ena_dev);
|
|
||||||
ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
|
ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
|
||||||
|
ena_com_mmio_reg_read_request_destroy(ena_dev);
|
||||||
err:
|
err:
|
||||||
clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
|
clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
|
||||||
clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
|
clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
|
||||||
@@ -3452,6 +3455,8 @@ err_rss:
|
|||||||
ena_com_rss_destroy(ena_dev);
|
ena_com_rss_destroy(ena_dev);
|
||||||
err_free_msix:
|
err_free_msix:
|
||||||
ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR);
|
ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR);
|
||||||
|
/* stop submitting admin commands on a device that was reset */
|
||||||
|
ena_com_set_admin_running_state(ena_dev, false);
|
||||||
ena_free_mgmnt_irq(adapter);
|
ena_free_mgmnt_irq(adapter);
|
||||||
ena_disable_msix(adapter);
|
ena_disable_msix(adapter);
|
||||||
err_worker_destroy:
|
err_worker_destroy:
|
||||||
@@ -3498,18 +3503,12 @@ static void ena_remove(struct pci_dev *pdev)
|
|||||||
|
|
||||||
cancel_work_sync(&adapter->reset_task);
|
cancel_work_sync(&adapter->reset_task);
|
||||||
|
|
||||||
unregister_netdev(netdev);
|
|
||||||
|
|
||||||
/* If the device is running then we want to make sure the device will be
|
|
||||||
* reset to make sure no more events will be issued by the device.
|
|
||||||
*/
|
|
||||||
if (test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
|
|
||||||
set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
|
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
ena_destroy_device(adapter, true);
|
ena_destroy_device(adapter, true);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
|
unregister_netdev(netdev);
|
||||||
|
|
||||||
free_netdev(netdev);
|
free_netdev(netdev);
|
||||||
|
|
||||||
ena_com_rss_destroy(ena_dev);
|
ena_com_rss_destroy(ena_dev);
|
||||||
|
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
#define DRV_MODULE_VER_MAJOR 2
|
#define DRV_MODULE_VER_MAJOR 2
|
||||||
#define DRV_MODULE_VER_MINOR 0
|
#define DRV_MODULE_VER_MINOR 0
|
||||||
#define DRV_MODULE_VER_SUBMINOR 1
|
#define DRV_MODULE_VER_SUBMINOR 2
|
||||||
|
|
||||||
#define DRV_MODULE_NAME "ena"
|
#define DRV_MODULE_NAME "ena"
|
||||||
#ifndef DRV_MODULE_VERSION
|
#ifndef DRV_MODULE_VERSION
|
||||||
|
@@ -1419,7 +1419,7 @@ static int sparc_lance_probe_one(struct platform_device *op,
|
|||||||
|
|
||||||
prop = of_get_property(nd, "tpe-link-test?", NULL);
|
prop = of_get_property(nd, "tpe-link-test?", NULL);
|
||||||
if (!prop)
|
if (!prop)
|
||||||
goto no_link_test;
|
goto node_put;
|
||||||
|
|
||||||
if (strcmp(prop, "true")) {
|
if (strcmp(prop, "true")) {
|
||||||
printk(KERN_NOTICE "SunLance: warning: overriding option "
|
printk(KERN_NOTICE "SunLance: warning: overriding option "
|
||||||
@@ -1428,6 +1428,8 @@ static int sparc_lance_probe_one(struct platform_device *op,
|
|||||||
"to ecd@skynet.be\n");
|
"to ecd@skynet.be\n");
|
||||||
auxio_set_lte(AUXIO_LTE_ON);
|
auxio_set_lte(AUXIO_LTE_ON);
|
||||||
}
|
}
|
||||||
|
node_put:
|
||||||
|
of_node_put(nd);
|
||||||
no_link_test:
|
no_link_test:
|
||||||
lp->auto_select = 1;
|
lp->auto_select = 1;
|
||||||
lp->tpe = 0;
|
lp->tpe = 0;
|
||||||
|
@@ -2191,6 +2191,13 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
|
|||||||
#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
|
#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
|
||||||
E1HVN_MAX)
|
E1HVN_MAX)
|
||||||
|
|
||||||
|
/* Following is the DMAE channel number allocation for the clients.
|
||||||
|
* MFW: OCBB/OCSD implementations use DMAE channels 14/15 respectively.
|
||||||
|
* Driver: 0-3 and 8-11 (for PF dmae operations)
|
||||||
|
* 4 and 12 (for stats requests)
|
||||||
|
*/
|
||||||
|
#define BNX2X_FW_DMAE_C 13 /* Channel for FW DMAE operations */
|
||||||
|
|
||||||
/* PCIE link and speed */
|
/* PCIE link and speed */
|
||||||
#define PCICFG_LINK_WIDTH 0x1f00000
|
#define PCICFG_LINK_WIDTH 0x1f00000
|
||||||
#define PCICFG_LINK_WIDTH_SHIFT 20
|
#define PCICFG_LINK_WIDTH_SHIFT 20
|
||||||
|
@@ -6149,6 +6149,7 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
|
|||||||
rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
|
rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
|
||||||
rdata->path_id = BP_PATH(bp);
|
rdata->path_id = BP_PATH(bp);
|
||||||
rdata->network_cos_mode = start_params->network_cos_mode;
|
rdata->network_cos_mode = start_params->network_cos_mode;
|
||||||
|
rdata->dmae_cmd_id = BNX2X_FW_DMAE_C;
|
||||||
|
|
||||||
rdata->vxlan_dst_port = cpu_to_le16(start_params->vxlan_dst_port);
|
rdata->vxlan_dst_port = cpu_to_le16(start_params->vxlan_dst_port);
|
||||||
rdata->geneve_dst_port = cpu_to_le16(start_params->geneve_dst_port);
|
rdata->geneve_dst_port = cpu_to_le16(start_params->geneve_dst_port);
|
||||||
|
@@ -1675,7 +1675,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
|||||||
} else {
|
} else {
|
||||||
if (rxcmp1->rx_cmp_cfa_code_errors_v2 & RX_CMP_L4_CS_ERR_BITS) {
|
if (rxcmp1->rx_cmp_cfa_code_errors_v2 & RX_CMP_L4_CS_ERR_BITS) {
|
||||||
if (dev->features & NETIF_F_RXCSUM)
|
if (dev->features & NETIF_F_RXCSUM)
|
||||||
cpr->rx_l4_csum_errors++;
|
bnapi->cp_ring.rx_l4_csum_errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8714,6 +8714,26 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bnxt_dbg_hwrm_ring_info_get(struct bnxt *bp, u8 ring_type,
|
||||||
|
u32 ring_id, u32 *prod, u32 *cons)
|
||||||
|
{
|
||||||
|
struct hwrm_dbg_ring_info_get_output *resp = bp->hwrm_cmd_resp_addr;
|
||||||
|
struct hwrm_dbg_ring_info_get_input req = {0};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_RING_INFO_GET, -1, -1);
|
||||||
|
req.ring_type = ring_type;
|
||||||
|
req.fw_ring_id = cpu_to_le32(ring_id);
|
||||||
|
mutex_lock(&bp->hwrm_cmd_lock);
|
||||||
|
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
|
||||||
|
if (!rc) {
|
||||||
|
*prod = le32_to_cpu(resp->producer_index);
|
||||||
|
*cons = le32_to_cpu(resp->consumer_index);
|
||||||
|
}
|
||||||
|
mutex_unlock(&bp->hwrm_cmd_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static void bnxt_dump_tx_sw_state(struct bnxt_napi *bnapi)
|
static void bnxt_dump_tx_sw_state(struct bnxt_napi *bnapi)
|
||||||
{
|
{
|
||||||
struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
|
struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
|
||||||
@@ -8821,6 +8841,11 @@ static void bnxt_timer(struct timer_list *t)
|
|||||||
bnxt_queue_sp_work(bp);
|
bnxt_queue_sp_work(bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((bp->flags & BNXT_FLAG_CHIP_P5) && netif_carrier_ok(dev)) {
|
||||||
|
set_bit(BNXT_RING_COAL_NOW_SP_EVENT, &bp->sp_event);
|
||||||
|
bnxt_queue_sp_work(bp);
|
||||||
|
}
|
||||||
bnxt_restart_timer:
|
bnxt_restart_timer:
|
||||||
mod_timer(&bp->timer, jiffies + bp->current_interval);
|
mod_timer(&bp->timer, jiffies + bp->current_interval);
|
||||||
}
|
}
|
||||||
@@ -8851,6 +8876,44 @@ static void bnxt_reset(struct bnxt *bp, bool silent)
|
|||||||
bnxt_rtnl_unlock_sp(bp);
|
bnxt_rtnl_unlock_sp(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bnxt_chk_missed_irq(struct bnxt *bp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!(bp->flags & BNXT_FLAG_CHIP_P5))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < bp->cp_nr_rings; i++) {
|
||||||
|
struct bnxt_napi *bnapi = bp->bnapi[i];
|
||||||
|
struct bnxt_cp_ring_info *cpr;
|
||||||
|
u32 fw_ring_id;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (!bnapi)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cpr = &bnapi->cp_ring;
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
|
||||||
|
u32 val[2];
|
||||||
|
|
||||||
|
if (!cpr2 || cpr2->has_more_work ||
|
||||||
|
!bnxt_has_work(bp, cpr2))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cpr2->cp_raw_cons != cpr2->last_cp_raw_cons) {
|
||||||
|
cpr2->last_cp_raw_cons = cpr2->cp_raw_cons;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fw_ring_id = cpr2->cp_ring_struct.fw_ring_id;
|
||||||
|
bnxt_dbg_hwrm_ring_info_get(bp,
|
||||||
|
DBG_RING_INFO_GET_REQ_RING_TYPE_L2_CMPL,
|
||||||
|
fw_ring_id, &val[0], &val[1]);
|
||||||
|
cpr->missed_irqs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void bnxt_cfg_ntp_filters(struct bnxt *);
|
static void bnxt_cfg_ntp_filters(struct bnxt *);
|
||||||
|
|
||||||
static void bnxt_sp_task(struct work_struct *work)
|
static void bnxt_sp_task(struct work_struct *work)
|
||||||
@@ -8930,6 +8993,9 @@ static void bnxt_sp_task(struct work_struct *work)
|
|||||||
if (test_and_clear_bit(BNXT_FLOW_STATS_SP_EVENT, &bp->sp_event))
|
if (test_and_clear_bit(BNXT_FLOW_STATS_SP_EVENT, &bp->sp_event))
|
||||||
bnxt_tc_flow_stats_work(bp);
|
bnxt_tc_flow_stats_work(bp);
|
||||||
|
|
||||||
|
if (test_and_clear_bit(BNXT_RING_COAL_NOW_SP_EVENT, &bp->sp_event))
|
||||||
|
bnxt_chk_missed_irq(bp);
|
||||||
|
|
||||||
/* These functions below will clear BNXT_STATE_IN_SP_TASK. They
|
/* These functions below will clear BNXT_STATE_IN_SP_TASK. They
|
||||||
* must be the last functions to be called before exiting.
|
* must be the last functions to be called before exiting.
|
||||||
*/
|
*/
|
||||||
@@ -10087,6 +10153,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bnxt_hwrm_func_qcfg(bp);
|
bnxt_hwrm_func_qcfg(bp);
|
||||||
|
bnxt_hwrm_vnic_qcaps(bp);
|
||||||
bnxt_hwrm_port_led_qcaps(bp);
|
bnxt_hwrm_port_led_qcaps(bp);
|
||||||
bnxt_ethtool_init(bp);
|
bnxt_ethtool_init(bp);
|
||||||
bnxt_dcb_init(bp);
|
bnxt_dcb_init(bp);
|
||||||
@@ -10120,7 +10187,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
|
VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
|
||||||
}
|
}
|
||||||
|
|
||||||
bnxt_hwrm_vnic_qcaps(bp);
|
|
||||||
if (bnxt_rfs_supported(bp)) {
|
if (bnxt_rfs_supported(bp)) {
|
||||||
dev->hw_features |= NETIF_F_NTUPLE;
|
dev->hw_features |= NETIF_F_NTUPLE;
|
||||||
if (bnxt_rfs_capable(bp)) {
|
if (bnxt_rfs_capable(bp)) {
|
||||||
|
@@ -798,6 +798,8 @@ struct bnxt_cp_ring_info {
|
|||||||
u8 had_work_done:1;
|
u8 had_work_done:1;
|
||||||
u8 has_more_work:1;
|
u8 has_more_work:1;
|
||||||
|
|
||||||
|
u32 last_cp_raw_cons;
|
||||||
|
|
||||||
struct bnxt_coal rx_ring_coal;
|
struct bnxt_coal rx_ring_coal;
|
||||||
u64 rx_packets;
|
u64 rx_packets;
|
||||||
u64 rx_bytes;
|
u64 rx_bytes;
|
||||||
@@ -816,6 +818,7 @@ struct bnxt_cp_ring_info {
|
|||||||
dma_addr_t hw_stats_map;
|
dma_addr_t hw_stats_map;
|
||||||
u32 hw_stats_ctx_id;
|
u32 hw_stats_ctx_id;
|
||||||
u64 rx_l4_csum_errors;
|
u64 rx_l4_csum_errors;
|
||||||
|
u64 missed_irqs;
|
||||||
|
|
||||||
struct bnxt_ring_struct cp_ring_struct;
|
struct bnxt_ring_struct cp_ring_struct;
|
||||||
|
|
||||||
@@ -1527,6 +1530,7 @@ struct bnxt {
|
|||||||
#define BNXT_LINK_SPEED_CHNG_SP_EVENT 14
|
#define BNXT_LINK_SPEED_CHNG_SP_EVENT 14
|
||||||
#define BNXT_FLOW_STATS_SP_EVENT 15
|
#define BNXT_FLOW_STATS_SP_EVENT 15
|
||||||
#define BNXT_UPDATE_PHY_SP_EVENT 16
|
#define BNXT_UPDATE_PHY_SP_EVENT 16
|
||||||
|
#define BNXT_RING_COAL_NOW_SP_EVENT 17
|
||||||
|
|
||||||
struct bnxt_hw_resc hw_resc;
|
struct bnxt_hw_resc hw_resc;
|
||||||
struct bnxt_pf_info pf;
|
struct bnxt_pf_info pf;
|
||||||
|
@@ -137,7 +137,7 @@ reset_coalesce:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BNXT_NUM_STATS 21
|
#define BNXT_NUM_STATS 22
|
||||||
|
|
||||||
#define BNXT_RX_STATS_ENTRY(counter) \
|
#define BNXT_RX_STATS_ENTRY(counter) \
|
||||||
{ BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }
|
{ BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }
|
||||||
@@ -384,6 +384,7 @@ static void bnxt_get_ethtool_stats(struct net_device *dev,
|
|||||||
for (k = 0; k < stat_fields; j++, k++)
|
for (k = 0; k < stat_fields; j++, k++)
|
||||||
buf[j] = le64_to_cpu(hw_stats[k]);
|
buf[j] = le64_to_cpu(hw_stats[k]);
|
||||||
buf[j++] = cpr->rx_l4_csum_errors;
|
buf[j++] = cpr->rx_l4_csum_errors;
|
||||||
|
buf[j++] = cpr->missed_irqs;
|
||||||
|
|
||||||
bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter +=
|
bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter +=
|
||||||
le64_to_cpu(cpr->hw_stats->rx_discard_pkts);
|
le64_to_cpu(cpr->hw_stats->rx_discard_pkts);
|
||||||
@@ -468,6 +469,8 @@ static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
|
|||||||
buf += ETH_GSTRING_LEN;
|
buf += ETH_GSTRING_LEN;
|
||||||
sprintf(buf, "[%d]: rx_l4_csum_errors", i);
|
sprintf(buf, "[%d]: rx_l4_csum_errors", i);
|
||||||
buf += ETH_GSTRING_LEN;
|
buf += ETH_GSTRING_LEN;
|
||||||
|
sprintf(buf, "[%d]: missed_irqs", i);
|
||||||
|
buf += ETH_GSTRING_LEN;
|
||||||
}
|
}
|
||||||
for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) {
|
for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) {
|
||||||
strcpy(buf, bnxt_sw_func_stats[i].string);
|
strcpy(buf, bnxt_sw_func_stats[i].string);
|
||||||
@@ -2942,8 +2945,8 @@ bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record,
|
|||||||
record->asic_state = 0;
|
record->asic_state = 0;
|
||||||
strlcpy(record->system_name, utsname()->nodename,
|
strlcpy(record->system_name, utsname()->nodename,
|
||||||
sizeof(record->system_name));
|
sizeof(record->system_name));
|
||||||
record->year = cpu_to_le16(tm.tm_year);
|
record->year = cpu_to_le16(tm.tm_year + 1900);
|
||||||
record->month = cpu_to_le16(tm.tm_mon);
|
record->month = cpu_to_le16(tm.tm_mon + 1);
|
||||||
record->day = cpu_to_le16(tm.tm_mday);
|
record->day = cpu_to_le16(tm.tm_mday);
|
||||||
record->hour = cpu_to_le16(tm.tm_hour);
|
record->hour = cpu_to_le16(tm.tm_hour);
|
||||||
record->minute = cpu_to_le16(tm.tm_min);
|
record->minute = cpu_to_le16(tm.tm_min);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user