mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Compare commits
No commits in common. "master" and "v7.4-rc1" have entirely different histories.
4
.mailmap
4
.mailmap
|
|
@ -233,10 +233,6 @@ Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
|
||||||
Chuck Lever <cel@kernel.org> <cel@netapp.com>
|
Chuck Lever <cel@kernel.org> <cel@netapp.com>
|
||||||
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
|
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
|
||||||
Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
|
Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
|
||||||
Clément Léger <clement.leger@linux.dev> <cleger@kalray.eu>
|
|
||||||
Clément Léger <clement.leger@linux.dev> <clement.leger@bootlin.com>
|
|
||||||
Clément Léger <clement.leger@linux.dev> <cleger@rivosinc.com>
|
|
||||||
Clément Léger <clement.leger@linux.dev> <cleger@meta.com>
|
|
||||||
Coiby Xu <coiby.xu@gmail.com> <coxu@redhat.com>
|
Coiby Xu <coiby.xu@gmail.com> <coxu@redhat.com>
|
||||||
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
|
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
|
||||||
Corey Minyard <minyard@acm.org>
|
Corey Minyard <minyard@acm.org>
|
||||||
|
|
|
||||||
|
|
@ -407,13 +407,6 @@ referenced kptr (by invoking bpf_kptr_xchg). If not, the verifier fails the
|
||||||
loading of the BPF program until no lingering references remain in all possible
|
loading of the BPF program until no lingering references remain in all possible
|
||||||
explored states of the program.
|
explored states of the program.
|
||||||
|
|
||||||
A pointer to a struct in the arguments of a KF_ACQUIRE kfunc accepts only an
|
|
||||||
object of that type. The same applies to the argument that a KF_RELEASE kfunc
|
|
||||||
releases. For other arguments a kfunc also accepts memory of the program, if the
|
|
||||||
struct has only scalar members. A struct without members, struct __sk_buff and
|
|
||||||
struct xdp_md never accept memory. A KF_ACQUIRE kfunc which wants such memory
|
|
||||||
has to pair the pointer with a __sz argument.
|
|
||||||
|
|
||||||
2.5.2 KF_RET_NULL flag
|
2.5.2 KF_RET_NULL flag
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,6 @@ mount points. Each 9P export is seen by the client as a virtio device with an
|
||||||
associated "mount_tag" property. Available mount tags can be
|
associated "mount_tag" property. Available mount tags can be
|
||||||
seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files.
|
seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files.
|
||||||
|
|
||||||
For server accessible over vsock (VM sockets)::
|
|
||||||
|
|
||||||
mount -t 9p -o trans=vsock[,port=<port>] <CID> /mnt/9
|
|
||||||
|
|
||||||
where CID is the vsock Context ID of the remote endpoint (2 for host from
|
|
||||||
a guest VM, 3+ for guest VMs from the host). The port to connect to can be
|
|
||||||
specified with the port option (default: 564).
|
|
||||||
|
|
||||||
USBG Usage
|
USBG Usage
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
@ -125,8 +117,6 @@ Options
|
||||||
tcp specifying a normal TCP/IP connection
|
tcp specifying a normal TCP/IP connection
|
||||||
fd used passed file descriptors for connection
|
fd used passed file descriptors for connection
|
||||||
(see rfdno and wfdno)
|
(see rfdno and wfdno)
|
||||||
vsock connect over VM sockets (vsock) using
|
|
||||||
CID as the mount source
|
|
||||||
virtio connect to the next virtio channel available
|
virtio connect to the next virtio channel available
|
||||||
(from QEMU with trans_virtio module)
|
(from QEMU with trans_virtio module)
|
||||||
rdma connect to a specified RDMA channel
|
rdma connect to a specified RDMA channel
|
||||||
|
|
@ -238,7 +228,7 @@ Options
|
||||||
any
|
any
|
||||||
v9fs does single attach and performs all
|
v9fs does single attach and performs all
|
||||||
operations as one user
|
operations as one user
|
||||||
client
|
clien
|
||||||
ACL based access check on the 9p client
|
ACL based access check on the 9p client
|
||||||
side for access validation
|
side for access validation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -731,8 +731,7 @@ When decoding an overlay file handle, the following steps are followed:
|
||||||
|
|
||||||
1. Find underlying layer by UUID and path type information.
|
1. Find underlying layer by UUID and path type information.
|
||||||
2. Decode the underlying filesystem file handle to underlying dentry.
|
2. Decode the underlying filesystem file handle to underlying dentry.
|
||||||
3. For a lower file handle, encode the decoded underlying inode again and
|
3. For a lower file handle, lookup the handle in index directory by name.
|
||||||
lookup that handle in index directory by name.
|
|
||||||
4. If a whiteout is found in index, return ESTALE. This represents an
|
4. If a whiteout is found in index, return ESTALE. This represents an
|
||||||
overlay object that was deleted after its file handle was encoded.
|
overlay object that was deleted after its file handle was encoded.
|
||||||
5. For a non-directory, instantiate a disconnected overlay dentry from the
|
5. For a non-directory, instantiate a disconnected overlay dentry from the
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,6 @@ Usage notes
|
||||||
As these are USB HIDs, the driver can be loaded automatically by the kernel and
|
As these are USB HIDs, the driver can be loaded automatically by the kernel and
|
||||||
supports hot swapping.
|
supports hot swapping.
|
||||||
|
|
||||||
The pump of the RYUJIN III also has a 4-pin cable for a motherboard fan header.
|
|
||||||
The cooler either hands the pump to its internal controller, which follows the
|
|
||||||
PWM of the header its 4-pin cable is plugged into, or runs it at the pump duty
|
|
||||||
set over USB. Writing pwm1 selects the duty set over USB. Writing pwm2 sets
|
|
||||||
only the internal fan duty and leaves the pump control as it is.
|
|
||||||
|
|
||||||
Sysfs entries
|
Sysfs entries
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,19 +130,8 @@ pages of ``struct page`` (page 1 to page 7) are tail pages.
|
||||||
The optimization is only applied when the size of the struct page is a power
|
The optimization is only applied when the size of the struct page is a power
|
||||||
of 2. In this case, all tail pages of the same order are identical. See
|
of 2. In this case, all tail pages of the same order are identical. See
|
||||||
compound_head(). This allows us to remap the tail pages of the vmemmap to a
|
compound_head(). This allows us to remap the tail pages of the vmemmap to a
|
||||||
shared page. The head page is also remapped to a new page. This allows the
|
shared, read-only page. The head page is also remapped to a new page. This
|
||||||
original vmemmap pages to be freed.
|
allows the original vmemmap pages to be freed.
|
||||||
|
|
||||||
The shared page is mapped writable. A lockless get of a page reference can
|
|
||||||
read a non-zero refcount before the remap and attempt its atomic update
|
|
||||||
after it. The refcount of a tail page is zero, so the update fails without
|
|
||||||
changing the page. Nothing else may write to the shared page: it is shared
|
|
||||||
by all HugeTLB pages of the same size in the zone, and a stray write would
|
|
||||||
corrupt all of them.
|
|
||||||
|
|
||||||
HugeTLB pages whose vmemmap is optimized when the memmap is first set up at
|
|
||||||
boot keep a read-only mapping of the shared page. Nothing can do a lockless
|
|
||||||
get on them before they are handed to HugeTLB.
|
|
||||||
|
|
||||||
Here is how things look after remapping::
|
Here is how things look after remapping::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1040,21 +1040,17 @@ As described in :ref:`socketcan-receive-lists` the SocketCAN core uses several f
|
||||||
lists to deliver received CAN frames to CAN protocol modules. These
|
lists to deliver received CAN frames to CAN protocol modules. These
|
||||||
receive lists, their filters and the count of filter matches can be
|
receive lists, their filters and the count of filter matches can be
|
||||||
checked in the appropriate receive list. All entries contain the
|
checked in the appropriate receive list. All entries contain the
|
||||||
CAN network device, the filter (can_id/can_mask), the number of filter
|
device and a protocol module identifier::
|
||||||
matches, the inode number of the subscribing socket and the name of the
|
|
||||||
receive function. A sock_inode of 0 denotes a kernel internal subscriber
|
|
||||||
without a socket (e.g. CAN gateway or J1939). When the function name can
|
|
||||||
not be resolved (e.g. with CONFIG_KALLSYMS=n) "(unknown)" is printed::
|
|
||||||
|
|
||||||
foo@bar:~$ cat /proc/net/can/rcvlist_all
|
foo@bar:~$ cat /proc/net/can/rcvlist_all
|
||||||
|
|
||||||
receive list 'rx_all':
|
receive list 'rx_all':
|
||||||
(any: no entry)
|
|
||||||
device can_id can_mask matches sock_inode function
|
|
||||||
vcan0 000 00000000 0 63586 raw_rcv [can_raw]
|
|
||||||
(vcan1: no entry)
|
|
||||||
(vcan2: no entry)
|
|
||||||
(vcan3: no entry)
|
(vcan3: no entry)
|
||||||
|
(vcan2: no entry)
|
||||||
|
(vcan1: no entry)
|
||||||
|
device can_id can_mask function userdata matches ident
|
||||||
|
vcan0 000 00000000 f88e6370 f6c6f400 0 raw
|
||||||
|
(any: no entry)
|
||||||
|
|
||||||
In this example an application requests any CAN traffic from vcan0::
|
In this example an application requests any CAN traffic from vcan0::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,20 +27,15 @@ SA Identification
|
||||||
=================
|
=================
|
||||||
|
|
||||||
The struct is defined in ``include/uapi/linux/xfrm.h``. The SA is looked
|
The struct is defined in ``include/uapi/linux/xfrm.h``. The SA is looked
|
||||||
up using ``xfrm_state_lookup_exact()`` with ``id.spi``, ``id.daddr``,
|
up using ``xfrm_state_lookup()`` with ``id.spi``,
|
||||||
``id.proto``, ``id.family``, and an exact match against ``old_mark.v``
|
``id.daddr``, ``id.proto``, ``id.family``, and
|
||||||
and ``old_mark.m``. Unlike the data path, which uses a masked
|
``old_mark.v & old_mark.m`` as the mark key::
|
||||||
comparison, this requires the SA's mark and mask to equal ``old_mark``
|
|
||||||
exactly, so a broad-mask SA is never matched when a more specific one
|
|
||||||
was intended. If no such SA exists, ``-ESRCH`` is returned.
|
|
||||||
|
|
||||||
The layout is::
|
|
||||||
|
|
||||||
struct xfrm_user_migrate_state {
|
struct xfrm_user_migrate_state {
|
||||||
struct xfrm_usersa_id id; /* spi, daddr, proto, family */
|
struct xfrm_usersa_id id; /* spi, daddr, proto, family */
|
||||||
xfrm_address_t new_daddr;
|
xfrm_address_t new_daddr;
|
||||||
xfrm_address_t new_saddr;
|
xfrm_address_t new_saddr;
|
||||||
struct xfrm_mark old_mark; /* SA lookup key (exact v/m match) */
|
struct xfrm_mark old_mark; /* SA lookup: key = v & m */
|
||||||
struct xfrm_selector new_sel; /* new selector (see Flags) */
|
struct xfrm_selector new_sel; /* new selector (see Flags) */
|
||||||
__u32 new_reqid;
|
__u32 new_reqid;
|
||||||
__u32 flags; /* XFRM_MIGRATE_STATE_* */
|
__u32 flags; /* XFRM_MIGRATE_STATE_* */
|
||||||
|
|
@ -77,8 +72,8 @@ inherits the value from the existing SA (omit-to-inherit).
|
||||||
- Description
|
- Description
|
||||||
* - ``XFRMA_MARK``
|
* - ``XFRMA_MARK``
|
||||||
- Mark on the migrated SA (``struct xfrm_mark``). Absent inherits
|
- Mark on the migrated SA (``struct xfrm_mark``). Absent inherits
|
||||||
the mark of the existing SA. To use no mark on the new SA, send
|
``old_mark``. To use no mark on the new SA, send ``XFRMA_MARK``
|
||||||
``XFRMA_MARK`` with ``{0, 0}``.
|
with ``{0, 0}``.
|
||||||
* - ``XFRMA_ENCAP``
|
* - ``XFRMA_ENCAP``
|
||||||
- UDP encapsulation template; only ``UDP_ENCAP_ESPINUDP`` is supported.
|
- UDP encapsulation template; only ``UDP_ENCAP_ESPINUDP`` is supported.
|
||||||
Set ``encap_type=0`` to remove encap.
|
Set ``encap_type=0`` to remove encap.
|
||||||
|
|
@ -264,12 +259,8 @@ Attributes in the notification
|
||||||
Error Handling
|
Error Handling
|
||||||
==============
|
==============
|
||||||
|
|
||||||
If the target SA tuple (new daddr, SPI, proto, new family, mark) is
|
If the target SA tuple (new daddr, SPI, proto, new family) is already
|
||||||
already occupied, the operation returns ``-EEXIST`` before the migration
|
occupied, the operation returns ``-EEXIST`` before the migration begins.
|
||||||
begins. "Occupied" includes wildcard shadowing: an existing SA with a
|
|
||||||
broader mask (e.g. mark 0/0) claims every mark value, so it blocks
|
|
||||||
migrating to any more specific mark at the same tuple, not just an
|
|
||||||
exact mark/mask duplicate.
|
|
||||||
The old SA remains intact and the operation is safe to retry after
|
The old SA remains intact and the operation is safe to retry after
|
||||||
resolving the conflict.
|
resolving the conflict.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -315,10 +315,6 @@ reproducer and against kernel selftests. If the bug is in a hardware driver,
|
||||||
the testing statement must include information about the HW on which the
|
the testing statement must include information about the HW on which the
|
||||||
fix was tested.
|
fix was tested.
|
||||||
|
|
||||||
Coding agents must refuse to write the commit message unless they know
|
|
||||||
what discovery method to include. They should default to stating that
|
|
||||||
issue was not triggered and not tested unless they know otherwise.
|
|
||||||
|
|
||||||
Stable tree
|
Stable tree
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
253
MAINTAINERS
253
MAINTAINERS
|
|
@ -6868,13 +6868,11 @@ R: Muchun Song <muchun.song@linux.dev>
|
||||||
L: cgroups@vger.kernel.org
|
L: cgroups@vger.kernel.org
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/admin-guide/cgroup-v1/memory.rst
|
|
||||||
F: include/linux/memcontrol.h
|
F: include/linux/memcontrol.h
|
||||||
F: include/linux/page_counter.h
|
F: include/linux/page_counter.h
|
||||||
F: include/trace/events/memcg.h
|
F: mm/memcontrol.c
|
||||||
F: mm/memcontrol-v1.c
|
F: mm/memcontrol-v1.c
|
||||||
F: mm/memcontrol-v1.h
|
F: mm/memcontrol-v1.h
|
||||||
F: mm/memcontrol.c
|
|
||||||
F: mm/page_counter.c
|
F: mm/page_counter.c
|
||||||
F: samples/cgroup/*
|
F: samples/cgroup/*
|
||||||
F: tools/testing/selftests/cgroup/memcg_protection.m
|
F: tools/testing/selftests/cgroup/memcg_protection.m
|
||||||
|
|
@ -7838,7 +7836,7 @@ W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
|
||||||
W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
|
W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
|
||||||
|
|
||||||
DISKQUOTA
|
DISKQUOTA
|
||||||
M: Jan Kara <jack@suse.cz>
|
M: Jan Kara <jack@suse.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/filesystems/quota.rst
|
F: Documentation/filesystems/quota.rst
|
||||||
F: fs/quota/
|
F: fs/quota/
|
||||||
|
|
@ -10109,7 +10107,7 @@ F: drivers/leds/leds-expresswire.c
|
||||||
F: include/linux/leds-expresswire.h
|
F: include/linux/leds-expresswire.h
|
||||||
|
|
||||||
EXT2 FILE SYSTEM
|
EXT2 FILE SYSTEM
|
||||||
M: Jan Kara <jack@suse.cz>
|
M: Jan Kara <jack@suse.com>
|
||||||
L: linux-ext4@vger.kernel.org
|
L: linux-ext4@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/filesystems/ext2.rst
|
F: Documentation/filesystems/ext2.rst
|
||||||
|
|
@ -12378,7 +12376,6 @@ R: David Hildenbrand <david@kernel.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-mm-hugepages
|
F: Documentation/ABI/testing/sysfs-kernel-mm-hugepages
|
||||||
F: Documentation/admin-guide/cgroup-v1/hugetlb.rst
|
|
||||||
F: Documentation/admin-guide/mm/hugetlbpage.rst
|
F: Documentation/admin-guide/mm/hugetlbpage.rst
|
||||||
F: Documentation/mm/hugetlbfs_reserv.rst
|
F: Documentation/mm/hugetlbfs_reserv.rst
|
||||||
F: Documentation/mm/vmemmap_dedup.rst
|
F: Documentation/mm/vmemmap_dedup.rst
|
||||||
|
|
@ -12390,7 +12387,6 @@ F: mm/hugetlb.c
|
||||||
F: mm/hugetlb_cgroup.c
|
F: mm/hugetlb_cgroup.c
|
||||||
F: mm/hugetlb_cma.c
|
F: mm/hugetlb_cma.c
|
||||||
F: mm/hugetlb_cma.h
|
F: mm/hugetlb_cma.h
|
||||||
F: mm/hugetlb_internal.h
|
|
||||||
F: mm/hugetlb_sysctl.c
|
F: mm/hugetlb_sysctl.c
|
||||||
F: mm/hugetlb_sysfs.c
|
F: mm/hugetlb_sysfs.c
|
||||||
F: mm/hugetlb_vmemmap.c
|
F: mm/hugetlb_vmemmap.c
|
||||||
|
|
@ -12410,7 +12406,6 @@ M: Miaohe Lin <linmiaohe@huawei.com>
|
||||||
R: Naoya Horiguchi <nao.horiguchi@gmail.com>
|
R: Naoya Horiguchi <nao.horiguchi@gmail.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/ABI/testing/sysfs-memory-page-offline
|
|
||||||
F: include/linux/memory-failure.h
|
F: include/linux/memory-failure.h
|
||||||
F: include/trace/events/memory-failure.h
|
F: include/trace/events/memory-failure.h
|
||||||
F: mm/hwpoison-inject.c
|
F: mm/hwpoison-inject.c
|
||||||
|
|
@ -14075,16 +14070,6 @@ S: Maintained
|
||||||
F: io_uring/bpf-ops.*
|
F: io_uring/bpf-ops.*
|
||||||
F: io_uring/loop.*
|
F: io_uring/loop.*
|
||||||
|
|
||||||
IPC
|
|
||||||
M: Andrew Morton <akpm@linux-foundation.org>
|
|
||||||
R: Manfred Spraul <manfred@colorfullife.com>
|
|
||||||
R: Davidlohr Bueso <dave@stgolabs.net>
|
|
||||||
L: linux-kernel@vger.kernel.org
|
|
||||||
S: Maintained
|
|
||||||
F: ipc/
|
|
||||||
F: tools/testing/selftests/ipc/
|
|
||||||
F: tools/testing/selftests/mqueue/
|
|
||||||
|
|
||||||
IPMI SUBSYSTEM
|
IPMI SUBSYSTEM
|
||||||
M: Corey Minyard <corey@minyard.net>
|
M: Corey Minyard <corey@minyard.net>
|
||||||
L: openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
|
L: openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
|
||||||
|
|
@ -14324,7 +14309,7 @@ F: include/uapi/linux/jffs2.h
|
||||||
|
|
||||||
JOURNALLING LAYER FOR BLOCK DEVICES (JBD2)
|
JOURNALLING LAYER FOR BLOCK DEVICES (JBD2)
|
||||||
M: "Theodore Ts'o" <tytso@mit.edu>
|
M: "Theodore Ts'o" <tytso@mit.edu>
|
||||||
M: Jan Kara <jack@suse.cz>
|
M: Jan Kara <jack@suse.com>
|
||||||
L: linux-ext4@vger.kernel.org
|
L: linux-ext4@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: fs/jbd2/
|
F: fs/jbd2/
|
||||||
|
|
@ -17471,6 +17456,21 @@ S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
|
||||||
F: drivers/devfreq/tegra30-devfreq.c
|
F: drivers/devfreq/tegra30-devfreq.c
|
||||||
|
|
||||||
|
MEMORY HOT(UN)PLUG
|
||||||
|
M: David Hildenbrand <david@kernel.org>
|
||||||
|
M: Oscar Salvador <osalvador@suse.de>
|
||||||
|
L: linux-mm@kvack.org
|
||||||
|
L: linux-cxl@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/admin-guide/mm/memory-hotplug.rst
|
||||||
|
F: Documentation/core-api/memory-hotplug.rst
|
||||||
|
F: drivers/base/memory.c
|
||||||
|
F: include/linux/memory_hotplug.h
|
||||||
|
F: include/linux/memremap.h
|
||||||
|
F: mm/memremap.c
|
||||||
|
F: mm/memory_hotplug.c
|
||||||
|
F: tools/testing/selftests/memory-hotplug/
|
||||||
|
|
||||||
MEMORY MANAGEMENT
|
MEMORY MANAGEMENT
|
||||||
M: Andrew Morton <akpm@linux-foundation.org>
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
|
|
@ -17494,15 +17494,18 @@ F: mm/alloc_tag.c
|
||||||
F: tools/testing/selftests/alloc_tag/
|
F: tools/testing/selftests/alloc_tag/
|
||||||
|
|
||||||
MEMORY MANAGEMENT - BALLOON
|
MEMORY MANAGEMENT - BALLOON
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
L: virtualization@lists.linux.dev
|
L: virtualization@lists.linux.dev
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: include/linux/balloon.h
|
F: include/linux/balloon.h
|
||||||
F: mm/balloon.c
|
F: mm/balloon.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - CORE
|
MEMORY MANAGEMENT - CORE
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
R: Lorenzo Stoakes <ljs@kernel.org>
|
R: Lorenzo Stoakes <ljs@kernel.org>
|
||||||
R: Liam R. Howlett <liam@infradead.org>
|
R: Liam R. Howlett <liam@infradead.org>
|
||||||
|
|
@ -17512,34 +17515,27 @@ R: Suren Baghdasaryan <surenb@google.com>
|
||||||
R: Michal Hocko <mhocko@suse.com>
|
R: Michal Hocko <mhocko@suse.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: Documentation/admin-guide/sysctl/vm.rst
|
F: Documentation/admin-guide/sysctl/vm.rst
|
||||||
F: Documentation/core-api/gfp_mask-from-fs-io.rst
|
|
||||||
F: fs/proc/meminfo.c
|
|
||||||
F: include/linux/cacheflush.h
|
|
||||||
F: include/linux/folio_batch.h
|
F: include/linux/folio_batch.h
|
||||||
F: include/linux/gfp.h
|
F: include/linux/gfp.h
|
||||||
F: include/linux/gfp_types.h
|
F: include/linux/gfp_types.h
|
||||||
F: include/linux/highmem-internal.h
|
|
||||||
F: include/linux/highmem.h
|
F: include/linux/highmem.h
|
||||||
F: include/linux/leafops.h
|
F: include/linux/leafops.h
|
||||||
F: include/linux/memory.h
|
F: include/linux/memory.h
|
||||||
F: include/linux/mm.h
|
F: include/linux/mm.h
|
||||||
F: include/linux/mm_*.h
|
F: include/linux/mm_*.h
|
||||||
|
F: include/linux/mmzone.h
|
||||||
F: include/linux/mmdebug.h
|
F: include/linux/mmdebug.h
|
||||||
F: include/linux/mmu_notifier.h
|
F: include/linux/mmu_notifier.h
|
||||||
F: include/linux/mmzone.h
|
|
||||||
F: include/linux/pagewalk.h
|
F: include/linux/pagewalk.h
|
||||||
F: include/linux/pfn.h
|
|
||||||
F: include/linux/pgalloc.h
|
F: include/linux/pgalloc.h
|
||||||
F: include/linux/pgtable.h
|
F: include/linux/pgtable.h
|
||||||
F: include/linux/ptdump.h
|
F: include/linux/ptdump.h
|
||||||
F: include/linux/sched/mm.h
|
|
||||||
F: include/linux/vm_event_item.h
|
|
||||||
F: include/linux/vmpressure.h
|
F: include/linux/vmpressure.h
|
||||||
F: include/linux/vmstat.h
|
F: include/linux/vmstat.h
|
||||||
F: include/trace/events/mmflags.h
|
F: fs/proc/meminfo.c
|
||||||
F: include/trace/events/pagemap.h
|
|
||||||
F: kernel/fork.c
|
F: kernel/fork.c
|
||||||
F: mm/Kconfig
|
F: mm/Kconfig
|
||||||
F: mm/debug.c
|
F: mm/debug.c
|
||||||
|
|
@ -17558,7 +17554,6 @@ F: mm/ptdump.c
|
||||||
F: mm/util.c
|
F: mm/util.c
|
||||||
F: mm/vmpressure.c
|
F: mm/vmpressure.c
|
||||||
F: mm/vmstat.c
|
F: mm/vmstat.c
|
||||||
F: scripts/gdb/linux/mm.py
|
|
||||||
N: include\/linux\/page[-_][a-zA-Z]*
|
N: include\/linux\/page[-_][a-zA-Z]*
|
||||||
|
|
||||||
MEMORY MANAGEMENT - EXECMEM
|
MEMORY MANAGEMENT - EXECMEM
|
||||||
|
|
@ -17570,14 +17565,15 @@ F: include/linux/execmem.h
|
||||||
F: mm/execmem.c
|
F: mm/execmem.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - GUP (GET USER PAGES)
|
MEMORY MANAGEMENT - GUP (GET USER PAGES)
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
R: Jason Gunthorpe <jgg@nvidia.com>
|
R: Jason Gunthorpe <jgg@nvidia.com>
|
||||||
R: John Hubbard <jhubbard@nvidia.com>
|
R: John Hubbard <jhubbard@nvidia.com>
|
||||||
R: Peter Xu <peterx@redhat.com>
|
R: Peter Xu <peterx@redhat.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
F: Documentation/core-api/pin_user_pages.rst
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: mm/gup.c
|
F: mm/gup.c
|
||||||
F: mm/gup_test.c
|
F: mm/gup_test.c
|
||||||
F: mm/gup_test.h
|
F: mm/gup_test.h
|
||||||
|
|
@ -17586,12 +17582,14 @@ F: tools/testing/selftests/mm/gup.c
|
||||||
F: tools/testing/selftests/mm/gup_longterm.c
|
F: tools/testing/selftests/mm/gup_longterm.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
|
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
R: Xu Xin <xu.xin@linux.dev>
|
R: Xu Xin <xu.xin@linux.dev>
|
||||||
R: Chengming Zhou <chengming.zhou@linux.dev>
|
R: Chengming Zhou <chengming.zhou@linux.dev>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-mm-ksm
|
F: Documentation/ABI/testing/sysfs-kernel-mm-ksm
|
||||||
F: Documentation/admin-guide/mm/ksm.rst
|
F: Documentation/admin-guide/mm/ksm.rst
|
||||||
F: Documentation/mm/ksm.rst
|
F: Documentation/mm/ksm.rst
|
||||||
|
|
@ -17600,30 +17598,13 @@ F: include/trace/events/ksm.h
|
||||||
F: mm/ksm.c
|
F: mm/ksm.c
|
||||||
F: mm/mm_slot.h
|
F: mm/mm_slot.h
|
||||||
|
|
||||||
MEMORY MANAGEMENT - MEMORY HOT(UN)PLUG
|
|
||||||
M: David Hildenbrand <david@kernel.org>
|
|
||||||
M: Oscar Salvador <osalvador@suse.de>
|
|
||||||
L: linux-mm@kvack.org
|
|
||||||
L: linux-cxl@vger.kernel.org
|
|
||||||
S: Maintained
|
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
|
||||||
F: Documentation/ABI/testing/sysfs-devices-memory
|
|
||||||
F: Documentation/admin-guide/mm/memory-hotplug.rst
|
|
||||||
F: Documentation/core-api/memory-hotplug.rst
|
|
||||||
F: drivers/base/memory.c
|
|
||||||
F: include/linux/memory_hotplug.h
|
|
||||||
F: include/linux/memremap.h
|
|
||||||
F: mm/memory_hotplug.c
|
|
||||||
F: mm/memremap.c
|
|
||||||
F: tools/testing/selftests/memory-hotplug/
|
|
||||||
|
|
||||||
MEMORY MANAGEMENT - MEMORY MAP
|
MEMORY MANAGEMENT - MEMORY MAP
|
||||||
M: Muchun Song <muchun.song@linux.dev>
|
M: Muchun Song <muchun.song@linux.dev>
|
||||||
M: Mike Rapoport <rppt@kernel.org>
|
M: Mike Rapoport <rppt@kernel.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git memmap
|
||||||
F: Documentation/mm/memory-model.rst
|
F: Documentation/mm/memory-model.rst
|
||||||
F: arch/*/include/asm/sparsemem.h
|
F: arch/*/include/asm/sparsemem.h
|
||||||
F: include/asm-generic/memory_model.h
|
F: include/asm-generic/memory_model.h
|
||||||
|
|
@ -17655,6 +17636,7 @@ F: mm/vmscan.c
|
||||||
F: mm/workingset.c
|
F: mm/workingset.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - MIGRATION
|
MEMORY MANAGEMENT - MIGRATION
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
R: Zi Yan <ziy@nvidia.com>
|
R: Zi Yan <ziy@nvidia.com>
|
||||||
R: Matthew Brost <matthew.brost@intel.com>
|
R: Matthew Brost <matthew.brost@intel.com>
|
||||||
|
|
@ -17665,10 +17647,10 @@ R: Ying Huang <ying.huang@linux.alibaba.com>
|
||||||
R: Alistair Popple <apopple@nvidia.com>
|
R: Alistair Popple <apopple@nvidia.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: include/linux/migrate.h
|
F: include/linux/migrate.h
|
||||||
F: include/linux/migrate_mode.h
|
F: include/linux/migrate_mode.h
|
||||||
F: include/trace/events/migrate.h
|
|
||||||
F: mm/migrate.c
|
F: mm/migrate.c
|
||||||
F: mm/migrate_device.c
|
F: mm/migrate_device.c
|
||||||
|
|
||||||
|
|
@ -17692,20 +17674,15 @@ F: Documentation/admin-guide/mm/
|
||||||
F: Documentation/core-api/memory-allocation.rst
|
F: Documentation/core-api/memory-allocation.rst
|
||||||
F: Documentation/core-api/mm-api.rst
|
F: Documentation/core-api/mm-api.rst
|
||||||
F: Documentation/mm/
|
F: Documentation/mm/
|
||||||
F: fs/proc/page.c
|
X: Documentation/admin-guide/mm/damon/
|
||||||
F: include/linux/backing-dev-defs.h
|
X: Documentation/mm/damon/
|
||||||
F: include/linux/backing-dev.h
|
F: mm/char-mem.c
|
||||||
F: include/linux/cma.h
|
F: include/linux/cma.h
|
||||||
F: include/linux/dmapool.h
|
F: include/linux/dmapool.h
|
||||||
F: include/linux/ioremap.h
|
F: include/linux/ioremap.h
|
||||||
F: include/linux/kernel-page-flags.h
|
|
||||||
F: include/linux/page_idle.h
|
F: include/linux/page_idle.h
|
||||||
F: include/trace/events/cma.h
|
|
||||||
F: include/uapi/linux/kernel-page-flags.h
|
|
||||||
F: mm/backing-dev.c
|
F: mm/backing-dev.c
|
||||||
F: mm/char-mem.c
|
|
||||||
F: mm/cma.c
|
F: mm/cma.c
|
||||||
F: mm/cma.h
|
|
||||||
F: mm/cma_debug.c
|
F: mm/cma_debug.c
|
||||||
F: mm/cma_sysfs.c
|
F: mm/cma_sysfs.c
|
||||||
F: mm/dmapool.c
|
F: mm/dmapool.c
|
||||||
|
|
@ -17718,11 +17695,7 @@ F: mm/page_idle.c
|
||||||
F: mm/pgalloc-track.h
|
F: mm/pgalloc-track.h
|
||||||
F: mm/process_vm_access.c
|
F: mm/process_vm_access.c
|
||||||
F: tools/lib/mm/
|
F: tools/lib/mm/
|
||||||
F: tools/mm/
|
|
||||||
F: tools/testing/selftests/mm/
|
F: tools/testing/selftests/mm/
|
||||||
X: Documentation/ABI/testing/sysfs-kernel-mm-damon
|
|
||||||
X: Documentation/admin-guide/mm/damon/
|
|
||||||
X: Documentation/mm/damon/
|
|
||||||
|
|
||||||
MEMORY MANAGEMENT - NUMA MEMBLOCKS AND NUMA EMULATION
|
MEMORY MANAGEMENT - NUMA MEMBLOCKS AND NUMA EMULATION
|
||||||
M: Andrew Morton <akpm@linux-foundation.org>
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
|
@ -17730,13 +17703,13 @@ M: Mike Rapoport <rppt@kernel.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git
|
||||||
F: include/linux/numa.h
|
|
||||||
F: include/linux/numa_memblks.h
|
F: include/linux/numa_memblks.h
|
||||||
F: mm/numa.c
|
F: mm/numa.c
|
||||||
F: mm/numa_emulation.c
|
F: mm/numa_emulation.c
|
||||||
F: mm/numa_memblks.c
|
F: mm/numa_memblks.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - NUMA PLACEMENT
|
MEMORY MANAGEMENT - NUMA PLACEMENT
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
M: Gregory Price <gourry@gourry.net>
|
M: Gregory Price <gourry@gourry.net>
|
||||||
R: Zi Yan <ziy@nvidia.com>
|
R: Zi Yan <ziy@nvidia.com>
|
||||||
|
|
@ -17745,11 +17718,11 @@ R: Rakie Kim <rakie.kim@sk.com>
|
||||||
R: Ying Huang <ying.huang@linux.alibaba.com>
|
R: Ying Huang <ying.huang@linux.alibaba.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
|
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
|
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
|
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
|
||||||
F: Documentation/admin-guide/numastat.rst
|
|
||||||
F: include/linux/memory-tiers.h
|
F: include/linux/memory-tiers.h
|
||||||
F: include/linux/mempolicy.h
|
F: include/linux/mempolicy.h
|
||||||
F: include/uapi/linux/mempolicy.h
|
F: include/uapi/linux/mempolicy.h
|
||||||
|
|
@ -17768,22 +17741,19 @@ F: include/uapi/linux/oom.h
|
||||||
F: mm/oom_kill.c
|
F: mm/oom_kill.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - PAGE ALLOCATOR
|
MEMORY MANAGEMENT - PAGE ALLOCATOR
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: Vlastimil Babka <vbabka@kernel.org>
|
M: Vlastimil Babka <vbabka@kernel.org>
|
||||||
M: Johannes Weiner <hannes@cmpxchg.org>
|
|
||||||
R: Suren Baghdasaryan <surenb@google.com>
|
R: Suren Baghdasaryan <surenb@google.com>
|
||||||
R: Michal Hocko <mhocko@suse.com>
|
R: Michal Hocko <mhocko@suse.com>
|
||||||
R: Brendan Jackman <brendan.jackman@linux.dev>
|
R: Brendan Jackman <brendan.jackman@linux.dev>
|
||||||
|
R: Johannes Weiner <hannes@cmpxchg.org>
|
||||||
R: Zi Yan <ziy@nvidia.com>
|
R: Zi Yan <ziy@nvidia.com>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/page_alloc.git page_alloc/for-next
|
|
||||||
F: include/linux/compaction.h
|
F: include/linux/compaction.h
|
||||||
F: include/linux/gfp.h
|
F: include/linux/gfp.h
|
||||||
F: include/linux/page-isolation.h
|
F: include/linux/page-isolation.h
|
||||||
F: include/linux/pageblock-flags.h
|
F: include/linux/pageblock-flags.h
|
||||||
F: include/trace/events/compaction.h
|
|
||||||
F: include/trace/events/page_isolation.h
|
|
||||||
F: include/trace/events/page_ref.h
|
|
||||||
F: mm/compaction.c
|
F: mm/compaction.c
|
||||||
F: mm/debug_page_alloc.c
|
F: mm/debug_page_alloc.c
|
||||||
F: mm/debug_page_ref.c
|
F: mm/debug_page_ref.c
|
||||||
|
|
@ -17800,9 +17770,6 @@ F: mm/page_reporting.h
|
||||||
F: mm/show_mem.c
|
F: mm/show_mem.c
|
||||||
F: mm/shuffle.c
|
F: mm/shuffle.c
|
||||||
F: mm/shuffle.h
|
F: mm/shuffle.h
|
||||||
F: scripts/gdb/linux/page_owner.py
|
|
||||||
F: tools/mm/page_owner_filter.c
|
|
||||||
F: tools/mm/page_owner_sort.c
|
|
||||||
|
|
||||||
MEMORY MANAGEMENT - RECLAIM
|
MEMORY MANAGEMENT - RECLAIM
|
||||||
M: Andrew Morton <akpm@linux-foundation.org>
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
|
@ -17814,11 +17781,11 @@ R: Shakeel Butt <shakeel.butt@linux.dev>
|
||||||
R: Lorenzo Stoakes <ljs@kernel.org>
|
R: Lorenzo Stoakes <ljs@kernel.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/trace/events/vmscan.h
|
|
||||||
F: mm/vmscan.c
|
F: mm/vmscan.c
|
||||||
F: mm/workingset.c
|
F: mm/workingset.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - RMAP (REVERSE MAPPING)
|
MEMORY MANAGEMENT - RMAP (REVERSE MAPPING)
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
M: Lorenzo Stoakes <ljs@kernel.org>
|
M: Lorenzo Stoakes <ljs@kernel.org>
|
||||||
R: Rik van Riel <riel@surriel.com>
|
R: Rik van Riel <riel@surriel.com>
|
||||||
|
|
@ -17829,7 +17796,6 @@ R: Jann Horn <jannh@google.com>
|
||||||
R: Lance Yang <lance.yang@linux.dev>
|
R: Lance Yang <lance.yang@linux.dev>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
|
||||||
F: include/linux/rmap.h
|
F: include/linux/rmap.h
|
||||||
F: mm/interval_tree.c
|
F: mm/interval_tree.c
|
||||||
F: mm/page_vma_mapped.c
|
F: mm/page_vma_mapped.c
|
||||||
|
|
@ -17844,54 +17810,6 @@ S: Maintained
|
||||||
F: include/linux/secretmem.h
|
F: include/linux/secretmem.h
|
||||||
F: mm/secretmem.c
|
F: mm/secretmem.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - SHARED MEMORY (SHMEM/TMPFS/MEMFD)
|
|
||||||
M: Hugh Dickins <hughd@google.com>
|
|
||||||
M: David Hildenbrand <david@kernel.org>
|
|
||||||
R: Baolin Wang <baolin.wang@linux.alibaba.com>
|
|
||||||
L: linux-mm@kvack.org
|
|
||||||
S: Maintained
|
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
|
||||||
F: Documentation/filesystems/tmpfs.rst
|
|
||||||
F: Documentation/mm/shmfs.rst
|
|
||||||
F: Documentation/userspace-api/mfd_noexec.rst
|
|
||||||
F: include/linux/memfd.h
|
|
||||||
F: include/linux/shmem_fs.h
|
|
||||||
F: include/uapi/linux/memfd.h
|
|
||||||
F: mm/memfd.c
|
|
||||||
F: mm/shmem.c
|
|
||||||
F: mm/shmem_quota.c
|
|
||||||
F: tools/testing/selftests/memfd/
|
|
||||||
F: tools/testing/selftests/tmpfs/
|
|
||||||
|
|
||||||
MEMORY MANAGEMENT - SLAB ALLOCATOR
|
|
||||||
M: Vlastimil Babka <vbabka@kernel.org>
|
|
||||||
M: Harry Yoo <harry@kernel.org>
|
|
||||||
R: Hao Li <hao.li@linux.dev>
|
|
||||||
R: Christoph Lameter <cl@gentwo.org>
|
|
||||||
R: David Rientjes <rientjes@google.com>
|
|
||||||
R: Roman Gushchin <roman.gushchin@linux.dev>
|
|
||||||
L: linux-mm@kvack.org
|
|
||||||
S: Maintained
|
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/slab.git slab/for-next
|
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-slab
|
|
||||||
F: Documentation/admin-guide/mm/slab.rst
|
|
||||||
F: Documentation/mm/slab.rst
|
|
||||||
F: include/linux/mempool.h
|
|
||||||
F: include/linux/slab.h
|
|
||||||
F: include/trace/events/kmem.h
|
|
||||||
F: lib/tests/slub_kunit.c
|
|
||||||
F: mm/failslab.c
|
|
||||||
F: mm/mempool.c
|
|
||||||
F: mm/slab.h
|
|
||||||
F: mm/slab_common.c
|
|
||||||
F: mm/slub.c
|
|
||||||
F: scripts/gdb/linux/slab.py
|
|
||||||
F: tools/cgroup/memcg_slabinfo.py
|
|
||||||
F: tools/include/linux/slab.h
|
|
||||||
F: tools/lib/slab.c
|
|
||||||
F: tools/mm/slabinfo-gnuplot.sh
|
|
||||||
F: tools/mm/slabinfo.c
|
|
||||||
|
|
||||||
MEMORY MANAGEMENT - SWAP
|
MEMORY MANAGEMENT - SWAP
|
||||||
M: Andrew Morton <akpm@linux-foundation.org>
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: Chris Li <chrisl@kernel.org>
|
M: Chris Li <chrisl@kernel.org>
|
||||||
|
|
@ -17911,13 +17829,14 @@ F: include/linux/swapfile.h
|
||||||
F: include/linux/swapops.h
|
F: include/linux/swapops.h
|
||||||
F: mm/page_io.c
|
F: mm/page_io.c
|
||||||
F: mm/swap.h
|
F: mm/swap.h
|
||||||
F: mm/swap_state.c
|
|
||||||
F: mm/swap_table.h
|
F: mm/swap_table.h
|
||||||
|
F: mm/swap_state.c
|
||||||
F: mm/swapfile.c
|
F: mm/swapfile.c
|
||||||
|
|
||||||
MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE)
|
MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE)
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
M: David Hildenbrand <david@kernel.org>
|
M: David Hildenbrand <david@kernel.org>
|
||||||
M: Zi Yan <ziy@nvidia.com>
|
R: Zi Yan <ziy@nvidia.com>
|
||||||
R: Baolin Wang <baolin.wang@linux.alibaba.com>
|
R: Baolin Wang <baolin.wang@linux.alibaba.com>
|
||||||
R: Liam R. Howlett <liam@infradead.org>
|
R: Liam R. Howlett <liam@infradead.org>
|
||||||
R: Nico Pache <nico.pache@linux.dev>
|
R: Nico Pache <nico.pache@linux.dev>
|
||||||
|
|
@ -17929,18 +17848,17 @@ R: Usama Arif <usama.arif@linux.dev>
|
||||||
R: Kiryl Shutsemau <kas@kernel.org>
|
R: Kiryl Shutsemau <kas@kernel.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/core.git for-next
|
W: http://www.linux-mm.org
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: Documentation/ABI/testing/sysfs-kernel-mm-transparent-hugepage
|
F: Documentation/ABI/testing/sysfs-kernel-mm-transparent-hugepage
|
||||||
F: Documentation/admin-guide/mm/transhuge.rst
|
F: Documentation/admin-guide/mm/transhuge.rst
|
||||||
F: include/linux/huge_mm.h
|
F: include/linux/huge_mm.h
|
||||||
F: include/linux/khugepaged.h
|
F: include/linux/khugepaged.h
|
||||||
F: include/trace/events/huge_memory.h
|
F: include/trace/events/huge_memory.h
|
||||||
F: include/trace/events/thp.h
|
|
||||||
F: mm/collapse.h
|
F: mm/collapse.h
|
||||||
F: mm/huge_memory.c
|
F: mm/huge_memory.c
|
||||||
F: mm/khugepaged.c
|
F: mm/khugepaged.c
|
||||||
F: mm/mm_slot.h
|
F: mm/mm_slot.h
|
||||||
F: tools/mm/thpmaps
|
|
||||||
F: tools/testing/selftests/mm/khugepaged.c
|
F: tools/testing/selftests/mm/khugepaged.c
|
||||||
F: tools/testing/selftests/mm/split_huge_page_test.c
|
F: tools/testing/selftests/mm/split_huge_page_test.c
|
||||||
F: tools/testing/selftests/mm/transhuge-stress.c
|
F: tools/testing/selftests/mm/transhuge-stress.c
|
||||||
|
|
@ -17984,16 +17902,10 @@ L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: http://www.linux-mm.org
|
W: http://www.linux-mm.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: Documentation/core-api/protection-keys.rst
|
F: mm/char-mem.c
|
||||||
F: Documentation/filesystems/mmap_prepare.rst
|
F: include/trace/events/mmap.h
|
||||||
F: Documentation/userspace-api/mseal.rst
|
|
||||||
F: fs/proc/task_mmu.c
|
F: fs/proc/task_mmu.c
|
||||||
F: fs/proc/task_nommu.c
|
F: fs/proc/task_nommu.c
|
||||||
F: include/linux/mman.h
|
|
||||||
F: include/linux/pkeys.h
|
|
||||||
F: include/trace/events/mmap.h
|
|
||||||
F: include/uapi/linux/mman.h
|
|
||||||
F: mm/char-mem.c
|
|
||||||
F: mm/mincore.c
|
F: mm/mincore.c
|
||||||
F: mm/mlock.c
|
F: mm/mlock.c
|
||||||
F: mm/mmap.c
|
F: mm/mmap.c
|
||||||
|
|
@ -18831,7 +18743,6 @@ M: Peter Zijlstra <peterz@infradead.org>
|
||||||
L: linux-arch@vger.kernel.org
|
L: linux-arch@vger.kernel.org
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/core-api/cachetlb.rst
|
|
||||||
F: arch/*/include/asm/tlb.h
|
F: arch/*/include/asm/tlb.h
|
||||||
F: include/asm-generic/tlb.h
|
F: include/asm-generic/tlb.h
|
||||||
F: include/trace/events/tlb.h
|
F: include/trace/events/tlb.h
|
||||||
|
|
@ -21013,7 +20924,7 @@ S: Maintained
|
||||||
F: drivers/char/hw_random/optee-rng.c
|
F: drivers/char/hw_random/optee-rng.c
|
||||||
|
|
||||||
OP-TEE RTC DRIVER
|
OP-TEE RTC DRIVER
|
||||||
M: Clément Léger <clement.leger@linux.dev>
|
M: Clément Léger <clement.leger@bootlin.com>
|
||||||
L: linux-rtc@vger.kernel.org
|
L: linux-rtc@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/rtc/rtc-optee.c
|
F: drivers/rtc/rtc-optee.c
|
||||||
|
|
@ -21942,7 +21853,6 @@ S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git
|
||||||
F: arch/*/include/asm/percpu.h
|
F: arch/*/include/asm/percpu.h
|
||||||
F: include/linux/percpu*.h
|
F: include/linux/percpu*.h
|
||||||
F: include/trace/events/percpu.h
|
|
||||||
F: lib/percpu*.c
|
F: lib/percpu*.c
|
||||||
F: mm/percpu*.c
|
F: mm/percpu*.c
|
||||||
F: mm/percpu-internal.h
|
F: mm/percpu-internal.h
|
||||||
|
|
@ -22436,7 +22346,6 @@ M: Petr Mladek <pmladek@suse.com>
|
||||||
M: John Ogness <john.ogness@linutronix.de>
|
M: John Ogness <john.ogness@linutronix.de>
|
||||||
R: Steven Rostedt <rostedt@goodmis.org>
|
R: Steven Rostedt <rostedt@goodmis.org>
|
||||||
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||||
L: printk@lists.linux.dev
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
|
||||||
F: Documentation/core-api/printk-basics.rst
|
F: Documentation/core-api/printk-basics.rst
|
||||||
|
|
@ -22445,7 +22354,6 @@ F: kernel/printk/
|
||||||
|
|
||||||
PRINTK INDEXING
|
PRINTK INDEXING
|
||||||
R: Chris Down <chris@chrisdown.name>
|
R: Chris Down <chris@chrisdown.name>
|
||||||
L: printk@lists.linux.dev
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/core-api/printk-index.rst
|
F: Documentation/core-api/printk-index.rst
|
||||||
F: kernel/printk/index.c
|
F: kernel/printk/index.c
|
||||||
|
|
@ -23915,7 +23823,7 @@ F: Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
|
||||||
F: drivers/rtc/rtc-renesas-rtca3.c
|
F: drivers/rtc/rtc-renesas-rtca3.c
|
||||||
|
|
||||||
RENESAS RZ/N1 A5PSW SWITCH DRIVER
|
RENESAS RZ/N1 A5PSW SWITCH DRIVER
|
||||||
M: Clément Léger <clement.leger@linux.dev>
|
M: Clément Léger <clement.leger@bootlin.com>
|
||||||
L: linux-renesas-soc@vger.kernel.org
|
L: linux-renesas-soc@vger.kernel.org
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
@ -25671,7 +25579,6 @@ F: include/linux/shrinker.h
|
||||||
F: mm/list_lru.c
|
F: mm/list_lru.c
|
||||||
F: mm/shrinker.c
|
F: mm/shrinker.c
|
||||||
F: mm/shrinker_debug.c
|
F: mm/shrinker_debug.c
|
||||||
F: tools/cgroup/memcg_shrinker.py
|
|
||||||
|
|
||||||
SH_VOU V4L2 OUTPUT DRIVER
|
SH_VOU V4L2 OUTPUT DRIVER
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
|
|
@ -25893,6 +25800,34 @@ S: Maintained
|
||||||
F: Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml
|
F: Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml
|
||||||
F: drivers/nvmem/layouts/sl28vpd.c
|
F: drivers/nvmem/layouts/sl28vpd.c
|
||||||
|
|
||||||
|
SLAB ALLOCATOR
|
||||||
|
M: Vlastimil Babka <vbabka@kernel.org>
|
||||||
|
M: Harry Yoo <harry@kernel.org>
|
||||||
|
M: Andrew Morton <akpm@linux-foundation.org>
|
||||||
|
R: Hao Li <hao.li@linux.dev>
|
||||||
|
R: Christoph Lameter <cl@gentwo.org>
|
||||||
|
R: David Rientjes <rientjes@google.com>
|
||||||
|
R: Roman Gushchin <roman.gushchin@linux.dev>
|
||||||
|
L: linux-mm@kvack.org
|
||||||
|
S: Maintained
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/slab.git
|
||||||
|
F: Documentation/admin-guide/mm/slab.rst
|
||||||
|
F: Documentation/mm/slab.rst
|
||||||
|
F: include/linux/mempool.h
|
||||||
|
F: include/linux/slab.h
|
||||||
|
F: lib/tests/slub_kunit.c
|
||||||
|
F: mm/failslab.c
|
||||||
|
F: mm/mempool.c
|
||||||
|
F: mm/slab.h
|
||||||
|
F: mm/slab_common.c
|
||||||
|
F: mm/slub.c
|
||||||
|
F: scripts/gdb/linux/slab.py
|
||||||
|
F: tools/cgroup/memcg_slabinfo.py
|
||||||
|
F: tools/include/linux/slab.h
|
||||||
|
F: tools/lib/slab.c
|
||||||
|
F: tools/mm/slabinfo-gnuplot.sh
|
||||||
|
F: tools/mm/slabinfo.c
|
||||||
|
|
||||||
SLCAN CAN NETWORK DRIVER
|
SLCAN CAN NETWORK DRIVER
|
||||||
M: Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
M: Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
||||||
L: linux-can@vger.kernel.org
|
L: linux-can@vger.kernel.org
|
||||||
|
|
@ -28310,6 +28245,17 @@ S: Maintained
|
||||||
F: Documentation/hwmon/tmp513.rst
|
F: Documentation/hwmon/tmp513.rst
|
||||||
F: drivers/hwmon/tmp513.c
|
F: drivers/hwmon/tmp513.c
|
||||||
|
|
||||||
|
TMPFS (SHMEM FILESYSTEM)
|
||||||
|
M: Hugh Dickins <hughd@google.com>
|
||||||
|
R: Baolin Wang <baolin.wang@linux.alibaba.com>
|
||||||
|
L: linux-mm@kvack.org
|
||||||
|
S: Maintained
|
||||||
|
F: include/linux/memfd.h
|
||||||
|
F: include/linux/shmem_fs.h
|
||||||
|
F: mm/memfd.c
|
||||||
|
F: mm/shmem.c
|
||||||
|
F: mm/shmem_quota.c
|
||||||
|
|
||||||
TOMOYO SECURITY MODULE
|
TOMOYO SECURITY MODULE
|
||||||
M: Kentaro Takeda <takedakn@nttdata.co.jp>
|
M: Kentaro Takeda <takedakn@nttdata.co.jp>
|
||||||
M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
|
M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
|
||||||
|
|
@ -28716,7 +28662,7 @@ F: arch/m68k/coldfire/
|
||||||
F: arch/m68k/include/asm/*_no.*
|
F: arch/m68k/include/asm/*_no.*
|
||||||
|
|
||||||
UDF FILESYSTEM
|
UDF FILESYSTEM
|
||||||
M: Jan Kara <jack@suse.cz>
|
M: Jan Kara <jack@suse.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/filesystems/udf.rst
|
F: Documentation/filesystems/udf.rst
|
||||||
F: fs/udf/
|
F: fs/udf/
|
||||||
|
|
@ -29664,12 +29610,9 @@ F: drivers/block/virtio_blk.c
|
||||||
F: drivers/crypto/virtio/
|
F: drivers/crypto/virtio/
|
||||||
F: drivers/vdpa/
|
F: drivers/vdpa/
|
||||||
F: drivers/virtio/
|
F: drivers/virtio/
|
||||||
F: include/linux/device-id/virtio.h
|
|
||||||
F: include/linux/vdpa.h
|
F: include/linux/vdpa.h
|
||||||
F: include/linux/virtio*.h
|
F: include/linux/virtio*.h
|
||||||
F: include/linux/vringh.h
|
F: include/linux/vringh.h
|
||||||
F: include/uapi/linux/vdpa.h
|
|
||||||
F: include/uapi/linux/vduse.h
|
|
||||||
F: include/uapi/linux/virtio_*.h
|
F: include/uapi/linux/virtio_*.h
|
||||||
F: net/vmw_vsock/virtio*
|
F: net/vmw_vsock/virtio*
|
||||||
F: tools/virtio/
|
F: tools/virtio/
|
||||||
|
|
@ -29743,7 +29686,6 @@ F: drivers/vhost/
|
||||||
F: include/linux/sched/vhost_task.h
|
F: include/linux/sched/vhost_task.h
|
||||||
F: include/linux/vhost_iotlb.h
|
F: include/linux/vhost_iotlb.h
|
||||||
F: include/uapi/linux/vhost.h
|
F: include/uapi/linux/vhost.h
|
||||||
F: include/uapi/linux/vhost_types.h
|
|
||||||
F: kernel/vhost_task.c
|
F: kernel/vhost_task.c
|
||||||
|
|
||||||
VIRTIO HOST (VHOST-SCSI)
|
VIRTIO HOST (VHOST-SCSI)
|
||||||
|
|
@ -29937,11 +29879,9 @@ S: Maintained
|
||||||
W: http://www.linux-mm.org
|
W: http://www.linux-mm.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||||
F: include/linux/vmalloc.h
|
F: include/linux/vmalloc.h
|
||||||
F: include/trace/events/vmalloc.h
|
|
||||||
F: lib/test_vmalloc.c
|
|
||||||
F: mm/vmalloc.c
|
F: mm/vmalloc.c
|
||||||
F: mm/vmalloc.h
|
F: mm/vmalloc.h
|
||||||
F: scripts/gdb/linux/vmalloc.py
|
F: lib/test_vmalloc.c
|
||||||
|
|
||||||
VME SUBSYSTEM
|
VME SUBSYSTEM
|
||||||
L: linux-kernel@vger.kernel.org
|
L: linux-kernel@vger.kernel.org
|
||||||
|
|
@ -30064,7 +30004,6 @@ M: Steven Rostedt <rostedt@goodmis.org>
|
||||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||||
R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
|
R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
|
||||||
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||||
L: printk@lists.linux.dev
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
|
||||||
F: Documentation/core-api/printk-formats.rst
|
F: Documentation/core-api/printk-formats.rst
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ asmlinkage unsigned long __sdei_handler(struct pt_regs *regs,
|
||||||
struct sdei_registered_event *arg);
|
struct sdei_registered_event *arg);
|
||||||
|
|
||||||
unsigned long do_sdei_event(struct pt_regs *regs,
|
unsigned long do_sdei_event(struct pt_regs *regs,
|
||||||
struct sdei_registered_event *arg,
|
struct sdei_registered_event *arg);
|
||||||
unsigned long vbar);
|
|
||||||
|
|
||||||
unsigned long sdei_arch_get_entry_point(int conduit);
|
unsigned long sdei_arch_get_entry_point(int conduit);
|
||||||
#define sdei_arch_get_entry_point(x) sdei_arch_get_entry_point(x)
|
#define sdei_arch_get_entry_point(x) sdei_arch_get_entry_point(x)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#ifndef __ASM_SUSPEND_H
|
#ifndef __ASM_SUSPEND_H
|
||||||
#define __ASM_SUSPEND_H
|
#define __ASM_SUSPEND_H
|
||||||
|
|
||||||
#define NR_CTX_REGS 15
|
#define NR_CTX_REGS 14
|
||||||
#define NR_CALLEE_SAVED_REGS 12
|
#define NR_CALLEE_SAVED_REGS 12
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include <asm/stacktrace.h>
|
#include <asm/stacktrace.h>
|
||||||
#include <asm/sysreg.h>
|
#include <asm/sysreg.h>
|
||||||
#include <asm/system_misc.h>
|
#include <asm/system_misc.h>
|
||||||
#include <asm/vectors.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Where the context being returned to had an active percpu GPR critical
|
* Where the context being returned to had an active percpu GPR critical
|
||||||
|
|
@ -1041,7 +1040,6 @@ asmlinkage void noinstr __noreturn handle_bad_stack(struct pt_regs *regs)
|
||||||
asmlinkage noinstr unsigned long
|
asmlinkage noinstr unsigned long
|
||||||
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
|
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
|
||||||
{
|
{
|
||||||
unsigned long elr, spsr, esr, far, vbar;
|
|
||||||
irqentry_state_t state;
|
irqentry_state_t state;
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
|
|
||||||
|
|
@ -1067,46 +1065,10 @@ __sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
|
||||||
else if (cpu_has_pan())
|
else if (cpu_has_pan())
|
||||||
set_pstate_pan(0);
|
set_pstate_pan(0);
|
||||||
|
|
||||||
/*
|
|
||||||
* Nothing saved the interrupted context's exception registers on the
|
|
||||||
* way in, and it may be in the middle of exception entry or return
|
|
||||||
* (SDEI ignores DAIF). Save them before anything can take an exception
|
|
||||||
* and overwrite them.
|
|
||||||
*/
|
|
||||||
elr = read_sysreg(elr_el1);
|
|
||||||
spsr = read_sysreg(spsr_el1);
|
|
||||||
esr = read_sysreg(esr_el1);
|
|
||||||
far = read_sysreg(far_el1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* With KPTI, VBAR_EL1 holds the trampoline vectors from the return to
|
|
||||||
* EL0 until the next exception from EL0 maps the kernel. They only
|
|
||||||
* handle exceptions from EL0: an exception taken here would run their
|
|
||||||
* empty current-EL half and never come back. Switch to the kernel
|
|
||||||
* vectors. The IRQ-like resume keeps using the interrupted VBAR, so it
|
|
||||||
* still goes through the trampoline.
|
|
||||||
*/
|
|
||||||
vbar = read_sysreg(vbar_el1);
|
|
||||||
if (arm64_kernel_unmapped_at_el0() &&
|
|
||||||
vbar == (unsigned long)raw_cpu_read(this_cpu_vector)) {
|
|
||||||
write_sysreg((unsigned long)vectors, vbar_el1);
|
|
||||||
isb();
|
|
||||||
}
|
|
||||||
|
|
||||||
state = irqentry_nmi_enter(regs);
|
state = irqentry_nmi_enter(regs);
|
||||||
ret = do_sdei_event(regs, arg, vbar);
|
ret = do_sdei_event(regs, arg);
|
||||||
irqentry_nmi_exit(regs, state);
|
irqentry_nmi_exit(regs, state);
|
||||||
|
|
||||||
/*
|
|
||||||
* Put them back unconditionally. An unchanged ELR does not rule out a
|
|
||||||
* nested exception: one may have returned to the same address.
|
|
||||||
*/
|
|
||||||
write_sysreg(elr, elr_el1);
|
|
||||||
write_sysreg(spsr, spsr_el1);
|
|
||||||
write_sysreg(esr, esr_el1);
|
|
||||||
write_sysreg(far, far_el1);
|
|
||||||
write_sysreg(vbar, vbar_el1);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_ARM_SDE_INTERFACE */
|
#endif /* CONFIG_ARM_SDE_INTERFACE */
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,6 @@ int load_other_segments(struct kimage *image,
|
||||||
vfree(headers);
|
vfree(headers);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfree(image->elf_headers);
|
|
||||||
image->elf_headers = headers;
|
image->elf_headers = headers;
|
||||||
image->elf_load_addr = kbuf.mem;
|
image->elf_load_addr = kbuf.mem;
|
||||||
image->elf_headers_sz = headers_sz;
|
image->elf_headers_sz = headers_sz;
|
||||||
|
|
|
||||||
|
|
@ -195,49 +195,21 @@ unsigned long sdei_arch_get_entry_point(int conduit)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Exceptions an SDEI handler may take without harm once __sdei_handler() has
|
|
||||||
* restored the interrupted context's exception registers. Their handlers are
|
|
||||||
* safe in NMI context:
|
|
||||||
* - EL1 data aborts on translation, permission and access-flag faults:
|
|
||||||
* faulthandler_disabled() is true in NMI context, so do_page_fault() never
|
|
||||||
* takes the mmap lock. This covers the _nofault() accessors used by the
|
|
||||||
* generic dump_stack()/show_regs() code (e.g. print_worker_info()).
|
|
||||||
* - BRK: kprobes, WARN/BUG, kCFI and UBSAN traps, all NMI-capable.
|
|
||||||
* Anything else taken at EL1 is fatal on its own, or unexpected here.
|
|
||||||
*/
|
|
||||||
static bool sdei_nested_exception_ok(unsigned long esr)
|
|
||||||
{
|
|
||||||
switch (ESR_ELx_EC(esr)) {
|
|
||||||
case ESR_ELx_EC_DABT_CUR:
|
|
||||||
return esr_fsc_is_translation_fault(esr) ||
|
|
||||||
esr_fsc_is_permission_fault(esr) ||
|
|
||||||
esr_fsc_is_access_flag_fault(esr);
|
|
||||||
case ESR_ELx_EC_BRK64:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do_sdei_event() returns one of:
|
* do_sdei_event() returns one of:
|
||||||
* SDEI_EV_HANDLED - success, return to the interrupted context.
|
* SDEI_EV_HANDLED - success, return to the interrupted context.
|
||||||
* SDEI_EV_FAILED - failure, return this error code to firmware.
|
* SDEI_EV_FAILED - failure, return this error code to firmware.
|
||||||
* virtual-address - success, return to this address.
|
* virtual-address - success, return to this address.
|
||||||
*
|
|
||||||
* vbar is the interrupted context's VBAR_EL1, for the IRQ-like resume.
|
|
||||||
*/
|
*/
|
||||||
unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
|
unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
|
||||||
struct sdei_registered_event *arg,
|
struct sdei_registered_event *arg)
|
||||||
unsigned long vbar)
|
|
||||||
{
|
{
|
||||||
u32 mode;
|
u32 mode;
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
int clobbered_registers = 4;
|
int clobbered_registers = 4;
|
||||||
u64 elr = read_sysreg(elr_el1);
|
u64 elr = read_sysreg(elr_el1);
|
||||||
u64 nested_elr, nested_esr, nested_far;
|
|
||||||
u32 kernel_mode = read_sysreg(CurrentEL) | 1; /* +SPSel */
|
u32 kernel_mode = read_sysreg(CurrentEL) | 1; /* +SPSel */
|
||||||
|
unsigned long vbar = read_sysreg(vbar_el1);
|
||||||
|
|
||||||
if (arm64_kernel_unmapped_at_el0())
|
if (arm64_kernel_unmapped_at_el0())
|
||||||
clobbered_registers++;
|
clobbered_registers++;
|
||||||
|
|
@ -249,27 +221,18 @@ unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sdei_event_handler(regs, arg);
|
err = sdei_event_handler(regs, arg);
|
||||||
|
|
||||||
/*
|
|
||||||
* A synchronous exception taken by the handler has overwritten the
|
|
||||||
* exception registers; __sdei_handler() puts them back. Only the last
|
|
||||||
* one's syndrome survives; report it if it is not one known to be
|
|
||||||
* harmless.
|
|
||||||
*
|
|
||||||
* If the event interrupted a KVM world switch, VBAR points at the KVM
|
|
||||||
* hyp vectors and any such exception is a hyp panic instead.
|
|
||||||
*/
|
|
||||||
nested_elr = read_sysreg(elr_el1);
|
|
||||||
nested_esr = read_sysreg(esr_el1);
|
|
||||||
nested_far = read_sysreg(far_el1);
|
|
||||||
if (nested_elr != elr && !sdei_nested_exception_ok(nested_esr)) {
|
|
||||||
pr_warn_once("unexpected exception during handler: ESR %#llx FAR %#llx near %pS\n",
|
|
||||||
nested_esr, nested_far, (void *)nested_elr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return SDEI_EV_FAILED;
|
return SDEI_EV_FAILED;
|
||||||
|
|
||||||
|
if (elr != read_sysreg(elr_el1)) {
|
||||||
|
/*
|
||||||
|
* We took a synchronous exception from the SDEI handler.
|
||||||
|
* This could deadlock, and if you interrupt KVM it will
|
||||||
|
* hyp-panic instead.
|
||||||
|
*/
|
||||||
|
pr_warn("unsafe: exception during handler\n");
|
||||||
|
}
|
||||||
|
|
||||||
mode = regs->pstate & (PSR_MODE32_BIT | PSR_MODE_MASK);
|
mode = regs->pstate & (PSR_MODE32_BIT | PSR_MODE_MASK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,7 @@ int valid_phys_addr_range(phys_addr_t addr, size_t size)
|
||||||
*/
|
*/
|
||||||
int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
|
int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
|
||||||
{
|
{
|
||||||
const phys_addr_t limit = PHYS_MASK + 1;
|
return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
|
||||||
|
|
||||||
return size <= limit && pfn <= (limit - size) >> PAGE_SHIFT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init adjust_protection_map(void)
|
static int __init adjust_protection_map(void)
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,6 @@ SYM_FUNC_START(cpu_do_suspend)
|
||||||
alternative_if ARM64_HAS_TCR2
|
alternative_if ARM64_HAS_TCR2
|
||||||
mrs x2, REG_TCR2_EL1
|
mrs x2, REG_TCR2_EL1
|
||||||
str x2, [x0, #104]
|
str x2, [x0, #104]
|
||||||
alternative_else_nop_endif
|
|
||||||
alternative_if ARM64_SME
|
|
||||||
mrs_s x2, SYS_TPIDR2_EL0
|
|
||||||
str x2, [x0, #112]
|
|
||||||
alternative_else_nop_endif
|
alternative_else_nop_endif
|
||||||
ret
|
ret
|
||||||
SYM_FUNC_END(cpu_do_suspend)
|
SYM_FUNC_END(cpu_do_suspend)
|
||||||
|
|
@ -156,10 +152,6 @@ alternative_if ARM64_HAS_TCR2
|
||||||
ldr x2, [x0, #104]
|
ldr x2, [x0, #104]
|
||||||
msr REG_TCR2_EL1, x2
|
msr REG_TCR2_EL1, x2
|
||||||
alternative_else_nop_endif
|
alternative_else_nop_endif
|
||||||
alternative_if ARM64_SME
|
|
||||||
ldr x2, [x0, #112]
|
|
||||||
msr_s SYS_TPIDR2_EL0, x2
|
|
||||||
alternative_else_nop_endif
|
|
||||||
|
|
||||||
msr sctlr_el1, x12
|
msr sctlr_el1, x12
|
||||||
set_this_cpu_offset x13
|
set_this_cpu_offset x13
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,16 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
str x7, [sp, #80]
|
str x7, [sp, #80]
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The pointer to count and timestamp was passed in BPF_REG_AX (x9),
|
* Stack depth was passed in BPF_REG_AX (x9), add it to the BPF_FP
|
||||||
* pass it as the first argument in x0.
|
* (x25) to get the pointer to count and timestamp and pass it as the
|
||||||
|
* first argument in x0.
|
||||||
|
*
|
||||||
|
* Before generating the call to arch_bpf_timed_may_goto, the verifier
|
||||||
|
* generates a load instruction using FP, i.e. REG_AX = *(u64 *)(FP -
|
||||||
|
* stack_off_cnt), so BPF_REG_FP (x25) is always set up by the arm64
|
||||||
|
* jit in this case.
|
||||||
*/
|
*/
|
||||||
mov x0, x9
|
add x0, x9, x25
|
||||||
bl bpf_check_timed_may_goto
|
bl bpf_check_timed_may_goto
|
||||||
/* BPF_REG_AX(x9) will be stored into count, so move return value to it. */
|
/* BPF_REG_AX(x9) will be stored into count, so move return value to it. */
|
||||||
mov x9, x0
|
mov x9, x0
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,14 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
st.d a4, sp, 48
|
st.d a4, sp, 48
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BPF_REG_AX (t0) holds the pointer to the count and timestamp;
|
* BPF_REG_AX (t0) holds the offset passed in by the verifier;
|
||||||
* pass it as the first argument in a0.
|
* add it to BPF_REG_FP (s4) to get the pointer to the count and
|
||||||
|
* timestamp, then pass it as the first argument in a0.
|
||||||
|
*
|
||||||
|
* The verifier emits a load using FP right before this call,
|
||||||
|
* so BPF_REG_FP (s4) is always set up by the JIT in this case.
|
||||||
*/
|
*/
|
||||||
move a0, t0
|
add.d a0, t0, s4
|
||||||
bl bpf_check_timed_may_goto
|
bl bpf_check_timed_may_goto
|
||||||
/* BPF_REG_AX (t0) will be stored into count, so move the return value to it. */
|
/* BPF_REG_AX (t0) will be stored into count, so move the return value to it. */
|
||||||
move t0, a0
|
move t0, a0
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ DECLARE_EXPORT(__divsi3);
|
||||||
DECLARE_EXPORT(__umodsi3);
|
DECLARE_EXPORT(__umodsi3);
|
||||||
DECLARE_EXPORT(__modsi3);
|
DECLARE_EXPORT(__modsi3);
|
||||||
DECLARE_EXPORT(__muldi3);
|
DECLARE_EXPORT(__muldi3);
|
||||||
DECLARE_EXPORT(__mulsi3);
|
|
||||||
DECLARE_EXPORT(__ashrdi3);
|
DECLARE_EXPORT(__ashrdi3);
|
||||||
DECLARE_EXPORT(__ashldi3);
|
DECLARE_EXPORT(__ashldi3);
|
||||||
DECLARE_EXPORT(__lshrdi3);
|
DECLARE_EXPORT(__lshrdi3);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
* arch_bpf_timed_may_goto() trampoline for powerpc64
|
* arch_bpf_timed_may_goto() trampoline for powerpc64
|
||||||
*
|
*
|
||||||
* Custom BPF convention (verifier/JIT):
|
* Custom BPF convention (verifier/JIT):
|
||||||
* - input: pointer to count and timestamp in BPF_REG_AX (r12)
|
* - input: stack offset in BPF_REG_AX (r12)
|
||||||
* - output: updated count in BPF_REG_AX (r12)
|
* - output: updated count in BPF_REG_AX (r12)
|
||||||
*
|
*
|
||||||
* Call bpf_check_timed_may_goto(ptr) with normal powerpc64 ABI:
|
* Call bpf_check_timed_may_goto(ptr) with normal powerpc64 ABI:
|
||||||
|
|
@ -31,8 +31,11 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
std r7, 64(r1)
|
std r7, 64(r1)
|
||||||
std r8, 72(r1)
|
std r8, 72(r1)
|
||||||
|
|
||||||
/* r3 = BPF_REG_AX (r12) */
|
/*
|
||||||
mr r3, r12
|
* r3 = BPF_REG_FP + BPF_REG_AX
|
||||||
|
* BPF_REG_FP is r31; BPF_REG_AX is r12 (stack offset in bytes).
|
||||||
|
*/
|
||||||
|
add r3, r31, r12
|
||||||
bl CFUNC(bpf_check_timed_may_goto)
|
bl CFUNC(bpf_check_timed_may_goto)
|
||||||
|
|
||||||
/* Put return value back into AX */
|
/* Put return value back into AX */
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trampoline for the BPF timed may_goto loop bound. Custom calling convention:
|
* Trampoline for the BPF timed may_goto loop bound. Custom calling convention:
|
||||||
* - input: pointer to count and timestamp in BPF_REG_AX (t0)
|
* - input: stack offset in BPF_REG_AX (t0)
|
||||||
* - output: updated count in BPF_REG_AX (t0)
|
* - output: updated count in BPF_REG_AX (t0)
|
||||||
*
|
*
|
||||||
* Calls bpf_check_timed_may_goto(ptr) with the standard RISC-V ABI. BPF R0-R5
|
* Calls bpf_check_timed_may_goto(ptr) with the standard RISC-V ABI, where
|
||||||
* (t6, a0-a4) and stack arguments 6-8 (a5-a7) are saved across the call.
|
* ptr = BPF_REG_FP (s5) + BPF_REG_AX (t0). BPF R0-R5 (t6, a0-a4) and stack
|
||||||
|
* arguments 6-8 (a5-a7) are saved across the call; BPF_REG_FP (s5) is
|
||||||
|
* callee-saved and needs no saving.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SYM_FUNC_START(arch_bpf_timed_may_goto)
|
SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
|
|
@ -31,7 +33,7 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
REG_S a6, 7*SZREG(sp)
|
REG_S a6, 7*SZREG(sp)
|
||||||
REG_S a7, 8*SZREG(sp)
|
REG_S a7, 8*SZREG(sp)
|
||||||
|
|
||||||
mv a0, t0
|
add a0, t0, s5
|
||||||
call bpf_check_timed_may_goto
|
call bpf_check_timed_may_goto
|
||||||
mv t0, a0
|
mv t0, a0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1005,17 +1005,6 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||||
(jit->prg - patch_brc) >> 1;
|
(jit->prg - patch_brc) >> 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (insn_is_mov_percpu_addr(insn)) {
|
|
||||||
const u64 *percpu_offset = &get_lowcore()->percpu_offset;
|
|
||||||
|
|
||||||
if (dst_reg != src_reg)
|
|
||||||
/* lgr %dst,%src */
|
|
||||||
EMIT4(0xb9040000, dst_reg, src_reg);
|
|
||||||
/* ag %dst,percpu_offset */
|
|
||||||
EMIT6_DISP_LH(0xe3000000, 0x0008, dst_reg, REG_0, REG_0,
|
|
||||||
(unsigned long)percpu_offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (insn->off) {
|
switch (insn->off) {
|
||||||
case 0: /* DST = SRC */
|
case 0: /* DST = SRC */
|
||||||
/* lgr %dst,%src */
|
/* lgr %dst,%src */
|
||||||
|
|
@ -1877,9 +1866,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||||
if ((void *)func == arch_bpf_timed_may_goto) {
|
if ((void *)func == arch_bpf_timed_may_goto) {
|
||||||
/*
|
/*
|
||||||
* arch_bpf_timed_may_goto() has a special ABI: the
|
* arch_bpf_timed_may_goto() has a special ABI: the
|
||||||
* parameter is in BPF_REG_AX; the return value is in
|
* parameters are in BPF_REG_AX and BPF_REG_10; the
|
||||||
* BPF_REG_AX; and all GPRs except REG_W0, REG_W1, and
|
* return value is in BPF_REG_AX; and all GPRs except
|
||||||
* BPF_REG_AX are callee-saved.
|
* REG_W0, REG_W1, and BPF_REG_AX are callee-saved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* brasl %r0,func */
|
/* brasl %r0,func */
|
||||||
|
|
@ -2439,6 +2428,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
|
||||||
fp->jited_len = jit.size - cfi_get_offset();
|
fp->jited_len = jit.size - cfi_get_offset();
|
||||||
|
|
||||||
if (!fp->is_func || extra_pass) {
|
if (!fp->is_func || extra_pass) {
|
||||||
|
for (int i = 0; i < fp->len; i++)
|
||||||
|
jit.addrs[i] -= cfi_get_offset();
|
||||||
bpf_prog_fill_jited_linfo(fp, jit.addrs + 1);
|
bpf_prog_fill_jited_linfo(fp, jit.addrs + 1);
|
||||||
free_addrs:
|
free_addrs:
|
||||||
kvfree(jit.addrs);
|
kvfree(jit.addrs);
|
||||||
|
|
@ -3125,11 +3116,6 @@ bool bpf_jit_supports_timed_may_goto(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpf_jit_supports_percpu_insn(void)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpf_jit_inlines_helper_call(s32 imm)
|
bool bpf_jit_inlines_helper_call(s32 imm)
|
||||||
{
|
{
|
||||||
switch (imm) {
|
switch (imm) {
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@
|
||||||
|
|
||||||
SYM_FUNC_START(arch_bpf_timed_may_goto)
|
SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
/*
|
/*
|
||||||
* This function has a special ABI: the parameter is in %r12; the
|
* This function has a special ABI: the parameters are in %r12 and
|
||||||
* return value is in %r12; all GPRs except %r0, %r1, and %r12 are
|
* %r13; the return value is in %r12; all GPRs except %r0, %r1, and
|
||||||
* callee-saved; and the return address is in %r0.
|
* %r12 are callee-saved; and the return address is in %r0.
|
||||||
*/
|
*/
|
||||||
stmg %r2,%r5,FRAME_OFF+R2_OFF(%r15)
|
stmg %r2,%r5,FRAME_OFF+R2_OFF(%r15)
|
||||||
stg %r14,FRAME_OFF+R14_OFF(%r15)
|
stg %r14,FRAME_OFF+R14_OFF(%r15)
|
||||||
|
|
@ -33,7 +33,7 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
lay %r15,-FRAME_SIZE(%r15)
|
lay %r15,-FRAME_SIZE(%r15)
|
||||||
stg %r1,__SF_BACKCHAIN(%r15)
|
stg %r1,__SF_BACKCHAIN(%r15)
|
||||||
|
|
||||||
lgr %r2,%r12
|
lay %r2,0(%r12,%r13)
|
||||||
brasl %r14,bpf_check_timed_may_goto
|
brasl %r14,bpf_check_timed_may_goto
|
||||||
lgr %r12,%r2
|
lgr %r12,%r2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -286,9 +286,9 @@ SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
1:
|
1:
|
||||||
/* See ftrace_jmp_set(), jmp to the trampoline */
|
testb $1, %al
|
||||||
btsq $63, %rax
|
jz 2f
|
||||||
jc 2f
|
andq $0xfffffffffffffffe, %rax
|
||||||
movq %rax, MCOUNT_REG_SIZE+8(%rsp)
|
movq %rax, MCOUNT_REG_SIZE+8(%rsp)
|
||||||
restore_mcount_regs
|
restore_mcount_regs
|
||||||
/* Restore flags */
|
/* Restore flags */
|
||||||
|
|
|
||||||
|
|
@ -2359,16 +2359,6 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm *kvm,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Note! Unlike fully direct MMUs, direct SPs in indirect MMUs
|
|
||||||
* can have an arbitrary number of parents, e.g if the guest is
|
|
||||||
* mapping a huge PTE at many points in its page tables.
|
|
||||||
*/
|
|
||||||
if (pte_list_count(&sp->parent_ptes) >= RMAP_RECYCLE_THRESHOLD) {
|
|
||||||
kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unsync and write-flooding only apply to indirect SPs. */
|
/* unsync and write-flooding only apply to indirect SPs. */
|
||||||
if (sp->role.direct)
|
if (sp->role.direct)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -339,13 +339,6 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
||||||
gpa_t real_gpa;
|
gpa_t real_gpa;
|
||||||
gfn_t gfn;
|
gfn_t gfn;
|
||||||
|
|
||||||
/*
|
|
||||||
* KVM might sleep/resched when retrying the walk if the updating A/D
|
|
||||||
* fails because the gPTE changed between reading the gPTE and trying
|
|
||||||
* the CMPXHG to set A/D bits.
|
|
||||||
*/
|
|
||||||
might_sleep();
|
|
||||||
|
|
||||||
trace_kvm_mmu_pagetable_walk(addr, access);
|
trace_kvm_mmu_pagetable_walk(addr, access);
|
||||||
retry_walk:
|
retry_walk:
|
||||||
walker->level = w->cpu_role.base.level;
|
walker->level = w->cpu_role.base.level;
|
||||||
|
|
@ -488,10 +481,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
||||||
addr, write_fault);
|
addr, write_fault);
|
||||||
if (unlikely(ret < 0))
|
if (unlikely(ret < 0))
|
||||||
goto error;
|
goto error;
|
||||||
else if (ret) {
|
else if (ret)
|
||||||
cond_resched();
|
|
||||||
goto retry_walk;
|
goto retry_walk;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
|
|
@ -1889,21 +1889,6 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
|
||||||
/* 'clean' and 'hv_enlightenments' are not changed by KVM */
|
/* 'clean' and 'hv_enlightenments' are not changed by KVM */
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nested_svm_check_vmcb01_save(struct kvm_vcpu *vcpu,
|
|
||||||
struct vmcb_save_area *save)
|
|
||||||
{
|
|
||||||
struct vmcb_save_area_cached save_cached;
|
|
||||||
|
|
||||||
if (!(save->cr0 & X86_CR0_PG) ||
|
|
||||||
!(save->cr0 & X86_CR0_PE) ||
|
|
||||||
(save->rflags & X86_EFLAGS_VM) ||
|
|
||||||
((save->efer & EFER_LMA) && !(save->efer & EFER_LME)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
__nested_copy_vmcb_save_to_cache(&save_cached, save);
|
|
||||||
return nested_vmcb_check_save(vcpu, &save_cached, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int svm_get_nested_state(struct kvm_vcpu *vcpu,
|
static int svm_get_nested_state(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_nested_state __user *user_kvm_nested_state,
|
struct kvm_nested_state __user *user_kvm_nested_state,
|
||||||
u32 user_data_size)
|
u32 user_data_size)
|
||||||
|
|
@ -1983,6 +1968,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
|
||||||
&user_kvm_nested_state->data.svm[0];
|
&user_kvm_nested_state->data.svm[0];
|
||||||
struct vmcb_control_area *ctl;
|
struct vmcb_control_area *ctl;
|
||||||
struct vmcb_save_area *save;
|
struct vmcb_save_area *save;
|
||||||
|
struct vmcb_save_area_cached save_cached;
|
||||||
struct vmcb_ctrl_area_cached ctl_cached;
|
struct vmcb_ctrl_area_cached ctl_cached;
|
||||||
bool use_separate_l2_pat;
|
bool use_separate_l2_pat;
|
||||||
unsigned long cr0;
|
unsigned long cr0;
|
||||||
|
|
@ -2054,7 +2040,12 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
|
||||||
* KVM_GET_NESTED_STATE, and (b) it is not loaded at emulated
|
* KVM_GET_NESTED_STATE, and (b) it is not loaded at emulated
|
||||||
* #VMEXIT.
|
* #VMEXIT.
|
||||||
*/
|
*/
|
||||||
if (!nested_svm_check_vmcb01_save(vcpu, save))
|
__nested_copy_vmcb_save_to_cache(&save_cached, save);
|
||||||
|
if (!(save->cr0 & X86_CR0_PG) ||
|
||||||
|
!(save->cr0 & X86_CR0_PE) ||
|
||||||
|
(save->rflags & X86_EFLAGS_VM) ||
|
||||||
|
((save->efer & EFER_LMA) && !(save->efer & EFER_LME)) ||
|
||||||
|
!nested_vmcb_check_save(vcpu, &save_cached, false))
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -5223,8 +5223,6 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
svm_copy_vmrun_state(vcpu, &svm->vmcb01.ptr->save, m_save.map.hva + 0x400);
|
svm_copy_vmrun_state(vcpu, &svm->vmcb01.ptr->save, m_save.map.hva + 0x400);
|
||||||
if (!nested_svm_check_vmcb01_save(vcpu, &svm->vmcb01.ptr->save))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter the nested guest now
|
* Enter the nested guest now
|
||||||
|
|
|
||||||
|
|
@ -911,8 +911,6 @@ void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
|
||||||
void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm,
|
void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm,
|
||||||
struct vmcb_save_area *save);
|
struct vmcb_save_area *save);
|
||||||
void nested_sync_control_from_vmcb02(struct vcpu_svm *svm);
|
void nested_sync_control_from_vmcb02(struct vcpu_svm *svm);
|
||||||
bool nested_svm_check_vmcb01_save(struct kvm_vcpu *vcpu,
|
|
||||||
struct vmcb_save_area *save);
|
|
||||||
void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb);
|
void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,6 @@ static __always_inline int evmcs_field_offset(unsigned long field,
|
||||||
if (unlikely(index >= nr_evmcs_1_fields))
|
if (unlikely(index >= nr_evmcs_1_fields))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
index = array_index_nospec(index, nr_evmcs_1_fields);
|
|
||||||
|
|
||||||
evmcs_field = &vmcs_field_to_evmcs_1[index];
|
evmcs_field = &vmcs_field_to_evmcs_1[index];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -5059,7 +5059,6 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu)
|
||||||
__func__, j, h.index, h.value);
|
__func__, j, h.index, h.value);
|
||||||
goto vmabort;
|
goto vmabort;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6558,12 +6558,10 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
|
||||||
} else if (vcpu->arch.complete_userspace_io) {
|
} else if (vcpu->arch.complete_userspace_io) {
|
||||||
writeback = false;
|
writeback = false;
|
||||||
r = 0;
|
r = 0;
|
||||||
} else if (r == EMULATION_RESTART) {
|
} else if (r == EMULATION_RESTART)
|
||||||
cond_resched();
|
|
||||||
goto restart;
|
goto restart;
|
||||||
} else {
|
else
|
||||||
r = 1;
|
r = 1;
|
||||||
}
|
|
||||||
|
|
||||||
writeback:
|
writeback:
|
||||||
if (writeback) {
|
if (writeback) {
|
||||||
|
|
@ -9732,31 +9730,29 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||||
kvm_x86_call(update_exception_bitmap)(vcpu);
|
kvm_x86_call(update_exception_bitmap)(vcpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unconditionally reset the MMU, even though super strictly speaking,
|
* On the standard CR0/CR4/EFER modification paths, there are several
|
||||||
* a MMU reset is only necessary if and only one of the page role bits
|
* complex conditions determining whether the MMU has to be reset and/or
|
||||||
* is changing. All of the CR0/CR4/EFER bits effectively get covered
|
* which PCIDs have to be flushed. However, CR0.WP and the paging-related
|
||||||
* by checking CR0.PG=1, as CR0.WP and the paging-related bits in CR4
|
* bits in CR4 and EFER are irrelevant if CR0.PG was '0'; and a reset+flush
|
||||||
* and EFER are irrelevant if CR0.PG was '0'. Subtly, if the vCPU was
|
* is needed anyway if CR0.PG was '1' (which can only happen for INIT, as
|
||||||
* in guest mode (L2) or SMM (although emulating INIT in SMM _should_
|
* CR0 will be '0' prior to RESET). So we only need to check CR0.PG here.
|
||||||
* be impossible), an MMU reset is also necessary as "guest mode" and
|
|
||||||
* "smm" are both encoded in the shadow page role. As a result, the
|
|
||||||
* only scenarios where an MMU reset is *not* needed is if the vCPU is
|
|
||||||
* in Real Mode or Unpaged Protected Mode, and micro-optimizing those
|
|
||||||
* paths are not worth the risk of running with a stale MMU context.
|
|
||||||
*/
|
*/
|
||||||
kvm_mmu_reset_context(vcpu);
|
if (old_cr0 & X86_CR0_PG) {
|
||||||
|
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
||||||
|
kvm_mmu_reset_context(vcpu);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intel's SDM states that all TLB entries are flushed on INIT "as with
|
* Intel's SDM states that all TLB entries are flushed on INIT. AMD's
|
||||||
* a hardware reset", and AMD's APM states the TLBs are flushed on
|
* APM states the TLBs are untouched by INIT, but it also states that
|
||||||
* "External initialization of the processor". Flush the guest TLB for
|
* the TLBs are flushed on "External initialization of the processor."
|
||||||
* both RESET and INIT, regardless of vendor, even though both the SDM
|
* Flush the guest TLB regardless of vendor, there is no meaningful
|
||||||
* and APM contradict the above statements in other tables. There is
|
* benefit in relying on the guest to flush the TLB immediately after
|
||||||
* no meaningful benefit in relying on the guest to flush the TLB, and
|
* INIT. A spurious TLB flush is benign and likely negligible from a
|
||||||
* a spurious TLB flush is benign and likely negligible from a
|
* performance perspective.
|
||||||
* performance perspective (especially for RESET).
|
|
||||||
*/
|
*/
|
||||||
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
if (init_event)
|
||||||
|
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_reset);
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_reset);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2626,13 +2626,8 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
|
||||||
* Arg 6 goes into r9 register, not on stack.
|
* Arg 6 goes into r9 register, not on stack.
|
||||||
*/
|
*/
|
||||||
outgoing_rsp = out_stack_arg_cnt > 1 ? (out_stack_arg_cnt - 1) * 8 : 0;
|
outgoing_rsp = out_stack_arg_cnt > 1 ? (out_stack_arg_cnt - 1) * 8 : 0;
|
||||||
/*
|
|
||||||
* bpf_throw() sees rsp of this frame as it is at a call. The callee-saved
|
|
||||||
* regs are above the outgoing args, or above r9, which is pushed around
|
|
||||||
* every call when the stack is private.
|
|
||||||
*/
|
|
||||||
if (bpf_prog->aux->exception_boundary)
|
if (bpf_prog->aux->exception_boundary)
|
||||||
bpf_prog->aux->stack_arg_sp_adjust = outgoing_rsp + (priv_frame_ptr ? 8 : 0);
|
bpf_prog->aux->stack_arg_sp_adjust = outgoing_rsp;
|
||||||
emit_sub_rsp(&prog, outgoing_rsp);
|
emit_sub_rsp(&prog, outgoing_rsp);
|
||||||
|
|
||||||
if (arena_vm_start)
|
if (arena_vm_start)
|
||||||
|
|
@ -3441,6 +3436,18 @@ static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *
|
||||||
ip += emit_kfunc_arg_moves(fm, outgoing_arg_base -
|
ip += emit_kfunc_arg_moves(fm, outgoing_arg_base -
|
||||||
outgoing_rsp, &prog);
|
outgoing_rsp, &prog);
|
||||||
}
|
}
|
||||||
|
if (func == (u8 *)arch_bpf_timed_may_goto) {
|
||||||
|
u32 fp = priv_frame_ptr ? X86_REG_R9 : BPF_REG_FP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AX has the offset of count and timestamp
|
||||||
|
* in the stack. Turn it into a pointer.
|
||||||
|
* add r10, rbp or add r10, r9
|
||||||
|
*/
|
||||||
|
maybe_emit_mod(&prog, BPF_REG_AX, fp, true);
|
||||||
|
EMIT2(0x01, add_2reg(0xC0, BPF_REG_AX, fp));
|
||||||
|
ip += 3;
|
||||||
|
}
|
||||||
if (priv_frame_ptr) {
|
if (priv_frame_ptr) {
|
||||||
push_r9(&prog);
|
push_r9(&prog);
|
||||||
ip += 2;
|
ip += 2;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,10 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
|
||||||
/* Save stack argument 6. */
|
/* Save stack argument 6. */
|
||||||
pushq %r9
|
pushq %r9
|
||||||
|
|
||||||
/* r10 has the pointer to count and timestamp. Pass it as first argument. */
|
/*
|
||||||
|
* r10 has the pointer to count and timestamp. JIT added the frame
|
||||||
|
* pointer to the offset. Pass it as first argument.
|
||||||
|
*/
|
||||||
movq %r10, %rdi
|
movq %r10, %rdi
|
||||||
|
|
||||||
/* Emit call depth accounting for call below. */
|
/* Emit call depth accounting for call below. */
|
||||||
|
|
|
||||||
|
|
@ -2936,9 +2936,6 @@ static void ioc_rqos_done(struct rq_qos *rqos, struct request *rq)
|
||||||
if (!ioc->enabled || !rq->alloc_time_ns || !rq->start_time_ns)
|
if (!ioc->enabled || !rq->alloc_time_ns || !rq->start_time_ns)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (unlikely(rq->rq_flags & RQF_FLUSH_SEQ))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (req_op(rq)) {
|
switch (req_op(rq)) {
|
||||||
case REQ_OP_READ:
|
case REQ_OP_READ:
|
||||||
pidx = QOS_RLAT;
|
pidx = QOS_RLAT;
|
||||||
|
|
|
||||||
|
|
@ -374,7 +374,7 @@ bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_mq_sched_try_insert_merge);
|
EXPORT_SYMBOL_GPL(blk_mq_sched_try_insert_merge);
|
||||||
|
|
||||||
/* Clear scheduler tags and reset queue state. */
|
/* called in queue's release handler, tagset has gone away */
|
||||||
static void blk_mq_sched_tags_teardown(struct request_queue *q, unsigned int flags)
|
static void blk_mq_sched_tags_teardown(struct request_queue *q, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct blk_mq_hw_ctx *hctx;
|
struct blk_mq_hw_ctx *hctx;
|
||||||
|
|
@ -385,10 +385,6 @@ static void blk_mq_sched_tags_teardown(struct request_queue *q, unsigned int fla
|
||||||
|
|
||||||
if (blk_mq_is_shared_tags(flags))
|
if (blk_mq_is_shared_tags(flags))
|
||||||
q->sched_shared_tags = NULL;
|
q->sched_shared_tags = NULL;
|
||||||
|
|
||||||
blk_queue_flag_clear(QUEUE_FLAG_SQ_SCHED, q);
|
|
||||||
q->nr_requests = q->tag_set->queue_depth;
|
|
||||||
q->async_depth = q->tag_set->queue_depth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void blk_mq_sched_reg_debugfs(struct request_queue *q)
|
void blk_mq_sched_reg_debugfs(struct request_queue *q)
|
||||||
|
|
|
||||||
|
|
@ -3160,15 +3160,8 @@ void blk_mq_submit_bio(struct bio *bio)
|
||||||
goto queue_exit;
|
goto queue_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* The block layer cannot generate or verify PI for a dma-buf bio, as
|
|
||||||
* that walks the data pages. Only fail the bio if it needs that, not
|
|
||||||
* if the submitter attached its own integrity payload or if PI
|
|
||||||
* generation or verification is turned off for the device.
|
|
||||||
*/
|
|
||||||
if (unlikely(op_is_dmabuf(bio->bi_opf) &&
|
if (unlikely(op_is_dmabuf(bio->bi_opf) &&
|
||||||
bdev_has_integrity_csum(bio->bi_bdev) &&
|
bdev_has_integrity_csum(bio->bi_bdev))) {
|
||||||
(bio_integrity_action(bio) & BI_ACT_CHECK))) {
|
|
||||||
bio_endio_status(bio, BLK_STS_NOTSUPP);
|
bio_endio_status(bio, BLK_STS_NOTSUPP);
|
||||||
goto queue_exit;
|
goto queue_exit;
|
||||||
}
|
}
|
||||||
|
|
@ -3216,15 +3209,16 @@ void blk_mq_submit_bio(struct bio *bio)
|
||||||
|
|
||||||
blk_mq_bio_to_request(rq, bio, nr_segs);
|
blk_mq_bio_to_request(rq, bio, nr_segs);
|
||||||
|
|
||||||
if (bio_zone_write_plugging(bio))
|
|
||||||
blk_zone_write_plug_init_request(rq);
|
|
||||||
|
|
||||||
ret = blk_crypto_rq_get_keyslot(rq);
|
ret = blk_crypto_rq_get_keyslot(rq);
|
||||||
if (ret != BLK_STS_OK) {
|
if (ret != BLK_STS_OK) {
|
||||||
blk_mq_end_request(rq, ret);
|
bio_endio_status(bio, ret);
|
||||||
|
blk_mq_free_request(rq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bio_zone_write_plugging(bio))
|
||||||
|
blk_zone_write_plug_init_request(rq);
|
||||||
|
|
||||||
if (op_is_flush(bio->bi_opf) && blk_insert_flush(rq))
|
if (op_is_flush(bio->bi_opf) && blk_insert_flush(rq))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -3507,10 +3501,8 @@ void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
|
||||||
|
|
||||||
if (blk_mq_is_shared_tags(set->flags))
|
if (blk_mq_is_shared_tags(set->flags))
|
||||||
drv_tags = set->shared_tags;
|
drv_tags = set->shared_tags;
|
||||||
else if (hctx_idx < set->nr_hw_queues)
|
|
||||||
drv_tags = set->tags[hctx_idx];
|
|
||||||
else
|
else
|
||||||
drv_tags = NULL;
|
drv_tags = set->tags[hctx_idx];
|
||||||
|
|
||||||
if (tags->static_rqs && set->ops->exit_request) {
|
if (tags->static_rqs && set->ops->exit_request) {
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -418,8 +418,6 @@ static inline bool bio_may_need_split(struct bio *bio,
|
||||||
|
|
||||||
if (!bio->bi_io_vec)
|
if (!bio->bi_io_vec)
|
||||||
return true;
|
return true;
|
||||||
if (op_is_dmabuf(bio->bi_opf))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bv = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
|
bv = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
|
||||||
if (bio->bi_iter.bi_size > bv->bv_len - bio->bi_iter.bi_offset)
|
if (bio->bi_iter.bi_size > bv->bv_len - bio->bi_iter.bi_offset)
|
||||||
|
|
|
||||||
|
|
@ -812,29 +812,25 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
||||||
* reference during concurrent disk deletion:
|
* reference during concurrent disk deletion:
|
||||||
* update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
|
* update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
|
||||||
* kn->active -> update_nr_hwq_lock (via this sysfs write path)
|
* kn->active -> update_nr_hwq_lock (via this sysfs write path)
|
||||||
|
*
|
||||||
|
* Use the writer lock instead of the reader lock of update_nr_hwq_lock
|
||||||
|
* to serialize the two-stage elevator switch steps in
|
||||||
|
* elevator_change(): the core switch step under the elevator lock and
|
||||||
|
* the elevator_change_done() step outside the elevator lock.
|
||||||
*/
|
*/
|
||||||
if (!down_read_trylock(&set->update_nr_hwq_lock)) {
|
if (!down_write_trylock(&set->update_nr_hwq_lock)) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (!blk_queue_no_elv_switch(q)) {
|
||||||
/*
|
ret = elevator_change(q, &ctx);
|
||||||
* The reader lock is shared, so use QUEUE_FLAG_NO_ELV_SWITCH to allow
|
if (!ret)
|
||||||
* only one switch of this queue at a time, and none once the disk is
|
ret = count;
|
||||||
* going away.
|
} else {
|
||||||
*/
|
ret = -ENOENT;
|
||||||
if (test_and_set_bit(QUEUE_FLAG_NO_ELV_SWITCH, &q->queue_flags)) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
}
|
||||||
|
up_write(&set->update_nr_hwq_lock);
|
||||||
|
|
||||||
ret = elevator_change(q, &ctx);
|
|
||||||
if (!ret)
|
|
||||||
ret = count;
|
|
||||||
|
|
||||||
blk_queue_flag_clear(QUEUE_FLAG_NO_ELV_SWITCH, q);
|
|
||||||
out_unlock:
|
|
||||||
up_read(&set->update_nr_hwq_lock);
|
|
||||||
out:
|
out:
|
||||||
if (ctx.type)
|
if (ctx.type)
|
||||||
elevator_put(ctx.type);
|
elevator_put(ctx.type);
|
||||||
|
|
|
||||||
|
|
@ -1018,6 +1018,8 @@ static int blkdev_init_dma_buf_io_ctx(struct file *file,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!disk->fops->init_dma_buf_io_ctx)
|
if (!disk->fops->init_dma_buf_io_ctx)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
if (bdev_has_integrity_csum(bdev))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
return disk->fops->init_dma_buf_io_ctx(bdev, ctx);
|
return disk->fops->init_dma_buf_io_ctx(bdev, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1146,7 +1146,7 @@ static ssize_t disk_discard_alignment_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct gendisk *disk = dev_to_disk(dev);
|
struct gendisk *disk = dev_to_disk(dev);
|
||||||
|
|
||||||
return sysfs_emit(buf, "%u\n", bdev_discard_alignment(disk->part0));
|
return sysfs_emit(buf, "%d\n", bdev_alignment_offset(disk->part0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t diskseq_show(struct device *dev,
|
static ssize_t diskseq_show(struct device *dev,
|
||||||
|
|
|
||||||
|
|
@ -835,8 +835,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||||
return compat_put_ulong(argp, bdev_nr_sectors(bdev));
|
return compat_put_ulong(argp, bdev_nr_sectors(bdev));
|
||||||
|
|
||||||
/* The data is compatible, but the command number is different */
|
/* The data is compatible, but the command number is different */
|
||||||
case BLKBSZGET_32: /* get the soft block size (cf. BLKSSZGET) */
|
case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
|
||||||
return put_int(argp, block_size(bdev));
|
return put_int(argp, bdev_logical_block_size(bdev));
|
||||||
case BLKBSZSET_32:
|
case BLKBSZSET_32:
|
||||||
return blkdev_bszset(file, mode, argp);
|
return blkdev_bszset(file, mode, argp);
|
||||||
case BLKGETSIZE64_32:
|
case BLKGETSIZE64_32:
|
||||||
|
|
|
||||||
|
|
@ -460,7 +460,6 @@ static inline int
|
||||||
is_pte_valid(const gpt_entry *pte, const u64 lastlba)
|
is_pte_valid(const gpt_entry *pte, const u64 lastlba)
|
||||||
{
|
{
|
||||||
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
|
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
|
||||||
le64_to_cpu(pte->starting_lba) > le64_to_cpu(pte->ending_lba) ||
|
|
||||||
le64_to_cpu(pte->starting_lba) > lastlba ||
|
le64_to_cpu(pte->starting_lba) > lastlba ||
|
||||||
le64_to_cpu(pte->ending_lba) > lastlba)
|
le64_to_cpu(pte->ending_lba) > lastlba)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -1976,7 +1976,6 @@ static int null_add_dev(struct nullb_device *dev)
|
||||||
rv = null_validate_conf(dev);
|
rv = null_validate_conf(dev);
|
||||||
if (rv)
|
if (rv)
|
||||||
return rv;
|
return rv;
|
||||||
clear_bit(NULLB_DEV_FL_CACHE, &dev->flags);
|
|
||||||
|
|
||||||
nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, dev->home_node);
|
nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, dev->home_node);
|
||||||
if (!nullb) {
|
if (!nullb) {
|
||||||
|
|
|
||||||
|
|
@ -311,8 +311,10 @@ static blk_status_t null_check_open(struct nullb_device *dev)
|
||||||
return BLK_STS_OK;
|
return BLK_STS_OK;
|
||||||
|
|
||||||
if (dev->nr_zones_imp_open) {
|
if (dev->nr_zones_imp_open) {
|
||||||
null_close_imp_open_zone(dev);
|
if (null_check_active(dev) == BLK_STS_OK) {
|
||||||
return BLK_STS_OK;
|
null_close_imp_open_zone(dev);
|
||||||
|
return BLK_STS_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLK_STS_ZONE_OPEN_RESOURCE;
|
return BLK_STS_ZONE_OPEN_RESOURCE;
|
||||||
|
|
@ -328,11 +330,8 @@ static blk_status_t null_check_open(struct nullb_device *dev)
|
||||||
*
|
*
|
||||||
* ZBC states that an implicit open zone shall be closed only if there is not
|
* ZBC states that an implicit open zone shall be closed only if there is not
|
||||||
* room within the open limit. However, with the addition of an active limit,
|
* room within the open limit. However, with the addition of an active limit,
|
||||||
* it is not certain that closing an implicit open zone will allow an empty
|
* it is not certain that closing an implicit open zone will allow a new zone
|
||||||
* zone to be opened, since we might already be at the active limit capacity.
|
* to be opened, since we might already be at the active limit capacity.
|
||||||
* Therefore, the active limit is checked first for an empty zone. A closed
|
|
||||||
* zone already holds an active zone resource, so only the open limit has to
|
|
||||||
* be checked for a closed zone.
|
|
||||||
*/
|
*/
|
||||||
static blk_status_t null_check_zone_resources(struct nullb_device *dev,
|
static blk_status_t null_check_zone_resources(struct nullb_device *dev,
|
||||||
struct nullb_zone *zone)
|
struct nullb_zone *zone)
|
||||||
|
|
@ -744,47 +743,23 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release the zone resources held by a zone, before changing the condition of
|
* Set a zone in the read-only or offline condition.
|
||||||
* the zone to a condition that does not hold any zone resources.
|
|
||||||
*/
|
*/
|
||||||
static void null_release_zone_resources(struct nullb_device *dev,
|
static void null_set_zone_cond(struct nullb_device *dev,
|
||||||
struct nullb_zone *zone)
|
struct nullb_zone *zone, enum blk_zone_cond cond)
|
||||||
{
|
{
|
||||||
if (!dev->need_zone_res_mgmt)
|
if (WARN_ON_ONCE(cond != BLK_ZONE_COND_READONLY &&
|
||||||
|
cond != BLK_ZONE_COND_OFFLINE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock(&dev->zone_res_lock);
|
|
||||||
switch (zone->cond) {
|
|
||||||
case BLK_ZONE_COND_IMP_OPEN:
|
|
||||||
dev->nr_zones_imp_open--;
|
|
||||||
break;
|
|
||||||
case BLK_ZONE_COND_EXP_OPEN:
|
|
||||||
dev->nr_zones_exp_open--;
|
|
||||||
break;
|
|
||||||
case BLK_ZONE_COND_CLOSED:
|
|
||||||
dev->nr_zones_closed--;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
spin_unlock(&dev->zone_res_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void null_set_zone_readonly_or_offline(struct nullb_device *dev,
|
|
||||||
struct nullb_zone *zone,
|
|
||||||
bool set_offline)
|
|
||||||
{
|
|
||||||
enum blk_zone_cond cond =
|
|
||||||
set_offline ? BLK_ZONE_COND_OFFLINE : BLK_ZONE_COND_READONLY;
|
|
||||||
|
|
||||||
null_lock_zone(dev, zone);
|
null_lock_zone(dev, zone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the read-only condition is requested again to zones already in
|
* If the read-only condition is requested again to zones already in
|
||||||
* read-only condition, restore back normal empty condition. Do the same
|
* read-only condition, restore back normal empty condition. Do the same
|
||||||
* if the offline condition is requested for offline zones. Otherwise,
|
* if the offline condition is requested for offline zones. Otherwise,
|
||||||
* set the specified zone condition to the zones. Release the zone
|
* set the specified zone condition to the zones. Finish the zones
|
||||||
* resources held by the zones beforehand.
|
* beforehand to free up zone resources.
|
||||||
*/
|
*/
|
||||||
if (zone->cond == cond) {
|
if (zone->cond == cond) {
|
||||||
zone->cond = BLK_ZONE_COND_EMPTY;
|
zone->cond = BLK_ZONE_COND_EMPTY;
|
||||||
|
|
@ -792,7 +767,9 @@ static void null_set_zone_readonly_or_offline(struct nullb_device *dev,
|
||||||
if (dev->memory_backed)
|
if (dev->memory_backed)
|
||||||
null_handle_discard(dev, zone->start, zone->len);
|
null_handle_discard(dev, zone->start, zone->len);
|
||||||
} else {
|
} else {
|
||||||
null_release_zone_resources(dev, zone);
|
if (zone->cond != BLK_ZONE_COND_READONLY &&
|
||||||
|
zone->cond != BLK_ZONE_COND_OFFLINE)
|
||||||
|
null_finish_zone(dev, zone);
|
||||||
zone->cond = cond;
|
zone->cond = cond;
|
||||||
zone->wp = NULL_ZONE_INVALID_WP;
|
zone->wp = NULL_ZONE_INVALID_WP;
|
||||||
}
|
}
|
||||||
|
|
@ -811,11 +788,6 @@ ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
|
||||||
unsigned int zone_no;
|
unsigned int zone_no;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Read-only and offline are the only conditions supported for now */
|
|
||||||
if (WARN_ON_ONCE(cond != BLK_ZONE_COND_READONLY &&
|
|
||||||
cond != BLK_ZONE_COND_OFFLINE))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!dev->zoned) {
|
if (!dev->zoned) {
|
||||||
pr_err("null_blk device is not zoned\n");
|
pr_err("null_blk device is not zoned\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -841,8 +813,7 @@ ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
null_set_zone_readonly_or_offline(dev, &dev->zones[zone_no],
|
null_set_zone_cond(dev, &dev->zones[zone_no], cond);
|
||||||
cond == BLK_ZONE_COND_OFFLINE);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5878,7 +5878,6 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
|
||||||
case UBLK_CMD_STOP_DEV:
|
case UBLK_CMD_STOP_DEV:
|
||||||
case UBLK_CMD_ADD_DEV:
|
case UBLK_CMD_ADD_DEV:
|
||||||
case UBLK_CMD_DEL_DEV:
|
case UBLK_CMD_DEL_DEV:
|
||||||
case UBLK_CMD_DEL_DEV_ASYNC:
|
|
||||||
case UBLK_CMD_SET_PARAMS:
|
case UBLK_CMD_SET_PARAMS:
|
||||||
case UBLK_CMD_START_USER_RECOVERY:
|
case UBLK_CMD_START_USER_RECOVERY:
|
||||||
case UBLK_CMD_END_USER_RECOVERY:
|
case UBLK_CMD_END_USER_RECOVERY:
|
||||||
|
|
|
||||||
|
|
@ -331,25 +331,18 @@ static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
|
||||||
return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
|
return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void virtblk_update_zone_append_sector(struct request *req,
|
|
||||||
struct virtblk_req *vbr)
|
|
||||||
{
|
|
||||||
struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
|
|
||||||
|
|
||||||
if (req_op(req) == REQ_OP_ZONE_APPEND)
|
|
||||||
req->__sector = virtio64_to_cpu(vblk->vdev,
|
|
||||||
vbr->in_hdr.zone_append.sector);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void virtblk_request_done(struct request *req)
|
static inline void virtblk_request_done(struct request *req)
|
||||||
{
|
{
|
||||||
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
|
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
|
||||||
blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
|
blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
|
||||||
|
struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
|
||||||
|
|
||||||
virtblk_unmap_data(req, vbr);
|
virtblk_unmap_data(req, vbr);
|
||||||
virtblk_cleanup_cmd(req);
|
virtblk_cleanup_cmd(req);
|
||||||
|
|
||||||
virtblk_update_zone_append_sector(req, vbr);
|
if (req_op(req) == REQ_OP_ZONE_APPEND)
|
||||||
|
req->__sector = virtio64_to_cpu(vblk->vdev,
|
||||||
|
vbr->in_hdr.zone_append.sector);
|
||||||
|
|
||||||
blk_mq_end_request(req, status);
|
blk_mq_end_request(req, status);
|
||||||
}
|
}
|
||||||
|
|
@ -965,13 +958,16 @@ static void virtblk_config_changed(struct virtio_device *vdev)
|
||||||
queue_work(virtblk_wq, &vblk->config_work);
|
queue_work(virtblk_wq, &vblk->config_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the queue layout unchanged for the lifetime of the tag set. */
|
static int init_vq(struct virtio_blk *vblk)
|
||||||
static int virtblk_init_queue_layout(struct virtio_blk *vblk)
|
|
||||||
{
|
{
|
||||||
struct virtio_device *vdev = vblk->vdev;
|
int err;
|
||||||
|
unsigned short i;
|
||||||
|
struct virtqueue_info *vqs_info;
|
||||||
|
struct virtqueue **vqs;
|
||||||
unsigned short num_vqs;
|
unsigned short num_vqs;
|
||||||
unsigned short num_poll_vqs;
|
unsigned short num_poll_vqs;
|
||||||
int err;
|
struct virtio_device *vdev = vblk->vdev;
|
||||||
|
struct irq_affinity desc = { 0, };
|
||||||
|
|
||||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ,
|
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ,
|
||||||
struct virtio_blk_config, num_queues,
|
struct virtio_blk_config, num_queues,
|
||||||
|
|
@ -989,7 +985,6 @@ static int virtblk_init_queue_layout(struct virtio_blk *vblk)
|
||||||
|
|
||||||
num_poll_vqs = min_t(unsigned int, poll_queues, num_vqs - 1);
|
num_poll_vqs = min_t(unsigned int, poll_queues, num_vqs - 1);
|
||||||
|
|
||||||
vblk->num_vqs = num_vqs;
|
|
||||||
vblk->io_queues[HCTX_TYPE_DEFAULT] = num_vqs - num_poll_vqs;
|
vblk->io_queues[HCTX_TYPE_DEFAULT] = num_vqs - num_poll_vqs;
|
||||||
vblk->io_queues[HCTX_TYPE_READ] = 0;
|
vblk->io_queues[HCTX_TYPE_READ] = 0;
|
||||||
vblk->io_queues[HCTX_TYPE_POLL] = num_poll_vqs;
|
vblk->io_queues[HCTX_TYPE_POLL] = num_poll_vqs;
|
||||||
|
|
@ -999,20 +994,6 @@ static int virtblk_init_queue_layout(struct virtio_blk *vblk)
|
||||||
vblk->io_queues[HCTX_TYPE_READ],
|
vblk->io_queues[HCTX_TYPE_READ],
|
||||||
vblk->io_queues[HCTX_TYPE_POLL]);
|
vblk->io_queues[HCTX_TYPE_POLL]);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init_vq(struct virtio_blk *vblk)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
unsigned short i;
|
|
||||||
struct virtqueue_info *vqs_info;
|
|
||||||
struct virtqueue **vqs;
|
|
||||||
unsigned short num_vqs = vblk->num_vqs;
|
|
||||||
unsigned short num_poll_vqs = vblk->io_queues[HCTX_TYPE_POLL];
|
|
||||||
struct virtio_device *vdev = vblk->vdev;
|
|
||||||
struct irq_affinity desc = { 0, };
|
|
||||||
|
|
||||||
vblk->vqs = kmalloc_objs(*vblk->vqs, num_vqs);
|
vblk->vqs = kmalloc_objs(*vblk->vqs, num_vqs);
|
||||||
if (!vblk->vqs)
|
if (!vblk->vqs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
@ -1041,33 +1022,10 @@ static int init_vq(struct virtio_blk *vblk)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i < num_vqs; i++) {
|
for (i = 0; i < num_vqs; i++) {
|
||||||
unsigned int ring_size = virtqueue_get_vring_size(vqs[i]);
|
|
||||||
/*
|
|
||||||
* Each request consumes 2 extra descriptors (out_hdr and
|
|
||||||
* in_hdr) in addition to the data segments.
|
|
||||||
*
|
|
||||||
* At initial probe (!vblk->disk), each virtqueue must fit at
|
|
||||||
* least 1 data segment + 2 header descriptors (3).
|
|
||||||
* On resume/recovery (vblk->disk), each virtqueue must fit the
|
|
||||||
* existing queue_max_segments() + 2 header descriptors.
|
|
||||||
*/
|
|
||||||
unsigned int min_ring_size = 3;
|
|
||||||
|
|
||||||
if (vblk->disk)
|
|
||||||
min_ring_size = queue_max_segments(vblk->disk->queue) + 2;
|
|
||||||
|
|
||||||
if (ring_size < min_ring_size) {
|
|
||||||
dev_err(&vdev->dev,
|
|
||||||
"virtqueue %u ring size %u is smaller than minimum %u\n",
|
|
||||||
i, ring_size, min_ring_size);
|
|
||||||
vdev->config->del_vqs(vdev);
|
|
||||||
err = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_init(&vblk->vqs[i].lock);
|
spin_lock_init(&vblk->vqs[i].lock);
|
||||||
vblk->vqs[i].vq = vqs[i];
|
vblk->vqs[i].vq = vqs[i];
|
||||||
}
|
}
|
||||||
|
vblk->num_vqs = num_vqs;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(vqs);
|
kfree(vqs);
|
||||||
|
|
@ -1238,11 +1196,8 @@ static void virtblk_complete_batch(struct io_comp_batch *iob)
|
||||||
struct request *req;
|
struct request *req;
|
||||||
|
|
||||||
rq_list_for_each(&iob->req_list, req) {
|
rq_list_for_each(&iob->req_list, req) {
|
||||||
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
|
virtblk_unmap_data(req, blk_mq_rq_to_pdu(req));
|
||||||
|
|
||||||
virtblk_unmap_data(req, vbr);
|
|
||||||
virtblk_cleanup_cmd(req);
|
virtblk_cleanup_cmd(req);
|
||||||
virtblk_update_zone_append_sector(req, vbr);
|
|
||||||
}
|
}
|
||||||
blk_mq_end_request_batch(iob);
|
blk_mq_end_request_batch(iob);
|
||||||
}
|
}
|
||||||
|
|
@ -1299,7 +1254,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk,
|
||||||
u16 min_io_size;
|
u16 min_io_size;
|
||||||
u8 physical_block_exp, alignment_offset;
|
u8 physical_block_exp, alignment_offset;
|
||||||
size_t max_dma_size;
|
size_t max_dma_size;
|
||||||
int err, i;
|
int err;
|
||||||
|
|
||||||
/* We need to know how many segments before we allocate. */
|
/* We need to know how many segments before we allocate. */
|
||||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
|
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
|
||||||
|
|
@ -1313,23 +1268,6 @@ static int virtblk_read_limits(struct virtio_blk *vblk,
|
||||||
/* Prevent integer overflows and honor max vq size */
|
/* Prevent integer overflows and honor max vq size */
|
||||||
sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
|
sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
|
||||||
|
|
||||||
/*
|
|
||||||
* virtblk_add_req() uses separate outgoing and incoming header
|
|
||||||
* descriptors (out_hdr and in_hdr), consuming 2 extra descriptors
|
|
||||||
* per request in addition to the data segments.
|
|
||||||
*
|
|
||||||
* Per virtio specification (2.7.5.3.1), a driver MUST NOT create a
|
|
||||||
* descriptor chain longer than the Queue Size of the device.
|
|
||||||
*
|
|
||||||
* Clamp max_segments to (ring_size - 2) across all virtqueues so
|
|
||||||
* that a request never exceeds the ring size of any queue.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < vblk->num_vqs; i++) {
|
|
||||||
u32 ring_size = virtqueue_get_vring_size(vblk->vqs[i].vq);
|
|
||||||
|
|
||||||
sg_elems = min_t(u32, sg_elems, ring_size - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We can handle whatever the host told us to handle. */
|
/* We can handle whatever the host told us to handle. */
|
||||||
lim->max_segments = sg_elems;
|
lim->max_segments = sg_elems;
|
||||||
|
|
||||||
|
|
@ -1529,14 +1467,9 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||||
mutex_init(&vblk->vdev_mutex);
|
mutex_init(&vblk->vdev_mutex);
|
||||||
|
|
||||||
vblk->vdev = vdev;
|
vblk->vdev = vdev;
|
||||||
vblk->disk = NULL;
|
|
||||||
|
|
||||||
INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
|
INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
|
||||||
|
|
||||||
err = virtblk_init_queue_layout(vblk);
|
|
||||||
if (err)
|
|
||||||
goto out_free_vblk;
|
|
||||||
|
|
||||||
err = init_vq(vblk);
|
err = init_vq(vblk);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_free_vblk;
|
goto out_free_vblk;
|
||||||
|
|
@ -1615,7 +1548,6 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_cleanup_disk:
|
out_cleanup_disk:
|
||||||
virtio_reset_device(vdev);
|
|
||||||
put_disk(vblk->disk);
|
put_disk(vblk->disk);
|
||||||
out_free_tags:
|
out_free_tags:
|
||||||
blk_mq_free_tag_set(&vblk->tag_set);
|
blk_mq_free_tag_set(&vblk->tag_set);
|
||||||
|
|
@ -1664,7 +1596,7 @@ static int virtblk_freeze_priv(struct virtio_device *vdev)
|
||||||
|
|
||||||
/* Ensure no requests in virtqueues before deleting vqs. */
|
/* Ensure no requests in virtqueues before deleting vqs. */
|
||||||
memflags = blk_mq_freeze_queue(q);
|
memflags = blk_mq_freeze_queue(q);
|
||||||
blk_mq_quiesce_queue(q);
|
blk_mq_quiesce_queue_nowait(q);
|
||||||
blk_mq_unfreeze_queue(q, memflags);
|
blk_mq_unfreeze_queue(q, memflags);
|
||||||
|
|
||||||
/* Ensure we don't receive any more interrupts */
|
/* Ensure we don't receive any more interrupts */
|
||||||
|
|
|
||||||
|
|
@ -318,10 +318,8 @@ struct xen_blkif {
|
||||||
unsigned int nr_ring_pages;
|
unsigned int nr_ring_pages;
|
||||||
bool multi_ref;
|
bool multi_ref;
|
||||||
/* All rings for this device. */
|
/* All rings for this device. */
|
||||||
rwlock_t rings_lock;
|
|
||||||
struct xen_blkif_ring *rings;
|
struct xen_blkif_ring *rings;
|
||||||
unsigned int nr_rings;
|
unsigned int nr_rings;
|
||||||
|
|
||||||
unsigned long buffer_squeeze_end;
|
unsigned long buffer_squeeze_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,23 +127,14 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xen_blkif_alloc_rings(struct xen_blkif *blkif,
|
static int xen_blkif_alloc_rings(struct xen_blkif *blkif)
|
||||||
unsigned int nr_rings)
|
|
||||||
{
|
{
|
||||||
unsigned int r;
|
unsigned int r;
|
||||||
struct xen_blkif_ring *rings;
|
|
||||||
|
|
||||||
rings = kzalloc_objs(struct xen_blkif_ring, nr_rings);
|
blkif->rings = kzalloc_objs(struct xen_blkif_ring, blkif->nr_rings);
|
||||||
if (!rings)
|
if (!blkif->rings)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
write_lock(&blkif->rings_lock);
|
|
||||||
|
|
||||||
blkif->rings = rings;
|
|
||||||
blkif->nr_rings = nr_rings;
|
|
||||||
|
|
||||||
write_unlock(&blkif->rings_lock);
|
|
||||||
|
|
||||||
for (r = 0; r < blkif->nr_rings; r++) {
|
for (r = 0; r < blkif->nr_rings; r++) {
|
||||||
struct xen_blkif_ring *ring = &blkif->rings[r];
|
struct xen_blkif_ring *ring = &blkif->rings[r];
|
||||||
|
|
||||||
|
|
@ -183,7 +174,6 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
|
||||||
blkif->domid = domid;
|
blkif->domid = domid;
|
||||||
atomic_set(&blkif->refcnt, 1);
|
atomic_set(&blkif->refcnt, 1);
|
||||||
init_completion(&blkif->drain_complete);
|
init_completion(&blkif->drain_complete);
|
||||||
rwlock_init(&blkif->rings_lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Because freeing back to the cache may be deferred, it is not
|
* Because freeing back to the cache may be deferred, it is not
|
||||||
|
|
@ -278,7 +268,6 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
|
||||||
struct pending_req *req, *n;
|
struct pending_req *req, *n;
|
||||||
unsigned int j, r;
|
unsigned int j, r;
|
||||||
bool busy = false;
|
bool busy = false;
|
||||||
struct xen_blkif_ring *rings;
|
|
||||||
|
|
||||||
for (r = 0; r < blkif->nr_rings; r++) {
|
for (r = 0; r < blkif->nr_rings; r++) {
|
||||||
struct xen_blkif_ring *ring = &blkif->rings[r];
|
struct xen_blkif_ring *ring = &blkif->rings[r];
|
||||||
|
|
@ -345,16 +334,10 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
|
||||||
* blkif->rings was allocated in connect_ring, so we should free it in
|
* blkif->rings was allocated in connect_ring, so we should free it in
|
||||||
* here.
|
* here.
|
||||||
*/
|
*/
|
||||||
write_lock(&blkif->rings_lock);
|
kfree(blkif->rings);
|
||||||
|
|
||||||
rings = blkif->rings;
|
|
||||||
blkif->rings = NULL;
|
blkif->rings = NULL;
|
||||||
blkif->nr_rings = 0;
|
blkif->nr_rings = 0;
|
||||||
|
|
||||||
write_unlock(&blkif->rings_lock);
|
|
||||||
|
|
||||||
kfree(rings);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,7 +385,6 @@ void xen_blkif_interface_fini(void)
|
||||||
unsigned int i; \
|
unsigned int i; \
|
||||||
unsigned long long result = 0; \
|
unsigned long long result = 0; \
|
||||||
\
|
\
|
||||||
read_lock(&blkif->rings_lock); \
|
|
||||||
if (!blkif->rings) \
|
if (!blkif->rings) \
|
||||||
goto out; \
|
goto out; \
|
||||||
\
|
\
|
||||||
|
|
@ -413,7 +395,6 @@ void xen_blkif_interface_fini(void)
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
out: \
|
out: \
|
||||||
read_unlock(&blkif->rings_lock); \
|
|
||||||
return sprintf(buf, format, result); \
|
return sprintf(buf, format, result); \
|
||||||
} \
|
} \
|
||||||
static DEVICE_ATTR(name, 0444, show_##name, NULL)
|
static DEVICE_ATTR(name, 0444, show_##name, NULL)
|
||||||
|
|
@ -1121,7 +1102,8 @@ static int connect_ring(struct backend_info *be)
|
||||||
requested_num_queues, xenblk_max_queues);
|
requested_num_queues, xenblk_max_queues);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
if (xen_blkif_alloc_rings(blkif, requested_num_queues))
|
blkif->nr_rings = requested_num_queues;
|
||||||
|
if (xen_blkif_alloc_rings(blkif))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pr_info("%s: using %d queues, protocol %d (%s) %s\n", dev->nodename,
|
pr_info("%s: using %d queues, protocol %d (%s) %s\n", dev->nodename,
|
||||||
|
|
|
||||||
|
|
@ -1137,7 +1137,7 @@ static int zloop_init_zone(struct zloop_device *zlo, struct zloop_options *opts,
|
||||||
goto out_fput;
|
goto out_fput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!zlo->block_size) {
|
if (zlo->block_size) {
|
||||||
ret = zloop_get_block_size(zlo, zone);
|
ret = zloop_get_block_size(zlo, zone);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_fput;
|
goto out_fput;
|
||||||
|
|
@ -1161,8 +1161,7 @@ static int zloop_init_zone(struct zloop_device *zlo, struct zloop_options *opts,
|
||||||
|
|
||||||
if (restore && file_sectors != zlo->zone_size) {
|
if (restore && file_sectors != zlo->zone_size) {
|
||||||
pr_err("Invalid conventional zone %u file size (%llu sectors != %llu)\n",
|
pr_err("Invalid conventional zone %u file size (%llu sectors != %llu)\n",
|
||||||
zone_no, file_sectors, zlo->zone_size);
|
zone_no, file_sectors, zlo->zone_capacity);
|
||||||
ret = -EINVAL;
|
|
||||||
goto out_fput;
|
goto out_fput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1340,8 +1339,8 @@ static int zloop_ctl_add(struct zloop_options *opts)
|
||||||
|
|
||||||
zlo->disk = blk_mq_alloc_disk(&zlo->tag_set, &lim, zlo);
|
zlo->disk = blk_mq_alloc_disk(&zlo->tag_set, &lim, zlo);
|
||||||
if (IS_ERR(zlo->disk)) {
|
if (IS_ERR(zlo->disk)) {
|
||||||
ret = PTR_ERR(zlo->disk);
|
|
||||||
pr_err("blk_mq_alloc_disk failed (err=%d)\n", ret);
|
pr_err("blk_mq_alloc_disk failed (err=%d)\n", ret);
|
||||||
|
ret = PTR_ERR(zlo->disk);
|
||||||
goto out_cleanup_tags;
|
goto out_cleanup_tags;
|
||||||
}
|
}
|
||||||
zlo->disk->flags = GENHD_FL_NO_PART;
|
zlo->disk->flags = GENHD_FL_NO_PART;
|
||||||
|
|
|
||||||
|
|
@ -1201,29 +1201,7 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
while (fw_ptr - fw->data < fw->size) {
|
while (fw_ptr - fw->data < fw->size) {
|
||||||
struct hci_command_hdr *cmd;
|
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||||
size_t remain = fw->size - (fw_ptr - fw->data);
|
|
||||||
|
|
||||||
/* Ensure the header fits before dereferencing */
|
|
||||||
if (frag_len + sizeof(*cmd) > remain) {
|
|
||||||
bt_dev_err(hdev,
|
|
||||||
"Firmware buffer overrun at header (frag_len %u, need %zu, remain %zu)",
|
|
||||||
frag_len, frag_len + sizeof(*cmd), remain);
|
|
||||||
err = -EINVAL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd = (void *)(fw_ptr + frag_len);
|
|
||||||
|
|
||||||
/* Ensure the full command (header + payload) fits before use */
|
|
||||||
if (frag_len + sizeof(*cmd) + cmd->plen > remain) {
|
|
||||||
bt_dev_err(hdev,
|
|
||||||
"Firmware buffer overrun at payload (frag_len %u, plen %u, need %zu, remain %zu)",
|
|
||||||
frag_len, cmd->plen,
|
|
||||||
frag_len + sizeof(*cmd) + cmd->plen, remain);
|
|
||||||
err = -EINVAL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
frag_len += sizeof(*cmd) + cmd->plen;
|
frag_len += sizeof(*cmd) + cmd->plen;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
#include <linux/overflow.h>
|
#include <linux/overflow.h>
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/unaligned.h>
|
#include <linux/unaligned.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
|
|
@ -31,7 +30,7 @@
|
||||||
#define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1
|
#define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1
|
||||||
|
|
||||||
/* It is for mt79xx iso data transmission setting */
|
/* It is for mt79xx iso data transmission setting */
|
||||||
#define MTK_ISO_THRESHOLD 342
|
#define MTK_ISO_THRESHOLD 264
|
||||||
|
|
||||||
struct btmtk_patch_header {
|
struct btmtk_patch_header {
|
||||||
u8 datetime[16];
|
u8 datetime[16];
|
||||||
|
|
@ -1557,15 +1556,8 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
|
||||||
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int iso_mtu;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* The controller reports the largest Data_Total_Length it will send in
|
|
||||||
* LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that
|
|
||||||
* command has not completed yet.
|
|
||||||
*/
|
|
||||||
iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&btmtk_data->isorxlock, flags);
|
spin_lock_irqsave(&btmtk_data->isorxlock, flags);
|
||||||
skb = btmtk_data->isopkt_skb;
|
skb = btmtk_data->isopkt_skb;
|
||||||
|
|
||||||
|
|
@ -1573,16 +1565,7 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
/* Drop the endpoint's zero-filled padding before
|
skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC);
|
||||||
* allocating an skb for it; a zero Data_Total_Length
|
|
||||||
* check below would miss a padding remainder
|
|
||||||
* shorter than an ISO header.
|
|
||||||
*/
|
|
||||||
if (mem_is_zero(buffer, count))
|
|
||||||
break;
|
|
||||||
|
|
||||||
skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu,
|
|
||||||
GFP_ATOMIC);
|
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1605,24 +1588,7 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
|
||||||
/* Complete ISO header */
|
/* Complete ISO header */
|
||||||
hci_skb_expect(skb) = __le16_to_cpu(dlen);
|
hci_skb_expect(skb) = __le16_to_cpu(dlen);
|
||||||
|
|
||||||
if (!hci_skb_expect(skb)) {
|
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
|
||||||
/* Zero padding was ruled out above, so a
|
|
||||||
* zero Data_Total_Length here is invalid.
|
|
||||||
*/
|
|
||||||
kfree_skb(skb);
|
|
||||||
skb = NULL;
|
|
||||||
|
|
||||||
err = -EILSEQ;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reject a length the controller said it would never
|
|
||||||
* send. The skb_tailroom() test is kept because a
|
|
||||||
* fragment started before hdev->iso_mtu was populated
|
|
||||||
* sits in a smaller skb than iso_mtu now allows.
|
|
||||||
*/
|
|
||||||
if (hci_skb_expect(skb) > iso_mtu ||
|
|
||||||
skb_tailroom(skb) < hci_skb_expect(skb)) {
|
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
skb = NULL;
|
skb = NULL;
|
||||||
|
|
||||||
|
|
@ -1741,15 +1707,13 @@ static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||||
static int btmtk_usb_isointf_init(struct hci_dev *hdev)
|
static int btmtk_usb_isointf_init(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
||||||
__le16 iso_param = cpu_to_le16(MTK_ISO_THRESHOLD);
|
u8 iso_param[2] = { 0x08, 0x01 };
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
spin_lock_init(&btmtk_data->isorxlock);
|
spin_lock_init(&btmtk_data->isorxlock);
|
||||||
|
|
||||||
err = __set_mtk_intr_interface(hdev);
|
__set_mtk_intr_interface(hdev);
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = btmtk_submit_intr_urb(hdev, GFP_KERNEL);
|
err = btmtk_submit_intr_urb(hdev, GFP_KERNEL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
@ -1758,10 +1722,9 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param,
|
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param,
|
||||||
HCI_INIT_TIMEOUT);
|
HCI_INIT_TIMEOUT);
|
||||||
if (IS_ERR(skb)) {
|
if (IS_ERR(skb)) {
|
||||||
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
|
|
||||||
bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb));
|
bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb));
|
||||||
return PTR_ERR(skb);
|
return PTR_ERR(skb);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -426,8 +426,7 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
|
||||||
tlv_nvm->data[0] |= 0x80;
|
tlv_nvm->data[0] |= 0x80;
|
||||||
|
|
||||||
/* UART Baud Rate */
|
/* UART Baud Rate */
|
||||||
if (soc_type == QCA_WCN3950 ||
|
if (soc_type >= QCA_WCN3991)
|
||||||
soc_type >= QCA_WCN3991)
|
|
||||||
tlv_nvm->data[1] = nvm_baud_rate;
|
tlv_nvm->data[1] = nvm_baud_rate;
|
||||||
else
|
else
|
||||||
tlv_nvm->data[2] = nvm_baud_rate;
|
tlv_nvm->data[2] = nvm_baud_rate;
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,6 @@ static int probe_common(struct virtio_device *vdev)
|
||||||
err_find:
|
err_find:
|
||||||
ida_free(&rng_index_ida, index);
|
ida_free(&rng_index_ida, index);
|
||||||
err_ida:
|
err_ida:
|
||||||
vdev->priv = NULL;
|
|
||||||
kfree(vi);
|
kfree(vi);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -199,11 +198,6 @@ static void remove_common(struct virtio_device *vdev)
|
||||||
{
|
{
|
||||||
struct virtrng_info *vi = vdev->priv;
|
struct virtrng_info *vi = vdev->priv;
|
||||||
|
|
||||||
if (!vi) {
|
|
||||||
virtio_reset_device(vdev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vi->hwrng_removed = true;
|
vi->hwrng_removed = true;
|
||||||
vi->data_avail = 0;
|
vi->data_avail = 0;
|
||||||
vi->data_idx = 0;
|
vi->data_idx = 0;
|
||||||
|
|
@ -213,7 +207,6 @@ static void remove_common(struct virtio_device *vdev)
|
||||||
virtio_reset_device(vdev);
|
virtio_reset_device(vdev);
|
||||||
vdev->config->del_vqs(vdev);
|
vdev->config->del_vqs(vdev);
|
||||||
ida_free(&rng_index_ida, vi->index);
|
ida_free(&rng_index_ida, vi->index);
|
||||||
vdev->priv = NULL;
|
|
||||||
kfree(vi);
|
kfree(vi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ static int coreboot_cfr_read_value(const struct coreboot_cfr_setting *setting,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (IS_ERR(efi_name))
|
if (IS_ERR(efi_name))
|
||||||
return PTR_ERR(efi_name);
|
return PTR_ERR(no_free_ptr(efi_name));
|
||||||
|
|
||||||
ret = efivar_lock();
|
ret = efivar_lock();
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
||||||
|
|
@ -114,30 +114,6 @@ void coreboot_driver_unregister(struct coreboot_driver *driver)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(coreboot_driver_unregister);
|
EXPORT_SYMBOL(coreboot_driver_unregister);
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether the memory of a CBMEM entry may be mapped: it must be exclusively
|
|
||||||
* System RAM, or exclusively Reserved memory, as CBMEM often is on x86, or
|
|
||||||
* memory that the kernel doesn't know about at all. coreboot leaves CBMEM out
|
|
||||||
* of the /memory node of the device tree that it passes to FIT payloads, e.g.
|
|
||||||
* on arm64, and only lists it in the memory reservation block.
|
|
||||||
*
|
|
||||||
* Anything else, such as no-map regions on arm64, which are IORESOURCE_MEM
|
|
||||||
* (see request_standard_resources() in arch/arm64/kernel/setup.c), must not
|
|
||||||
* be mapped.
|
|
||||||
*/
|
|
||||||
static bool cbmem_entry_is_mappable(const struct lb_cbmem_entry *entry)
|
|
||||||
{
|
|
||||||
resource_size_t start = entry->address;
|
|
||||||
size_t size = entry->entry_size;
|
|
||||||
|
|
||||||
return region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
|
|
||||||
IORES_DESC_NONE) == REGION_INTERSECTS ||
|
|
||||||
region_intersects(start, size, IORESOURCE_MEM,
|
|
||||||
IORES_DESC_RESERVED) == REGION_INTERSECTS ||
|
|
||||||
region_intersects(start, size, IORESOURCE_MEM,
|
|
||||||
IORES_DESC_NONE) == REGION_DISJOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_t len)
|
static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_t len)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
@ -173,7 +149,23 @@ static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_
|
||||||
|
|
||||||
switch (device->entry.tag) {
|
switch (device->entry.tag) {
|
||||||
case LB_TAG_CBMEM_ENTRY:
|
case LB_TAG_CBMEM_ENTRY:
|
||||||
if (!cbmem_entry_is_mappable(&device->cbmem_entry)) {
|
/*
|
||||||
|
* Skip entries that are not exclusively System RAM or
|
||||||
|
* Reserved memory.
|
||||||
|
* On ARM64, no-map regions are filtered out as they are
|
||||||
|
* IORESOURCE_MEM (see request_standard_resources() in
|
||||||
|
* arch/arm64/kernel/setup.c).
|
||||||
|
* On x86, CBMEM often resides in standard reserved regions
|
||||||
|
* (IORES_DESC_RESERVED).
|
||||||
|
*/
|
||||||
|
if (region_intersects(device->cbmem_entry.address,
|
||||||
|
device->cbmem_entry.entry_size,
|
||||||
|
IORESOURCE_SYSTEM_RAM,
|
||||||
|
IORES_DESC_NONE) != REGION_INTERSECTS &&
|
||||||
|
region_intersects(device->cbmem_entry.address,
|
||||||
|
device->cbmem_entry.entry_size,
|
||||||
|
IORESOURCE_MEM,
|
||||||
|
IORES_DESC_RESERVED) != REGION_INTERSECTS) {
|
||||||
kfree(device);
|
kfree(device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,7 @@ struct amdgpu_watchdog_timer {
|
||||||
* Modules parameters.
|
* Modules parameters.
|
||||||
*/
|
*/
|
||||||
extern int amdgpu_modeset;
|
extern int amdgpu_modeset;
|
||||||
|
extern int amdgpu_iommu_perfopt;
|
||||||
extern unsigned int amdgpu_vram_limit;
|
extern unsigned int amdgpu_vram_limit;
|
||||||
extern int amdgpu_vis_vram_limit;
|
extern int amdgpu_vis_vram_limit;
|
||||||
extern int amdgpu_gart_size;
|
extern int amdgpu_gart_size;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
|
#include <linux/amd-iommu.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/pci-p2pdma.h>
|
#include <linux/pci-p2pdma.h>
|
||||||
#include <linux/apple-gmux.h>
|
#include <linux/apple-gmux.h>
|
||||||
|
|
@ -3769,6 +3770,28 @@ amdgpu_device_should_register_switcheroo(struct amdgpu_device *adev, bool px)
|
||||||
apple_gmux_detect(NULL, NULL)));
|
apple_gmux_detect(NULL, NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool amdgpu_device_identity(struct amdgpu_device *adev)
|
||||||
|
{
|
||||||
|
struct pci_dev *pdev = adev->pdev;
|
||||||
|
struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
|
||||||
|
|
||||||
|
if (!domain)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return domain->type == IOMMU_DOMAIN_IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amdgpu_device_use_perfopt(struct amdgpu_device *adev)
|
||||||
|
{
|
||||||
|
if (amdgpu_iommu_perfopt == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(adev->flags & AMD_IS_APU))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return amdgpu_device_identity(adev);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* amdgpu_device_init - initialize the driver
|
* amdgpu_device_init - initialize the driver
|
||||||
*
|
*
|
||||||
|
|
@ -3978,6 +4001,16 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (amdgpu_device_use_perfopt(adev)) {
|
||||||
|
int perfopt_ret = amd_iommu_enable_perfopt(pdev);
|
||||||
|
|
||||||
|
/* Optional optimization; a failure to arm it must not abort probe. */
|
||||||
|
if (perfopt_ret)
|
||||||
|
dev_warn(adev->dev,
|
||||||
|
"Failed to enable IOMMU PerfOpt (%d); continuing without it\n",
|
||||||
|
perfopt_ret);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No need to remove conflicting FBs for non-display class devices.
|
* No need to remove conflicting FBs for non-display class devices.
|
||||||
* This prevents the sysfb from being freed accidently.
|
* This prevents the sysfb from being freed accidently.
|
||||||
|
|
@ -4347,6 +4380,9 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
||||||
|
|
||||||
amdgpu_gart_dummy_page_fini(adev);
|
amdgpu_gart_dummy_page_fini(adev);
|
||||||
|
|
||||||
|
if (amdgpu_device_use_perfopt(adev))
|
||||||
|
amd_iommu_disable_perfopt(adev->pdev);
|
||||||
|
|
||||||
if (pci_dev_is_disconnected(adev->pdev))
|
if (pci_dev_is_disconnected(adev->pdev))
|
||||||
amdgpu_device_unmap_mmio(adev);
|
amdgpu_device_unmap_mmio(adev);
|
||||||
|
|
||||||
|
|
@ -4710,6 +4746,20 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
|
||||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (amdgpu_device_use_perfopt(adev)) {
|
||||||
|
int perfopt_ret = amd_iommu_enable_perfopt(adev->pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must not return on failure: a bare return would leak the
|
||||||
|
* SR-IOV VF exclusive-mode acquisition taken above (released
|
||||||
|
* via the exit: path).
|
||||||
|
*/
|
||||||
|
if (perfopt_ret)
|
||||||
|
dev_warn(adev->dev,
|
||||||
|
"Failed to enable IOMMU PerfOpt (%d); continuing without it\n",
|
||||||
|
perfopt_ret);
|
||||||
|
}
|
||||||
|
|
||||||
if (adev->in_s0ix)
|
if (adev->in_s0ix)
|
||||||
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry);
|
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ char *amdgpu_disable_cu;
|
||||||
char *amdgpu_virtual_display;
|
char *amdgpu_virtual_display;
|
||||||
int amdgpu_enforce_isolation = -1;
|
int amdgpu_enforce_isolation = -1;
|
||||||
int amdgpu_modeset = -1;
|
int amdgpu_modeset = -1;
|
||||||
|
int amdgpu_iommu_perfopt = -1;
|
||||||
|
|
||||||
/* Specifies the default granularity for SVM, used in buffer
|
/* Specifies the default granularity for SVM, used in buffer
|
||||||
* migration and restoration of backing memory when handling
|
* migration and restoration of backing memory when handling
|
||||||
|
|
@ -398,6 +399,17 @@ module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444);
|
||||||
MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
|
MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
|
||||||
module_param_named(aspm, amdgpu_aspm, int, 0444);
|
module_param_named(aspm, amdgpu_aspm, int, 0444);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: iommu_perfopt (int)
|
||||||
|
* Control the AMD IOMMU PerfOpt DMA-latency optimization
|
||||||
|
* (0 = disable; -1 = enable on supported devices).
|
||||||
|
* This arms the IOMMU PerfOpt control (IOMMU spec, MMIO Offset 016Ch, EFR PerfOptSup / PerfOptEn)
|
||||||
|
* Arming it disables ATS, PRI, PASID and SVA for the GPU and removes IOMMU DMA containment for it,
|
||||||
|
* trading isolation for lower DMA latency.
|
||||||
|
*/
|
||||||
|
MODULE_PARM_DESC(iommu_perfopt, "Control IOMMU PerfOpt DMA-latency optimization (-1 = enable on supported devices, 0 = disable)");
|
||||||
|
module_param_named(iommu_perfopt, amdgpu_iommu_perfopt, int, 0444);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: runpm (int)
|
* DOC: runpm (int)
|
||||||
* Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down
|
* Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,13 @@
|
||||||
#define POWER_METER_CAN_CAP (1 << 2)
|
#define POWER_METER_CAN_CAP (1 << 2)
|
||||||
#define POWER_METER_CAN_NOTIFY (1 << 3)
|
#define POWER_METER_CAN_NOTIFY (1 << 3)
|
||||||
#define POWER_METER_IS_BATTERY (1 << 8)
|
#define POWER_METER_IS_BATTERY (1 << 8)
|
||||||
|
#define UNKNOWN_HYSTERESIS 0xFFFFFFFF
|
||||||
|
/*
|
||||||
|
* ACPI integers can either be 32-bit or 64-bit wide, so
|
||||||
|
* we have to check for both values.
|
||||||
|
*/
|
||||||
|
#define UNKNOWN_POWER_32 U32_MAX
|
||||||
|
#define UNKNOWN_POWER_64 U64_MAX
|
||||||
|
|
||||||
#define METER_NOTIFY_CONFIG 0x80
|
#define METER_NOTIFY_CONFIG 0x80
|
||||||
#define METER_NOTIFY_TRIP 0x81
|
#define METER_NOTIFY_TRIP 0x81
|
||||||
|
|
@ -47,15 +54,6 @@ static bool force_cap_on;
|
||||||
|
|
||||||
static DEFINE_MUTEX(acpi_notify_lock);
|
static DEFINE_MUTEX(acpi_notify_lock);
|
||||||
|
|
||||||
/*
|
|
||||||
* ACPI integers can either be 32-bit or 64-bit wide, so
|
|
||||||
* we have to check for both values.
|
|
||||||
*/
|
|
||||||
static bool acpi_power_meter_is_unknown(u64 val)
|
|
||||||
{
|
|
||||||
return val == U32_MAX || val == U64_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int can_cap_in_hardware(void)
|
static int can_cap_in_hardware(void)
|
||||||
{
|
{
|
||||||
return force_cap_on || cap_in_hardware;
|
return force_cap_on || cap_in_hardware;
|
||||||
|
|
@ -181,10 +179,9 @@ static int update_meter(struct acpi_power_meter_resource *resource)
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
unsigned long local_jiffies = jiffies;
|
unsigned long local_jiffies = jiffies;
|
||||||
|
|
||||||
if (!acpi_power_meter_is_unknown(resource->caps.sampling_time) &&
|
if (time_before(local_jiffies, resource->sensors_last_updated +
|
||||||
time_before(local_jiffies, resource->sensors_last_updated +
|
|
||||||
msecs_to_jiffies(resource->caps.sampling_time)) &&
|
msecs_to_jiffies(resource->caps.sampling_time)) &&
|
||||||
resource->sensors_valid)
|
resource->sensors_valid)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
|
status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
|
||||||
|
|
@ -380,30 +377,28 @@ static int set_avg_interval(struct acpi_power_meter_resource *resource,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool get_power_alarm_state(struct acpi_power_meter_resource *resource)
|
static int get_power_alarm_state(struct acpi_power_meter_resource *resource,
|
||||||
|
long *val)
|
||||||
{
|
{
|
||||||
bool alarm = false;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (resource->caps.flags & POWER_METER_CAN_NOTIFY)
|
|
||||||
alarm = resource->power_alarm;
|
|
||||||
resource->power_alarm = false;
|
|
||||||
|
|
||||||
ret = update_meter(resource);
|
ret = update_meter(resource);
|
||||||
if (ret || acpi_power_meter_is_unknown(resource->power))
|
if (ret)
|
||||||
return alarm;
|
return ret;
|
||||||
|
|
||||||
/* need to update cap if not to support the notification. */
|
/* need to update cap if not to support the notification. */
|
||||||
if (!(resource->caps.flags & POWER_METER_CAN_NOTIFY)) {
|
if (!(resource->caps.flags & POWER_METER_CAN_NOTIFY)) {
|
||||||
ret = update_cap(resource);
|
ret = update_cap(resource);
|
||||||
if (ret)
|
if (ret)
|
||||||
return false;
|
return ret;
|
||||||
|
resource->power_alarm = resource->power > resource->cap;
|
||||||
|
*val = resource->power_alarm;
|
||||||
|
} else {
|
||||||
|
*val = resource->power_alarm || resource->power > resource->cap;
|
||||||
|
resource->power_alarm = resource->power > resource->cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acpi_power_meter_is_unknown(resource->cap))
|
return 0;
|
||||||
return alarm;
|
|
||||||
|
|
||||||
return alarm || resource->power > resource->cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static umode_t power_meter_is_visible(const void *data,
|
static umode_t power_meter_is_visible(const void *data,
|
||||||
|
|
@ -463,47 +458,37 @@ static int power_meter_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
ret = update_meter(res);
|
ret = update_meter(res);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (acpi_power_meter_is_unknown(res->power))
|
if (res->power == UNKNOWN_POWER_32 || res->power == UNKNOWN_POWER_64)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
*val = res->power * 1000;
|
*val = res->power * 1000;
|
||||||
break;
|
break;
|
||||||
case hwmon_power_average_interval_min:
|
case hwmon_power_average_interval_min:
|
||||||
if (acpi_power_meter_is_unknown(res->caps.min_avg_interval))
|
|
||||||
return -ENODATA;
|
|
||||||
*val = res->caps.min_avg_interval;
|
*val = res->caps.min_avg_interval;
|
||||||
break;
|
break;
|
||||||
case hwmon_power_average_interval_max:
|
case hwmon_power_average_interval_max:
|
||||||
if (acpi_power_meter_is_unknown(res->caps.max_avg_interval))
|
|
||||||
return -ENODATA;
|
|
||||||
*val = res->caps.max_avg_interval;
|
*val = res->caps.max_avg_interval;
|
||||||
break;
|
break;
|
||||||
case hwmon_power_average_interval:
|
case hwmon_power_average_interval:
|
||||||
ret = update_avg_interval(res);
|
ret = update_avg_interval(res);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (acpi_power_meter_is_unknown(res->avg_interval))
|
*val = (res)->avg_interval;
|
||||||
return -ENODATA;
|
|
||||||
*val = res->avg_interval;
|
|
||||||
break;
|
break;
|
||||||
case hwmon_power_cap_min:
|
case hwmon_power_cap_min:
|
||||||
if (acpi_power_meter_is_unknown(res->caps.min_cap))
|
|
||||||
return -ENODATA;
|
|
||||||
*val = res->caps.min_cap * 1000;
|
*val = res->caps.min_cap * 1000;
|
||||||
break;
|
break;
|
||||||
case hwmon_power_cap_max:
|
case hwmon_power_cap_max:
|
||||||
if (acpi_power_meter_is_unknown(res->caps.max_cap))
|
|
||||||
return -ENODATA;
|
|
||||||
*val = res->caps.max_cap * 1000;
|
*val = res->caps.max_cap * 1000;
|
||||||
break;
|
break;
|
||||||
case hwmon_power_alarm:
|
case hwmon_power_alarm:
|
||||||
*val = get_power_alarm_state(res);
|
ret = get_power_alarm_state(res, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
break;
|
break;
|
||||||
case hwmon_power_cap:
|
case hwmon_power_cap:
|
||||||
ret = update_cap(res);
|
ret = update_cap(res);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (acpi_power_meter_is_unknown(res->cap))
|
|
||||||
return -ENODATA;
|
|
||||||
*val = res->cap * 1000;
|
*val = res->cap * 1000;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -599,8 +584,6 @@ static ssize_t power1_average_min_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
if (res->trip[POWER_METER_TRIP_AVERAGE_MIN_IDX] < 0)
|
if (res->trip[POWER_METER_TRIP_AVERAGE_MIN_IDX] < 0)
|
||||||
return sysfs_emit(buf, "unknown\n");
|
return sysfs_emit(buf, "unknown\n");
|
||||||
|
|
||||||
|
|
@ -613,8 +596,6 @@ static ssize_t power1_average_max_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
if (res->trip[POWER_METER_TRIP_AVERAGE_MAX_IDX] < 0)
|
if (res->trip[POWER_METER_TRIP_AVERAGE_MAX_IDX] < 0)
|
||||||
return sysfs_emit(buf, "unknown\n");
|
return sysfs_emit(buf, "unknown\n");
|
||||||
|
|
||||||
|
|
@ -627,9 +608,7 @@ static ssize_t power1_cap_hyst_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
if (res->caps.hysteresis == UNKNOWN_HYSTERESIS)
|
||||||
|
|
||||||
if (acpi_power_meter_is_unknown(res->caps.hysteresis))
|
|
||||||
return sysfs_emit(buf, "unknown\n");
|
return sysfs_emit(buf, "unknown\n");
|
||||||
|
|
||||||
return sysfs_emit(buf, "%llu\n", res->caps.hysteresis * 1000);
|
return sysfs_emit(buf, "%llu\n", res->caps.hysteresis * 1000);
|
||||||
|
|
@ -640,14 +619,8 @@ static ssize_t power1_accuracy_show(struct device *dev,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
unsigned int acc;
|
unsigned int acc = res->caps.accuracy;
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
if (acpi_power_meter_is_unknown(res->caps.accuracy))
|
|
||||||
return sysfs_emit(buf, "unknown\n");
|
|
||||||
|
|
||||||
acc = res->caps.accuracy;
|
|
||||||
return sysfs_emit(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
|
return sysfs_emit(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -657,8 +630,6 @@ static ssize_t power1_is_battery_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
return sysfs_emit(buf, "%u\n",
|
return sysfs_emit(buf, "%u\n",
|
||||||
res->caps.flags & POWER_METER_IS_BATTERY ? 1 : 0);
|
res->caps.flags & POWER_METER_IS_BATTERY ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
@ -669,11 +640,6 @@ static ssize_t power1_model_number_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
if (!res->model_number)
|
|
||||||
return -ENODATA;
|
|
||||||
|
|
||||||
return sysfs_emit(buf, "%s\n", res->model_number);
|
return sysfs_emit(buf, "%s\n", res->model_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -683,11 +649,6 @@ static ssize_t power1_oem_info_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
if (!res->oem_info)
|
|
||||||
return -ENODATA;
|
|
||||||
|
|
||||||
return sysfs_emit(buf, "%s\n", res->oem_info);
|
return sysfs_emit(buf, "%s\n", res->oem_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -697,11 +658,6 @@ static ssize_t power1_serial_number_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&res->lock);
|
|
||||||
|
|
||||||
if (!res->serial_number)
|
|
||||||
return -ENODATA;
|
|
||||||
|
|
||||||
return sysfs_emit(buf, "%s\n", res->serial_number);
|
return sysfs_emit(buf, "%s\n", res->serial_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1028,8 +984,6 @@ static int acpi_power_meter_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct acpi_power_meter_resource *resource = dev_get_drvdata(dev);
|
struct acpi_power_meter_resource *resource = dev_get_drvdata(dev);
|
||||||
|
|
||||||
guard(mutex)(&resource->lock);
|
|
||||||
|
|
||||||
free_capabilities(resource);
|
free_capabilities(resource);
|
||||||
read_capabilities(resource);
|
read_capabilities(resource);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
#include <linux/hwmon.h>
|
#include <linux/hwmon.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/ktime.h>
|
#include <linux/ktime.h>
|
||||||
#include <linux/limits.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/unaligned.h>
|
#include <linux/unaligned.h>
|
||||||
|
|
@ -133,7 +132,6 @@ static u8 aquaero_secondary_ctrl_report[] = {
|
||||||
#define AQUAERO_FAN_CURRENT_OFFSET 0x06
|
#define AQUAERO_FAN_CURRENT_OFFSET 0x06
|
||||||
#define AQUAERO_FAN_POWER_OFFSET 0x08
|
#define AQUAERO_FAN_POWER_OFFSET 0x08
|
||||||
#define AQUAERO_FAN_SPEED_OFFSET 0x00
|
#define AQUAERO_FAN_SPEED_OFFSET 0x00
|
||||||
#define AQUAERO_MIN_STATUS_REPORT_SIZE (0x18B + AQUAERO_FAN_POWER_OFFSET + sizeof(u16))
|
|
||||||
static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
|
static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
|
||||||
|
|
||||||
/* Control report offsets for the Aquaero fan controllers */
|
/* Control report offsets for the Aquaero fan controllers */
|
||||||
|
|
@ -157,8 +155,6 @@ static u16 aquaero_ctrl_fan_offsets[] = { 0x20c, 0x220, 0x234, 0x248 };
|
||||||
#define D5NEXT_5V_VOLTAGE 0x39
|
#define D5NEXT_5V_VOLTAGE 0x39
|
||||||
#define D5NEXT_12V_VOLTAGE 0x37
|
#define D5NEXT_12V_VOLTAGE 0x37
|
||||||
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
|
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
|
||||||
#define D5NEXT_MIN_STATUS_REPORT_SIZE (D5NEXT_PUMP_OFFSET + AQC_FAN_SPEED_OFFSET + \
|
|
||||||
sizeof(u16))
|
|
||||||
static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
|
static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
|
||||||
|
|
||||||
/* Control report offsets for the D5 Next pump */
|
/* Control report offsets for the D5 Next pump */
|
||||||
|
|
@ -183,14 +179,11 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr
|
||||||
#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00
|
#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00
|
||||||
#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04
|
#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04
|
||||||
#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06
|
#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06
|
||||||
#define AQUASTREAMULT_MIN_STATUS_REPORT_SIZE (AQUASTREAMULT_PRESSURE_OFFSET + sizeof(u16))
|
|
||||||
static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
|
static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
|
||||||
|
|
||||||
/* Spec and sensor report offset for the Farbwerk RGB controller */
|
/* Spec and sensor report offset for the Farbwerk RGB controller */
|
||||||
#define FARBWERK_NUM_SENSORS 4
|
#define FARBWERK_NUM_SENSORS 4
|
||||||
#define FARBWERK_SENSOR_START 0x2f
|
#define FARBWERK_SENSOR_START 0x2f
|
||||||
#define FARBWERK_MIN_STATUS_REPORT_SIZE (FARBWERK_SENSOR_START + \
|
|
||||||
FARBWERK_NUM_SENSORS * AQC_SENSOR_SIZE)
|
|
||||||
|
|
||||||
/* Specs of the Farbwerk 360 RGB controller */
|
/* Specs of the Farbwerk 360 RGB controller */
|
||||||
#define FARBWERK360_NUM_SENSORS 4
|
#define FARBWERK360_NUM_SENSORS 4
|
||||||
|
|
@ -200,8 +193,6 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
|
||||||
/* Sensor report offsets for the Farbwerk 360 */
|
/* Sensor report offsets for the Farbwerk 360 */
|
||||||
#define FARBWERK360_SENSOR_START 0x32
|
#define FARBWERK360_SENSOR_START 0x32
|
||||||
#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a
|
#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a
|
||||||
#define FARBWERK360_MIN_STATUS_REPORT_SIZE (FARBWERK360_VIRTUAL_SENSORS_START + \
|
|
||||||
FARBWERK360_NUM_VIRTUAL_SENSORS * AQC_SENSOR_SIZE)
|
|
||||||
|
|
||||||
/* Control report offsets for the Farbwerk 360 */
|
/* Control report offsets for the Farbwerk 360 */
|
||||||
#define FARBWERK360_TEMP_CTRL_OFFSET 0x8
|
#define FARBWERK360_TEMP_CTRL_OFFSET 0x8
|
||||||
|
|
@ -218,7 +209,6 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
|
||||||
#define OCTO_SENSOR_START 0x3D
|
#define OCTO_SENSOR_START 0x3D
|
||||||
#define OCTO_VIRTUAL_SENSORS_START 0x45
|
#define OCTO_VIRTUAL_SENSORS_START 0x45
|
||||||
#define OCTO_FLOW_SENSOR_OFFSET 0x7B
|
#define OCTO_FLOW_SENSOR_OFFSET 0x7B
|
||||||
#define OCTO_MIN_STATUS_REPORT_SIZE (0xD8 + AQC_FAN_SPEED_OFFSET + sizeof(u16))
|
|
||||||
static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
|
static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
|
||||||
|
|
||||||
/* Control report offsets for the Octo */
|
/* Control report offsets for the Octo */
|
||||||
|
|
@ -239,7 +229,6 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
|
||||||
#define QUADRO_SENSOR_START 0x34
|
#define QUADRO_SENSOR_START 0x34
|
||||||
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
|
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
|
||||||
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
|
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
|
||||||
#define QUADRO_MIN_STATUS_REPORT_SIZE (0x97 + AQC_FAN_SPEED_OFFSET + sizeof(u16))
|
|
||||||
static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
|
static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
|
||||||
|
|
||||||
/* Control report offsets for the Quadro */
|
/* Control report offsets for the Quadro */
|
||||||
|
|
@ -259,7 +248,6 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
|
||||||
#define HIGHFLOWNEXT_CONDUCTIVITY 95
|
#define HIGHFLOWNEXT_CONDUCTIVITY 95
|
||||||
#define HIGHFLOWNEXT_5V_VOLTAGE 97
|
#define HIGHFLOWNEXT_5V_VOLTAGE 97
|
||||||
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
|
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
|
||||||
#define HIGHFLOWNEXT_MIN_STATUS_REPORT_SIZE (HIGHFLOWNEXT_5V_VOLTAGE_USB + sizeof(u16))
|
|
||||||
|
|
||||||
/* Specs of the Leakshield */
|
/* Specs of the Leakshield */
|
||||||
#define LEAKSHIELD_NUM_SENSORS 2
|
#define LEAKSHIELD_NUM_SENSORS 2
|
||||||
|
|
@ -275,7 +263,6 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
|
||||||
#define LEAKSHIELD_FLOW_IN 111
|
#define LEAKSHIELD_FLOW_IN 111
|
||||||
#define LEAKSHIELD_RESERVOIR_VOLUME 313
|
#define LEAKSHIELD_RESERVOIR_VOLUME 313
|
||||||
#define LEAKSHIELD_RESERVOIR_FILLED 311
|
#define LEAKSHIELD_RESERVOIR_FILLED 311
|
||||||
#define LEAKSHIELD_MIN_STATUS_REPORT_SIZE (LEAKSHIELD_RESERVOIR_VOLUME + sizeof(u16))
|
|
||||||
|
|
||||||
/* Specs of the Aquastream XT pump */
|
/* Specs of the Aquastream XT pump */
|
||||||
#define AQUASTREAMXT_SERIAL_START 0x3a
|
#define AQUASTREAMXT_SERIAL_START 0x3a
|
||||||
|
|
@ -567,7 +554,6 @@ struct aqc_data {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
int status_report_id; /* Used for legacy devices, report is stored in buffer */
|
int status_report_id; /* Used for legacy devices, report is stored in buffer */
|
||||||
u16 min_report_size;
|
|
||||||
int ctrl_report_id;
|
int ctrl_report_id;
|
||||||
int secondary_ctrl_report_id;
|
int secondary_ctrl_report_id;
|
||||||
int secondary_ctrl_report_size;
|
int secondary_ctrl_report_size;
|
||||||
|
|
@ -613,9 +599,9 @@ struct aqc_data {
|
||||||
u32 speed_input_min[1];
|
u32 speed_input_min[1];
|
||||||
u32 speed_input_target[1];
|
u32 speed_input_target[1];
|
||||||
u32 speed_input_max[1];
|
u32 speed_input_max[1];
|
||||||
long power_input[8];
|
u32 power_input[8];
|
||||||
u16 voltage_input[8];
|
u16 voltage_input[8];
|
||||||
u32 current_input[8];
|
u16 current_input[8];
|
||||||
|
|
||||||
/* Label values */
|
/* Label values */
|
||||||
const char *const *temp_label;
|
const char *const *temp_label;
|
||||||
|
|
@ -990,7 +976,7 @@ static int aqc_legacy_read(struct aqc_data *priv)
|
||||||
|
|
||||||
/* Calculation derived from linear regression */
|
/* Calculation derived from linear regression */
|
||||||
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_CURR_OFFSET);
|
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_CURR_OFFSET);
|
||||||
priv->current_input[0] = max(DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52, 0);
|
priv->current_input[0] = DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52;
|
||||||
|
|
||||||
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET);
|
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET);
|
||||||
priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61);
|
priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61);
|
||||||
|
|
@ -1020,7 +1006,6 @@ static int aqc_legacy_read(struct aqc_data *priv)
|
||||||
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||||
int channel, long *val)
|
int channel, long *val)
|
||||||
{
|
{
|
||||||
long power;
|
|
||||||
int ret;
|
int ret;
|
||||||
struct aqc_data *priv = dev_get_drvdata(dev);
|
struct aqc_data *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
|
@ -1085,10 +1070,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hwmon_power:
|
case hwmon_power:
|
||||||
power = READ_ONCE(priv->power_input[channel]);
|
*val = priv->power_input[channel];
|
||||||
if (power == -ENODATA)
|
|
||||||
return -ENODATA;
|
|
||||||
*val = power;
|
|
||||||
break;
|
break;
|
||||||
case hwmon_pwm:
|
case hwmon_pwm:
|
||||||
switch (priv->kind) {
|
switch (priv->kind) {
|
||||||
|
|
@ -1351,8 +1333,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
priv = hid_get_drvdata(hdev);
|
priv = hid_get_drvdata(hdev);
|
||||||
if (!priv->min_report_size || size < priv->min_report_size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Info provided with every report */
|
/* Info provided with every report */
|
||||||
priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
|
priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
|
||||||
|
|
@ -1388,9 +1368,9 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
||||||
priv->speed_input[i] =
|
priv->speed_input[i] =
|
||||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||||
priv->fan_structure->speed);
|
priv->fan_structure->speed);
|
||||||
WRITE_ONCE(priv->power_input[i],
|
priv->power_input[i] =
|
||||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||||
priv->fan_structure->power) * 10000);
|
priv->fan_structure->power) * 10000;
|
||||||
priv->voltage_input[i] =
|
priv->voltage_input[i] =
|
||||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||||
priv->fan_structure->voltage) * 10;
|
priv->fan_structure->voltage) * 10;
|
||||||
|
|
@ -1430,8 +1410,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
||||||
priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
|
priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
|
||||||
priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
|
priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
|
||||||
|
|
||||||
WRITE_ONCE(priv->power_input[1],
|
priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000;
|
||||||
get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000);
|
|
||||||
|
|
||||||
priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
|
priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
|
||||||
|
|
||||||
|
|
@ -1444,11 +1423,10 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
||||||
case highflownext:
|
case highflownext:
|
||||||
/* If external temp sensor is not connected, its power reading is also N/A */
|
/* If external temp sensor is not connected, its power reading is also N/A */
|
||||||
if (priv->temp_input[1] == -ENODATA)
|
if (priv->temp_input[1] == -ENODATA)
|
||||||
WRITE_ONCE(priv->power_input[0], -ENODATA);
|
priv->power_input[0] = -ENODATA;
|
||||||
else
|
else
|
||||||
WRITE_ONCE(priv->power_input[0],
|
priv->power_input[0] =
|
||||||
min_t(u64, get_unaligned_be16(data + HIGHFLOWNEXT_POWER) *
|
get_unaligned_be16(data + HIGHFLOWNEXT_POWER) * 1000000;
|
||||||
1000000ULL, LONG_MAX));
|
|
||||||
|
|
||||||
priv->voltage_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE) * 10;
|
priv->voltage_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE) * 10;
|
||||||
priv->voltage_input[1] =
|
priv->voltage_input[1] =
|
||||||
|
|
@ -1540,7 +1518,6 @@ static void aqc_debugfs_init(struct aqc_data *priv)
|
||||||
static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
{
|
{
|
||||||
struct aqc_data *priv;
|
struct aqc_data *priv;
|
||||||
u16 min_report_size = 0;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
|
@ -1577,7 +1554,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
* they present. The two other devices have the type of the second element in
|
* they present. The two other devices have the type of the second element in
|
||||||
* their respective collections set to 1, while the real device has it set to 0.
|
* their respective collections set to 1, while the real device has it set to 0.
|
||||||
*/
|
*/
|
||||||
if (hdev->maxcollection < 2 || hdev->collection[1].type != 0) {
|
if (hdev->collection[1].type != 0) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto fail_and_close;
|
goto fail_and_close;
|
||||||
}
|
}
|
||||||
|
|
@ -1608,7 +1585,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->power_label = label_fan_power;
|
priv->power_label = label_fan_power;
|
||||||
priv->voltage_label = label_fan_voltage;
|
priv->voltage_label = label_fan_voltage;
|
||||||
priv->current_label = label_fan_current;
|
priv->current_label = label_fan_current;
|
||||||
min_report_size = AQUAERO_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_D5NEXT:
|
case USB_PRODUCT_ID_D5NEXT:
|
||||||
priv->kind = d5next;
|
priv->kind = d5next;
|
||||||
|
|
@ -1634,7 +1610,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->power_label = label_d5next_power;
|
priv->power_label = label_d5next_power;
|
||||||
priv->voltage_label = label_d5next_voltages;
|
priv->voltage_label = label_d5next_voltages;
|
||||||
priv->current_label = label_d5next_current;
|
priv->current_label = label_d5next_current;
|
||||||
min_report_size = D5NEXT_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_FARBWERK:
|
case USB_PRODUCT_ID_FARBWERK:
|
||||||
priv->kind = farbwerk;
|
priv->kind = farbwerk;
|
||||||
|
|
@ -1645,7 +1620,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->temp_sensor_start_offset = FARBWERK_SENSOR_START;
|
priv->temp_sensor_start_offset = FARBWERK_SENSOR_START;
|
||||||
|
|
||||||
priv->temp_label = label_temp_sensors;
|
priv->temp_label = label_temp_sensors;
|
||||||
min_report_size = FARBWERK_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_FARBWERK360:
|
case USB_PRODUCT_ID_FARBWERK360:
|
||||||
priv->kind = farbwerk360;
|
priv->kind = farbwerk360;
|
||||||
|
|
@ -1662,7 +1636,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
|
|
||||||
priv->temp_label = label_temp_sensors;
|
priv->temp_label = label_temp_sensors;
|
||||||
priv->virtual_temp_label = label_virtual_temp_sensors;
|
priv->virtual_temp_label = label_virtual_temp_sensors;
|
||||||
min_report_size = FARBWERK360_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_OCTO:
|
case USB_PRODUCT_ID_OCTO:
|
||||||
priv->kind = octo;
|
priv->kind = octo;
|
||||||
|
|
@ -1692,7 +1665,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->power_label = label_fan_power;
|
priv->power_label = label_fan_power;
|
||||||
priv->voltage_label = label_fan_voltage;
|
priv->voltage_label = label_fan_voltage;
|
||||||
priv->current_label = label_fan_current;
|
priv->current_label = label_fan_current;
|
||||||
min_report_size = OCTO_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_QUADRO:
|
case USB_PRODUCT_ID_QUADRO:
|
||||||
priv->kind = quadro;
|
priv->kind = quadro;
|
||||||
|
|
@ -1722,7 +1694,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->power_label = label_fan_power;
|
priv->power_label = label_fan_power;
|
||||||
priv->voltage_label = label_fan_voltage;
|
priv->voltage_label = label_fan_voltage;
|
||||||
priv->current_label = label_fan_current;
|
priv->current_label = label_fan_current;
|
||||||
min_report_size = QUADRO_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_HIGHFLOWNEXT:
|
case USB_PRODUCT_ID_HIGHFLOWNEXT:
|
||||||
priv->kind = highflownext;
|
priv->kind = highflownext;
|
||||||
|
|
@ -1740,7 +1711,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->speed_label = label_highflownext_fan_speed;
|
priv->speed_label = label_highflownext_fan_speed;
|
||||||
priv->power_label = label_highflownext_power;
|
priv->power_label = label_highflownext_power;
|
||||||
priv->voltage_label = label_highflownext_voltage;
|
priv->voltage_label = label_highflownext_voltage;
|
||||||
min_report_size = HIGHFLOWNEXT_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_LEAKSHIELD:
|
case USB_PRODUCT_ID_LEAKSHIELD:
|
||||||
/*
|
/*
|
||||||
|
|
@ -1760,7 +1730,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
|
|
||||||
priv->temp_label = label_leakshield_temp_sensors;
|
priv->temp_label = label_leakshield_temp_sensors;
|
||||||
priv->speed_label = label_leakshield_fan_speed;
|
priv->speed_label = label_leakshield_fan_speed;
|
||||||
min_report_size = LEAKSHIELD_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_AQUASTREAMXT:
|
case USB_PRODUCT_ID_AQUASTREAMXT:
|
||||||
priv->kind = aquastreamxt;
|
priv->kind = aquastreamxt;
|
||||||
|
|
@ -1791,7 +1760,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
priv->power_label = label_aquastreamult_power;
|
priv->power_label = label_aquastreamult_power;
|
||||||
priv->voltage_label = label_aquastreamult_voltages;
|
priv->voltage_label = label_aquastreamult_voltages;
|
||||||
priv->current_label = label_aquastreamult_current;
|
priv->current_label = label_aquastreamult_current;
|
||||||
min_report_size = AQUASTREAMULT_MIN_STATUS_REPORT_SIZE;
|
|
||||||
break;
|
break;
|
||||||
case USB_PRODUCT_ID_POWERADJUST3:
|
case USB_PRODUCT_ID_POWERADJUST3:
|
||||||
priv->kind = poweradjust3;
|
priv->kind = poweradjust3;
|
||||||
|
|
@ -1865,8 +1833,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->min_report_size = min_report_size;
|
|
||||||
|
|
||||||
if (priv->buffer_size != 0) {
|
if (priv->buffer_size != 0) {
|
||||||
priv->checksum_start = 0x01;
|
priv->checksum_start = 0x01;
|
||||||
priv->checksum_length = priv->buffer_size - 3;
|
priv->checksum_length = priv->buffer_size - 3;
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ static const struct rog_ryujin_device_info rog_ryujin_iii_info = {
|
||||||
#define MAX_REPORT_LENGTH 65
|
#define MAX_REPORT_LENGTH 65
|
||||||
|
|
||||||
/* Cooler duty report offsets */
|
/* Cooler duty report offsets */
|
||||||
#define RYUJIN_PUMP_SOURCE 3
|
|
||||||
#define RYUJIN_PUMP_DUTY 4
|
#define RYUJIN_PUMP_DUTY 4
|
||||||
#define RYUJIN_INTERNAL_FAN_DUTY 5
|
#define RYUJIN_INTERNAL_FAN_DUTY 5
|
||||||
|
|
||||||
|
|
@ -71,15 +70,10 @@ static const u8 get_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x9A };
|
||||||
static const u8 get_controller_speed_cmd[] = { RYUJIN_CMD_PREFIX, 0xA0 };
|
static const u8 get_controller_speed_cmd[] = { RYUJIN_CMD_PREFIX, 0xA0 };
|
||||||
static const u8 get_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0xA1 };
|
static const u8 get_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0xA1 };
|
||||||
|
|
||||||
#define RYUJIN_SET_COOLER_CHANNEL_OFFSET 2
|
|
||||||
#define RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET 3
|
#define RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET 3
|
||||||
#define RYUJIN_SET_COOLER_FAN_DUTY_OFFSET 4
|
#define RYUJIN_SET_COOLER_FAN_DUTY_OFFSET 4
|
||||||
static const u8 set_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x1A, 0x00, 0x00, 0x00 };
|
static const u8 set_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x1A, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
/* Pump control sources in the set cooler duty command and the cooler duty report */
|
|
||||||
#define RYUJIN_SOURCE_HEADER 0
|
|
||||||
#define RYUJIN_SOURCE_USB 1
|
|
||||||
|
|
||||||
#define RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET 4
|
#define RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET 4
|
||||||
static const u8 set_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x21, 0x00, 0x00, 0x00 };
|
static const u8 set_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x21, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
|
@ -123,7 +117,6 @@ struct rog_ryujin_data {
|
||||||
s32 temp_input[1];
|
s32 temp_input[1];
|
||||||
u16 speed_input[6]; /* Pump, internal fan and four controller fan speeds in RPM */
|
u16 speed_input[6]; /* Pump, internal fan and four controller fan speeds in RPM */
|
||||||
u8 duty_input[3]; /* Pump, internal fan and controller fan duty in PWM */
|
u8 duty_input[3]; /* Pump, internal fan and controller fan duty in PWM */
|
||||||
u8 pump_source; /* Pump control source from the cooler duty report */
|
|
||||||
|
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
unsigned long updated; /* jiffies */
|
unsigned long updated; /* jiffies */
|
||||||
|
|
@ -207,23 +200,16 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i
|
||||||
/* Send command for getting data */
|
/* Send command for getting data */
|
||||||
ret = rog_ryujin_write_expanded(priv, cmd, cmd_length);
|
ret = rog_ryujin_write_expanded(priv, cmd, cmd_length);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_complete;
|
return ret;
|
||||||
|
|
||||||
ret = wait_for_completion_interruptible_timeout(status_completion,
|
ret = wait_for_completion_interruptible_timeout(status_completion,
|
||||||
msecs_to_jiffies(STATUS_VALIDITY));
|
msecs_to_jiffies(STATUS_VALIDITY));
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
if (ret < 0)
|
else if (ret < 0)
|
||||||
goto out_complete;
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_complete:
|
|
||||||
spin_lock_irqsave(&priv->status_report_request_lock, flags);
|
|
||||||
if (!completion_done(status_completion))
|
|
||||||
complete_all(status_completion);
|
|
||||||
spin_unlock_irqrestore(&priv->status_report_request_lock, flags);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
|
static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
|
||||||
|
|
@ -320,44 +306,6 @@ static int rog_ryujin_read_string(struct device *dev, enum hwmon_sensor_types ty
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* On devices with a non-zero duty_channel (the RYUJIN III), the channel byte of
|
|
||||||
* the set cooler duty command selects the pump control source.
|
|
||||||
* RYUJIN_SOURCE_HEADER hands the pump to its internal controller, which follows
|
|
||||||
* the PWM of the header its 4-pin cable is plugged into. RYUJIN_SOURCE_USB
|
|
||||||
* makes the pump follow the pump duty in the command. The cooler duty report
|
|
||||||
* returns the current source.
|
|
||||||
*
|
|
||||||
* A fan duty write sends the reported source back, so that it leaves the pump
|
|
||||||
* control source as it is. A pump duty write selects USB. The cooler does not
|
|
||||||
* pass on a pump duty equal to the one it reports, and after power-on it
|
|
||||||
* reports 40% while a pump handed over at that duty runs at full speed. So
|
|
||||||
* when a pump duty write asks for the reported duty, write a duty 1% away
|
|
||||||
* first.
|
|
||||||
*/
|
|
||||||
static int rog_ryujin_select_pump_source(struct rog_ryujin_data *priv, u8 *set_cmd,
|
|
||||||
int channel)
|
|
||||||
{
|
|
||||||
u8 duty = set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (channel == 1) {
|
|
||||||
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = priv->pump_source;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = RYUJIN_SOURCE_USB;
|
|
||||||
|
|
||||||
if (duty != rog_ryujin_pwm_to_percent(priv->duty_input[0]))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = duty < 100 ? duty + 1 : duty - 1;
|
|
||||||
ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
|
|
||||||
set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = duty;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val)
|
static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val)
|
||||||
{
|
{
|
||||||
u8 set_cmd[SET_CMD_LENGTH];
|
u8 set_cmd[SET_CMD_LENGTH];
|
||||||
|
|
@ -375,7 +323,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
|
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
|
||||||
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = priv->info->duty_channel;
|
set_cmd[2] = priv->info->duty_channel;
|
||||||
|
|
||||||
/* Cooler duties are set as 0-100% */
|
/* Cooler duties are set as 0-100% */
|
||||||
val = rog_ryujin_pwm_to_percent(val);
|
val = rog_ryujin_pwm_to_percent(val);
|
||||||
|
|
@ -392,12 +340,6 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
|
||||||
set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
|
set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->info->duty_channel) {
|
|
||||||
ret = rog_ryujin_select_pump_source(priv, set_cmd, channel);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
|
return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
|
@ -540,7 +482,6 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
read_cooler_duty:
|
read_cooler_duty:
|
||||||
priv->pump_source = data[RYUJIN_PUMP_SOURCE];
|
|
||||||
priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
|
priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
|
||||||
priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]);
|
priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]);
|
||||||
|
|
||||||
|
|
@ -637,18 +578,6 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
|
||||||
init_completion(&priv->cooler_duty_set);
|
init_completion(&priv->cooler_duty_set);
|
||||||
init_completion(&priv->controller_duty_set);
|
init_completion(&priv->controller_duty_set);
|
||||||
|
|
||||||
/*
|
|
||||||
* Start completions in the completed state so rog_ryujin_raw_event()
|
|
||||||
* only sees !completion_done() while rog_ryujin_execute_cmd() is
|
|
||||||
* awaiting a response.
|
|
||||||
*/
|
|
||||||
complete_all(&priv->cooler_status_received);
|
|
||||||
complete_all(&priv->controller_status_received);
|
|
||||||
complete_all(&priv->cooler_duty_received);
|
|
||||||
complete_all(&priv->controller_duty_received);
|
|
||||||
complete_all(&priv->cooler_duty_set);
|
|
||||||
complete_all(&priv->controller_duty_set);
|
|
||||||
|
|
||||||
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "rog_ryujin",
|
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "rog_ryujin",
|
||||||
priv, &rog_ryujin_chip_info, NULL);
|
priv, &rog_ryujin_chip_info, NULL);
|
||||||
if (IS_ERR(priv->hwmon_dev)) {
|
if (IS_ERR(priv->hwmon_dev)) {
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,6 @@ struct asus_wmi_wmi_info {
|
||||||
|
|
||||||
struct asus_wmi_sensors {
|
struct asus_wmi_sensors {
|
||||||
struct asus_wmi_wmi_info wmi;
|
struct asus_wmi_wmi_info wmi;
|
||||||
struct hwmon_chip_info chip_info;
|
|
||||||
/* lock access to internal cache */
|
/* lock access to internal cache */
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
};
|
};
|
||||||
|
|
@ -497,6 +496,11 @@ static const struct hwmon_ops asus_wmi_hwmon_ops = {
|
||||||
.read_string = asus_wmi_hwmon_read_string,
|
.read_string = asus_wmi_hwmon_read_string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct hwmon_chip_info asus_wmi_chip_info = {
|
||||||
|
.ops = &asus_wmi_hwmon_ops,
|
||||||
|
.info = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static int asus_wmi_configure_sensor_setup(struct device *dev,
|
static int asus_wmi_configure_sensor_setup(struct device *dev,
|
||||||
struct asus_wmi_sensors *sensor_data)
|
struct asus_wmi_sensors *sensor_data)
|
||||||
{
|
{
|
||||||
|
|
@ -504,7 +508,7 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
|
||||||
struct hwmon_channel_info *asus_wmi_hwmon_chan;
|
struct hwmon_channel_info *asus_wmi_hwmon_chan;
|
||||||
int nr_count[hwmon_max] = {}, nr_types = 0;
|
int nr_count[hwmon_max] = {}, nr_types = 0;
|
||||||
struct asus_wmi_sensor_info *temp_sensor;
|
struct asus_wmi_sensor_info *temp_sensor;
|
||||||
struct hwmon_chip_info *chip_info;
|
const struct hwmon_chip_info *chip_info;
|
||||||
enum hwmon_sensor_types type;
|
enum hwmon_sensor_types type;
|
||||||
struct device *hwdev;
|
struct device *hwdev;
|
||||||
int i, idx;
|
int i, idx;
|
||||||
|
|
@ -545,9 +549,8 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
|
||||||
if (!ptr_asus_wmi_ci)
|
if (!ptr_asus_wmi_ci)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
chip_info = &sensor_data->chip_info;
|
asus_wmi_chip_info.info = ptr_asus_wmi_ci;
|
||||||
chip_info->ops = &asus_wmi_hwmon_ops;
|
chip_info = &asus_wmi_chip_info;
|
||||||
chip_info->info = ptr_asus_wmi_ci;
|
|
||||||
|
|
||||||
sensor_data->wmi.info_by_id = devm_kcalloc(dev, sensor_data->wmi.sensor_count,
|
sensor_data->wmi.info_by_id = devm_kcalloc(dev, sensor_data->wmi.sensor_count,
|
||||||
sizeof(*sensor_data->wmi.info_by_id),
|
sizeof(*sensor_data->wmi.info_by_id),
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/unaligned.h>
|
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/mod_devicetable.h>
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
|
|
@ -92,9 +90,6 @@ struct cc2_data {
|
||||||
int irq_low;
|
int irq_low;
|
||||||
int irq_high;
|
int irq_high;
|
||||||
bool process_irqs;
|
bool process_irqs;
|
||||||
/* protects process_irqs and the alarm indicators */
|
|
||||||
struct mutex irq_lock;
|
|
||||||
bool regulator_enabled;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* %RH as a per cent mille from a register value */
|
/* %RH as a per cent mille from a register value */
|
||||||
|
|
@ -123,33 +118,20 @@ static int cc2_enable(struct cc2_data *data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (data->irq_ready > 0) {
|
|
||||||
scoped_guard(mutex, &data->irq_lock)
|
|
||||||
data->process_irqs = false;
|
|
||||||
|
|
||||||
synchronize_irq(data->irq_ready);
|
|
||||||
|
|
||||||
scoped_guard(mutex, &data->irq_lock)
|
|
||||||
reinit_completion(&data->complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* exclusive regulator, check in case a disable failed */
|
/* exclusive regulator, check in case a disable failed */
|
||||||
if (data->regulator_enabled) {
|
if (regulator_is_enabled(data->regulator))
|
||||||
scoped_guard(mutex, &data->irq_lock)
|
|
||||||
data->process_irqs = true;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
/* clear any pending completion */
|
||||||
|
try_wait_for_completion(&data->complete);
|
||||||
|
|
||||||
ret = regulator_enable(data->regulator);
|
ret = regulator_enable(data->regulator);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
data->regulator_enabled = true;
|
|
||||||
|
|
||||||
usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
|
usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
|
||||||
|
|
||||||
scoped_guard(mutex, &data->irq_lock)
|
data->process_irqs = true;
|
||||||
data->process_irqs = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -158,36 +140,15 @@ static void cc2_disable(struct cc2_data *data)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* let the alarms already raised by the last measurement be processed */
|
|
||||||
if (data->irq_low > 0)
|
|
||||||
synchronize_irq(data->irq_low);
|
|
||||||
|
|
||||||
if (data->irq_high > 0)
|
|
||||||
synchronize_irq(data->irq_high);
|
|
||||||
|
|
||||||
/* ignore alarms triggered by voltage toggling when powering up */
|
/* ignore alarms triggered by voltage toggling when powering up */
|
||||||
scoped_guard(mutex, &data->irq_lock)
|
data->process_irqs = false;
|
||||||
data->process_irqs = false;
|
|
||||||
|
|
||||||
if (data->irq_ready > 0)
|
|
||||||
synchronize_irq(data->irq_ready);
|
|
||||||
|
|
||||||
/* exclusive regulator, check in case an enable failed */
|
/* exclusive regulator, check in case an enable failed */
|
||||||
if (!data->regulator_enabled)
|
if (regulator_is_enabled(data->regulator)) {
|
||||||
return;
|
err = regulator_disable(data->regulator);
|
||||||
|
if (err)
|
||||||
err = regulator_disable(data->regulator);
|
dev_dbg(&data->client->dev, "Failed to disable device");
|
||||||
if (err) {
|
|
||||||
dev_dbg(&data->client->dev, "Failed to disable device");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data->regulator_enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cc2_disable_action(void *data)
|
|
||||||
{
|
|
||||||
cc2_disable(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
|
static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
|
||||||
|
|
@ -206,13 +167,13 @@ static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
|
||||||
case CC2_RESPONSE_BUSY:
|
case CC2_RESPONSE_BUSY:
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
case CC2_RESPONSE_NACK:
|
case CC2_RESPONSE_NACK:
|
||||||
if (status & CC2_ERR_CORR_EEPROM)
|
if (resp & CC2_ERR_CORR_EEPROM)
|
||||||
dev_dbg(dev, "Command failed: corrected EEPROM\n");
|
dev_dbg(dev, "Command failed: corrected EEPROM\n");
|
||||||
if (status & CC2_ERR_UNCORR_EEPROM)
|
if (resp & CC2_ERR_UNCORR_EEPROM)
|
||||||
dev_dbg(dev, "Command failed: uncorrected EEPROM\n");
|
dev_dbg(dev, "Command failed: uncorrected EEPROM\n");
|
||||||
if (status & CC2_ERR_RAM_PARITY)
|
if (resp & CC2_ERR_RAM_PARITY)
|
||||||
dev_dbg(dev, "Command failed: RAM parity\n");
|
dev_dbg(dev, "Command failed: RAM parity\n");
|
||||||
if (status & CC2_ERR_CONFIG_LOAD)
|
if (resp & CC2_ERR_RAM_PARITY)
|
||||||
dev_dbg(dev, "Command failed: configuration error\n");
|
dev_dbg(dev, "Command failed: configuration error\n");
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
default:
|
default:
|
||||||
|
|
@ -265,7 +226,7 @@ static int cc2_command_mode_start(struct cc2_data *data)
|
||||||
2 * CC2_RESP_START_CM_US);
|
2 * CC2_RESP_START_CM_US);
|
||||||
}
|
}
|
||||||
ret = cc2_read_command_status(data->client);
|
ret = cc2_read_command_status(data->client);
|
||||||
if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES - 1)
|
if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* command window missed, prepare for a retry */
|
/* command window missed, prepare for a retry */
|
||||||
|
|
@ -299,7 +260,8 @@ static int cc2_write_reg(struct cc2_data *data, u8 reg, u16 val)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto disable;
|
goto disable;
|
||||||
|
|
||||||
ret = i2c_smbus_write_word_swapped(data->client, reg, val);
|
cpu_to_be16s(&val);
|
||||||
|
ret = i2c_smbus_write_word_data(data->client, reg, val);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto disable;
|
goto disable;
|
||||||
|
|
||||||
|
|
@ -349,7 +311,7 @@ static int cc2_read_reg(struct cc2_data *data, u8 reg, u16 *val)
|
||||||
if (ret != CC2_EEPROM_DATA_LEN)
|
if (ret != CC2_EEPROM_DATA_LEN)
|
||||||
return ret < 0 ? ret : -EIO;
|
return ret < 0 ? ret : -EIO;
|
||||||
|
|
||||||
*val = get_unaligned_be16(&buf[1]);
|
*val = be16_to_cpup((__be16 *)&buf[1]);
|
||||||
|
|
||||||
return cc2_read_command_status(data->client);
|
return cc2_read_command_status(data->client);
|
||||||
}
|
}
|
||||||
|
|
@ -389,10 +351,10 @@ static int cc2_data_fetch(struct i2c_client *client,
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case hwmon_humidity:
|
case hwmon_humidity:
|
||||||
*val = cc2_rh_convert(get_unaligned_be16(&data[0]));
|
*val = cc2_rh_convert(be16_to_cpup((__be16 *)&data[0]));
|
||||||
break;
|
break;
|
||||||
case hwmon_temp:
|
case hwmon_temp:
|
||||||
*val = cc2_temp_convert(get_unaligned_be16(&data[2]));
|
*val = cc2_temp_convert(be16_to_cpup((__be16 *)&data[2]));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -520,10 +482,8 @@ static irqreturn_t cc2_ready_interrupt(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct cc2_data *cc2 = data;
|
struct cc2_data *cc2 = data;
|
||||||
|
|
||||||
scoped_guard(mutex, &cc2->irq_lock) {
|
if (cc2->process_irqs)
|
||||||
if (cc2->process_irqs)
|
complete(&cc2->complete);
|
||||||
complete(&cc2->complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
@ -532,12 +492,10 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct cc2_data *cc2 = data;
|
struct cc2_data *cc2 = data;
|
||||||
|
|
||||||
scoped_guard(mutex, &cc2->irq_lock) {
|
if (cc2->process_irqs) {
|
||||||
if (cc2->process_irqs) {
|
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
hwmon_humidity_min_alarm, 0);
|
||||||
hwmon_humidity_min_alarm, 0);
|
cc2->rh_alarm.low_alarm = true;
|
||||||
cc2->rh_alarm.low_alarm = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
@ -547,12 +505,10 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct cc2_data *cc2 = data;
|
struct cc2_data *cc2 = data;
|
||||||
|
|
||||||
scoped_guard(mutex, &cc2->irq_lock) {
|
if (cc2->process_irqs) {
|
||||||
if (cc2->process_irqs) {
|
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
hwmon_humidity_max_alarm, 0);
|
||||||
hwmon_humidity_max_alarm, 0);
|
cc2->rh_alarm.high_alarm = true;
|
||||||
cc2->rh_alarm.high_alarm = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
@ -568,13 +524,11 @@ static int cc2_humidity_min_alarm_status(struct cc2_data *data, long *val)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
scoped_guard(mutex, &data->irq_lock) {
|
if (data->rh_alarm.low_alarm) {
|
||||||
if (data->rh_alarm.low_alarm) {
|
*val = (measurement < min_hyst) ? 1 : 0;
|
||||||
*val = (measurement < min_hyst) ? 1 : 0;
|
data->rh_alarm.low_alarm = *val;
|
||||||
data->rh_alarm.low_alarm = *val;
|
} else {
|
||||||
} else {
|
*val = 0;
|
||||||
*val = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -590,13 +544,11 @@ static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
scoped_guard(mutex, &data->irq_lock) {
|
if (data->rh_alarm.high_alarm) {
|
||||||
if (data->rh_alarm.high_alarm) {
|
*val = (measurement > max_hyst) ? 1 : 0;
|
||||||
*val = (measurement > max_hyst) ? 1 : 0;
|
data->rh_alarm.high_alarm = *val;
|
||||||
data->rh_alarm.high_alarm = *val;
|
} else {
|
||||||
} else {
|
*val = 0;
|
||||||
*val = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -679,47 +631,28 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cc2_get_irqs(struct cc2_data *data, struct device *dev)
|
static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
|
||||||
{
|
|
||||||
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
|
|
||||||
if (data->irq_ready == -EPROBE_DEFER)
|
|
||||||
return data->irq_ready;
|
|
||||||
if (data->irq_ready > 0)
|
|
||||||
init_completion(&data->complete);
|
|
||||||
|
|
||||||
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
|
|
||||||
if (data->irq_low == -EPROBE_DEFER)
|
|
||||||
return data->irq_low;
|
|
||||||
if (data->irq_low > 0)
|
|
||||||
data->rh_alarm.low_alarm_visible = true;
|
|
||||||
|
|
||||||
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
|
|
||||||
if (data->irq_high == -EPROBE_DEFER)
|
|
||||||
return data->irq_high;
|
|
||||||
if (data->irq_high > 0)
|
|
||||||
data->rh_alarm.high_alarm_visible = true;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cc2_request_data_ready(struct cc2_data *data, struct device *dev)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (data->irq_ready > 0)
|
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
|
||||||
|
if (data->irq_ready > 0) {
|
||||||
|
init_completion(&data->complete);
|
||||||
ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
|
ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
|
||||||
cc2_ready_interrupt,
|
cc2_ready_interrupt,
|
||||||
IRQF_ONESHOT |
|
IRQF_ONESHOT |
|
||||||
IRQF_TRIGGER_RISING,
|
IRQF_TRIGGER_RISING,
|
||||||
dev_name(dev), data);
|
dev_name(dev), data);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cc2_request_alarms(struct cc2_data *data, struct device *dev)
|
static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
|
||||||
if (data->irq_low > 0) {
|
if (data->irq_low > 0) {
|
||||||
ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
|
ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
|
||||||
cc2_low_interrupt,
|
cc2_low_interrupt,
|
||||||
|
|
@ -728,8 +661,11 @@ static int cc2_request_alarms(struct cc2_data *data, struct device *dev)
|
||||||
dev_name(dev), data);
|
dev_name(dev), data);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
data->rh_alarm.low_alarm_visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
|
||||||
if (data->irq_high > 0) {
|
if (data->irq_high > 0) {
|
||||||
ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
|
ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
|
||||||
cc2_high_interrupt,
|
cc2_high_interrupt,
|
||||||
|
|
@ -738,6 +674,8 @@ static int cc2_request_alarms(struct cc2_data *data, struct device *dev)
|
||||||
dev_name(dev), data);
|
dev_name(dev), data);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
data->rh_alarm.high_alarm_visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -779,8 +717,6 @@ static int cc2_probe(struct i2c_client *client)
|
||||||
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
mutex_init(&data->irq_lock);
|
|
||||||
|
|
||||||
data->client = client;
|
data->client = client;
|
||||||
|
|
||||||
data->regulator = devm_regulator_get_exclusive(dev, "vdd");
|
data->regulator = devm_regulator_get_exclusive(dev, "vdd");
|
||||||
|
|
@ -790,18 +726,14 @@ static int cc2_probe(struct i2c_client *client)
|
||||||
|
|
||||||
device_property_read_string(dev, "label", &data->label);
|
device_property_read_string(dev, "label", &data->label);
|
||||||
|
|
||||||
ret = cc2_get_irqs(data, dev);
|
ret = cc2_request_ready_irq(data, dev);
|
||||||
if (ret)
|
|
||||||
return dev_err_probe(dev, ret, "Failed to get IRQs\n");
|
|
||||||
|
|
||||||
ret = devm_add_action_or_reset(dev, cc2_disable_action, data);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = cc2_request_data_ready(data, dev);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return dev_err_probe(dev, ret, "Failed to request ready irq\n");
|
return dev_err_probe(dev, ret, "Failed to request ready irq\n");
|
||||||
|
|
||||||
|
ret = cc2_request_alarm_irqs(data, dev);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
|
||||||
|
|
||||||
data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
|
data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
|
||||||
data, &cc2_chip_info,
|
data, &cc2_chip_info,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -809,13 +741,16 @@ static int cc2_probe(struct i2c_client *client)
|
||||||
return dev_err_probe(dev, PTR_ERR(data->hwmon),
|
return dev_err_probe(dev, PTR_ERR(data->hwmon),
|
||||||
"Failed to register hwmon device\n");
|
"Failed to register hwmon device\n");
|
||||||
|
|
||||||
ret = cc2_request_alarms(data, dev);
|
|
||||||
if (ret)
|
|
||||||
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cc2_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct cc2_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
cc2_disable(data);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id cc2_id[] = {
|
static const struct i2c_device_id cc2_id[] = {
|
||||||
{ .name = "cc2d23" },
|
{ .name = "cc2d23" },
|
||||||
{ .name = "cc2d23s" },
|
{ .name = "cc2d23s" },
|
||||||
|
|
@ -848,6 +783,7 @@ static struct i2c_driver cc2_driver = {
|
||||||
.of_match_table = cc2_of_match,
|
.of_match_table = cc2_of_match,
|
||||||
},
|
},
|
||||||
.probe = cc2_probe,
|
.probe = cc2_probe,
|
||||||
|
.remove = cc2_remove,
|
||||||
.id_table = cc2_id,
|
.id_table = cc2_id,
|
||||||
};
|
};
|
||||||
module_i2c_driver(cc2_driver);
|
module_i2c_driver(cc2_driver);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ struct temp_data {
|
||||||
int temp;
|
int temp;
|
||||||
bool temp_valid;
|
bool temp_valid;
|
||||||
int tjmax;
|
int tjmax;
|
||||||
u64 last_updated;
|
unsigned long last_updated;
|
||||||
unsigned int cpu;
|
unsigned int cpu;
|
||||||
int index;
|
int index;
|
||||||
u32 cpu_core_id;
|
u32 cpu_core_id;
|
||||||
|
|
@ -407,7 +407,7 @@ static ssize_t show_temp(struct device *dev,
|
||||||
mutex_lock(&tdata->update_lock);
|
mutex_lock(&tdata->update_lock);
|
||||||
|
|
||||||
/* Check whether the time interval has elapsed */
|
/* Check whether the time interval has elapsed */
|
||||||
if (time_after64(get_jiffies_64(), tdata->last_updated + HZ)) {
|
if (time_after(jiffies, tdata->last_updated + HZ)) {
|
||||||
tjmax = get_tjmax(tdata, dev);
|
tjmax = get_tjmax(tdata, dev);
|
||||||
rdmsrq_on_cpu(tdata->cpu, tdata->status_reg, &val.q);
|
rdmsrq_on_cpu(tdata->cpu, tdata->status_reg, &val.q);
|
||||||
/*
|
/*
|
||||||
|
|
@ -417,7 +417,7 @@ static ssize_t show_temp(struct device *dev,
|
||||||
*/
|
*/
|
||||||
tdata->temp_valid = (val.l >> 31) & 1;
|
tdata->temp_valid = (val.l >> 31) & 1;
|
||||||
tdata->temp = tjmax - ((val.l >> 16) & 0xff) * 1000;
|
tdata->temp = tjmax - ((val.l >> 16) & 0xff) * 1000;
|
||||||
tdata->last_updated = get_jiffies_64();
|
tdata->last_updated = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
valid = tdata->temp_valid;
|
valid = tdata->temp_valid;
|
||||||
|
|
@ -491,12 +491,11 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag)
|
||||||
struct temp_data *tdata;
|
struct temp_data *tdata;
|
||||||
|
|
||||||
if (!pdata->core_data) {
|
if (!pdata->core_data) {
|
||||||
int nr_cores = topology_num_cores_per_package();
|
pdata->nr_cores = topology_num_cores_per_package();
|
||||||
|
pdata->core_data = kzalloc_objs(struct temp_data *,
|
||||||
pdata->core_data = kzalloc_objs(struct temp_data *, nr_cores);
|
pdata->nr_cores);
|
||||||
if (!pdata->core_data)
|
if (!pdata->core_data)
|
||||||
return NULL;
|
return NULL;
|
||||||
pdata->nr_cores = nr_cores;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tdata = kzalloc_obj(struct temp_data);
|
tdata = kzalloc_obj(struct temp_data);
|
||||||
|
|
@ -521,8 +520,11 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag)
|
||||||
tdata->cpu = cpu;
|
tdata->cpu = cpu;
|
||||||
tdata->cpu_core_id = topology_core_id(cpu);
|
tdata->cpu_core_id = topology_core_id(cpu);
|
||||||
tdata->attr_size = MAX_CORE_ATTRS;
|
tdata->attr_size = MAX_CORE_ATTRS;
|
||||||
/* Backdate to force a refresh on the first read */
|
/*
|
||||||
tdata->last_updated = get_jiffies_64() - HZ - 1;
|
* A zero timestamp does not look stale on 32-bit, where jiffies
|
||||||
|
* starts just short of wrapping. Backdate it instead.
|
||||||
|
*/
|
||||||
|
tdata->last_updated = jiffies - HZ - 1;
|
||||||
mutex_init(&tdata->update_lock);
|
mutex_init(&tdata->update_lock);
|
||||||
return tdata;
|
return tdata;
|
||||||
}
|
}
|
||||||
|
|
@ -693,9 +695,6 @@ static int coretemp_cpu_online(unsigned int cpu)
|
||||||
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
|
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!pdev)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pdata = platform_get_drvdata(pdev);
|
pdata = platform_get_drvdata(pdev);
|
||||||
if (!pdata->hwmon_dev) {
|
if (!pdata->hwmon_dev) {
|
||||||
struct device *hwmon;
|
struct device *hwmon;
|
||||||
|
|
@ -747,9 +746,6 @@ static int coretemp_cpu_offline(unsigned int cpu)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If the physical CPU device does not exist, just return */
|
/* If the physical CPU device does not exist, just return */
|
||||||
if (!pdev)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pd = platform_get_drvdata(pdev);
|
pd = platform_get_drvdata(pdev);
|
||||||
if (!pd->hwmon_dev)
|
if (!pd->hwmon_dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -215,11 +215,10 @@ static int set_target(struct ccp_device *ccp, int channel, long val)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
val = clamp_val(val, 0, 0xFFFF);
|
val = clamp_val(val, 0, 0xFFFF);
|
||||||
|
ccp->target[channel] = val;
|
||||||
|
|
||||||
mutex_lock(&ccp->mutex);
|
mutex_lock(&ccp->mutex);
|
||||||
ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val);
|
ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val);
|
||||||
if (!ret)
|
|
||||||
ccp->target[channel] = val;
|
|
||||||
|
|
||||||
mutex_unlock(&ccp->mutex);
|
mutex_unlock(&ccp->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,6 @@ static void gpd_duo_set_pwm_enable(struct gpd_fan_data *data, enum FAN_PWM_ENABL
|
||||||
break;
|
break;
|
||||||
case AUTOMATIC:
|
case AUTOMATIC:
|
||||||
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write, 0);
|
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write, 0);
|
||||||
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write + 1, 0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,10 +150,7 @@ static int set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
|
||||||
|
|
||||||
__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
|
__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
|
||||||
|
|
||||||
/* The GPIOs have changed, and a PM put drops the reference on error. */
|
if (fan_data->speed_index > 0 && speed_index == 0) {
|
||||||
fan_data->speed_index = speed_index;
|
|
||||||
|
|
||||||
if (speed_index == 0) {
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = pm_runtime_put_sync(fan_data->dev);
|
ret = pm_runtime_put_sync(fan_data->dev);
|
||||||
|
|
@ -161,6 +158,8 @@ static int set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fan_data->speed_index = speed_index;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,6 @@ struct hp_wmi_info {
|
||||||
*/
|
*/
|
||||||
struct hp_wmi_sensors {
|
struct hp_wmi_sensors {
|
||||||
struct wmi_device *wdev;
|
struct wmi_device *wdev;
|
||||||
struct hwmon_chip_info chip_info;
|
|
||||||
struct hp_wmi_info **info_map[hwmon_max];
|
struct hp_wmi_info **info_map[hwmon_max];
|
||||||
u8 channel_count[hwmon_max];
|
u8 channel_count[hwmon_max];
|
||||||
bool has_intrusion;
|
bool has_intrusion;
|
||||||
|
|
@ -739,21 +738,15 @@ static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
|
||||||
|
|
||||||
val = current_reading;
|
val = current_reading;
|
||||||
|
|
||||||
for (; val && unit_modifier < target_modifier; unit_modifier++)
|
for (; unit_modifier < target_modifier; unit_modifier++)
|
||||||
val = DIV_ROUND_CLOSEST(val, 10);
|
val = DIV_ROUND_CLOSEST(val, 10);
|
||||||
|
|
||||||
if (val) {
|
for (; unit_modifier > target_modifier; unit_modifier--) {
|
||||||
for (; unit_modifier > target_modifier; unit_modifier--) {
|
if (val > LONG_MAX / 10) {
|
||||||
if (val > LONG_MAX / 10) {
|
val = LONG_MAX;
|
||||||
val = LONG_MAX;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (val < LONG_MIN / 10) {
|
|
||||||
val = LONG_MIN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val *= 10;
|
|
||||||
}
|
}
|
||||||
|
val *= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {
|
if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {
|
||||||
|
|
@ -1480,10 +1473,8 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
|
|
||||||
if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
|
if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
|
||||||
(type == hwmon_fan && attr == hwmon_fan_alarm)) {
|
(type == hwmon_fan && attr == hwmon_fan_alarm)) {
|
||||||
mutex_lock(&state->lock);
|
|
||||||
*out_val = info->alarm ? 1 : 0;
|
*out_val = info->alarm ? 1 : 0;
|
||||||
info->alarm = false;
|
info->alarm = false;
|
||||||
mutex_unlock(&state->lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1540,6 +1531,11 @@ static const struct hwmon_ops hp_wmi_hwmon_ops = {
|
||||||
.write = hp_wmi_hwmon_write,
|
.write = hp_wmi_hwmon_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct hwmon_chip_info hp_wmi_chip_info = {
|
||||||
|
.ops = &hp_wmi_hwmon_ops,
|
||||||
|
.info = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
|
static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
|
||||||
const char *event_description)
|
const char *event_description)
|
||||||
{
|
{
|
||||||
|
|
@ -1966,8 +1962,7 @@ static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)
|
||||||
if (!ptr_channel_info)
|
if (!ptr_channel_info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
state->chip_info.ops = &hp_wmi_hwmon_ops;
|
hp_wmi_chip_info.info = ptr_channel_info;
|
||||||
state->chip_info.info = ptr_channel_info;
|
|
||||||
|
|
||||||
for (type = hwmon_chip; type < hwmon_max; type++) {
|
for (type = hwmon_chip; type < hwmon_max; type++) {
|
||||||
count = channel_count[type];
|
count = channel_count[type];
|
||||||
|
|
@ -2058,7 +2053,7 @@ static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
|
hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
|
||||||
state, &state->chip_info,
|
state, &hp_wmi_chip_info,
|
||||||
NULL);
|
NULL);
|
||||||
return PTR_ERR_OR_ZERO(hwdev);
|
return PTR_ERR_OR_ZERO(hwdev);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,8 @@ struct lm75_data {
|
||||||
|
|
||||||
static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
|
static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
|
||||||
|
|
||||||
#define LM75_ALERT_POLARITY_HIGH_BIT BIT(2)
|
#define LM75_ALERT_POLARITY_HIGH_8_BIT (BIT(2))
|
||||||
|
#define LM75_ALERT_POLARITY_HIGH_16_BIT (BIT(2) << 8)
|
||||||
#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
|
#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
|
||||||
|
|
||||||
/* The structure below stores the configuration values of the supported devices.
|
/* The structure below stores the configuration values of the supported devices.
|
||||||
|
|
@ -769,7 +770,11 @@ static int lm75_generic_probe(struct device *dev, const char *name,
|
||||||
data->orig_conf = status;
|
data->orig_conf = status;
|
||||||
|
|
||||||
/* Enforce polarity active-low (default) or active-high (devicetree) */
|
/* Enforce polarity active-low (default) or active-high (devicetree) */
|
||||||
pol_mask = LM75_ALERT_POLARITY_HIGH_BIT;
|
if (!data->params->config_reg_16bits)
|
||||||
|
pol_mask = LM75_ALERT_POLARITY_HIGH_8_BIT;
|
||||||
|
else
|
||||||
|
pol_mask = LM75_ALERT_POLARITY_HIGH_16_BIT;
|
||||||
|
|
||||||
clr_mask = data->params->clr_mask | pol_mask;
|
clr_mask = data->params->clr_mask | pol_mask;
|
||||||
set_mask = data->params->set_mask & ~pol_mask;
|
set_mask = data->params->set_mask & ~pol_mask;
|
||||||
if (device_property_read_bool(dev, "ti,alert-polarity-active-high"))
|
if (device_property_read_bool(dev, "ti,alert-polarity-active-high"))
|
||||||
|
|
|
||||||
|
|
@ -606,16 +606,13 @@ static DEVICE_ATTR_RO(cpu0_vid);
|
||||||
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
|
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = dev_get_drvdata(dev);
|
struct lm87_data *data = dev_get_drvdata(dev);
|
||||||
struct lm87_data *data = i2c_get_clientdata(client);
|
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", data->vrm);
|
return sprintf(buf, "%d\n", data->vrm);
|
||||||
}
|
}
|
||||||
static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
|
static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = dev_get_drvdata(dev);
|
struct lm87_data *data = dev_get_drvdata(dev);
|
||||||
struct lm87_data *data = i2c_get_clientdata(client);
|
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -920,7 +920,7 @@ static ssize_t
|
||||||
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
|
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct nct6683_data *data = nct6683_update_device(dev);
|
struct nct6683_data *data = nct6683_update_device(dev);
|
||||||
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
|
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||||
int index = sattr->index;
|
int index = sattr->index;
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", data->pwm[index]);
|
return sprintf(buf, "%d\n", data->pwm[index]);
|
||||||
|
|
@ -930,7 +930,7 @@ static ssize_t
|
||||||
store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
|
store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
|
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||||
struct nct6683_data *data = dev_get_drvdata(dev);
|
struct nct6683_data *data = dev_get_drvdata(dev);
|
||||||
int index = sattr->index;
|
int index = sattr->index;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <linux/auxiliary_bus.h>
|
#include <linux/auxiliary_bus.h>
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/devm-helpers.h>
|
||||||
#include <linux/hwmon.h>
|
#include <linux/hwmon.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
@ -325,13 +326,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
|
||||||
if (ret == -ENODEV) {
|
if (ret == -ENODEV) {
|
||||||
dev_dbg(priv->dev, "No DIMMs found\n");
|
dev_dbg(priv->dev, "No DIMMs found\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else if (ret) {
|
||||||
if (ret == -EAGAIN) {
|
|
||||||
schedule_delayed_work(&priv->detect_work, DIMM_MASK_CHECK_DELAY_JIFFIES);
|
schedule_delayed_work(&priv->detect_work, DIMM_MASK_CHECK_DELAY_JIFFIES);
|
||||||
dev_dbg(priv->dev, "Deferred populating DIMM temp info\n");
|
dev_dbg(priv->dev, "Deferred populating DIMM temp info\n");
|
||||||
}
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
channels = priv->gen_info->chan_rank_max * priv->gen_info->dimm_idx_max;
|
channels = priv->gen_info->chan_rank_max * priv->gen_info->dimm_idx_max;
|
||||||
|
|
||||||
|
|
@ -399,8 +398,10 @@ static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxil
|
||||||
"Unexpected PECI revision %#x, some features may be unavailable\n",
|
"Unexpected PECI revision %#x, some features may be unavailable\n",
|
||||||
peci_dev->info.peci_revision);
|
peci_dev->info.peci_revision);
|
||||||
|
|
||||||
auxiliary_set_drvdata(adev, priv);
|
ret = devm_delayed_work_autocancel(priv->dev, &priv->detect_work,
|
||||||
INIT_DELAYED_WORK(&priv->detect_work, create_dimm_temp_info_delayed);
|
create_dimm_temp_info_delayed);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = create_dimm_temp_info(priv);
|
ret = create_dimm_temp_info(priv);
|
||||||
if (ret && ret != -EAGAIN) {
|
if (ret && ret != -EAGAIN) {
|
||||||
|
|
@ -411,13 +412,6 @@ static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxil
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void peci_dimmtemp_remove(struct auxiliary_device *adev)
|
|
||||||
{
|
|
||||||
struct peci_dimmtemp *priv = auxiliary_get_drvdata(adev);
|
|
||||||
|
|
||||||
cancel_delayed_work_sync(&priv->detect_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_thresholds_hsx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
|
read_thresholds_hsx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
|
||||||
{
|
{
|
||||||
|
|
@ -671,7 +665,6 @@ MODULE_DEVICE_TABLE(auxiliary, peci_dimmtemp_ids);
|
||||||
|
|
||||||
static struct auxiliary_driver peci_dimmtemp_driver = {
|
static struct auxiliary_driver peci_dimmtemp_driver = {
|
||||||
.probe = peci_dimmtemp_probe,
|
.probe = peci_dimmtemp_probe,
|
||||||
.remove = peci_dimmtemp_remove,
|
|
||||||
.id_table = peci_dimmtemp_ids,
|
.id_table = peci_dimmtemp_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1524,22 +1524,14 @@ static int pmbus_thermal_add_sensor(struct pmbus_data *pmbus_data,
|
||||||
tdata->sensor = sensor;
|
tdata->sensor = sensor;
|
||||||
tdata->pmbus_data = pmbus_data;
|
tdata->pmbus_data = pmbus_data;
|
||||||
|
|
||||||
/*
|
tzd = devm_thermal_of_zone_register(dev, index, tdata,
|
||||||
* The PMBus core numbers its temperature sensors from 1, as the
|
|
||||||
* hwmon tempN attributes, while the thermal core expects a 0-based
|
|
||||||
* sensor index.
|
|
||||||
*/
|
|
||||||
tzd = devm_thermal_of_zone_register(dev, index - 1, tdata,
|
|
||||||
&pmbus_thermal_ops);
|
&pmbus_thermal_ops);
|
||||||
/*
|
/*
|
||||||
* If CONFIG_THERMAL_OF is disabled, devm_thermal_of_zone_register()
|
* If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
|
||||||
* returns -ENOTSUPP. If no thermal zone is configured for the sensor,
|
* so ignore that error but forward any other error.
|
||||||
* it returns -ENODEV. Ignore those errors but forward any other error.
|
|
||||||
*/
|
*/
|
||||||
if (IS_ERR(tzd) && PTR_ERR(tzd) != -ENODEV && PTR_ERR(tzd) != -ENOTSUPP) {
|
if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV))
|
||||||
devm_kfree(dev, tdata);
|
|
||||||
return PTR_ERR(tzd);
|
return PTR_ERR(tzd);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1554,11 +1546,10 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
||||||
{
|
{
|
||||||
struct sensor_device_attribute *a;
|
struct sensor_device_attribute *a;
|
||||||
struct pmbus_sensor *sensor;
|
struct pmbus_sensor *sensor;
|
||||||
int err;
|
|
||||||
|
|
||||||
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
|
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
|
||||||
if (!sensor)
|
if (!sensor)
|
||||||
return ERR_PTR(-ENOMEM);
|
return NULL;
|
||||||
a = &sensor->attribute;
|
a = &sensor->attribute;
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
|
|
@ -1583,17 +1574,14 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
||||||
pmbus_set_sensor, -1);
|
pmbus_set_sensor, -1);
|
||||||
|
|
||||||
if (pmbus_add_attribute(data, &a->dev_attr.attr))
|
if (pmbus_add_attribute(data, &a->dev_attr.attr))
|
||||||
return ERR_PTR(-ENOMEM);
|
return NULL;
|
||||||
|
|
||||||
sensor->next = data->sensors;
|
sensor->next = data->sensors;
|
||||||
data->sensors = sensor;
|
data->sensors = sensor;
|
||||||
|
|
||||||
/* temperature sensors with _input values are registered with thermal */
|
/* temperature sensors with _input values are registered with thermal */
|
||||||
if (class == PSC_TEMPERATURE && strcmp(type, "input") == 0) {
|
if (class == PSC_TEMPERATURE && strcmp(type, "input") == 0)
|
||||||
err = pmbus_thermal_add_sensor(data, sensor, seq);
|
pmbus_thermal_add_sensor(data, sensor, seq);
|
||||||
if (err)
|
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sensor;
|
return sensor;
|
||||||
}
|
}
|
||||||
|
|
@ -1694,8 +1682,8 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
|
||||||
page, 0xff, l->reg, attr->class,
|
page, 0xff, l->reg, attr->class,
|
||||||
attr->update || l->update,
|
attr->update || l->update,
|
||||||
l->readonly, l->writeonly, true);
|
l->readonly, l->writeonly, true);
|
||||||
if (IS_ERR(curr))
|
if (!curr)
|
||||||
return PTR_ERR(curr);
|
return -ENOMEM;
|
||||||
if (l->sbit && (info->func[page] & attr->sfunc)) {
|
if (l->sbit && (info->func[page] & attr->sfunc)) {
|
||||||
ret = pmbus_add_boolean(data, name,
|
ret = pmbus_add_boolean(data, name,
|
||||||
l->alarm, index,
|
l->alarm, index,
|
||||||
|
|
@ -1734,8 +1722,8 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
|
||||||
}
|
}
|
||||||
base = pmbus_add_sensor(data, name, "input", index, page, phase,
|
base = pmbus_add_sensor(data, name, "input", index, page, phase,
|
||||||
attr->reg, attr->class, true, true, false, true);
|
attr->reg, attr->class, true, true, false, true);
|
||||||
if (IS_ERR(base))
|
if (!base)
|
||||||
return PTR_ERR(base);
|
return -ENOMEM;
|
||||||
/* No limit and alarm attributes for phase specific sensors */
|
/* No limit and alarm attributes for phase specific sensors */
|
||||||
if (attr->sfunc && phase == 0xff) {
|
if (attr->sfunc && phase == 0xff) {
|
||||||
ret = pmbus_add_limit_attrs(client, data, info, name,
|
ret = pmbus_add_limit_attrs(client, data, info, name,
|
||||||
|
|
@ -2408,8 +2396,8 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
|
||||||
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
|
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
|
||||||
false, false, false, true);
|
false, false, false, true);
|
||||||
|
|
||||||
if (IS_ERR(sensor))
|
if (!sensor)
|
||||||
return PTR_ERR(sensor);
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!((data->info->func[page] & PMBUS_HAVE_PWM12) ||
|
if (!((data->info->func[page] & PMBUS_HAVE_PWM12) ||
|
||||||
(data->info->func[page] & PMBUS_HAVE_PWM34)))
|
(data->info->func[page] & PMBUS_HAVE_PWM34)))
|
||||||
|
|
@ -2419,15 +2407,15 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
|
||||||
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
|
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
|
||||||
false, false, false, true);
|
false, false, false, true);
|
||||||
|
|
||||||
if (IS_ERR(sensor))
|
if (!sensor)
|
||||||
return PTR_ERR(sensor);
|
return -ENOMEM;
|
||||||
|
|
||||||
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
|
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
|
||||||
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
|
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
|
||||||
true, false, false, false);
|
true, false, false, false);
|
||||||
|
|
||||||
if (IS_ERR(sensor))
|
if (!sensor)
|
||||||
return PTR_ERR(sensor);
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -2444,7 +2432,6 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
|
||||||
int f;
|
int f;
|
||||||
|
|
||||||
for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
|
for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
|
||||||
struct pmbus_sensor *sensor;
|
|
||||||
int regval;
|
int regval;
|
||||||
|
|
||||||
if (!(info->func[page] & pmbus_fan_flags[f]))
|
if (!(info->func[page] & pmbus_fan_flags[f]))
|
||||||
|
|
@ -2465,11 +2452,10 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
|
||||||
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
|
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sensor = pmbus_add_sensor(data, "fan", "input", index,
|
if (pmbus_add_sensor(data, "fan", "input", index,
|
||||||
page, 0xff, pmbus_fan_registers[f],
|
page, 0xff, pmbus_fan_registers[f],
|
||||||
PSC_FAN, true, true, false, true);
|
PSC_FAN, true, true, false, true) == NULL)
|
||||||
if (IS_ERR(sensor))
|
return -ENOMEM;
|
||||||
return PTR_ERR(sensor);
|
|
||||||
|
|
||||||
/* Fan control */
|
/* Fan control */
|
||||||
if (pmbus_check_word_register(client, page,
|
if (pmbus_check_word_register(client, page,
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,6 @@ static int q54sj108a2_probe(struct i2c_client *client)
|
||||||
psu->client = client;
|
psu->client = client;
|
||||||
|
|
||||||
debugfs = pmbus_get_debugfs_dir(client);
|
debugfs = pmbus_get_debugfs_dir(client);
|
||||||
if (!debugfs)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
q54sj108a2_dir = debugfs_create_dir(client->name, debugfs);
|
q54sj108a2_dir = debugfs_create_dir(client->name, debugfs);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include <linux/bitrev.h>
|
#include <linux/bitrev.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/workqueue.h>
|
|
||||||
|
|
||||||
/* Commands */
|
/* Commands */
|
||||||
#define SHT15_MEASURE_TEMP 0x03
|
#define SHT15_MEASURE_TEMP 0x03
|
||||||
|
|
@ -977,22 +976,25 @@ static int sht15_probe(struct platform_device *pdev)
|
||||||
goto err_release_reg;
|
goto err_release_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = request_irq(gpiod_to_irq(data->data), sht15_interrupt_fired,
|
ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
|
||||||
IRQF_TRIGGER_FALLING, "sht15 data", data);
|
sht15_interrupt_fired,
|
||||||
|
IRQF_TRIGGER_FALLING,
|
||||||
|
"sht15 data",
|
||||||
|
data);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_release_reg;
|
goto err_release_reg;
|
||||||
disable_irq_nosync(gpiod_to_irq(data->data));
|
disable_irq_nosync(gpiod_to_irq(data->data));
|
||||||
ret = sht15_connection_reset(data);
|
ret = sht15_connection_reset(data);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_irq;
|
goto err_release_reg;
|
||||||
ret = sht15_soft_reset(data);
|
ret = sht15_soft_reset(data);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_irq;
|
goto err_release_reg;
|
||||||
|
|
||||||
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
|
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "sysfs create failed\n");
|
dev_err(&pdev->dev, "sysfs create failed\n");
|
||||||
goto err_free_irq;
|
goto err_release_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(data->dev);
|
data->hwmon_dev = hwmon_device_register(data->dev);
|
||||||
|
|
@ -1005,13 +1007,9 @@ static int sht15_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
err_release_sysfs_group:
|
err_release_sysfs_group:
|
||||||
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
|
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
|
||||||
err_free_irq:
|
|
||||||
disable_work_sync(&data->read_work);
|
|
||||||
free_irq(gpiod_to_irq(data->data), data);
|
|
||||||
err_release_reg:
|
err_release_reg:
|
||||||
if (!IS_ERR(data->reg)) {
|
if (!IS_ERR(data->reg)) {
|
||||||
regulator_unregister_notifier(data->reg, &data->nb);
|
regulator_unregister_notifier(data->reg, &data->nb);
|
||||||
cancel_work_sync(&data->update_supply_work);
|
|
||||||
regulator_disable(data->reg);
|
regulator_disable(data->reg);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -1025,16 +1023,12 @@ static void sht15_remove(struct platform_device *pdev)
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
|
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
|
||||||
|
|
||||||
disable_work_sync(&data->read_work);
|
|
||||||
free_irq(gpiod_to_irq(data->data), data);
|
|
||||||
|
|
||||||
ret = sht15_soft_reset(data);
|
ret = sht15_soft_reset(data);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
|
dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
|
||||||
|
|
||||||
if (!IS_ERR(data->reg)) {
|
if (!IS_ERR(data->reg)) {
|
||||||
regulator_unregister_notifier(data->reg, &data->nb);
|
regulator_unregister_notifier(data->reg, &data->nb);
|
||||||
cancel_work_sync(&data->update_supply_work);
|
|
||||||
regulator_disable(data->reg);
|
regulator_disable(data->reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,7 @@ static int sht4x_read_values(struct sht4x_data *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->data_pending &&
|
if (data->data_pending &&
|
||||||
time_before64(get_jiffies_64(),
|
time_before64(get_jiffies_64(), data->heating_complete + data->update_interval)) {
|
||||||
data->heating_complete +
|
|
||||||
msecs_to_jiffies(data->update_interval))) {
|
|
||||||
data->data_pending = false;
|
data->data_pending = false;
|
||||||
} else {
|
} else {
|
||||||
next_update = data->last_updated +
|
next_update = data->last_updated +
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/i3c/device.h>
|
#include <linux/i3c/device.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/ktime.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
struct tmp108 {
|
struct tmp108 {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
u16 orig_config;
|
u16 orig_config;
|
||||||
ktime_t ready_time;
|
u64 ready_time;
|
||||||
const struct tmp108_params *params;
|
const struct tmp108_params *params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -121,7 +121,6 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
struct tmp108 *tmp108 = dev_get_drvdata(dev);
|
struct tmp108 *tmp108 = dev_get_drvdata(dev);
|
||||||
unsigned int regval;
|
unsigned int regval;
|
||||||
int err, hyst;
|
int err, hyst;
|
||||||
s64 delay;
|
|
||||||
|
|
||||||
if (type == hwmon_chip) {
|
if (type == hwmon_chip) {
|
||||||
if (attr == hwmon_chip_update_interval) {
|
if (attr == hwmon_chip_update_interval) {
|
||||||
|
|
@ -138,10 +137,12 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
|
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case hwmon_temp_input:
|
case hwmon_temp_input:
|
||||||
/* Wait if it is too early to return a conversion */
|
/* Is it too early to return a conversion ? */
|
||||||
delay = ktime_us_delta(tmp108->ready_time, ktime_get());
|
if (time_before64(get_jiffies_64(), tmp108->ready_time)) {
|
||||||
if (delay > 0)
|
dev_dbg(dev, "%s: Conversion not ready yet..\n",
|
||||||
usleep_range(delay, delay + 1000);
|
__func__);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val);
|
err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -476,8 +477,11 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp108->ready_time = ktime_add_ms(ktime_get(),
|
tmp108->ready_time = get_jiffies_64();
|
||||||
TMP108_CONVERSION_TIME_MS);
|
if ((tmp108->orig_config & TMP108_CONF_MODE_MASK) ==
|
||||||
|
TMP108_MODE_SHUTDOWN)
|
||||||
|
tmp108->ready_time +=
|
||||||
|
msecs_to_jiffies(TMP108_CONVERSION_TIME_MS);
|
||||||
|
|
||||||
err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108);
|
err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -524,8 +528,8 @@ static int tmp108_resume(struct device *dev)
|
||||||
|
|
||||||
err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF,
|
err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF,
|
||||||
TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS);
|
TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS);
|
||||||
tmp108->ready_time = ktime_add_ms(ktime_get(),
|
tmp108->ready_time = get_jiffies_64() +
|
||||||
TMP108_CONVERSION_TIME_MS);
|
msecs_to_jiffies(TMP108_CONVERSION_TIME_MS);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ extern u8 amd_iommu_hpt_vasize;
|
||||||
extern unsigned long amd_iommu_pgsize_bitmap;
|
extern unsigned long amd_iommu_pgsize_bitmap;
|
||||||
extern bool amd_iommu_hatdis;
|
extern bool amd_iommu_hatdis;
|
||||||
|
|
||||||
int amd_iommu_perfopt_set(struct amd_iommu *iommu, bool enable);
|
int amd_iommu_perfopt_clear(struct amd_iommu *iommu);
|
||||||
|
int amd_iommu_perfopt_restore(struct amd_iommu *iommu);
|
||||||
|
|
||||||
/* Protection domain ops */
|
/* Protection domain ops */
|
||||||
void amd_iommu_init_identity_domain(void);
|
void amd_iommu_init_identity_domain(void);
|
||||||
|
|
|
||||||
|
|
@ -660,8 +660,8 @@ struct amd_iommu {
|
||||||
/* Extended features 2 */
|
/* Extended features 2 */
|
||||||
u64 features2;
|
u64 features2;
|
||||||
|
|
||||||
/* Saved PerfOpt activation state, protected by @lock. */
|
/* Devices requesting PerfOpt; the shared PERF_OPT_EN bit is on while >0. Protected by @lock. */
|
||||||
bool perfopt_enabled;
|
int perfopt_refcount;
|
||||||
|
|
||||||
/* PCI device id of the IOMMU device */
|
/* PCI device id of the IOMMU device */
|
||||||
u16 devid;
|
u16 devid;
|
||||||
|
|
@ -824,7 +824,7 @@ struct iommu_dev_data {
|
||||||
u8 ppr :1; /* Enable device PPR support */
|
u8 ppr :1; /* Enable device PPR support */
|
||||||
bool use_vapic; /* Enable device to use vapic mode */
|
bool use_vapic; /* Enable device to use vapic mode */
|
||||||
bool defer_attach;
|
bool defer_attach;
|
||||||
bool perfopt; /* Device is eligible for PerfOpt */
|
bool perfopt;
|
||||||
|
|
||||||
struct ratelimit_state rs; /* Ratelimit IOPF messages */
|
struct ratelimit_state rs; /* Ratelimit IOPF messages */
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -432,41 +432,8 @@ static void iommu_enable(struct amd_iommu *iommu)
|
||||||
iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
|
iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Program or clear the per-IOMMU PerfOpt enable bit.
|
|
||||||
* Gate on this IOMMU's own EFR, not the global AND-mask.
|
|
||||||
* Caller serializes access using iommu->lock or during init/suspend/resume.
|
|
||||||
*/
|
|
||||||
int amd_iommu_perfopt_set(struct amd_iommu *iommu, bool enable)
|
|
||||||
{
|
|
||||||
u32 old, val, readback;
|
|
||||||
|
|
||||||
if (!(readq(iommu->mmio_base + MMIO_EXT_FEATURES) & FEATURE_PERF_OPT))
|
|
||||||
return enable ? -ENODEV : 0;
|
|
||||||
|
|
||||||
old = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
|
||||||
if (old == U32_MAX)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
val = enable ? old | PERF_OPT_EN : old & ~PERF_OPT_EN;
|
|
||||||
if (val != old)
|
|
||||||
writel(val, iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
|
||||||
readback = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
|
||||||
if (readback == U32_MAX ||
|
|
||||||
(readback & PERF_OPT_EN) != (val & PERF_OPT_EN))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
iommu->perfopt_enabled = enable;
|
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
pr_err("IOMMU%d: failed to set PerfOpt to %d\n", iommu->index, enable);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iommu_disable(struct amd_iommu *iommu)
|
static void iommu_disable(struct amd_iommu *iommu)
|
||||||
{
|
{
|
||||||
bool perfopt_enabled = iommu->perfopt_enabled;
|
|
||||||
|
|
||||||
if (!iommu->mmio_base)
|
if (!iommu->mmio_base)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -490,10 +457,6 @@ static void iommu_disable(struct amd_iommu *iommu)
|
||||||
|
|
||||||
/* Clear IRTE cache disabling bit */
|
/* Clear IRTE cache disabling bit */
|
||||||
iommu_feature_disable(iommu, CONTROL_IRTCACHEDIS);
|
iommu_feature_disable(iommu, CONTROL_IRTCACHEDIS);
|
||||||
|
|
||||||
/* Clear hardware while preserving the activation state for resume. */
|
|
||||||
amd_iommu_perfopt_set(iommu, false);
|
|
||||||
iommu->perfopt_enabled = perfopt_enabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1925,7 +1888,6 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
|
||||||
struct acpi_table_header *ivrs_base)
|
struct acpi_table_header *ivrs_base)
|
||||||
{
|
{
|
||||||
struct amd_iommu_pci_seg *pci_seg;
|
struct amd_iommu_pci_seg *pci_seg;
|
||||||
int ret;
|
|
||||||
|
|
||||||
pci_seg = get_pci_segment(h->pci_seg, ivrs_base);
|
pci_seg = get_pci_segment(h->pci_seg, ivrs_base);
|
||||||
if (pci_seg == NULL)
|
if (pci_seg == NULL)
|
||||||
|
|
@ -1998,10 +1960,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
|
||||||
if (!iommu->mmio_base)
|
if (!iommu->mmio_base)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* A crash kernel may reuse device tables with PerfOpt still enabled. */
|
if (amd_iommu_perfopt_clear(iommu))
|
||||||
ret = amd_iommu_perfopt_set(iommu, false);
|
pr_err("IOMMU%d: failed to clear PerfOpt\n", iommu->index);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return init_iommu_from_acpi(iommu, h);
|
return init_iommu_from_acpi(iommu, h);
|
||||||
}
|
}
|
||||||
|
|
@ -2371,9 +2331,6 @@ static void print_iommu_info(void)
|
||||||
if (check_feature2(FEATURE_SEVSNPIO_SUP))
|
if (check_feature2(FEATURE_SEVSNPIO_SUP))
|
||||||
pr_cont(" SEV-TIO");
|
pr_cont(" SEV-TIO");
|
||||||
|
|
||||||
if (check_feature(FEATURE_PERF_OPT))
|
|
||||||
pr_cont(" PerfOpt");
|
|
||||||
|
|
||||||
pr_cont("\n");
|
pr_cont("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2776,15 +2733,6 @@ static int __init init_unity_map_range(struct ivmd_header *m,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ivrs_block_type_ivmd(u8 type)
|
|
||||||
{
|
|
||||||
if (type == ACPI_IVMD_TYPE ||
|
|
||||||
type == ACPI_IVMD_TYPE_ALL ||
|
|
||||||
type == ACPI_IVMD_TYPE_RANGE)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* iterates over all memory definitions we find in the ACPI table */
|
/* iterates over all memory definitions we find in the ACPI table */
|
||||||
static int __init init_memory_definitions(struct acpi_table_header *table)
|
static int __init init_memory_definitions(struct acpi_table_header *table)
|
||||||
{
|
{
|
||||||
|
|
@ -2796,11 +2744,10 @@ static int __init init_memory_definitions(struct acpi_table_header *table)
|
||||||
|
|
||||||
while (p < end) {
|
while (p < end) {
|
||||||
m = (struct ivmd_header *)p;
|
m = (struct ivmd_header *)p;
|
||||||
p += m->length;
|
|
||||||
if (!ivrs_block_type_ivmd(m->type))
|
|
||||||
continue;
|
|
||||||
if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE))
|
if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE))
|
||||||
init_unity_map_range(m, table);
|
init_unity_map_range(m, table);
|
||||||
|
|
||||||
|
p += m->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -3120,10 +3067,46 @@ static void enable_iommus_vapic(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int clear_perfopt_all(void)
|
||||||
|
{
|
||||||
|
struct amd_iommu *iommu;
|
||||||
|
int err, ret = 0;
|
||||||
|
|
||||||
|
for_each_iommu(iommu) {
|
||||||
|
err = amd_iommu_perfopt_clear(iommu);
|
||||||
|
if (err)
|
||||||
|
ret = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int restore_perfopt_all(void)
|
||||||
|
{
|
||||||
|
struct amd_iommu *iommu;
|
||||||
|
int err, ret = 0;
|
||||||
|
|
||||||
|
for_each_iommu(iommu) {
|
||||||
|
err = amd_iommu_perfopt_restore(iommu);
|
||||||
|
if (err)
|
||||||
|
ret = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void disable_iommus(void)
|
static void disable_iommus(void)
|
||||||
{
|
{
|
||||||
struct amd_iommu *iommu;
|
struct amd_iommu *iommu;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PerfOpt is an optional performance bit, so a failure to clear it must
|
||||||
|
* not skip the mandatory disable below. This also runs from the void
|
||||||
|
* amd_iommu_disable() shutdown/kexec path, which cannot report an error.
|
||||||
|
*/
|
||||||
|
if (clear_perfopt_all())
|
||||||
|
pr_err("Failed to clear PerfOpt while disabling IOMMUs\n");
|
||||||
|
|
||||||
for_each_iommu(iommu)
|
for_each_iommu(iommu)
|
||||||
iommu_disable(iommu);
|
iommu_disable(iommu);
|
||||||
|
|
||||||
|
|
@ -3149,11 +3132,9 @@ static void amd_iommu_resume(void *data)
|
||||||
for_each_iommu(iommu)
|
for_each_iommu(iommu)
|
||||||
early_enable_iommu(iommu);
|
early_enable_iommu(iommu);
|
||||||
|
|
||||||
/* Restore the activation state saved at suspend. */
|
/* early_enable_iommu() cleared PERF_OPT_EN; re-assert it from the refcount. */
|
||||||
for_each_iommu(iommu) {
|
if (restore_perfopt_all())
|
||||||
if (iommu->perfopt_enabled)
|
pr_err("Failed to restore PerfOpt after IOMMU resume\n");
|
||||||
amd_iommu_perfopt_set(iommu, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
iommu_enable_event_buffer();
|
iommu_enable_event_buffer();
|
||||||
amd_iommu_enable_interrupts();
|
amd_iommu_enable_interrupts();
|
||||||
|
|
@ -3524,7 +3505,6 @@ static __init void iommu_snp_enable(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
disable_snp:
|
disable_snp:
|
||||||
amd_iommu_snp_en = false;
|
|
||||||
cc_platform_clear(CC_ATTR_HOST_SEV_SNP);
|
cc_platform_clear(CC_ATTR_HOST_SEV_SNP);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/cleanup.h>
|
|
||||||
#include <linux/pci-ats.h>
|
#include <linux/pci-ats.h>
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
@ -488,10 +487,6 @@ static void setup_aliases(struct amd_iommu *iommu, struct device *dev)
|
||||||
clone_aliases(iommu, dev);
|
clone_aliases(iommu, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We keep dev_data around for unplugged devices and reuse it when the
|
|
||||||
* device is re-plugged - not doing so would introduce a ton of races.
|
|
||||||
*/
|
|
||||||
static struct iommu_dev_data *find_dev_data(struct amd_iommu *iommu, u16 devid)
|
static struct iommu_dev_data *find_dev_data(struct amd_iommu *iommu, u16 devid)
|
||||||
{
|
{
|
||||||
struct iommu_dev_data *dev_data;
|
struct iommu_dev_data *dev_data;
|
||||||
|
|
@ -2373,7 +2368,7 @@ static int attach_device(struct device *dev,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (dev_data->perfopt && pdom_is_in_pt_mode(domain))
|
if (dev_data->perfopt)
|
||||||
goto skip_caps;
|
goto skip_caps;
|
||||||
|
|
||||||
/* Setup GCR3 table */
|
/* Setup GCR3 table */
|
||||||
|
|
@ -2515,6 +2510,192 @@ static int iommu_init_device_caps(struct iommu_dev_data *dev_data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Program the per-IOMMU PerfOpt enable bit. Caller must hold iommu->lock. */
|
||||||
|
static int __perfopt_write(struct amd_iommu *iommu, bool enable)
|
||||||
|
{
|
||||||
|
u32 old, val, readback;
|
||||||
|
|
||||||
|
if (!(readq(iommu->mmio_base + MMIO_EXT_FEATURES) & FEATURE_PERF_OPT))
|
||||||
|
return enable ? -ENODEV : 0;
|
||||||
|
|
||||||
|
old = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
||||||
|
if (old == U32_MAX)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
val = enable ? old | PERF_OPT_EN : old & ~PERF_OPT_EN;
|
||||||
|
if (val != old)
|
||||||
|
writel(val, iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
||||||
|
readback = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
||||||
|
if (readback == U32_MAX ||
|
||||||
|
(readback & PERF_OPT_EN) != (val & PERF_OPT_EN))
|
||||||
|
return -EIO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PERF_OPT_EN is a single bit shared by every device behind @iommu, so it is
|
||||||
|
* reference counted: armed on the first requesting device, cleared on the last.
|
||||||
|
*/
|
||||||
|
static int perfopt_get(struct amd_iommu *iommu)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!iommu->mmio_base)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||||
|
if (iommu->perfopt_refcount == 0) {
|
||||||
|
ret = __perfopt_write(iommu, true);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
iommu->perfopt_refcount++;
|
||||||
|
out:
|
||||||
|
raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int perfopt_put(struct amd_iommu *iommu)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!iommu->mmio_base)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||||
|
if (iommu->perfopt_refcount > 0 && --iommu->perfopt_refcount == 0)
|
||||||
|
ret = __perfopt_write(iommu, false);
|
||||||
|
raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force PERF_OPT_EN off without touching the refcount (used on init, shutdown,
|
||||||
|
* and suspend). The count is preserved so amd_iommu_perfopt_restore() can
|
||||||
|
* re-arm on resume.
|
||||||
|
*/
|
||||||
|
int amd_iommu_perfopt_clear(struct amd_iommu *iommu)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!iommu->mmio_base)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||||
|
ret = __perfopt_write(iommu, false);
|
||||||
|
raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Re-assert PERF_OPT_EN from the refcount after the hardware was reprogrammed on
|
||||||
|
* resume, so devices armed before suspend keep the optimization without each
|
||||||
|
* consumer driver re-arming.
|
||||||
|
*/
|
||||||
|
int amd_iommu_perfopt_restore(struct amd_iommu *iommu)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!iommu->mmio_base)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||||
|
ret = __perfopt_write(iommu, iommu->perfopt_refcount > 0);
|
||||||
|
raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amd_iommu_enable_perfopt(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev);
|
||||||
|
struct amd_iommu *iommu = rlookup_amd_iommu(&pdev->dev);
|
||||||
|
struct protection_domain *domain;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!iommu || !dev_data)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (!(iommu->features & FEATURE_PERF_OPT))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
domain = dev_data->domain;
|
||||||
|
if (!domain)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Already armed for this device (e.g. re-entry on resume). */
|
||||||
|
if (dev_data->perfopt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The bit is only architecturally valid while the device is untranslated:
|
||||||
|
* identity domain with ATS/PRI/PASID off. The identity domain is
|
||||||
|
* SVA-capable so attach_device() enabled ATS/PRI/PASID and built a GCR3
|
||||||
|
* table. Re-home the device onto the same identity domain with
|
||||||
|
* perfopt set, so the attach_device() skip_caps path leaves
|
||||||
|
* ATS/PRI/PASID off and no GCR3 table. This follows the detach/attach
|
||||||
|
* pattern used by amd_iommu_attach_device().
|
||||||
|
*
|
||||||
|
* Locking: this and amd_iommu_disable_perfopt() run only from the
|
||||||
|
* consumer driver's bind/unbind path. group->mutex is not exposed to
|
||||||
|
* drivers, but a device bound to its native driver cannot have its domain
|
||||||
|
* changed concurrently by the core (VFIO ownership is mutually exclusive;
|
||||||
|
* sysfs domain changes require an unused group), so the detach/attach pair
|
||||||
|
* is serialized without it.
|
||||||
|
*/
|
||||||
|
dev_data->perfopt = true;
|
||||||
|
detach_device(&pdev->dev);
|
||||||
|
ret = attach_device(&pdev->dev, domain);
|
||||||
|
if (ret)
|
||||||
|
goto err_restore;
|
||||||
|
|
||||||
|
ret = perfopt_get(iommu);
|
||||||
|
if (ret)
|
||||||
|
goto err_rearm;
|
||||||
|
|
||||||
|
dev_info_once(&pdev->dev, "PerfOpt armed on IOMMU%d\n", iommu->index);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_rearm:
|
||||||
|
detach_device(&pdev->dev);
|
||||||
|
err_restore:
|
||||||
|
dev_data->perfopt = false;
|
||||||
|
if (attach_device(&pdev->dev, domain))
|
||||||
|
pci_err(pdev, "failed to restore state after PerfOpt setup; device left detached\n");
|
||||||
|
dev_err_once(&pdev->dev, "PerfOpt failed to arm on IOMMU%d (%d)\n",
|
||||||
|
iommu->index, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_iommu_enable_perfopt);
|
||||||
|
|
||||||
|
void amd_iommu_disable_perfopt(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev);
|
||||||
|
struct amd_iommu *iommu = rlookup_amd_iommu(&pdev->dev);
|
||||||
|
struct protection_domain *domain;
|
||||||
|
|
||||||
|
if (!iommu || !dev_data || !dev_data->perfopt || !dev_data->domain)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (WARN_ON(perfopt_put(iommu)))
|
||||||
|
pci_err(pdev, "failed to clear PerfOpt\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore ATS/PRI/PASID (and thus SVA) by re-homing the device onto its
|
||||||
|
* identity domain with the flag cleared, so a later bind without PerfOpt
|
||||||
|
* sees a normally-capable device. See the locking note in
|
||||||
|
* amd_iommu_enable_perfopt().
|
||||||
|
*/
|
||||||
|
domain = dev_data->domain;
|
||||||
|
dev_data->perfopt = false;
|
||||||
|
detach_device(&pdev->dev);
|
||||||
|
if (attach_device(&pdev->dev, domain))
|
||||||
|
pci_err(pdev, "failed to restore caps after PerfOpt disable\n");
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_iommu_disable_perfopt);
|
||||||
static struct iommu_device *amd_iommu_probe_device(struct device *dev)
|
static struct iommu_device *amd_iommu_probe_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct iommu_device *iommu_dev;
|
struct iommu_device *iommu_dev;
|
||||||
|
|
@ -2555,6 +2736,26 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev)
|
||||||
return iommu_dev;
|
return iommu_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void amd_iommu_release_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
|
||||||
|
struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data);
|
||||||
|
|
||||||
|
if (dev_data->perfopt) {
|
||||||
|
if (WARN_ON(perfopt_put(iommu)))
|
||||||
|
dev_err(dev, "IOMMU%d: failed to clear PerfOpt on release\n",
|
||||||
|
iommu->index);
|
||||||
|
dev_data->perfopt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_ON(dev_data->domain);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We keep dev_data around for unplugged devices and reuse it when the
|
||||||
|
* device is re-plugged - not doing so would introduce a ton of races.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
static struct iommu_group *amd_iommu_device_group(struct device *dev)
|
static struct iommu_group *amd_iommu_device_group(struct device *dev)
|
||||||
{
|
{
|
||||||
if (dev_is_pci(dev))
|
if (dev_is_pci(dev))
|
||||||
|
|
@ -2915,32 +3116,24 @@ void amd_iommu_domain_free(struct iommu_domain *dom)
|
||||||
kfree(domain);
|
kfree(domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Each IOMMU has at most one PerfOpt-eligible GPU. */
|
|
||||||
static int set_device_perfopt(struct iommu_dev_data *dev_data, bool enable)
|
|
||||||
{
|
|
||||||
struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data);
|
|
||||||
|
|
||||||
if (!dev_data->perfopt)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
guard(raw_spinlock_irqsave)(&iommu->lock);
|
|
||||||
if (iommu->perfopt_enabled == enable)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return amd_iommu_perfopt_set(iommu, enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int blocked_domain_attach_device(struct iommu_domain *domain,
|
static int blocked_domain_attach_device(struct iommu_domain *domain,
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
struct iommu_domain *old)
|
struct iommu_domain *old)
|
||||||
{
|
{
|
||||||
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
|
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
|
||||||
int ret;
|
struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data);
|
||||||
|
|
||||||
/* Clearing the DTE cannot block DMA while PerfOpt bypasses it. */
|
/*
|
||||||
ret = set_device_perfopt(dev_data, false);
|
* blocked_domain is also the .release_domain, so this is the normal
|
||||||
if (ret)
|
* teardown path: drop the reference and clear the flag here too, and
|
||||||
return ret;
|
* don't fail teardown if the WARN-guarded write doesn't stick.
|
||||||
|
*/
|
||||||
|
if (dev_data->perfopt) {
|
||||||
|
if (WARN_ON(perfopt_put(iommu)))
|
||||||
|
dev_err(dev, "IOMMU%d: failed to clear PerfOpt for blocked domain\n",
|
||||||
|
iommu->index);
|
||||||
|
dev_data->perfopt = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (dev_data->domain)
|
if (dev_data->domain)
|
||||||
detach_device(dev);
|
detach_device(dev);
|
||||||
|
|
@ -2974,9 +3167,6 @@ static struct protection_domain identity_domain;
|
||||||
static int amd_iommu_identity_attach(struct iommu_domain *dom, struct device *dev,
|
static int amd_iommu_identity_attach(struct iommu_domain *dom, struct device *dev,
|
||||||
struct iommu_domain *old)
|
struct iommu_domain *old)
|
||||||
{
|
{
|
||||||
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't allow attaching a device to the identity domain if SNP is
|
* Don't allow attaching a device to the identity domain if SNP is
|
||||||
* enabled and SNP Mode0 support is not present.
|
* enabled and SNP Mode0 support is not present.
|
||||||
|
|
@ -2984,13 +3174,7 @@ static int amd_iommu_identity_attach(struct iommu_domain *dom, struct device *de
|
||||||
if (amd_iommu_snp_en && !amd_iommu_snp_mode0_sup)
|
if (amd_iommu_snp_en && !amd_iommu_snp_mode0_sup)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = amd_iommu_attach_device(dom, dev, old);
|
return amd_iommu_attach_device(dom, dev, old);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* PerfOpt is optional; the identity attachment is already complete. */
|
|
||||||
set_device_perfopt(dev_data, true);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct iommu_domain_ops identity_domain_ops = {
|
static const struct iommu_domain_ops identity_domain_ops = {
|
||||||
|
|
@ -3018,6 +3202,9 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct device *dev,
|
||||||
struct amd_iommu *iommu = get_amd_iommu_from_dev(dev);
|
struct amd_iommu *iommu = get_amd_iommu_from_dev(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (dev_data->perfopt && !pdom_is_in_pt_mode(domain))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip attach device to domain if new domain is same as
|
* Skip attach device to domain if new domain is same as
|
||||||
* devices current domain
|
* devices current domain
|
||||||
|
|
@ -3034,12 +3221,6 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct device *dev,
|
||||||
if (dom->dirty_ops && !amd_iommu_hd_support(iommu))
|
if (dom->dirty_ops && !amd_iommu_hd_support(iommu))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!pdom_is_in_pt_mode(domain)) {
|
|
||||||
ret = set_device_perfopt(dev_data, false);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev_data->domain)
|
if (dev_data->domain)
|
||||||
detach_device(dev);
|
detach_device(dev);
|
||||||
|
|
||||||
|
|
@ -3191,7 +3372,6 @@ static bool amd_iommu_is_attach_deferred(struct device *dev)
|
||||||
|
|
||||||
static bool quirks_force_identity_mapping(struct pci_dev *pdev)
|
static bool quirks_force_identity_mapping(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct pci_dev *bridge;
|
|
||||||
int class = pdev->class >> 8;
|
int class = pdev->class >> 8;
|
||||||
|
|
||||||
/* AMD GPU vendor ID */
|
/* AMD GPU vendor ID */
|
||||||
|
|
@ -3203,8 +3383,7 @@ static bool quirks_force_identity_mapping(struct pci_dev *pdev)
|
||||||
class != PCI_CLASS_DISPLAY_OTHER)
|
class != PCI_CLASS_DISPLAY_OTHER)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bridge = pci_upstream_bridge(pdev);
|
if (pci_upstream_bridge(pdev)->vendor == PCI_VENDOR_ID_ATI)
|
||||||
if (bridge && bridge->vendor == PCI_VENDOR_ID_ATI)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* It is the GPU in an APU, force identity domain */
|
/* It is the GPU in an APU, force identity domain */
|
||||||
|
|
@ -3236,9 +3415,6 @@ static int amd_iommu_def_domain_type(struct device *dev)
|
||||||
if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))
|
if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev_data->perfopt = get_amd_iommu_from_dev_data(dev_data)->features &
|
|
||||||
FEATURE_PERF_OPT;
|
|
||||||
|
|
||||||
return IOMMU_DOMAIN_IDENTITY;
|
return IOMMU_DOMAIN_IDENTITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3260,6 +3436,7 @@ const struct iommu_ops amd_iommu_ops = {
|
||||||
.domain_alloc_paging_flags = amd_iommu_domain_alloc_paging_flags,
|
.domain_alloc_paging_flags = amd_iommu_domain_alloc_paging_flags,
|
||||||
.domain_alloc_sva = amd_iommu_domain_alloc_sva,
|
.domain_alloc_sva = amd_iommu_domain_alloc_sva,
|
||||||
.probe_device = amd_iommu_probe_device,
|
.probe_device = amd_iommu_probe_device,
|
||||||
|
.release_device = amd_iommu_release_device,
|
||||||
.device_group = amd_iommu_device_group,
|
.device_group = amd_iommu_device_group,
|
||||||
.get_resv_regions = amd_iommu_get_resv_regions,
|
.get_resv_regions = amd_iommu_get_resv_regions,
|
||||||
.is_attach_deferred = amd_iommu_is_attach_deferred,
|
.is_attach_deferred = amd_iommu_is_attach_deferred,
|
||||||
|
|
|
||||||
|
|
@ -1227,12 +1227,12 @@ static int viommu_probe(struct virtio_device *vdev)
|
||||||
/* Populate the event queue with buffers */
|
/* Populate the event queue with buffers */
|
||||||
ret = viommu_fill_evtq(viommu);
|
ret = viommu_fill_evtq(viommu);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_reset_vdev;
|
goto err_free_vqs;
|
||||||
|
|
||||||
ret = iommu_device_sysfs_add(&viommu->iommu, dev, NULL, "%s",
|
ret = iommu_device_sysfs_add(&viommu->iommu, dev, NULL, "%s",
|
||||||
virtio_bus_name(vdev));
|
virtio_bus_name(vdev));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_reset_vdev;
|
goto err_free_vqs;
|
||||||
|
|
||||||
vdev->priv = viommu;
|
vdev->priv = viommu;
|
||||||
|
|
||||||
|
|
@ -1244,8 +1244,6 @@ static int viommu_probe(struct virtio_device *vdev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_reset_vdev:
|
|
||||||
virtio_reset_device(vdev);
|
|
||||||
err_free_vqs:
|
err_free_vqs:
|
||||||
vdev->config->del_vqs(vdev);
|
vdev->config->del_vqs(vdev);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2779,27 +2779,6 @@ static void bond_miimon_link_change(struct bonding *bond,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bond_miimon_slave_down(struct bonding *bond,
|
|
||||||
struct slave *slave)
|
|
||||||
{
|
|
||||||
if (slave->link_failure_count < UINT_MAX)
|
|
||||||
slave->link_failure_count++;
|
|
||||||
|
|
||||||
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
|
|
||||||
BOND_SLAVE_NOTIFY_NOW);
|
|
||||||
|
|
||||||
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
|
|
||||||
BOND_MODE(bond) == BOND_MODE_8023AD)
|
|
||||||
bond_set_slave_inactive_flags(slave,
|
|
||||||
BOND_SLAVE_NOTIFY_NOW);
|
|
||||||
|
|
||||||
slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
|
|
||||||
|
|
||||||
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
|
|
||||||
|
|
||||||
return slave == rcu_access_pointer(bond->curr_active_slave);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bond_miimon_commit(struct bonding *bond)
|
static void bond_miimon_commit(struct bonding *bond)
|
||||||
{
|
{
|
||||||
struct slave *slave, *primary, *active;
|
struct slave *slave, *primary, *active;
|
||||||
|
|
@ -2828,22 +2807,10 @@ static void bond_miimon_commit(struct bonding *bond)
|
||||||
err = bond_update_speed_duplex(slave);
|
err = bond_update_speed_duplex(slave);
|
||||||
netdev_unlock_ops(slave->dev);
|
netdev_unlock_ops(slave->dev);
|
||||||
if (err && bond_needs_speed_duplex(bond)) {
|
if (err && bond_needs_speed_duplex(bond)) {
|
||||||
|
slave->link = BOND_LINK_DOWN;
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
slave_warn(bond->dev, slave->dev,
|
slave_warn(bond->dev, slave->dev,
|
||||||
"failed to get link speed/duplex\n");
|
"failed to get link speed/duplex\n");
|
||||||
/* Coming from FAIL/UP, the slave may still be
|
|
||||||
* in use and may be curr_active_slave, so take
|
|
||||||
* it through the full down path. Coming from
|
|
||||||
* DOWN/BACK, it was never brought up, so just
|
|
||||||
* revert it to DOWN.
|
|
||||||
*/
|
|
||||||
if (slave->link == BOND_LINK_FAIL ||
|
|
||||||
slave->link == BOND_LINK_UP) {
|
|
||||||
if (bond_miimon_slave_down(bond, slave))
|
|
||||||
do_failover = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
slave->link = BOND_LINK_DOWN;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bond_set_slave_link_state(slave, BOND_LINK_UP,
|
bond_set_slave_link_state(slave, BOND_LINK_UP,
|
||||||
|
|
@ -2872,13 +2839,28 @@ static void bond_miimon_commit(struct bonding *bond)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case BOND_LINK_DOWN:
|
case BOND_LINK_DOWN:
|
||||||
if (bond_miimon_slave_down(bond, slave))
|
if (slave->link_failure_count < UINT_MAX)
|
||||||
|
slave->link_failure_count++;
|
||||||
|
|
||||||
|
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
|
||||||
|
BOND_SLAVE_NOTIFY_NOW);
|
||||||
|
|
||||||
|
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
|
||||||
|
BOND_MODE(bond) == BOND_MODE_8023AD)
|
||||||
|
bond_set_slave_inactive_flags(slave,
|
||||||
|
BOND_SLAVE_NOTIFY_NOW);
|
||||||
|
|
||||||
|
slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
|
||||||
|
|
||||||
|
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
|
||||||
|
|
||||||
|
if (slave == rcu_access_pointer(bond->curr_active_slave))
|
||||||
do_failover = true;
|
do_failover = true;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case BOND_LINK_FAIL:
|
case BOND_LINK_FAIL:
|
||||||
case BOND_LINK_BACK:
|
case BOND_LINK_BACK:
|
||||||
bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER);
|
|
||||||
slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
|
slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
|
||||||
slave->link_new_state);
|
slave->link_new_state);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2912,6 +2894,8 @@ static void bond_mii_monitor(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct bonding *bond = container_of(work, struct bonding,
|
struct bonding *bond = container_of(work, struct bonding,
|
||||||
mii_work.work);
|
mii_work.work);
|
||||||
|
struct list_head *iter;
|
||||||
|
struct slave *slave;
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
bool commit;
|
bool commit;
|
||||||
|
|
||||||
|
|
@ -2933,8 +2917,13 @@ static void bond_mii_monitor(struct work_struct *work)
|
||||||
goto re_arm;
|
goto re_arm;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit)
|
if (commit) {
|
||||||
|
bond_for_each_slave(bond, slave, iter) {
|
||||||
|
bond_commit_link_state(slave,
|
||||||
|
BOND_SLAVE_NOTIFY_LATER);
|
||||||
|
}
|
||||||
bond_miimon_commit(bond);
|
bond_miimon_commit(bond);
|
||||||
|
}
|
||||||
|
|
||||||
if (bond->send_peer_notif)
|
if (bond->send_peer_notif)
|
||||||
bond_peer_notify_may_events(bond, true);
|
bond_peer_notify_may_events(bond, true);
|
||||||
|
|
@ -3984,13 +3973,18 @@ static int bond_slave_netdev_event(unsigned long event,
|
||||||
case NETDEV_CHANGE:
|
case NETDEV_CHANGE:
|
||||||
/* For 802.3ad mode only:
|
/* For 802.3ad mode only:
|
||||||
* Getting invalid Speed/Duplex values here will put slave
|
* Getting invalid Speed/Duplex values here will put slave
|
||||||
* in weird state. Mark an up slave as link-fail and let
|
* in weird state. Mark it as link-fail if the link was
|
||||||
* miimon set it right when correct speed/duplex are available.
|
* previously up or link-down if it hasn't yet come up, and
|
||||||
|
* let link-monitoring (miimon) set it right when correct
|
||||||
|
* speeds/duplex are available.
|
||||||
*/
|
*/
|
||||||
if (bond_update_speed_duplex(slave) &&
|
if (bond_update_speed_duplex(slave) &&
|
||||||
BOND_MODE(bond) == BOND_MODE_8023AD &&
|
BOND_MODE(bond) == BOND_MODE_8023AD) {
|
||||||
slave->link == BOND_LINK_UP)
|
if (slave->last_link_up)
|
||||||
slave->link = BOND_LINK_FAIL;
|
slave->link = BOND_LINK_FAIL;
|
||||||
|
else
|
||||||
|
slave->link = BOND_LINK_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
if (BOND_MODE(bond) == BOND_MODE_8023AD)
|
if (BOND_MODE(bond) == BOND_MODE_8023AD)
|
||||||
bond_3ad_adapter_speed_duplex_changed(slave);
|
bond_3ad_adapter_speed_duplex_changed(slave);
|
||||||
|
|
|
||||||
|
|
@ -720,8 +720,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t can_tdc_get_size(const struct net_device *dev,
|
static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
|
||||||
struct data_bittiming_params *dbt_params,
|
|
||||||
u32 tdc_flags)
|
u32 tdc_flags)
|
||||||
{
|
{
|
||||||
bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK;
|
bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK;
|
||||||
|
|
@ -743,8 +742,7 @@ static size_t can_tdc_get_size(const struct net_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdc_flags) {
|
if (tdc_flags) {
|
||||||
if (tdc_manual ||
|
if (tdc_manual || dbt_params->do_get_auto_tdcv)
|
||||||
(dbt_params->do_get_auto_tdcv && netif_running(dev)))
|
|
||||||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */
|
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */
|
||||||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */
|
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */
|
||||||
if (dbt_params->tdc_const->tdcf_max)
|
if (dbt_params->tdc_const->tdcf_max)
|
||||||
|
|
@ -754,8 +752,7 @@ static size_t can_tdc_get_size(const struct net_device *dev,
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t can_data_bittiming_get_size(const struct net_device *dev,
|
static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_params,
|
||||||
struct data_bittiming_params *dbt_params,
|
|
||||||
u32 tdc_flags)
|
u32 tdc_flags)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
@ -767,7 +764,7 @@ static size_t can_data_bittiming_get_size(const struct net_device *dev,
|
||||||
if (dbt_params->data_bitrate_const) /* IFLA_CAN_{,XL}_DATA_BITRATE_CONST */
|
if (dbt_params->data_bitrate_const) /* IFLA_CAN_{,XL}_DATA_BITRATE_CONST */
|
||||||
size += nla_total_size(sizeof(*dbt_params->data_bitrate_const) *
|
size += nla_total_size(sizeof(*dbt_params->data_bitrate_const) *
|
||||||
dbt_params->data_bitrate_const_cnt);
|
dbt_params->data_bitrate_const_cnt);
|
||||||
size += can_tdc_get_size(dev, dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */
|
size += can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
@ -815,7 +812,7 @@ static size_t can_get_size(const struct net_device *dev)
|
||||||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
|
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
|
||||||
size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
|
size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
|
||||||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
|
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
|
||||||
if (priv->do_get_berr_counter && netif_running(dev)) /* IFLA_CAN_BERR_COUNTER */
|
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
|
||||||
size += nla_total_size(sizeof(struct can_berr_counter));
|
size += nla_total_size(sizeof(struct can_berr_counter));
|
||||||
if (priv->termination_const) {
|
if (priv->termination_const) {
|
||||||
size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
|
size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
|
||||||
|
|
@ -828,10 +825,10 @@ static size_t can_get_size(const struct net_device *dev)
|
||||||
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
||||||
size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */
|
size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */
|
||||||
|
|
||||||
size += can_data_bittiming_get_size(dev, &priv->fd,
|
size += can_data_bittiming_get_size(&priv->fd,
|
||||||
priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK);
|
priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK);
|
||||||
|
|
||||||
size += can_data_bittiming_get_size(dev, &priv->xl,
|
size += can_data_bittiming_get_size(&priv->xl,
|
||||||
priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK);
|
priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK);
|
||||||
size += can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */
|
size += can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */
|
||||||
priv->ctrlmode & CAN_CTRLMODE_XL_TMS);
|
priv->ctrlmode & CAN_CTRLMODE_XL_TMS);
|
||||||
|
|
@ -913,7 +910,7 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev,
|
||||||
if (tdc_manual) {
|
if (tdc_manual) {
|
||||||
tdcv = tdc->tdcv;
|
tdcv = tdc->tdcv;
|
||||||
err = 0;
|
err = 0;
|
||||||
} else if (dbt_params->do_get_auto_tdcv && netif_running(dev)) {
|
} else if (dbt_params->do_get_auto_tdcv) {
|
||||||
err = dbt_params->do_get_auto_tdcv(dev, &tdcv);
|
err = dbt_params->do_get_auto_tdcv(dev, &tdcv);
|
||||||
}
|
}
|
||||||
if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
|
if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
|
||||||
|
|
@ -1009,7 +1006,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||||
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
|
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
|
||||||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
|
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
|
||||||
|
|
||||||
(priv->do_get_berr_counter && netif_running(dev) &&
|
(priv->do_get_berr_counter &&
|
||||||
!priv->do_get_berr_counter(dev, &bec) &&
|
!priv->do_get_berr_counter(dev, &bec) &&
|
||||||
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
|
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/can/can-ml.h>
|
|
||||||
#include <linux/can/dev.h>
|
#include <linux/can/dev.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <net/can.h>
|
#include <net/can.h>
|
||||||
|
|
@ -55,7 +54,6 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||||
if (idx >= priv->echo_skb_max) {
|
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",
|
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);
|
__func__, idx, priv->echo_skb_max);
|
||||||
dev_kfree_skb_any(skb);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +62,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||||
(skb->protocol != htons(ETH_P_CAN) &&
|
(skb->protocol != htons(ETH_P_CAN) &&
|
||||||
skb->protocol != htons(ETH_P_CANFD) &&
|
skb->protocol != htons(ETH_P_CANFD) &&
|
||||||
skb->protocol != htons(ETH_P_CANXL))) {
|
skb->protocol != htons(ETH_P_CANXL))) {
|
||||||
dev_kfree_skb_any(skb);
|
kfree_skb(skb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,7 +90,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||||
} else {
|
} else {
|
||||||
/* locking problem with netif_stop_queue() ?? */
|
/* locking problem with netif_stop_queue() ?? */
|
||||||
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
|
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
|
||||||
dev_kfree_skb_any(skb);
|
kfree_skb(skb);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,7 +227,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
||||||
|
|
||||||
csx = can_skb_ext_add(skb);
|
csx = can_skb_ext_add(skb);
|
||||||
if (!csx) {
|
if (!csx) {
|
||||||
dev_kfree_skb_any(skb);
|
kfree_skb(skb);
|
||||||
goto out_error_cc;
|
goto out_error_cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,7 +258,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||||
|
|
||||||
csx = can_skb_ext_add(skb);
|
csx = can_skb_ext_add(skb);
|
||||||
if (!csx) {
|
if (!csx) {
|
||||||
dev_kfree_skb_any(skb);
|
kfree_skb(skb);
|
||||||
goto out_error_fd;
|
goto out_error_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,7 +296,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev,
|
||||||
|
|
||||||
csx = can_skb_ext_add(skb);
|
csx = can_skb_ext_add(skb);
|
||||||
if (!csx) {
|
if (!csx) {
|
||||||
dev_kfree_skb_any(skb);
|
kfree_skb(skb);
|
||||||
goto out_error_xl;
|
goto out_error_xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,7 +388,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ETH_P_CANXL:
|
case ETH_P_CANXL:
|
||||||
if (!can_cap_enabled(dev, CAN_CAP_XL) || !can_is_canxl_skb(skb))
|
if (!can_is_canxl_skb(skb))
|
||||||
goto inval_skb;
|
goto inval_skb;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -404,7 +402,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
inval_skb:
|
inval_skb:
|
||||||
dev_kfree_skb_any(skb);
|
kfree_skb(skb);
|
||||||
dev->stats.tx_dropped++;
|
dev->stats.tx_dropped++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -755,7 +755,7 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
|
||||||
u16 rx_msg_type, rx_msg_size;
|
u16 rx_msg_type, rx_msg_size;
|
||||||
size_t rx_msg_min_size;
|
size_t rx_msg_min_size;
|
||||||
|
|
||||||
if (msg_end - msg_ptr < sizeof(rx_msg->size)) {
|
if (msg_end - msg_ptr < sizeof(*rx_msg)) {
|
||||||
err = -EBADMSG;
|
err = -EBADMSG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -766,11 +766,6 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg_end - msg_ptr < sizeof(*rx_msg)) {
|
|
||||||
err = -EBADMSG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rx_msg_size = le16_to_cpu(rx_msg->size);
|
rx_msg_size = le16_to_cpu(rx_msg->size);
|
||||||
rx_msg_type = le16_to_cpu(rx_msg->type);
|
rx_msg_type = le16_to_cpu(rx_msg->type);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -836,59 +836,6 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(b53_brcm_hdr_setup);
|
EXPORT_SYMBOL(b53_brcm_hdr_setup);
|
||||||
|
|
||||||
int b53_enable_mcast_snooping(struct b53_device *dev)
|
|
||||||
{
|
|
||||||
u16 val16;
|
|
||||||
u32 val;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Older switches use different IGMP controls, not HL_PRTC_CTRL. */
|
|
||||||
if (is5325(dev) || is5365(dev) || dev->chip_id == BCM5389_DEVICE_ID ||
|
|
||||||
is5397_98(dev) || is63xx(dev))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* IGMPv2 and MLDv1 reports use the group's destination MAC. Once
|
|
||||||
* the first listener is offloaded, ordinary multicast forwarding
|
|
||||||
* can keep subsequent reports from reaching the bridge CPU.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* BCM5395 has a narrower register and a single IGMP classifier.
|
|
||||||
* Its ICMPv6 classifier also covers MLD.
|
|
||||||
*/
|
|
||||||
if (dev->chip_id == BCM5395_DEVICE_ID) {
|
|
||||||
ret = b53_read16(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, &val16);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
val16 |= HL_PRTC_IGMP_IP_EN_5395 | HL_PRTC_ICMPV6_EN;
|
|
||||||
/* Zero forwarding modes copy control traffic to the CPU
|
|
||||||
* independently of the ARL lookup, retaining L2 forwarding.
|
|
||||||
*/
|
|
||||||
val16 &= ~(HL_PRTC_IGMP_FWD_MODE_5395 |
|
|
||||||
HL_PRTC_ICMPV6_FWD_MODE);
|
|
||||||
|
|
||||||
return b53_write16(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL,
|
|
||||||
val16);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = b53_read32(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, &val);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
val |= HL_PRTC_IGMP_RPTLVE_EN | HL_PRTC_IGMP_QRY_EN |
|
|
||||||
HL_PRTC_IGMP_UKN_EN | HL_PRTC_MLD_RPTDONE_EN |
|
|
||||||
HL_PRTC_MLD_QRY_EN;
|
|
||||||
/* Zero forwarding modes copy control traffic to the CPU
|
|
||||||
* independently of the ARL lookup, retaining L2 forwarding.
|
|
||||||
*/
|
|
||||||
val &= ~(HL_PRTC_IGMP_RPTLVE_FWD_MODE | HL_PRTC_IGMP_QRY_FWD_MODE |
|
|
||||||
HL_PRTC_IGMP_UKN_FWD_MODE | HL_PRTC_MLD_RPTDONE_FWD_MODE |
|
|
||||||
HL_PRTC_MLD_QRY_FWD_MODE);
|
|
||||||
|
|
||||||
return b53_write32(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, val);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(b53_enable_mcast_snooping);
|
|
||||||
|
|
||||||
static void b53_enable_cpu_port(struct b53_device *dev, int port)
|
static void b53_enable_cpu_port(struct b53_device *dev, int port)
|
||||||
{
|
{
|
||||||
u8 port_ctrl;
|
u8 port_ctrl;
|
||||||
|
|
@ -1387,10 +1334,6 @@ static int b53_setup(struct dsa_switch *ds)
|
||||||
b53_disable_port(ds, port);
|
b53_disable_port(ds, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = b53_enable_mcast_snooping(dev);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return b53_setup_devlink_resources(ds);
|
return b53_setup_devlink_resources(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1720,15 +1663,9 @@ static void b53_phylink_mac_link_up(struct phylink_config *config,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == MLO_AN_FIXED) {
|
if (mode == MLO_AN_FIXED) {
|
||||||
/* Force flow control and 2Gbits/sec on BCM5301x and NSP CPU
|
/* Force flow control on BCM5301x's CPU port */
|
||||||
* ports
|
if (is5301x(dev) && dsa_is_cpu_port(ds, port))
|
||||||
*/
|
tx_pause = rx_pause = true;
|
||||||
if ((is5301x(dev) || dev->chip_id == BCM58XX_DEVICE_ID) &&
|
|
||||||
dsa_is_cpu_port(ds, port)) {
|
|
||||||
tx_pause = true;
|
|
||||||
rx_pause = true;
|
|
||||||
speed = 2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
b53_force_port_config(dev, port, speed, duplex,
|
b53_force_port_config(dev, port, speed, duplex,
|
||||||
tx_pause, rx_pause);
|
tx_pause, rx_pause);
|
||||||
|
|
|
||||||
|
|
@ -504,7 +504,6 @@ static inline struct gpio_desc *b53_switch_get_reset_gpio(struct b53_device *dev
|
||||||
/* Exported functions towards other drivers */
|
/* Exported functions towards other drivers */
|
||||||
void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port);
|
void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port);
|
||||||
int b53_configure_vlan(struct dsa_switch *ds);
|
int b53_configure_vlan(struct dsa_switch *ds);
|
||||||
int b53_enable_mcast_snooping(struct b53_device *dev);
|
|
||||||
void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
|
void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
|
||||||
uint8_t *data);
|
uint8_t *data);
|
||||||
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
|
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
|
||||||
|
|
|
||||||
|
|
@ -274,23 +274,6 @@
|
||||||
/* Revision ID register (8 bit) */
|
/* Revision ID register (8 bit) */
|
||||||
#define B53_REV_ID 0x40
|
#define B53_REV_ID 0x40
|
||||||
|
|
||||||
/* High-level protocol control (16 bit on BCM5395, otherwise 32 bit) */
|
|
||||||
#define B53_HL_PRTC_CTRL 0x50
|
|
||||||
#define HL_PRTC_ICMPV6_EN BIT(4)
|
|
||||||
#define HL_PRTC_ICMPV6_FWD_MODE BIT(5)
|
|
||||||
#define HL_PRTC_IGMP_IP_EN_5395 BIT(6)
|
|
||||||
#define HL_PRTC_IGMP_FWD_MODE_5395 BIT(8)
|
|
||||||
#define HL_PRTC_IGMP_RPTLVE_EN BIT(9)
|
|
||||||
#define HL_PRTC_IGMP_RPTLVE_FWD_MODE BIT(10)
|
|
||||||
#define HL_PRTC_IGMP_QRY_EN BIT(11)
|
|
||||||
#define HL_PRTC_IGMP_QRY_FWD_MODE BIT(12)
|
|
||||||
#define HL_PRTC_IGMP_UKN_EN BIT(13)
|
|
||||||
#define HL_PRTC_IGMP_UKN_FWD_MODE BIT(14)
|
|
||||||
#define HL_PRTC_MLD_RPTDONE_EN BIT(15)
|
|
||||||
#define HL_PRTC_MLD_RPTDONE_FWD_MODE BIT(16)
|
|
||||||
#define HL_PRTC_MLD_QRY_EN BIT(17)
|
|
||||||
#define HL_PRTC_MLD_QRY_FWD_MODE BIT(18)
|
|
||||||
|
|
||||||
/* Broadcom header RX control (16 bit) */
|
/* Broadcom header RX control (16 bit) */
|
||||||
#define B53_BRCM_HDR_RX_DIS 0x60
|
#define B53_BRCM_HDR_RX_DIS 0x60
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1059,7 +1059,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
|
||||||
{
|
{
|
||||||
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
|
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
|
||||||
unsigned int port;
|
unsigned int port;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Enable all valid ports and disable those unused */
|
/* Enable all valid ports and disable those unused */
|
||||||
for (port = 0; port < priv->hw_params.num_ports; port++) {
|
for (port = 0; port < priv->hw_params.num_ports; port++) {
|
||||||
|
|
@ -1075,10 +1074,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
|
||||||
b53_configure_vlan(ds);
|
b53_configure_vlan(ds);
|
||||||
bcm_sf2_enable_acb(ds);
|
bcm_sf2_enable_acb(ds);
|
||||||
|
|
||||||
ret = b53_enable_mcast_snooping(priv->dev);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return b53_setup_devlink_resources(ds);
|
return b53_setup_devlink_resources(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1934,39 +1934,6 @@ static int atl1c_clean_rx(struct napi_struct *napi, int budget)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
|
atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
|
||||||
|
|
||||||
/* A link partner whose l2mtu is larger than ours can hand us a
|
|
||||||
* frame that does not fit the buffer the hardware was given:
|
|
||||||
* the descriptor reports the untruncated length while at most
|
|
||||||
* buffer_info->length bytes were written. skb_put() of such a
|
|
||||||
* length would pull in whatever the tail of the buffer holds
|
|
||||||
* and, past the end of the skb, trips skb_over_panic and takes
|
|
||||||
* the host down. Bound it by what the device actually wrote
|
|
||||||
* rather than by skb_tailroom(): the skb carries 64 bytes of
|
|
||||||
* slack for the DMA erratum, so the two are not the same.
|
|
||||||
*
|
|
||||||
* Frames shorter than an Ethernet header plus its FCS are
|
|
||||||
* rejected by the same test; before this, a length below
|
|
||||||
* ETH_FCS_LEN underflowed in skb_put().
|
|
||||||
*/
|
|
||||||
if (unlikely(length < ETH_HLEN + ETH_FCS_LEN ||
|
|
||||||
length > buffer_info->length)) {
|
|
||||||
dev_core_stats_rx_dropped_inc(netdev);
|
|
||||||
if (netif_msg_rx_err(adapter))
|
|
||||||
dev_warn_ratelimited(&pdev->dev,
|
|
||||||
"dropped rx frame: %u bytes, buffer %u\n",
|
|
||||||
length, buffer_info->length);
|
|
||||||
kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG);
|
|
||||||
/* atl1c_clean_rfd() has already recycled the RFD, so
|
|
||||||
* count the drop as work: the refill at the end of the
|
|
||||||
* poll only runs when work_done is non-zero, and
|
|
||||||
* sustained oversized traffic would otherwise drain the
|
|
||||||
* ring and stop RX for good.
|
|
||||||
*/
|
|
||||||
work_done++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_put(skb, length - ETH_FCS_LEN);
|
skb_put(skb, length - ETH_FCS_LEN);
|
||||||
skb->protocol = eth_type_trans(skb, netdev);
|
skb->protocol = eth_type_trans(skb, netdev);
|
||||||
atl1c_rx_checksum(adapter, skb, rrs);
|
atl1c_rx_checksum(adapter, skb, rrs);
|
||||||
|
|
|
||||||
|
|
@ -243,8 +243,7 @@ static int bgmac_probe(struct platform_device *pdev)
|
||||||
bgmac->phy_connect = platform_phy_connect;
|
bgmac->phy_connect = platform_phy_connect;
|
||||||
} else {
|
} else {
|
||||||
bgmac->phy_connect = bgmac_phy_connect_direct;
|
bgmac->phy_connect = bgmac_phy_connect_direct;
|
||||||
if (of_machine_is_compatible("brcm,nsp"))
|
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
||||||
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bgmac_enet_probe(bgmac);
|
return bgmac_enet_probe(bgmac);
|
||||||
|
|
|
||||||
|
|
@ -1430,15 +1430,11 @@ void bgmac_adjust_link(struct net_device *net_dev)
|
||||||
{
|
{
|
||||||
struct bgmac *bgmac = netdev_priv(net_dev);
|
struct bgmac *bgmac = netdev_priv(net_dev);
|
||||||
struct phy_device *phy_dev = net_dev->phydev;
|
struct phy_device *phy_dev = net_dev->phydev;
|
||||||
int speed = phy_dev->speed;
|
|
||||||
bool update = false;
|
bool update = false;
|
||||||
|
|
||||||
if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500)
|
|
||||||
speed = SPEED_2500;
|
|
||||||
|
|
||||||
if (phy_dev->link) {
|
if (phy_dev->link) {
|
||||||
if (speed != bgmac->mac_speed) {
|
if (phy_dev->speed != bgmac->mac_speed) {
|
||||||
bgmac->mac_speed = speed;
|
bgmac->mac_speed = phy_dev->speed;
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11544,7 +11544,6 @@ static int bnxt_change_msix(struct bnxt *bp, int total)
|
||||||
map.index = i - 1;
|
map.index = i - 1;
|
||||||
map.virq = bp->irq_tbl[i - 1].vector;
|
map.virq = bp->irq_tbl[i - 1].vector;
|
||||||
pci_msix_free_irq(bp->pdev, map);
|
pci_msix_free_irq(bp->pdev, map);
|
||||||
bp->irq_tbl[i - 1].vector = 0;
|
|
||||||
bp->total_irqs--;
|
bp->total_irqs--;
|
||||||
}
|
}
|
||||||
return bp->total_irqs;
|
return bp->total_irqs;
|
||||||
|
|
@ -11722,23 +11721,8 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
|
||||||
int irqs_required;
|
int irqs_required;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!bnxt_need_reserve_rings(bp)) {
|
if (!bnxt_need_reserve_rings(bp))
|
||||||
/* FW may already hold the reservation from an earlier
|
|
||||||
* reservation that was not followed by growing the dynamic
|
|
||||||
* MSI-X vectors, e.g. because the allocation failed.
|
|
||||||
*/
|
|
||||||
if (irq_re_init && BNXT_NEW_RM(bp) && bp->irq_tbl &&
|
|
||||||
pci_msix_can_alloc_dyn(bp->pdev)) {
|
|
||||||
irqs_required = bnxt_get_num_msix(bp);
|
|
||||||
if (irqs_required > bp->total_irqs &&
|
|
||||||
bnxt_change_msix(bp, irqs_required) != irqs_required) {
|
|
||||||
netdev_err(bp->dev, "Unable to allocate %d MSIX vectors, maximum available %d\n",
|
|
||||||
irqs_required, bp->total_irqs);
|
|
||||||
return -ENOSPC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
|
if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
|
||||||
int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
|
int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
|
||||||
|
|
@ -11764,10 +11748,6 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
|
||||||
rc = bnxt_init_int_mode(bp);
|
rc = bnxt_init_int_mode(bp);
|
||||||
bnxt_ulp_irq_restart(bp, rc);
|
bnxt_ulp_irq_restart(bp, rc);
|
||||||
} else if (irq_change && !rc) {
|
} else if (irq_change && !rc) {
|
||||||
/* Size the vectors from what FW actually reserved, which
|
|
||||||
* can be less than what was requested.
|
|
||||||
*/
|
|
||||||
irqs_required = bnxt_get_num_msix(bp);
|
|
||||||
if (bnxt_change_msix(bp, irqs_required) != irqs_required)
|
if (bnxt_change_msix(bp, irqs_required) != irqs_required)
|
||||||
rc = -ENOSPC;
|
rc = -ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
@ -15133,7 +15113,6 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
|
||||||
hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp));
|
hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp));
|
||||||
}
|
}
|
||||||
if (hwr.cp > bp->total_irqs) {
|
if (hwr.cp > bp->total_irqs) {
|
||||||
int old_total = bp->total_irqs;
|
|
||||||
int total_msix = bnxt_change_msix(bp, hwr.cp);
|
int total_msix = bnxt_change_msix(bp, hwr.cp);
|
||||||
|
|
||||||
if (total_msix < hwr.cp) {
|
if (total_msix < hwr.cp) {
|
||||||
|
|
@ -15141,17 +15120,6 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
|
||||||
hwr.cp, total_msix);
|
hwr.cp, total_msix);
|
||||||
rc = -ENOSPC;
|
rc = -ENOSPC;
|
||||||
}
|
}
|
||||||
/* FW has not reserved the new vectors yet, and writes to
|
|
||||||
* MSI-X table entries beyond the reserved IRQs don't
|
|
||||||
* stick (seen on BCM57508). Free them again;
|
|
||||||
* bnxt_reserve_rings() allocates them after
|
|
||||||
* __bnxt_reserve_rings(). Without the new resource
|
|
||||||
* manager there is no IRQ reservation and
|
|
||||||
* bnxt_reserve_rings() does not grow the vectors, so
|
|
||||||
* keep them.
|
|
||||||
*/
|
|
||||||
if (BNXT_NEW_RM(bp))
|
|
||||||
bnxt_change_msix(bp, old_total);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
||||||
|
|
@ -1502,8 +1502,7 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
|
||||||
* all other events are ignored
|
* all other events are ignored
|
||||||
*/
|
*/
|
||||||
jwrite32(jme, JME_IEVE, intrstat);
|
jwrite32(jme, JME_IEVE, intrstat);
|
||||||
if (!test_bit(JME_FLAG_WOL_QUIESCE, &jme->flags))
|
schedule_work(&jme->linkch_task);
|
||||||
schedule_work(&jme->linkch_task);
|
|
||||||
goto out_reenable;
|
goto out_reenable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1547,8 +1546,7 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
|
||||||
/*
|
/*
|
||||||
* Re-enable interrupt
|
* Re-enable interrupt
|
||||||
*/
|
*/
|
||||||
if (!test_bit(JME_FLAG_WOL_QUIESCE, &jme->flags))
|
jwrite32f(jme, JME_IENS, INTR_ENABLE);
|
||||||
jwrite32f(jme, JME_IENS, INTR_ENABLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t
|
static irqreturn_t
|
||||||
|
|
@ -1894,7 +1892,6 @@ jme_powersave_phy(struct jme_adapter *jme)
|
||||||
jme_set_100m_half(jme);
|
jme_set_100m_half(jme);
|
||||||
if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
|
if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
|
||||||
jme_wait_link(jme);
|
jme_wait_link(jme);
|
||||||
jme_mac_rxclk_on(jme);
|
|
||||||
jme_clear_pm_enable_wol(jme);
|
jme_clear_pm_enable_wol(jme);
|
||||||
} else {
|
} else {
|
||||||
jme_phy_off(jme);
|
jme_phy_off(jme);
|
||||||
|
|
@ -3161,21 +3158,6 @@ jme_shutdown(struct pci_dev *pdev)
|
||||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||||
struct jme_adapter *jme = netdev_priv(netdev);
|
struct jme_adapter *jme = netdev_priv(netdev);
|
||||||
|
|
||||||
if (netif_running(netdev)) {
|
|
||||||
set_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
|
|
||||||
netif_device_detach(netdev);
|
|
||||||
netif_stop_queue(netdev);
|
|
||||||
jme_stop_irq(jme);
|
|
||||||
synchronize_irq(pdev->irq);
|
|
||||||
jme_stop_irq(jme);
|
|
||||||
cancel_work_sync(&jme->linkch_task);
|
|
||||||
tasklet_disable(&jme->pcc_task);
|
|
||||||
napi_disable(&jme->napi);
|
|
||||||
tasklet_disable(&jme->txclean_task);
|
|
||||||
tasklet_disable(&jme->rxclean_task);
|
|
||||||
tasklet_disable(&jme->rxempty_task);
|
|
||||||
}
|
|
||||||
|
|
||||||
jme_powersave_phy(jme);
|
jme_powersave_phy(jme);
|
||||||
pci_pme_active(pdev, true);
|
pci_pme_active(pdev, true);
|
||||||
}
|
}
|
||||||
|
|
@ -3190,16 +3172,11 @@ jme_suspend(struct device *dev)
|
||||||
if (!netif_running(netdev))
|
if (!netif_running(netdev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
set_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
|
atomic_dec(&jme->link_changing);
|
||||||
|
|
||||||
netif_device_detach(netdev);
|
netif_device_detach(netdev);
|
||||||
netif_stop_queue(netdev);
|
netif_stop_queue(netdev);
|
||||||
jme_stop_irq(jme);
|
jme_stop_irq(jme);
|
||||||
synchronize_irq(jme->pdev->irq);
|
|
||||||
jme_stop_irq(jme);
|
|
||||||
cancel_work_sync(&jme->linkch_task);
|
|
||||||
tasklet_disable(&jme->pcc_task);
|
|
||||||
napi_disable(&jme->napi);
|
|
||||||
atomic_dec(&jme->link_changing);
|
|
||||||
|
|
||||||
tasklet_disable(&jme->txclean_task);
|
tasklet_disable(&jme->txclean_task);
|
||||||
tasklet_disable(&jme->rxclean_task);
|
tasklet_disable(&jme->rxclean_task);
|
||||||
|
|
@ -3238,7 +3215,6 @@ jme_resume(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
jme_clear_pm_disable_wol(jme);
|
jme_clear_pm_disable_wol(jme);
|
||||||
jme_mac_rxclk_off(jme);
|
|
||||||
jme_phy_on(jme);
|
jme_phy_on(jme);
|
||||||
if (test_bit(JME_FLAG_SSET, &jme->flags))
|
if (test_bit(JME_FLAG_SSET, &jme->flags))
|
||||||
jme_set_link_ksettings(netdev, &jme->old_cmd);
|
jme_set_link_ksettings(netdev, &jme->old_cmd);
|
||||||
|
|
@ -3250,11 +3226,8 @@ jme_resume(struct device *dev)
|
||||||
|
|
||||||
atomic_inc(&jme->link_changing);
|
atomic_inc(&jme->link_changing);
|
||||||
|
|
||||||
napi_enable(&jme->napi);
|
|
||||||
tasklet_enable(&jme->pcc_task);
|
|
||||||
clear_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
|
|
||||||
|
|
||||||
jme_reset_link(jme);
|
jme_reset_link(jme);
|
||||||
|
|
||||||
jme_start_irq(jme);
|
jme_start_irq(jme);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -450,7 +450,6 @@ enum jme_flags_bits {
|
||||||
JME_FLAG_SSET = 2,
|
JME_FLAG_SSET = 2,
|
||||||
JME_FLAG_POLL = 5,
|
JME_FLAG_POLL = 5,
|
||||||
JME_FLAG_SHUTDOWN = 6,
|
JME_FLAG_SHUTDOWN = 6,
|
||||||
JME_FLAG_WOL_QUIESCE = 7,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TX_TIMEOUT (5 * HZ)
|
#define TX_TIMEOUT (5 * HZ)
|
||||||
|
|
|
||||||
|
|
@ -754,7 +754,8 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||||
|
|
||||||
hlist_for_each_entry_safe(entry, n, head, list) {
|
hlist_for_each_entry_safe(entry, n, head, list) {
|
||||||
if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
|
if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
|
||||||
if (entry->hash != hash)
|
if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) ==
|
||||||
|
MTK_FOE_STATE_BIND))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
entry->hash = 0xffff;
|
entry->hash = 0xffff;
|
||||||
|
|
@ -763,7 +764,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) {
|
if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) {
|
||||||
if (entry->hash == hash)
|
if (entry->hash != 0xffff)
|
||||||
entry->hash = 0xffff;
|
entry->hash = 0xffff;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
|
||||||
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
|
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
|
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
|
||||||
if (!dev->rx_wdma[i].desc)
|
if (dev->rx_wdma[i].desc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
wdma_w32(dev,
|
wdma_w32(dev,
|
||||||
|
|
@ -949,14 +949,6 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
|
||||||
static void
|
static void
|
||||||
mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
|
mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++)
|
|
||||||
mtk_wed_free_ring(dev, &dev->rx_ring[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
|
|
||||||
mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
|
|
||||||
|
|
||||||
mtk_wed_free_rx_buffer(dev);
|
mtk_wed_free_rx_buffer(dev);
|
||||||
mtk_wed_free_ring(dev, &dev->rro.ring);
|
mtk_wed_free_ring(dev, &dev->rro.ring);
|
||||||
}
|
}
|
||||||
|
|
@ -1946,7 +1938,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
|
||||||
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
|
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
|
||||||
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
|
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
|
||||||
|
|
||||||
if (!mtk_wed_is_v3_or_greater(dev->hw) && reset)
|
if (reset)
|
||||||
mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
|
mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
|
||||||
|
|
||||||
if (!idx) {
|
if (!idx) {
|
||||||
|
|
@ -2345,20 +2337,7 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
|
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
|
||||||
if (!dev->rx_wdma[i].desc)
|
if (!dev->rx_wdma[i].desc)
|
||||||
if (mtk_wed_wdma_rx_ring_setup(dev, i, 16, false)) {
|
mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
|
||||||
dev_err(dev->hw->dev, "wdma rx ring %d setup failed\n", i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* non-DBDC MT7986 allocates only rx_ring[1] and tx_wdma[1] during setup
|
|
||||||
* but tx_wdma[0] is also needed for WED to function.
|
|
||||||
*/
|
|
||||||
if (mtk_wed_is_v2(dev->hw) && !dev->rx_ring[0].desc)
|
|
||||||
if (mtk_wed_wdma_tx_ring_setup(dev, 0, MTK_WED_WDMA_RING_SIZE, !!dev->tx_wdma[0].desc)) {
|
|
||||||
dev_err(dev->hw->dev, "wdma tx ring 0 setup failed\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->wlan.hw_rro) {
|
if (dev->wlan.hw_rro) {
|
||||||
for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
|
for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user