Compare commits

..

No commits in common. "master" and "v7.4-rc1" have entirely different histories.

497 changed files with 5235 additions and 11701 deletions

View File

@ -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>

View File

@ -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
---------------------- ----------------------

View File

@ -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

View File

@ -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

View File

@ -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
------------- -------------

View File

@ -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::

View File

@ -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::

View File

@ -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.

View File

@ -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
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -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

View File

@ -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)

View File

@ -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
/* /*

View File

@ -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 */

View File

@ -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;

View File

@ -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);
/* /*

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;
/* /*

View File

@ -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

View File

@ -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);

View File

@ -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];
/* /*

View File

@ -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;
} }
} }

View File

@ -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);

View File

@ -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;

View File

@ -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. */

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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);
} }

View File

@ -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,

View File

@ -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:

View File

@ -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;

View File

@ -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) {

View File

@ -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;
} }

View File

@ -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:

View File

@ -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 */

View File

@ -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;
}; };

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);
} }

View File

@ -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)

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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)) {

View File

@ -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),

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }
} }

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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"))

View File

@ -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;

View File

@ -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;

View File

@ -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,
}; };

View File

@ -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,

View File

@ -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);

View File

@ -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);
} }
} }

View File

@ -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 +

View File

@ -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, &regval); err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, &regval);
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;
} }

View File

@ -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);

View File

@ -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 */
}; };

View File

@ -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
} }

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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)) ||

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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;
} }

View File

@ -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