* Extend SPI NAND continuous read to Winbond devices, which requires numerous changes in the spi-{mem,nand} layers such as the need for a secondary read operation template. * Continuous reads in general have also been enhanced/fixed for avoiding potential issues at probe time and at block boundaries. Plus, there is the usual load of misc fixes and improvements.
Unified · Split
| @@ -19,6 +19,7 @@ Abhinav Kumar <quic_abhinavk@quicinc.com> <abhinavk@codeaurora.org> · 18 unmodified lines | ||
| 19 | 19 | Ahmad Masri <quic_amasri@quicinc.com> <amasri@codeaurora.org> |
| 20 | 20 | Adam Oldham <oldhamca@gmail.com> |
| 21 | 21 | Adam Radford <aradford@gmail.com> |
| 22 | +Aditya Garg <gargaditya08@proton.me> <gargaditya08@live.com> | |
| 22 | 23 | Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com> |
| 23 | 24 | Adrian Bunk <bunk@stusta.de> |
| 24 | 25 | Ajay Kaher <ajay.kaher@broadcom.com> <akaher@vmware.com> |
| @@ -207,6 +208,7 @@ Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com> · 182 unmodified lines | ||
| 207 | 208 | Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com> |
| 208 | 209 | Corey Minyard <minyard@acm.org> |
| 209 | 210 | Damian Hobson-Garcia <dhobsong@igel.co.jp> |
| 211 | +Dan Carpenter <error27@gmail.com> <dan.carpenter@linaro.org> | |
| 210 | 212 | Dan Carpenter <error27@gmail.com> <dan.carpenter@oracle.com> |
| 211 | 213 | Dan Williams <djbw@kernel.org> <dan.j.williams@intel.com> |
| 212 | 214 | Daniel Borkmann <daniel@iogearbox.net> <danborkmann@googlemail.com> |
| @@ -495,6 +497,7 @@ Leon Romanovsky <leon@kernel.org> <leon@leon.nu> · 282 unmodified lines | ||
| 495 | 497 | Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com> |
| 496 | 498 | Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com> |
| 497 | 499 | Leo Yan <leo.yan@linux.dev> <leo.yan@linaro.org> |
| 500 | +Liam R. Howlett <liam@infradead.org> <Liam.Howlett@oracle.com> | |
| 498 | 501 | Liam Mark <quic_lmark@quicinc.com> <lmark@codeaurora.org> |
| 499 | 502 | Linas Vepstas <linas@austin.ibm.com> |
| 500 | 503 | Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch> |
| @@ -505,6 +508,8 @@ Linus Walleij <linusw@kernel.org> <linus.walleij@stericsson.com> · 4 unmodified lines | ||
| 505 | 508 | Linus Walleij <linusw@kernel.org> <linus.walleij@linaro.org> |
| 506 | 509 | Linus Walleij <linusw@kernel.org> <triad@df.lth.se> |
| 507 | 510 | <linux-hardening@vger.kernel.org> <kernel-hardening@lists.openwall.com> |
| 511 | +Li Wang <li.wang@linux.dev> <liwang@redhat.com> | |
| 512 | +Li Wang <li.wang@linux.dev> <wangli.ahau@gmail.com> | |
| 508 | 513 | Li Yang <leoyang.li@nxp.com> <leoli@freescale.com> |
| 509 | 514 | Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org> |
| 510 | 515 | Lior David <quic_liord@quicinc.com> <liord@codeaurora.org> |
| @@ -687,6 +692,7 @@ Punit Agrawal <punitagrawal@gmail.com> <punit.agrawal@arm.com> · 176 unmodified lines | ||
| 687 | 692 | Puranjay Mohan <puranjay@kernel.org> <puranjay12@gmail.com> |
| 688 | 693 | Qais Yousef <qyousef@layalina.io> <qais.yousef@imgtec.com> |
| 689 | 694 | Qais Yousef <qyousef@layalina.io> <qais.yousef@arm.com> |
| 695 | +Qi Zheng <qi.zheng@linux.dev> <zhengqi.arch@bytedance.com> | |
| 690 | 696 | Quentin Monnet <qmo@kernel.org> <quentin.monnet@netronome.com> |
| 691 | 697 | Quentin Monnet <qmo@kernel.org> <quentin@isovalent.com> |
| 692 | 698 | Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com> |
| @@ -220,7 +220,7 @@ cgroup v2 currently supports the following mount options. · 219 unmodified lines | ||
| 220 | 220 | memory_hugetlb_accounting |
| 221 | 221 | Count HugeTLB memory usage towards the cgroup's overall |
| 222 | 222 | memory usage for the memory controller (for the purpose of |
| 223 | − statistics reporting and memory protetion). This is a new | |
| 223 | + statistics reporting and memory protection). This is a new | |
| 224 | 224 | behavior that could regress existing setups, so it must be |
| 225 | 225 | explicitly opted in with this mount option. |
| 226 | 226 | |
| @@ -24,6 +24,7 @@ properties: · 23 unmodified lines | ||
| 24 | 24 | compatible: |
| 25 | 25 | items: |
| 26 | 26 | - enum: |
| 27 | + - qcom,eliza-ipcc | |
| 27 | 28 | - qcom,glymur-ipcc |
| 28 | 29 | - qcom,kaanapali-ipcc |
| 29 | 30 | - qcom,milos-ipcc |
| @@ -23,6 +23,15 @@ properties: · 22 unmodified lines | ||
| 23 | 23 | description: |
| 24 | 24 | Contains the chip-select IDs. |
| 25 | 25 | |
| 26 | + nand-randomizer: | |
| 27 | + description: | | |
| 28 | + Control the data randomizer feature. | |
| 29 | + 0: Disable randomizer. | |
| 30 | + 1: Enable randomizer. | |
| 31 | + If absent, the current hardware state is left unchanged. | |
| 32 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 33 | + enum: [0, 1] | |
| 34 | + | |
| 26 | 35 | required: |
| 27 | 36 | - reg |
| 28 | 37 | |
| @@ -57,7 +57,7 @@ Mount options unique to the isofs filesystem. · 56 unmodified lines | ||
| 57 | 57 | Recommended documents about ISO 9660 standard are located at: |
| 58 | 58 | |
| 59 | 59 | - http://www.y-adagio.com/ |
| 60 | −- ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf | |
| 60 | +- https://ecma-international.org/wp-content/uploads/ECMA-119_2nd_edition_december_1987.pdf | |
| 61 | 61 | |
| 62 | 62 | Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically |
| 63 | 63 | identical with ISO 9660.", so it is a valid and gratis substitute of the |
| @@ -188,6 +188,7 @@ operations: · 187 unmodified lines | ||
| 188 | 188 | name: dev-set |
| 189 | 189 | doc: Set the configuration of a PSP device. |
| 190 | 190 | attribute-set: dev |
| 191 | + flags: [admin-perm] | |
| 191 | 192 | do: |
| 192 | 193 | request: |
| 193 | 194 | attributes: |
| @@ -207,6 +208,7 @@ operations: · 13 unmodified lines | ||
| 207 | 208 | name: key-rotate |
| 208 | 209 | doc: Rotate the device key. |
| 209 | 210 | attribute-set: dev |
| 211 | + flags: [admin-perm] | |
| 210 | 212 | do: |
| 211 | 213 | request: |
| 212 | 214 | attributes: |
| @@ -7873,7 +7873,7 @@ F: drivers/gpu/drm/sun4i/sun8i* · 7872 unmodified lines | ||
| 7873 | 7873 | |
| 7874 | 7874 | DRM DRIVER FOR APPLE TOUCH BARS |
| 7875 | 7875 | M: Aun-Ali Zaidi <admin@kodeit.net> |
| 7876 | −M: Aditya Garg <gargaditya08@live.com> | |
| 7876 | +M: Aditya Garg <gargaditya08@proton.me> | |
| 7877 | 7877 | L: dri-devel@lists.freedesktop.org |
| 7878 | 7878 | S: Maintained |
| 7879 | 7879 | T: git https://gitlab.freedesktop.org/drm/misc/kernel.git |
| @@ -13860,7 +13860,6 @@ M: Pratyush Yadav <pratyush@kernel.org> · 5980 unmodified lines | ||
| 13860 | 13860 | R: Dave Young <ruirui.yang@linux.dev> |
| 13861 | 13861 | L: kexec@lists.infradead.org |
| 13862 | 13862 | S: Maintained |
| 13863 | −W: http://lse.sourceforge.net/kdump/ | |
| 13864 | 13863 | F: Documentation/admin-guide/kdump/ |
| 13865 | 13864 | F: fs/proc/vmcore.c |
| 13866 | 13865 | F: include/linux/crash_core.h |
| @@ -15252,7 +15251,7 @@ M: Andrea Cervesato <andrea.cervesato@suse.com> · 1385 unmodified lines | ||
| 15252 | 15251 | M: Cyril Hrubis <chrubis@suse.cz> |
| 15253 | 15252 | M: Jan Stancek <jstancek@redhat.com> |
| 15254 | 15253 | M: Petr Vorel <pvorel@suse.cz> |
| 15255 | −M: Li Wang <liwang@redhat.com> | |
| 15254 | +M: Li Wang <li.wang@linux.dev> | |
| 15256 | 15255 | M: Yang Xu <xuyang2018.jy@fujitsu.com> |
| 15257 | 15256 | M: Xiao Yang <yangx.jy@fujitsu.com> |
| 15258 | 15257 | L: ltp@lists.linux.it (subscribers-only) |
| @@ -15399,7 +15398,7 @@ F: include/net/netns/mctp.h · 140 unmodified lines | ||
| 15399 | 15398 | F: net/mctp/ |
| 15400 | 15399 | |
| 15401 | 15400 | MAPLE TREE |
| 15402 | −M: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 15401 | +M: Liam R. Howlett <liam@infradead.org> | |
| 15403 | 15402 | R: Alice Ryhl <aliceryhl@google.com> |
| 15404 | 15403 | R: Andrew Ballance <andrewjballance@gmail.com> |
| 15405 | 15404 | L: maple-tree@lists.infradead.org |
| @@ -16759,7 +16758,7 @@ MEMORY MANAGEMENT - CORE · 1353 unmodified lines | ||
| 16759 | 16758 | M: Andrew Morton <akpm@linux-foundation.org> |
| 16760 | 16759 | M: David Hildenbrand <david@kernel.org> |
| 16761 | 16760 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 16762 | −R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 16761 | +R: Liam R. Howlett <liam@infradead.org> | |
| 16763 | 16762 | R: Vlastimil Babka <vbabka@kernel.org> |
| 16764 | 16763 | R: Mike Rapoport <rppt@kernel.org> |
| 16765 | 16764 | R: Suren Baghdasaryan <surenb@google.com> |
| @@ -16805,7 +16804,7 @@ F: mm/sparse.c · 39 unmodified lines | ||
| 16805 | 16804 | F: mm/util.c |
| 16806 | 16805 | F: mm/vmpressure.c |
| 16807 | 16806 | F: mm/vmstat.c |
| 16808 | −N: include/linux/page[-_]* | |
| 16807 | +N: include\/linux\/page[-_][a-zA-Z]* | |
| 16809 | 16808 | |
| 16810 | 16809 | MEMORY MANAGEMENT - EXECMEM |
| 16811 | 16810 | M: Andrew Morton <akpm@linux-foundation.org> |
| @@ -16895,7 +16894,7 @@ MEMORY MANAGEMENT - MISC · 83 unmodified lines | ||
| 16895 | 16894 | M: Andrew Morton <akpm@linux-foundation.org> |
| 16896 | 16895 | M: David Hildenbrand <david@kernel.org> |
| 16897 | 16896 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 16898 | −R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 16897 | +R: Liam R. Howlett <liam@infradead.org> | |
| 16899 | 16898 | R: Vlastimil Babka <vbabka@kernel.org> |
| 16900 | 16899 | R: Mike Rapoport <rppt@kernel.org> |
| 16901 | 16900 | R: Suren Baghdasaryan <surenb@google.com> |
| @@ -16962,6 +16961,7 @@ S: Maintained · 60 unmodified lines | ||
| 16962 | 16961 | F: include/linux/compaction.h |
| 16963 | 16962 | F: include/linux/gfp.h |
| 16964 | 16963 | F: include/linux/page-isolation.h |
| 16964 | +F: include/linux/pageblock-flags.h | |
| 16965 | 16965 | F: mm/compaction.c |
| 16966 | 16966 | F: mm/debug_page_alloc.c |
| 16967 | 16967 | F: mm/debug_page_ref.c |
| @@ -16983,7 +16983,7 @@ M: Andrew Morton <akpm@linux-foundation.org> · 15 unmodified lines | ||
| 16983 | 16983 | M: Johannes Weiner <hannes@cmpxchg.org> |
| 16984 | 16984 | R: David Hildenbrand <david@kernel.org> |
| 16985 | 16985 | R: Michal Hocko <mhocko@kernel.org> |
| 16986 | −R: Qi Zheng <zhengqi.arch@bytedance.com> | |
| 16986 | +R: Qi Zheng <qi.zheng@linux.dev> | |
| 16987 | 16987 | R: Shakeel Butt <shakeel.butt@linux.dev> |
| 16988 | 16988 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 16989 | 16989 | L: linux-mm@kvack.org |
| @@ -16996,7 +16996,7 @@ M: Andrew Morton <akpm@linux-foundation.org> · 6 unmodified lines | ||
| 16996 | 16996 | M: David Hildenbrand <david@kernel.org> |
| 16997 | 16997 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 16998 | 16998 | R: Rik van Riel <riel@surriel.com> |
| 16999 | −R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 16999 | +R: Liam R. Howlett <liam@infradead.org> | |
| 17000 | 17000 | R: Vlastimil Babka <vbabka@kernel.org> |
| 17001 | 17001 | R: Harry Yoo <harry@kernel.org> |
| 17002 | 17002 | R: Jann Horn <jannh@google.com> |
| @@ -17043,7 +17043,7 @@ M: David Hildenbrand <david@kernel.org> · 40 unmodified lines | ||
| 17043 | 17043 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17044 | 17044 | R: Zi Yan <ziy@nvidia.com> |
| 17045 | 17045 | R: Baolin Wang <baolin.wang@linux.alibaba.com> |
| 17046 | −R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 17046 | +R: Liam R. Howlett <liam@infradead.org> | |
| 17047 | 17047 | R: Nico Pache <npache@redhat.com> |
| 17048 | 17048 | R: Ryan Roberts <ryan.roberts@arm.com> |
| 17049 | 17049 | R: Dev Jain <dev.jain@arm.com> |
| @@ -17081,7 +17081,7 @@ F: tools/testing/selftests/mm/uffd-*.[ch] · 31 unmodified lines | ||
| 17081 | 17081 | MEMORY MANAGEMENT - RUST |
| 17082 | 17082 | M: Alice Ryhl <aliceryhl@google.com> |
| 17083 | 17083 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 17084 | −R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 17084 | +R: Liam R. Howlett <liam@infradead.org> | |
| 17085 | 17085 | L: linux-mm@kvack.org |
| 17086 | 17086 | L: rust-for-linux@vger.kernel.org |
| 17087 | 17087 | S: Maintained |
| @@ -17095,7 +17095,7 @@ F: rust/kernel/page.rs · 7 unmodified lines | ||
| 17095 | 17095 | |
| 17096 | 17096 | MEMORY MAPPING |
| 17097 | 17097 | M: Andrew Morton <akpm@linux-foundation.org> |
| 17098 | −M: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 17098 | +M: Liam R. Howlett <liam@infradead.org> | |
| 17099 | 17099 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17100 | 17100 | R: Vlastimil Babka <vbabka@kernel.org> |
| 17101 | 17101 | R: Jann Horn <jannh@google.com> |
| @@ -17127,7 +17127,7 @@ F: tools/testing/vma/ · 25 unmodified lines | ||
| 17127 | 17127 | MEMORY MAPPING - LOCKING |
| 17128 | 17128 | M: Andrew Morton <akpm@linux-foundation.org> |
| 17129 | 17129 | M: Suren Baghdasaryan <surenb@google.com> |
| 17130 | −M: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 17130 | +M: Liam R. Howlett <liam@infradead.org> | |
| 17131 | 17131 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17132 | 17132 | R: Vlastimil Babka <vbabka@kernel.org> |
| 17133 | 17133 | R: Shakeel Butt <shakeel.butt@linux.dev> |
| @@ -17142,7 +17142,7 @@ F: mm/mmap_lock.c · 8 unmodified lines | ||
| 17142 | 17142 | |
| 17143 | 17143 | MEMORY MAPPING - MADVISE (MEMORY ADVICE) |
| 17144 | 17144 | M: Andrew Morton <akpm@linux-foundation.org> |
| 17145 | −M: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 17145 | +M: Liam R. Howlett <liam@infradead.org> | |
| 17146 | 17146 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17147 | 17147 | M: David Hildenbrand <david@kernel.org> |
| 17148 | 17148 | R: Vlastimil Babka <vbabka@kernel.org> |
| @@ -18672,19 +18672,59 @@ F: net/xfrm/ · 1523 unmodified lines | ||
| 18672 | 18672 | F: tools/testing/selftests/net/ipsec.c |
| 18673 | 18673 | |
| 18674 | 18674 | NETWORKING [IPv4/IPv6] |
| 18675 | −M: "David S. Miller" <davem@davemloft.net> | |
| 18676 | 18675 | M: David Ahern <dsahern@kernel.org> |
| 18676 | +M: Ido Schimmel <idosch@nvidia.com> | |
| 18677 | 18677 | L: netdev@vger.kernel.org |
| 18678 | 18678 | S: Maintained |
| 18679 | −T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git | |
| 18680 | −F: arch/x86/net/* | |
| 18681 | −F: include/linux/ip.h | |
| 18682 | −F: include/linux/ipv6* | |
| 18679 | +F: Documentation/netlink/specs/rt-addr.yaml | |
| 18680 | +F: Documentation/netlink/specs/rt-neigh.yaml | |
| 18681 | +F: Documentation/netlink/specs/rt-route.yaml | |
| 18682 | +F: Documentation/netlink/specs/rt-rule.yaml | |
| 18683 | +F: include/linux/inetdevice.h | |
| 18684 | +F: include/linux/mroute* | |
| 18685 | +F: include/net/addrconf.h | |
| 18686 | +F: include/net/arp.h | |
| 18683 | 18687 | F: include/net/fib* |
| 18688 | +F: include/net/if_inet6.h | |
| 18689 | +F: include/net/inetpeer.h | |
| 18684 | 18690 | F: include/net/ip* |
| 18691 | +F: include/net/lwtunnel.h | |
| 18692 | +F: include/net/ndisc.h | |
| 18693 | +F: include/net/netns/nexthop.h | |
| 18694 | +F: include/net/nexthop.h | |
| 18685 | 18695 | F: include/net/route.h |
| 18686 | −F: net/ipv4/ | |
| 18687 | −F: net/ipv6/ | |
| 18696 | +F: include/uapi/linux/fib_rules.h | |
| 18697 | +F: include/uapi/linux/in_route.h | |
| 18698 | +F: include/uapi/linux/mroute* | |
| 18699 | +F: include/uapi/linux/nexthop.h | |
| 18700 | +F: net/core/fib* | |
| 18701 | +F: net/core/lwtunnel.c | |
| 18702 | +F: net/ipv4/arp.c | |
| 18703 | +F: net/ipv4/devinet.c | |
| 18704 | +F: net/ipv4/fib* | |
| 18705 | +F: net/ipv4/icmp.c | |
| 18706 | +F: net/ipv4/igmp.c | |
| 18707 | +F: net/ipv4/inet_fragment.c | |
| 18708 | +F: net/ipv4/inetpeer.c | |
| 18709 | +F: net/ipv4/ip* | |
| 18710 | +F: net/ipv4/metrics.c | |
| 18711 | +F: net/ipv4/netlink.c | |
| 18712 | +F: net/ipv4/nexthop.c | |
| 18713 | +F: net/ipv4/route.c | |
| 18714 | +F: net/ipv6/addr* | |
| 18715 | +F: net/ipv6/anycast.c | |
| 18716 | +F: net/ipv6/exthdrs.c | |
| 18717 | +F: net/ipv6/exthdrs_core.c | |
| 18718 | +F: net/ipv6/fib* | |
| 18719 | +F: net/ipv6/icmp.c | |
| 18720 | +F: net/ipv6/ip* | |
| 18721 | +F: net/ipv6/mcast* | |
| 18722 | +F: net/ipv6/ndisc.c | |
| 18723 | +F: net/ipv6/output_core.c | |
| 18724 | +F: net/ipv6/reassembly.c | |
| 18725 | +F: net/ipv6/route.c | |
| 18726 | +F: tools/testing/selftests/net/fib* | |
| 18727 | +F: tools/testing/selftests/net/forwarding/ | |
| 18688 | 18728 | |
| 18689 | 18729 | NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK) |
| 18690 | 18730 | M: Paul Moore <paul@paul-moore.com> |
| @@ -18819,18 +18859,11 @@ F: Documentation/networking/net_failover.rst · 128 unmodified lines | ||
| 18819 | 18859 | F: drivers/net/net_failover.c |
| 18820 | 18860 | F: include/net/net_failover.h |
| 18821 | 18861 | |
| 18822 | −NEXTHOP | |
| 18823 | −M: David Ahern <dsahern@kernel.org> | |
| 18824 | −L: netdev@vger.kernel.org | |
| 18825 | −S: Maintained | |
| 18826 | −F: include/net/netns/nexthop.h | |
| 18827 | −F: include/net/nexthop.h | |
| 18828 | −F: include/uapi/linux/nexthop.h | |
| 18829 | −F: net/ipv4/nexthop.c | |
| 18830 | − | |
| 18831 | 18862 | NFC SUBSYSTEM |
| 18832 | −L: netdev@vger.kernel.org | |
| 18833 | −S: Orphan | |
| 18863 | +M: David Heidelberg <david+nfc@ixit.cz> | |
| 18864 | +L: oe-linux-nfc@lists.linux.dev | |
| 18865 | +S: Maintained | |
| 18866 | +T: git https://codeberg.org/linux-nfc/linux.git | |
| 18834 | 18867 | F: Documentation/devicetree/bindings/net/nfc/ |
| 18835 | 18868 | F: drivers/nfc/ |
| 18836 | 18869 | F: include/net/nfc/ |
| @@ -20774,6 +20807,7 @@ M: Dominik Brodowski <linux@dominikbrodowski.net> · 1937 unmodified lines | ||
| 20774 | 20807 | S: Odd Fixes |
| 20775 | 20808 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux.git |
| 20776 | 20809 | F: Documentation/pcmcia/ |
| 20810 | +F: drivers/net/ethernet/8390/pcnet_cs.c | |
| 20777 | 20811 | F: drivers/pcmcia/ |
| 20778 | 20812 | F: include/pcmcia/ |
| 20779 | 20813 | F: tools/pcmcia/ |
| @@ -23369,7 +23403,7 @@ RUST [ALLOC] · 2589 unmodified lines | ||
| 23369 | 23403 | M: Danilo Krummrich <dakr@kernel.org> |
| 23370 | 23404 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 23371 | 23405 | R: Vlastimil Babka <vbabka@kernel.org> |
| 23372 | −R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 23406 | +R: Liam R. Howlett <liam@infradead.org> | |
| 23373 | 23407 | R: Uladzislau Rezki <urezki@gmail.com> |
| 23374 | 23408 | L: rust-for-linux@vger.kernel.org |
| 23375 | 23409 | S: Maintained |
| @@ -23521,7 +23555,7 @@ F: drivers/s390/net/ · 145 unmodified lines | ||
| 23521 | 23555 | |
| 23522 | 23556 | S390 PCI SUBSYSTEM |
| 23523 | 23557 | M: Niklas Schnelle <schnelle@linux.ibm.com> |
| 23524 | −M: Gerald Schaefer <gerald.schaefer@linux.ibm.com> | |
| 23558 | +M: Gerd Bayer <gbayer@linux.ibm.com> | |
| 23525 | 23559 | L: linux-s390@vger.kernel.org |
| 23526 | 23560 | S: Supported |
| 23527 | 23561 | F: Documentation/arch/s390/pci.rst |
| @@ -24314,7 +24348,7 @@ F: include/media/i2c/rj54n1cb0c.h · 786 unmodified lines | ||
| 24314 | 24348 | SHRINKER |
| 24315 | 24349 | M: Andrew Morton <akpm@linux-foundation.org> |
| 24316 | 24350 | M: Dave Chinner <david@fromorbit.com> |
| 24317 | −R: Qi Zheng <zhengqi.arch@bytedance.com> | |
| 24351 | +R: Qi Zheng <qi.zheng@linux.dev> | |
| 24318 | 24352 | R: Roman Gushchin <roman.gushchin@linux.dev> |
| 24319 | 24353 | R: Muchun Song <muchun.song@linux.dev> |
| 24320 | 24354 | L: linux-mm@kvack.org |
| @@ -24764,6 +24798,7 @@ SOFTWARE RAID (Multiple Disks) SUPPORT · 443 unmodified lines | ||
| 24764 | 24798 | M: Song Liu <song@kernel.org> |
| 24765 | 24799 | M: Yu Kuai <yukuai@fnnas.com> |
| 24766 | 24800 | R: Li Nan <linan122@huawei.com> |
| 24801 | +R: Xiao Ni <xiao@kernel.org> | |
| 24767 | 24802 | L: linux-raid@vger.kernel.org |
| 24768 | 24803 | S: Supported |
| 24769 | 24804 | Q: https://patchwork.kernel.org/project/linux-raid/list/ |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | VERSION = 7 |
| 3 | 3 | PATCHLEVEL = 1 |
| 4 | 4 | SUBLEVEL = 0 |
| 5 | −EXTRAVERSION = -rc1 | |
| 5 | +EXTRAVERSION = -rc2 | |
| 6 | 6 | NAME = Baby Opossum Posse |
| 7 | 7 | |
| 8 | 8 | # *DOCUMENTATION* |
| @@ -40,7 +40,7 @@ static __always_inline void __pmr_local_irq_enable(void) · 39 unmodified lines | ||
| 40 | 40 | barrier(); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | −static inline void arch_local_irq_enable(void) | |
| 43 | +static __always_inline void arch_local_irq_enable(void) | |
| 44 | 44 | { |
| 45 | 45 | if (system_uses_irq_prio_masking()) { |
| 46 | 46 | __pmr_local_irq_enable(); |
| @@ -68,7 +68,7 @@ static __always_inline void __pmr_local_irq_disable(void) · 21 unmodified lines | ||
| 68 | 68 | barrier(); |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | −static inline void arch_local_irq_disable(void) | |
| 71 | +static __always_inline void arch_local_irq_disable(void) | |
| 72 | 72 | { |
| 73 | 73 | if (system_uses_irq_prio_masking()) { |
| 74 | 74 | __pmr_local_irq_disable(); |
| @@ -90,7 +90,7 @@ static __always_inline unsigned long __pmr_local_save_flags(void) · 15 unmodified lines | ||
| 90 | 90 | /* |
| 91 | 91 | * Save the current interrupt enable state. |
| 92 | 92 | */ |
| 93 | −static inline unsigned long arch_local_save_flags(void) | |
| 93 | +static __always_inline unsigned long arch_local_save_flags(void) | |
| 94 | 94 | { |
| 95 | 95 | if (system_uses_irq_prio_masking()) { |
| 96 | 96 | return __pmr_local_save_flags(); |
| @@ -109,7 +109,7 @@ static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags) · 12 unmodified lines | ||
| 109 | 109 | return flags != GIC_PRIO_IRQON; |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | −static inline bool arch_irqs_disabled_flags(unsigned long flags) | |
| 112 | +static __always_inline bool arch_irqs_disabled_flags(unsigned long flags) | |
| 113 | 113 | { |
| 114 | 114 | if (system_uses_irq_prio_masking()) { |
| 115 | 115 | return __pmr_irqs_disabled_flags(flags); |
| @@ -128,7 +128,7 @@ static __always_inline bool __pmr_irqs_disabled(void) · 12 unmodified lines | ||
| 128 | 128 | return __pmr_irqs_disabled_flags(__pmr_local_save_flags()); |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | −static inline bool arch_irqs_disabled(void) | |
| 131 | +static __always_inline bool arch_irqs_disabled(void) | |
| 132 | 132 | { |
| 133 | 133 | if (system_uses_irq_prio_masking()) { |
| 134 | 134 | return __pmr_irqs_disabled(); |
| @@ -160,7 +160,7 @@ static __always_inline unsigned long __pmr_local_irq_save(void) · 25 unmodified lines | ||
| 160 | 160 | return flags; |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | −static inline unsigned long arch_local_irq_save(void) | |
| 163 | +static __always_inline unsigned long arch_local_irq_save(void) | |
| 164 | 164 | { |
| 165 | 165 | if (system_uses_irq_prio_masking()) { |
| 166 | 166 | return __pmr_local_irq_save(); |
| @@ -187,7 +187,7 @@ static __always_inline void __pmr_local_irq_restore(unsigned long flags) · 20 unmodified lines | ||
| 187 | 187 | /* |
| 188 | 188 | * restore saved IRQ state |
| 189 | 189 | */ |
| 190 | −static inline void arch_local_irq_restore(unsigned long flags) | |
| 190 | +static __always_inline void arch_local_irq_restore(unsigned long flags) | |
| 191 | 191 | { |
| 192 | 192 | if (system_uses_irq_prio_masking()) { |
| 193 | 193 | __pmr_local_irq_restore(flags); |
| @@ -68,7 +68,12 @@ · 67 unmodified lines | ||
| 68 | 68 | #define KERNEL_SEGMENT_COUNT 5 |
| 69 | 69 | |
| 70 | 70 | #if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN |
| 71 | −#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) | |
| 71 | +/* | |
| 72 | + * KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping | |
| 73 | + * has one additional split, [_text, _stext). Reserve one more page for the | |
| 74 | + * SWAPPER_BLOCK_SIZE-unaligned boundaries. | |
| 75 | + */ | |
| 76 | +#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2) | |
| 72 | 77 | /* |
| 73 | 78 | * The initial ID map consists of the kernel image, mapped as two separate |
| 74 | 79 | * segments, and may appear misaligned wrt the swapper block size. This means |
| @@ -50,6 +50,9 @@ · 49 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | #include <linux/mm.h> |
| 52 | 52 | |
| 53 | +#define MARKER(m) \ | |
| 54 | + m, __after_##m = m - 1 | |
| 55 | + | |
| 53 | 56 | enum __kvm_host_smccc_func { |
| 54 | 57 | /* Hypercalls that are unavailable once pKVM has finalised. */ |
| 55 | 58 | /* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */ |
| @@ -59,8 +62,10 @@ enum __kvm_host_smccc_func { · 3 unmodified lines | ||
| 59 | 62 | __KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs, |
| 60 | 63 | __KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs, |
| 61 | 64 | __KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config, |
| 65 | + | |
| 66 | + MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM), | |
| 67 | + | |
| 62 | 68 | __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize, |
| 63 | − __KVM_HOST_SMCCC_FUNC_MIN_PKVM = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize, | |
| 64 | 69 | |
| 65 | 70 | /* Hypercalls that are always available and common to [nh]VHE/pKVM. */ |
| 66 | 71 | __KVM_HOST_SMCCC_FUNC___kvm_adjust_pc, |
| @@ -72,11 +77,20 @@ enum __kvm_host_smccc_func { · 5 unmodified lines | ||
| 72 | 77 | __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range, |
| 73 | 78 | __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context, |
| 74 | 79 | __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff, |
| 80 | + __KVM_HOST_SMCCC_FUNC___tracing_load, | |
| 81 | + __KVM_HOST_SMCCC_FUNC___tracing_unload, | |
| 82 | + __KVM_HOST_SMCCC_FUNC___tracing_enable, | |
| 83 | + __KVM_HOST_SMCCC_FUNC___tracing_swap_reader, | |
| 84 | + __KVM_HOST_SMCCC_FUNC___tracing_update_clock, | |
| 85 | + __KVM_HOST_SMCCC_FUNC___tracing_reset, | |
| 86 | + __KVM_HOST_SMCCC_FUNC___tracing_enable_event, | |
| 87 | + __KVM_HOST_SMCCC_FUNC___tracing_write_event, | |
| 75 | 88 | __KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs, |
| 76 | 89 | __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs, |
| 77 | 90 | __KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr, |
| 78 | 91 | __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr, |
| 79 | − __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM = __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr, | |
| 92 | + | |
| 93 | + MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY), | |
| 80 | 94 | |
| 81 | 95 | /* Hypercalls that are available only when pKVM has finalised. */ |
| 82 | 96 | __KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp, |
| @@ -100,14 +114,8 @@ enum __kvm_host_smccc_func { · 17 unmodified lines | ||
| 100 | 114 | __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load, |
| 101 | 115 | __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put, |
| 102 | 116 | __KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid, |
| 103 | − __KVM_HOST_SMCCC_FUNC___tracing_load, | |
| 104 | − __KVM_HOST_SMCCC_FUNC___tracing_unload, | |
| 105 | − __KVM_HOST_SMCCC_FUNC___tracing_enable, | |
| 106 | − __KVM_HOST_SMCCC_FUNC___tracing_swap_reader, | |
| 107 | − __KVM_HOST_SMCCC_FUNC___tracing_update_clock, | |
| 108 | − __KVM_HOST_SMCCC_FUNC___tracing_reset, | |
| 109 | − __KVM_HOST_SMCCC_FUNC___tracing_enable_event, | |
| 110 | − __KVM_HOST_SMCCC_FUNC___tracing_write_event, | |
| 117 | + | |
| 118 | + MARKER(__KVM_HOST_SMCCC_FUNC_MAX) | |
| 111 | 119 | }; |
| 112 | 120 | |
| 113 | 121 | #define DECLARE_KVM_VHE_SYM(sym) extern char sym[] |
| @@ -450,9 +450,6 @@ struct kvm_vcpu_fault_info { · 449 unmodified lines | ||
| 450 | 450 | r = __VNCR_START__ + ((VNCR_ ## r) / 8), \ |
| 451 | 451 | __after_##r = __MAX__(__before_##r - 1, r) |
| 452 | 452 | |
| 453 | −#define MARKER(m) \ | |
| 454 | − m, __after_##m = m - 1 | |
| 455 | − | |
| 456 | 453 | enum vcpu_sysreg { |
| 457 | 454 | __INVALID_SYSREG__, /* 0 is reserved as an invalid value */ |
| 458 | 455 | MPIDR_EL1, /* MultiProcessor Affinity Register */ |
| @@ -1548,7 +1545,7 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature) · 1089 unmodified lines | ||
| 1548 | 1545 | #define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f)) |
| 1549 | 1546 | #define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f)) |
| 1550 | 1547 | |
| 1551 | −#define kvm_vcpu_initialized(v) vcpu_get_flag(vcpu, VCPU_INITIALIZED) | |
| 1548 | +#define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED) | |
| 1552 | 1549 | |
| 1553 | 1550 | int kvm_trng_call(struct kvm_vcpu *vcpu); |
| 1554 | 1551 | #ifdef CONFIG_KVM |
| @@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, · 195 unmodified lines | ||
| 196 | 196 | loc += *opcode++ * code_alignment_factor; |
| 197 | 197 | loc += (*opcode++ << 8) * code_alignment_factor; |
| 198 | 198 | loc += (*opcode++ << 16) * code_alignment_factor; |
| 199 | − loc += (*opcode++ << 24) * code_alignment_factor; | |
| 199 | + loc += ((u64)*opcode++ << 24) * code_alignment_factor; | |
| 200 | 200 | size -= 4; |
| 201 | − break; | |
| 201 | + break; | |
| 202 | 202 | |
| 203 | 203 | case DW_CFA_def_cfa: |
| 204 | 204 | case DW_CFA_offset_extended: |
| @@ -67,6 +67,9 @@ struct rt_sigframe_user_layout { · 66 unmodified lines | ||
| 67 | 67 | unsigned long end_offset; |
| 68 | 68 | }; |
| 69 | 69 | |
| 70 | +#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16) | |
| 71 | +#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16) | |
| 72 | + | |
| 70 | 73 | /* |
| 71 | 74 | * Holds any EL0-controlled state that influences unprivileged memory accesses. |
| 72 | 75 | * This includes both accesses done in userspace and uaccess done in the kernel. |
| @@ -74,13 +77,35 @@ struct rt_sigframe_user_layout { · 1 unmodified line | ||
| 74 | 77 | * This state needs to be carefully managed to ensure that it doesn't cause |
| 75 | 78 | * uaccess to fail when setting up the signal frame, and the signal handler |
| 76 | 79 | * itself also expects a well-defined state when entered. |
| 80 | + * | |
| 81 | + * The struct should be zero-initialised. Its members should only be accessed | |
| 82 | + * via the accessors below. __valid_fields tracks which of the fields are valid | |
| 83 | + * (have been set to some value). | |
| 77 | 84 | */ |
| 78 | 85 | struct user_access_state { |
| 79 | − u64 por_el0; | |
| 86 | + unsigned int __valid_fields; | |
| 87 | + u64 __por_el0; | |
| 80 | 88 | }; |
| 81 | 89 | |
| 82 | −#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16) | |
| 83 | −#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16) | |
| 90 | +#define UA_STATE_HAS_POR_EL0 BIT(0) | |
| 91 | + | |
| 92 | +static void set_ua_state_por_el0(struct user_access_state *ua_state, | |
| 93 | + u64 por_el0) | |
| 94 | +{ | |
| 95 | + ua_state->__por_el0 = por_el0; | |
| 96 | + ua_state->__valid_fields |= UA_STATE_HAS_POR_EL0; | |
| 97 | +} | |
| 98 | + | |
| 99 | +static int get_ua_state_por_el0(const struct user_access_state *ua_state, | |
| 100 | + u64 *por_el0) | |
| 101 | +{ | |
| 102 | + if (ua_state->__valid_fields & UA_STATE_HAS_POR_EL0) { | |
| 103 | + *por_el0 = ua_state->__por_el0; | |
| 104 | + return 0; | |
| 105 | + } | |
| 106 | + | |
| 107 | + return -ENOENT; | |
| 108 | +} | |
| 84 | 109 | |
| 85 | 110 | /* |
| 86 | 111 | * Save the user access state into ua_state and reset it to disable any |
| @@ -94,7 +119,7 @@ static void save_reset_user_access_state(struct user_access_state *ua_state) · 7 unmodified lines | ||
| 94 | 119 | for (int pkey = 0; pkey < arch_max_pkey(); pkey++) |
| 95 | 120 | por_enable_all |= POR_ELx_PERM_PREP(pkey, POE_RWX); |
| 96 | 121 | |
| 97 | − ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0); | |
| 122 | + set_ua_state_por_el0(ua_state, read_sysreg_s(SYS_POR_EL0)); | |
| 98 | 123 | write_sysreg_s(por_enable_all, SYS_POR_EL0); |
| 99 | 124 | /* |
| 100 | 125 | * No ISB required as we can tolerate spurious Overlay faults - |
| @@ -122,8 +147,10 @@ static void set_handler_user_access_state(void) · 21 unmodified lines | ||
| 122 | 147 | */ |
| 123 | 148 | static void restore_user_access_state(const struct user_access_state *ua_state) |
| 124 | 149 | { |
| 125 | − if (system_supports_poe()) | |
| 126 | − write_sysreg_s(ua_state->por_el0, SYS_POR_EL0); | |
| 150 | + u64 por_el0; | |
| 151 | + | |
| 152 | + if (get_ua_state_por_el0(ua_state, &por_el0) == 0) | |
| 153 | + write_sysreg_s(por_el0, SYS_POR_EL0); | |
| 127 | 154 | } |
| 128 | 155 | |
| 129 | 156 | static void init_user_layout(struct rt_sigframe_user_layout *user) |
| @@ -333,11 +360,16 @@ static int restore_fpmr_context(struct user_ctxs *user) · 203 unmodified lines | ||
| 333 | 360 | static int preserve_poe_context(struct poe_context __user *ctx, |
| 334 | 361 | const struct user_access_state *ua_state) |
| 335 | 362 | { |
| 336 | − int err = 0; | |
| 363 | + int err; | |
| 364 | + u64 por_el0; | |
| 365 | + | |
| 366 | + err = get_ua_state_por_el0(ua_state, &por_el0); | |
| 367 | + if (WARN_ON_ONCE(err)) | |
| 368 | + return err; | |
| 337 | 369 | |
| 338 | 370 | __put_user_error(POE_MAGIC, &ctx->head.magic, err); |
| 339 | 371 | __put_user_error(sizeof(*ctx), &ctx->head.size, err); |
| 340 | − __put_user_error(ua_state->por_el0, &ctx->por_el0, err); | |
| 372 | + __put_user_error(por_el0, &ctx->por_el0, err); | |
| 341 | 373 | |
| 342 | 374 | return err; |
| 343 | 375 | } |
| @@ -353,7 +385,7 @@ static int restore_poe_context(struct user_ctxs *user, · 9 unmodified lines | ||
| 353 | 385 | |
| 354 | 386 | __get_user_error(por_el0, &(user->poe->por_el0), err); |
| 355 | 387 | if (!err) |
| 356 | − ua_state->por_el0 = por_el0; | |
| 388 | + set_ua_state_por_el0(ua_state, por_el0); | |
| 357 | 389 | |
| 358 | 390 | return err; |
| 359 | 391 | } |
| @@ -1095,7 +1127,7 @@ SYSCALL_DEFINE0(rt_sigreturn) · 735 unmodified lines | ||
| 1095 | 1127 | { |
| 1096 | 1128 | struct pt_regs *regs = current_pt_regs(); |
| 1097 | 1129 | struct rt_sigframe __user *frame; |
| 1098 | − struct user_access_state ua_state; | |
| 1130 | + struct user_access_state ua_state = {}; | |
| 1099 | 1131 | |
| 1100 | 1132 | /* Always make any pending restarted system calls return -EINTR */ |
| 1101 | 1133 | current->restart_block.fn = do_no_restart_syscall; |
| @@ -1507,7 +1539,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, · 405 unmodified lines | ||
| 1507 | 1539 | { |
| 1508 | 1540 | struct rt_sigframe_user_layout user; |
| 1509 | 1541 | struct rt_sigframe __user *frame; |
| 1510 | − struct user_access_state ua_state; | |
| 1542 | + struct user_access_state ua_state = {}; | |
| 1511 | 1543 | int err = 0; |
| 1512 | 1544 | |
| 1513 | 1545 | fpsimd_save_and_flush_current_state(); |
| @@ -824,6 +824,10 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) · 823 unmodified lines | ||
| 824 | 824 | { |
| 825 | 825 | bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF | HCR_VSE); |
| 826 | 826 | |
| 827 | + irq_lines |= (!irqchip_in_kernel(v->kvm) && | |
| 828 | + (kvm_timer_should_notify_user(v) || | |
| 829 | + kvm_pmu_should_notify_user(v))); | |
| 830 | + | |
| 827 | 831 | return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) |
| 828 | 832 | && !kvm_arm_vcpu_stopped(v) && !v->arch.pause); |
| 829 | 833 | } |
| @@ -131,7 +131,6 @@ struct reg_feat_map_desc { · 130 unmodified lines | ||
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | #define FEAT_SPE ID_AA64DFR0_EL1, PMSVer, IMP |
| 134 | −#define FEAT_SPE_FnE ID_AA64DFR0_EL1, PMSVer, V1P2 | |
| 135 | 134 | #define FEAT_BRBE ID_AA64DFR0_EL1, BRBE, IMP |
| 136 | 135 | #define FEAT_TRC_SR ID_AA64DFR0_EL1, TraceVer, IMP |
| 137 | 136 | #define FEAT_PMUv3 ID_AA64DFR0_EL1, PMUVer, IMP |
| @@ -192,7 +191,7 @@ struct reg_feat_map_desc { · 54 unmodified lines | ||
| 192 | 191 | #define FEAT_SRMASK ID_AA64MMFR4_EL1, SRMASK, IMP |
| 193 | 192 | #define FEAT_PoPS ID_AA64MMFR4_EL1, PoPS, IMP |
| 194 | 193 | #define FEAT_PFAR ID_AA64PFR1_EL1, PFAR, IMP |
| 195 | −#define FEAT_Debugv8p9 ID_AA64DFR0_EL1, PMUVer, V3P9 | |
| 194 | +#define FEAT_Debugv8p9 ID_AA64DFR0_EL1, DebugVer, V8P9 | |
| 196 | 195 | #define FEAT_PMUv3_SS ID_AA64DFR0_EL1, PMSS, IMP |
| 197 | 196 | #define FEAT_SEBEP ID_AA64DFR0_EL1, SEBEP, IMP |
| 198 | 197 | #define FEAT_EBEP ID_AA64DFR1_EL1, EBEP, IMP |
| @@ -283,7 +282,7 @@ static bool feat_anerr(struct kvm *kvm) · 84 unmodified lines | ||
| 283 | 282 | static bool feat_sme_smps(struct kvm *kvm) |
| 284 | 283 | { |
| 285 | 284 | /* |
| 286 | − * Revists this if KVM ever supports SME -- this really should | |
| 285 | + * Revisit this if KVM ever supports SME -- this really should | |
| 287 | 286 | * look at the guest's view of SMIDR_EL1. Funnily enough, this |
| 288 | 287 | * is not captured in the JSON file, but only as a note in the |
| 289 | 288 | * ARM ARM. |
| @@ -295,17 +294,27 @@ static bool feat_sme_smps(struct kvm *kvm) · 5 unmodified lines | ||
| 295 | 294 | static bool feat_spe_fds(struct kvm *kvm) |
| 296 | 295 | { |
| 297 | 296 | /* |
| 298 | − * Revists this if KVM ever supports SPE -- this really should | |
| 297 | + * Revisit this if KVM ever supports SPE -- this really should | |
| 299 | 298 | * look at the guest's view of PMSIDR_EL1. |
| 300 | 299 | */ |
| 301 | 300 | return (kvm_has_feat(kvm, FEAT_SPEv1p4) && |
| 302 | 301 | (read_sysreg_s(SYS_PMSIDR_EL1) & PMSIDR_EL1_FDS)); |
| 303 | 302 | } |
| 304 | 303 | |
| 304 | +static bool feat_spe_fne(struct kvm *kvm) | |
| 305 | +{ | |
| 306 | + /* | |
| 307 | + * Revisit this if KVM ever supports SPE -- this really should | |
| 308 | + * look at the guest's view of PMSIDR_EL1. | |
| 309 | + */ | |
| 310 | + return (kvm_has_feat(kvm, FEAT_SPEv1p2) && | |
| 311 | + (read_sysreg_s(SYS_PMSIDR_EL1) & PMSIDR_EL1_FnE)); | |
| 312 | +} | |
| 313 | + | |
| 305 | 314 | static bool feat_trbe_mpam(struct kvm *kvm) |
| 306 | 315 | { |
| 307 | 316 | /* |
| 308 | − * Revists this if KVM ever supports both MPAM and TRBE -- | |
| 317 | + * Revisit this if KVM ever supports both MPAM and TRBE -- | |
| 309 | 318 | * this really should look at the guest's view of TRBIDR_EL1. |
| 310 | 319 | */ |
| 311 | 320 | return (kvm_has_feat(kvm, FEAT_TRBE) && |
| @@ -537,7 +546,7 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = { · 225 unmodified lines | ||
| 537 | 546 | HDFGRTR_EL2_PMBPTR_EL1 | |
| 538 | 547 | HDFGRTR_EL2_PMBLIMITR_EL1, |
| 539 | 548 | FEAT_SPE), |
| 540 | − NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE), | |
| 549 | + NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, feat_spe_fne), | |
| 541 | 550 | NEEDS_FEAT(HDFGRTR_EL2_nBRBDATA | |
| 542 | 551 | HDFGRTR_EL2_nBRBCTL | |
| 543 | 552 | HDFGRTR_EL2_nBRBIDR, |
| @@ -605,7 +614,7 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = { · 61 unmodified lines | ||
| 605 | 614 | HDFGWTR_EL2_PMBPTR_EL1 | |
| 606 | 615 | HDFGWTR_EL2_PMBLIMITR_EL1, |
| 607 | 616 | FEAT_SPE), |
| 608 | − NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE), | |
| 617 | + NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, feat_spe_fne), | |
| 609 | 618 | NEEDS_FEAT(HDFGWTR_EL2_nBRBDATA | |
| 610 | 619 | HDFGWTR_EL2_nBRBCTL, |
| 611 | 620 | FEAT_BRBE), |
| @@ -709,6 +709,14 @@ static const hcall_t host_hcall[] = { · 708 unmodified lines | ||
| 709 | 709 | HANDLE_FUNC(__kvm_tlb_flush_vmid_range), |
| 710 | 710 | HANDLE_FUNC(__kvm_flush_cpu_context), |
| 711 | 711 | HANDLE_FUNC(__kvm_timer_set_cntvoff), |
| 712 | + HANDLE_FUNC(__tracing_load), | |
| 713 | + HANDLE_FUNC(__tracing_unload), | |
| 714 | + HANDLE_FUNC(__tracing_enable), | |
| 715 | + HANDLE_FUNC(__tracing_swap_reader), | |
| 716 | + HANDLE_FUNC(__tracing_update_clock), | |
| 717 | + HANDLE_FUNC(__tracing_reset), | |
| 718 | + HANDLE_FUNC(__tracing_enable_event), | |
| 719 | + HANDLE_FUNC(__tracing_write_event), | |
| 712 | 720 | HANDLE_FUNC(__vgic_v3_save_aprs), |
| 713 | 721 | HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs), |
| 714 | 722 | HANDLE_FUNC(__vgic_v5_save_apr), |
| @@ -735,22 +743,16 @@ static const hcall_t host_hcall[] = { · 20 unmodified lines | ||
| 735 | 743 | HANDLE_FUNC(__pkvm_vcpu_load), |
| 736 | 744 | HANDLE_FUNC(__pkvm_vcpu_put), |
| 737 | 745 | HANDLE_FUNC(__pkvm_tlb_flush_vmid), |
| 738 | − HANDLE_FUNC(__tracing_load), | |
| 739 | − HANDLE_FUNC(__tracing_unload), | |
| 740 | − HANDLE_FUNC(__tracing_enable), | |
| 741 | − HANDLE_FUNC(__tracing_swap_reader), | |
| 742 | − HANDLE_FUNC(__tracing_update_clock), | |
| 743 | − HANDLE_FUNC(__tracing_reset), | |
| 744 | − HANDLE_FUNC(__tracing_enable_event), | |
| 745 | − HANDLE_FUNC(__tracing_write_event), | |
| 746 | 746 | }; |
| 747 | 747 | |
| 748 | 748 | static void handle_host_hcall(struct kvm_cpu_context *host_ctxt) |
| 749 | 749 | { |
| 750 | 750 | DECLARE_REG(unsigned long, id, host_ctxt, 0); |
| 751 | − unsigned long hcall_min = 0, hcall_max = -1; | |
| 751 | + unsigned long hcall_min = 0, hcall_max = __KVM_HOST_SMCCC_FUNC_MAX; | |
| 752 | 752 | hcall_t hfn; |
| 753 | 753 | |
| 754 | + BUILD_BUG_ON(ARRAY_SIZE(host_hcall) != __KVM_HOST_SMCCC_FUNC_MAX); | |
| 755 | + | |
| 754 | 756 | /* |
| 755 | 757 | * If pKVM has been initialised then reject any calls to the |
| 756 | 758 | * early "privileged" hypercalls. Note that we cannot reject |
| @@ -763,16 +765,14 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt) · 6 unmodified lines | ||
| 763 | 765 | if (static_branch_unlikely(&kvm_protected_mode_initialized)) { |
| 764 | 766 | hcall_min = __KVM_HOST_SMCCC_FUNC_MIN_PKVM; |
| 765 | 767 | } else { |
| 766 | − hcall_max = __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM; | |
| 768 | + hcall_max = __KVM_HOST_SMCCC_FUNC_PKVM_ONLY; | |
| 767 | 769 | } |
| 768 | 770 | |
| 769 | 771 | id &= ~ARM_SMCCC_CALL_HINTS; |
| 770 | 772 | id -= KVM_HOST_SMCCC_ID(0); |
| 771 | 773 | |
| 772 | − if (unlikely(id < hcall_min || id > hcall_max || | |
| 773 | − id >= ARRAY_SIZE(host_hcall))) { | |
| 774 | + if (unlikely(id < hcall_min || id >= hcall_max)) | |
| 774 | 775 | goto inval; |
| 775 | − } | |
| 776 | 776 | |
| 777 | 777 | hfn = host_hcall[id]; |
| 778 | 778 | if (unlikely(!hfn)) |
| @@ -805,6 +805,10 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt) · 26 unmodified lines | ||
| 805 | 805 | } |
| 806 | 806 | |
| 807 | 807 | func_id &= ~ARM_SMCCC_CALL_HINTS; |
| 808 | + if (upper_32_bits(func_id)) { | |
| 809 | + cpu_reg(host_ctxt, 0) = SMCCC_RET_NOT_SUPPORTED; | |
| 810 | + goto exit_skip_instr; | |
| 811 | + } | |
| 808 | 812 | |
| 809 | 813 | handled = kvm_host_psci_handler(host_ctxt, func_id); |
| 810 | 814 | if (!handled) |
| @@ -266,7 +266,8 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle, · 265 unmodified lines | ||
| 266 | 266 | if (hyp_vm->kvm.created_vcpus <= vcpu_idx) |
| 267 | 267 | goto unlock; |
| 268 | 268 | |
| 269 | − hyp_vcpu = hyp_vm->vcpus[vcpu_idx]; | |
| 269 | + /* Pairs with smp_store_release() in register_hyp_vcpu(). */ | |
| 270 | + hyp_vcpu = smp_load_acquire(&hyp_vm->vcpus[vcpu_idx]); | |
| 270 | 271 | if (!hyp_vcpu) |
| 271 | 272 | goto unlock; |
| 272 | 273 | |
| @@ -860,12 +861,30 @@ err_unpin_kvm: · 587 unmodified lines | ||
| 860 | 861 | * the page-aligned size of 'struct pkvm_hyp_vcpu'. |
| 861 | 862 | * Return 0 on success, negative error code on failure. |
| 862 | 863 | */ |
| 864 | +static int register_hyp_vcpu(struct pkvm_hyp_vm *hyp_vm, | |
| 865 | + struct pkvm_hyp_vcpu *hyp_vcpu) | |
| 866 | +{ | |
| 867 | + unsigned int idx = hyp_vcpu->vcpu.vcpu_idx; | |
| 868 | + | |
| 869 | + if (idx >= hyp_vm->kvm.created_vcpus) | |
| 870 | + return -EINVAL; | |
| 871 | + | |
| 872 | + if (hyp_vm->vcpus[idx]) | |
| 873 | + return -EINVAL; | |
| 874 | + | |
| 875 | + /* | |
| 876 | + * Ensure the hyp_vcpu is initialised before publishing it to | |
| 877 | + * the vCPU-load path via 'hyp_vm->vcpus[]'. | |
| 878 | + */ | |
| 879 | + smp_store_release(&hyp_vm->vcpus[idx], hyp_vcpu); | |
| 880 | + return 0; | |
| 881 | +} | |
| 882 | + | |
| 863 | 883 | int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu, |
| 864 | 884 | unsigned long vcpu_hva) |
| 865 | 885 | { |
| 866 | 886 | struct pkvm_hyp_vcpu *hyp_vcpu; |
| 867 | 887 | struct pkvm_hyp_vm *hyp_vm; |
| 868 | − unsigned int idx; | |
| 869 | 888 | int ret; |
| 870 | 889 | |
| 871 | 890 | hyp_vcpu = map_donated_memory(vcpu_hva, sizeof(*hyp_vcpu)); |
| @@ -884,18 +903,11 @@ int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu, · 12 unmodified lines | ||
| 884 | 903 | if (ret) |
| 885 | 904 | goto unlock; |
| 886 | 905 | |
| 887 | − idx = hyp_vcpu->vcpu.vcpu_idx; | |
| 888 | − if (idx >= hyp_vm->kvm.created_vcpus) { | |
| 889 | − ret = -EINVAL; | |
| 890 | − goto unlock; | |
| 891 | − } | |
| 892 | − | |
| 893 | − if (hyp_vm->vcpus[idx]) { | |
| 894 | − ret = -EINVAL; | |
| 895 | − goto unlock; | |
| 906 | + ret = register_hyp_vcpu(hyp_vm, hyp_vcpu); | |
| 907 | + if (ret) { | |
| 908 | + unpin_host_vcpu(host_vcpu); | |
| 909 | + unpin_host_sve_state(hyp_vcpu); | |
| 896 | 910 | } |
| 897 | − | |
| 898 | − hyp_vm->vcpus[idx] = hyp_vcpu; | |
| 899 | 911 | unlock: |
| 900 | 912 | hyp_spin_unlock(&vm_table_lock); |
| 901 | 913 | |
| @@ -312,15 +312,15 @@ void __noreturn __pkvm_init_finalise(void) · 311 unmodified lines | ||
| 312 | 312 | }; |
| 313 | 313 | pkvm_pgtable.mm_ops = &pkvm_pgtable_mm_ops; |
| 314 | 314 | |
| 315 | − ret = fix_host_ownership(); | |
| 315 | + ret = fix_hyp_pgtable_refcnt(); | |
| 316 | 316 | if (ret) |
| 317 | 317 | goto out; |
| 318 | 318 | |
| 319 | − ret = fix_hyp_pgtable_refcnt(); | |
| 319 | + ret = hyp_create_fixmap(); | |
| 320 | 320 | if (ret) |
| 321 | 321 | goto out; |
| 322 | 322 | |
| 323 | − ret = hyp_create_fixmap(); | |
| 323 | + ret = fix_host_ownership(); | |
| 324 | 324 | if (ret) |
| 325 | 325 | goto out; |
| 326 | 326 | |
| @@ -91,7 +91,7 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu, · 90 unmodified lines | ||
| 91 | 91 | * migration from old kernels to new kernels with legacy |
| 92 | 92 | * userspace. |
| 93 | 93 | */ |
| 94 | − reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg); | |
| 94 | + reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val); | |
| 95 | 95 | switch (reg) { |
| 96 | 96 | case KVM_VGIC_IMP_REV_2: |
| 97 | 97 | case KVM_VGIC_IMP_REV_3: |
| @@ -194,7 +194,7 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu, · 193 unmodified lines | ||
| 194 | 194 | if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK) |
| 195 | 195 | return -EINVAL; |
| 196 | 196 | |
| 197 | − reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg); | |
| 197 | + reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val); | |
| 198 | 198 | switch (reg) { |
| 199 | 199 | case KVM_VGIC_IMP_REV_2: |
| 200 | 200 | case KVM_VGIC_IMP_REV_3: |
| @@ -1414,6 +1414,9 @@ static inline char *debug_get_user_string(const char __user *user_buf, · 1413 unmodified lines | ||
| 1414 | 1414 | { |
| 1415 | 1415 | char *buffer; |
| 1416 | 1416 | |
| 1417 | + if (!user_len) | |
| 1418 | + return ERR_PTR(-EINVAL); | |
| 1419 | + | |
| 1417 | 1420 | buffer = memdup_user_nul(user_buf, user_len); |
| 1418 | 1421 | if (IS_ERR(buffer)) |
| 1419 | 1422 | return buffer; |
| @@ -1584,6 +1587,11 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view, · 164 unmodified lines | ||
| 1584 | 1587 | char input_buf[1]; |
| 1585 | 1588 | int rc = user_len; |
| 1586 | 1589 | |
| 1590 | + if (!user_len) { | |
| 1591 | + rc = -EINVAL; | |
| 1592 | + goto out; | |
| 1593 | + } | |
| 1594 | + | |
| 1587 | 1595 | if (user_len > 0x10000) |
| 1588 | 1596 | user_len = 0x10000; |
| 1589 | 1597 | if (*offset != 0) { |
| @@ -438,7 +438,7 @@ void do_secure_storage_access(struct pt_regs *regs) · 437 unmodified lines | ||
| 438 | 438 | panic("Unexpected PGM 0x3d with TEID bit 61=0"); |
| 439 | 439 | } |
| 440 | 440 | if (is_kernel_fault(regs)) { |
| 441 | − folio = phys_to_folio(addr); | |
| 441 | + folio = virt_to_folio((void *)addr); | |
| 442 | 442 | if (unlikely(!folio_try_get(folio))) |
| 443 | 443 | return; |
| 444 | 444 | rc = uv_convert_from_secure(folio_to_phys(folio)); |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | /* |
| 8 | 8 | * This is set up by the setup-routine at boot-time |
| 9 | 9 | */ |
| 10 | −extern unsigned char *boot_params_page; | |
| 10 | +extern unsigned char boot_params_page[]; | |
| 11 | 11 | #define PARAM boot_params_page |
| 12 | 12 | |
| 13 | 13 | #define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000)) |
| @@ -390,6 +390,11 @@ static int crypto_authenc_esn_create(struct crypto_template *tmpl, · 389 unmodified lines | ||
| 390 | 390 | auth = crypto_spawn_ahash_alg(&ctx->auth); |
| 391 | 391 | auth_base = &auth->base; |
| 392 | 392 | |
| 393 | + if (auth->digestsize > 0 && auth->digestsize < 4) { | |
| 394 | + err = -EINVAL; | |
| 395 | + goto err_free_inst; | |
| 396 | + } | |
| 397 | + | |
| 393 | 398 | err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), |
| 394 | 399 | crypto_attr_alg_name(tb[2]), 0, mask); |
| 395 | 400 | if (err) |
| @@ -605,15 +605,12 @@ static umode_t acpi_tad_attr_is_visible(struct kobject *kobj, · 604 unmodified lines | ||
| 605 | 605 | return 0; |
| 606 | 606 | } |
| 607 | 607 | |
| 608 | −static const struct attribute_group acpi_tad_attr_group = { | |
| 608 | +static const struct attribute_group acpi_tad_group = { | |
| 609 | 609 | .attrs = acpi_tad_attrs, |
| 610 | 610 | .is_visible = acpi_tad_attr_is_visible, |
| 611 | 611 | }; |
| 612 | 612 | |
| 613 | −static const struct attribute_group *acpi_tad_attr_groups[] = { | |
| 614 | − &acpi_tad_attr_group, | |
| 615 | − NULL, | |
| 616 | −}; | |
| 613 | +__ATTRIBUTE_GROUPS(acpi_tad); | |
| 617 | 614 | |
| 618 | 615 | #ifdef CONFIG_RTC_CLASS |
| 619 | 616 | /* RTC class device interface */ |
| @@ -683,9 +680,8 @@ static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) · 63 unmodified lines | ||
| 683 | 680 | |
| 684 | 681 | acpi_tad_rt_to_tm(&rt, &tm_now); |
| 685 | 682 | |
| 686 | − value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time), | |
| 687 | − rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC); | |
| 688 | − if (value <= 0 || value > U32_MAX) | |
| 683 | + value = rtc_tm_to_time64(&t->time) - rtc_tm_to_time64(&tm_now); | |
| 684 | + if (value <= 0 || value >= U32_MAX) | |
| 689 | 685 | return -EINVAL; |
| 690 | 686 | } |
| 691 | 687 | |
| @@ -748,8 +744,7 @@ static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) · 56 unmodified lines | ||
| 748 | 744 | |
| 749 | 745 | if (retval != ACPI_TAD_WAKE_DISABLED) { |
| 750 | 746 | t->enabled = 1; |
| 751 | − t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now), | |
| 752 | − (u64)retval * NSEC_PER_SEC)); | |
| 747 | + rtc_time64_to_tm(rtc_tm_to_time64(&tm_now) + retval, &t->time); | |
| 753 | 748 | } else { |
| 754 | 749 | t->enabled = 0; |
| 755 | 750 | t->time = tm_now; |
| @@ -795,9 +790,9 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) · 39 unmodified lines | ||
| 795 | 790 | return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED); |
| 796 | 791 | } |
| 797 | 792 | |
| 798 | −static void acpi_tad_remove(struct platform_device *pdev) | |
| 793 | +static void acpi_tad_remove(void *data) | |
| 799 | 794 | { |
| 800 | − struct device *dev = &pdev->dev; | |
| 795 | + struct device *dev = data; | |
| 801 | 796 | struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); |
| 802 | 797 | |
| 803 | 798 | device_init_wakeup(dev, false); |
| @@ -824,6 +819,7 @@ static int acpi_tad_probe(struct platform_device *pdev) · 20 unmodified lines | ||
| 824 | 819 | struct acpi_tad_driver_data *dd; |
| 825 | 820 | acpi_status status; |
| 826 | 821 | unsigned long long caps; |
| 822 | + int ret; | |
| 827 | 823 | |
| 828 | 824 | /* |
| 829 | 825 | * Initialization failure messages are mostly about firmware issues, so |
| @@ -863,13 +859,21 @@ static int acpi_tad_probe(struct platform_device *pdev) · 33 unmodified lines | ||
| 863 | 859 | } |
| 864 | 860 | |
| 865 | 861 | /* |
| 866 | − * The platform bus type layer tells the ACPI PM domain powers up the | |
| 867 | − * device, so set the runtime PM status of it to "active". | |
| 862 | + * The platform bus type probe callback tells the ACPI PM domain to | |
| 863 | + * power up the device, so set the runtime PM status of it to "active". | |
| 868 | 864 | */ |
| 869 | 865 | pm_runtime_set_active(dev); |
| 870 | 866 | pm_runtime_enable(dev); |
| 871 | 867 | pm_runtime_suspend(dev); |
| 872 | 868 | |
| 869 | + /* | |
| 870 | + * acpi_tad_remove() needs to run after unregistering the RTC class | |
| 871 | + * device to avoid racing with the latter's callbacks. | |
| 872 | + */ | |
| 873 | + ret = devm_add_action_or_reset(&pdev->dev, acpi_tad_remove, &pdev->dev); | |
| 874 | + if (ret) | |
| 875 | + return ret; | |
| 876 | + | |
| 873 | 877 | if (caps & ACPI_TAD_RT) |
| 874 | 878 | acpi_tad_register_rtc(dev, caps); |
| 875 | 879 | |
| @@ -885,10 +889,9 @@ static struct platform_driver acpi_tad_driver = { · 9 unmodified lines | ||
| 885 | 889 | .driver = { |
| 886 | 890 | .name = "acpi-tad", |
| 887 | 891 | .acpi_match_table = acpi_tad_ids, |
| 888 | − .dev_groups = acpi_tad_attr_groups, | |
| 892 | + .dev_groups = acpi_tad_groups, | |
| 889 | 893 | }, |
| 890 | 894 | .probe = acpi_tad_probe, |
| 891 | − .remove = acpi_tad_remove, | |
| 892 | 895 | }; |
| 893 | 896 | MODULE_DEVICE_TABLE(acpi, acpi_tad_ids); |
| 894 | 897 | |
| @@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region( · 400 unmodified lines | ||
| 401 | 401 | |
| 402 | 402 | return NULL; |
| 403 | 403 | } |
| 404 | + | |
| 405 | +static bool is_memory_injection(u32 type, u32 flags) | |
| 406 | +{ | |
| 407 | + if (flags & SETWA_FLAGS_EINJV2) | |
| 408 | + return !!(type & ACPI_EINJV2_MEMORY); | |
| 409 | + if (type & ACPI5_VENDOR_BIT) | |
| 410 | + return !!(vendor_flags & SETWA_FLAGS_MEM); | |
| 411 | + return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM); | |
| 412 | +} | |
| 413 | + | |
| 404 | 414 | /* Execute instructions in trigger error action table */ |
| 405 | −static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |
| 415 | +static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags, | |
| 406 | 416 | u64 param1, u64 param2) |
| 407 | 417 | { |
| 408 | 418 | struct acpi_einj_trigger trigger_tab; |
| @@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, · 71 unmodified lines | ||
| 480 | 490 | * This will cause resource conflict with regular memory. So |
| 481 | 491 | * remove it from trigger table resources. |
| 482 | 492 | */ |
| 483 | − if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) { | |
| 493 | + if ((param_extension || acpi5) && is_memory_injection(type, flags)) { | |
| 484 | 494 | struct apei_resources addr_resources; |
| 485 | 495 | |
| 486 | 496 | apei_resources_init(&addr_resources); |
| @@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, · 173 unmodified lines | ||
| 660 | 670 | return rc; |
| 661 | 671 | trigger_paddr = apei_exec_ctx_get_output(&ctx); |
| 662 | 672 | if (notrigger == 0) { |
| 663 | − rc = __einj_error_trigger(trigger_paddr, type, param1, param2); | |
| 673 | + rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2); | |
| 664 | 674 | if (rc) |
| 665 | 675 | return rc; |
| 666 | 676 | } |
| @@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, · 51 unmodified lines | ||
| 718 | 728 | SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2))) |
| 719 | 729 | return -EINVAL; |
| 720 | 730 | |
| 731 | + /* | |
| 732 | + * Injections targeting a CXL 1.0/1.1 port have to be injected | |
| 733 | + * via the einj_cxl_rch_error_inject() path as that does the proper | |
| 734 | + * validation of the given RCRB base (MMIO) address. | |
| 735 | + */ | |
| 736 | + if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) | |
| 737 | + return -EINVAL; | |
| 738 | + | |
| 721 | 739 | /* check if type is a valid EINJv2 error type */ |
| 722 | 740 | if (is_v2) { |
| 723 | 741 | if (!(type & available_error_type_v2)) |
| 724 | 742 | return -EINVAL; |
| 725 | 743 | } |
| 726 | − /* | |
| 727 | − * We need extra sanity checks for memory errors. | |
| 728 | − * Other types leap directly to injection. | |
| 729 | − */ | |
| 730 | 744 | |
| 731 | 745 | /* ensure param1/param2 existed */ |
| 732 | 746 | if (!(param_extension || acpi5)) |
| 733 | 747 | goto inject; |
| 734 | 748 | |
| 735 | − /* ensure injection is memory related */ | |
| 736 | − if (type & ACPI5_VENDOR_BIT) { | |
| 737 | − if (vendor_flags != SETWA_FLAGS_MEM) | |
| 738 | − goto inject; | |
| 739 | − } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) { | |
| 740 | − goto inject; | |
| 741 | − } | |
| 742 | − | |
| 743 | 749 | /* |
| 744 | − * Injections targeting a CXL 1.0/1.1 port have to be injected | |
| 745 | − * via the einj_cxl_rch_error_inject() path as that does the proper | |
| 746 | − * validation of the given RCRB base (MMIO) address. | |
| 750 | + * We need extra sanity checks for memory errors. | |
| 751 | + * Other types leap directly to injection. | |
| 747 | 752 | */ |
| 748 | − if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) | |
| 749 | − return -EINVAL; | |
| 753 | + if (!is_memory_injection(type, flags)) | |
| 754 | + goto inject; | |
| 750 | 755 | |
| 751 | 756 | /* |
| 752 | 757 | * Disallow crazy address masks that give BIOS leeway to pick |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | static int psci_acpi_cpu_init_idle(unsigned int cpu) |
| 18 | 18 | { |
| 19 | − int i, count; | |
| 19 | + int i; | |
| 20 | 20 | struct acpi_lpi_state *lpi; |
| 21 | 21 | struct acpi_processor *pr = per_cpu(processors, cpu); |
| 22 | 22 | |
| @@ -30,14 +30,10 @@ static int psci_acpi_cpu_init_idle(unsigned int cpu) · 7 unmodified lines | ||
| 30 | 30 | if (!psci_ops.cpu_suspend) |
| 31 | 31 | return -EOPNOTSUPP; |
| 32 | 32 | |
| 33 | − count = pr->power.count - 1; | |
| 34 | − if (count <= 0) | |
| 35 | − return -ENODEV; | |
| 36 | − | |
| 37 | − for (i = 0; i < count; i++) { | |
| 33 | + for (i = 1; i < pr->power.count; i++) { | |
| 38 | 34 | u32 state; |
| 39 | 35 | |
| 40 | − lpi = &pr->power.lpi_states[i + 1]; | |
| 36 | + lpi = &pr->power.lpi_states[i]; | |
| 41 | 37 | /* |
| 42 | 38 | * Only bits[31:0] represent a PSCI power_state while |
| 43 | 39 | * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification |
| @@ -362,7 +362,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd) · 361 unmodified lines | ||
| 362 | 362 | end: |
| 363 | 363 | if (cmd == CMD_WRITE) { |
| 364 | 364 | if (unlikely(ret)) { |
| 365 | − for_each_online_cpu(i) { | |
| 365 | + for_each_possible_cpu(i) { | |
| 366 | 366 | struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i); |
| 367 | 367 | |
| 368 | 368 | if (!desc) |
| @@ -524,13 +524,13 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data) · 155 unmodified lines | ||
| 524 | 524 | else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) |
| 525 | 525 | cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY; |
| 526 | 526 | |
| 527 | − for_each_online_cpu(i) { | |
| 527 | + for_each_possible_cpu(i) { | |
| 528 | 528 | if (i == cpu) |
| 529 | 529 | continue; |
| 530 | 530 | |
| 531 | 531 | match_cpc_ptr = per_cpu(cpc_desc_ptr, i); |
| 532 | 532 | if (!match_cpc_ptr) |
| 533 | − goto err_fault; | |
| 533 | + continue; | |
| 534 | 534 | |
| 535 | 535 | match_pdomain = &(match_cpc_ptr->domain_info); |
| 536 | 536 | if (match_pdomain->domain != pdomain->domain) |
| @@ -916,6 +916,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { · 915 unmodified lines | ||
| 916 | 916 | DMI_MATCH(DMI_PRODUCT_NAME, "82K8"), |
| 917 | 917 | }, |
| 918 | 918 | }, |
| 919 | + { | |
| 920 | + .callback = video_detect_force_native, | |
| 921 | + /* HP OMEN Gaming Laptop 16-n0xxx */ | |
| 922 | + .matches = { | |
| 923 | + DMI_MATCH(DMI_SYS_VENDOR, "HP"), | |
| 924 | + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-n0xxx"), | |
| 925 | + }, | |
| 926 | + }, | |
| 919 | 927 | |
| 920 | 928 | /* |
| 921 | 929 | * x86 android tablets which directly control the backlight through |
| @@ -459,19 +459,11 @@ static void pata_parport_dev_release(struct device *dev) · 458 unmodified lines | ||
| 459 | 459 | kfree(pi); |
| 460 | 460 | } |
| 461 | 461 | |
| 462 | −static void pata_parport_bus_release(struct device *dev) | |
| 463 | −{ | |
| 464 | − /* nothing to do here but required to avoid warning on device removal */ | |
| 465 | −} | |
| 466 | − | |
| 467 | 462 | static const struct bus_type pata_parport_bus_type = { |
| 468 | 463 | .name = DRV_NAME, |
| 469 | 464 | }; |
| 470 | 465 | |
| 471 | −static struct device pata_parport_bus = { | |
| 472 | − .init_name = DRV_NAME, | |
| 473 | − .release = pata_parport_bus_release, | |
| 474 | −}; | |
| 466 | +static struct device *pata_parport_bus; | |
| 475 | 467 | |
| 476 | 468 | static const struct scsi_host_template pata_parport_sht = { |
| 477 | 469 | PATA_PARPORT_SHT("pata_parport") |
| @@ -518,7 +510,7 @@ static struct pi_adapter *pi_init_one(struct parport *parport, · 40 unmodified lines | ||
| 518 | 510 | } |
| 519 | 511 | |
| 520 | 512 | /* set up pi->dev before pi_probe_unit() so it can use dev_printk() */ |
| 521 | − pi->dev.parent = &pata_parport_bus; | |
| 513 | + pi->dev.parent = pata_parport_bus; | |
| 522 | 514 | pi->dev.bus = &pata_parport_bus_type; |
| 523 | 515 | pi->dev.driver = &pr->driver; |
| 524 | 516 | pi->dev.release = pata_parport_dev_release; |
| @@ -780,8 +772,9 @@ static __init int pata_parport_init(void) · 255 unmodified lines | ||
| 780 | 772 | return error; |
| 781 | 773 | } |
| 782 | 774 | |
| 783 | − error = device_register(&pata_parport_bus); | |
| 784 | − if (error) { | |
| 775 | + pata_parport_bus = root_device_register(DRV_NAME); | |
| 776 | + if (IS_ERR(pata_parport_bus)) { | |
| 777 | + error = PTR_ERR(pata_parport_bus); | |
| 785 | 778 | pr_err("failed to register pata_parport bus, error: %d\n", error); |
| 786 | 779 | goto out_unregister_bus; |
| 787 | 780 | } |
| @@ -811,7 +804,7 @@ out_remove_del: · 23 unmodified lines | ||
| 811 | 804 | out_remove_new: |
| 812 | 805 | bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device); |
| 813 | 806 | out_unregister_dev: |
| 814 | − device_unregister(&pata_parport_bus); | |
| 807 | + root_device_unregister(pata_parport_bus); | |
| 815 | 808 | out_unregister_bus: |
| 816 | 809 | bus_unregister(&pata_parport_bus_type); |
| 817 | 810 | return error; |
| @@ -822,7 +815,7 @@ static __exit void pata_parport_exit(void) · 4 unmodified lines | ||
| 822 | 815 | parport_unregister_driver(&pata_parport_driver); |
| 823 | 816 | bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device); |
| 824 | 817 | bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device); |
| 825 | − device_unregister(&pata_parport_bus); | |
| 818 | + root_device_unregister(pata_parport_bus); | |
| 826 | 819 | bus_unregister(&pata_parport_bus_type); |
| 827 | 820 | } |
| 828 | 821 | |
| @@ -172,7 +172,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va · 171 unmodified lines | ||
| 172 | 172 | ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size); |
| 173 | 173 | if (ret == -ENODATA) { |
| 174 | 174 | if (!deferrable) |
| 175 | − dev_warn(dev, "Defer on undeferable control: %x\n", reg); | |
| 175 | + dev_warn(dev, "Defer on undeferrable control: %x\n", reg); | |
| 176 | 176 | |
| 177 | 177 | ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx); |
| 178 | 178 | if (ret) |
| @@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) · 630 unmodified lines | ||
| 631 | 631 | |
| 632 | 632 | WARN_ON(!cdo->generic_packet); |
| 633 | 633 | |
| 634 | + /* | |
| 635 | + * Propagate the drive's write support to the block layer so BLKROGET | |
| 636 | + * reflects actual write capability. Drivers that use GET CONFIGURATION | |
| 637 | + * features (CDC_MRW_W, CDC_RAM) must have called | |
| 638 | + * cdrom_probe_write_features() before register_cdrom() so the mask is | |
| 639 | + * complete here. | |
| 640 | + */ | |
| 641 | + set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | | |
| 642 | + CDC_CD_RW)); | |
| 643 | + | |
| 634 | 644 | cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); |
| 635 | 645 | mutex_lock(&cdrom_mutex); |
| 636 | 646 | list_add(&cdi->list, &cdrom_list); |
| @@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) · 105 unmodified lines | ||
| 742 | 752 | return 0; |
| 743 | 753 | } |
| 744 | 754 | |
| 755 | +/* | |
| 756 | + * Probe write-related MMC features via GET CONFIGURATION and update | |
| 757 | + * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE | |
| 758 | + * capabilities page (e.g. sr) should call this after those MODE SENSE bits | |
| 759 | + * have been set but before register_cdrom(), so that the full set of | |
| 760 | + * write-capability bits is known by the time register_cdrom() decides on the | |
| 761 | + * initial read-only state of the disk. | |
| 762 | + */ | |
| 763 | +void cdrom_probe_write_features(struct cdrom_device_info *cdi) | |
| 764 | +{ | |
| 765 | + int mrw, mrw_write, ram_write; | |
| 766 | + | |
| 767 | + mrw = 0; | |
| 768 | + if (!cdrom_is_mrw(cdi, &mrw_write)) | |
| 769 | + mrw = 1; | |
| 770 | + | |
| 771 | + if (CDROM_CAN(CDC_MO_DRIVE)) | |
| 772 | + ram_write = 1; | |
| 773 | + else | |
| 774 | + (void) cdrom_is_random_writable(cdi, &ram_write); | |
| 775 | + | |
| 776 | + if (mrw) | |
| 777 | + cdi->mask &= ~CDC_MRW; | |
| 778 | + else | |
| 779 | + cdi->mask |= CDC_MRW; | |
| 780 | + | |
| 781 | + if (mrw_write) | |
| 782 | + cdi->mask &= ~CDC_MRW_W; | |
| 783 | + else | |
| 784 | + cdi->mask |= CDC_MRW_W; | |
| 785 | + | |
| 786 | + if (ram_write) | |
| 787 | + cdi->mask &= ~CDC_RAM; | |
| 788 | + else | |
| 789 | + cdi->mask |= CDC_RAM; | |
| 790 | +} | |
| 791 | +EXPORT_SYMBOL(cdrom_probe_write_features); | |
| 792 | + | |
| 745 | 793 | static int cdrom_media_erasable(struct cdrom_device_info *cdi) |
| 746 | 794 | { |
| 747 | 795 | disc_information di; |
| @@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) · 146 unmodified lines | ||
| 894 | 942 | */ |
| 895 | 943 | static int cdrom_open_write(struct cdrom_device_info *cdi) |
| 896 | 944 | { |
| 897 | − int mrw, mrw_write, ram_write; | |
| 898 | 945 | int ret = 1; |
| 899 | 946 | |
| 900 | − mrw = 0; | |
| 901 | − if (!cdrom_is_mrw(cdi, &mrw_write)) | |
| 902 | − mrw = 1; | |
| 903 | − | |
| 904 | − if (CDROM_CAN(CDC_MO_DRIVE)) | |
| 905 | − ram_write = 1; | |
| 906 | − else | |
| 907 | − (void) cdrom_is_random_writable(cdi, &ram_write); | |
| 908 | − | |
| 909 | − if (mrw) | |
| 910 | − cdi->mask &= ~CDC_MRW; | |
| 911 | − else | |
| 912 | − cdi->mask |= CDC_MRW; | |
| 913 | − | |
| 914 | − if (mrw_write) | |
| 915 | − cdi->mask &= ~CDC_MRW_W; | |
| 916 | − else | |
| 917 | − cdi->mask |= CDC_MRW_W; | |
| 918 | − | |
| 919 | − if (ram_write) | |
| 920 | − cdi->mask &= ~CDC_RAM; | |
| 921 | − else | |
| 922 | − cdi->mask |= CDC_RAM; | |
| 923 | − | |
| 924 | 947 | if (CDROM_CAN(CDC_MRW_W)) |
| 925 | 948 | ret = cdrom_mrw_open_write(cdi); |
| 926 | 949 | else if (CDROM_CAN(CDC_DVD_RAM)) |
| @@ -900,11 +900,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin) · 899 unmodified lines | ||
| 900 | 900 | return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); |
| 901 | 901 | } |
| 902 | 902 | |
| 903 | +/** | |
| 904 | + * __dpll_pin_change_ntf - notify that the pin has been changed | |
| 905 | + * @pin: registered pin pointer | |
| 906 | + * | |
| 907 | + * Context: caller must hold dpll_lock. Suitable for use inside pin | |
| 908 | + * callbacks which are already invoked under dpll_lock. | |
| 909 | + * Return: 0 if succeeds, error code otherwise. | |
| 910 | + */ | |
| 903 | 911 | int __dpll_pin_change_ntf(struct dpll_pin *pin) |
| 904 | 912 | { |
| 913 | + lockdep_assert_held(&dpll_lock); | |
| 905 | 914 | dpll_pin_notify(pin, DPLL_PIN_CHANGED); |
| 906 | 915 | return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); |
| 907 | 916 | } |
| 917 | +EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf); | |
| 908 | 918 | |
| 909 | 919 | /** |
| 910 | 920 | * dpll_pin_change_ntf - notify that the pin has been changed |
| @@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll); · 10 unmodified lines | ||
| 11 | 11 | int dpll_pin_create_ntf(struct dpll_pin *pin); |
| 12 | 12 | |
| 13 | 13 | int dpll_pin_delete_ntf(struct dpll_pin *pin); |
| 14 | − | |
| 15 | −int __dpll_pin_change_ntf(struct dpll_pin *pin); | |
| @@ -2839,8 +2839,12 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) · 2838 unmodified lines | ||
| 2839 | 2839 | * that checks whether the PSP is running. A solution for those issues |
| 2840 | 2840 | * in the APU is to trigger a GPU reset, but this should be done during |
| 2841 | 2841 | * the unload phase to avoid adding boot latency and screen flicker. |
| 2842 | + * GFX V11 has GC block as default off IP. Every time AMDGPU driver sends | |
| 2843 | + * a request to PMFW to unload MP1, PMFW will put GC in reset and power down | |
| 2844 | + * the voltage. Hence, skipping reset for APUs with GFX V11 or later. | |
| 2842 | 2845 | */ |
| 2843 | − if ((adev->flags & AMD_IS_APU) && !adev->gmc.is_app_apu) { | |
| 2846 | + if ((adev->flags & AMD_IS_APU) && !adev->gmc.is_app_apu && | |
| 2847 | + amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(11, 0, 0)) { | |
| 2844 | 2848 | r = amdgpu_asic_reset(adev); |
| 2845 | 2849 | if (r) |
| 2846 | 2850 | dev_err(adev->dev, "asic reset on %s failed\n", __func__); |
| @@ -3090,10 +3090,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) · 3089 unmodified lines | ||
| 3090 | 3090 | case IP_VERSION(11, 5, 1): |
| 3091 | 3091 | case IP_VERSION(11, 5, 2): |
| 3092 | 3092 | case IP_VERSION(11, 5, 3): |
| 3093 | − adev->family = AMDGPU_FAMILY_GC_11_5_0; | |
| 3094 | − break; | |
| 3095 | 3093 | case IP_VERSION(11, 5, 4): |
| 3096 | − adev->family = AMDGPU_FAMILY_GC_11_5_4; | |
| 3094 | + adev->family = AMDGPU_FAMILY_GC_11_5_0; | |
| 3097 | 3095 | break; |
| 3098 | 3096 | case IP_VERSION(12, 0, 0): |
| 3099 | 3097 | case IP_VERSION(12, 0, 1): |
| @@ -3158,8 +3158,10 @@ static int __init amdgpu_init(void) · 3157 unmodified lines | ||
| 3158 | 3158 | amdgpu_register_atpx_handler(); |
| 3159 | 3159 | amdgpu_acpi_detect(); |
| 3160 | 3160 | |
| 3161 | − /* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */ | |
| 3162 | − amdgpu_amdkfd_init(); | |
| 3161 | + /* Ignore KFD init failures when CONFIG_HSA_AMD is not set. */ | |
| 3162 | + r = amdgpu_amdkfd_init(); | |
| 3163 | + if (r && r != -ENOENT) | |
| 3164 | + goto error_fence; | |
| 3163 | 3165 | |
| 3164 | 3166 | if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) { |
| 3165 | 3167 | add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); |
| @@ -314,7 +314,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, · 313 unmodified lines | ||
| 314 | 314 | mc->gart_start = max_mc_address - mc->gart_size + 1; |
| 315 | 315 | break; |
| 316 | 316 | case AMDGPU_GART_PLACEMENT_LOW: |
| 317 | − mc->gart_start = 0; | |
| 317 | + if (size_bf >= mc->gart_size) | |
| 318 | + mc->gart_start = 0; | |
| 319 | + else | |
| 320 | + mc->gart_start = ALIGN(mc->fb_end, four_gb); | |
| 318 | 321 | break; |
| 319 | 322 | case AMDGPU_GART_PLACEMENT_BEST_FIT: |
| 320 | 323 | default: |
| @@ -873,68 +873,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) · 872 unmodified lines | ||
| 873 | 873 | ? -EFAULT : 0; |
| 874 | 874 | } |
| 875 | 875 | case AMDGPU_INFO_READ_MMR_REG: { |
| 876 | − int ret = 0; | |
| 877 | − unsigned int n, alloc_size; | |
| 878 | − uint32_t *regs; | |
| 879 | 876 | unsigned int se_num = (info->read_mmr_reg.instance >> |
| 880 | 877 | AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & |
| 881 | 878 | AMDGPU_INFO_MMR_SE_INDEX_MASK; |
| 882 | 879 | unsigned int sh_num = (info->read_mmr_reg.instance >> |
| 883 | 880 | AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & |
| 884 | 881 | AMDGPU_INFO_MMR_SH_INDEX_MASK; |
| 885 | − | |
| 886 | − if (!down_read_trylock(&adev->reset_domain->sem)) | |
| 887 | − return -ENOENT; | |
| 882 | + unsigned int alloc_size; | |
| 883 | + uint32_t *regs; | |
| 884 | + int ret; | |
| 888 | 885 | |
| 889 | 886 | /* set full masks if the userspace set all bits |
| 890 | 887 | * in the bitfields |
| 891 | 888 | */ |
| 892 | − if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { | |
| 889 | + if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) | |
| 893 | 890 | se_num = 0xffffffff; |
| 894 | − } else if (se_num >= AMDGPU_GFX_MAX_SE) { | |
| 895 | − ret = -EINVAL; | |
| 896 | − goto out; | |
| 897 | − } | |
| 891 | + else if (se_num >= AMDGPU_GFX_MAX_SE) | |
| 892 | + return -EINVAL; | |
| 898 | 893 | |
| 899 | − if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { | |
| 894 | + if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) | |
| 900 | 895 | sh_num = 0xffffffff; |
| 901 | − } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { | |
| 902 | − ret = -EINVAL; | |
| 903 | − goto out; | |
| 904 | − } | |
| 896 | + else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) | |
| 897 | + return -EINVAL; | |
| 905 | 898 | |
| 906 | − if (info->read_mmr_reg.count > 128) { | |
| 907 | − ret = -EINVAL; | |
| 908 | − goto out; | |
| 909 | − } | |
| 899 | + if (info->read_mmr_reg.count > 128) | |
| 900 | + return -EINVAL; | |
| 910 | 901 | |
| 911 | − regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); | |
| 912 | − if (!regs) { | |
| 913 | − ret = -ENOMEM; | |
| 914 | − goto out; | |
| 915 | − } | |
| 902 | + regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), | |
| 903 | + GFP_KERNEL); | |
| 904 | + if (!regs) | |
| 905 | + return -ENOMEM; | |
| 916 | 906 | |
| 907 | + down_read(&adev->reset_domain->sem); | |
| 917 | 908 | alloc_size = info->read_mmr_reg.count * sizeof(*regs); |
| 918 | − | |
| 919 | 909 | amdgpu_gfx_off_ctrl(adev, false); |
| 910 | + ret = 0; | |
| 920 | 911 | for (i = 0; i < info->read_mmr_reg.count; i++) { |
| 921 | 912 | if (amdgpu_asic_read_register(adev, se_num, sh_num, |
| 922 | 913 | info->read_mmr_reg.dword_offset + i, |
| 923 | 914 | ®s[i])) { |
| 924 | 915 | DRM_DEBUG_KMS("unallowed offset %#x\n", |
| 925 | 916 | info->read_mmr_reg.dword_offset + i); |
| 926 | − kfree(regs); | |
| 927 | − amdgpu_gfx_off_ctrl(adev, true); | |
| 928 | 917 | ret = -EFAULT; |
| 929 | − goto out; | |
| 918 | + break; | |
| 930 | 919 | } |
| 931 | 920 | } |
| 932 | 921 | amdgpu_gfx_off_ctrl(adev, true); |
| 933 | − n = copy_to_user(out, regs, min(size, alloc_size)); | |
| 934 | − kfree(regs); | |
| 935 | − ret = (n ? -EFAULT : 0); | |
| 936 | −out: | |
| 937 | 922 | up_read(&adev->reset_domain->sem); |
| 923 | + | |
| 924 | + if (!ret) { | |
| 925 | + ret = copy_to_user(out, regs, min(size, alloc_size)) | |
| 926 | + ? -EFAULT : 0; | |
| 927 | + } | |
| 928 | + kfree(regs); | |
| 938 | 929 | return ret; |
| 939 | 930 | } |
| 940 | 931 | case AMDGPU_INFO_DEV_INFO: { |
| @@ -1950,7 +1950,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev) · 1949 unmodified lines | ||
| 1950 | 1950 | if (!control || amdgpu_bad_page_threshold == 0) |
| 1951 | 1951 | return; |
| 1952 | 1952 | |
| 1953 | − if (control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) { | |
| 1953 | + if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) { | |
| 1954 | 1954 | if (amdgpu_dpm_send_rma_reason(adev)) |
| 1955 | 1955 | dev_warn(adev->dev, "Unable to send out-of-band RMA CPER"); |
| 1956 | 1956 | else |
| @@ -75,6 +75,9 @@ static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, · 74 unmodified lines | ||
| 75 | 75 | unsigned int type, |
| 76 | 76 | uint64_t size_in_page) |
| 77 | 77 | { |
| 78 | + if (!size_in_page) | |
| 79 | + return 0; | |
| 80 | + | |
| 78 | 81 | return ttm_range_man_init(&adev->mman.bdev, type, |
| 79 | 82 | false, size_in_page); |
| 80 | 83 | } |
| @@ -205,6 +205,19 @@ void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue) · 204 unmodified lines | ||
| 205 | 205 | msecs_to_jiffies(timeout_ms)); |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | +void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) | |
| 209 | +{ | |
| 210 | + struct xarray *xa = &adev->userq_doorbell_xa; | |
| 211 | + struct amdgpu_usermode_queue *queue; | |
| 212 | + unsigned long flags; | |
| 213 | + | |
| 214 | + xa_lock_irqsave(xa, flags); | |
| 215 | + queue = xa_load(xa, doorbell); | |
| 216 | + if (queue) | |
| 217 | + amdgpu_userq_fence_driver_process(queue->fence_drv); | |
| 218 | + xa_unlock_irqrestore(xa, flags); | |
| 219 | +} | |
| 220 | + | |
| 208 | 221 | static void amdgpu_userq_init_hang_detect_work(struct amdgpu_usermode_queue *queue) |
| 209 | 222 | { |
| 210 | 223 | INIT_DELAYED_WORK(&queue->hang_detect_work, amdgpu_userq_hang_detect_work); |
| @@ -643,12 +656,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que · 432 unmodified lines | ||
| 643 | 656 | #endif |
| 644 | 657 | amdgpu_userq_detect_and_reset_queues(uq_mgr); |
| 645 | 658 | r = amdgpu_userq_unmap_helper(queue); |
| 646 | − /*TODO: It requires a reset for userq hw unmap error*/ | |
| 647 | − if (r) { | |
| 648 | − drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n"); | |
| 649 | − queue->state = AMDGPU_USERQ_STATE_HUNG; | |
| 650 | − } | |
| 651 | − | |
| 652 | 659 | atomic_dec(&uq_mgr->userq_count[queue->queue_type]); |
| 653 | 660 | amdgpu_userq_cleanup(queue); |
| 654 | 661 | mutex_unlock(&uq_mgr->userq_mutex); |
| @@ -1187,7 +1194,7 @@ retry_lock: · 532 unmodified lines | ||
| 1187 | 1194 | bo = range->bo; |
| 1188 | 1195 | ret = amdgpu_ttm_tt_get_user_pages(bo, range); |
| 1189 | 1196 | if (ret) |
| 1190 | − goto unlock_all; | |
| 1197 | + goto free_ranges; | |
| 1191 | 1198 | } |
| 1192 | 1199 | |
| 1193 | 1200 | invalidated = true; |
| @@ -1214,6 +1221,7 @@ retry_lock: · 20 unmodified lines | ||
| 1214 | 1221 | |
| 1215 | 1222 | unlock_all: |
| 1216 | 1223 | drm_exec_fini(&exec); |
| 1224 | +free_ranges: | |
| 1217 | 1225 | xa_for_each(&xa, tmp_key, range) { |
| 1218 | 1226 | if (!range) |
| 1219 | 1227 | continue; |
| @@ -156,6 +156,7 @@ void amdgpu_userq_reset_work(struct work_struct *work); · 155 unmodified lines | ||
| 156 | 156 | void amdgpu_userq_pre_reset(struct amdgpu_device *adev); |
| 157 | 157 | int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost); |
| 158 | 158 | void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue); |
| 159 | +void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell); | |
| 159 | 160 | |
| 160 | 161 | int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, |
| 161 | 162 | struct amdgpu_usermode_queue *queue, |
| @@ -3023,11 +3023,22 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, · 3022 unmodified lines | ||
| 3023 | 3023 | |
| 3024 | 3024 | is_compute_context = vm->is_compute_context; |
| 3025 | 3025 | |
| 3026 | − if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid, | |
| 3027 | − node_id, addr >> PAGE_SHIFT, ts, write_fault)) { | |
| 3026 | + if (is_compute_context) { | |
| 3027 | + /* Unreserve root since svm_range_restore_pages might try to reserve it. */ | |
| 3028 | + /* TODO: rework svm_range_restore_pages so that this isn't necessary. */ | |
| 3028 | 3029 | amdgpu_bo_unreserve(root); |
| 3030 | + | |
| 3031 | + if (!svm_range_restore_pages(adev, pasid, vmid, | |
| 3032 | + node_id, addr >> PAGE_SHIFT, ts, write_fault)) { | |
| 3033 | + amdgpu_bo_unref(&root); | |
| 3034 | + return true; | |
| 3035 | + } | |
| 3029 | 3036 | amdgpu_bo_unref(&root); |
| 3030 | − return true; | |
| 3037 | + | |
| 3038 | + /* Re-acquire the VM lock, could be that the VM was freed in between. */ | |
| 3039 | + vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid); | |
| 3040 | + if (!vm) | |
| 3041 | + return false; | |
| 3031 | 3042 | } |
| 3032 | 3043 | |
| 3033 | 3044 | addr /= AMDGPU_GPU_PAGE_SIZE; |
| @@ -6523,15 +6523,7 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev, · 6522 unmodified lines | ||
| 6523 | 6523 | DRM_DEBUG("IH: CP EOP\n"); |
| 6524 | 6524 | |
| 6525 | 6525 | if (adev->enable_mes && doorbell_offset) { |
| 6526 | − struct amdgpu_usermode_queue *queue; | |
| 6527 | − struct xarray *xa = &adev->userq_doorbell_xa; | |
| 6528 | − unsigned long flags; | |
| 6529 | − | |
| 6530 | − xa_lock_irqsave(xa, flags); | |
| 6531 | − queue = xa_load(xa, doorbell_offset); | |
| 6532 | − if (queue) | |
| 6533 | − amdgpu_userq_fence_driver_process(queue->fence_drv); | |
| 6534 | − xa_unlock_irqrestore(xa, flags); | |
| 6526 | + amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 6535 | 6527 | } else { |
| 6536 | 6528 | me_id = (entry->ring_id & 0x0c) >> 2; |
| 6537 | 6529 | pipe_id = (entry->ring_id & 0x03) >> 0; |
| @@ -4854,15 +4854,7 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev, · 4853 unmodified lines | ||
| 4854 | 4854 | DRM_DEBUG("IH: CP EOP\n"); |
| 4855 | 4855 | |
| 4856 | 4856 | if (adev->enable_mes && doorbell_offset) { |
| 4857 | − struct xarray *xa = &adev->userq_doorbell_xa; | |
| 4858 | − struct amdgpu_usermode_queue *queue; | |
| 4859 | − unsigned long flags; | |
| 4860 | − | |
| 4861 | − xa_lock_irqsave(xa, flags); | |
| 4862 | − queue = xa_load(xa, doorbell_offset); | |
| 4863 | − if (queue) | |
| 4864 | − amdgpu_userq_fence_driver_process(queue->fence_drv); | |
| 4865 | − xa_unlock_irqrestore(xa, flags); | |
| 4857 | + amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 4866 | 4858 | } else { |
| 4867 | 4859 | me_id = (entry->ring_id & 0x0c) >> 2; |
| 4868 | 4860 | pipe_id = (entry->ring_id & 0x03) >> 0; |
| @@ -3643,16 +3643,7 @@ static int gfx_v12_1_eop_irq(struct amdgpu_device *adev, · 3642 unmodified lines | ||
| 3643 | 3643 | DRM_DEBUG("IH: CP EOP\n"); |
| 3644 | 3644 | |
| 3645 | 3645 | if (adev->enable_mes && doorbell_offset) { |
| 3646 | − struct xarray *xa = &adev->userq_doorbell_xa; | |
| 3647 | − struct amdgpu_usermode_queue *queue; | |
| 3648 | − unsigned long flags; | |
| 3649 | − | |
| 3650 | − xa_lock_irqsave(xa, flags); | |
| 3651 | − queue = xa_load(xa, doorbell_offset); | |
| 3652 | − if (queue) | |
| 3653 | − amdgpu_userq_fence_driver_process(queue->fence_drv); | |
| 3654 | − | |
| 3655 | − xa_unlock_irqrestore(xa, flags); | |
| 3646 | + amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 3656 | 3647 | } else { |
| 3657 | 3648 | me_id = (entry->ring_id & 0x0c) >> 2; |
| 3658 | 3649 | pipe_id = (entry->ring_id & 0x03) >> 0; |
| @@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) · 1570 unmodified lines | ||
| 1571 | 1571 | mutex_unlock(&adev->grbm_idx_mutex); |
| 1572 | 1572 | } |
| 1573 | 1573 | |
| 1574 | +/** | |
| 1575 | + * gfx_v6_0_setup_tcc() - setup which TCCs are used | |
| 1576 | + * | |
| 1577 | + * @adev: amdgpu_device pointer | |
| 1578 | + * | |
| 1579 | + * Verify whether the current GPU has any TCCs disabled, | |
| 1580 | + * which can happen when the GPU is harvested and some | |
| 1581 | + * memory channels are disabled, reducing the memory bus width. | |
| 1582 | + * For example, on the Radeon HD 7870 XT (Tahiti LE). | |
| 1583 | + * | |
| 1584 | + * If some TCCs are disabled, we need to make sure that | |
| 1585 | + * the disabled TCCs are not used, and the remaining TCCs | |
| 1586 | + * are used optimally. | |
| 1587 | + * | |
| 1588 | + * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. | |
| 1589 | + * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. | |
| 1590 | + * | |
| 1591 | + * For optimal performance: | |
| 1592 | + * - Rely on the CHAN_STEER from the golden registers table, | |
| 1593 | + * only skip disabled TCCs but keep the mapping order. | |
| 1594 | + * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, | |
| 1595 | + * which performs better than using the same TCC twice. | |
| 1596 | + */ | |
| 1597 | +static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) | |
| 1598 | +{ | |
| 1599 | + u32 i, tcc, tcp_addr_config, num_active_tcc = 0; | |
| 1600 | + u64 chan_steer, patched_chan_steer = 0; | |
| 1601 | + const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; | |
| 1602 | + const u32 dis_tcc_mask = | |
| 1603 | + amdgpu_gfx_create_bitmask(num_max_tcc) & | |
| 1604 | + (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), | |
| 1605 | + CGTS_TCC_DISABLE, TCC_DISABLE) | | |
| 1606 | + REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), | |
| 1607 | + CGTS_USER_TCC_DISABLE, TCC_DISABLE)); | |
| 1608 | + | |
| 1609 | + /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ | |
| 1610 | + if (!dis_tcc_mask) | |
| 1611 | + return; | |
| 1612 | + | |
| 1613 | + /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ | |
| 1614 | + chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); | |
| 1615 | + | |
| 1616 | + /* Patch the TCP to TCC mapping to skip disabled TCCs */ | |
| 1617 | + for (i = 0; i < num_max_tcc; ++i) { | |
| 1618 | + tcc = (chan_steer >> (u64)(4 * i)) & 0xf; | |
| 1619 | + | |
| 1620 | + if (!((1 << tcc) & dis_tcc_mask)) { | |
| 1621 | + /* Copy enabled TCC indices to the patched register value. */ | |
| 1622 | + patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); | |
| 1623 | + ++num_active_tcc; | |
| 1624 | + } | |
| 1625 | + } | |
| 1626 | + | |
| 1627 | + WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); | |
| 1628 | + | |
| 1629 | + /* Patch number of TCCs used by TCPs */ | |
| 1630 | + tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), | |
| 1631 | + TCP_ADDR_CONFIG, NUM_TCC_BANKS, | |
| 1632 | + num_active_tcc - 1); | |
| 1633 | + | |
| 1634 | + WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); | |
| 1635 | + WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); | |
| 1636 | + WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); | |
| 1637 | +} | |
| 1638 | + | |
| 1574 | 1639 | static void gfx_v6_0_config_init(struct amdgpu_device *adev) |
| 1575 | 1640 | { |
| 1576 | 1641 | adev->gfx.config.double_offchip_lds_buf = 0; |
| @@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) · 152 unmodified lines | ||
| 1729 | 1794 | gfx_v6_0_tiling_mode_table_init(adev); |
| 1730 | 1795 | |
| 1731 | 1796 | gfx_v6_0_setup_rb(adev); |
| 1797 | + gfx_v6_0_setup_tcc(adev); | |
| 1732 | 1798 | |
| 1733 | 1799 | gfx_v6_0_setup_spi(adev); |
| 1734 | 1800 | |
| @@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { · 801 unmodified lines | ||
| 802 | 802 | static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { |
| 803 | 803 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 804 | 804 | .align_mask = 0xf, |
| 805 | + .no_user_fence = true, | |
| 805 | 806 | .get_rptr = jpeg_v2_0_dec_ring_get_rptr, |
| 806 | 807 | .get_wptr = jpeg_v2_0_dec_ring_get_wptr, |
| 807 | 808 | .set_wptr = jpeg_v2_0_dec_ring_set_wptr, |
| @@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { · 692 unmodified lines | ||
| 693 | 693 | static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { |
| 694 | 694 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 695 | 695 | .align_mask = 0xf, |
| 696 | + .no_user_fence = true, | |
| 696 | 697 | .get_rptr = jpeg_v2_5_dec_ring_get_rptr, |
| 697 | 698 | .get_wptr = jpeg_v2_5_dec_ring_get_wptr, |
| 698 | 699 | .set_wptr = jpeg_v2_5_dec_ring_set_wptr, |
| @@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { · 25 unmodified lines | ||
| 724 | 725 | static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { |
| 725 | 726 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 726 | 727 | .align_mask = 0xf, |
| 728 | + .no_user_fence = true, | |
| 727 | 729 | .get_rptr = jpeg_v2_5_dec_ring_get_rptr, |
| 728 | 730 | .get_wptr = jpeg_v2_5_dec_ring_get_wptr, |
| 729 | 731 | .set_wptr = jpeg_v2_5_dec_ring_set_wptr, |
| @@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { · 593 unmodified lines | ||
| 594 | 594 | static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { |
| 595 | 595 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 596 | 596 | .align_mask = 0xf, |
| 597 | + .no_user_fence = true, | |
| 597 | 598 | .get_rptr = jpeg_v3_0_dec_ring_get_rptr, |
| 598 | 599 | .get_wptr = jpeg_v3_0_dec_ring_get_wptr, |
| 599 | 600 | .set_wptr = jpeg_v3_0_dec_ring_set_wptr, |
| @@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { · 758 unmodified lines | ||
| 759 | 759 | static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { |
| 760 | 760 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 761 | 761 | .align_mask = 0xf, |
| 762 | + .no_user_fence = true, | |
| 762 | 763 | .get_rptr = jpeg_v4_0_dec_ring_get_rptr, |
| 763 | 764 | .get_wptr = jpeg_v4_0_dec_ring_get_wptr, |
| 764 | 765 | .set_wptr = jpeg_v4_0_dec_ring_set_wptr, |
| @@ -1219,6 +1219,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { · 1218 unmodified lines | ||
| 1219 | 1219 | static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { |
| 1220 | 1220 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 1221 | 1221 | .align_mask = 0xf, |
| 1222 | + .no_user_fence = true, | |
| 1222 | 1223 | .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, |
| 1223 | 1224 | .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, |
| 1224 | 1225 | .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, |
| @@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = { · 803 unmodified lines | ||
| 804 | 804 | static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { |
| 805 | 805 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 806 | 806 | .align_mask = 0xf, |
| 807 | + .no_user_fence = true, | |
| 807 | 808 | .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, |
| 808 | 809 | .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, |
| 809 | 810 | .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr, |
| @@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = { · 679 unmodified lines | ||
| 680 | 680 | static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { |
| 681 | 681 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 682 | 682 | .align_mask = 0xf, |
| 683 | + .no_user_fence = true, | |
| 683 | 684 | .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, |
| 684 | 685 | .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, |
| 685 | 686 | .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr, |
| @@ -884,6 +884,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = { · 883 unmodified lines | ||
| 884 | 884 | static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { |
| 885 | 885 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 886 | 886 | .align_mask = 0xf, |
| 887 | + .no_user_fence = true, | |
| 887 | 888 | .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, |
| 888 | 889 | .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, |
| 889 | 890 | .set_wptr = jpeg_v5_0_1_dec_ring_set_wptr, |
| @@ -703,6 +703,7 @@ static const struct amd_ip_funcs jpeg_v5_0_2_ip_funcs = { · 702 unmodified lines | ||
| 703 | 703 | static const struct amdgpu_ring_funcs jpeg_v5_0_2_dec_ring_vm_funcs = { |
| 704 | 704 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 705 | 705 | .align_mask = 0xf, |
| 706 | + .no_user_fence = true, | |
| 706 | 707 | .get_rptr = jpeg_v5_0_2_dec_ring_get_rptr, |
| 707 | 708 | .get_wptr = jpeg_v5_0_2_dec_ring_get_wptr, |
| 708 | 709 | .set_wptr = jpeg_v5_0_2_dec_ring_set_wptr, |
| @@ -661,6 +661,7 @@ static const struct amd_ip_funcs jpeg_v5_3_0_ip_funcs = { · 660 unmodified lines | ||
| 661 | 661 | static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = { |
| 662 | 662 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 663 | 663 | .align_mask = 0xf, |
| 664 | + .no_user_fence = true, | |
| 664 | 665 | .get_rptr = jpeg_v5_3_0_dec_ring_get_rptr, |
| 665 | 666 | .get_wptr = jpeg_v5_3_0_dec_ring_get_wptr, |
| 666 | 667 | .set_wptr = jpeg_v5_3_0_dec_ring_set_wptr, |
| @@ -1662,17 +1662,8 @@ static int sdma_v6_0_process_fence_irq(struct amdgpu_device *adev, · 1661 unmodified lines | ||
| 1662 | 1662 | u32 doorbell_offset = entry->src_data[0]; |
| 1663 | 1663 | |
| 1664 | 1664 | if (adev->enable_mes && doorbell_offset) { |
| 1665 | − struct amdgpu_usermode_queue *queue; | |
| 1666 | − struct xarray *xa = &adev->userq_doorbell_xa; | |
| 1667 | − unsigned long flags; | |
| 1668 | − | |
| 1669 | 1665 | doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; |
| 1670 | − | |
| 1671 | − xa_lock_irqsave(xa, flags); | |
| 1672 | − queue = xa_load(xa, doorbell_offset); | |
| 1673 | − if (queue) | |
| 1674 | − amdgpu_userq_fence_driver_process(queue->fence_drv); | |
| 1675 | − xa_unlock_irqrestore(xa, flags); | |
| 1666 | + amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 1676 | 1667 | } |
| 1677 | 1668 | |
| 1678 | 1669 | return 0; |
| @@ -1594,17 +1594,8 @@ static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev, · 1593 unmodified lines | ||
| 1594 | 1594 | u32 doorbell_offset = entry->src_data[0]; |
| 1595 | 1595 | |
| 1596 | 1596 | if (adev->enable_mes && doorbell_offset) { |
| 1597 | − struct xarray *xa = &adev->userq_doorbell_xa; | |
| 1598 | − struct amdgpu_usermode_queue *queue; | |
| 1599 | − unsigned long flags; | |
| 1600 | − | |
| 1601 | 1597 | doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; |
| 1602 | − | |
| 1603 | − xa_lock_irqsave(xa, flags); | |
| 1604 | − queue = xa_load(xa, doorbell_offset); | |
| 1605 | − if (queue) | |
| 1606 | − amdgpu_userq_fence_driver_process(queue->fence_drv); | |
| 1607 | − xa_unlock_irqrestore(xa, flags); | |
| 1598 | + amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 1608 | 1599 | } |
| 1609 | 1600 | |
| 1610 | 1601 | return 0; |
| @@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) · 241 unmodified lines | ||
| 242 | 242 | uint64_t addr; |
| 243 | 243 | uint32_t size; |
| 244 | 244 | |
| 245 | + /* When the keyselect is already set, don't perturb it. */ | |
| 246 | + if (RREG32(mmUVD_FW_START)) | |
| 247 | + return; | |
| 248 | + | |
| 245 | 249 | /* program the VCPU memory controller bits 0-27 */ |
| 246 | 250 | addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; |
| 247 | 251 | size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; |
| @@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) · 36 unmodified lines | ||
| 284 | 288 | int i; |
| 285 | 289 | uint32_t keysel = adev->uvd.keyselect; |
| 286 | 290 | |
| 291 | + if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { | |
| 292 | + dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", | |
| 293 | + RREG32(mmUVD_FW_START), adev->uvd.keyselect); | |
| 294 | + return 0; | |
| 295 | + } | |
| 296 | + | |
| 287 | 297 | WREG32(mmUVD_FW_START, keysel); |
| 288 | 298 | |
| 289 | 299 | for (i = 0; i < 10; ++i) { |
| @@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { · 2112 unmodified lines | ||
| 2113 | 2113 | static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { |
| 2114 | 2114 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 2115 | 2115 | .align_mask = 0xf, |
| 2116 | + .no_user_fence = true, | |
| 2116 | 2117 | .secure_submission_supported = true, |
| 2117 | 2118 | .get_rptr = vcn_v2_0_dec_ring_get_rptr, |
| 2118 | 2119 | .get_wptr = vcn_v2_0_dec_ring_get_wptr, |
| @@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { · 26 unmodified lines | ||
| 2145 | 2146 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 2146 | 2147 | .align_mask = 0x3f, |
| 2147 | 2148 | .nop = VCN_ENC_CMD_NO_OP, |
| 2149 | + .no_user_fence = true, | |
| 2148 | 2150 | .get_rptr = vcn_v2_0_enc_ring_get_rptr, |
| 2149 | 2151 | .get_wptr = vcn_v2_0_enc_ring_get_wptr, |
| 2150 | 2152 | .set_wptr = vcn_v2_0_enc_ring_set_wptr, |
| @@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) · 1777 unmodified lines | ||
| 1778 | 1778 | static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { |
| 1779 | 1779 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 1780 | 1780 | .align_mask = 0xf, |
| 1781 | + .no_user_fence = true, | |
| 1781 | 1782 | .secure_submission_supported = true, |
| 1782 | 1783 | .get_rptr = vcn_v2_5_dec_ring_get_rptr, |
| 1783 | 1784 | .get_wptr = vcn_v2_5_dec_ring_get_wptr, |
| @@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { · 95 unmodified lines | ||
| 1879 | 1880 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1880 | 1881 | .align_mask = 0x3f, |
| 1881 | 1882 | .nop = VCN_ENC_CMD_NO_OP, |
| 1883 | + .no_user_fence = true, | |
| 1882 | 1884 | .get_rptr = vcn_v2_5_enc_ring_get_rptr, |
| 1883 | 1885 | .get_wptr = vcn_v2_5_enc_ring_get_wptr, |
| 1884 | 1886 | .set_wptr = vcn_v2_5_enc_ring_set_wptr, |
| @@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { · 1855 unmodified lines | ||
| 1856 | 1856 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 1857 | 1857 | .align_mask = 0x3f, |
| 1858 | 1858 | .nop = VCN_DEC_SW_CMD_NO_OP, |
| 1859 | + .no_user_fence = true, | |
| 1859 | 1860 | .secure_submission_supported = true, |
| 1860 | 1861 | .get_rptr = vcn_v3_0_dec_ring_get_rptr, |
| 1861 | 1862 | .get_wptr = vcn_v3_0_dec_ring_get_wptr, |
| @@ -1972,6 +1973,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, · 110 unmodified lines | ||
| 1972 | 1973 | |
| 1973 | 1974 | for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { |
| 1974 | 1975 | uint32_t offset, size, *create; |
| 1976 | + uint64_t buf_end; | |
| 1975 | 1977 | |
| 1976 | 1978 | if (msg[0] != RDECODE_MESSAGE_CREATE) |
| 1977 | 1979 | continue; |
| @@ -1979,7 +1981,8 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, · 1 unmodified line | ||
| 1979 | 1981 | offset = msg[1]; |
| 1980 | 1982 | size = msg[2]; |
| 1981 | 1983 | |
| 1982 | − if (size < 4 || offset + size > end - addr) { | |
| 1984 | + if (size < 4 || check_add_overflow(offset, size, &buf_end) || | |
| 1985 | + buf_end > end - addr) { | |
| 1983 | 1986 | DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); |
| 1984 | 1987 | r = -EINVAL; |
| 1985 | 1988 | goto out; |
| @@ -2036,6 +2039,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, · 50 unmodified lines | ||
| 2036 | 2039 | static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { |
| 2037 | 2040 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 2038 | 2041 | .align_mask = 0xf, |
| 2042 | + .no_user_fence = true, | |
| 2039 | 2043 | .secure_submission_supported = true, |
| 2040 | 2044 | .get_rptr = vcn_v3_0_dec_ring_get_rptr, |
| 2041 | 2045 | .get_wptr = vcn_v3_0_dec_ring_get_wptr, |
| @@ -2138,6 +2142,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { · 96 unmodified lines | ||
| 2138 | 2142 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 2139 | 2143 | .align_mask = 0x3f, |
| 2140 | 2144 | .nop = VCN_ENC_CMD_NO_OP, |
| 2145 | + .no_user_fence = true, | |
| 2141 | 2146 | .get_rptr = vcn_v3_0_enc_ring_get_rptr, |
| 2142 | 2147 | .get_wptr = vcn_v3_0_enc_ring_get_wptr, |
| 2143 | 2148 | .set_wptr = vcn_v3_0_enc_ring_set_wptr, |
| @@ -1889,6 +1889,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, · 1888 unmodified lines | ||
| 1889 | 1889 | |
| 1890 | 1890 | for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { |
| 1891 | 1891 | uint32_t offset, size, *create; |
| 1892 | + uint64_t buf_end; | |
| 1892 | 1893 | |
| 1893 | 1894 | if (msg[0] != RDECODE_MESSAGE_CREATE) |
| 1894 | 1895 | continue; |
| @@ -1896,7 +1897,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, · 1 unmodified line | ||
| 1896 | 1897 | offset = msg[1]; |
| 1897 | 1898 | size = msg[2]; |
| 1898 | 1899 | |
| 1899 | − if (size < 4 || offset + size > end - addr) { | |
| 1900 | + if (size < 4 || check_add_overflow(offset, size, &buf_end) || | |
| 1901 | + buf_end > end - addr) { | |
| 1900 | 1902 | DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); |
| 1901 | 1903 | r = -EINVAL; |
| 1902 | 1904 | goto out; |
| @@ -1994,6 +1996,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { · 91 unmodified lines | ||
| 1994 | 1996 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1995 | 1997 | .align_mask = 0x3f, |
| 1996 | 1998 | .nop = VCN_ENC_CMD_NO_OP, |
| 1999 | + .no_user_fence = true, | |
| 1997 | 2000 | .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), |
| 1998 | 2001 | .get_rptr = vcn_v4_0_unified_ring_get_rptr, |
| 1999 | 2002 | .get_wptr = vcn_v4_0_unified_ring_get_wptr, |
| @@ -1775,6 +1775,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { · 1774 unmodified lines | ||
| 1775 | 1775 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1776 | 1776 | .align_mask = 0x3f, |
| 1777 | 1777 | .nop = VCN_ENC_CMD_NO_OP, |
| 1778 | + .no_user_fence = true, | |
| 1778 | 1779 | .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, |
| 1779 | 1780 | .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, |
| 1780 | 1781 | .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, |
| @@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { · 1482 unmodified lines | ||
| 1483 | 1483 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1484 | 1484 | .align_mask = 0x3f, |
| 1485 | 1485 | .nop = VCN_ENC_CMD_NO_OP, |
| 1486 | + .no_user_fence = true, | |
| 1486 | 1487 | .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, |
| 1487 | 1488 | .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, |
| 1488 | 1489 | .set_wptr = vcn_v4_0_5_unified_ring_set_wptr, |
| @@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { · 1206 unmodified lines | ||
| 1207 | 1207 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1208 | 1208 | .align_mask = 0x3f, |
| 1209 | 1209 | .nop = VCN_ENC_CMD_NO_OP, |
| 1210 | + .no_user_fence = true, | |
| 1210 | 1211 | .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, |
| 1211 | 1212 | .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, |
| 1212 | 1213 | .set_wptr = vcn_v5_0_0_unified_ring_set_wptr, |
| @@ -1419,6 +1419,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = { · 1418 unmodified lines | ||
| 1419 | 1419 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1420 | 1420 | .align_mask = 0x3f, |
| 1421 | 1421 | .nop = VCN_ENC_CMD_NO_OP, |
| 1422 | + .no_user_fence = true, | |
| 1422 | 1423 | .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, |
| 1423 | 1424 | .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, |
| 1424 | 1425 | .set_wptr = vcn_v5_0_1_unified_ring_set_wptr, |
| @@ -994,6 +994,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_2_unified_ring_vm_funcs = { · 993 unmodified lines | ||
| 994 | 994 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 995 | 995 | .align_mask = 0x3f, |
| 996 | 996 | .nop = VCN_ENC_CMD_NO_OP, |
| 997 | + .no_user_fence = true, | |
| 997 | 998 | .get_rptr = vcn_v5_0_2_unified_ring_get_rptr, |
| 998 | 999 | .get_wptr = vcn_v5_0_2_unified_ring_get_wptr, |
| 999 | 1000 | .set_wptr = vcn_v5_0_2_unified_ring_set_wptr, |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/err.h> |
| 26 | 26 | #include <linux/fs.h> |
| 27 | 27 | #include <linux/file.h> |
| 28 | +#include <linux/overflow.h> | |
| 28 | 29 | #include <linux/sched.h> |
| 29 | 30 | #include <linux/slab.h> |
| 30 | 31 | #include <linux/uaccess.h> |
| @@ -1695,6 +1696,16 @@ static int kfd_ioctl_smi_events(struct file *filep, · 1664 unmodified lines | ||
| 1695 | 1696 | return kfd_smi_event_open(pdd->dev, &args->anon_fd); |
| 1696 | 1697 | } |
| 1697 | 1698 | |
| 1699 | +static int kfd_ioctl_svm_validate(void *kdata, unsigned int usize) | |
| 1700 | +{ | |
| 1701 | + struct kfd_ioctl_svm_args *args = kdata; | |
| 1702 | + size_t expected = struct_size(args, attrs, args->nattr); | |
| 1703 | + | |
| 1704 | + if (expected == SIZE_MAX || usize < expected) | |
| 1705 | + return -EINVAL; | |
| 1706 | + return 0; | |
| 1707 | +} | |
| 1708 | + | |
| 1698 | 1709 | #if IS_ENABLED(CONFIG_HSA_AMD_SVM) |
| 1699 | 1710 | |
| 1700 | 1711 | static int kfd_ioctl_set_xnack_mode(struct file *filep, |
| @@ -3209,7 +3220,11 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v · 1508 unmodified lines | ||
| 3209 | 3220 | |
| 3210 | 3221 | #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \ |
| 3211 | 3222 | [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \ |
| 3212 | − .cmd_drv = 0, .name = #ioctl} | |
| 3223 | + .validate = NULL, .cmd_drv = 0, .name = #ioctl} | |
| 3224 | + | |
| 3225 | +#define AMDKFD_IOCTL_DEF_V(ioctl, _func, _validate, _flags) \ | |
| 3226 | + [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \ | |
| 3227 | + .validate = _validate, .cmd_drv = 0, .name = #ioctl} | |
| 3213 | 3228 | |
| 3214 | 3229 | /** Ioctl table */ |
| 3215 | 3230 | static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { |
| @@ -3306,7 +3321,8 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { · 90 unmodified lines | ||
| 3306 | 3321 | AMDKFD_IOCTL_DEF(AMDKFD_IOC_SMI_EVENTS, |
| 3307 | 3322 | kfd_ioctl_smi_events, 0), |
| 3308 | 3323 | |
| 3309 | − AMDKFD_IOCTL_DEF(AMDKFD_IOC_SVM, kfd_ioctl_svm, 0), | |
| 3324 | + AMDKFD_IOCTL_DEF_V(AMDKFD_IOC_SVM, kfd_ioctl_svm, | |
| 3325 | + kfd_ioctl_svm_validate, 0), | |
| 3310 | 3326 | |
| 3311 | 3327 | AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_XNACK_MODE, |
| 3312 | 3328 | kfd_ioctl_set_xnack_mode, 0), |
| @@ -3431,6 +3447,12 @@ static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) · 118 unmodified lines | ||
| 3431 | 3447 | memset(kdata, 0, usize); |
| 3432 | 3448 | } |
| 3433 | 3449 | |
| 3450 | + if (ioctl->validate) { | |
| 3451 | + retcode = ioctl->validate(kdata, usize); | |
| 3452 | + if (retcode) | |
| 3453 | + goto err_i1; | |
| 3454 | + } | |
| 3455 | + | |
| 3434 | 3456 | retcode = func(filep, process, kdata); |
| 3435 | 3457 | |
| 3436 | 3458 | if (cmd & IOC_OUT) |
| @@ -1047,10 +1047,13 @@ extern struct srcu_struct kfd_processes_srcu; · 1046 unmodified lines | ||
| 1047 | 1047 | typedef int amdkfd_ioctl_t(struct file *filep, struct kfd_process *p, |
| 1048 | 1048 | void *data); |
| 1049 | 1049 | |
| 1050 | +typedef int amdkfd_ioctl_validate_t(void *kdata, unsigned int usize); | |
| 1051 | + | |
| 1050 | 1052 | struct amdkfd_ioctl_desc { |
| 1051 | 1053 | unsigned int cmd; |
| 1052 | 1054 | int flags; |
| 1053 | 1055 | amdkfd_ioctl_t *func; |
| 1056 | + amdkfd_ioctl_validate_t *validate; | |
| 1054 | 1057 | unsigned int cmd_drv; |
| 1055 | 1058 | const char *name; |
| 1056 | 1059 | }; |
| @@ -1366,6 +1366,12 @@ svm_range_unmap_from_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm, · 1365 unmodified lines | ||
| 1366 | 1366 | |
| 1367 | 1367 | pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last, |
| 1368 | 1368 | gpu_start, gpu_end); |
| 1369 | + | |
| 1370 | + if (!amdgpu_vm_ready(vm)) { | |
| 1371 | + pr_debug("VM not ready, canceling unmap\n"); | |
| 1372 | + return -EINVAL; | |
| 1373 | + } | |
| 1374 | + | |
| 1369 | 1375 | return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start, |
| 1370 | 1376 | gpu_end, init_pte_value, 0, 0, NULL, NULL, |
| 1371 | 1377 | fence); |
| @@ -1443,6 +1449,11 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, · 71 unmodified lines | ||
| 1443 | 1449 | pr_debug("svms 0x%p [0x%lx 0x%lx] readonly %d\n", prange->svms, |
| 1444 | 1450 | last_start, last_start + npages - 1, readonly); |
| 1445 | 1451 | |
| 1452 | + if (!amdgpu_vm_ready(vm)) { | |
| 1453 | + pr_debug("VM not ready, canceling map\n"); | |
| 1454 | + return -EINVAL; | |
| 1455 | + } | |
| 1456 | + | |
| 1446 | 1457 | for (i = offset; i < offset + npages; i++) { |
| 1447 | 1458 | uint64_t gpu_start; |
| 1448 | 1459 | uint64_t gpu_end; |
| @@ -1903,7 +1903,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) · 1902 unmodified lines | ||
| 1903 | 1903 | goto error; |
| 1904 | 1904 | } |
| 1905 | 1905 | |
| 1906 | − init_data.asic_id.chip_family = adev->family; | |
| 1906 | + /* special handling for early revisions of GC 11.5.4 */ | |
| 1907 | + if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4)) | |
| 1908 | + init_data.asic_id.chip_family = AMDGPU_FAMILY_GC_11_5_4; | |
| 1909 | + else | |
| 1910 | + init_data.asic_id.chip_family = adev->family; | |
| 1907 | 1911 | |
| 1908 | 1912 | init_data.asic_id.pci_revision_id = adev->pdev->revision; |
| 1909 | 1913 | init_data.asic_id.hw_internal_rev = adev->external_rev_id; |
| @@ -9404,9 +9408,21 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, · 7494 unmodified lines | ||
| 9404 | 9408 | if (acrtc_state) { |
| 9405 | 9409 | timing = &acrtc_state->stream->timing; |
| 9406 | 9410 | |
| 9407 | − if (amdgpu_ip_version(adev, DCE_HWIP, 0) < | |
| 9408 | − IP_VERSION(3, 5, 0) || | |
| 9409 | − !(adev->flags & AMD_IS_APU)) { | |
| 9411 | + if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= | |
| 9412 | + IP_VERSION(3, 2, 0) && | |
| 9413 | + !(adev->flags & AMD_IS_APU)) { | |
| 9414 | + /* | |
| 9415 | + * DGPUs NV3x and newer that support idle optimizations | |
| 9416 | + * experience intermittent flip-done timeouts on cursor | |
| 9417 | + * updates. Restore 5s offdelay behavior for now. | |
| 9418 | + * | |
| 9419 | + * Discussion on the issue: | |
| 9420 | + * https://lore.kernel.org/amd-gfx/20260217191632.1243826-1-sysdadmin@m1k.cloud/ | |
| 9421 | + */ | |
| 9422 | + config.offdelay_ms = 5000; | |
| 9423 | + config.disable_immediate = false; | |
| 9424 | + } else if (amdgpu_ip_version(adev, DCE_HWIP, 0) < | |
| 9425 | + IP_VERSION(3, 5, 0)) { | |
| 9410 | 9426 | /* |
| 9411 | 9427 | * Older HW and DGPU have issues with instant off; |
| 9412 | 9428 | * use a 2 frame offdelay. |
| @@ -1032,6 +1032,45 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector) · 1031 unmodified lines | ||
| 1032 | 1032 | return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector); |
| 1033 | 1033 | } |
| 1034 | 1034 | |
| 1035 | +static const struct drm_edid * | |
| 1036 | +dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_connector *aconnector) | |
| 1037 | +{ | |
| 1038 | + struct dc_bios *bios = link->ctx->dc_bios; | |
| 1039 | + struct embedded_panel_info info; | |
| 1040 | + const struct drm_edid *edid; | |
| 1041 | + enum bp_result r; | |
| 1042 | + | |
| 1043 | + if (!dc_is_embedded_signal(link->connector_signal) || | |
| 1044 | + !bios->funcs->get_embedded_panel_info) | |
| 1045 | + return NULL; | |
| 1046 | + | |
| 1047 | + memset(&info, 0, sizeof(info)); | |
| 1048 | + r = bios->funcs->get_embedded_panel_info(bios, &info); | |
| 1049 | + | |
| 1050 | + if (r != BP_RESULT_OK) { | |
| 1051 | + dm_error("Error when reading embedded panel info: %u\n", r); | |
| 1052 | + return NULL; | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + if (!info.fake_edid || !info.fake_edid_size) { | |
| 1056 | + dm_error("Embedded panel info doesn't contain an EDID\n"); | |
| 1057 | + return NULL; | |
| 1058 | + } | |
| 1059 | + | |
| 1060 | + edid = drm_edid_alloc(info.fake_edid, info.fake_edid_size); | |
| 1061 | + | |
| 1062 | + if (!drm_edid_valid(edid)) { | |
| 1063 | + dm_error("EDID from embedded panel info is invalid\n"); | |
| 1064 | + drm_edid_free(edid); | |
| 1065 | + return NULL; | |
| 1066 | + } | |
| 1067 | + | |
| 1068 | + aconnector->base.display_info.width_mm = info.panel_width_mm; | |
| 1069 | + aconnector->base.display_info.height_mm = info.panel_height_mm; | |
| 1070 | + | |
| 1071 | + return edid; | |
| 1072 | +} | |
| 1073 | + | |
| 1035 | 1074 | void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps) |
| 1036 | 1075 | { |
| 1037 | 1076 | edid_caps->scdc_present = hdmi->scdc.supported; |
| @@ -1052,6 +1091,9 @@ enum dc_edid_status dm_helpers_read_local_edid( · 14 unmodified lines | ||
| 1052 | 1091 | |
| 1053 | 1092 | if (link->aux_mode) |
| 1054 | 1093 | ddc = &aconnector->dm_dp_aux.aux.ddc; |
| 1094 | + else if (link->ddc_hw_inst == GPIO_DDC_LINE_UNKNOWN && | |
| 1095 | + dc_is_embedded_signal(link->connector_signal)) | |
| 1096 | + ddc = NULL; | |
| 1055 | 1097 | else |
| 1056 | 1098 | ddc = &aconnector->i2c->base; |
| 1057 | 1099 | |
| @@ -1065,6 +1107,8 @@ enum dc_edid_status dm_helpers_read_local_edid( · 7 unmodified lines | ||
| 1065 | 1107 | drm_edid = dm_helpers_read_acpi_edid(aconnector); |
| 1066 | 1108 | if (drm_edid) |
| 1067 | 1109 | drm_info(connector->dev, "Using ACPI provided EDID for %s\n", connector->name); |
| 1110 | + else if (!ddc) | |
| 1111 | + drm_edid = dm_helpers_read_vbios_hardcoded_edid(link, aconnector); | |
| 1068 | 1112 | else |
| 1069 | 1113 | drm_edid = drm_edid_read_ddc(connector, ddc); |
| 1070 | 1114 | drm_edid_connector_update(connector, drm_edid); |
| @@ -794,11 +794,13 @@ static enum bp_result bios_parser_external_encoder_control( · 793 unmodified lines | ||
| 794 | 794 | |
| 795 | 795 | static enum bp_result bios_parser_dac_load_detection( |
| 796 | 796 | struct dc_bios *dcb, |
| 797 | − enum engine_id engine_id) | |
| 797 | + enum engine_id engine_id, | |
| 798 | + struct graphics_object_id ext_enc_id) | |
| 798 | 799 | { |
| 799 | 800 | struct bios_parser *bp = BP_FROM_DCB(dcb); |
| 800 | 801 | struct dc_context *ctx = dcb->ctx; |
| 801 | 802 | struct bp_load_detection_parameters bp_params = {0}; |
| 803 | + struct bp_external_encoder_control ext_cntl = {0}; | |
| 802 | 804 | enum bp_result bp_result = BP_RESULT_UNSUPPORTED; |
| 803 | 805 | uint32_t bios_0_scratch; |
| 804 | 806 | uint32_t device_id_mask = 0; |
| @@ -824,6 +826,13 @@ static enum bp_result bios_parser_dac_load_detection( · 19 unmodified lines | ||
| 824 | 826 | |
| 825 | 827 | bp_params.engine_id = engine_id; |
| 826 | 828 | bp_result = bp->cmd_tbl.dac_load_detection(bp, &bp_params); |
| 829 | + } else if (ext_enc_id.id) { | |
| 830 | + if (!bp->cmd_tbl.external_encoder_control) | |
| 831 | + return BP_RESULT_UNSUPPORTED; | |
| 832 | + | |
| 833 | + ext_cntl.action = EXTERNAL_ENCODER_CONTROL_DAC_LOAD_DETECT; | |
| 834 | + ext_cntl.encoder_id = ext_enc_id; | |
| 835 | + bp_result = bp->cmd_tbl.external_encoder_control(bp, &ext_cntl); | |
| 827 | 836 | } |
| 828 | 837 | |
| 829 | 838 | if (bp_result != BP_RESULT_OK) |
| @@ -1304,6 +1313,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( · 474 unmodified lines | ||
| 1304 | 1313 | return BP_RESULT_FAILURE; |
| 1305 | 1314 | } |
| 1306 | 1315 | |
| 1316 | +static enum bp_result get_embedded_panel_extra_info( | |
| 1317 | + struct bios_parser *bp, | |
| 1318 | + struct embedded_panel_info *info, | |
| 1319 | + const uint32_t table_offset) | |
| 1320 | +{ | |
| 1321 | + uint8_t *record = bios_get_image(&bp->base, table_offset, 1); | |
| 1322 | + ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; | |
| 1323 | + ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; | |
| 1324 | + | |
| 1325 | + while (*record != ATOM_RECORD_END_TYPE) { | |
| 1326 | + switch (*record) { | |
| 1327 | + case LCD_MODE_PATCH_RECORD_MODE_TYPE: | |
| 1328 | + record += sizeof(ATOM_PATCH_RECORD_MODE); | |
| 1329 | + break; | |
| 1330 | + case LCD_RTS_RECORD_TYPE: | |
| 1331 | + record += sizeof(ATOM_LCD_RTS_RECORD); | |
| 1332 | + break; | |
| 1333 | + case LCD_CAP_RECORD_TYPE: | |
| 1334 | + record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); | |
| 1335 | + break; | |
| 1336 | + case LCD_FAKE_EDID_PATCH_RECORD_TYPE: | |
| 1337 | + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; | |
| 1338 | + if (fake_edid_record->ucFakeEDIDLength) { | |
| 1339 | + if (fake_edid_record->ucFakeEDIDLength == 128) | |
| 1340 | + info->fake_edid_size = | |
| 1341 | + fake_edid_record->ucFakeEDIDLength; | |
| 1342 | + else | |
| 1343 | + info->fake_edid_size = | |
| 1344 | + fake_edid_record->ucFakeEDIDLength * 128; | |
| 1345 | + | |
| 1346 | + info->fake_edid = fake_edid_record->ucFakeEDIDString; | |
| 1347 | + | |
| 1348 | + record += struct_size(fake_edid_record, | |
| 1349 | + ucFakeEDIDString, | |
| 1350 | + info->fake_edid_size); | |
| 1351 | + } else { | |
| 1352 | + /* empty fake edid record must be 3 bytes long */ | |
| 1353 | + record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; | |
| 1354 | + } | |
| 1355 | + break; | |
| 1356 | + case LCD_PANEL_RESOLUTION_RECORD_TYPE: | |
| 1357 | + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; | |
| 1358 | + info->panel_width_mm = panel_res_record->usHSize; | |
| 1359 | + info->panel_height_mm = panel_res_record->usVSize; | |
| 1360 | + record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); | |
| 1361 | + break; | |
| 1362 | + default: | |
| 1363 | + return BP_RESULT_BADBIOSTABLE; | |
| 1364 | + } | |
| 1365 | + } | |
| 1366 | + | |
| 1367 | + return BP_RESULT_OK; | |
| 1368 | +} | |
| 1369 | + | |
| 1307 | 1370 | static enum bp_result get_embedded_panel_info_v1_2( |
| 1308 | 1371 | struct bios_parser *bp, |
| 1309 | 1372 | struct embedded_panel_info *info) |
| @@ -1420,6 +1483,10 @@ static enum bp_result get_embedded_panel_info_v1_2( · 110 unmodified lines | ||
| 1420 | 1483 | if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) |
| 1421 | 1484 | info->lcd_timing.misc_info.API_ENABLED = true; |
| 1422 | 1485 | |
| 1486 | + if (lvds->usExtInfoTableOffset) | |
| 1487 | + return get_embedded_panel_extra_info(bp, info, | |
| 1488 | + le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); | |
| 1489 | + | |
| 1423 | 1490 | return BP_RESULT_OK; |
| 1424 | 1491 | } |
| 1425 | 1492 | |
| @@ -1545,6 +1612,10 @@ static enum bp_result get_embedded_panel_info_v1_3( · 119 unmodified lines | ||
| 1545 | 1612 | (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & |
| 1546 | 1613 | lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; |
| 1547 | 1614 | |
| 1615 | + if (lvds->usExtInfoTableOffset) | |
| 1616 | + return get_embedded_panel_extra_info(bp, info, | |
| 1617 | + le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); | |
| 1618 | + | |
| 1548 | 1619 | return BP_RESULT_OK; |
| 1549 | 1620 | } |
| 1550 | 1621 | |
| @@ -1682,7 +1682,7 @@ struct dc_scratch_space { · 1681 unmodified lines | ||
| 1682 | 1682 | struct dc_link_training_overrides preferred_training_settings; |
| 1683 | 1683 | struct dp_audio_test_data audio_test_data; |
| 1684 | 1684 | |
| 1685 | − uint8_t ddc_hw_inst; | |
| 1685 | + enum gpio_ddc_line ddc_hw_inst; | |
| 1686 | 1686 | |
| 1687 | 1687 | uint8_t hpd_src; |
| 1688 | 1688 | |
| @@ -102,7 +102,8 @@ struct dc_vbios_funcs { · 101 unmodified lines | ||
| 102 | 102 | struct bp_external_encoder_control *cntl); |
| 103 | 103 | enum bp_result (*dac_load_detection)( |
| 104 | 104 | struct dc_bios *bios, |
| 105 | − enum engine_id engine_id); | |
| 105 | + enum engine_id engine_id, | |
| 106 | + struct graphics_object_id ext_enc_id); | |
| 106 | 107 | enum bp_result (*transmitter_control)( |
| 107 | 108 | struct dc_bios *bios, |
| 108 | 109 | struct bp_transmitter_control *cntl); |
| @@ -1102,7 +1102,9 @@ void dce110_link_encoder_hw_init( · 1101 unmodified lines | ||
| 1102 | 1102 | ASSERT(result == BP_RESULT_OK); |
| 1103 | 1103 | |
| 1104 | 1104 | } |
| 1105 | − aux_initialize(enc110); | |
| 1105 | + | |
| 1106 | + if (enc110->aux_regs) | |
| 1107 | + aux_initialize(enc110); | |
| 1106 | 1108 | |
| 1107 | 1109 | /* reinitialize HPD. |
| 1108 | 1110 | * hpd_initialize() will pass DIG_FE id to HW context. |
| @@ -40,8 +40,8 @@ · 39 unmodified lines | ||
| 40 | 40 | #define FN(reg_name, field_name) \ |
| 41 | 41 | mcif_wb30->mcif_wb_shift->field_name, mcif_wb30->mcif_wb_mask->field_name |
| 42 | 42 | |
| 43 | −#define MCIF_ADDR(addr) (((unsigned long long)addr & 0xffffffffff) + 0xFE) >> 8 | |
| 44 | −#define MCIF_ADDR_HIGH(addr) (unsigned long long)addr >> 40 | |
| 43 | +#define MCIF_ADDR(addr) ((uint32_t)((((unsigned long long)(addr) & 0xffffffffffULL) + 0xFEULL) >> 8)) | |
| 44 | +#define MCIF_ADDR_HIGH(addr) ((uint32_t)(((unsigned long long)(addr)) >> 40)) | |
| 45 | 45 | |
| 46 | 46 | /* wbif programming guide: |
| 47 | 47 | * 1. set up wbif parameter: |
| @@ -646,6 +646,9 @@ failure: · 645 unmodified lines | ||
| 646 | 646 | enum gpio_ddc_line dal_ddc_get_line( |
| 647 | 647 | const struct ddc *ddc) |
| 648 | 648 | { |
| 649 | + if (!ddc) | |
| 650 | + return GPIO_DDC_LINE_UNKNOWN; | |
| 651 | + | |
| 649 | 652 | return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data); |
| 650 | 653 | } |
| 651 | 654 | |
| @@ -665,16 +665,45 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx) · 664 unmodified lines | ||
| 665 | 665 | } |
| 666 | 666 | |
| 667 | 667 | static void |
| 668 | −dce110_dac_encoder_control(struct pipe_ctx *pipe_ctx, bool enable) | |
| 668 | +dce110_external_encoder_control(enum bp_external_encoder_control_action action, | |
| 669 | + struct dc_link *link, | |
| 670 | + struct dc_crtc_timing *timing) | |
| 669 | 671 | { |
| 670 | − struct dc_link *link = pipe_ctx->stream->link; | |
| 672 | + struct dc *dc = link->ctx->dc; | |
| 671 | 673 | struct dc_bios *bios = link->ctx->dc_bios; |
| 672 | − struct bp_encoder_control encoder_control = {0}; | |
| 674 | + const struct dc_link_settings *link_settings = &link->cur_link_settings; | |
| 675 | + enum bp_result bp_result = BP_RESULT_OK; | |
| 676 | + struct bp_external_encoder_control ext_cntl = { | |
| 677 | + .action = action, | |
| 678 | + .connector_obj_id = link->link_enc->connector, | |
| 679 | + .encoder_id = link->ext_enc_id, | |
| 680 | + .lanes_number = link_settings->lane_count, | |
| 681 | + .link_rate = link_settings->link_rate, | |
| 682 | + | |
| 683 | + /* Use signal type of the real link encoder, ie. DP */ | |
| 684 | + .signal = link->connector_signal, | |
| 685 | + | |
| 686 | + /* We don't know the timing yet when executing the SETUP action, | |
| 687 | + * so use a reasonably high default value. It seems that ENABLE | |
| 688 | + * can change the actual pixel clock but doesn't work with higher | |
| 689 | + * pixel clocks than what SETUP was called with. | |
| 690 | + */ | |
| 691 | + .pixel_clock = timing ? timing->pix_clk_100hz / 10 : 300000, | |
| 692 | + .color_depth = timing ? timing->display_color_depth : COLOR_DEPTH_888, | |
| 693 | + }; | |
| 694 | + DC_LOGGER_INIT(dc->ctx); | |
| 673 | 695 | |
| 674 | − encoder_control.action = enable ? ENCODER_CONTROL_ENABLE : ENCODER_CONTROL_DISABLE; | |
| 675 | − encoder_control.engine_id = link->link_enc->analog_engine; | |
| 676 | − encoder_control.pixel_clock = pipe_ctx->stream->timing.pix_clk_100hz / 10; | |
| 677 | − bios->funcs->encoder_control(bios, &encoder_control); | |
| 696 | + bp_result = bios->funcs->external_encoder_control(bios, &ext_cntl); | |
| 697 | + | |
| 698 | + if (bp_result != BP_RESULT_OK) | |
| 699 | + DC_LOG_ERROR("Failed to execute external encoder action: 0x%x\n", action); | |
| 700 | +} | |
| 701 | + | |
| 702 | +static void | |
| 703 | +dce110_prepare_ddc(struct dc_link *link) | |
| 704 | +{ | |
| 705 | + if (link->ext_enc_id.id) | |
| 706 | + dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_DDC_SETUP, link, NULL); | |
| 678 | 707 | } |
| 679 | 708 | |
| 680 | 709 | static bool |
| @@ -684,7 +713,8 @@ dce110_dac_load_detect(struct dc_link *link) · 3 unmodified lines | ||
| 684 | 713 | struct link_encoder *link_enc = link->link_enc; |
| 685 | 714 | enum bp_result bp_result; |
| 686 | 715 | |
| 687 | − bp_result = bios->funcs->dac_load_detection(bios, link_enc->analog_engine); | |
| 716 | + bp_result = bios->funcs->dac_load_detection( | |
| 717 | + bios, link_enc->analog_engine, link->ext_enc_id); | |
| 688 | 718 | return bp_result == BP_RESULT_OK; |
| 689 | 719 | } |
| 690 | 720 | |
| @@ -700,7 +730,6 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) · 9 unmodified lines | ||
| 700 | 730 | uint32_t early_control = 0; |
| 701 | 731 | struct timing_generator *tg = pipe_ctx->stream_res.tg; |
| 702 | 732 | |
| 703 | − link_hwss->setup_stream_attribute(pipe_ctx); | |
| 704 | 733 | link_hwss->setup_stream_encoder(pipe_ctx); |
| 705 | 734 | |
| 706 | 735 | dc->hwss.update_info_frame(pipe_ctx); |
| @@ -719,8 +748,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) · 12 unmodified lines | ||
| 719 | 748 | |
| 720 | 749 | tg->funcs->set_early_control(tg, early_control); |
| 721 | 750 | |
| 722 | − if (dc_is_rgb_signal(pipe_ctx->stream->signal)) | |
| 723 | − dce110_dac_encoder_control(pipe_ctx, true); | |
| 751 | + if (link->ext_enc_id.id) | |
| 752 | + dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_ENABLE, link, timing); | |
| 724 | 753 | } |
| 725 | 754 | |
| 726 | 755 | static enum bp_result link_transmitter_control( |
| @@ -1219,8 +1248,8 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) · 492 unmodified lines | ||
| 1219 | 1248 | link_enc->transmitter - TRANSMITTER_UNIPHY_A); |
| 1220 | 1249 | } |
| 1221 | 1250 | |
| 1222 | − if (dc_is_rgb_signal(pipe_ctx->stream->signal)) | |
| 1223 | − dce110_dac_encoder_control(pipe_ctx, false); | |
| 1251 | + if (link->ext_enc_id.id) | |
| 1252 | + dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_DISABLE, link, NULL); | |
| 1224 | 1253 | } |
| 1225 | 1254 | |
| 1226 | 1255 | void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, |
| @@ -1603,22 +1632,6 @@ static enum dc_status dce110_enable_stream_timing( · 376 unmodified lines | ||
| 1603 | 1632 | |
| 1604 | 1633 | return DC_OK; |
| 1605 | 1634 | } |
| 1606 | −static void | |
| 1607 | −dce110_select_crtc_source(struct pipe_ctx *pipe_ctx) | |
| 1608 | −{ | |
| 1609 | − struct dc_link *link = pipe_ctx->stream->link; | |
| 1610 | − struct dc_bios *bios = link->ctx->dc_bios; | |
| 1611 | − struct bp_crtc_source_select crtc_source_select = {0}; | |
| 1612 | − enum engine_id engine_id = link->link_enc->preferred_engine; | |
| 1613 | − | |
| 1614 | − if (dc_is_rgb_signal(pipe_ctx->stream->signal)) | |
| 1615 | − engine_id = link->link_enc->analog_engine; | |
| 1616 | − crtc_source_select.controller_id = CONTROLLER_ID_D0 + pipe_ctx->stream_res.tg->inst; | |
| 1617 | − crtc_source_select.color_depth = pipe_ctx->stream->timing.display_color_depth; | |
| 1618 | − crtc_source_select.engine_id = engine_id; | |
| 1619 | − crtc_source_select.sink_signal = pipe_ctx->stream->signal; | |
| 1620 | − bios->funcs->select_crtc_source(bios, &crtc_source_select); | |
| 1621 | −} | |
| 1622 | 1635 | |
| 1623 | 1636 | enum dc_status dce110_apply_single_controller_ctx_to_hw( |
| 1624 | 1637 | struct pipe_ctx *pipe_ctx, |
| @@ -1639,10 +1652,6 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw( · 14 unmodified lines | ||
| 1639 | 1652 | hws->funcs.disable_stream_gating(dc, pipe_ctx); |
| 1640 | 1653 | } |
| 1641 | 1654 | |
| 1642 | − if (pipe_ctx->stream->signal == SIGNAL_TYPE_RGB) { | |
| 1643 | − dce110_select_crtc_source(pipe_ctx); | |
| 1644 | − } | |
| 1645 | − | |
| 1646 | 1655 | if (pipe_ctx->stream_res.audio != NULL) { |
| 1647 | 1656 | struct audio_output audio_output = {0}; |
| 1648 | 1657 | |
| @@ -1722,8 +1731,7 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw( · 73 unmodified lines | ||
| 1722 | 1731 | pipe_ctx->stream_res.tg->funcs->set_static_screen_control( |
| 1723 | 1732 | pipe_ctx->stream_res.tg, event_triggers, 2); |
| 1724 | 1733 | |
| 1725 | − if (!dc_is_virtual_signal(pipe_ctx->stream->signal) && | |
| 1726 | − !dc_is_rgb_signal(pipe_ctx->stream->signal)) | |
| 1734 | + if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) | |
| 1727 | 1735 | pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( |
| 1728 | 1736 | pipe_ctx->stream_res.stream_enc, |
| 1729 | 1737 | pipe_ctx->stream_res.tg->inst); |
| @@ -3376,6 +3384,15 @@ void dce110_enable_tmds_link_output(struct dc_link *link, · 1646 unmodified lines | ||
| 3376 | 3384 | link->phy_state.symclk_state = SYMCLK_ON_TX_ON; |
| 3377 | 3385 | } |
| 3378 | 3386 | |
| 3387 | +static void dce110_enable_analog_link_output( | |
| 3388 | + struct dc_link *link, | |
| 3389 | + uint32_t pix_clk_100hz) | |
| 3390 | +{ | |
| 3391 | + link->link_enc->funcs->enable_analog_output( | |
| 3392 | + link->link_enc, | |
| 3393 | + pix_clk_100hz); | |
| 3394 | +} | |
| 3395 | + | |
| 3379 | 3396 | void dce110_enable_dp_link_output( |
| 3380 | 3397 | struct dc_link *link, |
| 3381 | 3398 | const struct link_resource *link_res, |
| @@ -3423,6 +3440,11 @@ void dce110_enable_dp_link_output( · 41 unmodified lines | ||
| 3423 | 3440 | } |
| 3424 | 3441 | } |
| 3425 | 3442 | |
| 3443 | + if (link->ext_enc_id.id) { | |
| 3444 | + dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_INIT, link, NULL); | |
| 3445 | + dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_SETUP, link, NULL); | |
| 3446 | + } | |
| 3447 | + | |
| 3426 | 3448 | if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) { |
| 3427 | 3449 | if (dc->clk_mgr->funcs->notify_link_rate_change) |
| 3428 | 3450 | dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); |
| @@ -3513,8 +3535,10 @@ static const struct hw_sequencer_funcs dce110_funcs = { · 84 unmodified lines | ||
| 3513 | 3535 | .enable_lvds_link_output = dce110_enable_lvds_link_output, |
| 3514 | 3536 | .enable_tmds_link_output = dce110_enable_tmds_link_output, |
| 3515 | 3537 | .enable_dp_link_output = dce110_enable_dp_link_output, |
| 3538 | + .enable_analog_link_output = dce110_enable_analog_link_output, | |
| 3516 | 3539 | .disable_link_output = dce110_disable_link_output, |
| 3517 | 3540 | .dac_load_detect = dce110_dac_load_detect, |
| 3541 | + .prepare_ddc = dce110_prepare_ddc, | |
| 3518 | 3542 | }; |
| 3519 | 3543 | |
| 3520 | 3544 | static const struct hwseq_private_funcs dce110_private_funcs = { |
| @@ -568,7 +568,9 @@ static bool construct_phy(struct dc_link *link, · 567 unmodified lines | ||
| 568 | 568 | goto ddc_create_fail; |
| 569 | 569 | } |
| 570 | 570 | |
| 571 | − if (!link->ddc->ddc_pin) { | |
| 571 | + /* Embedded display connectors such as LVDS may not have DDC. */ | |
| 572 | + if (!link->ddc->ddc_pin && | |
| 573 | + !dc_is_embedded_signal(link->connector_signal)) { | |
| 572 | 574 | DC_ERROR("Failed to get I2C info for connector!\n"); |
| 573 | 575 | goto ddc_create_fail; |
| 574 | 576 | } |
| @@ -753,7 +753,8 @@ static struct link_encoder *dce60_link_encoder_create( · 752 unmodified lines | ||
| 753 | 753 | enc_init_data, |
| 754 | 754 | &link_enc_feature, |
| 755 | 755 | &link_enc_regs[link_regs_id], |
| 756 | − &link_enc_aux_regs[enc_init_data->channel - 1], | |
| 756 | + enc_init_data->channel == CHANNEL_ID_UNKNOWN ? | |
| 757 | + NULL : &link_enc_aux_regs[enc_init_data->channel - 1], | |
| 757 | 758 | enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? |
| 758 | 759 | NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); |
| 759 | 760 | return &enc110->base; |
| @@ -760,7 +760,8 @@ static struct link_encoder *dce80_link_encoder_create( · 759 unmodified lines | ||
| 760 | 760 | enc_init_data, |
| 761 | 761 | &link_enc_feature, |
| 762 | 762 | &link_enc_regs[link_regs_id], |
| 763 | − &link_enc_aux_regs[enc_init_data->channel - 1], | |
| 763 | + enc_init_data->channel == CHANNEL_ID_UNKNOWN ? | |
| 764 | + NULL : &link_enc_aux_regs[enc_init_data->channel - 1], | |
| 764 | 765 | enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? |
| 765 | 766 | NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); |
| 766 | 767 | return &enc110->base; |
| @@ -153,6 +153,10 @@ struct embedded_panel_info { · 152 unmodified lines | ||
| 153 | 153 | uint32_t drr_enabled; |
| 154 | 154 | uint32_t min_drr_refresh_rate; |
| 155 | 155 | bool realtek_eDPToLVDS; |
| 156 | + uint16_t panel_width_mm; | |
| 157 | + uint16_t panel_height_mm; | |
| 158 | + uint16_t fake_edid_size; | |
| 159 | + const uint8_t *fake_edid; | |
| 156 | 160 | }; |
| 157 | 161 | |
| 158 | 162 | struct dc_firmware_info { |
| @@ -425,6 +425,7 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) · 424 unmodified lines | ||
| 425 | 425 | dpm_table->dpm_levels[0].enabled = true; |
| 426 | 426 | dpm_table->dpm_levels[1].value = pptable->GfxclkFmax; |
| 427 | 427 | dpm_table->dpm_levels[1].enabled = true; |
| 428 | + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; | |
| 428 | 429 | } else { |
| 429 | 430 | dpm_table->count = 1; |
| 430 | 431 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; |
| @@ -1129,6 +1129,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu) · 1128 unmodified lines | ||
| 1129 | 1129 | /* gfxclk dpm table setup */ |
| 1130 | 1130 | dpm_table = &dpm_context->dpm_tables.gfx_table; |
| 1131 | 1131 | dpm_table->clk_type = SMU_GFXCLK; |
| 1132 | + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; | |
| 1132 | 1133 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { |
| 1133 | 1134 | /* In the case of gfxclk, only fine-grained dpm is honored. |
| 1134 | 1135 | * Get min/max values from FW. |
| @@ -1370,7 +1370,7 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, · 1369 unmodified lines | ||
| 1370 | 1370 | level_index = 1; |
| 1371 | 1371 | } |
| 1372 | 1372 | |
| 1373 | − if (!is_fine_grained) { | |
| 1373 | + if (!is_fine_grained || count == 1) { | |
| 1374 | 1374 | for (i = 0; i < count; i++) { |
| 1375 | 1375 | freq_match = !is_deep_sleep && |
| 1376 | 1376 | smu_cmn_freqs_match( |
| @@ -831,7 +831,7 @@ static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b, · 830 unmodified lines | ||
| 831 | 831 | } |
| 832 | 832 | |
| 833 | 833 | /** |
| 834 | − * drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats | |
| 834 | + * drm_crtc_fill_palette_332 - Programs a default palette for RGB332-like formats | |
| 835 | 835 | * @crtc: The displaying CRTC |
| 836 | 836 | * @set_palette: Callback for programming the hardware gamma LUT |
| 837 | 837 | * |
| @@ -172,8 +172,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, · 171 unmodified lines | ||
| 172 | 172 | } |
| 173 | 173 | |
| 174 | 174 | for (i = 0; i < info->num_planes; i++) { |
| 175 | − unsigned int width = mode_cmd->width / (i ? info->hsub : 1); | |
| 176 | − unsigned int height = mode_cmd->height / (i ? info->vsub : 1); | |
| 175 | + unsigned int width = drm_format_info_plane_width(info, mode_cmd->width, i); | |
| 176 | + unsigned int height = drm_format_info_plane_height(info, mode_cmd->height, i); | |
| 177 | 177 | unsigned int min_size; |
| 178 | 178 | |
| 179 | 179 | objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); |
| @@ -558,6 +558,6 @@ pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) · 557 unmodified lines | ||
| 558 | 558 | &pvr_fw_trace_fops); |
| 559 | 559 | } |
| 560 | 560 | |
| 561 | − debugfs_create_file("trace_mask", 0600, dir, fw_trace, | |
| 561 | + debugfs_create_file("trace_mask", 0600, dir, pvr_dev, | |
| 562 | 562 | &pvr_fw_trace_mask_fops); |
| 563 | 563 | } |
| @@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data) · 349 unmodified lines | ||
| 350 | 350 | struct pci_dev *pcidev = data; |
| 351 | 351 | |
| 352 | 352 | pci_disable_device(pcidev); |
| 353 | + pci_dev_put(pcidev); | |
| 353 | 354 | } |
| 354 | 355 | |
| 355 | 356 | static int ofdrm_device_init_pci(struct ofdrm_device *odev) |
| @@ -375,6 +376,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev) · 19 unmodified lines | ||
| 375 | 376 | if (ret) { |
| 376 | 377 | drm_err(dev, "pci_enable_device(%s) failed: %d\n", |
| 377 | 378 | dev_name(&pcidev->dev), ret); |
| 379 | + pci_dev_put(pcidev); | |
| 378 | 380 | return ret; |
| 379 | 381 | } |
| 380 | 382 | ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); |
| @@ -353,7 +353,7 @@ static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, · 352 unmodified lines | ||
| 353 | 353 | frames_size + |
| 354 | 354 | sizeof(struct appletbdrm_fb_request_footer), 16); |
| 355 | 355 | |
| 356 | − appletbdrm_state->request = kzalloc(request_size, GFP_KERNEL); | |
| 356 | + appletbdrm_state->request = kvzalloc(request_size, GFP_KERNEL); | |
| 357 | 357 | |
| 358 | 358 | if (!appletbdrm_state->request) |
| 359 | 359 | return -ENOMEM; |
| @@ -543,7 +543,7 @@ static void appletbdrm_primary_plane_destroy_state(struct drm_plane *plane, · 183 unmodified lines | ||
| 543 | 543 | { |
| 544 | 544 | struct appletbdrm_plane_state *appletbdrm_state = to_appletbdrm_plane_state(state); |
| 545 | 545 | |
| 546 | − kfree(appletbdrm_state->request); | |
| 546 | + kvfree(appletbdrm_state->request); | |
| 547 | 547 | kfree(appletbdrm_state->response); |
| 548 | 548 | |
| 549 | 549 | __drm_gem_destroy_shadow_plane_state(&appletbdrm_state->base); |
| @@ -285,13 +285,12 @@ static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout) · 284 unmodified lines | ||
| 285 | 285 | return unode->urb; |
| 286 | 286 | } |
| 287 | 287 | |
| 288 | −#define GET_URB_TIMEOUT HZ | |
| 289 | 288 | struct urb *udl_get_urb(struct udl_device *udl) |
| 290 | 289 | { |
| 291 | 290 | struct urb *urb; |
| 292 | 291 | |
| 293 | 292 | spin_lock_irq(&udl->urbs.lock); |
| 294 | − urb = udl_get_urb_locked(udl, GET_URB_TIMEOUT); | |
| 293 | + urb = udl_get_urb_locked(udl, HZ * 2); | |
| 295 | 294 | spin_unlock_irq(&udl->urbs.lock); |
| 296 | 295 | return urb; |
| 297 | 296 | } |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <drm/drm_gem_framebuffer_helper.h> |
| 22 | 22 | #include <drm/drm_gem_shmem_helper.h> |
| 23 | 23 | #include <drm/drm_modeset_helper_vtables.h> |
| 24 | +#include <drm/drm_print.h> | |
| 24 | 25 | #include <drm/drm_probe_helper.h> |
| 25 | 26 | #include <drm/drm_vblank.h> |
| 26 | 27 | |
| @@ -342,8 +343,10 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom · 315 unmodified lines | ||
| 342 | 343 | return; |
| 343 | 344 | |
| 344 | 345 | urb = udl_get_urb(udl); |
| 345 | − if (!urb) | |
| 346 | + if (!urb) { | |
| 347 | + drm_err_ratelimited(dev, "get urb failed when enabling crtc\n"); | |
| 346 | 348 | goto out; |
| 349 | + } | |
| 347 | 350 | |
| 348 | 351 | buf = (char *)urb->transfer_buffer; |
| 349 | 352 | buf = udl_vidreg_lock(buf); |
| @@ -88,6 +88,7 @@ xe-y += xe_bb.o \ · 87 unmodified lines | ||
| 88 | 88 | xe_irq.o \ |
| 89 | 89 | xe_late_bind_fw.o \ |
| 90 | 90 | xe_lrc.o \ |
| 91 | + xe_mem_pool.o \ | |
| 91 | 92 | xe_migrate.o \ |
| 92 | 93 | xe_mmio.o \ |
| 93 | 94 | xe_mmio_gem.o \ |
| @@ -583,7 +583,7 @@ · 582 unmodified lines | ||
| 583 | 583 | #define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32) |
| 584 | 584 | #define LSCFE_SAME_ADDRESS_ATOMICS_COALESCING_DISABLE REG_BIT(35 - 32) |
| 585 | 585 | |
| 586 | −#define ROW_CHICKEN5 XE_REG_MCR(0xe7f0) | |
| 586 | +#define ROW_CHICKEN5 XE_REG_MCR(0xe7f0, XE_REG_OPTION_MASKED) | |
| 587 | 587 | #define CPSS_AWARE_DIS REG_BIT(3) |
| 588 | 588 | |
| 589 | 589 | #define SARB_CHICKEN1 XE_REG_MCR(0xe90c) |
| @@ -2322,8 +2322,10 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo, · 2321 unmodified lines | ||
| 2322 | 2322 | } |
| 2323 | 2323 | |
| 2324 | 2324 | /* XE_BO_FLAG_GGTTx requires XE_BO_FLAG_GGTT also be set */ |
| 2325 | − if ((flags & XE_BO_FLAG_GGTT_ALL) && !(flags & XE_BO_FLAG_GGTT)) | |
| 2325 | + if ((flags & XE_BO_FLAG_GGTT_ALL) && !(flags & XE_BO_FLAG_GGTT)) { | |
| 2326 | + xe_bo_free(bo); | |
| 2326 | 2327 | return ERR_PTR(-EINVAL); |
| 2328 | + } | |
| 2327 | 2329 | |
| 2328 | 2330 | if (flags & (XE_BO_FLAG_VRAM_MASK | XE_BO_FLAG_STOLEN) && |
| 2329 | 2331 | !(flags & XE_BO_FLAG_IGNORE_MIN_PAGE_SIZE) && |
| @@ -2342,8 +2344,10 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo, · 12 unmodified lines | ||
| 2342 | 2344 | alignment = SZ_4K >> PAGE_SHIFT; |
| 2343 | 2345 | } |
| 2344 | 2346 | |
| 2345 | − if (type == ttm_bo_type_device && aligned_size != size) | |
| 2347 | + if (type == ttm_bo_type_device && aligned_size != size) { | |
| 2348 | + xe_bo_free(bo); | |
| 2346 | 2349 | return ERR_PTR(-EINVAL); |
| 2350 | + } | |
| 2347 | 2351 | |
| 2348 | 2352 | if (!bo) { |
| 2349 | 2353 | bo = xe_bo_alloc(); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include "xe_ggtt_types.h" |
| 19 | 19 | |
| 20 | 20 | struct xe_device; |
| 21 | +struct xe_mem_pool_node; | |
| 21 | 22 | struct xe_vm; |
| 22 | 23 | |
| 23 | 24 | #define XE_BO_MAX_PLACEMENTS 3 |
| @@ -88,7 +89,7 @@ struct xe_bo { · 64 unmodified lines | ||
| 88 | 89 | bool ccs_cleared; |
| 89 | 90 | |
| 90 | 91 | /** @bb_ccs: BB instructions of CCS read/write. Valid only for VF */ |
| 91 | − struct xe_bb *bb_ccs[XE_SRIOV_VF_CCS_CTX_COUNT]; | |
| 92 | + struct xe_mem_pool_node *bb_ccs[XE_SRIOV_VF_CCS_CTX_COUNT]; | |
| 92 | 93 | |
| 93 | 94 | /** |
| 94 | 95 | * @cpu_caching: CPU caching mode. Currently only used for userspace |
| @@ -258,6 +258,13 @@ out_unlock: · 257 unmodified lines | ||
| 258 | 258 | return ERR_PTR(ret); |
| 259 | 259 | } |
| 260 | 260 | |
| 261 | +/* | |
| 262 | + * Takes ownership of @storage: on success it is transferred to the returned | |
| 263 | + * drm_gem_object; on failure it is freed before returning the error. | |
| 264 | + * This matches the contract of xe_bo_init_locked() which frees @storage on | |
| 265 | + * its error paths, so callers need not (and must not) free @storage after | |
| 266 | + * this call. | |
| 267 | + */ | |
| 261 | 268 | static struct drm_gem_object * |
| 262 | 269 | xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, |
| 263 | 270 | struct dma_buf *dma_buf) |
| @@ -271,8 +278,10 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, · 7 unmodified lines | ||
| 271 | 278 | int ret = 0; |
| 272 | 279 | |
| 273 | 280 | dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm); |
| 274 | − if (!dummy_obj) | |
| 281 | + if (!dummy_obj) { | |
| 282 | + xe_bo_free(storage); | |
| 275 | 283 | return ERR_PTR(-ENOMEM); |
| 284 | + } | |
| 276 | 285 | |
| 277 | 286 | dummy_obj->resv = resv; |
| 278 | 287 | xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, ret) { |
| @@ -281,6 +290,7 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, · 2 unmodified lines | ||
| 281 | 290 | if (ret) |
| 282 | 291 | break; |
| 283 | 292 | |
| 293 | + /* xe_bo_init_locked() frees storage on error */ | |
| 284 | 294 | bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size, |
| 285 | 295 | 0, /* Will require 1way or 2way for vm_bind */ |
| 286 | 296 | ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec); |
| @@ -368,12 +378,15 @@ struct drm_gem_object *xe_gem_prime_import(struct drm_device *dev, · 81 unmodified lines | ||
| 368 | 378 | goto out_err; |
| 369 | 379 | } |
| 370 | 380 | |
| 371 | − /* Errors here will take care of freeing the bo. */ | |
| 381 | + /* | |
| 382 | + * xe_dma_buf_init_obj() takes ownership of bo on both success | |
| 383 | + * and failure, so we must not touch bo after this call. | |
| 384 | + */ | |
| 372 | 385 | obj = xe_dma_buf_init_obj(dev, bo, dma_buf); |
| 373 | − if (IS_ERR(obj)) | |
| 386 | + if (IS_ERR(obj)) { | |
| 387 | + dma_buf_detach(dma_buf, attach); | |
| 374 | 388 | return obj; |
| 375 | − | |
| 376 | − | |
| 389 | + } | |
| 377 | 390 | get_dma_buf(dma_buf); |
| 378 | 391 | obj->import_attach = attach; |
| 379 | 392 | return obj; |
| @@ -869,14 +869,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file) · 868 unmodified lines | ||
| 869 | 869 | struct xe_eu_stall_data_stream *stream = file->private_data; |
| 870 | 870 | struct xe_gt *gt = stream->gt; |
| 871 | 871 | |
| 872 | − drm_dev_put(>->tile->xe->drm); | |
| 873 | − | |
| 874 | 872 | mutex_lock(>->eu_stall->stream_lock); |
| 875 | 873 | xe_eu_stall_disable_locked(stream); |
| 876 | 874 | xe_eu_stall_data_buf_destroy(stream); |
| 877 | 875 | xe_eu_stall_stream_free(stream); |
| 878 | 876 | mutex_unlock(>->eu_stall->stream_lock); |
| 879 | 877 | |
| 878 | + drm_dev_put(>->tile->xe->drm); | |
| 879 | + | |
| 880 | 880 | return 0; |
| 881 | 881 | } |
| 882 | 882 | |
| @@ -1405,7 +1405,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, · 1404 unmodified lines | ||
| 1405 | 1405 | if (q->vm && q->hwe->hw_engine_group) { |
| 1406 | 1406 | err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q); |
| 1407 | 1407 | if (err) |
| 1408 | − goto put_exec_queue; | |
| 1408 | + goto kill_exec_queue; | |
| 1409 | 1409 | } |
| 1410 | 1410 | } |
| 1411 | 1411 | |
| @@ -1416,12 +1416,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, · 4 unmodified lines | ||
| 1416 | 1416 | /* user id alloc must always be last in ioctl to prevent UAF */ |
| 1417 | 1417 | err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL); |
| 1418 | 1418 | if (err) |
| 1419 | − goto kill_exec_queue; | |
| 1419 | + goto del_hw_engine_group; | |
| 1420 | 1420 | |
| 1421 | 1421 | args->exec_queue_id = id; |
| 1422 | 1422 | |
| 1423 | 1423 | return 0; |
| 1424 | 1424 | |
| 1425 | +del_hw_engine_group: | |
| 1426 | + if (q->vm && q->hwe && q->hwe->hw_engine_group) | |
| 1427 | + xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); | |
| 1425 | 1428 | kill_exec_queue: |
| 1426 | 1429 | xe_exec_queue_kill(q); |
| 1427 | 1430 | delete_queue_group: |
| @@ -1760,7 +1763,7 @@ void xe_exec_queue_tlb_inval_last_fence_put(struct xe_exec_queue *q, · 332 unmodified lines | ||
| 1760 | 1763 | void xe_exec_queue_tlb_inval_last_fence_put_unlocked(struct xe_exec_queue *q, |
| 1761 | 1764 | unsigned int type) |
| 1762 | 1765 | { |
| 1763 | − xe_assert(q->vm->xe, type == XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT || | |
| 1766 | + xe_assert(gt_to_xe(q->gt), type == XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT || | |
| 1764 | 1767 | type == XE_EXEC_QUEUE_TLB_INVAL_PRIMARY_GT); |
| 1765 | 1768 | |
| 1766 | 1769 | dma_fence_put(q->tlb_inval[type].last_fence); |
| @@ -166,7 +166,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) · 165 unmodified lines | ||
| 166 | 166 | &rd_offset); |
| 167 | 167 | if (err) { |
| 168 | 168 | xe_gt_err(gt, "HuC: invalid GSC reply for version query (err=%d)\n", err); |
| 169 | − return err; | |
| 169 | + goto out_bo; | |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | compat->major = version_query_rd(xe, &bo->vmap, rd_offset, proj_major); |
| @@ -259,24 +259,12 @@ static void guc_submit_sw_fini(struct drm_device *drm, void *arg) · 258 unmodified lines | ||
| 259 | 259 | } |
| 260 | 260 | |
| 261 | 261 | static void guc_submit_fini(void *arg) |
| 262 | −{ | |
| 263 | − struct xe_guc *guc = arg; | |
| 264 | − | |
| 265 | − /* Forcefully kill any remaining exec queues */ | |
| 266 | − xe_guc_ct_stop(&guc->ct); | |
| 267 | − guc_submit_reset_prepare(guc); | |
| 268 | − xe_guc_softreset(guc); | |
| 269 | − xe_guc_submit_stop(guc); | |
| 270 | − xe_uc_fw_sanitize(&guc->fw); | |
| 271 | − xe_guc_submit_pause_abort(guc); | |
| 272 | −} | |
| 273 | − | |
| 274 | −static void guc_submit_wedged_fini(void *arg) | |
| 275 | 262 | { |
| 276 | 263 | struct xe_guc *guc = arg; |
| 277 | 264 | struct xe_exec_queue *q; |
| 278 | 265 | unsigned long index; |
| 279 | 266 | |
| 267 | + /* Drop any wedged queue refs */ | |
| 280 | 268 | mutex_lock(&guc->submission_state.lock); |
| 281 | 269 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { |
| 282 | 270 | if (exec_queue_wedged(q)) { |
| @@ -286,6 +274,14 @@ static void guc_submit_wedged_fini(void *arg) · 3 unmodified lines | ||
| 286 | 274 | } |
| 287 | 275 | } |
| 288 | 276 | mutex_unlock(&guc->submission_state.lock); |
| 277 | + | |
| 278 | + /* Forcefully kill any remaining exec queues */ | |
| 279 | + xe_guc_ct_stop(&guc->ct); | |
| 280 | + guc_submit_reset_prepare(guc); | |
| 281 | + xe_guc_softreset(guc); | |
| 282 | + xe_guc_submit_stop(guc); | |
| 283 | + xe_uc_fw_sanitize(&guc->fw); | |
| 284 | + xe_guc_submit_pause_abort(guc); | |
| 289 | 285 | } |
| 290 | 286 | |
| 291 | 287 | static const struct xe_exec_queue_ops guc_exec_queue_ops; |
| @@ -1320,10 +1316,8 @@ static void disable_scheduling_deregister(struct xe_guc *guc, · 1028 unmodified lines | ||
| 1320 | 1316 | void xe_guc_submit_wedge(struct xe_guc *guc) |
| 1321 | 1317 | { |
| 1322 | 1318 | struct xe_device *xe = guc_to_xe(guc); |
| 1323 | − struct xe_gt *gt = guc_to_gt(guc); | |
| 1324 | 1319 | struct xe_exec_queue *q; |
| 1325 | 1320 | unsigned long index; |
| 1326 | − int err; | |
| 1327 | 1321 | |
| 1328 | 1322 | xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode); |
| 1329 | 1323 | |
| @@ -1335,15 +1329,6 @@ void xe_guc_submit_wedge(struct xe_guc *guc) · 5 unmodified lines | ||
| 1335 | 1329 | return; |
| 1336 | 1330 | |
| 1337 | 1331 | if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { |
| 1338 | − err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev, | |
| 1339 | − guc_submit_wedged_fini, guc); | |
| 1340 | − if (err) { | |
| 1341 | − xe_gt_err(gt, "Failed to register clean-up on wedged.mode=%s; " | |
| 1342 | − "Although device is wedged.\n", | |
| 1343 | − xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)); | |
| 1344 | − return; | |
| 1345 | − } | |
| 1346 | − | |
| 1347 | 1332 | mutex_lock(&guc->submission_state.lock); |
| 1348 | 1333 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) |
| 1349 | 1334 | if (xe_exec_queue_get_unless_zero(q)) |
| @@ -1214,7 +1214,7 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc, · 1213 unmodified lines | ||
| 1214 | 1214 | if (xe_gt_WARN_ON(lrc->gt, max_len < 3)) |
| 1215 | 1215 | return -ENOSPC; |
| 1216 | 1216 | |
| 1217 | − *cmd++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1); | |
| 1217 | + *cmd++ = MI_LOAD_REGISTER_IMM | MI_LRI_LRM_CS_MMIO | MI_LRI_NUM_REGS(1); | |
| 1218 | 1218 | *cmd++ = CS_DEBUG_MODE2(0).addr; |
| 1219 | 1219 | *cmd++ = REG_MASKED_FIELD_ENABLE(INSTRUCTION_STATE_CACHE_INVALIDATE); |
| 1220 | 1220 | |
| @@ -0,0 +1,403 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | +/* | |
| 3 | + * Copyright © 2026 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <linux/kernel.h> | |
| 7 | + | |
| 8 | +#include <drm/drm_managed.h> | |
| 9 | + | |
| 10 | +#include "instructions/xe_mi_commands.h" | |
| 11 | +#include "xe_bo.h" | |
| 12 | +#include "xe_device_types.h" | |
| 13 | +#include "xe_map.h" | |
| 14 | +#include "xe_mem_pool.h" | |
| 15 | +#include "xe_mem_pool_types.h" | |
| 16 | +#include "xe_tile_printk.h" | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * struct xe_mem_pool - DRM MM pool for sub-allocating memory from a BO on an | |
| 20 | + * XE tile. | |
| 21 | + * | |
| 22 | + * The XE memory pool is a DRM MM manager that provides sub-allocation of memory | |
| 23 | + * from a backing buffer object (BO) on a specific XE tile. It is designed to | |
| 24 | + * manage memory for GPU workloads, allowing for efficient allocation and | |
| 25 | + * deallocation of memory regions within the BO. | |
| 26 | + * | |
| 27 | + * The memory pool maintains a primary BO that is pinned in the GGTT and mapped | |
| 28 | + * into the CPU address space for direct access. Optionally, it can also maintain | |
| 29 | + * a shadow BO that can be used for atomic updates to the primary BO's contents. | |
| 30 | + * | |
| 31 | + * The API provided by the memory pool allows clients to allocate and free memory | |
| 32 | + * regions, retrieve GPU and CPU addresses, and synchronize data between the | |
| 33 | + * primary and shadow BOs as needed. | |
| 34 | + */ | |
| 35 | +struct xe_mem_pool { | |
| 36 | + /** @base: Range allocator over [0, @size) in bytes */ | |
| 37 | + struct drm_mm base; | |
| 38 | + /** @bo: Active pool BO (GGTT-pinned, CPU-mapped). */ | |
| 39 | + struct xe_bo *bo; | |
| 40 | + /** @shadow: Shadow BO for atomic command updates. */ | |
| 41 | + struct xe_bo *shadow; | |
| 42 | + /** @swap_guard: Timeline guard updating @bo and @shadow */ | |
| 43 | + struct mutex swap_guard; | |
| 44 | + /** @cpu_addr: CPU virtual address of the active BO. */ | |
| 45 | + void *cpu_addr; | |
| 46 | + /** @is_iomem: Indicates if the BO mapping is I/O memory. */ | |
| 47 | + bool is_iomem; | |
| 48 | +}; | |
| 49 | + | |
| 50 | +static struct xe_mem_pool *node_to_pool(struct xe_mem_pool_node *node) | |
| 51 | +{ | |
| 52 | + return container_of(node->sa_node.mm, struct xe_mem_pool, base); | |
| 53 | +} | |
| 54 | + | |
| 55 | +static struct xe_tile *pool_to_tile(struct xe_mem_pool *pool) | |
| 56 | +{ | |
| 57 | + return pool->bo->tile; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static void fini_pool_action(struct drm_device *drm, void *arg) | |
| 61 | +{ | |
| 62 | + struct xe_mem_pool *pool = arg; | |
| 63 | + | |
| 64 | + if (pool->is_iomem) | |
| 65 | + kvfree(pool->cpu_addr); | |
| 66 | + | |
| 67 | + drm_mm_takedown(&pool->base); | |
| 68 | +} | |
| 69 | + | |
| 70 | +static int pool_shadow_init(struct xe_mem_pool *pool) | |
| 71 | +{ | |
| 72 | + struct xe_tile *tile = pool->bo->tile; | |
| 73 | + struct xe_device *xe = tile_to_xe(tile); | |
| 74 | + struct xe_bo *shadow; | |
| 75 | + int ret; | |
| 76 | + | |
| 77 | + xe_assert(xe, !pool->shadow); | |
| 78 | + | |
| 79 | + ret = drmm_mutex_init(&xe->drm, &pool->swap_guard); | |
| 80 | + if (ret) | |
| 81 | + return ret; | |
| 82 | + | |
| 83 | + if (IS_ENABLED(CONFIG_PROVE_LOCKING)) { | |
| 84 | + fs_reclaim_acquire(GFP_KERNEL); | |
| 85 | + might_lock(&pool->swap_guard); | |
| 86 | + fs_reclaim_release(GFP_KERNEL); | |
| 87 | + } | |
| 88 | + shadow = xe_managed_bo_create_pin_map(xe, tile, | |
| 89 | + xe_bo_size(pool->bo), | |
| 90 | + XE_BO_FLAG_VRAM_IF_DGFX(tile) | | |
| 91 | + XE_BO_FLAG_GGTT | | |
| 92 | + XE_BO_FLAG_GGTT_INVALIDATE | | |
| 93 | + XE_BO_FLAG_PINNED_NORESTORE); | |
| 94 | + if (IS_ERR(shadow)) | |
| 95 | + return PTR_ERR(shadow); | |
| 96 | + | |
| 97 | + pool->shadow = shadow; | |
| 98 | + | |
| 99 | + return 0; | |
| 100 | +} | |
| 101 | + | |
| 102 | +/** | |
| 103 | + * xe_mem_pool_init() - Initialize memory pool. | |
| 104 | + * @tile: the &xe_tile where allocate. | |
| 105 | + * @size: number of bytes to allocate. | |
| 106 | + * @guard: the size of the guard region at the end of the BO that is not | |
| 107 | + * sub-allocated, in bytes. | |
| 108 | + * @flags: flags to use to create shadow pool. | |
| 109 | + * | |
| 110 | + * Initializes a memory pool for sub-allocating memory from a backing BO on the | |
| 111 | + * specified XE tile. The backing BO is pinned in the GGTT and mapped into | |
| 112 | + * the CPU address space for direct access. Optionally, a shadow BO can also be | |
| 113 | + * initialized for atomic updates to the primary BO's contents. | |
| 114 | + * | |
| 115 | + * Returns: a pointer to the &xe_mem_pool, or an error pointer on failure. | |
| 116 | + */ | |
| 117 | +struct xe_mem_pool *xe_mem_pool_init(struct xe_tile *tile, u32 size, | |
| 118 | + u32 guard, int flags) | |
| 119 | +{ | |
| 120 | + struct xe_device *xe = tile_to_xe(tile); | |
| 121 | + struct xe_mem_pool *pool; | |
| 122 | + struct xe_bo *bo; | |
| 123 | + u32 managed_size; | |
| 124 | + int ret; | |
| 125 | + | |
| 126 | + xe_tile_assert(tile, size > guard); | |
| 127 | + managed_size = size - guard; | |
| 128 | + | |
| 129 | + pool = drmm_kzalloc(&xe->drm, sizeof(*pool), GFP_KERNEL); | |
| 130 | + if (!pool) | |
| 131 | + return ERR_PTR(-ENOMEM); | |
| 132 | + | |
| 133 | + bo = xe_managed_bo_create_pin_map(xe, tile, size, | |
| 134 | + XE_BO_FLAG_VRAM_IF_DGFX(tile) | | |
| 135 | + XE_BO_FLAG_GGTT | | |
| 136 | + XE_BO_FLAG_GGTT_INVALIDATE | | |
| 137 | + XE_BO_FLAG_PINNED_NORESTORE); | |
| 138 | + if (IS_ERR(bo)) { | |
| 139 | + xe_tile_err(tile, "Failed to prepare %uKiB BO for mem pool (%pe)\n", | |
| 140 | + size / SZ_1K, bo); | |
| 141 | + return ERR_CAST(bo); | |
| 142 | + } | |
| 143 | + pool->bo = bo; | |
| 144 | + pool->is_iomem = bo->vmap.is_iomem; | |
| 145 | + | |
| 146 | + if (pool->is_iomem) { | |
| 147 | + pool->cpu_addr = kvzalloc(size, GFP_KERNEL); | |
| 148 | + if (!pool->cpu_addr) | |
| 149 | + return ERR_PTR(-ENOMEM); | |
| 150 | + } else { | |
| 151 | + pool->cpu_addr = bo->vmap.vaddr; | |
| 152 | + } | |
| 153 | + | |
| 154 | + if (flags & XE_MEM_POOL_BO_FLAG_INIT_SHADOW_COPY) { | |
| 155 | + ret = pool_shadow_init(pool); | |
| 156 | + | |
| 157 | + if (ret) | |
| 158 | + goto out_err; | |
| 159 | + } | |
| 160 | + | |
| 161 | + drm_mm_init(&pool->base, 0, managed_size); | |
| 162 | + ret = drmm_add_action_or_reset(&xe->drm, fini_pool_action, pool); | |
| 163 | + if (ret) | |
| 164 | + return ERR_PTR(ret); | |
| 165 | + | |
| 166 | + return pool; | |
| 167 | + | |
| 168 | +out_err: | |
| 169 | + if (flags & XE_MEM_POOL_BO_FLAG_INIT_SHADOW_COPY) | |
| 170 | + xe_tile_err(tile, | |
| 171 | + "Failed to initialize shadow BO for mem pool (%d)\n", ret); | |
| 172 | + if (bo->vmap.is_iomem) | |
| 173 | + kvfree(pool->cpu_addr); | |
| 174 | + return ERR_PTR(ret); | |
| 175 | +} | |
| 176 | + | |
| 177 | +/** | |
| 178 | + * xe_mem_pool_sync() - Copy the entire contents of the main pool to shadow pool. | |
| 179 | + * @pool: the memory pool containing the primary and shadow BOs. | |
| 180 | + * | |
| 181 | + * Copies the entire contents of the primary pool to the shadow pool. This must | |
| 182 | + * be done after xe_mem_pool_init() with the XE_MEM_POOL_BO_FLAG_INIT_SHADOW_COPY | |
| 183 | + * flag to ensure that the shadow pool has the same initial contents as the primary | |
| 184 | + * pool. After this initial synchronization, clients can choose to synchronize the | |
| 185 | + * shadow pool with the primary pool on a node basis using | |
| 186 | + * xe_mem_pool_sync_shadow_locked() as needed. | |
| 187 | + * | |
| 188 | + * Return: None. | |
| 189 | + */ | |
| 190 | +void xe_mem_pool_sync(struct xe_mem_pool *pool) | |
| 191 | +{ | |
| 192 | + struct xe_tile *tile = pool_to_tile(pool); | |
| 193 | + struct xe_device *xe = tile_to_xe(tile); | |
| 194 | + | |
| 195 | + xe_tile_assert(tile, pool->shadow); | |
| 196 | + | |
| 197 | + xe_map_memcpy_to(xe, &pool->shadow->vmap, 0, | |
| 198 | + pool->cpu_addr, xe_bo_size(pool->bo)); | |
| 199 | +} | |
| 200 | + | |
| 201 | +/** | |
| 202 | + * xe_mem_pool_swap_shadow_locked() - Swap the primary BO with the shadow BO. | |
| 203 | + * @pool: the memory pool containing the primary and shadow BOs. | |
| 204 | + * | |
| 205 | + * Swaps the primary buffer object with the shadow buffer object in the mem | |
| 206 | + * pool. This allows for atomic updates to the contents of the primary BO | |
| 207 | + * by first writing to the shadow BO and then swapping it with the primary BO. | |
| 208 | + * Swap_guard must be held to ensure synchronization with any concurrent swap | |
| 209 | + * operations. | |
| 210 | + * | |
| 211 | + * Return: None. | |
| 212 | + */ | |
| 213 | +void xe_mem_pool_swap_shadow_locked(struct xe_mem_pool *pool) | |
| 214 | +{ | |
| 215 | + struct xe_tile *tile = pool_to_tile(pool); | |
| 216 | + | |
| 217 | + xe_tile_assert(tile, pool->shadow); | |
| 218 | + lockdep_assert_held(&pool->swap_guard); | |
| 219 | + | |
| 220 | + swap(pool->bo, pool->shadow); | |
| 221 | + if (!pool->bo->vmap.is_iomem) | |
| 222 | + pool->cpu_addr = pool->bo->vmap.vaddr; | |
| 223 | +} | |
| 224 | + | |
| 225 | +/** | |
| 226 | + * xe_mem_pool_sync_shadow_locked() - Copy node from primary pool to shadow pool. | |
| 227 | + * @node: the node allocated in the memory pool. | |
| 228 | + * | |
| 229 | + * Copies the specified batch buffer from the primary pool to the shadow pool. | |
| 230 | + * Swap_guard must be held to ensure synchronization with any concurrent swap | |
| 231 | + * operations. | |
| 232 | + * | |
| 233 | + * Return: None. | |
| 234 | + */ | |
| 235 | +void xe_mem_pool_sync_shadow_locked(struct xe_mem_pool_node *node) | |
| 236 | +{ | |
| 237 | + struct xe_mem_pool *pool = node_to_pool(node); | |
| 238 | + struct xe_tile *tile = pool_to_tile(pool); | |
| 239 | + struct xe_device *xe = tile_to_xe(tile); | |
| 240 | + struct drm_mm_node *sa_node = &node->sa_node; | |
| 241 | + | |
| 242 | + xe_tile_assert(tile, pool->shadow); | |
| 243 | + lockdep_assert_held(&pool->swap_guard); | |
| 244 | + | |
| 245 | + xe_map_memcpy_to(xe, &pool->shadow->vmap, | |
| 246 | + sa_node->start, | |
| 247 | + pool->cpu_addr + sa_node->start, | |
| 248 | + sa_node->size); | |
| 249 | +} | |
| 250 | + | |
| 251 | +/** | |
| 252 | + * xe_mem_pool_gpu_addr() - Retrieve GPU address of memory pool. | |
| 253 | + * @pool: the memory pool | |
| 254 | + * | |
| 255 | + * Returns: GGTT address of the memory pool. | |
| 256 | + */ | |
| 257 | +u64 xe_mem_pool_gpu_addr(struct xe_mem_pool *pool) | |
| 258 | +{ | |
| 259 | + return xe_bo_ggtt_addr(pool->bo); | |
| 260 | +} | |
| 261 | + | |
| 262 | +/** | |
| 263 | + * xe_mem_pool_cpu_addr() - Retrieve CPU address of manager pool. | |
| 264 | + * @pool: the memory pool | |
| 265 | + * | |
| 266 | + * Returns: CPU virtual address of memory pool. | |
| 267 | + */ | |
| 268 | +void *xe_mem_pool_cpu_addr(struct xe_mem_pool *pool) | |
| 269 | +{ | |
| 270 | + return pool->cpu_addr; | |
| 271 | +} | |
| 272 | + | |
| 273 | +/** | |
| 274 | + * xe_mem_pool_bo_swap_guard() - Retrieve the mutex used to guard swap | |
| 275 | + * operations on a memory pool. | |
| 276 | + * @pool: the memory pool | |
| 277 | + * | |
| 278 | + * Returns: Swap guard mutex or NULL if shadow pool is not created. | |
| 279 | + */ | |
| 280 | +struct mutex *xe_mem_pool_bo_swap_guard(struct xe_mem_pool *pool) | |
| 281 | +{ | |
| 282 | + if (!pool->shadow) | |
| 283 | + return NULL; | |
| 284 | + | |
| 285 | + return &pool->swap_guard; | |
| 286 | +} | |
| 287 | + | |
| 288 | +/** | |
| 289 | + * xe_mem_pool_bo_flush_write() - Copy the data from the sub-allocation | |
| 290 | + * to the GPU memory. | |
| 291 | + * @node: the node allocated in the memory pool to flush. | |
| 292 | + */ | |
| 293 | +void xe_mem_pool_bo_flush_write(struct xe_mem_pool_node *node) | |
| 294 | +{ | |
| 295 | + struct xe_mem_pool *pool = node_to_pool(node); | |
| 296 | + struct xe_tile *tile = pool_to_tile(pool); | |
| 297 | + struct xe_device *xe = tile_to_xe(tile); | |
| 298 | + struct drm_mm_node *sa_node = &node->sa_node; | |
| 299 | + | |
| 300 | + if (!pool->bo->vmap.is_iomem) | |
| 301 | + return; | |
| 302 | + | |
| 303 | + xe_map_memcpy_to(xe, &pool->bo->vmap, sa_node->start, | |
| 304 | + pool->cpu_addr + sa_node->start, | |
| 305 | + sa_node->size); | |
| 306 | +} | |
| 307 | + | |
| 308 | +/** | |
| 309 | + * xe_mem_pool_bo_sync_read() - Copy the data from GPU memory to the | |
| 310 | + * sub-allocation. | |
| 311 | + * @node: the node allocated in the memory pool to read back. | |
| 312 | + */ | |
| 313 | +void xe_mem_pool_bo_sync_read(struct xe_mem_pool_node *node) | |
| 314 | +{ | |
| 315 | + struct xe_mem_pool *pool = node_to_pool(node); | |
| 316 | + struct xe_tile *tile = pool_to_tile(pool); | |
| 317 | + struct xe_device *xe = tile_to_xe(tile); | |
| 318 | + struct drm_mm_node *sa_node = &node->sa_node; | |
| 319 | + | |
| 320 | + if (!pool->bo->vmap.is_iomem) | |
| 321 | + return; | |
| 322 | + | |
| 323 | + xe_map_memcpy_from(xe, pool->cpu_addr + sa_node->start, | |
| 324 | + &pool->bo->vmap, sa_node->start, sa_node->size); | |
| 325 | +} | |
| 326 | + | |
| 327 | +/** | |
| 328 | + * xe_mem_pool_alloc_node() - Allocate a new node for use with xe_mem_pool. | |
| 329 | + * | |
| 330 | + * Returns: node structure or an ERR_PTR(-ENOMEM). | |
| 331 | + */ | |
| 332 | +struct xe_mem_pool_node *xe_mem_pool_alloc_node(void) | |
| 333 | +{ | |
| 334 | + struct xe_mem_pool_node *node = kzalloc_obj(*node); | |
| 335 | + | |
| 336 | + if (!node) | |
| 337 | + return ERR_PTR(-ENOMEM); | |
| 338 | + | |
| 339 | + return node; | |
| 340 | +} | |
| 341 | + | |
| 342 | +/** | |
| 343 | + * xe_mem_pool_insert_node() - Insert a node into the memory pool. | |
| 344 | + * @pool: the memory pool to insert into | |
| 345 | + * @node: the node to insert | |
| 346 | + * @size: the size of the node to be allocated in bytes. | |
| 347 | + * | |
| 348 | + * Inserts a node into the specified memory pool using drm_mm for | |
| 349 | + * allocation. | |
| 350 | + * | |
| 351 | + * Returns: 0 on success or a negative error code on failure. | |
| 352 | + */ | |
| 353 | +int xe_mem_pool_insert_node(struct xe_mem_pool *pool, | |
| 354 | + struct xe_mem_pool_node *node, u32 size) | |
| 355 | +{ | |
| 356 | + if (!pool) | |
| 357 | + return -EINVAL; | |
| 358 | + | |
| 359 | + return drm_mm_insert_node(&pool->base, &node->sa_node, size); | |
| 360 | +} | |
| 361 | + | |
| 362 | +/** | |
| 363 | + * xe_mem_pool_free_node() - Free a node allocated from the memory pool. | |
| 364 | + * @node: the node to free | |
| 365 | + * | |
| 366 | + * Returns: None. | |
| 367 | + */ | |
| 368 | +void xe_mem_pool_free_node(struct xe_mem_pool_node *node) | |
| 369 | +{ | |
| 370 | + if (!node) | |
| 371 | + return; | |
| 372 | + | |
| 373 | + drm_mm_remove_node(&node->sa_node); | |
| 374 | + kfree(node); | |
| 375 | +} | |
| 376 | + | |
| 377 | +/** | |
| 378 | + * xe_mem_pool_node_cpu_addr() - Retrieve CPU address of the node. | |
| 379 | + * @node: the node allocated in the memory pool | |
| 380 | + * | |
| 381 | + * Returns: CPU virtual address of the node. | |
| 382 | + */ | |
| 383 | +void *xe_mem_pool_node_cpu_addr(struct xe_mem_pool_node *node) | |
| 384 | +{ | |
| 385 | + struct xe_mem_pool *pool = node_to_pool(node); | |
| 386 | + | |
| 387 | + return xe_mem_pool_cpu_addr(pool) + node->sa_node.start; | |
| 388 | +} | |
| 389 | + | |
| 390 | +/** | |
| 391 | + * xe_mem_pool_dump() - Dump the state of the DRM MM manager for debugging. | |
| 392 | + * @pool: the memory pool info be dumped. | |
| 393 | + * @p: The DRM printer to use for output. | |
| 394 | + * | |
| 395 | + * Only the drm managed region is dumped, not the state of the BOs or any other | |
| 396 | + * pool information. | |
| 397 | + * | |
| 398 | + * Returns: None. | |
| 399 | + */ | |
| 400 | +void xe_mem_pool_dump(struct xe_mem_pool *pool, struct drm_printer *p) | |
| 401 | +{ | |
| 402 | + drm_mm_print(&pool->base, p); | |
| 403 | +} | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +/* SPDX-License-Identifier: MIT */ | |
| 2 | +/* | |
| 3 | + * Copyright © 2026 Intel Corporation | |
| 4 | + */ | |
| 5 | +#ifndef _XE_MEM_POOL_H_ | |
| 6 | +#define _XE_MEM_POOL_H_ | |
| 7 | + | |
| 8 | +#include <linux/sizes.h> | |
| 9 | +#include <linux/types.h> | |
| 10 | + | |
| 11 | +#include <drm/drm_mm.h> | |
| 12 | +#include "xe_mem_pool_types.h" | |
| 13 | + | |
| 14 | +struct drm_printer; | |
| 15 | +struct xe_mem_pool; | |
| 16 | +struct xe_tile; | |
| 17 | + | |
| 18 | +struct xe_mem_pool *xe_mem_pool_init(struct xe_tile *tile, u32 size, | |
| 19 | + u32 guard, int flags); | |
| 20 | +void xe_mem_pool_sync(struct xe_mem_pool *pool); | |
| 21 | +void xe_mem_pool_swap_shadow_locked(struct xe_mem_pool *pool); | |
| 22 | +void xe_mem_pool_sync_shadow_locked(struct xe_mem_pool_node *node); | |
| 23 | +u64 xe_mem_pool_gpu_addr(struct xe_mem_pool *pool); | |
| 24 | +void *xe_mem_pool_cpu_addr(struct xe_mem_pool *pool); | |
| 25 | +struct mutex *xe_mem_pool_bo_swap_guard(struct xe_mem_pool *pool); | |
| 26 | +void xe_mem_pool_bo_flush_write(struct xe_mem_pool_node *node); | |
| 27 | +void xe_mem_pool_bo_sync_read(struct xe_mem_pool_node *node); | |
| 28 | +struct xe_mem_pool_node *xe_mem_pool_alloc_node(void); | |
| 29 | +int xe_mem_pool_insert_node(struct xe_mem_pool *pool, | |
| 30 | + struct xe_mem_pool_node *node, u32 size); | |
| 31 | +void xe_mem_pool_free_node(struct xe_mem_pool_node *node); | |
| 32 | +void *xe_mem_pool_node_cpu_addr(struct xe_mem_pool_node *node); | |
| 33 | +void xe_mem_pool_dump(struct xe_mem_pool *pool, struct drm_printer *p); | |
| 34 | + | |
| 35 | +#endif | |
| @@ -0,0 +1,21 @@ | ||
| 1 | +/* SPDX-License-Identifier: MIT */ | |
| 2 | +/* | |
| 3 | + * Copyright © 2026 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef _XE_MEM_POOL_TYPES_H_ | |
| 7 | +#define _XE_MEM_POOL_TYPES_H_ | |
| 8 | + | |
| 9 | +#include <drm/drm_mm.h> | |
| 10 | + | |
| 11 | +#define XE_MEM_POOL_BO_FLAG_INIT_SHADOW_COPY BIT(0) | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * struct xe_mem_pool_node - Sub-range allocations from mem pool. | |
| 15 | + */ | |
| 16 | +struct xe_mem_pool_node { | |
| 17 | + /** @sa_node: drm_mm_node for this allocation. */ | |
| 18 | + struct drm_mm_node sa_node; | |
| 19 | +}; | |
| 20 | + | |
| 21 | +#endif | |
| @@ -29,6 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | #include "xe_hw_engine.h" |
| 30 | 30 | #include "xe_lrc.h" |
| 31 | 31 | #include "xe_map.h" |
| 32 | +#include "xe_mem_pool.h" | |
| 32 | 33 | #include "xe_mocs.h" |
| 33 | 34 | #include "xe_printk.h" |
| 34 | 35 | #include "xe_pt.h" |
| @@ -1166,11 +1167,12 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 1131 unmodified lines | ||
| 1166 | 1167 | u32 batch_size, batch_size_allocated; |
| 1167 | 1168 | struct xe_device *xe = gt_to_xe(gt); |
| 1168 | 1169 | struct xe_res_cursor src_it, ccs_it; |
| 1170 | + struct xe_mem_pool *bb_pool; | |
| 1169 | 1171 | struct xe_sriov_vf_ccs_ctx *ctx; |
| 1170 | − struct xe_sa_manager *bb_pool; | |
| 1171 | 1172 | u64 size = xe_bo_size(src_bo); |
| 1172 | − struct xe_bb *bb = NULL; | |
| 1173 | + struct xe_mem_pool_node *bb; | |
| 1173 | 1174 | u64 src_L0, src_L0_ofs; |
| 1175 | + struct xe_bb xe_bb_tmp; | |
| 1174 | 1176 | u32 src_L0_pt; |
| 1175 | 1177 | int err; |
| 1176 | 1178 | |
| @@ -1208,18 +1210,18 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 31 unmodified lines | ||
| 1208 | 1210 | size -= src_L0; |
| 1209 | 1211 | } |
| 1210 | 1212 | |
| 1211 | − bb = xe_bb_alloc(gt); | |
| 1213 | + bb = xe_mem_pool_alloc_node(); | |
| 1212 | 1214 | if (IS_ERR(bb)) |
| 1213 | 1215 | return PTR_ERR(bb); |
| 1214 | 1216 | |
| 1215 | 1217 | bb_pool = ctx->mem.ccs_bb_pool; |
| 1216 | − scoped_guard(mutex, xe_sa_bo_swap_guard(bb_pool)) { | |
| 1217 | − xe_sa_bo_swap_shadow(bb_pool); | |
| 1218 | + scoped_guard(mutex, xe_mem_pool_bo_swap_guard(bb_pool)) { | |
| 1219 | + xe_mem_pool_swap_shadow_locked(bb_pool); | |
| 1218 | 1220 | |
| 1219 | − err = xe_bb_init(bb, bb_pool, batch_size); | |
| 1221 | + err = xe_mem_pool_insert_node(bb_pool, bb, batch_size * sizeof(u32)); | |
| 1220 | 1222 | if (err) { |
| 1221 | 1223 | xe_gt_err(gt, "BB allocation failed.\n"); |
| 1222 | − xe_bb_free(bb, NULL); | |
| 1224 | + kfree(bb); | |
| 1223 | 1225 | return err; |
| 1224 | 1226 | } |
| 1225 | 1227 | |
| @@ -1227,6 +1229,7 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 1 unmodified line | ||
| 1227 | 1229 | size = xe_bo_size(src_bo); |
| 1228 | 1230 | batch_size = 0; |
| 1229 | 1231 | |
| 1232 | + xe_bb_tmp = (struct xe_bb){ .cs = xe_mem_pool_node_cpu_addr(bb), .len = 0 }; | |
| 1230 | 1233 | /* |
| 1231 | 1234 | * Emit PTE and copy commands here. |
| 1232 | 1235 | * The CCS copy command can only support limited size. If the size to be |
| @@ -1255,24 +1258,27 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 22 unmodified lines | ||
| 1255 | 1258 | xe_assert(xe, IS_ALIGNED(ccs_it.start, PAGE_SIZE)); |
| 1256 | 1259 | batch_size += EMIT_COPY_CCS_DW; |
| 1257 | 1260 | |
| 1258 | − emit_pte(m, bb, src_L0_pt, false, true, &src_it, src_L0, src); | |
| 1261 | + emit_pte(m, &xe_bb_tmp, src_L0_pt, false, true, &src_it, src_L0, src); | |
| 1259 | 1262 | |
| 1260 | − emit_pte(m, bb, ccs_pt, false, false, &ccs_it, ccs_size, src); | |
| 1263 | + emit_pte(m, &xe_bb_tmp, ccs_pt, false, false, &ccs_it, ccs_size, src); | |
| 1261 | 1264 | |
| 1262 | − bb->len = emit_flush_invalidate(bb->cs, bb->len, flush_flags); | |
| 1263 | − flush_flags = xe_migrate_ccs_copy(m, bb, src_L0_ofs, src_is_pltt, | |
| 1265 | + xe_bb_tmp.len = emit_flush_invalidate(xe_bb_tmp.cs, xe_bb_tmp.len, | |
| 1266 | + flush_flags); | |
| 1267 | + flush_flags = xe_migrate_ccs_copy(m, &xe_bb_tmp, src_L0_ofs, src_is_pltt, | |
| 1264 | 1268 | src_L0_ofs, dst_is_pltt, |
| 1265 | 1269 | src_L0, ccs_ofs, true); |
| 1266 | − bb->len = emit_flush_invalidate(bb->cs, bb->len, flush_flags); | |
| 1270 | + xe_bb_tmp.len = emit_flush_invalidate(xe_bb_tmp.cs, xe_bb_tmp.len, | |
| 1271 | + flush_flags); | |
| 1267 | 1272 | |
| 1268 | 1273 | size -= src_L0; |
| 1269 | 1274 | } |
| 1270 | 1275 | |
| 1271 | − xe_assert(xe, (batch_size_allocated == bb->len)); | |
| 1276 | + xe_assert(xe, (batch_size_allocated == xe_bb_tmp.len)); | |
| 1277 | + xe_assert(xe, bb->sa_node.size == xe_bb_tmp.len * sizeof(u32)); | |
| 1272 | 1278 | src_bo->bb_ccs[read_write] = bb; |
| 1273 | 1279 | |
| 1274 | 1280 | xe_sriov_vf_ccs_rw_update_bb_addr(ctx); |
| 1275 | − xe_sa_bo_sync_shadow(bb->bo); | |
| 1281 | + xe_mem_pool_sync_shadow_locked(bb); | |
| 1276 | 1282 | } |
| 1277 | 1283 | |
| 1278 | 1284 | return 0; |
| @@ -1297,10 +1303,10 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 18 unmodified lines | ||
| 1297 | 1303 | void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, |
| 1298 | 1304 | enum xe_sriov_vf_ccs_rw_ctxs read_write) |
| 1299 | 1305 | { |
| 1300 | − struct xe_bb *bb = src_bo->bb_ccs[read_write]; | |
| 1306 | + struct xe_mem_pool_node *bb = src_bo->bb_ccs[read_write]; | |
| 1301 | 1307 | struct xe_device *xe = xe_bo_device(src_bo); |
| 1308 | + struct xe_mem_pool *bb_pool; | |
| 1302 | 1309 | struct xe_sriov_vf_ccs_ctx *ctx; |
| 1303 | − struct xe_sa_manager *bb_pool; | |
| 1304 | 1310 | u32 *cs; |
| 1305 | 1311 | |
| 1306 | 1312 | xe_assert(xe, IS_SRIOV_VF(xe)); |
| @@ -1308,17 +1314,17 @@ void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, · 1 unmodified line | ||
| 1308 | 1314 | ctx = &xe->sriov.vf.ccs.contexts[read_write]; |
| 1309 | 1315 | bb_pool = ctx->mem.ccs_bb_pool; |
| 1310 | 1316 | |
| 1311 | − guard(mutex) (xe_sa_bo_swap_guard(bb_pool)); | |
| 1312 | − xe_sa_bo_swap_shadow(bb_pool); | |
| 1313 | − | |
| 1314 | − cs = xe_sa_bo_cpu_addr(bb->bo); | |
| 1315 | − memset(cs, MI_NOOP, bb->len * sizeof(u32)); | |
| 1316 | − xe_sriov_vf_ccs_rw_update_bb_addr(ctx); | |
| 1317 | + scoped_guard(mutex, xe_mem_pool_bo_swap_guard(bb_pool)) { | |
| 1318 | + xe_mem_pool_swap_shadow_locked(bb_pool); | |
| 1317 | 1319 | |
| 1318 | − xe_sa_bo_sync_shadow(bb->bo); | |
| 1320 | + cs = xe_mem_pool_node_cpu_addr(bb); | |
| 1321 | + memset(cs, MI_NOOP, bb->sa_node.size); | |
| 1322 | + xe_sriov_vf_ccs_rw_update_bb_addr(ctx); | |
| 1319 | 1323 | |
| 1320 | − xe_bb_free(bb, NULL); | |
| 1321 | − src_bo->bb_ccs[read_write] = NULL; | |
| 1324 | + xe_mem_pool_sync_shadow_locked(bb); | |
| 1325 | + xe_mem_pool_free_node(bb); | |
| 1326 | + src_bo->bb_ccs[read_write] = NULL; | |
| 1327 | + } | |
| 1322 | 1328 | } |
| 1323 | 1329 | |
| 1324 | 1330 | /** |
| @@ -118,6 +118,7 @@ static const struct xe_graphics_desc graphics_xe2 = { · 117 unmodified lines | ||
| 118 | 118 | |
| 119 | 119 | static const struct xe_graphics_desc graphics_xe3p_lpg = { |
| 120 | 120 | XE2_GFX_FEATURES, |
| 121 | + .has_indirect_ring_state = 1, | |
| 121 | 122 | .multi_queue_engine_class_mask = BIT(XE_ENGINE_CLASS_COPY) | BIT(XE_ENGINE_CLASS_COMPUTE), |
| 122 | 123 | .num_geometry_xecore_fuse_regs = 3, |
| 123 | 124 | .num_compute_xecore_fuse_regs = 3, |
| @@ -226,7 +226,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, · 225 unmodified lines | ||
| 226 | 226 | } |
| 227 | 227 | |
| 228 | 228 | range_start = reg & REG_GENMASK(25, range_bit); |
| 229 | − range_end = range_start | REG_GENMASK(range_bit, 0); | |
| 229 | + range_end = range_start | REG_GENMASK(range_bit - 1, 0); | |
| 230 | 230 | |
| 231 | 231 | switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) { |
| 232 | 232 | case RING_FORCE_TO_NONPRIV_ACCESS_RW: |
| @@ -14,9 +14,9 @@ · 13 unmodified lines | ||
| 14 | 14 | #include "xe_guc.h" |
| 15 | 15 | #include "xe_guc_submit.h" |
| 16 | 16 | #include "xe_lrc.h" |
| 17 | +#include "xe_mem_pool.h" | |
| 17 | 18 | #include "xe_migrate.h" |
| 18 | 19 | #include "xe_pm.h" |
| 19 | −#include "xe_sa.h" | |
| 20 | 20 | #include "xe_sriov_printk.h" |
| 21 | 21 | #include "xe_sriov_vf.h" |
| 22 | 22 | #include "xe_sriov_vf_ccs.h" |
| @@ -141,43 +141,47 @@ static u64 get_ccs_bb_pool_size(struct xe_device *xe) · 118 unmodified lines | ||
| 141 | 141 | |
| 142 | 142 | static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) |
| 143 | 143 | { |
| 144 | + struct xe_mem_pool *pool; | |
| 144 | 145 | struct xe_device *xe = tile_to_xe(tile); |
| 145 | − struct xe_sa_manager *sa_manager; | |
| 146 | + u32 *pool_cpu_addr, *last_dw_addr; | |
| 146 | 147 | u64 bb_pool_size; |
| 147 | − int offset, err; | |
| 148 | + int err; | |
| 148 | 149 | |
| 149 | 150 | bb_pool_size = get_ccs_bb_pool_size(xe); |
| 150 | 151 | xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n", |
| 151 | 152 | ctx->ctx_id ? "Restore" : "Save", bb_pool_size / SZ_1M); |
| 152 | 153 | |
| 153 | − sa_manager = __xe_sa_bo_manager_init(tile, bb_pool_size, SZ_4K, SZ_16, | |
| 154 | − XE_SA_BO_MANAGER_FLAG_SHADOW); | |
| 155 | − | |
| 156 | − if (IS_ERR(sa_manager)) { | |
| 157 | − xe_sriov_err(xe, "Suballocator init failed with error: %pe\n", | |
| 158 | − sa_manager); | |
| 159 | − err = PTR_ERR(sa_manager); | |
| 154 | + pool = xe_mem_pool_init(tile, bb_pool_size, sizeof(u32), | |
| 155 | + XE_MEM_POOL_BO_FLAG_INIT_SHADOW_COPY); | |
| 156 | + if (IS_ERR(pool)) { | |
| 157 | + xe_sriov_err(xe, "xe_mem_pool_init failed with error: %pe\n", | |
| 158 | + pool); | |
| 159 | + err = PTR_ERR(pool); | |
| 160 | 160 | return err; |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | − offset = 0; | |
| 164 | − xe_map_memset(xe, &sa_manager->bo->vmap, offset, MI_NOOP, | |
| 165 | − bb_pool_size); | |
| 166 | − xe_map_memset(xe, &sa_manager->shadow->vmap, offset, MI_NOOP, | |
| 167 | − bb_pool_size); | |
| 163 | + pool_cpu_addr = xe_mem_pool_cpu_addr(pool); | |
| 164 | + memset(pool_cpu_addr, 0, bb_pool_size); | |
| 168 | 165 | |
| 169 | − offset = bb_pool_size - sizeof(u32); | |
| 170 | − xe_map_wr(xe, &sa_manager->bo->vmap, offset, u32, MI_BATCH_BUFFER_END); | |
| 171 | − xe_map_wr(xe, &sa_manager->shadow->vmap, offset, u32, MI_BATCH_BUFFER_END); | |
| 166 | + last_dw_addr = pool_cpu_addr + (bb_pool_size / sizeof(u32)) - 1; | |
| 167 | + *last_dw_addr = MI_BATCH_BUFFER_END; | |
| 172 | 168 | |
| 173 | − ctx->mem.ccs_bb_pool = sa_manager; | |
| 169 | + /** | |
| 170 | + * Sync the main copy and shadow copy so that the shadow copy is | |
| 171 | + * replica of main copy. We sync only BBs after init part. So, we | |
| 172 | + * need to make sure the main pool and shadow copy are in sync after | |
| 173 | + * this point. This is needed as GuC may read the BB commands from | |
| 174 | + * shadow copy. | |
| 175 | + */ | |
| 176 | + xe_mem_pool_sync(pool); | |
| 174 | 177 | |
| 178 | + ctx->mem.ccs_bb_pool = pool; | |
| 175 | 179 | return 0; |
| 176 | 180 | } |
| 177 | 181 | |
| 178 | 182 | static void ccs_rw_update_ring(struct xe_sriov_vf_ccs_ctx *ctx) |
| 179 | 183 | { |
| 180 | − u64 addr = xe_sa_manager_gpu_addr(ctx->mem.ccs_bb_pool); | |
| 184 | + u64 addr = xe_mem_pool_gpu_addr(ctx->mem.ccs_bb_pool); | |
| 181 | 185 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); |
| 182 | 186 | u32 dw[10], i = 0; |
| 183 | 187 | |
| @@ -388,7 +392,7 @@ err_ret: · 204 unmodified lines | ||
| 388 | 392 | #define XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET (2 * sizeof(u32)) |
| 389 | 393 | void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx) |
| 390 | 394 | { |
| 391 | − u64 addr = xe_sa_manager_gpu_addr(ctx->mem.ccs_bb_pool); | |
| 395 | + u64 addr = xe_mem_pool_gpu_addr(ctx->mem.ccs_bb_pool); | |
| 392 | 396 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); |
| 393 | 397 | struct xe_device *xe = gt_to_xe(ctx->mig_q->gt); |
| 394 | 398 | |
| @@ -412,8 +416,8 @@ int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo) · 17 unmodified lines | ||
| 412 | 416 | struct xe_device *xe = xe_bo_device(bo); |
| 413 | 417 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; |
| 414 | 418 | struct xe_sriov_vf_ccs_ctx *ctx; |
| 419 | + struct xe_mem_pool_node *bb; | |
| 415 | 420 | struct xe_tile *tile; |
| 416 | − struct xe_bb *bb; | |
| 417 | 421 | int err = 0; |
| 418 | 422 | |
| 419 | 423 | xe_assert(xe, IS_VF_CCS_READY(xe)); |
| @@ -445,7 +449,7 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo) · 25 unmodified lines | ||
| 445 | 449 | { |
| 446 | 450 | struct xe_device *xe = xe_bo_device(bo); |
| 447 | 451 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; |
| 448 | − struct xe_bb *bb; | |
| 452 | + struct xe_mem_pool_node *bb; | |
| 449 | 453 | |
| 450 | 454 | xe_assert(xe, IS_VF_CCS_READY(xe)); |
| 451 | 455 | |
| @@ -471,8 +475,8 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo) · 19 unmodified lines | ||
| 471 | 475 | */ |
| 472 | 476 | void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p) |
| 473 | 477 | { |
| 474 | − struct xe_sa_manager *bb_pool; | |
| 475 | 478 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; |
| 479 | + struct xe_mem_pool *bb_pool; | |
| 476 | 480 | |
| 477 | 481 | if (!IS_VF_CCS_READY(xe)) |
| 478 | 482 | return; |
| @@ -485,7 +489,7 @@ void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p) · 6 unmodified lines | ||
| 485 | 489 | |
| 486 | 490 | drm_printf(p, "ccs %s bb suballoc info\n", ctx_id ? "write" : "read"); |
| 487 | 491 | drm_printf(p, "-------------------------\n"); |
| 488 | − drm_suballoc_dump_debug_info(&bb_pool->base, p, xe_sa_manager_gpu_addr(bb_pool)); | |
| 492 | + xe_mem_pool_dump(bb_pool, p); | |
| 489 | 493 | drm_puts(p, "\n"); |
| 490 | 494 | } |
| 491 | 495 | } |
| @@ -17,9 +17,6 @@ enum xe_sriov_vf_ccs_rw_ctxs { · 16 unmodified lines | ||
| 17 | 17 | XE_SRIOV_VF_CCS_CTX_COUNT |
| 18 | 18 | }; |
| 19 | 19 | |
| 20 | −struct xe_migrate; | |
| 21 | −struct xe_sa_manager; | |
| 22 | − | |
| 23 | 20 | /** |
| 24 | 21 | * struct xe_sriov_vf_ccs_ctx - VF CCS migration context data. |
| 25 | 22 | */ |
| @@ -33,7 +30,7 @@ struct xe_sriov_vf_ccs_ctx { · 7 unmodified lines | ||
| 33 | 30 | /** @mem: memory data */ |
| 34 | 31 | struct { |
| 35 | 32 | /** @mem.ccs_bb_pool: Pool from which batch buffers are allocated. */ |
| 36 | − struct xe_sa_manager *ccs_bb_pool; | |
| 33 | + struct xe_mem_pool *ccs_bb_pool; | |
| 37 | 34 | } mem; |
| 38 | 35 | }; |
| 39 | 36 | |
| @@ -97,7 +97,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { · 96 unmodified lines | ||
| 97 | 97 | { XE_RTP_NAME("Tuning: Set STLB Bank Hash Mode to 4KB"), |
| 98 | 98 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3510, XE_RTP_END_VERSION_UNDEFINED), |
| 99 | 99 | IS_INTEGRATED), |
| 100 | − XE_RTP_ACTIONS(FIELD_SET(XEHP_GAMSTLB_CTRL, BANK_HASH_MODE, | |
| 100 | + XE_RTP_ACTIONS(FIELD_SET(GAMSTLB_CTRL, BANK_HASH_MODE, | |
| 101 | 101 | BANK_HASH_4KB_MODE)) |
| 102 | 102 | }, |
| 103 | 103 | }; |
| @@ -3658,6 +3658,8 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, · 3657 unmodified lines | ||
| 3658 | 3658 | op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || |
| 3659 | 3659 | XE_IOCTL_DBG(xe, coh_mode == XE_COH_NONE && |
| 3660 | 3660 | op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || |
| 3661 | + XE_IOCTL_DBG(xe, !IS_DGFX(xe) && coh_mode == XE_COH_NONE && | |
| 3662 | + is_cpu_addr_mirror) || | |
| 3661 | 3663 | XE_IOCTL_DBG(xe, xe_device_is_l2_flush_optimized(xe) && |
| 3662 | 3664 | (op == DRM_XE_VM_BIND_OP_MAP_USERPTR || |
| 3663 | 3665 | is_cpu_addr_mirror) && |
| @@ -4156,7 +4158,8 @@ int xe_vm_get_property_ioctl(struct drm_device *drm, void *data, · 492 unmodified lines | ||
| 4156 | 4158 | int ret = 0; |
| 4157 | 4159 | |
| 4158 | 4160 | if (XE_IOCTL_DBG(xe, (args->reserved[0] || args->reserved[1] || |
| 4159 | − args->reserved[2]))) | |
| 4161 | + args->reserved[2] || args->extensions || | |
| 4162 | + args->pad))) | |
| 4160 | 4163 | return -EINVAL; |
| 4161 | 4164 | |
| 4162 | 4165 | vm = xe_vm_lookup(xef, args->vm_id); |
| @@ -621,6 +621,45 @@ static int xe_madvise_purgeable_retained_to_user(const struct xe_madvise_details · 620 unmodified lines | ||
| 621 | 621 | return 0; |
| 622 | 622 | } |
| 623 | 623 | |
| 624 | +static bool check_pat_args_are_sane(struct xe_device *xe, | |
| 625 | + struct xe_vmas_in_madvise_range *madvise_range, | |
| 626 | + u16 pat_index) | |
| 627 | +{ | |
| 628 | + u16 coh_mode = xe_pat_index_get_coh_mode(xe, pat_index); | |
| 629 | + int i; | |
| 630 | + | |
| 631 | + /* | |
| 632 | + * Using coh_none with CPU cached buffers is not allowed on iGPU. | |
| 633 | + * On iGPU the GPU shares the LLC with the CPU, so with coh_none | |
| 634 | + * the GPU bypasses CPU caches and reads directly from DRAM, | |
| 635 | + * potentially seeing stale sensitive data from previously freed | |
| 636 | + * pages. On dGPU this restriction does not apply, because the | |
| 637 | + * platform does not provide a non-coherent system memory access | |
| 638 | + * path that would violate the DMA coherency contract. | |
| 639 | + */ | |
| 640 | + if (coh_mode != XE_COH_NONE || IS_DGFX(xe)) | |
| 641 | + return true; | |
| 642 | + | |
| 643 | + for (i = 0; i < madvise_range->num_vmas; i++) { | |
| 644 | + struct xe_vma *vma = madvise_range->vmas[i]; | |
| 645 | + struct xe_bo *bo = xe_vma_bo(vma); | |
| 646 | + | |
| 647 | + if (bo) { | |
| 648 | + /* BO with WB caching + COH_NONE is not allowed */ | |
| 649 | + if (XE_IOCTL_DBG(xe, bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB)) | |
| 650 | + return false; | |
| 651 | + /* Imported dma-buf without caching info, assume cached */ | |
| 652 | + if (XE_IOCTL_DBG(xe, !bo->cpu_caching)) | |
| 653 | + return false; | |
| 654 | + } else if (XE_IOCTL_DBG(xe, xe_vma_is_cpu_addr_mirror(vma) || | |
| 655 | + xe_vma_is_userptr(vma))) | |
| 656 | + /* System memory (userptr/SVM) is always CPU cached */ | |
| 657 | + return false; | |
| 658 | + } | |
| 659 | + | |
| 660 | + return true; | |
| 661 | +} | |
| 662 | + | |
| 624 | 663 | static bool check_bo_args_are_sane(struct xe_vm *vm, struct xe_vma **vmas, |
| 625 | 664 | int num_vmas, u32 atomic_val) |
| 626 | 665 | { |
| @@ -750,6 +789,14 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil · 123 unmodified lines | ||
| 750 | 789 | } |
| 751 | 790 | } |
| 752 | 791 | |
| 792 | + if (args->type == DRM_XE_MEM_RANGE_ATTR_PAT) { | |
| 793 | + if (!check_pat_args_are_sane(xe, &madvise_range, | |
| 794 | + args->pat_index.val)) { | |
| 795 | + err = -EINVAL; | |
| 796 | + goto free_vmas; | |
| 797 | + } | |
| 798 | + } | |
| 799 | + | |
| 753 | 800 | if (madvise_range.has_bo_vmas) { |
| 754 | 801 | if (args->type == DRM_XE_MEM_RANGE_ATTR_ATOMIC) { |
| 755 | 802 | if (!check_bo_args_are_sane(vm, madvise_range.vmas, |
| @@ -743,14 +743,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { · 742 unmodified lines | ||
| 743 | 743 | XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), |
| 744 | 744 | XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS)) |
| 745 | 745 | }, |
| 746 | − { XE_RTP_NAME("14019988906"), | |
| 747 | − XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), | |
| 748 | − XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) | |
| 749 | − }, | |
| 750 | − { XE_RTP_NAME("14019877138"), | |
| 751 | − XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), | |
| 752 | − XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) | |
| 753 | − }, | |
| 754 | 746 | { XE_RTP_NAME("14021490052"), |
| 755 | 747 | XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), |
| 756 | 748 | XE_RTP_ACTIONS(SET(FF_MODE, |
| @@ -12,8 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/module.h> |
| 13 | 13 | #include <linux/platform_device.h> |
| 14 | 14 | |
| 15 | −#include "mailbox.h" | |
| 16 | − | |
| 17 | 15 | /* |
| 18 | 16 | * The maximum transmission size is 32 words or 128 bytes. |
| 19 | 17 | */ |
| @@ -405,7 +403,7 @@ static int cix_mbox_startup(struct mbox_chan *chan) · 385 unmodified lines | ||
| 405 | 403 | int index = cp->index, ret; |
| 406 | 404 | u32 val; |
| 407 | 405 | |
| 408 | − ret = request_irq(priv->irq, cix_mbox_isr, 0, | |
| 406 | + ret = request_irq(priv->irq, cix_mbox_isr, IRQF_NO_SUSPEND, | |
| 409 | 407 | dev_name(priv->dev), chan); |
| 410 | 408 | if (ret) { |
| 411 | 409 | dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); |
| @@ -415,7 +413,7 @@ static int cix_mbox_startup(struct mbox_chan *chan) · 3 unmodified lines | ||
| 415 | 413 | switch (cp->type) { |
| 416 | 414 | case CIX_MBOX_TYPE_DB: |
| 417 | 415 | /* Overwrite txdone_method for DB channel */ |
| 418 | − chan->txdone_method = TXDONE_BY_ACK; | |
| 416 | + chan->txdone_method = MBOX_TXDONE_BY_ACK; | |
| 419 | 417 | fallthrough; |
| 420 | 418 | case CIX_MBOX_TYPE_REG: |
| 421 | 419 | if (priv->dir == CIX_MBOX_TX) { |
| @@ -99,7 +99,6 @@ static int exynos_mbox_probe(struct platform_device *pdev) · 98 unmodified lines | ||
| 99 | 99 | struct mbox_controller *mbox; |
| 100 | 100 | struct mbox_chan *chans; |
| 101 | 101 | struct clk *pclk; |
| 102 | − int i; | |
| 103 | 102 | |
| 104 | 103 | exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL); |
| 105 | 104 | if (!exynos_mbox) |
| @@ -129,9 +128,6 @@ static int exynos_mbox_probe(struct platform_device *pdev) · 23 unmodified lines | ||
| 129 | 128 | mbox->ops = &exynos_mbox_chan_ops; |
| 130 | 129 | mbox->of_xlate = exynos_mbox_of_xlate; |
| 131 | 130 | |
| 132 | − for (i = 0; i < EXYNOS_MBOX_CHAN_COUNT; i++) | |
| 133 | − chans[i].mbox = mbox; | |
| 134 | − | |
| 135 | 131 | exynos_mbox->mbox = mbox; |
| 136 | 132 | |
| 137 | 133 | platform_set_drvdata(pdev, exynos_mbox); |
| @@ -15,8 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/platform_device.h> |
| 16 | 16 | #include <linux/slab.h> |
| 17 | 17 | |
| 18 | −#include "mailbox.h" | |
| 19 | − | |
| 20 | 18 | #define MBOX_CHAN_MAX 32 |
| 21 | 19 | |
| 22 | 20 | #define MBOX_RX 0x0 |
| @@ -79,12 +79,12 @@ struct hi6220_mbox { · 78 unmodified lines | ||
| 79 | 79 | /* region for mailbox */ |
| 80 | 80 | void __iomem *base; |
| 81 | 81 | |
| 82 | − unsigned int chan_num; | |
| 83 | − struct hi6220_mbox_chan *mchan; | |
| 84 | − | |
| 85 | 82 | void *irq_map_chan[MBOX_CHAN_MAX]; |
| 86 | 83 | struct mbox_chan *chan; |
| 87 | 84 | struct mbox_controller controller; |
| 85 | + | |
| 86 | + unsigned int chan_num; | |
| 87 | + struct hi6220_mbox_chan mchan[] __counted_by(chan_num); | |
| 88 | 88 | }; |
| 89 | 89 | |
| 90 | 90 | static void mbox_set_state(struct hi6220_mbox *mbox, |
| @@ -267,16 +267,12 @@ static int hi6220_mbox_probe(struct platform_device *pdev) · 176 unmodified lines | ||
| 267 | 267 | struct hi6220_mbox *mbox; |
| 268 | 268 | int i, err; |
| 269 | 269 | |
| 270 | − mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); | |
| 270 | + mbox = devm_kzalloc(dev, struct_size(mbox, mchan, MBOX_CHAN_MAX), GFP_KERNEL); | |
| 271 | 271 | if (!mbox) |
| 272 | 272 | return -ENOMEM; |
| 273 | 273 | |
| 274 | − mbox->dev = dev; | |
| 275 | 274 | mbox->chan_num = MBOX_CHAN_MAX; |
| 276 | − mbox->mchan = devm_kcalloc(dev, | |
| 277 | − mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL); | |
| 278 | − if (!mbox->mchan) | |
| 279 | − return -ENOMEM; | |
| 275 | + mbox->dev = dev; | |
| 280 | 276 | |
| 281 | 277 | mbox->chan = devm_kcalloc(dev, |
| 282 | 278 | mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL); |
| @@ -23,8 +23,6 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <linux/slab.h> |
| 24 | 24 | #include <linux/workqueue.h> |
| 25 | 25 | |
| 26 | −#include "mailbox.h" | |
| 27 | − | |
| 28 | 26 | #define IMX_MU_CHANS 24 |
| 29 | 27 | /* TX0/RX0/RXDB[0-3] */ |
| 30 | 28 | #define IMX_MU_SCU_CHANS 6 |
| @@ -734,7 +732,7 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox, · 703 unmodified lines | ||
| 734 | 732 | p_chan = &mbox->chans[chan]; |
| 735 | 733 | |
| 736 | 734 | if (type == IMX_MU_TYPE_TXDB_V2) |
| 737 | − p_chan->txdone_method = TXDONE_BY_ACK; | |
| 735 | + p_chan->txdone_method = MBOX_TXDONE_BY_ACK; | |
| 738 | 736 | |
| 739 | 737 | return p_chan; |
| 740 | 738 | } |
| @@ -21,8 +21,6 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/property.h> |
| 22 | 22 | #include <linux/slab.h> |
| 23 | 23 | |
| 24 | −#include "mailbox.h" | |
| 25 | − | |
| 26 | 24 | #define STI_MBOX_INST_MAX 4 /* RAM saving: Max supported instances */ |
| 27 | 25 | #define STI_MBOX_CHAN_MAX 20 /* RAM saving: Max supported channels */ |
| 28 | 26 | |
| @@ -28,8 +28,6 @@ · 27 unmodified lines | ||
| 28 | 28 | #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ |
| 29 | 29 | (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) |
| 30 | 30 | |
| 31 | −static bool mbox_data_ready; | |
| 32 | − | |
| 33 | 31 | struct mbox_test_device { |
| 34 | 32 | struct device *dev; |
| 35 | 33 | void __iomem *tx_mmio; |
| @@ -42,6 +40,7 @@ struct mbox_test_device { · 6 unmodified lines | ||
| 42 | 40 | spinlock_t lock; |
| 43 | 41 | struct mutex mutex; |
| 44 | 42 | wait_queue_head_t waitq; |
| 43 | + bool data_ready; | |
| 45 | 44 | struct fasync_struct *async_queue; |
| 46 | 45 | struct dentry *root_debugfs_dir; |
| 47 | 46 | }; |
| @@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) · 114 unmodified lines | ||
| 162 | 161 | unsigned long flags; |
| 163 | 162 | |
| 164 | 163 | spin_lock_irqsave(&tdev->lock, flags); |
| 165 | − data_ready = mbox_data_ready; | |
| 164 | + data_ready = tdev->data_ready; | |
| 166 | 165 | spin_unlock_irqrestore(&tdev->lock, flags); |
| 167 | 166 | |
| 168 | 167 | return data_ready; |
| @@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, · 58 unmodified lines | ||
| 227 | 226 | *(touser + l) = '\0'; |
| 228 | 227 | |
| 229 | 228 | memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); |
| 230 | − mbox_data_ready = false; | |
| 229 | + tdev->data_ready = false; | |
| 231 | 230 | |
| 232 | 231 | spin_unlock_irqrestore(&tdev->lock, flags); |
| 233 | 232 | |
| @@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) · 63 unmodified lines | ||
| 297 | 296 | message, MBOX_MAX_MSG_LEN); |
| 298 | 297 | memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); |
| 299 | 298 | } |
| 300 | − mbox_data_ready = true; | |
| 299 | + tdev->data_ready = true; | |
| 301 | 300 | spin_unlock_irqrestore(&tdev->lock, flags); |
| 302 | 301 | |
| 303 | 302 | wake_up_interruptible(&tdev->waitq); |
| @@ -336,7 +335,7 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name) · 32 unmodified lines | ||
| 336 | 335 | |
| 337 | 336 | client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); |
| 338 | 337 | if (!client) |
| 339 | − return ERR_PTR(-ENOMEM); | |
| 338 | + return NULL; | |
| 340 | 339 | |
| 341 | 340 | client->dev = &pdev->dev; |
| 342 | 341 | client->rx_callback = mbox_test_receive_message; |
| @@ -355,67 +354,80 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name) · 12 unmodified lines | ||
| 355 | 354 | return channel; |
| 356 | 355 | } |
| 357 | 356 | |
| 357 | +static void __iomem *mbox_test_ioremap(struct platform_device *pdev, unsigned int res_num) | |
| 358 | +{ | |
| 359 | + struct resource *res; | |
| 360 | + void __iomem *mmio; | |
| 361 | + | |
| 362 | + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); | |
| 363 | + if (!res) | |
| 364 | + return NULL; | |
| 365 | + | |
| 366 | + mmio = devm_ioremap_resource(&pdev->dev, res); | |
| 367 | + if (PTR_ERR(mmio) == -EBUSY) { | |
| 368 | + dev_info(&pdev->dev, "trying workaround with plain ioremap\n"); | |
| 369 | + return devm_ioremap(&pdev->dev, res->start, resource_size(res)); | |
| 370 | + } | |
| 371 | + | |
| 372 | + return IS_ERR(mmio) ? NULL : mmio; | |
| 373 | +} | |
| 374 | + | |
| 358 | 375 | static int mbox_test_probe(struct platform_device *pdev) |
| 359 | 376 | { |
| 360 | 377 | struct mbox_test_device *tdev; |
| 361 | − struct resource *res; | |
| 362 | − resource_size_t size; | |
| 363 | 378 | int ret; |
| 364 | 379 | |
| 365 | 380 | tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); |
| 366 | 381 | if (!tdev) |
| 367 | 382 | return -ENOMEM; |
| 368 | 383 | |
| 384 | + tdev->dev = &pdev->dev; | |
| 385 | + spin_lock_init(&tdev->lock); | |
| 386 | + mutex_init(&tdev->mutex); | |
| 387 | + init_waitqueue_head(&tdev->waitq); | |
| 388 | + platform_set_drvdata(pdev, tdev); | |
| 389 | + | |
| 369 | 390 | /* It's okay for MMIO to be NULL */ |
| 370 | − tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); | |
| 371 | − if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { | |
| 372 | − /* if reserved area in SRAM, try just ioremap */ | |
| 373 | − size = resource_size(res); | |
| 374 | − tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); | |
| 375 | − } else if (IS_ERR(tdev->tx_mmio)) { | |
| 376 | − tdev->tx_mmio = NULL; | |
| 377 | − } | |
| 391 | + tdev->tx_mmio = mbox_test_ioremap(pdev, 0); | |
| 378 | 392 | |
| 379 | 393 | /* If specified, second reg entry is Rx MMIO */ |
| 380 | − tdev->rx_mmio = devm_platform_get_and_ioremap_resource(pdev, 1, &res); | |
| 381 | − if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { | |
| 382 | − size = resource_size(res); | |
| 383 | − tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); | |
| 384 | − } else if (IS_ERR(tdev->rx_mmio)) { | |
| 394 | + tdev->rx_mmio = mbox_test_ioremap(pdev, 1); | |
| 395 | + if (!tdev->rx_mmio) | |
| 385 | 396 | tdev->rx_mmio = tdev->tx_mmio; |
| 386 | − } | |
| 387 | 397 | |
| 388 | 398 | tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); |
| 389 | 399 | tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); |
| 390 | 400 | |
| 391 | − if (IS_ERR_OR_NULL(tdev->tx_channel) && IS_ERR_OR_NULL(tdev->rx_channel)) | |
| 401 | + if (!tdev->tx_channel && !tdev->rx_channel) | |
| 392 | 402 | return -EPROBE_DEFER; |
| 393 | 403 | |
| 394 | 404 | /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ |
| 395 | 405 | if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) |
| 396 | 406 | tdev->rx_channel = tdev->tx_channel; |
| 397 | 407 | |
| 398 | − tdev->dev = &pdev->dev; | |
| 399 | − platform_set_drvdata(pdev, tdev); | |
| 400 | − | |
| 401 | − spin_lock_init(&tdev->lock); | |
| 402 | − mutex_init(&tdev->mutex); | |
| 403 | − | |
| 404 | 408 | if (tdev->rx_channel) { |
| 405 | 409 | tdev->rx_buffer = devm_kzalloc(&pdev->dev, |
| 406 | 410 | MBOX_MAX_MSG_LEN, GFP_KERNEL); |
| 407 | − if (!tdev->rx_buffer) | |
| 408 | − return -ENOMEM; | |
| 411 | + if (!tdev->rx_buffer) { | |
| 412 | + ret = -ENOMEM; | |
| 413 | + goto err_free_chans; | |
| 414 | + } | |
| 409 | 415 | } |
| 410 | 416 | |
| 411 | 417 | ret = mbox_test_add_debugfs(pdev, tdev); |
| 412 | 418 | if (ret) |
| 413 | − return ret; | |
| 419 | + goto err_free_chans; | |
| 414 | 420 | |
| 415 | − init_waitqueue_head(&tdev->waitq); | |
| 416 | 421 | dev_info(&pdev->dev, "Successfully registered\n"); |
| 417 | 422 | |
| 418 | 423 | return 0; |
| 424 | + | |
| 425 | +err_free_chans: | |
| 426 | + if (tdev->tx_channel) | |
| 427 | + mbox_free_channel(tdev->tx_channel); | |
| 428 | + if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) | |
| 429 | + mbox_free_channel(tdev->rx_channel); | |
| 430 | + return ret; | |
| 419 | 431 | } |
| 420 | 432 | |
| 421 | 433 | static void mbox_test_remove(struct platform_device *pdev) |
| @@ -426,7 +438,7 @@ static void mbox_test_remove(struct platform_device *pdev) · 4 unmodified lines | ||
| 426 | 438 | |
| 427 | 439 | if (tdev->tx_channel) |
| 428 | 440 | mbox_free_channel(tdev->tx_channel); |
| 429 | − if (tdev->rx_channel) | |
| 441 | + if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) | |
| 430 | 442 | mbox_free_channel(tdev->rx_channel); |
| 431 | 443 | } |
| 432 | 444 | |
| @@ -18,8 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/property.h> |
| 19 | 19 | #include <linux/spinlock.h> |
| 20 | 20 | |
| 21 | −#include "mailbox.h" | |
| 22 | − | |
| 23 | 21 | static LIST_HEAD(mbox_cons); |
| 24 | 22 | static DEFINE_MUTEX(con_mutex); |
| 25 | 23 | |
| @@ -52,7 +50,7 @@ static void msg_submit(struct mbox_chan *chan) · 26 unmodified lines | ||
| 52 | 50 | int err = -EBUSY; |
| 53 | 51 | |
| 54 | 52 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 55 | − if (!chan->msg_count || chan->active_req) | |
| 53 | + if (!chan->msg_count || chan->active_req != MBOX_NO_MSG) | |
| 56 | 54 | break; |
| 57 | 55 | |
| 58 | 56 | count = chan->msg_count; |
| @@ -74,7 +72,7 @@ static void msg_submit(struct mbox_chan *chan) · 15 unmodified lines | ||
| 74 | 72 | } |
| 75 | 73 | } |
| 76 | 74 | |
| 77 | − if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { | |
| 75 | + if (!err && (chan->txdone_method & MBOX_TXDONE_BY_POLL)) { | |
| 78 | 76 | /* kick start the timer immediately to avoid delays */ |
| 79 | 77 | scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock) |
| 80 | 78 | hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); |
| @@ -87,13 +85,13 @@ static void tx_tick(struct mbox_chan *chan, int r) · 6 unmodified lines | ||
| 87 | 85 | |
| 88 | 86 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 89 | 87 | mssg = chan->active_req; |
| 90 | − chan->active_req = NULL; | |
| 88 | + chan->active_req = MBOX_NO_MSG; | |
| 91 | 89 | } |
| 92 | 90 | |
| 93 | 91 | /* Submit next message */ |
| 94 | 92 | msg_submit(chan); |
| 95 | 93 | |
| 96 | − if (!mssg) | |
| 94 | + if (mssg == MBOX_NO_MSG) | |
| 97 | 95 | return; |
| 98 | 96 | |
| 99 | 97 | /* Notify the client */ |
| @@ -114,7 +112,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) · 14 unmodified lines | ||
| 114 | 112 | for (i = 0; i < mbox->num_chans; i++) { |
| 115 | 113 | struct mbox_chan *chan = &mbox->chans[i]; |
| 116 | 114 | |
| 117 | − if (chan->active_req && chan->cl) { | |
| 115 | + if (chan->active_req != MBOX_NO_MSG && chan->cl) { | |
| 118 | 116 | txdone = chan->mbox->ops->last_tx_done(chan); |
| 119 | 117 | if (txdone) |
| 120 | 118 | tx_tick(chan, 0); |
| @@ -164,7 +162,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_received_data); · 43 unmodified lines | ||
| 164 | 162 | */ |
| 165 | 163 | void mbox_chan_txdone(struct mbox_chan *chan, int r) |
| 166 | 164 | { |
| 167 | − if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) { | |
| 165 | + if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_IRQ))) { | |
| 168 | 166 | dev_err(chan->mbox->dev, |
| 169 | 167 | "Controller can't run the TX ticker\n"); |
| 170 | 168 | return; |
| @@ -185,7 +183,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_txdone); · 14 unmodified lines | ||
| 185 | 183 | */ |
| 186 | 184 | void mbox_client_txdone(struct mbox_chan *chan, int r) |
| 187 | 185 | { |
| 188 | − if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) { | |
| 186 | + if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_ACK))) { | |
| 189 | 187 | dev_err(chan->mbox->dev, "Client can't run the TX ticker\n"); |
| 190 | 188 | return; |
| 191 | 189 | } |
| @@ -218,6 +216,29 @@ bool mbox_client_peek_data(struct mbox_chan *chan) · 26 unmodified lines | ||
| 218 | 216 | } |
| 219 | 217 | EXPORT_SYMBOL_GPL(mbox_client_peek_data); |
| 220 | 218 | |
| 219 | +/** | |
| 220 | + * mbox_chan_tx_slots_available - Query the number of available TX queue slots. | |
| 221 | + * @chan: Mailbox channel to query. | |
| 222 | + * | |
| 223 | + * Clients may call this to check how many messages can be queued via | |
| 224 | + * mbox_send_message() before the channel's TX queue is full. This helps | |
| 225 | + * clients avoid the -ENOBUFS error without needing to increase | |
| 226 | + * MBOX_TX_QUEUE_LEN. | |
| 227 | + * This can be called from atomic context. | |
| 228 | + * | |
| 229 | + * Return: Number of available slots in the channel's TX queue. | |
| 230 | + */ | |
| 231 | +unsigned int mbox_chan_tx_slots_available(struct mbox_chan *chan) | |
| 232 | +{ | |
| 233 | + unsigned int ret; | |
| 234 | + | |
| 235 | + guard(spinlock_irqsave)(&chan->lock); | |
| 236 | + ret = MBOX_TX_QUEUE_LEN - chan->msg_count; | |
| 237 | + | |
| 238 | + return ret; | |
| 239 | +} | |
| 240 | +EXPORT_SYMBOL_GPL(mbox_chan_tx_slots_available); | |
| 241 | + | |
| 221 | 242 | /** |
| 222 | 243 | * mbox_send_message - For client to submit a message to be |
| 223 | 244 | * sent to the remote. |
| @@ -246,7 +267,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg) · 22 unmodified lines | ||
| 246 | 267 | { |
| 247 | 268 | int t; |
| 248 | 269 | |
| 249 | − if (!chan || !chan->cl) | |
| 270 | + if (!chan || !chan->cl || mssg == MBOX_NO_MSG) | |
| 250 | 271 | return -EINVAL; |
| 251 | 272 | |
| 252 | 273 | t = add_to_rbuf(chan, mssg); |
| @@ -319,12 +340,12 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) · 66 unmodified lines | ||
| 319 | 340 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 320 | 341 | chan->msg_free = 0; |
| 321 | 342 | chan->msg_count = 0; |
| 322 | − chan->active_req = NULL; | |
| 343 | + chan->active_req = MBOX_NO_MSG; | |
| 323 | 344 | chan->cl = cl; |
| 324 | 345 | init_completion(&chan->tx_complete); |
| 325 | 346 | |
| 326 | − if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) | |
| 327 | − chan->txdone_method = TXDONE_BY_ACK; | |
| 347 | + if (chan->txdone_method == MBOX_TXDONE_BY_POLL && cl->knows_txdone) | |
| 348 | + chan->txdone_method = MBOX_TXDONE_BY_ACK; | |
| 328 | 349 | } |
| 329 | 350 | |
| 330 | 351 | if (chan->mbox->ops->startup) { |
| @@ -341,7 +362,7 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) · 10 unmodified lines | ||
| 341 | 362 | } |
| 342 | 363 | |
| 343 | 364 | /** |
| 344 | − * mbox_bind_client - Request a mailbox channel. | |
| 365 | + * mbox_bind_client - Bind client to a mailbox channel. | |
| 345 | 366 | * @chan: The mailbox channel to bind the client to. |
| 346 | 367 | * @cl: Identity of the client requesting the channel. |
| 347 | 368 | * |
| @@ -477,9 +498,9 @@ void mbox_free_channel(struct mbox_chan *chan) · 129 unmodified lines | ||
| 477 | 498 | /* The queued TX requests are simply aborted, no callbacks are made */ |
| 478 | 499 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 479 | 500 | chan->cl = NULL; |
| 480 | − chan->active_req = NULL; | |
| 481 | − if (chan->txdone_method == TXDONE_BY_ACK) | |
| 482 | − chan->txdone_method = TXDONE_BY_POLL; | |
| 501 | + chan->active_req = MBOX_NO_MSG; | |
| 502 | + if (chan->txdone_method == MBOX_TXDONE_BY_ACK) | |
| 503 | + chan->txdone_method = MBOX_TXDONE_BY_POLL; | |
| 483 | 504 | } |
| 484 | 505 | |
| 485 | 506 | module_put(chan->mbox->dev->driver->owner); |
| @@ -505,18 +526,17 @@ int mbox_controller_register(struct mbox_controller *mbox) · 19 unmodified lines | ||
| 505 | 526 | { |
| 506 | 527 | int i, txdone; |
| 507 | 528 | |
| 508 | − /* Sanity check */ | |
| 509 | − if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) | |
| 529 | + if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) | |
| 510 | 530 | return -EINVAL; |
| 511 | 531 | |
| 512 | 532 | if (mbox->txdone_irq) |
| 513 | − txdone = TXDONE_BY_IRQ; | |
| 533 | + txdone = MBOX_TXDONE_BY_IRQ; | |
| 514 | 534 | else if (mbox->txdone_poll) |
| 515 | − txdone = TXDONE_BY_POLL; | |
| 535 | + txdone = MBOX_TXDONE_BY_POLL; | |
| 516 | 536 | else /* It has to be ACK then */ |
| 517 | − txdone = TXDONE_BY_ACK; | |
| 537 | + txdone = MBOX_TXDONE_BY_ACK; | |
| 518 | 538 | |
| 519 | − if (txdone == TXDONE_BY_POLL) { | |
| 539 | + if (txdone == MBOX_TXDONE_BY_POLL) { | |
| 520 | 540 | |
| 521 | 541 | if (!mbox->ops->last_tx_done) { |
| 522 | 542 | dev_err(mbox->dev, "last_tx_done method is absent\n"); |
| @@ -532,6 +552,7 @@ int mbox_controller_register(struct mbox_controller *mbox) · 9 unmodified lines | ||
| 532 | 552 | |
| 533 | 553 | chan->cl = NULL; |
| 534 | 554 | chan->mbox = mbox; |
| 555 | + chan->active_req = MBOX_NO_MSG; | |
| 535 | 556 | chan->txdone_method = txdone; |
| 536 | 557 | spin_lock_init(&chan->lock); |
| 537 | 558 | } |
| @@ -1,12 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | − | |
| 3 | −#ifndef __MAILBOX_H | |
| 4 | −#define __MAILBOX_H | |
| 5 | − | |
| 6 | −#include <linux/bits.h> | |
| 7 | − | |
| 8 | −#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ | |
| 9 | −#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ | |
| 10 | −#define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ | |
| 11 | − | |
| 12 | −#endif /* __MAILBOX_H */ | |
| @@ -493,14 +493,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) · 492 unmodified lines | ||
| 493 | 493 | if (curr_pa == end_pa - CMDQ_INST_SIZE || |
| 494 | 494 | curr_pa == end_pa) { |
| 495 | 495 | /* set to this task directly */ |
| 496 | − writel(task->pa_base >> cmdq->pdata->shift, | |
| 497 | − thread->base + CMDQ_THR_CURR_ADDR); | |
| 496 | + gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata); | |
| 497 | + writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR); | |
| 498 | 498 | } else { |
| 499 | 499 | cmdq_task_insert_into_thread(task); |
| 500 | 500 | smp_mb(); /* modify jump before enable thread */ |
| 501 | 501 | } |
| 502 | − writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, | |
| 503 | − thread->base + CMDQ_THR_END_ADDR); | |
| 502 | + gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata); | |
| 503 | + writel(gce_addr, thread->base + CMDQ_THR_END_ADDR); | |
| 504 | 504 | cmdq_thread_resume(thread); |
| 505 | 505 | } |
| 506 | 506 | list_move_tail(&task->list_entry, &thread->task_busy_list); |
| @@ -728,7 +728,7 @@ static int cmdq_probe(struct platform_device *pdev) · 221 unmodified lines | ||
| 728 | 728 | cmdq->mbox.ops = &cmdq_mbox_chan_ops; |
| 729 | 729 | cmdq->mbox.of_xlate = cmdq_xlate; |
| 730 | 730 | |
| 731 | − /* make use of TXDONE_BY_ACK */ | |
| 731 | + /* make use of MBOX_TXDONE_BY_ACK */ | |
| 732 | 732 | cmdq->mbox.txdone_irq = false; |
| 733 | 733 | cmdq->mbox.txdone_poll = false; |
| 734 | 734 | |
| @@ -50,7 +50,7 @@ static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox, · 49 unmodified lines | ||
| 50 | 50 | const struct of_phandle_args *sp) |
| 51 | 51 | { |
| 52 | 52 | if (sp->args_count) |
| 53 | − return NULL; | |
| 53 | + return ERR_PTR(-EINVAL); | |
| 54 | 54 | |
| 55 | 55 | return &mbox->chans[0]; |
| 56 | 56 | } |
| @@ -22,8 +22,6 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <linux/pm_runtime.h> |
| 23 | 23 | #include <linux/mailbox_controller.h> |
| 24 | 24 | |
| 25 | −#include "mailbox.h" | |
| 26 | − | |
| 27 | 25 | #define MAILBOX_REVISION 0x000 |
| 28 | 26 | #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) |
| 29 | 27 | #define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) |
| @@ -240,7 +238,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox) · 210 unmodified lines | ||
| 240 | 238 | } |
| 241 | 239 | |
| 242 | 240 | if (mbox->send_no_irq) |
| 243 | − mbox->chan->txdone_method = TXDONE_BY_ACK; | |
| 241 | + mbox->chan->txdone_method = MBOX_TXDONE_BY_ACK; | |
| 244 | 242 | |
| 245 | 243 | omap_mbox_enable_irq(mbox, IRQ_RX); |
| 246 | 244 | |
| @@ -59,8 +59,6 @@ · 58 unmodified lines | ||
| 59 | 59 | #include <linux/io-64-nonatomic-lo-hi.h> |
| 60 | 60 | #include <acpi/pcc.h> |
| 61 | 61 | |
| 62 | −#include "mailbox.h" | |
| 63 | − | |
| 64 | 62 | #define MBOX_IRQ_NAME "pcc-mbox" |
| 65 | 63 | |
| 66 | 64 | /** |
| @@ -46,7 +46,7 @@ struct rockchip_mbox { · 45 unmodified lines | ||
| 46 | 46 | /* The maximum size of buf for each channel */ |
| 47 | 47 | u32 buf_size; |
| 48 | 48 | |
| 49 | − struct rockchip_mbox_chan *chans; | |
| 49 | + struct rockchip_mbox_chan chans[]; | |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | 52 | static int rockchip_mbox_send_data(struct mbox_chan *chan, void *data) |
| @@ -173,15 +173,10 @@ static int rockchip_mbox_probe(struct platform_device *pdev) · 120 unmodified lines | ||
| 173 | 173 | |
| 174 | 174 | drv_data = (const struct rockchip_mbox_data *) device_get_match_data(&pdev->dev); |
| 175 | 175 | |
| 176 | − mb = devm_kzalloc(&pdev->dev, sizeof(*mb), GFP_KERNEL); | |
| 176 | + mb = devm_kzalloc(&pdev->dev, struct_size(mb, chans, drv_data->num_chans), GFP_KERNEL); | |
| 177 | 177 | if (!mb) |
| 178 | 178 | return -ENOMEM; |
| 179 | 179 | |
| 180 | − mb->chans = devm_kcalloc(&pdev->dev, drv_data->num_chans, | |
| 181 | − sizeof(*mb->chans), GFP_KERNEL); | |
| 182 | − if (!mb->chans) | |
| 183 | − return -ENOMEM; | |
| 184 | − | |
| 185 | 180 | mb->mbox.chans = devm_kcalloc(&pdev->dev, drv_data->num_chans, |
| 186 | 181 | sizeof(*mb->mbox.chans), GFP_KERNEL); |
| 187 | 182 | if (!mb->mbox.chans) |
| @@ -16,8 +16,6 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #include <dt-bindings/mailbox/tegra186-hsp.h> |
| 18 | 18 | |
| 19 | −#include "mailbox.h" | |
| 20 | − | |
| 21 | 19 | #define HSP_INT_IE(x) (0x100 + ((x) * 4)) |
| 22 | 20 | #define HSP_INT_IV 0x300 |
| 23 | 21 | #define HSP_INT_IR 0x304 |
| @@ -497,7 +495,7 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, · 473 unmodified lines | ||
| 497 | 495 | mbox_chan_txdone(chan, 0); |
| 498 | 496 | |
| 499 | 497 | /* Wait until channel is empty */ |
| 500 | − if (chan->active_req != NULL) | |
| 498 | + if (chan->active_req != MBOX_NO_MSG) | |
| 501 | 499 | continue; |
| 502 | 500 | |
| 503 | 501 | return 0; |
| @@ -516,7 +514,7 @@ static int tegra_hsp_mailbox_startup(struct mbox_chan *chan) · 12 unmodified lines | ||
| 516 | 514 | struct tegra_hsp *hsp = mb->channel.hsp; |
| 517 | 515 | unsigned long flags; |
| 518 | 516 | |
| 519 | − chan->txdone_method = TXDONE_BY_IRQ; | |
| 517 | + chan->txdone_method = MBOX_TXDONE_BY_IRQ; | |
| 520 | 518 | |
| 521 | 519 | /* |
| 522 | 520 | * Shared mailboxes start out as consumers by default. FULL and EMPTY |
| @@ -216,6 +216,7 @@ struct bitmap { · 215 unmodified lines | ||
| 216 | 216 | }; |
| 217 | 217 | |
| 218 | 218 | static struct workqueue_struct *md_bitmap_wq; |
| 219 | +static struct attribute_group md_bitmap_internal_group; | |
| 219 | 220 | |
| 220 | 221 | static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, |
| 221 | 222 | int chunksize, bool init); |
| @@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize) · 2358 unmodified lines | ||
| 2580 | 2581 | return __bitmap_resize(bitmap, blocks, chunksize, false); |
| 2581 | 2582 | } |
| 2582 | 2583 | |
| 2584 | +static bool bitmap_none_enabled(void *data, bool flush) | |
| 2585 | +{ | |
| 2586 | + return false; | |
| 2587 | +} | |
| 2588 | + | |
| 2589 | +static int bitmap_none_create(struct mddev *mddev) | |
| 2590 | +{ | |
| 2591 | + return 0; | |
| 2592 | +} | |
| 2593 | + | |
| 2594 | +static int bitmap_none_load(struct mddev *mddev) | |
| 2595 | +{ | |
| 2596 | + return 0; | |
| 2597 | +} | |
| 2598 | + | |
| 2599 | +static void bitmap_none_destroy(struct mddev *mddev) | |
| 2600 | +{ | |
| 2601 | +} | |
| 2602 | + | |
| 2603 | +static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats) | |
| 2604 | +{ | |
| 2605 | + return -ENOENT; | |
| 2606 | +} | |
| 2607 | + | |
| 2583 | 2608 | static ssize_t |
| 2584 | 2609 | location_show(struct mddev *mddev, char *page) |
| 2585 | 2610 | { |
| @@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len) · 32 unmodified lines | ||
| 2618 | 2643 | goto out; |
| 2619 | 2644 | } |
| 2620 | 2645 | |
| 2621 | − bitmap_destroy(mddev); | |
| 2646 | + sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group); | |
| 2647 | + md_bitmap_destroy_nosysfs(mddev); | |
| 2648 | + mddev->bitmap_id = ID_BITMAP_NONE; | |
| 2649 | + if (!mddev_set_bitmap_ops_nosysfs(mddev)) | |
| 2650 | + goto none_err; | |
| 2622 | 2651 | mddev->bitmap_info.offset = 0; |
| 2623 | 2652 | if (mddev->bitmap_info.file) { |
| 2624 | 2653 | struct file *f = mddev->bitmap_info.file; |
| @@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len) · 29 unmodified lines | ||
| 2654 | 2683 | } |
| 2655 | 2684 | |
| 2656 | 2685 | mddev->bitmap_info.offset = offset; |
| 2657 | − rv = bitmap_create(mddev); | |
| 2686 | + md_bitmap_destroy_nosysfs(mddev); | |
| 2687 | + mddev->bitmap_id = ID_BITMAP; | |
| 2688 | + if (!mddev_set_bitmap_ops_nosysfs(mddev)) | |
| 2689 | + goto bitmap_err; | |
| 2690 | + | |
| 2691 | + rv = md_bitmap_create_nosysfs(mddev); | |
| 2658 | 2692 | if (rv) |
| 2659 | − goto out; | |
| 2693 | + goto create_err; | |
| 2660 | 2694 | |
| 2661 | − rv = bitmap_load(mddev); | |
| 2695 | + rv = mddev->bitmap_ops->load(mddev); | |
| 2662 | 2696 | if (rv) { |
| 2663 | 2697 | mddev->bitmap_info.offset = 0; |
| 2664 | − bitmap_destroy(mddev); | |
| 2665 | − goto out; | |
| 2698 | + goto load_err; | |
| 2666 | 2699 | } |
| 2700 | + | |
| 2701 | + rv = sysfs_merge_group(&mddev->kobj, | |
| 2702 | + &md_bitmap_internal_group); | |
| 2703 | + if (rv) | |
| 2704 | + goto merge_err; | |
| 2667 | 2705 | } |
| 2668 | 2706 | } |
| 2669 | 2707 | if (!mddev->external) { |
| @@ -2679,6 +2717,22 @@ out: · 9 unmodified lines | ||
| 2679 | 2717 | if (rv) |
| 2680 | 2718 | return rv; |
| 2681 | 2719 | return len; |
| 2720 | + | |
| 2721 | +merge_err: | |
| 2722 | + mddev->bitmap_info.offset = 0; | |
| 2723 | +load_err: | |
| 2724 | + md_bitmap_destroy_nosysfs(mddev); | |
| 2725 | +create_err: | |
| 2726 | + mddev->bitmap_info.offset = 0; | |
| 2727 | + mddev->bitmap_id = ID_BITMAP_NONE; | |
| 2728 | + if (!mddev_set_bitmap_ops_nosysfs(mddev)) | |
| 2729 | + rv = -ENOENT; | |
| 2730 | + goto out; | |
| 2731 | +bitmap_err: | |
| 2732 | + rv = -ENOENT; | |
| 2733 | +none_err: | |
| 2734 | + mddev->bitmap_info.offset = 0; | |
| 2735 | + goto out; | |
| 2682 | 2736 | } |
| 2683 | 2737 | |
| 2684 | 2738 | static struct md_sysfs_entry bitmap_location = |
| @@ -2955,8 +3009,12 @@ static struct md_sysfs_entry max_backlog_used = · 270 unmodified lines | ||
| 2955 | 3009 | __ATTR(max_backlog_used, S_IRUGO | S_IWUSR, |
| 2956 | 3010 | behind_writes_used_show, behind_writes_used_reset); |
| 2957 | 3011 | |
| 2958 | −static struct attribute *md_bitmap_attrs[] = { | |
| 3012 | +static struct attribute *md_bitmap_common_attrs[] = { | |
| 2959 | 3013 | &bitmap_location.attr, |
| 3014 | + NULL | |
| 3015 | +}; | |
| 3016 | + | |
| 3017 | +static struct attribute *md_bitmap_internal_attrs[] = { | |
| 2960 | 3018 | &bitmap_space.attr, |
| 2961 | 3019 | &bitmap_timeout.attr, |
| 2962 | 3020 | &bitmap_backlog.attr, |
| @@ -2967,9 +3025,41 @@ static struct attribute *md_bitmap_attrs[] = { · 4 unmodified lines | ||
| 2967 | 3025 | NULL |
| 2968 | 3026 | }; |
| 2969 | 3027 | |
| 2970 | −static struct attribute_group md_bitmap_group = { | |
| 3028 | +static struct attribute_group md_bitmap_common_group = { | |
| 2971 | 3029 | .name = "bitmap", |
| 2972 | − .attrs = md_bitmap_attrs, | |
| 3030 | + .attrs = md_bitmap_common_attrs, | |
| 3031 | +}; | |
| 3032 | + | |
| 3033 | +static struct attribute_group md_bitmap_internal_group = { | |
| 3034 | + .name = "bitmap", | |
| 3035 | + .attrs = md_bitmap_internal_attrs, | |
| 3036 | +}; | |
| 3037 | + | |
| 3038 | +static const struct attribute_group *bitmap_groups[] = { | |
| 3039 | + &md_bitmap_common_group, | |
| 3040 | + &md_bitmap_internal_group, | |
| 3041 | + NULL, | |
| 3042 | +}; | |
| 3043 | + | |
| 3044 | +static const struct attribute_group *bitmap_none_groups[] = { | |
| 3045 | + &md_bitmap_common_group, | |
| 3046 | + NULL, | |
| 3047 | +}; | |
| 3048 | + | |
| 3049 | +static struct bitmap_operations bitmap_none_ops = { | |
| 3050 | + .head = { | |
| 3051 | + .type = MD_BITMAP, | |
| 3052 | + .id = ID_BITMAP_NONE, | |
| 3053 | + .name = "none", | |
| 3054 | + }, | |
| 3055 | + | |
| 3056 | + .enabled = bitmap_none_enabled, | |
| 3057 | + .create = bitmap_none_create, | |
| 3058 | + .load = bitmap_none_load, | |
| 3059 | + .destroy = bitmap_none_destroy, | |
| 3060 | + .get_stats = bitmap_none_get_stats, | |
| 3061 | + | |
| 3062 | + .groups = bitmap_none_groups, | |
| 2973 | 3063 | }; |
| 2974 | 3064 | |
| 2975 | 3065 | static struct bitmap_operations bitmap_ops = { |
| @@ -3013,21 +3103,38 @@ static struct bitmap_operations bitmap_ops = { · 37 unmodified lines | ||
| 3013 | 3103 | .set_pages = bitmap_set_pages, |
| 3014 | 3104 | .free = md_bitmap_free, |
| 3015 | 3105 | |
| 3016 | − .group = &md_bitmap_group, | |
| 3106 | + .groups = bitmap_groups, | |
| 3017 | 3107 | }; |
| 3018 | 3108 | |
| 3019 | 3109 | int md_bitmap_init(void) |
| 3020 | 3110 | { |
| 3111 | + int err; | |
| 3112 | + | |
| 3021 | 3113 | md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND, |
| 3022 | 3114 | 0); |
| 3023 | 3115 | if (!md_bitmap_wq) |
| 3024 | 3116 | return -ENOMEM; |
| 3025 | 3117 | |
| 3026 | − return register_md_submodule(&bitmap_ops.head); | |
| 3118 | + err = register_md_submodule(&bitmap_none_ops.head); | |
| 3119 | + if (err) | |
| 3120 | + goto err_wq; | |
| 3121 | + | |
| 3122 | + err = register_md_submodule(&bitmap_ops.head); | |
| 3123 | + if (err) | |
| 3124 | + goto err_none; | |
| 3125 | + | |
| 3126 | + return 0; | |
| 3127 | + | |
| 3128 | +err_none: | |
| 3129 | + unregister_md_submodule(&bitmap_none_ops.head); | |
| 3130 | +err_wq: | |
| 3131 | + destroy_workqueue(md_bitmap_wq); | |
| 3132 | + return err; | |
| 3027 | 3133 | } |
| 3028 | 3134 | |
| 3029 | 3135 | void md_bitmap_exit(void) |
| 3030 | 3136 | { |
| 3031 | − destroy_workqueue(md_bitmap_wq); | |
| 3032 | 3137 | unregister_md_submodule(&bitmap_ops.head); |
| 3138 | + unregister_md_submodule(&bitmap_none_ops.head); | |
| 3139 | + destroy_workqueue(md_bitmap_wq); | |
| 3033 | 3140 | } |
| @@ -125,7 +125,7 @@ struct bitmap_operations { · 124 unmodified lines | ||
| 125 | 125 | void (*set_pages)(void *data, unsigned long pages); |
| 126 | 126 | void (*free)(void *data); |
| 127 | 127 | |
| 128 | − struct attribute_group *group; | |
| 128 | + const struct attribute_group **groups; | |
| 129 | 129 | }; |
| 130 | 130 | |
| 131 | 131 | /* the bitmap API */ |
| @@ -1738,6 +1738,11 @@ static struct attribute_group md_llbitmap_group = { · 1737 unmodified lines | ||
| 1738 | 1738 | .attrs = md_llbitmap_attrs, |
| 1739 | 1739 | }; |
| 1740 | 1740 | |
| 1741 | +static const struct attribute_group *md_llbitmap_groups[] = { | |
| 1742 | + &md_llbitmap_group, | |
| 1743 | + NULL, | |
| 1744 | +}; | |
| 1745 | + | |
| 1741 | 1746 | static struct bitmap_operations llbitmap_ops = { |
| 1742 | 1747 | .head = { |
| 1743 | 1748 | .type = MD_BITMAP, |
| @@ -1774,7 +1779,7 @@ static struct bitmap_operations llbitmap_ops = { · 30 unmodified lines | ||
| 1774 | 1779 | .dirty_bits = llbitmap_dirty_bits, |
| 1775 | 1780 | .write_all = llbitmap_write_all, |
| 1776 | 1781 | |
| 1777 | − .group = &md_llbitmap_group, | |
| 1782 | + .groups = md_llbitmap_groups, | |
| 1778 | 1783 | }; |
| 1779 | 1784 | |
| 1780 | 1785 | int md_llbitmap_init(void) |
| @@ -396,27 +396,19 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio) · 395 unmodified lines | ||
| 396 | 396 | { |
| 397 | 397 | check_suspended: |
| 398 | 398 | if (is_suspended(mddev, bio)) { |
| 399 | − DEFINE_WAIT(__wait); | |
| 400 | 399 | /* Bail out if REQ_NOWAIT is set for the bio */ |
| 401 | 400 | if (bio->bi_opf & REQ_NOWAIT) { |
| 402 | 401 | bio_wouldblock_error(bio); |
| 403 | 402 | return true; |
| 404 | 403 | } |
| 405 | − for (;;) { | |
| 406 | − prepare_to_wait(&mddev->sb_wait, &__wait, | |
| 407 | − TASK_UNINTERRUPTIBLE); | |
| 408 | − if (!is_suspended(mddev, bio)) | |
| 409 | − break; | |
| 410 | − schedule(); | |
| 411 | − } | |
| 412 | − finish_wait(&mddev->sb_wait, &__wait); | |
| 404 | + wait_event(mddev->sb_wait, !is_suspended(mddev, bio)); | |
| 413 | 405 | } |
| 414 | 406 | if (!percpu_ref_tryget_live(&mddev->active_io)) |
| 415 | 407 | goto check_suspended; |
| 416 | 408 | |
| 417 | 409 | if (!mddev->pers->make_request(mddev, bio)) { |
| 418 | 410 | percpu_ref_put(&mddev->active_io); |
| 419 | − if (!mddev->gendisk && mddev->pers->prepare_suspend) | |
| 411 | + if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend) | |
| 420 | 412 | return false; |
| 421 | 413 | goto check_suspended; |
| 422 | 414 | } |
| @@ -687,13 +679,38 @@ static void active_io_release(struct percpu_ref *ref) · 264 unmodified lines | ||
| 687 | 679 | |
| 688 | 680 | static void no_op(struct percpu_ref *r) {} |
| 689 | 681 | |
| 690 | −static bool mddev_set_bitmap_ops(struct mddev *mddev) | |
| 682 | +static void md_bitmap_sysfs_add(struct mddev *mddev) | |
| 683 | +{ | |
| 684 | + if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups)) | |
| 685 | + pr_warn("md: cannot register extra bitmap attributes for %s\n", | |
| 686 | + mdname(mddev)); | |
| 687 | + else | |
| 688 | + /* | |
| 689 | + * Inform user with KOBJ_CHANGE about new bitmap | |
| 690 | + * attributes. | |
| 691 | + */ | |
| 692 | + kobject_uevent(&mddev->kobj, KOBJ_CHANGE); | |
| 693 | +} | |
| 694 | + | |
| 695 | +static void md_bitmap_sysfs_del(struct mddev *mddev) | |
| 696 | +{ | |
| 697 | + int nr_groups = 0; | |
| 698 | + | |
| 699 | + for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++) | |
| 700 | + ; | |
| 701 | + | |
| 702 | + while (--nr_groups >= 1) | |
| 703 | + sysfs_unmerge_group(&mddev->kobj, | |
| 704 | + mddev->bitmap_ops->groups[nr_groups]); | |
| 705 | + sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]); | |
| 706 | +} | |
| 707 | + | |
| 708 | +bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) | |
| 691 | 709 | { |
| 692 | − struct bitmap_operations *old = mddev->bitmap_ops; | |
| 693 | 710 | struct md_submodule_head *head; |
| 694 | 711 | |
| 695 | − if (mddev->bitmap_id == ID_BITMAP_NONE || | |
| 696 | − (old && old->head.id == mddev->bitmap_id)) | |
| 712 | + if (mddev->bitmap_ops && | |
| 713 | + mddev->bitmap_ops->head.id == mddev->bitmap_id) | |
| 697 | 714 | return true; |
| 698 | 715 | |
| 699 | 716 | xa_lock(&md_submodule); |
| @@ -711,18 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) · 11 unmodified lines | ||
| 711 | 728 | |
| 712 | 729 | mddev->bitmap_ops = (void *)head; |
| 713 | 730 | xa_unlock(&md_submodule); |
| 714 | − | |
| 715 | − if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) { | |
| 716 | − if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) | |
| 717 | − pr_warn("md: cannot register extra bitmap attributes for %s\n", | |
| 718 | − mdname(mddev)); | |
| 719 | − else | |
| 720 | − /* | |
| 721 | − * Inform user with KOBJ_CHANGE about new bitmap | |
| 722 | − * attributes. | |
| 723 | − */ | |
| 724 | − kobject_uevent(&mddev->kobj, KOBJ_CHANGE); | |
| 725 | − } | |
| 726 | 731 | return true; |
| 727 | 732 | |
| 728 | 733 | err: |
| @@ -730,15 +735,6 @@ err: · 1 unmodified line | ||
| 730 | 735 | return false; |
| 731 | 736 | } |
| 732 | 737 | |
| 733 | −static void mddev_clear_bitmap_ops(struct mddev *mddev) | |
| 734 | −{ | |
| 735 | − if (!mddev_is_dm(mddev) && mddev->bitmap_ops && | |
| 736 | − mddev->bitmap_ops->group) | |
| 737 | − sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); | |
| 738 | − | |
| 739 | − mddev->bitmap_ops = NULL; | |
| 740 | −} | |
| 741 | − | |
| 742 | 738 | int mddev_init(struct mddev *mddev) |
| 743 | 739 | { |
| 744 | 740 | int err = 0; |
| @@ -4279,7 +4275,7 @@ bitmap_type_show(struct mddev *mddev, char *page) · 3534 unmodified lines | ||
| 4279 | 4275 | |
| 4280 | 4276 | xa_lock(&md_submodule); |
| 4281 | 4277 | xa_for_each(&md_submodule, i, head) { |
| 4282 | − if (head->type != MD_BITMAP) | |
| 4278 | + if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE) | |
| 4283 | 4279 | continue; |
| 4284 | 4280 | |
| 4285 | 4281 | if (mddev->bitmap_id == head->id) |
| @@ -6059,10 +6055,7 @@ static struct attribute *md_default_attrs[] = { · 1773 unmodified lines | ||
| 6059 | 6055 | &md_logical_block_size.attr, |
| 6060 | 6056 | NULL, |
| 6061 | 6057 | }; |
| 6062 | − | |
| 6063 | −static const struct attribute_group md_default_group = { | |
| 6064 | − .attrs = md_default_attrs, | |
| 6065 | −}; | |
| 6058 | +ATTRIBUTE_GROUPS(md_default); | |
| 6066 | 6059 | |
| 6067 | 6060 | static struct attribute *md_redundancy_attrs[] = { |
| 6068 | 6061 | &md_scan_mode.attr, |
| @@ -6087,11 +6080,6 @@ static const struct attribute_group md_redundancy_group = { · 18 unmodified lines | ||
| 6087 | 6080 | .attrs = md_redundancy_attrs, |
| 6088 | 6081 | }; |
| 6089 | 6082 | |
| 6090 | −static const struct attribute_group *md_attr_groups[] = { | |
| 6091 | − &md_default_group, | |
| 6092 | − NULL, | |
| 6093 | −}; | |
| 6094 | − | |
| 6095 | 6083 | static ssize_t |
| 6096 | 6084 | md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) |
| 6097 | 6085 | { |
| @@ -6174,7 +6162,7 @@ static const struct sysfs_ops md_sysfs_ops = { · 76 unmodified lines | ||
| 6174 | 6162 | static const struct kobj_type md_ktype = { |
| 6175 | 6163 | .release = md_kobj_release, |
| 6176 | 6164 | .sysfs_ops = &md_sysfs_ops, |
| 6177 | − .default_groups = md_attr_groups, | |
| 6165 | + .default_groups = md_default_groups, | |
| 6178 | 6166 | }; |
| 6179 | 6167 | |
| 6180 | 6168 | int mdp_major = 0; |
| @@ -6539,7 +6527,7 @@ out: · 358 unmodified lines | ||
| 6539 | 6527 | return id; |
| 6540 | 6528 | } |
| 6541 | 6529 | |
| 6542 | −static int md_bitmap_create(struct mddev *mddev) | |
| 6530 | +int md_bitmap_create_nosysfs(struct mddev *mddev) | |
| 6543 | 6531 | { |
| 6544 | 6532 | enum md_submodule_id orig_id = mddev->bitmap_id; |
| 6545 | 6533 | enum md_submodule_id sb_id; |
| @@ -6548,8 +6536,10 @@ static int md_bitmap_create(struct mddev *mddev) · 2 unmodified lines | ||
| 6548 | 6536 | if (mddev->bitmap_id == ID_BITMAP_NONE) |
| 6549 | 6537 | return -EINVAL; |
| 6550 | 6538 | |
| 6551 | − if (!mddev_set_bitmap_ops(mddev)) | |
| 6539 | + if (!mddev_set_bitmap_ops_nosysfs(mddev)) { | |
| 6540 | + mddev->bitmap_id = orig_id; | |
| 6552 | 6541 | return -ENOENT; |
| 6542 | + } | |
| 6553 | 6543 | |
| 6554 | 6544 | err = mddev->bitmap_ops->create(mddev); |
| 6555 | 6545 | if (!err) |
| @@ -6560,37 +6550,72 @@ static int md_bitmap_create(struct mddev *mddev) · 4 unmodified lines | ||
| 6560 | 6550 | * doesn't match, and mdadm is not the latest version to set |
| 6561 | 6551 | * bitmap_type, set bitmap_ops based on the disk version. |
| 6562 | 6552 | */ |
| 6563 | − mddev_clear_bitmap_ops(mddev); | |
| 6553 | + mddev->bitmap_ops = NULL; | |
| 6564 | 6554 | |
| 6565 | 6555 | sb_id = md_bitmap_get_id_from_sb(mddev); |
| 6566 | − if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) | |
| 6556 | + if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) { | |
| 6557 | + mddev->bitmap_id = orig_id; | |
| 6567 | 6558 | return err; |
| 6559 | + } | |
| 6568 | 6560 | |
| 6569 | 6561 | pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", |
| 6570 | 6562 | mdname(mddev), orig_id, sb_id); |
| 6571 | 6563 | |
| 6572 | 6564 | mddev->bitmap_id = sb_id; |
| 6573 | − if (!mddev_set_bitmap_ops(mddev)) { | |
| 6565 | + if (!mddev_set_bitmap_ops_nosysfs(mddev)) { | |
| 6574 | 6566 | mddev->bitmap_id = orig_id; |
| 6575 | 6567 | return -ENOENT; |
| 6576 | 6568 | } |
| 6577 | 6569 | |
| 6578 | 6570 | err = mddev->bitmap_ops->create(mddev); |
| 6579 | 6571 | if (err) { |
| 6580 | − mddev_clear_bitmap_ops(mddev); | |
| 6572 | + mddev->bitmap_ops = NULL; | |
| 6581 | 6573 | mddev->bitmap_id = orig_id; |
| 6582 | 6574 | } |
| 6583 | 6575 | |
| 6584 | 6576 | return err; |
| 6585 | 6577 | } |
| 6586 | 6578 | |
| 6587 | −static void md_bitmap_destroy(struct mddev *mddev) | |
| 6579 | +static int md_bitmap_create(struct mddev *mddev) | |
| 6580 | +{ | |
| 6581 | + int err; | |
| 6582 | + | |
| 6583 | + err = md_bitmap_create_nosysfs(mddev); | |
| 6584 | + if (err) | |
| 6585 | + return err; | |
| 6586 | + | |
| 6587 | + if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups) | |
| 6588 | + md_bitmap_sysfs_add(mddev); | |
| 6589 | + | |
| 6590 | + return 0; | |
| 6591 | +} | |
| 6592 | + | |
| 6593 | +void md_bitmap_destroy_nosysfs(struct mddev *mddev) | |
| 6588 | 6594 | { |
| 6589 | 6595 | if (!md_bitmap_registered(mddev)) |
| 6590 | 6596 | return; |
| 6591 | 6597 | |
| 6592 | 6598 | mddev->bitmap_ops->destroy(mddev); |
| 6593 | − mddev_clear_bitmap_ops(mddev); | |
| 6599 | + mddev->bitmap_ops = NULL; | |
| 6600 | +} | |
| 6601 | + | |
| 6602 | +static void md_bitmap_destroy(struct mddev *mddev) | |
| 6603 | +{ | |
| 6604 | + if (!mddev_is_dm(mddev) && mddev->bitmap_ops && | |
| 6605 | + mddev->bitmap_ops->groups) | |
| 6606 | + md_bitmap_sysfs_del(mddev); | |
| 6607 | + | |
| 6608 | + md_bitmap_destroy_nosysfs(mddev); | |
| 6609 | +} | |
| 6610 | + | |
| 6611 | +static void md_bitmap_set_none(struct mddev *mddev) | |
| 6612 | +{ | |
| 6613 | + mddev->bitmap_id = ID_BITMAP_NONE; | |
| 6614 | + if (!mddev_set_bitmap_ops_nosysfs(mddev)) | |
| 6615 | + return; | |
| 6616 | + | |
| 6617 | + if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups) | |
| 6618 | + md_bitmap_sysfs_add(mddev); | |
| 6594 | 6619 | } |
| 6595 | 6620 | |
| 6596 | 6621 | int md_run(struct mddev *mddev) |
| @@ -6713,7 +6738,7 @@ int md_run(struct mddev *mddev) · 116 unmodified lines | ||
| 6713 | 6738 | } |
| 6714 | 6739 | |
| 6715 | 6740 | /* dm-raid expect sync_thread to be frozen until resume */ |
| 6716 | − if (mddev->gendisk) | |
| 6741 | + if (!mddev_is_dm(mddev)) | |
| 6717 | 6742 | mddev->recovery = 0; |
| 6718 | 6743 | |
| 6719 | 6744 | /* may be over-ridden by personality */ |
| @@ -6802,6 +6827,10 @@ int md_run(struct mddev *mddev) · 82 unmodified lines | ||
| 6802 | 6827 | if (mddev->sb_flags) |
| 6803 | 6828 | md_update_sb(mddev, 0); |
| 6804 | 6829 | |
| 6830 | + if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file && | |
| 6831 | + !mddev->bitmap_info.offset) | |
| 6832 | + md_bitmap_set_none(mddev); | |
| 6833 | + | |
| 6805 | 6834 | md_new_event(); |
| 6806 | 6835 | return 0; |
| 6807 | 6836 | |
| @@ -7747,7 +7776,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd) · 939 unmodified lines | ||
| 7747 | 7776 | { |
| 7748 | 7777 | int err = 0; |
| 7749 | 7778 | |
| 7750 | − if (!md_bitmap_registered(mddev)) | |
| 7779 | + if (!md_bitmap_registered(mddev) || | |
| 7780 | + mddev->bitmap_id == ID_BITMAP_NONE) | |
| 7751 | 7781 | return -EINVAL; |
| 7752 | 7782 | |
| 7753 | 7783 | if (mddev->pers) { |
| @@ -7812,10 +7842,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd) · 58 unmodified lines | ||
| 7812 | 7842 | |
| 7813 | 7843 | if (err) { |
| 7814 | 7844 | md_bitmap_destroy(mddev); |
| 7845 | + md_bitmap_set_none(mddev); | |
| 7815 | 7846 | fd = -1; |
| 7816 | 7847 | } |
| 7817 | 7848 | } else if (fd < 0) { |
| 7818 | 7849 | md_bitmap_destroy(mddev); |
| 7850 | + md_bitmap_set_none(mddev); | |
| 7819 | 7851 | } |
| 7820 | 7852 | } |
| 7821 | 7853 | |
| @@ -8122,12 +8154,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) · 300 unmodified lines | ||
| 8122 | 8154 | mddev->bitmap_info.default_offset; |
| 8123 | 8155 | mddev->bitmap_info.space = |
| 8124 | 8156 | mddev->bitmap_info.default_space; |
| 8157 | + mddev->bitmap_id = ID_BITMAP; | |
| 8125 | 8158 | rv = md_bitmap_create(mddev); |
| 8126 | 8159 | if (!rv) |
| 8127 | 8160 | rv = mddev->bitmap_ops->load(mddev); |
| 8128 | 8161 | |
| 8129 | − if (rv) | |
| 8162 | + if (rv) { | |
| 8130 | 8163 | md_bitmap_destroy(mddev); |
| 8164 | + mddev->bitmap_info.offset = 0; | |
| 8165 | + md_bitmap_set_none(mddev); | |
| 8166 | + } | |
| 8131 | 8167 | } else { |
| 8132 | 8168 | struct md_bitmap_stats stats; |
| 8133 | 8169 | |
| @@ -8155,6 +8191,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) · 21 unmodified lines | ||
| 8155 | 8191 | } |
| 8156 | 8192 | md_bitmap_destroy(mddev); |
| 8157 | 8193 | mddev->bitmap_info.offset = 0; |
| 8194 | + md_bitmap_set_none(mddev); | |
| 8158 | 8195 | } |
| 8159 | 8196 | } |
| 8160 | 8197 | md_update_sb(mddev, 1); |
| @@ -9341,9 +9378,11 @@ static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone) · 1180 unmodified lines | ||
| 9341 | 9378 | |
| 9342 | 9379 | static void md_end_clone_io(struct bio *bio) |
| 9343 | 9380 | { |
| 9344 | − struct md_io_clone *md_io_clone = bio->bi_private; | |
| 9381 | + struct md_io_clone *md_io_clone = container_of(bio, struct md_io_clone, | |
| 9382 | + bio_clone); | |
| 9345 | 9383 | struct bio *orig_bio = md_io_clone->orig_bio; |
| 9346 | 9384 | struct mddev *mddev = md_io_clone->mddev; |
| 9385 | + struct completion *reshape_completion = bio->bi_private; | |
| 9347 | 9386 | |
| 9348 | 9387 | if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) |
| 9349 | 9388 | md_bitmap_end(mddev, md_io_clone); |
| @@ -9355,7 +9394,10 @@ static void md_end_clone_io(struct bio *bio) · 5 unmodified lines | ||
| 9355 | 9394 | bio_end_io_acct(orig_bio, md_io_clone->start_time); |
| 9356 | 9395 | |
| 9357 | 9396 | bio_put(bio); |
| 9358 | − bio_endio(orig_bio); | |
| 9397 | + if (unlikely(reshape_completion)) | |
| 9398 | + complete(reshape_completion); | |
| 9399 | + else | |
| 9400 | + bio_endio(orig_bio); | |
| 9359 | 9401 | percpu_ref_put(&mddev->active_io); |
| 9360 | 9402 | } |
| 9361 | 9403 | |
| @@ -9380,7 +9422,7 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio) · 18 unmodified lines | ||
| 9380 | 9422 | } |
| 9381 | 9423 | |
| 9382 | 9424 | clone->bi_end_io = md_end_clone_io; |
| 9383 | − clone->bi_private = md_io_clone; | |
| 9425 | + clone->bi_private = NULL; | |
| 9384 | 9426 | *bio = clone; |
| 9385 | 9427 | } |
| 9386 | 9428 | |
| @@ -9391,26 +9433,6 @@ void md_account_bio(struct mddev *mddev, struct bio **bio) · 4 unmodified lines | ||
| 9391 | 9433 | } |
| 9392 | 9434 | EXPORT_SYMBOL_GPL(md_account_bio); |
| 9393 | 9435 | |
| 9394 | −void md_free_cloned_bio(struct bio *bio) | |
| 9395 | −{ | |
| 9396 | − struct md_io_clone *md_io_clone = bio->bi_private; | |
| 9397 | − struct bio *orig_bio = md_io_clone->orig_bio; | |
| 9398 | − struct mddev *mddev = md_io_clone->mddev; | |
| 9399 | − | |
| 9400 | − if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) | |
| 9401 | − md_bitmap_end(mddev, md_io_clone); | |
| 9402 | − | |
| 9403 | − if (bio->bi_status && !orig_bio->bi_status) | |
| 9404 | − orig_bio->bi_status = bio->bi_status; | |
| 9405 | − | |
| 9406 | − if (md_io_clone->start_time) | |
| 9407 | − bio_end_io_acct(orig_bio, md_io_clone->start_time); | |
| 9408 | − | |
| 9409 | − bio_put(bio); | |
| 9410 | − percpu_ref_put(&mddev->active_io); | |
| 9411 | −} | |
| 9412 | −EXPORT_SYMBOL_GPL(md_free_cloned_bio); | |
| 9413 | − | |
| 9414 | 9436 | /* md_allow_write(mddev) |
| 9415 | 9437 | * Calling this ensures that the array is marked 'active' so that writes |
| 9416 | 9438 | * may proceed without blocking. It is important to call this before |
| @@ -920,7 +920,6 @@ extern void md_finish_reshape(struct mddev *mddev); · 919 unmodified lines | ||
| 920 | 920 | void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev, |
| 921 | 921 | struct bio *bio, sector_t start, sector_t size); |
| 922 | 922 | void md_account_bio(struct mddev *mddev, struct bio **bio); |
| 923 | −void md_free_cloned_bio(struct bio *bio); | |
| 924 | 923 | |
| 925 | 924 | extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio); |
| 926 | 925 | void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev, |
| @@ -935,6 +934,9 @@ extern void md_allow_write(struct mddev *mddev); · 8 unmodified lines | ||
| 935 | 934 | extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev); |
| 936 | 935 | extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors); |
| 937 | 936 | extern int md_check_no_bitmap(struct mddev *mddev); |
| 937 | +bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev); | |
| 938 | +int md_bitmap_create_nosysfs(struct mddev *mddev); | |
| 939 | +void md_bitmap_destroy_nosysfs(struct mddev *mddev); | |
| 938 | 940 | extern int md_integrity_register(struct mddev *mddev); |
| 939 | 941 | extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); |
| 940 | 942 | |
| @@ -1015,7 +1017,7 @@ static inline int mddev_suspend_and_lock(struct mddev *mddev) · 74 unmodified lines | ||
| 1015 | 1017 | static inline void mddev_suspend_and_lock_nointr(struct mddev *mddev) |
| 1016 | 1018 | { |
| 1017 | 1019 | mddev_suspend(mddev, false); |
| 1018 | − mutex_lock(&mddev->reconfig_mutex); | |
| 1020 | + mddev_lock_nointr(mddev); | |
| 1019 | 1021 | } |
| 1020 | 1022 | |
| 1021 | 1023 | static inline void mddev_unlock_and_resume(struct mddev *mddev) |
| @@ -490,12 +490,20 @@ static int rebalance_children(struct shadow_spine *s, · 489 unmodified lines | ||
| 490 | 490 | |
| 491 | 491 | if (le32_to_cpu(n->header.nr_entries) == 1) { |
| 492 | 492 | struct dm_block *child; |
| 493 | + int is_shared; | |
| 493 | 494 | dm_block_t b = value64(n, 0); |
| 494 | 495 | |
| 496 | + r = dm_tm_block_is_shared(info->tm, b, &is_shared); | |
| 497 | + if (r) | |
| 498 | + return r; | |
| 499 | + | |
| 495 | 500 | r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child); |
| 496 | 501 | if (r) |
| 497 | 502 | return r; |
| 498 | 503 | |
| 504 | + if (is_shared) | |
| 505 | + inc_children(info->tm, dm_block_data(child), vt); | |
| 506 | + | |
| 499 | 507 | memcpy(n, dm_block_data(child), |
| 500 | 508 | dm_bm_block_size(dm_tm_get_bm(info->tm))); |
| 501 | 509 | |
| @@ -293,8 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev, · 292 unmodified lines | ||
| 293 | 293 | * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is |
| 294 | 294 | * submitted to the underlying disks, hence don't record badblocks or retry |
| 295 | 295 | * in this case. |
| 296 | + * | |
| 297 | + * BLK_STS_INVAL means the bio was not valid for the underlying device. This | |
| 298 | + * is a user error, not a device failure, so retrying or recording bad blocks | |
| 299 | + * would be wrong. | |
| 296 | 300 | */ |
| 297 | 301 | static inline bool raid1_should_handle_error(struct bio *bio) |
| 298 | 302 | { |
| 299 | − return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)); | |
| 303 | + return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) && | |
| 304 | + bio->bi_status != BLK_STS_INVAL; | |
| 300 | 305 | } |
| @@ -1510,21 +1510,14 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, · 1509 unmodified lines | ||
| 1510 | 1510 | mddev->cluster_ops->area_resyncing(mddev, WRITE, |
| 1511 | 1511 | bio->bi_iter.bi_sector, bio_end_sector(bio))) { |
| 1512 | 1512 | |
| 1513 | − DEFINE_WAIT(w); | |
| 1514 | 1513 | if (bio->bi_opf & REQ_NOWAIT) { |
| 1515 | 1514 | bio_wouldblock_error(bio); |
| 1516 | 1515 | return; |
| 1517 | 1516 | } |
| 1518 | − for (;;) { | |
| 1519 | − prepare_to_wait(&conf->wait_barrier, | |
| 1520 | − &w, TASK_IDLE); | |
| 1521 | − if (!mddev->cluster_ops->area_resyncing(mddev, WRITE, | |
| 1522 | − bio->bi_iter.bi_sector, | |
| 1523 | − bio_end_sector(bio))) | |
| 1524 | − break; | |
| 1525 | − schedule(); | |
| 1526 | − } | |
| 1527 | − finish_wait(&conf->wait_barrier, &w); | |
| 1517 | + wait_event_idle(conf->wait_barrier, | |
| 1518 | + !mddev->cluster_ops->area_resyncing(mddev, WRITE, | |
| 1519 | + bio->bi_iter.bi_sector, | |
| 1520 | + bio_end_sector(bio))); | |
| 1528 | 1521 | } |
| 1529 | 1522 | |
| 1530 | 1523 | /* |
| @@ -3791,6 +3791,8 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new) · 3790 unmodified lines | ||
| 3791 | 3791 | nc = layout & 255; |
| 3792 | 3792 | fc = (layout >> 8) & 255; |
| 3793 | 3793 | fo = layout & (1<<16); |
| 3794 | + if (!nc || !fc) | |
| 3795 | + return -1; | |
| 3794 | 3796 | geo->raid_disks = disks; |
| 3795 | 3797 | geo->near_copies = nc; |
| 3796 | 3798 | geo->far_copies = fc; |
| @@ -6217,7 +6217,12 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) · 6216 unmodified lines | ||
| 6217 | 6217 | |
| 6218 | 6218 | mempool_free(ctx, conf->ctx_pool); |
| 6219 | 6219 | if (res == STRIPE_WAIT_RESHAPE) { |
| 6220 | − md_free_cloned_bio(bi); | |
| 6220 | + DECLARE_COMPLETION_ONSTACK(done); | |
| 6221 | + WRITE_ONCE(bi->bi_private, &done); | |
| 6222 | + | |
| 6223 | + bio_endio(bi); | |
| 6224 | + | |
| 6225 | + wait_for_completion(&done); | |
| 6221 | 6226 | return false; |
| 6222 | 6227 | } |
| 6223 | 6228 | |
| @@ -71,7 +71,7 @@ config MTD_NAND_AU1550 · 70 unmodified lines | ||
| 71 | 71 | |
| 72 | 72 | config MTD_NAND_NDFC |
| 73 | 73 | tristate "IBM/MCC 4xx NAND controller" |
| 74 | − depends on 4xx | |
| 74 | + depends on 44x || COMPILE_TEST | |
| 75 | 75 | select MTD_NAND_ECC_SW_HAMMING |
| 76 | 76 | select MTD_NAND_ECC_SW_HAMMING_SMC |
| 77 | 77 | help |
| @@ -175,7 +175,7 @@ void nand_select_target(struct nand_chip *chip, unsigned int cs) · 174 unmodified lines | ||
| 175 | 175 | * cs should always lie between 0 and nanddev_ntargets(), when that's |
| 176 | 176 | * not the case it's a bug and the caller should be fixed. |
| 177 | 177 | */ |
| 178 | − if (WARN_ON(cs > nanddev_ntargets(&chip->base))) | |
| 178 | + if (WARN_ON(cs >= nanddev_ntargets(&chip->base))) | |
| 179 | 179 | return; |
| 180 | 180 | |
| 181 | 181 | chip->cur_cs = cs; |
| @@ -1216,32 +1216,32 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page, · 1034 unmodified lines | ||
| 1216 | 1216 | return nand_exec_op(chip, &op); |
| 1217 | 1217 | } |
| 1218 | 1218 | |
| 1219 | −static unsigned int rawnand_last_page_of_lun(unsigned int pages_per_lun, unsigned int lun) | |
| 1219 | +static unsigned int rawnand_last_page_of_block(unsigned int ppb, unsigned int block) | |
| 1220 | 1220 | { |
| 1221 | − /* lun is expected to be very small */ | |
| 1222 | − return (lun * pages_per_lun) + pages_per_lun - 1; | |
| 1221 | + /* block is expected to be very small */ | |
| 1222 | + return (block * ppb) + ppb - 1; | |
| 1223 | 1223 | } |
| 1224 | 1224 | |
| 1225 | 1225 | static void rawnand_cap_cont_reads(struct nand_chip *chip) |
| 1226 | 1226 | { |
| 1227 | 1227 | struct nand_memory_organization *memorg; |
| 1228 | − unsigned int ppl, first_lun, last_lun; | |
| 1228 | + unsigned int ppb, first_block, last_block; | |
| 1229 | 1229 | |
| 1230 | 1230 | memorg = nanddev_get_memorg(&chip->base); |
| 1231 | − ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun; | |
| 1232 | − first_lun = chip->cont_read.first_page / ppl; | |
| 1233 | − last_lun = chip->cont_read.last_page / ppl; | |
| 1231 | + ppb = memorg->pages_per_eraseblock; | |
| 1232 | + first_block = chip->cont_read.first_page / ppb; | |
| 1233 | + last_block = chip->cont_read.last_page / ppb; | |
| 1234 | 1234 | |
| 1235 | − /* Prevent sequential cache reads across LUN boundaries */ | |
| 1236 | − if (first_lun != last_lun) | |
| 1237 | − chip->cont_read.pause_page = rawnand_last_page_of_lun(ppl, first_lun); | |
| 1235 | + /* Prevent sequential cache reads across block boundaries */ | |
| 1236 | + if (first_block != last_block) | |
| 1237 | + chip->cont_read.pause_page = rawnand_last_page_of_block(ppb, first_block); | |
| 1238 | 1238 | else |
| 1239 | 1239 | chip->cont_read.pause_page = chip->cont_read.last_page; |
| 1240 | 1240 | |
| 1241 | 1241 | if (chip->cont_read.first_page == chip->cont_read.pause_page) { |
| 1242 | 1242 | chip->cont_read.first_page++; |
| 1243 | 1243 | chip->cont_read.pause_page = min(chip->cont_read.last_page, |
| 1244 | − rawnand_last_page_of_lun(ppl, first_lun + 1)); | |
| 1244 | + rawnand_last_page_of_block(ppb, first_block + 1)); | |
| 1245 | 1245 | } |
| 1246 | 1246 | |
| 1247 | 1247 | if (chip->cont_read.first_page >= chip->cont_read.last_page) |
| @@ -44,13 +44,13 @@ static void ndfc_select_chip(struct nand_chip *nchip, int chip) · 43 unmodified lines | ||
| 44 | 44 | uint32_t ccr; |
| 45 | 45 | struct ndfc_controller *ndfc = nand_get_controller_data(nchip); |
| 46 | 46 | |
| 47 | − ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); | |
| 47 | + ccr = ioread32be(ndfc->ndfcbase + NDFC_CCR); | |
| 48 | 48 | if (chip >= 0) { |
| 49 | 49 | ccr &= ~NDFC_CCR_BS_MASK; |
| 50 | 50 | ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); |
| 51 | 51 | } else |
| 52 | 52 | ccr |= NDFC_CCR_RESET_CE; |
| 53 | − out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); | |
| 53 | + iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR); | |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | 56 | static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) |
| @@ -70,7 +70,7 @@ static int ndfc_ready(struct nand_chip *chip) · 13 unmodified lines | ||
| 70 | 70 | { |
| 71 | 71 | struct ndfc_controller *ndfc = nand_get_controller_data(chip); |
| 72 | 72 | |
| 73 | − return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; | |
| 73 | + return ioread32be(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; | |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | static void ndfc_enable_hwecc(struct nand_chip *chip, int mode) |
| @@ -78,9 +78,9 @@ static void ndfc_enable_hwecc(struct nand_chip *chip, int mode) · 1 unmodified line | ||
| 78 | 78 | uint32_t ccr; |
| 79 | 79 | struct ndfc_controller *ndfc = nand_get_controller_data(chip); |
| 80 | 80 | |
| 81 | − ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); | |
| 81 | + ccr = ioread32be(ndfc->ndfcbase + NDFC_CCR); | |
| 82 | 82 | ccr |= NDFC_CCR_RESET_ECC; |
| 83 | − out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); | |
| 83 | + iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR); | |
| 84 | 84 | wmb(); |
| 85 | 85 | } |
| 86 | 86 | |
| @@ -92,7 +92,7 @@ static int ndfc_calculate_ecc(struct nand_chip *chip, · 5 unmodified lines | ||
| 92 | 92 | uint8_t *p = (uint8_t *)&ecc; |
| 93 | 93 | |
| 94 | 94 | wmb(); |
| 95 | − ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); | |
| 95 | + ecc = ioread32be(ndfc->ndfcbase + NDFC_ECC); | |
| 96 | 96 | /* The NDFC uses Smart Media (SMC) bytes order */ |
| 97 | 97 | ecc_code[0] = p[1]; |
| 98 | 98 | ecc_code[1] = p[2]; |
| @@ -114,7 +114,7 @@ static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) · 15 unmodified lines | ||
| 114 | 114 | uint32_t *p = (uint32_t *) buf; |
| 115 | 115 | |
| 116 | 116 | for(;len > 0; len -= 4) |
| 117 | − *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); | |
| 117 | + *p++ = ioread32be(ndfc->ndfcbase + NDFC_DATA); | |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | 120 | static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) |
| @@ -123,7 +123,7 @@ static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) · 2 unmodified lines | ||
| 123 | 123 | uint32_t *p = (uint32_t *) buf; |
| 124 | 124 | |
| 125 | 125 | for(;len > 0; len -= 4) |
| 126 | − out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); | |
| 126 | + iowrite32be(*p++, ndfc->ndfcbase + NDFC_DATA); | |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | /* |
| @@ -223,13 +223,13 @@ static int ndfc_probe(struct platform_device *ofdev) · 93 unmodified lines | ||
| 223 | 223 | if (reg) |
| 224 | 224 | ccr |= be32_to_cpup(reg); |
| 225 | 225 | |
| 226 | − out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); | |
| 226 | + iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR); | |
| 227 | 227 | |
| 228 | 228 | /* Set the bank settings if given */ |
| 229 | 229 | reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); |
| 230 | 230 | if (reg) { |
| 231 | 231 | int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); |
| 232 | − out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg)); | |
| 232 | + iowrite32be(be32_to_cpup(reg), ndfc->ndfcbase + offset); | |
| 233 | 233 | } |
| 234 | 234 | |
| 235 | 235 | err = ndfc_chip_init(ndfc, ofdev->dev.of_node); |
| @@ -1155,7 +1155,7 @@ static int pl35x_nand_probe(struct platform_device *pdev) · 1154 unmodified lines | ||
| 1155 | 1155 | nfc->controller.ops = &pl35x_nandc_ops; |
| 1156 | 1156 | INIT_LIST_HEAD(&nfc->chips); |
| 1157 | 1157 | |
| 1158 | − nfc->conf_regs = devm_ioremap_resource(&smc_amba->dev, &smc_amba->res); | |
| 1158 | + nfc->conf_regs = devm_ioremap_resource(nfc->dev, &smc_amba->res); | |
| 1159 | 1159 | if (IS_ERR(nfc->conf_regs)) |
| 1160 | 1160 | return PTR_ERR(nfc->conf_regs); |
| 1161 | 1161 | |
| @@ -128,8 +128,8 @@ static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) · 127 unmodified lines | ||
| 128 | 128 | static struct qcom_nand_controller * |
| 129 | 129 | get_qcom_nand_controller(struct nand_chip *chip) |
| 130 | 130 | { |
| 131 | − return (struct qcom_nand_controller *) | |
| 132 | − ((u8 *)chip->controller - sizeof(struct qcom_nand_controller)); | |
| 131 | + return container_of(chip->controller, struct qcom_nand_controller, | |
| 132 | + controller); | |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | 135 | static u32 nandc_read(struct qcom_nand_controller *nandc, int offset) |
| @@ -2034,8 +2034,8 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) · 1898 unmodified lines | ||
| 2034 | 2034 | { |
| 2035 | 2035 | u32 nand_ctrl; |
| 2036 | 2036 | |
| 2037 | − nand_controller_init(nandc->controller); | |
| 2038 | − nandc->controller->ops = &qcom_nandc_ops; | |
| 2037 | + nand_controller_init(&nandc->controller); | |
| 2038 | + nandc->controller.ops = &qcom_nandc_ops; | |
| 2039 | 2039 | |
| 2040 | 2040 | /* kill onenand */ |
| 2041 | 2041 | if (!nandc->props->nandc_part_of_qpic) |
| @@ -2175,7 +2175,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, · 133 unmodified lines | ||
| 2175 | 2175 | chip->legacy.block_bad = qcom_nandc_block_bad; |
| 2176 | 2176 | chip->legacy.block_markbad = qcom_nandc_block_markbad; |
| 2177 | 2177 | |
| 2178 | − chip->controller = nandc->controller; | |
| 2178 | + chip->controller = &nandc->controller; | |
| 2179 | 2179 | chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA | |
| 2180 | 2180 | NAND_SKIP_BBTSCAN; |
| 2181 | 2181 | |
| @@ -2256,21 +2256,17 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) · 74 unmodified lines | ||
| 2256 | 2256 | static int qcom_nandc_probe(struct platform_device *pdev) |
| 2257 | 2257 | { |
| 2258 | 2258 | struct qcom_nand_controller *nandc; |
| 2259 | − struct nand_controller *controller; | |
| 2260 | 2259 | const void *dev_data; |
| 2261 | 2260 | struct device *dev = &pdev->dev; |
| 2262 | 2261 | struct resource *res; |
| 2263 | 2262 | int ret; |
| 2264 | 2263 | |
| 2265 | − nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller), | |
| 2266 | − GFP_KERNEL); | |
| 2264 | + nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL); | |
| 2267 | 2265 | if (!nandc) |
| 2268 | 2266 | return -ENOMEM; |
| 2269 | − controller = (struct nand_controller *)&nandc[1]; | |
| 2270 | 2267 | |
| 2271 | 2268 | platform_set_drvdata(pdev, nandc); |
| 2272 | 2269 | nandc->dev = dev; |
| 2273 | − nandc->controller = controller; | |
| 2274 | 2270 | |
| 2275 | 2271 | dev_data = of_device_get_match_data(dev); |
| 2276 | 2272 | if (!dev_data) { |
| @@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr) · 99 unmodified lines | ||
| 100 | 100 | return op; |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | +static struct spi_mem_op | |
| 104 | +spinand_fill_page_read_packed_op(struct spinand_device *spinand, u64 addr) | |
| 105 | +{ | |
| 106 | + struct spi_mem_op op = spinand->op_templates->page_read; | |
| 107 | + | |
| 108 | + op.cmd.opcode |= addr >> 16; | |
| 109 | + op.addr.val = addr & 0xFFFF; | |
| 110 | + | |
| 111 | + return op; | |
| 112 | +} | |
| 113 | + | |
| 103 | 114 | struct spi_mem_op |
| 104 | 115 | spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr) |
| 105 | 116 | { |
| @@ -453,7 +464,10 @@ static int spinand_load_page_op(struct spinand_device *spinand, · 347 unmodified lines | ||
| 453 | 464 | { |
| 454 | 465 | struct nand_device *nand = spinand_to_nand(spinand); |
| 455 | 466 | unsigned int row = nanddev_pos_to_row(nand, &req->pos); |
| 456 | − struct spi_mem_op op = SPINAND_OP(spinand, page_read, row); | |
| 467 | + bool packed = spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ; | |
| 468 | + struct spi_mem_op op = packed ? | |
| 469 | + SPINAND_OP(spinand, page_read_packed, row) : | |
| 470 | + SPINAND_OP(spinand, page_read, row); | |
| 457 | 471 | |
| 458 | 472 | return spi_mem_exec_op(spinand->spimem, &op); |
| 459 | 473 | } |
| @@ -487,10 +501,18 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, · 27 unmodified lines | ||
| 487 | 501 | } |
| 488 | 502 | } |
| 489 | 503 | |
| 490 | − if (req->mode == MTD_OPS_RAW) | |
| 491 | − rdesc = spinand->dirmaps[req->pos.plane].rdesc; | |
| 504 | + rdesc = spinand->dirmaps[req->pos.plane].rdesc; | |
| 505 | + | |
| 506 | + if (spinand->op_templates->cont_read_cache && req->continuous) | |
| 507 | + rdesc->info.op_tmpl = &rdesc->info.secondary_op_tmpl; | |
| 508 | + else | |
| 509 | + rdesc->info.op_tmpl = &rdesc->info.primary_op_tmpl; | |
| 510 | + | |
| 511 | + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && | |
| 512 | + req->mode != MTD_OPS_RAW) | |
| 513 | + rdesc->info.op_tmpl->data.ecc = true; | |
| 492 | 514 | else |
| 493 | − rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc; | |
| 515 | + rdesc->info.op_tmpl->data.ecc = false; | |
| 494 | 516 | |
| 495 | 517 | if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) |
| 496 | 518 | column |= req->pos.plane << fls(nanddev_page_size(nand)); |
| @@ -579,10 +601,13 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, · 82 unmodified lines | ||
| 579 | 601 | req->ooblen); |
| 580 | 602 | } |
| 581 | 603 | |
| 582 | − if (req->mode == MTD_OPS_RAW) | |
| 583 | − wdesc = spinand->dirmaps[req->pos.plane].wdesc; | |
| 604 | + wdesc = spinand->dirmaps[req->pos.plane].wdesc; | |
| 605 | + | |
| 606 | + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED && | |
| 607 | + req->mode != MTD_OPS_RAW) | |
| 608 | + wdesc->info.op_tmpl->data.ecc = true; | |
| 584 | 609 | else |
| 585 | − wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc; | |
| 610 | + wdesc->info.op_tmpl->data.ecc = false; | |
| 586 | 611 | |
| 587 | 612 | if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) |
| 588 | 613 | column |= req->pos.plane << fls(nanddev_page_size(nand)); |
| @@ -878,6 +903,12 @@ static int spinand_mtd_continuous_page_read(struct mtd_info *mtd, loff_t from, · 289 unmodified lines | ||
| 878 | 903 | * Each data read must be a multiple of 4-bytes and full pages should be read; |
| 879 | 904 | * otherwise, the data output might get out of sequence from one read command |
| 880 | 905 | * to another. |
| 906 | + * | |
| 907 | + * Continuous reads never cross LUN boundaries. Some devices don't | |
| 908 | + * support crossing planes boundaries. Some devices don't even support | |
| 909 | + * crossing blocks boundaries. The common case being to read through UBI, | |
| 910 | + * we will very rarely read two consequent blocks or more, so let's only enable | |
| 911 | + * continuous reads when reading within the same erase block. | |
| 881 | 912 | */ |
| 882 | 913 | nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { |
| 883 | 914 | ret = spinand_select_target(spinand, iter.req.pos.target); |
| @@ -934,13 +965,10 @@ static void spinand_cont_read_init(struct spinand_device *spinand) · 50 unmodified lines | ||
| 934 | 965 | { |
| 935 | 966 | struct nand_device *nand = spinand_to_nand(spinand); |
| 936 | 967 | enum nand_ecc_engine_type engine_type = nand->ecc.ctx.conf.engine_type; |
| 968 | + struct spi_controller *ctlr = spinand->spimem->spi->controller; | |
| 937 | 969 | |
| 938 | 970 | /* OOBs cannot be retrieved so external/on-host ECC engine won't work */ |
| 939 | − if (spinand->set_cont_read && | |
| 940 | − (engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE || | |
| 941 | − engine_type == NAND_ECC_ENGINE_TYPE_NONE)) { | |
| 942 | − spinand->cont_read_possible = true; | |
| 943 | − | |
| 971 | + if (spinand->set_cont_read) { | |
| 944 | 972 | /* |
| 945 | 973 | * Ensure continuous read is disabled on probe. |
| 946 | 974 | * Some devices retain this state across soft reset, |
| @@ -948,6 +976,11 @@ static void spinand_cont_read_init(struct spinand_device *spinand) · 1 unmodified line | ||
| 948 | 976 | * in false positive returns from spinand_isbad(). |
| 949 | 977 | */ |
| 950 | 978 | spinand_cont_read_enable(spinand, false); |
| 979 | + | |
| 980 | + if ((engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE || | |
| 981 | + engine_type == NAND_ECC_ENGINE_TYPE_NONE) && | |
| 982 | + !spi_mem_controller_is_capable(ctlr, no_cs_assertion)) | |
| 983 | + spinand->cont_read_possible = true; | |
| 951 | 984 | } |
| 952 | 985 | } |
| 953 | 986 | |
| @@ -968,19 +1001,6 @@ static bool spinand_use_cont_read(struct mtd_info *mtd, loff_t from, · 14 unmodified lines | ||
| 968 | 1001 | nanddev_offs_to_pos(nand, from, &start_pos); |
| 969 | 1002 | nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos); |
| 970 | 1003 | |
| 971 | − /* | |
| 972 | − * Continuous reads never cross LUN boundaries. Some devices don't | |
| 973 | − * support crossing planes boundaries. Some devices don't even support | |
| 974 | − * crossing blocks boundaries. The common case being to read through UBI, | |
| 975 | − * we will very rarely read two consequent blocks or more, so it is safer | |
| 976 | − * and easier (can be improved) to only enable continuous reads when | |
| 977 | − * reading within the same erase block. | |
| 978 | − */ | |
| 979 | − if (start_pos.target != end_pos.target || | |
| 980 | − start_pos.plane != end_pos.plane || | |
| 981 | − start_pos.eraseblock != end_pos.eraseblock) | |
| 982 | − return false; | |
| 983 | − | |
| 984 | 1004 | return start_pos.page < end_pos.page; |
| 985 | 1005 | } |
| 986 | 1006 | |
| @@ -1222,6 +1242,7 @@ static struct spi_mem_dirmap_desc *spinand_create_rdesc( · 235 unmodified lines | ||
| 1222 | 1242 | * its spi controller, use regular reading |
| 1223 | 1243 | */ |
| 1224 | 1244 | spinand->cont_read_possible = false; |
| 1245 | + memset(&info->secondary_op_tmpl, 0, sizeof(info->secondary_op_tmpl)); | |
| 1225 | 1246 | |
| 1226 | 1247 | info->length = nanddev_page_size(nand) + |
| 1227 | 1248 | nanddev_per_page_oobsize(nand); |
| @@ -1238,12 +1259,31 @@ static int spinand_create_dirmap(struct spinand_device *spinand, · 10 unmodified lines | ||
| 1238 | 1259 | struct nand_device *nand = spinand_to_nand(spinand); |
| 1239 | 1260 | struct spi_mem_dirmap_info info = { 0 }; |
| 1240 | 1261 | struct spi_mem_dirmap_desc *desc; |
| 1262 | + bool enable_ecc = false, secondary_op = false; | |
| 1263 | + | |
| 1264 | + if (nand->ecc.engine->integration == NAND_ECC_ENGINE_INTEGRATION_PIPELINED) | |
| 1265 | + enable_ecc = true; | |
| 1266 | + | |
| 1267 | + if (spinand->cont_read_possible && spinand->op_templates->cont_read_cache) | |
| 1268 | + secondary_op = true; | |
| 1269 | + | |
| 1270 | + /* | |
| 1271 | + * Continuous read implies that only the main data is retrieved, backed | |
| 1272 | + * by an on-die ECC engine. It is not possible to use a pipelind ECC | |
| 1273 | + * engine with continuous read. | |
| 1274 | + */ | |
| 1275 | + if (enable_ecc && secondary_op) { | |
| 1276 | + secondary_op = false; | |
| 1277 | + spinand->cont_read_possible = false; | |
| 1278 | + } | |
| 1241 | 1279 | |
| 1242 | 1280 | /* The plane number is passed in MSB just above the column address */ |
| 1243 | 1281 | info.offset = plane << fls(nand->memorg.pagesize); |
| 1244 | 1282 | |
| 1283 | + /* Write descriptor */ | |
| 1245 | 1284 | info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); |
| 1246 | − info.op_tmpl = *spinand->op_templates->update_cache; | |
| 1285 | + info.primary_op_tmpl = *spinand->op_templates->update_cache; | |
| 1286 | + info.primary_op_tmpl.data.ecc = enable_ecc; | |
| 1247 | 1287 | desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, |
| 1248 | 1288 | spinand->spimem, &info); |
| 1249 | 1289 | if (IS_ERR(desc)) |
| @@ -1251,37 +1291,18 @@ static int spinand_create_dirmap(struct spinand_device *spinand, · 1 unmodified line | ||
| 1251 | 1291 | |
| 1252 | 1292 | spinand->dirmaps[plane].wdesc = desc; |
| 1253 | 1293 | |
| 1254 | − info.op_tmpl = *spinand->op_templates->read_cache; | |
| 1255 | − desc = spinand_create_rdesc(spinand, &info); | |
| 1256 | − if (IS_ERR(desc)) | |
| 1257 | − return PTR_ERR(desc); | |
| 1258 | − | |
| 1259 | − spinand->dirmaps[plane].rdesc = desc; | |
| 1260 | − | |
| 1261 | − if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) { | |
| 1262 | − spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc; | |
| 1263 | − spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc; | |
| 1264 | − | |
| 1265 | − return 0; | |
| 1294 | + /* Read descriptor */ | |
| 1295 | + info.primary_op_tmpl = *spinand->op_templates->read_cache; | |
| 1296 | + info.primary_op_tmpl.data.ecc = enable_ecc; | |
| 1297 | + if (secondary_op) { | |
| 1298 | + info.secondary_op_tmpl = *spinand->op_templates->cont_read_cache; | |
| 1299 | + info.secondary_op_tmpl.data.ecc = enable_ecc; | |
| 1266 | 1300 | } |
| 1267 | − | |
| 1268 | − info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); | |
| 1269 | − info.op_tmpl = *spinand->op_templates->update_cache; | |
| 1270 | − info.op_tmpl.data.ecc = true; | |
| 1271 | − desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, | |
| 1272 | − spinand->spimem, &info); | |
| 1273 | − if (IS_ERR(desc)) | |
| 1274 | − return PTR_ERR(desc); | |
| 1275 | − | |
| 1276 | − spinand->dirmaps[plane].wdesc_ecc = desc; | |
| 1277 | − | |
| 1278 | − info.op_tmpl = *spinand->op_templates->read_cache; | |
| 1279 | − info.op_tmpl.data.ecc = true; | |
| 1280 | 1301 | desc = spinand_create_rdesc(spinand, &info); |
| 1281 | 1302 | if (IS_ERR(desc)) |
| 1282 | 1303 | return PTR_ERR(desc); |
| 1283 | 1304 | |
| 1284 | − spinand->dirmaps[plane].rdesc_ecc = desc; | |
| 1305 | + spinand->dirmaps[plane].rdesc = desc; | |
| 1285 | 1306 | |
| 1286 | 1307 | return 0; |
| 1287 | 1308 | } |
| @@ -1307,6 +1328,22 @@ static int spinand_create_dirmaps(struct spinand_device *spinand) · 19 unmodified lines | ||
| 1307 | 1328 | return 0; |
| 1308 | 1329 | } |
| 1309 | 1330 | |
| 1331 | +static int spinand_randomizer_init(struct spinand_device *spinand) | |
| 1332 | +{ | |
| 1333 | + struct device_node *np = spinand->spimem->spi->dev.of_node; | |
| 1334 | + u32 rand_val; | |
| 1335 | + int ret; | |
| 1336 | + | |
| 1337 | + if (!spinand->set_randomizer) | |
| 1338 | + return 0; | |
| 1339 | + | |
| 1340 | + ret = of_property_read_u32(np, "nand-randomizer", &rand_val); | |
| 1341 | + if (ret) | |
| 1342 | + return 0; | |
| 1343 | + | |
| 1344 | + return spinand->set_randomizer(spinand, rand_val); | |
| 1345 | +} | |
| 1346 | + | |
| 1310 | 1347 | static const struct nand_ops spinand_ops = { |
| 1311 | 1348 | .erase = spinand_erase, |
| 1312 | 1349 | .markbad = spinand_markbad, |
| @@ -1407,7 +1444,7 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand) · 94 unmodified lines | ||
| 1407 | 1444 | return spinand->manufacturer->ops->cleanup(spinand); |
| 1408 | 1445 | } |
| 1409 | 1446 | |
| 1410 | −static bool spinand_op_is_odtr(const struct spi_mem_op *op) | |
| 1447 | +bool spinand_op_is_odtr(const struct spi_mem_op *op) | |
| 1411 | 1448 | { |
| 1412 | 1449 | return op->cmd.dtr && op->cmd.buswidth == 8; |
| 1413 | 1450 | } |
| @@ -1489,9 +1526,13 @@ static int spinand_init_odtr_instruction_set(struct spinand_device *spinand) · 75 unmodified lines | ||
| 1489 | 1526 | if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase)) |
| 1490 | 1527 | return -EOPNOTSUPP; |
| 1491 | 1528 | |
| 1492 | − tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0); | |
| 1493 | − if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) | |
| 1529 | + if (spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ) | |
| 1530 | + tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(0); | |
| 1531 | + else | |
| 1532 | + tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0); | |
| 1533 | + if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) { | |
| 1494 | 1534 | return -EOPNOTSUPP; |
| 1535 | + } | |
| 1495 | 1536 | |
| 1496 | 1537 | tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0); |
| 1497 | 1538 | if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec)) |
| @@ -1594,6 +1635,7 @@ int spinand_match_and_init(struct spinand_device *spinand, · 96 unmodified lines | ||
| 1594 | 1635 | spinand->user_otp = &table[i].user_otp; |
| 1595 | 1636 | spinand->read_retries = table[i].read_retries; |
| 1596 | 1637 | spinand->set_read_retry = table[i].set_read_retry; |
| 1638 | + spinand->set_randomizer = table[i].set_randomizer; | |
| 1597 | 1639 | |
| 1598 | 1640 | /* I/O variants selection with single-spi SDR commands */ |
| 1599 | 1641 | |
| @@ -1622,6 +1664,33 @@ int spinand_match_and_init(struct spinand_device *spinand, · 22 unmodified lines | ||
| 1622 | 1664 | if (ret) |
| 1623 | 1665 | return ret; |
| 1624 | 1666 | |
| 1667 | + if (info->op_variants.cont_read_cache) { | |
| 1668 | + op = spinand_select_op_variant(spinand, SSDR, | |
| 1669 | + info->op_variants.cont_read_cache); | |
| 1670 | + if (op) { | |
| 1671 | + const struct spi_mem_op *read_op; | |
| 1672 | + | |
| 1673 | + read_op = spinand->ssdr_op_templates.read_cache; | |
| 1674 | + | |
| 1675 | + /* | |
| 1676 | + * Sometimes the fastest continuous read variant may not | |
| 1677 | + * be supported. In this case, prefer to use the fastest | |
| 1678 | + * read from cache variant and disable continuous reads. | |
| 1679 | + */ | |
| 1680 | + if (read_op->cmd.buswidth > op->cmd.buswidth || | |
| 1681 | + (read_op->cmd.dtr && !op->cmd.dtr) || | |
| 1682 | + read_op->addr.buswidth > op->addr.buswidth || | |
| 1683 | + (read_op->addr.dtr && !op->addr.dtr) || | |
| 1684 | + read_op->data.buswidth > op->data.buswidth || | |
| 1685 | + (read_op->data.dtr && !op->data.dtr)) | |
| 1686 | + spinand->cont_read_possible = false; | |
| 1687 | + else | |
| 1688 | + spinand->ssdr_op_templates.cont_read_cache = op; | |
| 1689 | + } else { | |
| 1690 | + spinand->cont_read_possible = false; | |
| 1691 | + } | |
| 1692 | + } | |
| 1693 | + | |
| 1625 | 1694 | /* I/O variants selection with octo-spi DDR commands (optional) */ |
| 1626 | 1695 | |
| 1627 | 1696 | ret = spinand_init_odtr_instruction_set(spinand); |
| @@ -1644,6 +1713,15 @@ int spinand_match_and_init(struct spinand_device *spinand, · 16 unmodified lines | ||
| 1644 | 1713 | info->op_variants.update_cache); |
| 1645 | 1714 | spinand->odtr_op_templates.update_cache = op; |
| 1646 | 1715 | |
| 1716 | + if (info->op_variants.cont_read_cache) { | |
| 1717 | + op = spinand_select_op_variant(spinand, ODTR, | |
| 1718 | + info->op_variants.cont_read_cache); | |
| 1719 | + if (op) | |
| 1720 | + spinand->odtr_op_templates.cont_read_cache = op; | |
| 1721 | + else | |
| 1722 | + spinand->cont_read_possible = false; | |
| 1723 | + } | |
| 1724 | + | |
| 1647 | 1725 | return 0; |
| 1648 | 1726 | } |
| 1649 | 1727 | |
| @@ -1881,6 +1959,9 @@ static int spinand_init(struct spinand_device *spinand) · 231 unmodified lines | ||
| 1881 | 1959 | * ECC initialization must have happened previously. |
| 1882 | 1960 | */ |
| 1883 | 1961 | spinand_cont_read_init(spinand); |
| 1962 | + ret = spinand_randomizer_init(spinand); | |
| 1963 | + if (ret) | |
| 1964 | + goto err_cleanup_nanddev; | |
| 1884 | 1965 | |
| 1885 | 1966 | mtd->_read_oob = spinand_mtd_read; |
| 1886 | 1967 | mtd->_write_oob = spinand_mtd_write; |
| @@ -14,6 +14,8 @@ · 13 unmodified lines | ||
| 14 | 14 | #define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr) |
| 15 | 15 | #define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr) |
| 16 | 16 | #define MACRONIX_CFG_CONT_READ BIT(2) |
| 17 | +#define MACRONIX_CFG_RANDOMIZER_EN BIT(1) | |
| 18 | +#define MACRONIX_FEATURE_ADDR_RANDOMIZER 0x10 | |
| 17 | 19 | #define MACRONIX_FEATURE_ADDR_READ_RETRY 0x70 |
| 18 | 20 | #define MACRONIX_NUM_READ_RETRY_MODES 5 |
| 19 | 21 | |
| @@ -170,6 +172,12 @@ static int macronix_set_read_retry(struct spinand_device *spinand, · 150 unmodified lines | ||
| 170 | 172 | return spi_mem_exec_op(spinand->spimem, &op); |
| 171 | 173 | } |
| 172 | 174 | |
| 175 | +static int macronix_set_randomizer(struct spinand_device *spinand, bool enable) | |
| 176 | +{ | |
| 177 | + return spinand_write_reg_op(spinand, MACRONIX_FEATURE_ADDR_RANDOMIZER, | |
| 178 | + enable ? MACRONIX_CFG_RANDOMIZER_EN : 0); | |
| 179 | +} | |
| 180 | + | |
| 173 | 181 | static const struct spinand_info macronix_spinand_table[] = { |
| 174 | 182 | SPINAND_INFO("MX35LF1GE4AB", |
| 175 | 183 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12), |
| @@ -231,7 +239,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 55 unmodified lines | ||
| 231 | 239 | SPINAND_HAS_QE_BIT, |
| 232 | 240 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 233 | 241 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 234 | − macronix_set_read_retry)), | |
| 242 | + macronix_set_read_retry), | |
| 243 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 235 | 244 | SPINAND_INFO("MX35LF2G24AD", |
| 236 | 245 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03), |
| 237 | 246 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), |
| @@ -243,7 +252,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 5 unmodified lines | ||
| 243 | 252 | SPINAND_HAS_PROG_PLANE_SELECT_BIT, |
| 244 | 253 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 245 | 254 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 246 | − macronix_set_read_retry)), | |
| 255 | + macronix_set_read_retry), | |
| 256 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 247 | 257 | SPINAND_INFO("MX35LF2G24AD-Z4I8", |
| 248 | 258 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03), |
| 249 | 259 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
| @@ -254,7 +264,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 4 unmodified lines | ||
| 254 | 264 | SPINAND_HAS_QE_BIT, |
| 255 | 265 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 256 | 266 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 257 | − macronix_set_read_retry)), | |
| 267 | + macronix_set_read_retry), | |
| 268 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 258 | 269 | SPINAND_INFO("MX35LF4G24AD", |
| 259 | 270 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03), |
| 260 | 271 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1), |
| @@ -266,7 +277,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 5 unmodified lines | ||
| 266 | 277 | SPINAND_HAS_PROG_PLANE_SELECT_BIT, |
| 267 | 278 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 268 | 279 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 269 | − macronix_set_read_retry)), | |
| 280 | + macronix_set_read_retry), | |
| 281 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 270 | 282 | SPINAND_INFO("MX35LF4G24AD-Z4I8", |
| 271 | 283 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03), |
| 272 | 284 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
| @@ -277,7 +289,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 4 unmodified lines | ||
| 277 | 289 | SPINAND_HAS_QE_BIT, |
| 278 | 290 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 279 | 291 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 280 | − macronix_set_read_retry)), | |
| 292 | + macronix_set_read_retry), | |
| 293 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 281 | 294 | SPINAND_INFO("MX31LF1GE4BC", |
| 282 | 295 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), |
| 283 | 296 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), |
| @@ -327,7 +340,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 43 unmodified lines | ||
| 327 | 340 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 328 | 341 | macronix_ecc_get_status), |
| 329 | 342 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 330 | − macronix_set_read_retry)), | |
| 343 | + macronix_set_read_retry), | |
| 344 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 331 | 345 | SPINAND_INFO("MX35UF4G24AD-Z4I8", |
| 332 | 346 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03), |
| 333 | 347 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
| @@ -340,7 +354,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 6 unmodified lines | ||
| 340 | 354 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 341 | 355 | macronix_ecc_get_status), |
| 342 | 356 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 343 | − macronix_set_read_retry)), | |
| 357 | + macronix_set_read_retry), | |
| 358 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 344 | 359 | SPINAND_INFO("MX35UF4GE4AD", |
| 345 | 360 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03), |
| 346 | 361 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
| @@ -381,7 +396,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 34 unmodified lines | ||
| 381 | 396 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 382 | 397 | macronix_ecc_get_status), |
| 383 | 398 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 384 | − macronix_set_read_retry)), | |
| 399 | + macronix_set_read_retry), | |
| 400 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 385 | 401 | SPINAND_INFO("MX35UF2G24AD-Z4I8", |
| 386 | 402 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03), |
| 387 | 403 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
| @@ -394,7 +410,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 6 unmodified lines | ||
| 394 | 410 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 395 | 411 | macronix_ecc_get_status), |
| 396 | 412 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 397 | − macronix_set_read_retry)), | |
| 413 | + macronix_set_read_retry), | |
| 414 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 398 | 415 | SPINAND_INFO("MX35UF2GE4AD", |
| 399 | 416 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03), |
| 400 | 417 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
| @@ -444,7 +461,8 @@ static const struct spinand_info macronix_spinand_table[] = { · 43 unmodified lines | ||
| 444 | 461 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 445 | 462 | macronix_ecc_get_status), |
| 446 | 463 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, |
| 447 | − macronix_set_read_retry)), | |
| 464 | + macronix_set_read_retry), | |
| 465 | + SPINAND_RANDOMIZER(macronix_set_randomizer)), | |
| 448 | 466 | SPINAND_INFO("MX35UF1GE4AD", |
| 449 | 467 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03), |
| 450 | 468 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), |
| @@ -15,9 +15,11 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #define SPINAND_MFR_WINBOND 0xEF |
| 17 | 17 | |
| 18 | +#define WINBOND_CFG_HFREQ BIT(0) | |
| 18 | 19 | #define WINBOND_CFG_BUF_READ BIT(3) |
| 19 | 20 | |
| 20 | 21 | #define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4) |
| 22 | +#define W25W35NXXJW_STATUS_ECC_MULT_UNCOR (3 << 4) | |
| 21 | 23 | |
| 22 | 24 | #define W25N0XJW_SR4 0xD0 |
| 23 | 25 | #define W25N0XJW_SR4_HS BIT(2) |
| @@ -29,6 +31,105 @@ · 5 unmodified lines | ||
| 29 | 31 | #define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7 |
| 30 | 32 | #define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01 |
| 31 | 33 | |
| 34 | +/* | |
| 35 | + * Winbond chips ignore the address bytes during continuous reads, and | |
| 36 | + * because the dummy cycles are enough they indicate dropping the | |
| 37 | + * address cycles from the continuous read from cache variants. This is | |
| 38 | + * very poorly supported by SPI controller drivers which are "wired" to | |
| 39 | + * always at least provide the column. Keep using address cycles, but | |
| 40 | + * reduce the number of dummy cycles accordingly. | |
| 41 | + */ | |
| 42 | +#define WINBOND_CONT_READ_FROM_CACHE_FAST_1S_1S_1S_OP(ndummy, buf, len, freq) \ | |
| 43 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ | |
| 44 | + SPI_MEM_OP_ADDR(1, 0, 1), \ | |
| 45 | + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ | |
| 46 | + SPI_MEM_OP_DATA_IN(len, buf, 1), \ | |
| 47 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 48 | + | |
| 49 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_1D_1D_OP(ndummy, buf, len, freq) \ | |
| 50 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \ | |
| 51 | + SPI_MEM_DTR_OP_ADDR(2, 0, 1), \ | |
| 52 | + SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ | |
| 53 | + SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \ | |
| 54 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 55 | + | |
| 56 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_1S_2S_OP(ndummy, buf, len, freq) \ | |
| 57 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ | |
| 58 | + SPI_MEM_OP_ADDR(1, 0, 1), \ | |
| 59 | + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ | |
| 60 | + SPI_MEM_OP_DATA_IN(len, buf, 2), \ | |
| 61 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 62 | + | |
| 63 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_2S_2S_OP(ndummy, buf, len, freq) \ | |
| 64 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ | |
| 65 | + SPI_MEM_OP_ADDR(1, 0, 2), \ | |
| 66 | + SPI_MEM_OP_DUMMY(ndummy - 1, 2), \ | |
| 67 | + SPI_MEM_OP_DATA_IN(len, buf, 2), \ | |
| 68 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 69 | + | |
| 70 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_2D_2D_OP(ndummy, buf, len, freq) \ | |
| 71 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \ | |
| 72 | + SPI_MEM_DTR_OP_ADDR(1, 0, 2), \ | |
| 73 | + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 2), \ | |
| 74 | + SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ | |
| 75 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 76 | + | |
| 77 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_1S_4S_OP(ndummy, buf, len, freq) \ | |
| 78 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ | |
| 79 | + SPI_MEM_OP_ADDR(1, 0, 1), \ | |
| 80 | + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ | |
| 81 | + SPI_MEM_OP_DATA_IN(len, buf, 4), \ | |
| 82 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 83 | + | |
| 84 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_1D_4D_OP(ndummy, buf, len, freq) \ | |
| 85 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \ | |
| 86 | + SPI_MEM_DTR_OP_ADDR(1, 0, 1), \ | |
| 87 | + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 1), \ | |
| 88 | + SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ | |
| 89 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 90 | + | |
| 91 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_4S_4S_OP(ndummy, buf, len, freq) \ | |
| 92 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ | |
| 93 | + SPI_MEM_OP_ADDR(1, 0, 4), \ | |
| 94 | + SPI_MEM_OP_DUMMY(ndummy - 1, 4), \ | |
| 95 | + SPI_MEM_OP_DATA_IN(len, buf, 4), \ | |
| 96 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 97 | + | |
| 98 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_4D_4D_OP(ndummy, buf, len, freq) \ | |
| 99 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \ | |
| 100 | + SPI_MEM_DTR_OP_ADDR(1, 0, 4), \ | |
| 101 | + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 4), \ | |
| 102 | + SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ | |
| 103 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 104 | + | |
| 105 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(ndummy, buf, len, freq) \ | |
| 106 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \ | |
| 107 | + SPI_MEM_OP_ADDR(1, 0, 1), \ | |
| 108 | + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ | |
| 109 | + SPI_MEM_OP_DATA_IN(len, buf, 8), \ | |
| 110 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 111 | + | |
| 112 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_1D_8D_OP(ndummy, buf, len, freq) \ | |
| 113 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0x9d, 1), \ | |
| 114 | + SPI_MEM_DTR_OP_ADDR(1, 0, 1), \ | |
| 115 | + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 1), \ | |
| 116 | + SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ | |
| 117 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 118 | + | |
| 119 | +#define WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(ndummy, buf, len, freq) \ | |
| 120 | + SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \ | |
| 121 | + SPI_MEM_OP_ADDR(1, 0, 8), \ | |
| 122 | + SPI_MEM_OP_DUMMY(ndummy - 1, 8), \ | |
| 123 | + SPI_MEM_OP_DATA_IN(len, buf, 8), \ | |
| 124 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 125 | + | |
| 126 | +#define WINBOND_CONT_READ_FROM_CACHE_8D_8D_8D_OP(ndummy, buf, len, freq) \ | |
| 127 | + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ | |
| 128 | + SPI_MEM_DTR_OP_ADDR(2, 0, 8), \ | |
| 129 | + SPI_MEM_DTR_OP_DUMMY(ndummy - 2, 8), \ | |
| 130 | + SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ | |
| 131 | + SPI_MEM_OP_MAX_FREQ(freq)) | |
| 132 | + | |
| 32 | 133 | /* |
| 33 | 134 | * "X2" in the core is equivalent to "dual output" in the datasheets, |
| 34 | 135 | * "X4" in the core is equivalent to "quad output" in the datasheets. |
| @@ -49,6 +150,19 @@ static SPINAND_OP_VARIANTS(read_cache_octal_variants, · 14 unmodified lines | ||
| 49 | 150 | SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), |
| 50 | 151 | SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); |
| 51 | 152 | |
| 153 | +static SPINAND_OP_VARIANTS(cont_read_cache_octal_variants, | |
| 154 | + WINBOND_CONT_READ_FROM_CACHE_8D_8D_8D_OP(24, NULL, 0, 120 * HZ_PER_MHZ), | |
| 155 | + WINBOND_CONT_READ_FROM_CACHE_8D_8D_8D_OP(16, NULL, 0, 86 * HZ_PER_MHZ), | |
| 156 | + WINBOND_CONT_READ_FROM_CACHE_1S_1D_8D_OP(3, NULL, 0, 120 * HZ_PER_MHZ), | |
| 157 | + WINBOND_CONT_READ_FROM_CACHE_1S_1D_8D_OP(2, NULL, 0, 105 * HZ_PER_MHZ), | |
| 158 | + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(20, NULL, 0, 0), | |
| 159 | + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(16, NULL, 0, 162 * HZ_PER_MHZ), | |
| 160 | + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(12, NULL, 0, 124 * HZ_PER_MHZ), | |
| 161 | + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(8, NULL, 0, 86 * HZ_PER_MHZ), | |
| 162 | + WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(2, NULL, 0, 0), | |
| 163 | + WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(1, NULL, 0, 133 * HZ_PER_MHZ), | |
| 164 | + WINBOND_CONT_READ_FROM_CACHE_FAST_1S_1S_1S_OP(1, NULL, 0, 0)); | |
| 165 | + | |
| 52 | 166 | static SPINAND_OP_VARIANTS(write_cache_octal_variants, |
| 53 | 167 | SPINAND_PROG_LOAD_8D_8D_8D_OP(true, 0, NULL, 0), |
| 54 | 168 | SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0), |
| @@ -75,6 +189,20 @@ static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants, · 20 unmodified lines | ||
| 75 | 189 | SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), |
| 76 | 190 | SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ)); |
| 77 | 191 | |
| 192 | +static SPINAND_OP_VARIANTS(cont_read_cache_dual_quad_dtr_variants, | |
| 193 | + WINBOND_CONT_READ_FROM_CACHE_1S_4D_4D_OP(11, NULL, 0, 80 * HZ_PER_MHZ), | |
| 194 | + WINBOND_CONT_READ_FROM_CACHE_1S_1D_4D_OP(5, NULL, 0, 80 * HZ_PER_MHZ), | |
| 195 | + WINBOND_CONT_READ_FROM_CACHE_1S_4S_4S_OP(7, NULL, 0, 0), | |
| 196 | + WINBOND_CONT_READ_FROM_CACHE_1S_4S_4S_OP(6, NULL, 0, 104 * HZ_PER_MHZ), | |
| 197 | + WINBOND_CONT_READ_FROM_CACHE_1S_1S_4S_OP(4, NULL, 0, 0), | |
| 198 | + WINBOND_CONT_READ_FROM_CACHE_1S_2D_2D_OP(6, NULL, 0, 80 * HZ_PER_MHZ), | |
| 199 | + /* The 1S_1D_2D variant would require 4.5 dummy bytes, this is not possible */ | |
| 200 | + WINBOND_CONT_READ_FROM_CACHE_1S_2S_2S_OP(5, NULL, 0, 0), | |
| 201 | + WINBOND_CONT_READ_FROM_CACHE_1S_2S_2S_OP(4, NULL, 0, 104 * HZ_PER_MHZ), | |
| 202 | + WINBOND_CONT_READ_FROM_CACHE_1S_1S_2S_OP(4, NULL, 0, 0), | |
| 203 | + /* The 1S_1D_1D variant would require 4.5 dummy bytes, this is not possible */ | |
| 204 | + WINBOND_CONT_READ_FROM_CACHE_FAST_1S_1S_1S_OP(4, NULL, 0, 0)); | |
| 205 | + | |
| 78 | 206 | static SPINAND_OP_VARIANTS(read_cache_variants, |
| 79 | 207 | SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), |
| 80 | 208 | SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), |
| @@ -99,7 +227,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants, · 18 unmodified lines | ||
| 99 | 227 | |
| 100 | 228 | #define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \ |
| 101 | 229 | SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \ |
| 102 | − SPI_MEM_DTR_OP_ADDR(4, reg, 8), \ | |
| 230 | + SPI_MEM_DTR_OP_ADDR(4, reg << 8, 8), \ | |
| 103 | 231 | SPI_MEM_OP_NO_DUMMY, \ |
| 104 | 232 | SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8)) |
| 105 | 233 | |
| @@ -326,45 +454,84 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, · 220 unmodified lines | ||
| 326 | 454 | return -EINVAL; |
| 327 | 455 | } |
| 328 | 456 | |
| 457 | +static int w25w35nxxjw_ecc_get_status(struct spinand_device *spinand, u8 status) | |
| 458 | +{ | |
| 459 | + switch (status & STATUS_ECC_MASK) { | |
| 460 | + case STATUS_ECC_NO_BITFLIPS: | |
| 461 | + return 0; | |
| 462 | + | |
| 463 | + case STATUS_ECC_HAS_BITFLIPS: | |
| 464 | + return 1; | |
| 465 | + | |
| 466 | + case STATUS_ECC_UNCOR_ERROR: | |
| 467 | + case W25W35NXXJW_STATUS_ECC_MULT_UNCOR: | |
| 468 | + return -EBADMSG; | |
| 469 | + | |
| 470 | + default: | |
| 471 | + break; | |
| 472 | + } | |
| 473 | + | |
| 474 | + return -EINVAL; | |
| 475 | +} | |
| 476 | + | |
| 477 | +static int w25n0xjw_set_sr4_hs(struct spinand_device *spinand, bool enable) | |
| 478 | +{ | |
| 479 | + int ret; | |
| 480 | + u8 sr4; | |
| 481 | + | |
| 482 | + ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); | |
| 483 | + if (ret) | |
| 484 | + return ret; | |
| 485 | + | |
| 486 | + if (enable) | |
| 487 | + sr4 |= W25N0XJW_SR4_HS; | |
| 488 | + else | |
| 489 | + sr4 &= ~W25N0XJW_SR4_HS; | |
| 490 | + | |
| 491 | + return spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); | |
| 492 | +} | |
| 493 | + | |
| 494 | +/* | |
| 495 | + * SDR dual and quad I/O operations over 104MHz require the HS bit to | |
| 496 | + * enable a few more dummy cycles. | |
| 497 | + */ | |
| 498 | +static bool w25n0xjw_op_needs_hs(const struct spi_mem_op *op) | |
| 499 | +{ | |
| 500 | + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) | |
| 501 | + return false; | |
| 502 | + else if (op->cmd.buswidth != 1 || op->addr.buswidth == 1) | |
| 503 | + return false; | |
| 504 | + else if (op->max_freq && op->max_freq <= 104 * HZ_PER_MHZ) | |
| 505 | + return false; | |
| 506 | + | |
| 507 | + return true; | |
| 508 | +} | |
| 509 | + | |
| 329 | 510 | static int w25n0xjw_hs_cfg(struct spinand_device *spinand, |
| 330 | 511 | enum spinand_bus_interface iface) |
| 331 | 512 | { |
| 332 | 513 | const struct spi_mem_op *op; |
| 333 | − bool hs; | |
| 334 | − u8 sr4; | |
| 335 | − int ret; | |
| 336 | 514 | |
| 337 | 515 | if (iface != SSDR) |
| 338 | 516 | return -EOPNOTSUPP; |
| 339 | 517 | |
| 340 | 518 | /* |
| 341 | − * SDR dual and quad I/O operations over 104MHz require the HS bit to | |
| 342 | − * enable a few more dummy cycles. | |
| 519 | + * At this stage, we do not yet know the continuous read template, nor | |
| 520 | + * if there is going to be one. Let's assume the continuous read | |
| 521 | + * template will be selected with the same heuristics as the buffered | |
| 522 | + * read variant, as there cannot be a HS configuration mismatch between | |
| 523 | + * them. | |
| 343 | 524 | */ |
| 344 | 525 | op = spinand->op_templates->read_cache; |
| 345 | − if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) | |
| 346 | − hs = false; | |
| 347 | − else if (op->cmd.buswidth != 1 || op->addr.buswidth == 1) | |
| 348 | − hs = false; | |
| 349 | − else if (op->max_freq && op->max_freq <= 104 * HZ_PER_MHZ) | |
| 350 | − hs = false; | |
| 351 | − else | |
| 352 | − hs = true; | |
| 353 | − | |
| 354 | − ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); | |
| 355 | − if (ret) | |
| 356 | − return ret; | |
| 357 | 526 | |
| 358 | − if (hs) | |
| 359 | − sr4 |= W25N0XJW_SR4_HS; | |
| 360 | − else | |
| 361 | − sr4 &= ~W25N0XJW_SR4_HS; | |
| 527 | + return w25n0xjw_set_sr4_hs(spinand, w25n0xjw_op_needs_hs(op)); | |
| 528 | +} | |
| 362 | 529 | |
| 363 | − ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); | |
| 364 | − if (ret) | |
| 365 | − return ret; | |
| 530 | +static int w25n0xjw_set_cont_read(struct spinand_device *spinand, bool enable) | |
| 531 | +{ | |
| 532 | + u8 mask = enable ? 0 : WINBOND_CFG_BUF_READ; | |
| 366 | 533 | |
| 367 | − return 0; | |
| 534 | + return spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ, mask); | |
| 368 | 535 | } |
| 369 | 536 | |
| 370 | 537 | static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val) |
| @@ -451,6 +618,18 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand, · 80 unmodified lines | ||
| 451 | 618 | return 0; |
| 452 | 619 | } |
| 453 | 620 | |
| 621 | +static int w35n0xjw_set_cont_read(struct spinand_device *spinand, bool enable) | |
| 622 | +{ | |
| 623 | + const struct spi_mem_op *cont_op = spinand->op_templates->cont_read_cache; | |
| 624 | + u8 mask = enable ? 0 : WINBOND_CFG_BUF_READ; | |
| 625 | + | |
| 626 | + if (cont_op && enable && spinand_op_is_odtr(cont_op) && | |
| 627 | + cont_op->max_freq >= 90 * HZ_PER_MHZ) | |
| 628 | + mask |= WINBOND_CFG_HFREQ; | |
| 629 | + | |
| 630 | + return spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ | WINBOND_CFG_HFREQ, mask); | |
| 631 | +} | |
| 632 | + | |
| 454 | 633 | static const struct spinand_info winbond_spinand_table[] = { |
| 455 | 634 | /* 512M-bit densities */ |
| 456 | 635 | SPINAND_INFO("W25N512GW", /* 1.8V */ |
| @@ -485,12 +664,14 @@ static const struct spinand_info winbond_spinand_table[] = { · 28 unmodified lines | ||
| 485 | 664 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), |
| 486 | 665 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), |
| 487 | 666 | NAND_ECCREQ(1, 512), |
| 488 | − SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, | |
| 489 | − &write_cache_variants, | |
| 490 | − &update_cache_variants), | |
| 667 | + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_dual_quad_dtr_variants, | |
| 668 | + &write_cache_variants, | |
| 669 | + &update_cache_variants, | |
| 670 | + &cont_read_cache_dual_quad_dtr_variants), | |
| 491 | 671 | SPINAND_HAS_QE_BIT, |
| 492 | − SPINAND_ECCINFO(&w25n01jw_ooblayout, NULL), | |
| 493 | − SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), | |
| 672 | + SPINAND_ECCINFO(&w25n01jw_ooblayout, w25w35nxxjw_ecc_get_status), | |
| 673 | + SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg), | |
| 674 | + SPINAND_CONT_READ(w25n0xjw_set_cont_read)), | |
| 494 | 675 | SPINAND_INFO("W25N01KV", /* 3.3V */ |
| 495 | 676 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), |
| 496 | 677 | NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), |
| @@ -504,35 +685,15 @@ static const struct spinand_info winbond_spinand_table[] = { · 7 unmodified lines | ||
| 504 | 685 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21), |
| 505 | 686 | NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1), |
| 506 | 687 | NAND_ECCREQ(1, 512), |
| 507 | − SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, | |
| 508 | − &write_cache_octal_variants, | |
| 509 | − &update_cache_octal_variants), | |
| 688 | + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, | |
| 689 | + &write_cache_octal_variants, | |
| 690 | + &update_cache_octal_variants, | |
| 691 | + &cont_read_cache_octal_variants), | |
| 510 | 692 | 0, |
| 511 | 693 | SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), |
| 512 | − SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), | |
| 513 | − SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), | |
| 514 | − SPINAND_INFO("W35N02JW", /* 1.8V */ | |
| 515 | − SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22), | |
| 516 | − NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1), | |
| 517 | − NAND_ECCREQ(1, 512), | |
| 518 | − SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, | |
| 519 | − &write_cache_octal_variants, | |
| 520 | − &update_cache_octal_variants), | |
| 521 | − 0, | |
| 522 | − SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), | |
| 523 | − SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), | |
| 524 | − SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), | |
| 525 | − SPINAND_INFO("W35N04JW", /* 1.8V */ | |
| 526 | − SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23), | |
| 527 | − NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1), | |
| 528 | − NAND_ECCREQ(1, 512), | |
| 529 | − SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, | |
| 530 | − &write_cache_octal_variants, | |
| 531 | − &update_cache_octal_variants), | |
| 532 | − 0, | |
| 533 | − SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), | |
| 534 | − SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), | |
| 535 | − SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), | |
| 694 | + SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), | |
| 695 | + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), | |
| 696 | + SPINAND_CONT_READ(w35n0xjw_set_cont_read)), | |
| 536 | 697 | /* 2G-bit densities */ |
| 537 | 698 | SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ |
| 538 | 699 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), |
| @@ -549,12 +710,14 @@ static const struct spinand_info winbond_spinand_table[] = { · 10 unmodified lines | ||
| 549 | 710 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22), |
| 550 | 711 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1), |
| 551 | 712 | NAND_ECCREQ(1, 512), |
| 552 | − SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, | |
| 553 | − &write_cache_variants, | |
| 554 | − &update_cache_variants), | |
| 713 | + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_dual_quad_dtr_variants, | |
| 714 | + &write_cache_variants, | |
| 715 | + &update_cache_variants, | |
| 716 | + &cont_read_cache_dual_quad_dtr_variants), | |
| 555 | 717 | SPINAND_HAS_QE_BIT, |
| 556 | − SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), | |
| 557 | − SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), | |
| 718 | + SPINAND_ECCINFO(&w25m02gv_ooblayout, w25w35nxxjw_ecc_get_status), | |
| 719 | + SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg), | |
| 720 | + SPINAND_CONT_READ(w25n0xjw_set_cont_read)), | |
| 558 | 721 | SPINAND_INFO("W25N02KV", /* 3.3V */ |
| 559 | 722 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), |
| 560 | 723 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
| @@ -573,6 +736,19 @@ static const struct spinand_info winbond_spinand_table[] = { · 12 unmodified lines | ||
| 573 | 736 | &update_cache_variants), |
| 574 | 737 | 0, |
| 575 | 738 | SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), |
| 739 | + SPINAND_INFO("W35N02JW", /* 1.8V */ | |
| 740 | + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22), | |
| 741 | + NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1), | |
| 742 | + NAND_ECCREQ(1, 512), | |
| 743 | + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, | |
| 744 | + &write_cache_octal_variants, | |
| 745 | + &update_cache_octal_variants, | |
| 746 | + &cont_read_cache_octal_variants), | |
| 747 | + SPINAND_ODTR_PACKED_PAGE_READ, | |
| 748 | + SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), | |
| 749 | + SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), | |
| 750 | + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), | |
| 751 | + SPINAND_CONT_READ(w35n0xjw_set_cont_read)), | |
| 576 | 752 | /* 4G-bit densities */ |
| 577 | 753 | SPINAND_INFO("W25N04KV", /* 3.3V */ |
| 578 | 754 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), |
| @@ -592,6 +768,19 @@ static const struct spinand_info winbond_spinand_table[] = { · 13 unmodified lines | ||
| 592 | 768 | &update_cache_variants), |
| 593 | 769 | 0, |
| 594 | 770 | SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), |
| 771 | + SPINAND_INFO("W35N04JW", /* 1.8V */ | |
| 772 | + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23), | |
| 773 | + NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1), | |
| 774 | + NAND_ECCREQ(1, 512), | |
| 775 | + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, | |
| 776 | + &write_cache_octal_variants, | |
| 777 | + &update_cache_octal_variants, | |
| 778 | + &cont_read_cache_octal_variants), | |
| 779 | + SPINAND_ODTR_PACKED_PAGE_READ, | |
| 780 | + SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), | |
| 781 | + SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), | |
| 782 | + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), | |
| 783 | + SPINAND_CONT_READ(w35n0xjw_set_cont_read)), | |
| 595 | 784 | }; |
| 596 | 785 | |
| 597 | 786 | static int winbond_spinand_init(struct spinand_device *spinand) |
| @@ -3711,14 +3711,15 @@ EXPORT_SYMBOL_GPL(spi_nor_scan); · 3710 unmodified lines | ||
| 3711 | 3711 | static int spi_nor_create_read_dirmap(struct spi_nor *nor) |
| 3712 | 3712 | { |
| 3713 | 3713 | struct spi_mem_dirmap_info info = { |
| 3714 | − .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), | |
| 3715 | − SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), | |
| 3716 | − SPI_MEM_OP_DUMMY(nor->read_dummy, 0), | |
| 3717 | − SPI_MEM_OP_DATA_IN(0, NULL, 0)), | |
| 3714 | + .op_tmpl = &info.primary_op_tmpl, | |
| 3715 | + .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), | |
| 3716 | + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), | |
| 3717 | + SPI_MEM_OP_DUMMY(nor->read_dummy, 0), | |
| 3718 | + SPI_MEM_OP_DATA_IN(0, NULL, 0)), | |
| 3718 | 3719 | .offset = 0, |
| 3719 | 3720 | .length = nor->params->size, |
| 3720 | 3721 | }; |
| 3721 | − struct spi_mem_op *op = &info.op_tmpl; | |
| 3722 | + struct spi_mem_op *op = info.op_tmpl; | |
| 3722 | 3723 | |
| 3723 | 3724 | spi_nor_spimem_setup_op(nor, op, nor->read_proto); |
| 3724 | 3725 | |
| @@ -3742,14 +3743,15 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor) · 17 unmodified lines | ||
| 3742 | 3743 | static int spi_nor_create_write_dirmap(struct spi_nor *nor) |
| 3743 | 3744 | { |
| 3744 | 3745 | struct spi_mem_dirmap_info info = { |
| 3745 | − .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), | |
| 3746 | − SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), | |
| 3747 | − SPI_MEM_OP_NO_DUMMY, | |
| 3748 | − SPI_MEM_OP_DATA_OUT(0, NULL, 0)), | |
| 3746 | + .op_tmpl = &info.primary_op_tmpl, | |
| 3747 | + .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), | |
| 3748 | + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), | |
| 3749 | + SPI_MEM_OP_NO_DUMMY, | |
| 3750 | + SPI_MEM_OP_DATA_OUT(0, NULL, 0)), | |
| 3749 | 3751 | .offset = 0, |
| 3750 | 3752 | .length = nor->params->size, |
| 3751 | 3753 | }; |
| 3752 | − struct spi_mem_op *op = &info.op_tmpl; | |
| 3754 | + struct spi_mem_op *op = info.op_tmpl; | |
| 3753 | 3755 | |
| 3754 | 3756 | if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) |
| 3755 | 3757 | op->addr.nbytes = 0; |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | |
| 3 | +#include <linux/array_size.h> | |
| 3 | 4 | #include <linux/debugfs.h> |
| 4 | 5 | #include <linux/math64.h> |
| 5 | 6 | #include <linux/mtd/spi-nor.h> |
| @@ -98,7 +99,8 @@ static int spi_nor_params_show(struct seq_file *s, void *data) · 92 unmodified lines | ||
| 98 | 99 | seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes); |
| 99 | 100 | |
| 100 | 101 | seq_puts(s, "flags\t\t"); |
| 101 | − spi_nor_print_flags(s, nor->flags, snor_f_names, sizeof(snor_f_names)); | |
| 102 | + spi_nor_print_flags(s, nor->flags, snor_f_names, | |
| 103 | + ARRAY_SIZE(snor_f_names)); | |
| 102 | 104 | seq_puts(s, "\n"); |
| 103 | 105 | |
| 104 | 106 | seq_puts(s, "\nopcodes\n"); |
| @@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, · 528 unmodified lines | ||
| 529 | 529 | struct in6_addr saddr; |
| 530 | 530 | struct socket *sock = rcu_dereference(bareudp->sock); |
| 531 | 531 | |
| 532 | + if (!sock) | |
| 533 | + return -ESHUTDOWN; | |
| 534 | + | |
| 532 | 535 | dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, |
| 533 | 536 | 0, &saddr, &info->key, |
| 534 | 537 | sport, bareudp->port, info->key.tos, |
| @@ -1029,6 +1029,7 @@ static void ad_cond_set_peer_notif(struct port *port) · 1028 unmodified lines | ||
| 1029 | 1029 | static void ad_mux_machine(struct port *port, bool *update_slave_arr) |
| 1030 | 1030 | { |
| 1031 | 1031 | struct bonding *bond = __get_bond_by_port(port); |
| 1032 | + struct aggregator *aggregator; | |
| 1032 | 1033 | mux_states_t last_state; |
| 1033 | 1034 | |
| 1034 | 1035 | /* keep current State Machine state to compare later if it was |
| @@ -1036,6 +1037,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 1 unmodified line | ||
| 1036 | 1037 | */ |
| 1037 | 1038 | last_state = port->sm_mux_state; |
| 1038 | 1039 | |
| 1040 | + aggregator = rcu_dereference(port->aggregator); | |
| 1039 | 1041 | if (port->sm_vars & AD_PORT_BEGIN) { |
| 1040 | 1042 | port->sm_mux_state = AD_MUX_DETACHED; |
| 1041 | 1043 | } else { |
| @@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 13 unmodified lines | ||
| 1055 | 1057 | * cycle to update ready variable, we check |
| 1056 | 1058 | * READY_N and update READY here |
| 1057 | 1059 | */ |
| 1058 | − __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); | |
| 1060 | + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); | |
| 1059 | 1061 | port->sm_mux_state = AD_MUX_DETACHED; |
| 1060 | 1062 | break; |
| 1061 | 1063 | } |
| @@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 8 unmodified lines | ||
| 1070 | 1072 | * update ready variable, we check READY_N and update |
| 1071 | 1073 | * READY here |
| 1072 | 1074 | */ |
| 1073 | − __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); | |
| 1075 | + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); | |
| 1074 | 1076 | |
| 1075 | 1077 | /* if the wait_while_timer expired, and the port is |
| 1076 | 1078 | * in READY state, move to ATTACHED state |
| @@ -1086,7 +1088,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 9 unmodified lines | ||
| 1086 | 1088 | if ((port->sm_vars & AD_PORT_SELECTED) && |
| 1087 | 1089 | (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && |
| 1088 | 1090 | !__check_agg_selection_timer(port)) { |
| 1089 | − if (port->aggregator->is_active) { | |
| 1091 | + if (aggregator->is_active) { | |
| 1090 | 1092 | int state = AD_MUX_COLLECTING_DISTRIBUTING; |
| 1091 | 1093 | |
| 1092 | 1094 | if (!bond->params.coupled_control) |
| @@ -1102,9 +1104,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 9 unmodified lines | ||
| 1102 | 1104 | * cycle to update ready variable, we check |
| 1103 | 1105 | * READY_N and update READY here |
| 1104 | 1106 | */ |
| 1105 | − __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); | |
| 1107 | + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); | |
| 1106 | 1108 | port->sm_mux_state = AD_MUX_DETACHED; |
| 1107 | − } else if (port->aggregator->is_active) { | |
| 1109 | + } else if (aggregator->is_active) { | |
| 1108 | 1110 | port->actor_oper_port_state |= |
| 1109 | 1111 | LACP_STATE_SYNCHRONIZATION; |
| 1110 | 1112 | } |
| @@ -1115,7 +1117,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 4 unmodified lines | ||
| 1115 | 1117 | * sure that a collecting distributing |
| 1116 | 1118 | * port in an active aggregator is enabled |
| 1117 | 1119 | */ |
| 1118 | − if (port->aggregator->is_active && | |
| 1120 | + if (aggregator->is_active && | |
| 1119 | 1121 | !__port_is_collecting_distributing(port)) { |
| 1120 | 1122 | __enable_port(port); |
| 1121 | 1123 | *update_slave_arr = true; |
| @@ -1134,7 +1136,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 12 unmodified lines | ||
| 1134 | 1136 | */ |
| 1135 | 1137 | struct slave *slave = port->slave; |
| 1136 | 1138 | |
| 1137 | − if (port->aggregator->is_active && | |
| 1139 | + if (aggregator->is_active && | |
| 1138 | 1140 | bond_is_slave_rx_disabled(slave)) { |
| 1139 | 1141 | ad_enable_collecting(port); |
| 1140 | 1142 | *update_slave_arr = true; |
| @@ -1154,8 +1156,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 13 unmodified lines | ||
| 1154 | 1156 | * sure that a collecting distributing |
| 1155 | 1157 | * port in an active aggregator is enabled |
| 1156 | 1158 | */ |
| 1157 | − if (port->aggregator && | |
| 1158 | − port->aggregator->is_active && | |
| 1159 | + if (aggregator && | |
| 1160 | + aggregator->is_active && | |
| 1159 | 1161 | !__port_is_collecting_distributing(port)) { |
| 1160 | 1162 | __enable_port(port); |
| 1161 | 1163 | *update_slave_arr = true; |
| @@ -1187,7 +1189,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 25 unmodified lines | ||
| 1187 | 1189 | port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); |
| 1188 | 1190 | break; |
| 1189 | 1191 | case AD_MUX_ATTACHED: |
| 1190 | − if (port->aggregator->is_active) | |
| 1192 | + if (aggregator->is_active) | |
| 1191 | 1193 | port->actor_oper_port_state |= |
| 1192 | 1194 | LACP_STATE_SYNCHRONIZATION; |
| 1193 | 1195 | else |
| @@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 367 unmodified lines | ||
| 1561 | 1563 | bond = __get_bond_by_port(port); |
| 1562 | 1564 | |
| 1563 | 1565 | /* if the port is connected to other aggregator, detach it */ |
| 1564 | − if (port->aggregator) { | |
| 1566 | + temp_aggregator = rcu_dereference(port->aggregator); | |
| 1567 | + if (temp_aggregator) { | |
| 1565 | 1568 | /* detach the port from its former aggregator */ |
| 1566 | − temp_aggregator = port->aggregator; | |
| 1567 | 1569 | for (curr_port = temp_aggregator->lag_ports; curr_port; |
| 1568 | 1570 | last_port = curr_port, |
| 1569 | 1571 | curr_port = curr_port->next_port_in_aggregator) { |
| @@ -1586,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 16 unmodified lines | ||
| 1586 | 1588 | /* clear the port's relations to this |
| 1587 | 1589 | * aggregator |
| 1588 | 1590 | */ |
| 1589 | − port->aggregator = NULL; | |
| 1591 | + RCU_INIT_POINTER(port->aggregator, NULL); | |
| 1590 | 1592 | port->next_port_in_aggregator = NULL; |
| 1591 | 1593 | port->actor_port_aggregator_identifier = 0; |
| 1592 | 1594 | |
| @@ -1609,7 +1611,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 16 unmodified lines | ||
| 1609 | 1611 | port->slave->bond->dev->name, |
| 1610 | 1612 | port->slave->dev->name, |
| 1611 | 1613 | port->actor_port_number, |
| 1612 | − port->aggregator->aggregator_identifier); | |
| 1614 | + temp_aggregator->aggregator_identifier); | |
| 1613 | 1615 | } |
| 1614 | 1616 | } |
| 1615 | 1617 | /* search on all aggregators for a suitable aggregator for this port */ |
| @@ -1633,15 +1635,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 17 unmodified lines | ||
| 1633 | 1635 | ) |
| 1634 | 1636 | ) { |
| 1635 | 1637 | /* attach to the founded aggregator */ |
| 1636 | − port->aggregator = aggregator; | |
| 1638 | + rcu_assign_pointer(port->aggregator, aggregator); | |
| 1637 | 1639 | port->actor_port_aggregator_identifier = |
| 1638 | − port->aggregator->aggregator_identifier; | |
| 1640 | + aggregator->aggregator_identifier; | |
| 1639 | 1641 | port->next_port_in_aggregator = aggregator->lag_ports; |
| 1640 | − port->aggregator->num_of_ports++; | |
| 1642 | + aggregator->num_of_ports++; | |
| 1641 | 1643 | aggregator->lag_ports = port; |
| 1642 | 1644 | slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", |
| 1643 | 1645 | port->actor_port_number, |
| 1644 | − port->aggregator->aggregator_identifier); | |
| 1646 | + aggregator->aggregator_identifier); | |
| 1645 | 1647 | |
| 1646 | 1648 | /* mark this port as selected */ |
| 1647 | 1649 | port->sm_vars |= AD_PORT_SELECTED; |
| @@ -1656,39 +1658,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 8 unmodified lines | ||
| 1656 | 1658 | if (!found) { |
| 1657 | 1659 | if (free_aggregator) { |
| 1658 | 1660 | /* assign port a new aggregator */ |
| 1659 | − port->aggregator = free_aggregator; | |
| 1660 | 1661 | port->actor_port_aggregator_identifier = |
| 1661 | − port->aggregator->aggregator_identifier; | |
| 1662 | + free_aggregator->aggregator_identifier; | |
| 1662 | 1663 | |
| 1663 | 1664 | /* update the new aggregator's parameters |
| 1664 | 1665 | * if port was responsed from the end-user |
| 1665 | 1666 | */ |
| 1666 | 1667 | if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) |
| 1667 | 1668 | /* if port is full duplex */ |
| 1668 | − port->aggregator->is_individual = false; | |
| 1669 | + free_aggregator->is_individual = false; | |
| 1669 | 1670 | else |
| 1670 | − port->aggregator->is_individual = true; | |
| 1671 | + free_aggregator->is_individual = true; | |
| 1671 | 1672 | |
| 1672 | − port->aggregator->actor_admin_aggregator_key = | |
| 1673 | + free_aggregator->actor_admin_aggregator_key = | |
| 1673 | 1674 | port->actor_admin_port_key; |
| 1674 | − port->aggregator->actor_oper_aggregator_key = | |
| 1675 | + free_aggregator->actor_oper_aggregator_key = | |
| 1675 | 1676 | port->actor_oper_port_key; |
| 1676 | − port->aggregator->partner_system = | |
| 1677 | + free_aggregator->partner_system = | |
| 1677 | 1678 | port->partner_oper.system; |
| 1678 | − port->aggregator->partner_system_priority = | |
| 1679 | + free_aggregator->partner_system_priority = | |
| 1679 | 1680 | port->partner_oper.system_priority; |
| 1680 | − port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; | |
| 1681 | − port->aggregator->receive_state = 1; | |
| 1682 | − port->aggregator->transmit_state = 1; | |
| 1683 | − port->aggregator->lag_ports = port; | |
| 1684 | − port->aggregator->num_of_ports++; | |
| 1681 | + free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; | |
| 1682 | + free_aggregator->receive_state = 1; | |
| 1683 | + free_aggregator->transmit_state = 1; | |
| 1684 | + free_aggregator->lag_ports = port; | |
| 1685 | + free_aggregator->num_of_ports++; | |
| 1686 | + | |
| 1687 | + rcu_assign_pointer(port->aggregator, free_aggregator); | |
| 1685 | 1688 | |
| 1686 | 1689 | /* mark this port as selected */ |
| 1687 | 1690 | port->sm_vars |= AD_PORT_SELECTED; |
| 1688 | 1691 | |
| 1689 | 1692 | slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", |
| 1690 | 1693 | port->actor_port_number, |
| 1691 | − port->aggregator->aggregator_identifier); | |
| 1694 | + free_aggregator->aggregator_identifier); | |
| 1692 | 1695 | } else { |
| 1693 | 1696 | slave_err(bond->dev, port->slave->dev, |
| 1694 | 1697 | "Port %d did not find a suitable aggregator\n", |
| @@ -1700,13 +1703,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 5 unmodified lines | ||
| 1700 | 1703 | * in all aggregator's ports, else set ready=FALSE in all |
| 1701 | 1704 | * aggregator's ports |
| 1702 | 1705 | */ |
| 1703 | − __set_agg_ports_ready(port->aggregator, | |
| 1704 | − __agg_ports_are_ready(port->aggregator)); | |
| 1706 | + aggregator = rcu_dereference(port->aggregator); | |
| 1707 | + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); | |
| 1705 | 1708 | |
| 1706 | − aggregator = __get_first_agg(port); | |
| 1707 | − ad_agg_selection_logic(aggregator, update_slave_arr); | |
| 1709 | + ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); | |
| 1708 | 1710 | |
| 1709 | − if (!port->aggregator->is_active) | |
| 1711 | + if (!aggregator->is_active) | |
| 1710 | 1712 | port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; |
| 1711 | 1713 | } |
| 1712 | 1714 | |
| @@ -2075,13 +2077,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond · 362 unmodified lines | ||
| 2075 | 2077 | */ |
| 2076 | 2078 | static void ad_enable_collecting(struct port *port) |
| 2077 | 2079 | { |
| 2078 | − if (port->aggregator->is_active) { | |
| 2080 | + struct aggregator *aggregator = rcu_dereference(port->aggregator); | |
| 2081 | + | |
| 2082 | + if (aggregator->is_active) { | |
| 2079 | 2083 | struct slave *slave = port->slave; |
| 2080 | 2084 | |
| 2081 | 2085 | slave_dbg(slave->bond->dev, slave->dev, |
| 2082 | 2086 | "Enabling collecting on port %d (LAG %d)\n", |
| 2083 | 2087 | port->actor_port_number, |
| 2084 | − port->aggregator->aggregator_identifier); | |
| 2088 | + aggregator->aggregator_identifier); | |
| 2085 | 2089 | __enable_collecting_port(port); |
| 2086 | 2090 | } |
| 2087 | 2091 | } |
| @@ -2093,11 +2097,13 @@ static void ad_enable_collecting(struct port *port) · 5 unmodified lines | ||
| 2093 | 2097 | */ |
| 2094 | 2098 | static void ad_disable_distributing(struct port *port, bool *update_slave_arr) |
| 2095 | 2099 | { |
| 2096 | − if (port->aggregator && __agg_has_partner(port->aggregator)) { | |
| 2100 | + struct aggregator *aggregator = rcu_dereference(port->aggregator); | |
| 2101 | + | |
| 2102 | + if (aggregator && __agg_has_partner(aggregator)) { | |
| 2097 | 2103 | slave_dbg(port->slave->bond->dev, port->slave->dev, |
| 2098 | 2104 | "Disabling distributing on port %d (LAG %d)\n", |
| 2099 | 2105 | port->actor_port_number, |
| 2100 | − port->aggregator->aggregator_identifier); | |
| 2106 | + aggregator->aggregator_identifier); | |
| 2101 | 2107 | __disable_distributing_port(port); |
| 2102 | 2108 | /* Slave array needs an update */ |
| 2103 | 2109 | *update_slave_arr = true; |
| @@ -2114,11 +2120,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) · 10 unmodified lines | ||
| 2114 | 2120 | static void ad_enable_collecting_distributing(struct port *port, |
| 2115 | 2121 | bool *update_slave_arr) |
| 2116 | 2122 | { |
| 2117 | − if (port->aggregator->is_active) { | |
| 2123 | + struct aggregator *aggregator = rcu_dereference(port->aggregator); | |
| 2124 | + | |
| 2125 | + if (aggregator->is_active) { | |
| 2118 | 2126 | slave_dbg(port->slave->bond->dev, port->slave->dev, |
| 2119 | 2127 | "Enabling port %d (LAG %d)\n", |
| 2120 | 2128 | port->actor_port_number, |
| 2121 | − port->aggregator->aggregator_identifier); | |
| 2129 | + aggregator->aggregator_identifier); | |
| 2122 | 2130 | __enable_port(port); |
| 2123 | 2131 | /* Slave array needs update */ |
| 2124 | 2132 | *update_slave_arr = true; |
| @@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port, · 10 unmodified lines | ||
| 2135 | 2143 | static void ad_disable_collecting_distributing(struct port *port, |
| 2136 | 2144 | bool *update_slave_arr) |
| 2137 | 2145 | { |
| 2138 | − if (port->aggregator && __agg_has_partner(port->aggregator)) { | |
| 2146 | + struct aggregator *aggregator = rcu_dereference(port->aggregator); | |
| 2147 | + | |
| 2148 | + if (aggregator && __agg_has_partner(aggregator)) { | |
| 2139 | 2149 | slave_dbg(port->slave->bond->dev, port->slave->dev, |
| 2140 | 2150 | "Disabling port %d (LAG %d)\n", |
| 2141 | 2151 | port->actor_port_number, |
| 2142 | − port->aggregator->aggregator_identifier); | |
| 2152 | + aggregator->aggregator_identifier); | |
| 2143 | 2153 | __disable_port(port); |
| 2144 | 2154 | /* Slave array needs an update */ |
| 2145 | 2155 | *update_slave_arr = true; |
| @@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave) · 233 unmodified lines | ||
| 2379 | 2389 | */ |
| 2380 | 2390 | for (temp_port = aggregator->lag_ports; temp_port; |
| 2381 | 2391 | temp_port = temp_port->next_port_in_aggregator) { |
| 2382 | − temp_port->aggregator = new_aggregator; | |
| 2392 | + rcu_assign_pointer(temp_port->aggregator, new_aggregator); | |
| 2383 | 2393 | temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; |
| 2384 | 2394 | } |
| 2385 | 2395 | |
| @@ -2848,15 +2858,16 @@ out: · 462 unmodified lines | ||
| 2848 | 2858 | int __bond_3ad_get_active_agg_info(struct bonding *bond, |
| 2849 | 2859 | struct ad_info *ad_info) |
| 2850 | 2860 | { |
| 2851 | − struct aggregator *aggregator = NULL; | |
| 2861 | + struct aggregator *aggregator = NULL, *tmp; | |
| 2852 | 2862 | struct list_head *iter; |
| 2853 | 2863 | struct slave *slave; |
| 2854 | 2864 | struct port *port; |
| 2855 | 2865 | |
| 2856 | 2866 | bond_for_each_slave_rcu(bond, slave, iter) { |
| 2857 | 2867 | port = &(SLAVE_AD_INFO(slave)->port); |
| 2858 | − if (port->aggregator && port->aggregator->is_active) { | |
| 2859 | − aggregator = port->aggregator; | |
| 2868 | + tmp = rcu_dereference(port->aggregator); | |
| 2869 | + if (tmp && tmp->is_active) { | |
| 2870 | + aggregator = tmp; | |
| 2860 | 2871 | break; |
| 2861 | 2872 | } |
| 2862 | 2873 | } |
| @@ -1433,7 +1433,7 @@ static void bond_poll_controller(struct net_device *bond_dev) · 1432 unmodified lines | ||
| 1433 | 1433 | |
| 1434 | 1434 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { |
| 1435 | 1435 | struct aggregator *agg = |
| 1436 | − SLAVE_AD_INFO(slave)->port.aggregator; | |
| 1436 | + rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); | |
| 1437 | 1437 | |
| 1438 | 1438 | if (agg && |
| 1439 | 1439 | agg->aggregator_identifier != ad_info.aggregator_id) |
| @@ -5179,15 +5179,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) · 3739 unmodified lines | ||
| 5179 | 5179 | spin_unlock_bh(&bond->mode_lock); |
| 5180 | 5180 | agg_id = ad_info.aggregator_id; |
| 5181 | 5181 | } |
| 5182 | + rcu_read_lock(); | |
| 5182 | 5183 | bond_for_each_slave(bond, slave, iter) { |
| 5183 | 5184 | if (skipslave == slave) |
| 5184 | 5185 | continue; |
| 5185 | 5186 | |
| 5186 | 5187 | all_slaves->arr[all_slaves->count++] = slave; |
| 5187 | 5188 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { |
| 5188 | − struct aggregator *agg; | |
| 5189 | + const struct aggregator *agg; | |
| 5189 | 5190 | |
| 5190 | − agg = SLAVE_AD_INFO(slave)->port.aggregator; | |
| 5191 | + agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); | |
| 5191 | 5192 | if (!agg || agg->aggregator_identifier != agg_id) |
| 5192 | 5193 | continue; |
| 5193 | 5194 | } |
| @@ -5199,6 +5200,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) · 5 unmodified lines | ||
| 5199 | 5200 | |
| 5200 | 5201 | usable_slaves->arr[usable_slaves->count++] = slave; |
| 5201 | 5202 | } |
| 5203 | + rcu_read_unlock(); | |
| 5202 | 5204 | |
| 5203 | 5205 | bond_set_slave_arr(bond, usable_slaves, all_slaves); |
| 5204 | 5206 | return ret; |
| @@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb, · 65 unmodified lines | ||
| 66 | 66 | const struct port *ad_port; |
| 67 | 67 | |
| 68 | 68 | ad_port = &SLAVE_AD_INFO(slave)->port; |
| 69 | − agg = SLAVE_AD_INFO(slave)->port.aggregator; | |
| 69 | + rcu_read_lock(); | |
| 70 | + agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); | |
| 70 | 71 | if (agg) { |
| 71 | 72 | if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, |
| 72 | 73 | agg->aggregator_identifier)) |
| 73 | − goto nla_put_failure; | |
| 74 | + goto nla_put_failure_rcu; | |
| 74 | 75 | if (nla_put_u8(skb, |
| 75 | 76 | IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, |
| 76 | 77 | ad_port->actor_oper_port_state)) |
| 77 | − goto nla_put_failure; | |
| 78 | + goto nla_put_failure_rcu; | |
| 78 | 79 | if (nla_put_u16(skb, |
| 79 | 80 | IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, |
| 80 | 81 | ad_port->partner_oper.port_state)) |
| 81 | − goto nla_put_failure; | |
| 82 | + goto nla_put_failure_rcu; | |
| 82 | 83 | |
| 83 | 84 | if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, |
| 84 | 85 | ad_port->sm_churn_actor_state)) |
| 85 | − goto nla_put_failure; | |
| 86 | + goto nla_put_failure_rcu; | |
| 86 | 87 | if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, |
| 87 | 88 | ad_port->sm_churn_partner_state)) |
| 88 | − goto nla_put_failure; | |
| 89 | + goto nla_put_failure_rcu; | |
| 89 | 90 | } |
| 91 | + rcu_read_unlock(); | |
| 90 | 92 | |
| 91 | 93 | if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, |
| 92 | 94 | SLAVE_AD_INFO(slave)->port_priority)) |
| @@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb, · 2 unmodified lines | ||
| 95 | 97 | |
| 96 | 98 | return 0; |
| 97 | 99 | |
| 100 | +nla_put_failure_rcu: | |
| 101 | + rcu_read_unlock(); | |
| 98 | 102 | nla_put_failure: |
| 99 | 103 | return -EMSGSIZE; |
| 100 | 104 | } |
| @@ -188,6 +188,7 @@ static void bond_info_show_master(struct seq_file *seq) · 187 unmodified lines | ||
| 188 | 188 | } |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | +/* Note: runs under rcu_read_lock() */ | |
| 191 | 192 | static void bond_info_show_slave(struct seq_file *seq, |
| 192 | 193 | const struct slave *slave) |
| 193 | 194 | { |
| @@ -214,7 +215,7 @@ static void bond_info_show_slave(struct seq_file *seq, · 20 unmodified lines | ||
| 214 | 215 | |
| 215 | 216 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { |
| 216 | 217 | const struct port *port = &SLAVE_AD_INFO(slave)->port; |
| 217 | − const struct aggregator *agg = port->aggregator; | |
| 218 | + const struct aggregator *agg = rcu_dereference(port->aggregator); | |
| 218 | 219 | |
| 219 | 220 | if (agg) { |
| 220 | 221 | seq_printf(seq, "Aggregator ID: %d\n", |
| @@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) · 61 unmodified lines | ||
| 62 | 62 | const struct aggregator *agg; |
| 63 | 63 | |
| 64 | 64 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { |
| 65 | − agg = SLAVE_AD_INFO(slave)->port.aggregator; | |
| 66 | − if (agg) | |
| 67 | − return sysfs_emit(buf, "%d\n", | |
| 68 | − agg->aggregator_identifier); | |
| 65 | + rcu_read_lock(); | |
| 66 | + agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); | |
| 67 | + if (agg) { | |
| 68 | + ssize_t res = sysfs_emit(buf, "%d\n", | |
| 69 | + agg->aggregator_identifier); | |
| 70 | + rcu_read_unlock(); | |
| 71 | + return res; | |
| 72 | + } | |
| 73 | + rcu_read_unlock(); | |
| 69 | 74 | } |
| 70 | 75 | |
| 71 | 76 | return sysfs_emit(buf, "N/A\n"); |
| @@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) · 6 unmodified lines | ||
| 78 | 83 | |
| 79 | 84 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { |
| 80 | 85 | ad_port = &SLAVE_AD_INFO(slave)->port; |
| 81 | − if (ad_port->aggregator) | |
| 86 | + if (rcu_access_pointer(ad_port->aggregator)) | |
| 82 | 87 | return sysfs_emit(buf, "%u\n", |
| 83 | 88 | ad_port->actor_oper_port_state); |
| 84 | 89 | } |
| @@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) · 8 unmodified lines | ||
| 93 | 98 | |
| 94 | 99 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { |
| 95 | 100 | ad_port = &SLAVE_AD_INFO(slave)->port; |
| 96 | − if (ad_port->aggregator) | |
| 101 | + if (rcu_access_pointer(ad_port->aggregator)) | |
| 97 | 102 | return sysfs_emit(buf, "%u\n", |
| 98 | 103 | ad_port->partner_oper.port_state); |
| 99 | 104 | } |
| @@ -847,13 +847,24 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) · 846 unmodified lines | ||
| 847 | 847 | { |
| 848 | 848 | struct airoha_qdma *qdma = q->qdma; |
| 849 | 849 | struct airoha_eth *eth = qdma->eth; |
| 850 | − int i; | |
| 850 | + int i, qid = q - &qdma->q_tx[0]; | |
| 851 | 851 | |
| 852 | 852 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { |
| 853 | 853 | struct airoha_gdm_port *port = eth->ports[i]; |
| 854 | + int j; | |
| 855 | + | |
| 856 | + if (!port) | |
| 857 | + continue; | |
| 858 | + | |
| 859 | + if (port->qdma != qdma) | |
| 860 | + continue; | |
| 854 | 861 | |
| 855 | − if (port && port->qdma == qdma) | |
| 856 | − netif_tx_wake_all_queues(port->dev); | |
| 862 | + for (j = 0; j < port->dev->num_tx_queues; j++) { | |
| 863 | + if (airoha_qdma_get_txq(qdma, j) != qid) | |
| 864 | + continue; | |
| 865 | + | |
| 866 | + netif_wake_subqueue(port->dev, j); | |
| 867 | + } | |
| 857 | 868 | } |
| 858 | 869 | q->txq_stopped = false; |
| 859 | 870 | } |
| @@ -929,10 +940,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) · 69 unmodified lines | ||
| 929 | 940 | q->queued--; |
| 930 | 941 | |
| 931 | 942 | if (skb) { |
| 932 | − u16 queue = skb_get_queue_mapping(skb); | |
| 933 | 943 | struct netdev_queue *txq; |
| 934 | 944 | |
| 935 | − txq = netdev_get_tx_queue(skb->dev, queue); | |
| 945 | + txq = skb_get_tx_queue(skb->dev, skb); | |
| 936 | 946 | netdev_tx_completed_queue(txq, 1, skb->len); |
| 937 | 947 | dev_kfree_skb_any(skb); |
| 938 | 948 | } |
| @@ -1737,14 +1747,11 @@ static int airoha_dev_stop(struct net_device *dev) · 798 unmodified lines | ||
| 1737 | 1747 | { |
| 1738 | 1748 | struct airoha_gdm_port *port = netdev_priv(dev); |
| 1739 | 1749 | struct airoha_qdma *qdma = port->qdma; |
| 1740 | − int i, err; | |
| 1750 | + int i; | |
| 1741 | 1751 | |
| 1742 | 1752 | netif_tx_disable(dev); |
| 1743 | − err = airoha_set_vip_for_gdm_port(port, false); | |
| 1744 | − if (err) | |
| 1745 | − return err; | |
| 1746 | − | |
| 1747 | − for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) | |
| 1753 | + airoha_set_vip_for_gdm_port(port, false); | |
| 1754 | + for (i = 0; i < dev->num_tx_queues; i++) | |
| 1748 | 1755 | netdev_tx_reset_subqueue(dev, i); |
| 1749 | 1756 | |
| 1750 | 1757 | airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), |
| @@ -1997,12 +2004,12 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 246 unmodified lines | ||
| 1997 | 2004 | struct netdev_queue *txq; |
| 1998 | 2005 | struct airoha_queue *q; |
| 1999 | 2006 | LIST_HEAD(tx_list); |
| 2007 | + int i = 0, qid; | |
| 2000 | 2008 | void *data; |
| 2001 | − int i, qid; | |
| 2002 | 2009 | u16 index; |
| 2003 | 2010 | u8 fport; |
| 2004 | 2011 | |
| 2005 | − qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx); | |
| 2012 | + qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); | |
| 2006 | 2013 | tag = airoha_get_dsa_tag(skb, dev); |
| 2007 | 2014 | |
| 2008 | 2015 | msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, |
| @@ -2039,7 +2046,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 30 unmodified lines | ||
| 2039 | 2046 | |
| 2040 | 2047 | spin_lock_bh(&q->lock); |
| 2041 | 2048 | |
| 2042 | − txq = netdev_get_tx_queue(dev, qid); | |
| 2049 | + txq = skb_get_tx_queue(dev, skb); | |
| 2043 | 2050 | nr_frags = 1 + skb_shinfo(skb)->nr_frags; |
| 2044 | 2051 | |
| 2045 | 2052 | if (q->queued + nr_frags >= q->ndesc) { |
| @@ -2057,7 +2064,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 11 unmodified lines | ||
| 2057 | 2064 | list); |
| 2058 | 2065 | index = e - q->entry; |
| 2059 | 2066 | |
| 2060 | − for (i = 0; i < nr_frags; i++) { | |
| 2067 | + while (true) { | |
| 2061 | 2068 | struct airoha_qdma_desc *desc = &q->desc[index]; |
| 2062 | 2069 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
| 2063 | 2070 | dma_addr_t addr; |
| @@ -2069,7 +2076,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 5 unmodified lines | ||
| 2069 | 2076 | goto error_unmap; |
| 2070 | 2077 | |
| 2071 | 2078 | list_move_tail(&e->list, &tx_list); |
| 2072 | − e->skb = i ? NULL : skb; | |
| 2079 | + e->skb = i == nr_frags - 1 ? skb : NULL; | |
| 2073 | 2080 | e->dma_addr = addr; |
| 2074 | 2081 | e->dma_len = len; |
| 2075 | 2082 | |
| @@ -2088,6 +2095,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 12 unmodified lines | ||
| 2088 | 2095 | WRITE_ONCE(desc->msg1, cpu_to_le32(msg1)); |
| 2089 | 2096 | WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff)); |
| 2090 | 2097 | |
| 2098 | + if (++i == nr_frags) | |
| 2099 | + break; | |
| 2100 | + | |
| 2091 | 2101 | data = skb_frag_address(frag); |
| 2092 | 2102 | len = skb_frag_size(frag); |
| 2093 | 2103 | } |
| @@ -2095,17 +2105,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 1 unmodified line | ||
| 2095 | 2105 | |
| 2096 | 2106 | skb_tx_timestamp(skb); |
| 2097 | 2107 | netdev_tx_sent_queue(txq, skb->len); |
| 2108 | + if (q->ndesc - q->queued < q->free_thr) { | |
| 2109 | + netif_tx_stop_queue(txq); | |
| 2110 | + q->txq_stopped = true; | |
| 2111 | + } | |
| 2098 | 2112 | |
| 2099 | 2113 | if (netif_xmit_stopped(txq) || !netdev_xmit_more()) |
| 2100 | 2114 | airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), |
| 2101 | 2115 | TX_RING_CPU_IDX_MASK, |
| 2102 | 2116 | FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); |
| 2103 | 2117 | |
| 2104 | − if (q->ndesc - q->queued < q->free_thr) { | |
| 2105 | − netif_tx_stop_queue(txq); | |
| 2106 | − q->txq_stopped = true; | |
| 2107 | − } | |
| 2108 | − | |
| 2109 | 2118 | spin_unlock_bh(&q->lock); |
| 2110 | 2119 | |
| 2111 | 2120 | return NETDEV_TX_OK; |
| @@ -631,6 +631,11 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val); · 630 unmodified lines | ||
| 631 | 631 | #define airoha_qdma_clear(qdma, offset, val) \ |
| 632 | 632 | airoha_rmw((qdma)->regs, (offset), (val), 0) |
| 633 | 633 | |
| 634 | +static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid) | |
| 635 | +{ | |
| 636 | + return qid % ARRAY_SIZE(qdma->q_tx); | |
| 637 | +} | |
| 638 | + | |
| 634 | 639 | static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) |
| 635 | 640 | { |
| 636 | 641 | /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. |
| @@ -1756,6 +1756,27 @@ static int ibmveth_set_mac_addr(struct net_device *dev, void *p) · 1755 unmodified lines | ||
| 1756 | 1756 | return 0; |
| 1757 | 1757 | } |
| 1758 | 1758 | |
| 1759 | +static netdev_features_t ibmveth_features_check(struct sk_buff *skb, | |
| 1760 | + struct net_device *dev, | |
| 1761 | + netdev_features_t features) | |
| 1762 | +{ | |
| 1763 | + /* Some physical adapters do not support segmentation offload with | |
| 1764 | + * MSS < 224. Disable GSO for such packets to avoid adapter freeze. | |
| 1765 | + * Note: Single-segment packets (gso_segs == 1) don't need this check | |
| 1766 | + * as they bypass the LSO path and are transmitted without segmentation. | |
| 1767 | + */ | |
| 1768 | + if (skb_is_gso(skb)) { | |
| 1769 | + if (skb_shinfo(skb)->gso_size < IBMVETH_MIN_LSO_MSS) { | |
| 1770 | + netdev_warn_once(dev, | |
| 1771 | + "MSS %u too small for LSO, disabling GSO\n", | |
| 1772 | + skb_shinfo(skb)->gso_size); | |
| 1773 | + features &= ~NETIF_F_GSO_MASK; | |
| 1774 | + } | |
| 1775 | + } | |
| 1776 | + | |
| 1777 | + return vlan_features_check(skb, features); | |
| 1778 | +} | |
| 1779 | + | |
| 1759 | 1780 | static const struct net_device_ops ibmveth_netdev_ops = { |
| 1760 | 1781 | .ndo_open = ibmveth_open, |
| 1761 | 1782 | .ndo_stop = ibmveth_close, |
| @@ -1767,6 +1788,7 @@ static const struct net_device_ops ibmveth_netdev_ops = { · 5 unmodified lines | ||
| 1767 | 1788 | .ndo_set_features = ibmveth_set_features, |
| 1768 | 1789 | .ndo_validate_addr = eth_validate_addr, |
| 1769 | 1790 | .ndo_set_mac_address = ibmveth_set_mac_addr, |
| 1791 | + .ndo_features_check = ibmveth_features_check, | |
| 1770 | 1792 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| 1771 | 1793 | .ndo_poll_controller = ibmveth_poll_controller, |
| 1772 | 1794 | #endif |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | #define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL |
| 38 | 38 | #define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL |
| 39 | 39 | |
| 40 | +#define IBMVETH_MIN_LSO_MSS 224 /* Minimum MSS for LSO */ | |
| 40 | 41 | /* hcall macros */ |
| 41 | 42 | #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ |
| 42 | 43 | plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac) |
| @@ -158,11 +158,10 @@ struct iavf_vlan { · 157 unmodified lines | ||
| 158 | 158 | enum iavf_vlan_state_t { |
| 159 | 159 | IAVF_VLAN_INVALID, |
| 160 | 160 | IAVF_VLAN_ADD, /* filter needs to be added */ |
| 161 | − IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ | |
| 162 | − IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ | |
| 163 | − IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ | |
| 164 | − IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ | |
| 165 | − IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ | |
| 161 | + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ | |
| 162 | + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ | |
| 163 | + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ | |
| 164 | + IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ | |
| 166 | 165 | }; |
| 167 | 166 | |
| 168 | 167 | struct iavf_vlan_filter { |
| @@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, · 756 unmodified lines | ||
| 757 | 757 | adapter->num_vlan_filters++; |
| 758 | 758 | iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); |
| 759 | 759 | } else if (f->state == IAVF_VLAN_REMOVE) { |
| 760 | − /* Re-add the filter since we cannot tell whether the | |
| 761 | − * pending delete has already been processed by the PF. | |
| 762 | − * A duplicate add is harmless. | |
| 763 | − */ | |
| 760 | + /* DEL not yet sent to PF, cancel it */ | |
| 761 | + f->state = IAVF_VLAN_ACTIVE; | |
| 762 | + } else if (f->state == IAVF_VLAN_REMOVING) { | |
| 763 | + /* DEL already sent to PF, re-add after completion */ | |
| 764 | 764 | f->state = IAVF_VLAN_ADD; |
| 765 | 765 | iavf_schedule_aq_request(adapter, |
| 766 | 766 | IAVF_FLAG_AQ_ADD_VLAN_FILTER); |
| @@ -791,37 +791,19 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) · 24 unmodified lines | ||
| 791 | 791 | list_del(&f->list); |
| 792 | 792 | kfree(f); |
| 793 | 793 | adapter->num_vlan_filters--; |
| 794 | − } else { | |
| 794 | + } else if (f->state != IAVF_VLAN_REMOVING) { | |
| 795 | 795 | f->state = IAVF_VLAN_REMOVE; |
| 796 | 796 | iavf_schedule_aq_request(adapter, |
| 797 | 797 | IAVF_FLAG_AQ_DEL_VLAN_FILTER); |
| 798 | 798 | } |
| 799 | + /* If REMOVING, DEL is already sent to PF; completion | |
| 800 | + * handler will free the filter when PF confirms. | |
| 801 | + */ | |
| 799 | 802 | } |
| 800 | 803 | |
| 801 | 804 | spin_unlock_bh(&adapter->mac_vlan_list_lock); |
| 802 | 805 | } |
| 803 | 806 | |
| 804 | −/** | |
| 805 | − * iavf_restore_filters | |
| 806 | − * @adapter: board private structure | |
| 807 | − * | |
| 808 | − * Restore existing non MAC filters when VF netdev comes back up | |
| 809 | − **/ | |
| 810 | −static void iavf_restore_filters(struct iavf_adapter *adapter) | |
| 811 | −{ | |
| 812 | − struct iavf_vlan_filter *f; | |
| 813 | − | |
| 814 | − /* re-add all VLAN filters */ | |
| 815 | − spin_lock_bh(&adapter->mac_vlan_list_lock); | |
| 816 | − | |
| 817 | − list_for_each_entry(f, &adapter->vlan_filter_list, list) { | |
| 818 | − if (f->state == IAVF_VLAN_INACTIVE) | |
| 819 | − f->state = IAVF_VLAN_ADD; | |
| 820 | − } | |
| 821 | − | |
| 822 | − spin_unlock_bh(&adapter->mac_vlan_list_lock); | |
| 823 | − adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; | |
| 824 | −} | |
| 825 | 807 | |
| 826 | 808 | /** |
| 827 | 809 | * iavf_get_num_vlans_added - get number of VLANs added |
| @@ -1246,13 +1228,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) · 418 unmodified lines | ||
| 1246 | 1228 | } |
| 1247 | 1229 | |
| 1248 | 1230 | /** |
| 1249 | − * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF | |
| 1250 | − * yet and mark other to be removed. | |
| 1231 | + * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark | |
| 1232 | + * others to be removed. | |
| 1251 | 1233 | * @adapter: board private structure |
| 1252 | 1234 | **/ |
| 1253 | −static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) | |
| 1235 | +static void iavf_clear_mac_filters(struct iavf_adapter *adapter) | |
| 1254 | 1236 | { |
| 1255 | − struct iavf_vlan_filter *vlf, *vlftmp; | |
| 1256 | 1237 | struct iavf_mac_filter *f, *ftmp; |
| 1257 | 1238 | |
| 1258 | 1239 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| @@ -1271,11 +1252,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) · 12 unmodified lines | ||
| 1271 | 1252 | } |
| 1272 | 1253 | } |
| 1273 | 1254 | |
| 1274 | − /* disable all VLAN filters */ | |
| 1275 | − list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, | |
| 1276 | − list) | |
| 1277 | − vlf->state = IAVF_VLAN_DISABLE; | |
| 1278 | − | |
| 1279 | 1255 | spin_unlock_bh(&adapter->mac_vlan_list_lock); |
| 1280 | 1256 | } |
| 1281 | 1257 | |
| @@ -1371,7 +1347,7 @@ void iavf_down(struct iavf_adapter *adapter) · 89 unmodified lines | ||
| 1371 | 1347 | iavf_napi_disable_all(adapter); |
| 1372 | 1348 | iavf_irq_disable(adapter); |
| 1373 | 1349 | |
| 1374 | − iavf_clear_mac_vlan_filters(adapter); | |
| 1350 | + iavf_clear_mac_filters(adapter); | |
| 1375 | 1351 | iavf_clear_cloud_filters(adapter); |
| 1376 | 1352 | iavf_clear_fdir_filters(adapter); |
| 1377 | 1353 | iavf_clear_adv_rss_conf(adapter); |
| @@ -1388,8 +1364,6 @@ void iavf_down(struct iavf_adapter *adapter) · 10 unmodified lines | ||
| 1388 | 1364 | */ |
| 1389 | 1365 | if (!list_empty(&adapter->mac_filter_list)) |
| 1390 | 1366 | adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; |
| 1391 | − if (!list_empty(&adapter->vlan_filter_list)) | |
| 1392 | − adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; | |
| 1393 | 1367 | if (!list_empty(&adapter->cloud_filter_list)) |
| 1394 | 1368 | adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; |
| 1395 | 1369 | if (!list_empty(&adapter->fdir_list_head)) |
| @@ -4494,8 +4468,6 @@ static int iavf_open(struct net_device *netdev) · 3098 unmodified lines | ||
| 4494 | 4468 | iavf_add_filter(adapter, adapter->hw.mac.addr); |
| 4495 | 4469 | spin_unlock_bh(&adapter->mac_vlan_list_lock); |
| 4496 | 4470 | |
| 4497 | − /* Restore filters that were removed with IFF_DOWN */ | |
| 4498 | − iavf_restore_filters(adapter); | |
| 4499 | 4471 | iavf_restore_fdir_filters(adapter); |
| 4500 | 4472 | |
| 4501 | 4473 | iavf_configure(adapter); |
| @@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) · 745 unmodified lines | ||
| 746 | 746 | |
| 747 | 747 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| 748 | 748 | list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { |
| 749 | − if (f->state == IAVF_VLAN_IS_NEW) { | |
| 749 | + if (f->state == IAVF_VLAN_ADDING) { | |
| 750 | 750 | list_del(&f->list); |
| 751 | 751 | kfree(f); |
| 752 | 752 | adapter->num_vlan_filters--; |
| @@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) · 59 unmodified lines | ||
| 812 | 812 | if (f->state == IAVF_VLAN_ADD) { |
| 813 | 813 | vvfl->vlan_id[i] = f->vlan.vid; |
| 814 | 814 | i++; |
| 815 | − f->state = IAVF_VLAN_IS_NEW; | |
| 815 | + f->state = IAVF_VLAN_ADDING; | |
| 816 | 816 | if (i == count) |
| 817 | 817 | break; |
| 818 | 818 | } |
| @@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) · 55 unmodified lines | ||
| 874 | 874 | vlan->tpid = f->vlan.tpid; |
| 875 | 875 | |
| 876 | 876 | i++; |
| 877 | − f->state = IAVF_VLAN_IS_NEW; | |
| 877 | + f->state = IAVF_VLAN_ADDING; | |
| 878 | 878 | } |
| 879 | 879 | } |
| 880 | 880 | |
| @@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 30 unmodified lines | ||
| 911 | 911 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| 912 | 912 | |
| 913 | 913 | list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { |
| 914 | − /* since VLAN capabilities are not allowed, we dont want to send | |
| 915 | − * a VLAN delete request because it will most likely fail and | |
| 916 | − * create unnecessary errors/noise, so just free the VLAN | |
| 917 | − * filters marked for removal to enable bailing out before | |
| 918 | − * sending a virtchnl message | |
| 919 | − */ | |
| 920 | 914 | if (f->state == IAVF_VLAN_REMOVE && |
| 921 | 915 | !VLAN_FILTERING_ALLOWED(adapter)) { |
| 922 | 916 | list_del(&f->list); |
| 923 | 917 | kfree(f); |
| 924 | 918 | adapter->num_vlan_filters--; |
| 925 | − } else if (f->state == IAVF_VLAN_DISABLE && | |
| 926 | − !VLAN_FILTERING_ALLOWED(adapter)) { | |
| 927 | − f->state = IAVF_VLAN_INACTIVE; | |
| 928 | − } else if (f->state == IAVF_VLAN_REMOVE || | |
| 929 | − f->state == IAVF_VLAN_DISABLE) { | |
| 919 | + } else if (f->state == IAVF_VLAN_REMOVE) { | |
| 930 | 920 | count++; |
| 931 | 921 | } |
| 932 | 922 | } |
| @@ -958,18 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 25 unmodified lines | ||
| 958 | 948 | |
| 959 | 949 | vvfl->vsi_id = adapter->vsi_res->vsi_id; |
| 960 | 950 | vvfl->num_elements = count; |
| 961 | − list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | |
| 962 | − if (f->state == IAVF_VLAN_DISABLE) { | |
| 963 | − vvfl->vlan_id[i] = f->vlan.vid; | |
| 964 | − f->state = IAVF_VLAN_INACTIVE; | |
| 965 | − i++; | |
| 966 | − if (i == count) | |
| 967 | − break; | |
| 968 | − } else if (f->state == IAVF_VLAN_REMOVE) { | |
| 951 | + list_for_each_entry(f, &adapter->vlan_filter_list, list) { | |
| 952 | + if (f->state == IAVF_VLAN_REMOVE) { | |
| 969 | 953 | vvfl->vlan_id[i] = f->vlan.vid; |
| 970 | − list_del(&f->list); | |
| 971 | − kfree(f); | |
| 972 | − adapter->num_vlan_filters--; | |
| 954 | + f->state = IAVF_VLAN_REMOVING; | |
| 973 | 955 | i++; |
| 974 | 956 | if (i == count) |
| 975 | 957 | break; |
| @@ -1006,9 +988,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 30 unmodified lines | ||
| 1006 | 988 | |
| 1007 | 989 | vvfl_v2->vport_id = adapter->vsi_res->vsi_id; |
| 1008 | 990 | vvfl_v2->num_elements = count; |
| 1009 | − list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | |
| 1010 | − if (f->state == IAVF_VLAN_DISABLE || | |
| 1011 | − f->state == IAVF_VLAN_REMOVE) { | |
| 991 | + list_for_each_entry(f, &adapter->vlan_filter_list, list) { | |
| 992 | + if (f->state == IAVF_VLAN_REMOVE) { | |
| 1012 | 993 | struct virtchnl_vlan_supported_caps *filtering_support = |
| 1013 | 994 | &adapter->vlan_v2_caps.filtering.filtering_support; |
| 1014 | 995 | struct virtchnl_vlan *vlan; |
| @@ -1022,13 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 7 unmodified lines | ||
| 1022 | 1003 | vlan->tci = f->vlan.vid; |
| 1023 | 1004 | vlan->tpid = f->vlan.tpid; |
| 1024 | 1005 | |
| 1025 | − if (f->state == IAVF_VLAN_DISABLE) { | |
| 1026 | − f->state = IAVF_VLAN_INACTIVE; | |
| 1027 | − } else { | |
| 1028 | − list_del(&f->list); | |
| 1029 | − kfree(f); | |
| 1030 | − adapter->num_vlan_filters--; | |
| 1031 | − } | |
| 1006 | + f->state = IAVF_VLAN_REMOVING; | |
| 1032 | 1007 | i++; |
| 1033 | 1008 | if (i == count) |
| 1034 | 1009 | break; |
| @@ -2391,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, · 1356 unmodified lines | ||
| 2391 | 2366 | ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); |
| 2392 | 2367 | wake_up(&adapter->vc_waitqueue); |
| 2393 | 2368 | break; |
| 2394 | − case VIRTCHNL_OP_DEL_VLAN: | |
| 2395 | − dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", | |
| 2396 | − iavf_stat_str(&adapter->hw, v_retval)); | |
| 2397 | − break; | |
| 2398 | 2369 | case VIRTCHNL_OP_DEL_ETH_ADDR: |
| 2399 | 2370 | dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", |
| 2400 | 2371 | iavf_stat_str(&adapter->hw, v_retval)); |
| @@ -2905,17 +2876,42 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, · 504 unmodified lines | ||
| 2905 | 2876 | spin_unlock_bh(&adapter->adv_rss_lock); |
| 2906 | 2877 | } |
| 2907 | 2878 | break; |
| 2879 | + case VIRTCHNL_OP_ADD_VLAN: | |
| 2908 | 2880 | case VIRTCHNL_OP_ADD_VLAN_V2: { |
| 2909 | 2881 | struct iavf_vlan_filter *f; |
| 2910 | 2882 | |
| 2883 | + if (v_retval) | |
| 2884 | + break; | |
| 2885 | + | |
| 2911 | 2886 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| 2912 | 2887 | list_for_each_entry(f, &adapter->vlan_filter_list, list) { |
| 2913 | − if (f->state == IAVF_VLAN_IS_NEW) | |
| 2888 | + if (f->state == IAVF_VLAN_ADDING) | |
| 2914 | 2889 | f->state = IAVF_VLAN_ACTIVE; |
| 2915 | 2890 | } |
| 2916 | 2891 | spin_unlock_bh(&adapter->mac_vlan_list_lock); |
| 2917 | 2892 | } |
| 2918 | 2893 | break; |
| 2894 | + case VIRTCHNL_OP_DEL_VLAN: | |
| 2895 | + case VIRTCHNL_OP_DEL_VLAN_V2: { | |
| 2896 | + struct iavf_vlan_filter *f, *ftmp; | |
| 2897 | + | |
| 2898 | + spin_lock_bh(&adapter->mac_vlan_list_lock); | |
| 2899 | + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, | |
| 2900 | + list) { | |
| 2901 | + if (f->state == IAVF_VLAN_REMOVING) { | |
| 2902 | + if (v_retval) { | |
| 2903 | + /* PF rejected DEL, keep filter */ | |
| 2904 | + f->state = IAVF_VLAN_ACTIVE; | |
| 2905 | + } else { | |
| 2906 | + list_del(&f->list); | |
| 2907 | + kfree(f); | |
| 2908 | + adapter->num_vlan_filters--; | |
| 2909 | + } | |
| 2910 | + } | |
| 2911 | + } | |
| 2912 | + spin_unlock_bh(&adapter->mac_vlan_list_lock); | |
| 2913 | + } | |
| 2914 | + break; | |
| 2919 | 2915 | case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: |
| 2920 | 2916 | /* PF enabled vlan strip on this VF. |
| 2921 | 2917 | * Update netdev->features if needed to be in sync with ethtool. |
| @@ -1245,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) · 1244 unmodified lines | ||
| 1245 | 1245 | return err; |
| 1246 | 1246 | } |
| 1247 | 1247 | |
| 1248 | + ice_init_dev_hw(pf); | |
| 1249 | + | |
| 1248 | 1250 | /* load MSI-X values */ |
| 1249 | 1251 | ice_set_min_max_msix(pf); |
| 1250 | 1252 | |
| @@ -1126,8 +1126,6 @@ int ice_init_hw(struct ice_hw *hw) · 1125 unmodified lines | ||
| 1126 | 1126 | if (status) |
| 1127 | 1127 | goto err_unroll_fltr_mgmt_struct; |
| 1128 | 1128 | |
| 1129 | − ice_init_dev_hw(hw->back); | |
| 1130 | − | |
| 1131 | 1129 | mutex_init(&hw->tnl_lock); |
| 1132 | 1130 | ice_init_chk_recipe_reuse_support(hw); |
| 1133 | 1131 | |
| @@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, · 1153 unmodified lines | ||
| 1154 | 1154 | extack, ICE_DPLL_PIN_TYPE_INPUT); |
| 1155 | 1155 | } |
| 1156 | 1156 | |
| 1157 | +/** | |
| 1158 | + * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change | |
| 1159 | + * @d: pointer to dplls struct | |
| 1160 | + * @changed: the SW pin that was explicitly changed (already notified by dpll core) | |
| 1161 | + * | |
| 1162 | + * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and | |
| 1163 | + * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO | |
| 1164 | + * expander, the paired pin's state may also change. Send a change | |
| 1165 | + * notification for the peer pin so userspace consumers monitoring the | |
| 1166 | + * peer via dpll netlink learn about the update. | |
| 1167 | + * | |
| 1168 | + * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is | |
| 1169 | + * released. Uses __dpll_pin_change_ntf() because dpll_lock is | |
| 1170 | + * still held by the dpll netlink layer. | |
| 1171 | + */ | |
| 1172 | +static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d, | |
| 1173 | + struct ice_dpll_pin *changed) | |
| 1174 | +{ | |
| 1175 | + struct ice_dpll_pin *peer; | |
| 1176 | + | |
| 1177 | + peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ? | |
| 1178 | + &d->ufl[changed->idx] : &d->sma[changed->idx]; | |
| 1179 | + if (peer->pin) | |
| 1180 | + __dpll_pin_change_ntf(peer->pin); | |
| 1181 | +} | |
| 1182 | + | |
| 1157 | 1183 | /** |
| 1158 | 1184 | * ice_dpll_sma_direction_set - set direction of SMA pin |
| 1159 | 1185 | * @p: pointer to a pin |
| @@ -1171,6 +1197,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, · 11 unmodified lines | ||
| 1171 | 1197 | enum dpll_pin_direction direction, |
| 1172 | 1198 | struct netlink_ext_ack *extack) |
| 1173 | 1199 | { |
| 1200 | + struct ice_dplls *d = &p->pf->dplls; | |
| 1201 | + struct ice_dpll_pin *peer; | |
| 1174 | 1202 | u8 data; |
| 1175 | 1203 | int ret; |
| 1176 | 1204 | |
| @@ -1189,8 +1217,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, · 12 unmodified lines | ||
| 1189 | 1217 | case ICE_DPLL_PIN_SW_2_IDX: |
| 1190 | 1218 | if (direction == DPLL_PIN_DIRECTION_INPUT) { |
| 1191 | 1219 | data &= ~ICE_SMA2_DIR_EN; |
| 1220 | + data |= ICE_SMA2_UFL2_RX_DIS; | |
| 1192 | 1221 | } else { |
| 1193 | − data &= ~ICE_SMA2_TX_EN; | |
| 1222 | + data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS); | |
| 1194 | 1223 | data |= ICE_SMA2_DIR_EN; |
| 1195 | 1224 | } |
| 1196 | 1225 | break; |
| @@ -1202,6 +1231,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, · 5 unmodified lines | ||
| 1202 | 1231 | ret = ice_dpll_pin_state_update(p->pf, p, |
| 1203 | 1232 | ICE_DPLL_PIN_TYPE_SOFTWARE, |
| 1204 | 1233 | extack); |
| 1234 | + if (ret) | |
| 1235 | + return ret; | |
| 1236 | + | |
| 1237 | + /* When a direction change activates the paired U.FL pin, enable | |
| 1238 | + * its backing CGU pin so the pin reports as connected. Without | |
| 1239 | + * this the U.FL routing is correct but the CGU pin stays disabled | |
| 1240 | + * and userspace sees the pin as disconnected. Do not disable the | |
| 1241 | + * backing pin when U.FL becomes inactive because the SMA pin may | |
| 1242 | + * still be using it. | |
| 1243 | + */ | |
| 1244 | + peer = &d->ufl[p->idx]; | |
| 1245 | + if (peer->active) { | |
| 1246 | + struct ice_dpll_pin *target; | |
| 1247 | + enum ice_dpll_pin_type type; | |
| 1248 | + | |
| 1249 | + if (peer->output) { | |
| 1250 | + target = peer->output; | |
| 1251 | + type = ICE_DPLL_PIN_TYPE_OUTPUT; | |
| 1252 | + } else { | |
| 1253 | + target = peer->input; | |
| 1254 | + type = ICE_DPLL_PIN_TYPE_INPUT; | |
| 1255 | + } | |
| 1256 | + ret = ice_dpll_pin_enable(&p->pf->hw, target, | |
| 1257 | + d->eec.dpll_idx, type, extack); | |
| 1258 | + if (!ret) | |
| 1259 | + ret = ice_dpll_pin_state_update(p->pf, target, | |
| 1260 | + type, extack); | |
| 1261 | + } | |
| 1205 | 1262 | |
| 1206 | 1263 | return ret; |
| 1207 | 1264 | } |
| @@ -1253,6 +1310,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, · 45 unmodified lines | ||
| 1253 | 1310 | data &= ~ICE_SMA1_MASK; |
| 1254 | 1311 | enable = true; |
| 1255 | 1312 | } else if (state == DPLL_PIN_STATE_DISCONNECTED) { |
| 1313 | + /* Skip if U.FL1 is not active, setting TX_EN | |
| 1314 | + * while DIR_EN is set would also deactivate | |
| 1315 | + * the paired SMA1 output. | |
| 1316 | + */ | |
| 1317 | + if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) { | |
| 1318 | + ret = 0; | |
| 1319 | + goto unlock; | |
| 1320 | + } | |
| 1256 | 1321 | data |= ICE_SMA1_TX_EN; |
| 1257 | 1322 | enable = false; |
| 1258 | 1323 | } else { |
| @@ -1267,6 +1332,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, · 8 unmodified lines | ||
| 1267 | 1332 | data &= ~ICE_SMA2_UFL2_RX_DIS; |
| 1268 | 1333 | enable = true; |
| 1269 | 1334 | } else if (state == DPLL_PIN_STATE_DISCONNECTED) { |
| 1335 | + /* Skip if U.FL2 is not active, setting | |
| 1336 | + * UFL2_RX_DIS could also disable the paired | |
| 1337 | + * SMA2 input. | |
| 1338 | + */ | |
| 1339 | + if (!(data & ICE_SMA2_DIR_EN) || | |
| 1340 | + (data & ICE_SMA2_UFL2_RX_DIS)) { | |
| 1341 | + ret = 0; | |
| 1342 | + goto unlock; | |
| 1343 | + } | |
| 1270 | 1344 | data |= ICE_SMA2_UFL2_RX_DIS; |
| 1271 | 1345 | enable = false; |
| 1272 | 1346 | } else { |
| @@ -1296,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, · 23 unmodified lines | ||
| 1296 | 1370 | |
| 1297 | 1371 | unlock: |
| 1298 | 1372 | mutex_unlock(&pf->dplls.lock); |
| 1373 | + if (!ret) | |
| 1374 | + ice_dpll_sw_pin_notify_peer(&pf->dplls, p); | |
| 1299 | 1375 | |
| 1300 | 1376 | return ret; |
| 1301 | 1377 | } |
| @@ -1414,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, · 112 unmodified lines | ||
| 1414 | 1490 | |
| 1415 | 1491 | unlock: |
| 1416 | 1492 | mutex_unlock(&pf->dplls.lock); |
| 1493 | + if (!ret) | |
| 1494 | + ice_dpll_sw_pin_notify_peer(&pf->dplls, sma); | |
| 1417 | 1495 | |
| 1418 | 1496 | return ret; |
| 1419 | 1497 | } |
| @@ -1609,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv, · 189 unmodified lines | ||
| 1609 | 1687 | mutex_lock(&pf->dplls.lock); |
| 1610 | 1688 | ret = ice_dpll_sma_direction_set(p, direction, extack); |
| 1611 | 1689 | mutex_unlock(&pf->dplls.lock); |
| 1690 | + if (!ret) | |
| 1691 | + ice_dpll_sw_pin_notify_peer(&pf->dplls, p); | |
| 1612 | 1692 | |
| 1613 | 1693 | return ret; |
| 1614 | 1694 | } |
| @@ -1915,7 +1995,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, · 300 unmodified lines | ||
| 1915 | 1995 | d->active_input == p->input->pin)) |
| 1916 | 1996 | *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; |
| 1917 | 1997 | else if (d->phase_offset_monitor_period) |
| 1918 | − *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; | |
| 1998 | + *phase_offset = (p->input && | |
| 1999 | + p->direction == DPLL_PIN_DIRECTION_INPUT ? | |
| 2000 | + p->input->phase_offset : | |
| 2001 | + p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR; | |
| 1919 | 2002 | else |
| 1920 | 2003 | *phase_offset = 0; |
| 1921 | 2004 | mutex_unlock(&pf->dplls.lock); |
| @@ -2609,6 +2692,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) · 687 unmodified lines | ||
| 2609 | 2692 | return pci_get_dsn(pf->pdev); |
| 2610 | 2693 | } |
| 2611 | 2694 | |
| 2695 | +/** | |
| 2696 | + * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers | |
| 2697 | + * @dplls: pointer to dplls struct | |
| 2698 | + * @pin: the dpll_pin that changed | |
| 2699 | + * | |
| 2700 | + * Send a change notification for @pin and for any registered SMA/U.FL pin | |
| 2701 | + * whose backing CGU input matches @pin. | |
| 2702 | + */ | |
| 2703 | +static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin) | |
| 2704 | +{ | |
| 2705 | + dpll_pin_change_ntf(pin); | |
| 2706 | + for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { | |
| 2707 | + if (dplls->sma[i].pin && dplls->sma[i].input && | |
| 2708 | + dplls->sma[i].input->pin == pin) | |
| 2709 | + dpll_pin_change_ntf(dplls->sma[i].pin); | |
| 2710 | + if (dplls->ufl[i].pin && dplls->ufl[i].input && | |
| 2711 | + dplls->ufl[i].input->pin == pin) | |
| 2712 | + dpll_pin_change_ntf(dplls->ufl[i].pin); | |
| 2713 | + } | |
| 2714 | +} | |
| 2715 | + | |
| 2612 | 2716 | /** |
| 2613 | 2717 | * ice_dpll_notify_changes - notify dpll subsystem about changes |
| 2614 | 2718 | * @d: pointer do dpll |
| @@ -2617,6 +2721,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) · 2 unmodified lines | ||
| 2617 | 2721 | */ |
| 2618 | 2722 | static void ice_dpll_notify_changes(struct ice_dpll *d) |
| 2619 | 2723 | { |
| 2724 | + struct ice_dplls *dplls = &d->pf->dplls; | |
| 2620 | 2725 | bool pin_notified = false; |
| 2621 | 2726 | |
| 2622 | 2727 | if (d->prev_dpll_state != d->dpll_state) { |
| @@ -2625,17 +2730,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) · 2 unmodified lines | ||
| 2625 | 2730 | } |
| 2626 | 2731 | if (d->prev_input != d->active_input) { |
| 2627 | 2732 | if (d->prev_input) |
| 2628 | − dpll_pin_change_ntf(d->prev_input); | |
| 2733 | + ice_dpll_pin_ntf(dplls, d->prev_input); | |
| 2629 | 2734 | d->prev_input = d->active_input; |
| 2630 | 2735 | if (d->active_input) { |
| 2631 | − dpll_pin_change_ntf(d->active_input); | |
| 2736 | + ice_dpll_pin_ntf(dplls, d->active_input); | |
| 2632 | 2737 | pin_notified = true; |
| 2633 | 2738 | } |
| 2634 | 2739 | } |
| 2635 | 2740 | if (d->prev_phase_offset != d->phase_offset) { |
| 2636 | 2741 | d->prev_phase_offset = d->phase_offset; |
| 2637 | 2742 | if (!pin_notified && d->active_input) |
| 2638 | − dpll_pin_change_ntf(d->active_input); | |
| 2743 | + ice_dpll_pin_ntf(dplls, d->active_input); | |
| 2639 | 2744 | } |
| 2640 | 2745 | } |
| 2641 | 2746 | |
| @@ -2664,6 +2769,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) · 22 unmodified lines | ||
| 2664 | 2769 | |
| 2665 | 2770 | /** |
| 2666 | 2771 | * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes |
| 2772 | + * @dplls: pointer to dplls struct | |
| 2667 | 2773 | * @pins: array of ice_dpll_pin pointers registered within dpll subsystem |
| 2668 | 2774 | * @pin_num: number of pins |
| 2669 | 2775 | * @phase_offset_ntf_mask: bitmask of pin indexes to notify |
| @@ -2673,15 +2779,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) · 3 unmodified lines | ||
| 2673 | 2779 | * |
| 2674 | 2780 | * Context: Must be called while pf->dplls.lock is released. |
| 2675 | 2781 | */ |
| 2676 | −static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins, | |
| 2782 | +static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls, | |
| 2783 | + struct ice_dpll_pin *pins, | |
| 2677 | 2784 | u8 pin_num, |
| 2678 | 2785 | u32 phase_offset_ntf_mask) |
| 2679 | 2786 | { |
| 2680 | − int i = 0; | |
| 2681 | − | |
| 2682 | − for (i = 0; i < pin_num; i++) | |
| 2683 | − if (phase_offset_ntf_mask & (1 << i)) | |
| 2684 | − dpll_pin_change_ntf(pins[i].pin); | |
| 2787 | + for (int i = 0; i < pin_num; i++) | |
| 2788 | + if (phase_offset_ntf_mask & BIT(i)) | |
| 2789 | + ice_dpll_pin_ntf(dplls, pins[i].pin); | |
| 2685 | 2790 | } |
| 2686 | 2791 | |
| 2687 | 2792 | /** |
| @@ -2857,7 +2962,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work) · 169 unmodified lines | ||
| 2857 | 2962 | ice_dpll_notify_changes(de); |
| 2858 | 2963 | ice_dpll_notify_changes(dp); |
| 2859 | 2964 | if (phase_offset_ntf) |
| 2860 | − ice_dpll_pins_notify_mask(d->inputs, d->num_inputs, | |
| 2965 | + ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, | |
| 2861 | 2966 | phase_offset_ntf); |
| 2862 | 2967 | |
| 2863 | 2968 | resched: |
| @@ -4014,6 +4119,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) · 1150 unmodified lines | ||
| 4014 | 4119 | struct ice_dpll_pin *pin; |
| 4015 | 4120 | u32 phase_adj_max, caps; |
| 4016 | 4121 | int i, ret; |
| 4122 | + u8 data; | |
| 4017 | 4123 | |
| 4018 | 4124 | if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) |
| 4019 | 4125 | input_idx_offset = ICE_E810_RCLK_PINS_NUM; |
| @@ -4073,6 +4179,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) · 53 unmodified lines | ||
| 4073 | 4179 | } |
| 4074 | 4180 | ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); |
| 4075 | 4181 | } |
| 4182 | + | |
| 4183 | + /* Initialize the SMA control register to a known-good default state. | |
| 4184 | + * Without this write the PCA9575 GPIO expander retains its power-on | |
| 4185 | + * default (all outputs high) which makes all SW pins appear inactive. | |
| 4186 | + * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and | |
| 4187 | + * U.FL2 input. | |
| 4188 | + */ | |
| 4189 | + ret = ice_read_sma_ctrl(&pf->hw, &data); | |
| 4190 | + if (ret) | |
| 4191 | + return ret; | |
| 4192 | + data &= ~ICE_ALL_SMA_MASK; | |
| 4193 | + data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; | |
| 4194 | + ret = ice_write_sma_ctrl(&pf->hw, data); | |
| 4195 | + if (ret) | |
| 4196 | + return ret; | |
| 4197 | + | |
| 4076 | 4198 | ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, |
| 4077 | 4199 | NULL); |
| 4078 | 4200 | if (ret) |
| @@ -5245,6 +5245,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) · 5244 unmodified lines | ||
| 5245 | 5245 | return err; |
| 5246 | 5246 | } |
| 5247 | 5247 | |
| 5248 | + ice_init_dev_hw(pf); | |
| 5249 | + | |
| 5248 | 5250 | adapter = ice_adapter_get(pdev); |
| 5249 | 5251 | if (IS_ERR(adapter)) { |
| 5250 | 5252 | err = PTR_ERR(adapter); |
| @@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) · 803 unmodified lines | ||
| 804 | 804 | ice_vf_ctrl_invalidate_vsi(vf); |
| 805 | 805 | |
| 806 | 806 | ice_vf_pre_vsi_rebuild(vf); |
| 807 | − ice_vf_rebuild_vsi(vf); | |
| 807 | + if (ice_vf_rebuild_vsi(vf)) { | |
| 808 | + dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", | |
| 809 | + vf->vf_id); | |
| 810 | + mutex_unlock(&vf->cfg_lock); | |
| 811 | + continue; | |
| 812 | + } | |
| 808 | 813 | ice_vf_post_vsi_rebuild(vf); |
| 809 | 814 | |
| 810 | 815 | ice_eswitch_attach_vf(pf, vf); |
| @@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx, · 530 unmodified lines | ||
| 531 | 531 | if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { |
| 532 | 532 | netif_err(efx, drv, efx->net_dev, |
| 533 | 533 | "mcdi MC_CMD_GET_VERSION failed\n"); |
| 534 | − return rc; | |
| 534 | + return rc ?: -EIO; | |
| 535 | 535 | } |
| 536 | 536 | |
| 537 | 537 | /* Handle previous output */ |
| @@ -5549,9 +5549,12 @@ read_again: · 5548 unmodified lines | ||
| 5549 | 5549 | break; |
| 5550 | 5550 | |
| 5551 | 5551 | /* Prefetch the next RX descriptor */ |
| 5552 | − rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, | |
| 5553 | − priv->dma_conf.dma_rx_size); | |
| 5554 | − next_entry = rx_q->cur_rx; | |
| 5552 | + next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, | |
| 5553 | + priv->dma_conf.dma_rx_size); | |
| 5554 | + if (unlikely(next_entry == rx_q->dirty_rx)) | |
| 5555 | + break; | |
| 5556 | + | |
| 5557 | + rx_q->cur_rx = next_entry; | |
| 5555 | 5558 | |
| 5556 | 5559 | np = stmmac_get_rx_desc(priv, rx_q, next_entry); |
| 5557 | 5560 | |
| @@ -5686,7 +5689,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) · 128 unmodified lines | ||
| 5686 | 5689 | |
| 5687 | 5690 | dma_dir = page_pool_get_dma_dir(rx_q->page_pool); |
| 5688 | 5691 | bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; |
| 5689 | − limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit); | |
| 5690 | 5692 | |
| 5691 | 5693 | if (netif_msg_rx_status(priv)) { |
| 5692 | 5694 | void *rx_head = stmmac_get_rx_desc(priv, rx_q, 0); |
| @@ -5733,9 +5735,12 @@ read_again: · 40 unmodified lines | ||
| 5733 | 5735 | if (unlikely(status & dma_own)) |
| 5734 | 5736 | break; |
| 5735 | 5737 | |
| 5736 | − rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, | |
| 5737 | − priv->dma_conf.dma_rx_size); | |
| 5738 | − next_entry = rx_q->cur_rx; | |
| 5738 | + next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, | |
| 5739 | + priv->dma_conf.dma_rx_size); | |
| 5740 | + if (unlikely(next_entry == rx_q->dirty_rx)) | |
| 5741 | + break; | |
| 5742 | + | |
| 5743 | + rx_q->cur_rx = next_entry; | |
| 5739 | 5744 | |
| 5740 | 5745 | np = stmmac_get_rx_desc(priv, rx_q, next_entry); |
| 5741 | 5746 | |
| @@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) · 495 unmodified lines | ||
| 496 | 496 | u8 *pecp; |
| 497 | 497 | int rc; |
| 498 | 498 | |
| 499 | − fs = mctp_i2c_get_tx_flow_state(midev, skb); | |
| 500 | − | |
| 501 | 499 | hdr = (void *)skb_mac_header(skb); |
| 502 | 500 | /* Sanity check that packet contents matches skb length, |
| 503 | 501 | * and can't exceed MCTP_I2C_BUFSZ |
| @@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) · 5 unmodified lines | ||
| 509 | 507 | return; |
| 510 | 508 | } |
| 511 | 509 | |
| 510 | + fs = mctp_i2c_get_tx_flow_state(midev, skb); | |
| 511 | + | |
| 512 | 512 | if (skb_tailroom(skb) >= 1) { |
| 513 | 513 | /* Linear case with space, we can just append the PEC */ |
| 514 | 514 | skb_put(skb, 1); |
| @@ -752,7 +752,7 @@ static ssize_t enabled_store(struct config_item *item, · 751 unmodified lines | ||
| 752 | 752 | unregister_netcons_consoles(); |
| 753 | 753 | } |
| 754 | 754 | |
| 755 | − ret = strnlen(buf, count); | |
| 755 | + ret = count; | |
| 756 | 756 | /* Deferred cleanup */ |
| 757 | 757 | netconsole_process_cleanups(); |
| 758 | 758 | out_unlock: |
| @@ -781,7 +781,7 @@ static ssize_t release_store(struct config_item *item, const char *buf, · 22 unmodified lines | ||
| 781 | 781 | |
| 782 | 782 | nt->release = release; |
| 783 | 783 | |
| 784 | − ret = strnlen(buf, count); | |
| 784 | + ret = count; | |
| 785 | 785 | out_unlock: |
| 786 | 786 | dynamic_netconsole_mutex_unlock(); |
| 787 | 787 | return ret; |
| @@ -807,7 +807,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf, · 19 unmodified lines | ||
| 807 | 807 | goto out_unlock; |
| 808 | 808 | |
| 809 | 809 | nt->extended = extended; |
| 810 | − ret = strnlen(buf, count); | |
| 810 | + ret = count; | |
| 811 | 811 | out_unlock: |
| 812 | 812 | dynamic_netconsole_mutex_unlock(); |
| 813 | 813 | return ret; |
| @@ -817,6 +817,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, · 3 unmodified lines | ||
| 817 | 817 | size_t count) |
| 818 | 818 | { |
| 819 | 819 | struct netconsole_target *nt = to_target(item); |
| 820 | + size_t len = count; | |
| 821 | + | |
| 822 | + /* Account for a trailing newline appended by tools like echo */ | |
| 823 | + if (len && buf[len - 1] == '\n') | |
| 824 | + len--; | |
| 825 | + if (len >= IFNAMSIZ) | |
| 826 | + return -ENAMETOOLONG; | |
| 820 | 827 | |
| 821 | 828 | dynamic_netconsole_mutex_lock(); |
| 822 | 829 | if (nt->state == STATE_ENABLED) { |
| @@ -830,7 +837,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, · 7 unmodified lines | ||
| 830 | 837 | trim_newline(nt->np.dev_name, IFNAMSIZ); |
| 831 | 838 | |
| 832 | 839 | dynamic_netconsole_mutex_unlock(); |
| 833 | − return strnlen(buf, count); | |
| 840 | + return count; | |
| 834 | 841 | } |
| 835 | 842 | |
| 836 | 843 | static ssize_t local_port_store(struct config_item *item, const char *buf, |
| @@ -849,7 +856,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf, · 12 unmodified lines | ||
| 849 | 856 | ret = kstrtou16(buf, 10, &nt->np.local_port); |
| 850 | 857 | if (ret < 0) |
| 851 | 858 | goto out_unlock; |
| 852 | − ret = strnlen(buf, count); | |
| 859 | + ret = count; | |
| 853 | 860 | out_unlock: |
| 854 | 861 | dynamic_netconsole_mutex_unlock(); |
| 855 | 862 | return ret; |
| @@ -871,7 +878,7 @@ static ssize_t remote_port_store(struct config_item *item, · 15 unmodified lines | ||
| 871 | 878 | ret = kstrtou16(buf, 10, &nt->np.remote_port); |
| 872 | 879 | if (ret < 0) |
| 873 | 880 | goto out_unlock; |
| 874 | − ret = strnlen(buf, count); | |
| 881 | + ret = count; | |
| 875 | 882 | out_unlock: |
| 876 | 883 | dynamic_netconsole_mutex_unlock(); |
| 877 | 884 | return ret; |
| @@ -896,7 +903,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, · 18 unmodified lines | ||
| 896 | 903 | goto out_unlock; |
| 897 | 904 | nt->np.ipv6 = !!ipv6; |
| 898 | 905 | |
| 899 | − ret = strnlen(buf, count); | |
| 906 | + ret = count; | |
| 900 | 907 | out_unlock: |
| 901 | 908 | dynamic_netconsole_mutex_unlock(); |
| 902 | 909 | return ret; |
| @@ -921,7 +928,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, · 18 unmodified lines | ||
| 921 | 928 | goto out_unlock; |
| 922 | 929 | nt->np.ipv6 = !!ipv6; |
| 923 | 930 | |
| 924 | − ret = strnlen(buf, count); | |
| 931 | + ret = count; | |
| 925 | 932 | out_unlock: |
| 926 | 933 | dynamic_netconsole_mutex_unlock(); |
| 927 | 934 | return ret; |
| @@ -957,7 +964,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf, · 29 unmodified lines | ||
| 957 | 964 | goto out_unlock; |
| 958 | 965 | memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); |
| 959 | 966 | |
| 960 | − ret = strnlen(buf, count); | |
| 967 | + ret = count; | |
| 961 | 968 | out_unlock: |
| 962 | 969 | dynamic_netconsole_mutex_unlock(); |
| 963 | 970 | return ret; |
| @@ -1072,26 +1079,30 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, · 108 unmodified lines | ||
| 1072 | 1079 | size_t count) |
| 1073 | 1080 | { |
| 1074 | 1081 | struct userdatum *udm = to_userdatum(item); |
| 1082 | + char old_value[MAX_EXTRADATA_VALUE_LEN]; | |
| 1075 | 1083 | struct netconsole_target *nt; |
| 1076 | 1084 | struct userdata *ud; |
| 1077 | 1085 | ssize_t ret; |
| 1078 | 1086 | |
| 1079 | − if (count > MAX_EXTRADATA_VALUE_LEN) | |
| 1087 | + if (count >= MAX_EXTRADATA_VALUE_LEN) | |
| 1080 | 1088 | return -EMSGSIZE; |
| 1081 | 1089 | |
| 1082 | 1090 | mutex_lock(&netconsole_subsys.su_mutex); |
| 1083 | 1091 | dynamic_netconsole_mutex_lock(); |
| 1084 | − | |
| 1085 | − ret = strscpy(udm->value, buf, sizeof(udm->value)); | |
| 1086 | − if (ret < 0) | |
| 1087 | − goto out_unlock; | |
| 1092 | + /* Snapshot for rollback if update_userdata() fails below */ | |
| 1093 | + strscpy(old_value, udm->value, sizeof(old_value)); | |
| 1094 | + /* count is bounded above, so strscpy() cannot truncate here */ | |
| 1095 | + strscpy(udm->value, buf, sizeof(udm->value)); | |
| 1088 | 1096 | trim_newline(udm->value, sizeof(udm->value)); |
| 1089 | 1097 | |
| 1090 | 1098 | ud = to_userdata(item->ci_parent); |
| 1091 | 1099 | nt = userdata_to_target(ud); |
| 1092 | 1100 | ret = update_userdata(nt); |
| 1093 | − if (ret < 0) | |
| 1101 | + if (ret < 0) { | |
| 1102 | + /* Restore the previous value so it matches the live payload */ | |
| 1103 | + strscpy(udm->value, old_value, sizeof(udm->value)); | |
| 1094 | 1104 | goto out_unlock; |
| 1105 | + } | |
| 1095 | 1106 | ret = count; |
| 1096 | 1107 | out_unlock: |
| 1097 | 1108 | dynamic_netconsole_mutex_unlock(); |
| @@ -1133,7 +1144,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item, · 35 unmodified lines | ||
| 1133 | 1144 | disable_sysdata_feature(nt, SYSDATA_MSGID); |
| 1134 | 1145 | |
| 1135 | 1146 | unlock_ok: |
| 1136 | − ret = strnlen(buf, count); | |
| 1147 | + ret = count; | |
| 1137 | 1148 | dynamic_netconsole_mutex_unlock(); |
| 1138 | 1149 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1139 | 1150 | return ret; |
| @@ -1162,7 +1173,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item, · 22 unmodified lines | ||
| 1162 | 1173 | disable_sysdata_feature(nt, SYSDATA_RELEASE); |
| 1163 | 1174 | |
| 1164 | 1175 | unlock_ok: |
| 1165 | − ret = strnlen(buf, count); | |
| 1176 | + ret = count; | |
| 1166 | 1177 | dynamic_netconsole_mutex_unlock(); |
| 1167 | 1178 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1168 | 1179 | return ret; |
| @@ -1191,7 +1202,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item, · 22 unmodified lines | ||
| 1191 | 1202 | disable_sysdata_feature(nt, SYSDATA_TASKNAME); |
| 1192 | 1203 | |
| 1193 | 1204 | unlock_ok: |
| 1194 | − ret = strnlen(buf, count); | |
| 1205 | + ret = count; | |
| 1195 | 1206 | dynamic_netconsole_mutex_unlock(); |
| 1196 | 1207 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1197 | 1208 | return ret; |
| @@ -1225,7 +1236,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item, · 27 unmodified lines | ||
| 1225 | 1236 | disable_sysdata_feature(nt, SYSDATA_CPU_NR); |
| 1226 | 1237 | |
| 1227 | 1238 | unlock_ok: |
| 1228 | − ret = strnlen(buf, count); | |
| 1239 | + ret = count; | |
| 1229 | 1240 | dynamic_netconsole_mutex_unlock(); |
| 1230 | 1241 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1231 | 1242 | return ret; |
| @@ -829,7 +829,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) · 828 unmodified lines | ||
| 829 | 829 | skb->protocol = htons(ETH_P_IP); |
| 830 | 830 | |
| 831 | 831 | skb_set_network_header(skb, skb->len); |
| 832 | − iph = skb_put(skb, sizeof(struct iphdr)); | |
| 832 | + iph = skb_put_zero(skb, sizeof(struct iphdr)); | |
| 833 | 833 | iph->protocol = IPPROTO_UDP; |
| 834 | 834 | iph->saddr = in_aton("192.0.2.1"); |
| 835 | 835 | iph->daddr = in_aton("198.51.100.1"); |
| @@ -31,6 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | #define DP83869_RGMIICTL 0x0032 |
| 32 | 32 | #define DP83869_STRAP_STS1 0x006e |
| 33 | 33 | #define DP83869_RGMIIDCTL 0x0086 |
| 34 | +#define DP83869_ANA_PLL_PROG_PI 0x00c6 | |
| 34 | 35 | #define DP83869_RXFCFG 0x0134 |
| 35 | 36 | #define DP83869_RXFPMD1 0x0136 |
| 36 | 37 | #define DP83869_RXFPMD2 0x0137 |
| @@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev) · 789 unmodified lines | ||
| 826 | 827 | dp83869_config_port_mirroring(phydev); |
| 827 | 828 | |
| 828 | 829 | /* Clock output selection if muxing property is set */ |
| 829 | − if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) | |
| 830 | + if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { | |
| 831 | + /* | |
| 832 | + * Table 7-121 in datasheet says we have to set register 0xc6 | |
| 833 | + * to value 0x10 before CLK_O_SEL can be modified. | |
| 834 | + */ | |
| 835 | + ret = phy_write_mmd(phydev, DP83869_DEVADDR, | |
| 836 | + DP83869_ANA_PLL_PROG_PI, 0x10); | |
| 837 | + if (ret) | |
| 838 | + return ret; | |
| 839 | + | |
| 830 | 840 | ret = phy_modify_mmd(phydev, |
| 831 | 841 | DP83869_DEVADDR, DP83869_IO_MUX_CFG, |
| 832 | 842 | DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, |
| 833 | 843 | dp83869->clk_output_sel << |
| 834 | 844 | DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); |
| 845 | + } | |
| 835 | 846 | |
| 836 | 847 | if (phy_interface_is_rgmii(phydev)) { |
| 837 | 848 | ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, |
| @@ -683,6 +683,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, · 682 unmodified lines | ||
| 683 | 683 | struct net_device *netdev) |
| 684 | 684 | { |
| 685 | 685 | rtl8150_t *dev = netdev_priv(netdev); |
| 686 | + unsigned int skb_len; | |
| 686 | 687 | int count, res; |
| 687 | 688 | |
| 688 | 689 | /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ |
| @@ -694,6 +695,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, · 5 unmodified lines | ||
| 694 | 695 | return NETDEV_TX_OK; |
| 695 | 696 | } |
| 696 | 697 | |
| 698 | + skb_len = skb->len; | |
| 699 | + | |
| 697 | 700 | netif_stop_queue(netdev); |
| 698 | 701 | dev->tx_skb = skb; |
| 699 | 702 | usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), |
| @@ -707,9 +710,16 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, · 7 unmodified lines | ||
| 707 | 710 | netdev->stats.tx_errors++; |
| 708 | 711 | netif_start_queue(netdev); |
| 709 | 712 | } |
| 713 | + /* | |
| 714 | + * The URB was not submitted, so write_bulk_callback() will | |
| 715 | + * never run to free dev->tx_skb. Drop the skb here and | |
| 716 | + * clear tx_skb to avoid leaving a stale pointer. | |
| 717 | + */ | |
| 718 | + dev->tx_skb = NULL; | |
| 719 | + dev_kfree_skb_any(skb); | |
| 710 | 720 | } else { |
| 711 | 721 | netdev->stats.tx_packets++; |
| 712 | − netdev->stats.tx_bytes += skb->len; | |
| 722 | + netdev->stats.tx_bytes += skb_len; | |
| 713 | 723 | netif_trans_update(netdev); |
| 714 | 724 | } |
| 715 | 725 | |
| @@ -1034,6 +1034,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, · 1033 unmodified lines | ||
| 1034 | 1034 | |
| 1035 | 1035 | err: |
| 1036 | 1036 | port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; |
| 1037 | + synchronize_net(); | |
| 1037 | 1038 | return ret; |
| 1038 | 1039 | } |
| 1039 | 1040 | |
| @@ -1053,10 +1054,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, · 13 unmodified lines | ||
| 1053 | 1054 | } |
| 1054 | 1055 | |
| 1055 | 1056 | /* inverse of do_vrf_add_slave */ |
| 1056 | −static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) | |
| 1057 | +static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, | |
| 1058 | + bool needs_sync) | |
| 1057 | 1059 | { |
| 1058 | 1060 | netdev_upper_dev_unlink(port_dev, dev); |
| 1059 | 1061 | port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; |
| 1062 | + /* Make sure that concurrent RCU readers that identified the device | |
| 1063 | + * as a VRF port see a VRF master or no master at all. | |
| 1064 | + */ | |
| 1065 | + if (needs_sync) | |
| 1066 | + synchronize_net(); | |
| 1060 | 1067 | |
| 1061 | 1068 | cycle_netdev(port_dev, NULL); |
| 1062 | 1069 | |
| @@ -1065,7 +1072,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) · 2 unmodified lines | ||
| 1065 | 1072 | |
| 1066 | 1073 | static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) |
| 1067 | 1074 | { |
| 1068 | − return do_vrf_del_slave(dev, port_dev); | |
| 1075 | + return do_vrf_del_slave(dev, port_dev, true); | |
| 1069 | 1076 | } |
| 1070 | 1077 | |
| 1071 | 1078 | static void vrf_dev_uninit(struct net_device *dev) |
| @@ -1619,7 +1626,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) · 547 unmodified lines | ||
| 1619 | 1626 | struct list_head *iter; |
| 1620 | 1627 | |
| 1621 | 1628 | netdev_for_each_lower_dev(dev, port_dev, iter) |
| 1622 | − vrf_del_slave(dev, port_dev); | |
| 1629 | + do_vrf_del_slave(dev, port_dev, false); | |
| 1623 | 1630 | |
| 1624 | 1631 | vrf_map_unregister_dev(dev); |
| 1625 | 1632 | |
| @@ -1751,7 +1758,7 @@ static int vrf_device_event(struct notifier_block *unused, · 125 unmodified lines | ||
| 1751 | 1758 | goto out; |
| 1752 | 1759 | |
| 1753 | 1760 | vrf_dev = netdev_master_upper_dev_get(dev); |
| 1754 | − vrf_del_slave(vrf_dev, dev); | |
| 1761 | + do_vrf_del_slave(vrf_dev, dev, false); | |
| 1755 | 1762 | } |
| 1756 | 1763 | out: |
| 1757 | 1764 | return NOTIFY_DONE; |
| @@ -317,6 +317,7 @@ · 316 unmodified lines | ||
| 317 | 317 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) |
| 318 | 318 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) |
| 319 | 319 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) |
| 320 | +#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 | |
| 320 | 321 | |
| 321 | 322 | #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) |
| 322 | 323 | #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) |
| @@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) · 977 unmodified lines | ||
| 1300 | 1301 | if (ret) |
| 1301 | 1302 | return ret; |
| 1302 | 1303 | |
| 1303 | − if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) | |
| 1304 | + if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) | |
| 1304 | 1305 | *is_rf_field = true; |
| 1305 | 1306 | else |
| 1306 | 1307 | *is_rf_field = false; |
| @@ -351,18 +351,29 @@ struct nvme_dhchap_key *nvme_auth_transform_key( · 350 unmodified lines | ||
| 351 | 351 | } |
| 352 | 352 | EXPORT_SYMBOL_GPL(nvme_auth_transform_key); |
| 353 | 353 | |
| 354 | +/** | |
| 355 | + * nvme_auth_augmented_challenge() - Compute the augmented DH-HMAC-CHAP challenge | |
| 356 | + * @hmac_id: Hash algorithm identifier | |
| 357 | + * @skey: Session key | |
| 358 | + * @skey_len: Length of @skey | |
| 359 | + * @challenge: Challenge value | |
| 360 | + * @aug: Output buffer for the augmented challenge | |
| 361 | + * @hlen: Hash output length (length of @challenge and @aug) | |
| 362 | + * | |
| 363 | + * NVMe base specification 8.3.5.5.4: The augmented challenge is computed | |
| 364 | + * applying the HMAC function using the hash function H() selected by the | |
| 365 | + * HashID parameter ... with the hash of the ephemeral DH key ... as HMAC key | |
| 366 | + * to the challenge C (i.e., Ca = HMAC(H(g^xy mod p), C)). | |
| 367 | + * | |
| 368 | + * As the session key skey is already H(g^xy mod p) per section 8.3.5.5.9, use | |
| 369 | + * it directly as the HMAC key without additional hashing. | |
| 370 | + * | |
| 371 | + * Return: 0 on success, negative errno on failure. | |
| 372 | + */ | |
| 354 | 373 | int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len, |
| 355 | 374 | const u8 *challenge, u8 *aug, size_t hlen) |
| 356 | 375 | { |
| 357 | − u8 hashed_key[NVME_AUTH_MAX_DIGEST_SIZE]; | |
| 358 | − int ret; | |
| 359 | − | |
| 360 | − ret = nvme_auth_hash(hmac_id, skey, skey_len, hashed_key); | |
| 361 | − if (ret) | |
| 362 | − return ret; | |
| 363 | − ret = nvme_auth_hmac(hmac_id, hashed_key, hlen, challenge, hlen, aug); | |
| 364 | − memzero_explicit(hashed_key, sizeof(hashed_key)); | |
| 365 | − return ret; | |
| 376 | + return nvme_auth_hmac(hmac_id, skey, skey_len, challenge, hlen, aug); | |
| 366 | 377 | } |
| 367 | 378 | EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge); |
| 368 | 379 | |
| @@ -403,33 +414,76 @@ int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm, · 34 unmodified lines | ||
| 403 | 414 | } |
| 404 | 415 | EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey); |
| 405 | 416 | |
| 406 | −int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm, | |
| 407 | − const u8 *ctrl_key, size_t ctrl_key_len, | |
| 408 | − u8 *sess_key, size_t sess_key_len) | |
| 417 | +/** | |
| 418 | + * nvme_auth_gen_session_key() - Generate an ephemeral session key | |
| 419 | + * @dh_tfm: Diffie-Hellman transform with local private key already set | |
| 420 | + * @public_key: Peer's public key | |
| 421 | + * @public_key_len: Length of @public_key | |
| 422 | + * @sess_key: Output buffer for the session key | |
| 423 | + * @sess_key_len: Size of @sess_key buffer | |
| 424 | + * @hash_id: Hash algorithm identifier | |
| 425 | + * | |
| 426 | + * NVMe base specification 8.3.5.5.9: The session key Ks shall be computed from | |
| 427 | + * the ephemeral DH key (i.e., g^xy mod p) ... by applying the hash function | |
| 428 | + * H() selected by the HashID parameter ... (i.e., Ks = H(g^xy mod p)). | |
| 429 | + * | |
| 430 | + * Return: 0 on success, negative errno on failure. | |
| 431 | + */ | |
| 432 | +int nvme_auth_gen_session_key(struct crypto_kpp *dh_tfm, | |
| 433 | + const u8 *public_key, size_t public_key_len, | |
| 434 | + u8 *sess_key, size_t sess_key_len, u8 hash_id) | |
| 409 | 435 | { |
| 410 | 436 | struct kpp_request *req; |
| 411 | 437 | struct crypto_wait wait; |
| 412 | 438 | struct scatterlist src, dst; |
| 439 | + u8 *dh_secret; | |
| 440 | + size_t dh_secret_len, hash_len; | |
| 413 | 441 | int ret; |
| 414 | 442 | |
| 415 | − req = kpp_request_alloc(dh_tfm, GFP_KERNEL); | |
| 416 | − if (!req) | |
| 443 | + hash_len = nvme_auth_hmac_hash_len(hash_id); | |
| 444 | + if (!hash_len) { | |
| 445 | + pr_warn("%s: invalid hash algorithm %d\n", __func__, hash_id); | |
| 446 | + return -EINVAL; | |
| 447 | + } | |
| 448 | + | |
| 449 | + if (sess_key_len != hash_len) { | |
| 450 | + pr_warn("%s: sess_key buffer missized (%zu != %zu)\n", | |
| 451 | + __func__, sess_key_len, hash_len); | |
| 452 | + return -EINVAL; | |
| 453 | + } | |
| 454 | + | |
| 455 | + dh_secret_len = crypto_kpp_maxsize(dh_tfm); | |
| 456 | + dh_secret = kzalloc(dh_secret_len, GFP_KERNEL); | |
| 457 | + if (!dh_secret) | |
| 417 | 458 | return -ENOMEM; |
| 418 | 459 | |
| 460 | + req = kpp_request_alloc(dh_tfm, GFP_KERNEL); | |
| 461 | + if (!req) { | |
| 462 | + ret = -ENOMEM; | |
| 463 | + goto out_free_secret; | |
| 464 | + } | |
| 465 | + | |
| 419 | 466 | crypto_init_wait(&wait); |
| 420 | − sg_init_one(&src, ctrl_key, ctrl_key_len); | |
| 421 | − kpp_request_set_input(req, &src, ctrl_key_len); | |
| 422 | − sg_init_one(&dst, sess_key, sess_key_len); | |
| 423 | − kpp_request_set_output(req, &dst, sess_key_len); | |
| 467 | + sg_init_one(&src, public_key, public_key_len); | |
| 468 | + kpp_request_set_input(req, &src, public_key_len); | |
| 469 | + sg_init_one(&dst, dh_secret, dh_secret_len); | |
| 470 | + kpp_request_set_output(req, &dst, dh_secret_len); | |
| 424 | 471 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
| 425 | 472 | crypto_req_done, &wait); |
| 426 | 473 | |
| 427 | 474 | ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait); |
| 428 | − | |
| 429 | 475 | kpp_request_free(req); |
| 476 | + | |
| 477 | + if (ret) | |
| 478 | + goto out_free_secret; | |
| 479 | + | |
| 480 | + ret = nvme_auth_hash(hash_id, dh_secret, dh_secret_len, sess_key); | |
| 481 | + | |
| 482 | +out_free_secret: | |
| 483 | + kfree_sensitive(dh_secret); | |
| 430 | 484 | return ret; |
| 431 | 485 | } |
| 432 | −EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret); | |
| 486 | +EXPORT_SYMBOL_GPL(nvme_auth_gen_session_key); | |
| 433 | 487 | |
| 434 | 488 | int nvme_auth_parse_key(const char *secret, struct nvme_dhchap_key **ret_key) |
| 435 | 489 | { |
| @@ -1267,11 +1267,7 @@ static int apple_nvme_get_address(struct nvme_ctrl *ctrl, char *buf, int size) · 1266 unmodified lines | ||
| 1267 | 1267 | |
| 1268 | 1268 | static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl) |
| 1269 | 1269 | { |
| 1270 | − struct apple_nvme *anv = ctrl_to_apple_nvme(ctrl); | |
| 1271 | − | |
| 1272 | − if (anv->ctrl.admin_q) | |
| 1273 | − blk_put_queue(anv->ctrl.admin_q); | |
| 1274 | − put_device(anv->dev); | |
| 1270 | + put_device(ctrl->dev); | |
| 1275 | 1271 | } |
| 1276 | 1272 | |
| 1277 | 1273 | static const struct nvme_ctrl_ops nvme_ctrl_ops = { |
| @@ -535,11 +535,12 @@ static int nvme_auth_dhchap_setup_ctrl_response(struct nvme_ctrl *ctrl, · 534 unmodified lines | ||
| 535 | 535 | put_unaligned_le16(chap->transaction, buf); |
| 536 | 536 | nvme_auth_hmac_update(&hmac, buf, 2); |
| 537 | 537 | |
| 538 | − memset(buf, 0, 4); | |
| 538 | + *buf = chap->sc_c; | |
| 539 | 539 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 540 | 540 | nvme_auth_hmac_update(&hmac, "Controller", 10); |
| 541 | 541 | nvme_auth_hmac_update(&hmac, ctrl->opts->subsysnqn, |
| 542 | 542 | strlen(ctrl->opts->subsysnqn)); |
| 543 | + memset(buf, 0, 4); | |
| 543 | 544 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 544 | 545 | nvme_auth_hmac_update(&hmac, ctrl->opts->host->nqn, |
| 545 | 546 | strlen(ctrl->opts->host->nqn)); |
| @@ -587,7 +588,7 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl, · 41 unmodified lines | ||
| 587 | 588 | } |
| 588 | 589 | |
| 589 | 590 | gen_sesskey: |
| 590 | − chap->sess_key_len = chap->host_key_len; | |
| 591 | + chap->sess_key_len = chap->hash_len; | |
| 591 | 592 | chap->sess_key = kmalloc(chap->sess_key_len, GFP_KERNEL); |
| 592 | 593 | if (!chap->sess_key) { |
| 593 | 594 | chap->sess_key_len = 0; |
| @@ -595,16 +596,17 @@ gen_sesskey: · 1 unmodified line | ||
| 595 | 596 | return -ENOMEM; |
| 596 | 597 | } |
| 597 | 598 | |
| 598 | − ret = nvme_auth_gen_shared_secret(chap->dh_tfm, | |
| 599 | − chap->ctrl_key, chap->ctrl_key_len, | |
| 600 | − chap->sess_key, chap->sess_key_len); | |
| 599 | + ret = nvme_auth_gen_session_key(chap->dh_tfm, | |
| 600 | + chap->ctrl_key, chap->ctrl_key_len, | |
| 601 | + chap->sess_key, chap->sess_key_len, | |
| 602 | + chap->hash_id); | |
| 601 | 603 | if (ret) { |
| 602 | 604 | dev_dbg(ctrl->device, |
| 603 | − "failed to generate shared secret, error %d\n", ret); | |
| 605 | + "failed to generate session key, error %d\n", ret); | |
| 604 | 606 | chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; |
| 605 | 607 | return ret; |
| 606 | 608 | } |
| 607 | − dev_dbg(ctrl->device, "shared secret %*ph\n", | |
| 609 | + dev_dbg(ctrl->device, "session key %*ph\n", | |
| 608 | 610 | (int)chap->sess_key_len, chap->sess_key); |
| 609 | 611 | return 0; |
| 610 | 612 | } |
| @@ -454,11 +454,10 @@ void nvme_end_req(struct request *req) · 453 unmodified lines | ||
| 454 | 454 | blk_mq_end_request(req, status); |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | −void nvme_complete_rq(struct request *req) | |
| 457 | +static void __nvme_complete_rq(struct request *req) | |
| 458 | 458 | { |
| 459 | 459 | struct nvme_ctrl *ctrl = nvme_req(req)->ctrl; |
| 460 | 460 | |
| 461 | − trace_nvme_complete_rq(req); | |
| 462 | 461 | nvme_cleanup_cmd(req); |
| 463 | 462 | |
| 464 | 463 | /* |
| @@ -493,6 +492,12 @@ void nvme_complete_rq(struct request *req) · 28 unmodified lines | ||
| 493 | 492 | return; |
| 494 | 493 | } |
| 495 | 494 | } |
| 495 | + | |
| 496 | +void nvme_complete_rq(struct request *req) | |
| 497 | +{ | |
| 498 | + trace_nvme_complete_rq(req); | |
| 499 | + __nvme_complete_rq(req); | |
| 500 | +} | |
| 496 | 501 | EXPORT_SYMBOL_GPL(nvme_complete_rq); |
| 497 | 502 | |
| 498 | 503 | void nvme_complete_batch_req(struct request *req) |
| @@ -513,7 +518,7 @@ blk_status_t nvme_host_path_error(struct request *req) · 14 unmodified lines | ||
| 513 | 518 | { |
| 514 | 519 | nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR; |
| 515 | 520 | blk_mq_set_request_complete(req); |
| 516 | − nvme_complete_rq(req); | |
| 521 | + __nvme_complete_rq(req); | |
| 517 | 522 | return BLK_STS_OK; |
| 518 | 523 | } |
| 519 | 524 | EXPORT_SYMBOL_GPL(nvme_host_path_error); |
| @@ -3044,7 +3049,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = { · 2524 unmodified lines | ||
| 3044 | 3049 | * |
| 3045 | 3050 | * The device is left in a state where it is also not possible |
| 3046 | 3051 | * to use "nvme set-feature" to disable APST, but booting with |
| 3047 | − * nvme_core.default_ps_max_latency=0 works. | |
| 3052 | + * nvme_core.default_ps_max_latency_us=0 works. | |
| 3048 | 3053 | */ |
| 3049 | 3054 | .vid = 0x1e0f, |
| 3050 | 3055 | .mn = "KCD6XVUL6T40", |
| @@ -4083,7 +4088,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info) · 1032 unmodified lines | ||
| 4083 | 4088 | mutex_unlock(&ctrl->subsys->lock); |
| 4084 | 4089 | |
| 4085 | 4090 | #ifdef CONFIG_NVME_MULTIPATH |
| 4086 | − cancel_delayed_work(&head->remove_work); | |
| 4091 | + if (cancel_delayed_work(&head->remove_work)) | |
| 4092 | + module_put(THIS_MODULE); | |
| 4087 | 4093 | #endif |
| 4088 | 4094 | return 0; |
| 4089 | 4095 | |
| @@ -3968,3 +3968,4 @@ module_exit(nvme_fc_exit_module); · 3967 unmodified lines | ||
| 3968 | 3968 | |
| 3969 | 3969 | MODULE_DESCRIPTION("NVMe host FC transport driver"); |
| 3970 | 3970 | MODULE_LICENSE("GPL v2"); |
| 3971 | +MODULE_ALIAS("nvme-fc"); | |
| @@ -231,16 +231,12 @@ bool nvme_mpath_clear_current_path(struct nvme_ns *ns) · 230 unmodified lines | ||
| 231 | 231 | bool changed = false; |
| 232 | 232 | int node; |
| 233 | 233 | |
| 234 | − if (!head) | |
| 235 | − goto out; | |
| 236 | − | |
| 237 | 234 | for_each_node(node) { |
| 238 | 235 | if (ns == rcu_access_pointer(head->current_path[node])) { |
| 239 | 236 | rcu_assign_pointer(head->current_path[node], NULL); |
| 240 | 237 | changed = true; |
| 241 | 238 | } |
| 242 | 239 | } |
| 243 | −out: | |
| 244 | 240 | return changed; |
| 245 | 241 | } |
| 246 | 242 | |
| @@ -2241,6 +2241,7 @@ release_cq: · 2240 unmodified lines | ||
| 2241 | 2241 | static const struct blk_mq_ops nvme_mq_admin_ops = { |
| 2242 | 2242 | .queue_rq = nvme_queue_rq, |
| 2243 | 2243 | .complete = nvme_pci_complete_rq, |
| 2244 | + .commit_rqs = nvme_commit_rqs, | |
| 2244 | 2245 | .init_hctx = nvme_admin_init_hctx, |
| 2245 | 2246 | .init_request = nvme_pci_init_request, |
| 2246 | 2247 | .timeout = nvme_timeout, |
| @@ -4104,6 +4105,10 @@ static const struct pci_device_id nvme_id_table[] = { · 1857 unmodified lines | ||
| 4104 | 4105 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, |
| 4105 | 4106 | { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ |
| 4106 | 4107 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, |
| 4108 | + { PCI_DEVICE(0x1c5f, 0x0555), /* Memblaze Pblaze5 adapter */ | |
| 4109 | + .driver_data = NVME_QUIRK_NO_NS_DESC_LIST, }, | |
| 4110 | + { PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */ | |
| 4111 | + .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, | |
| 4107 | 4112 | { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ |
| 4108 | 4113 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, |
| 4109 | 4114 | { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ |
| @@ -2189,6 +2189,13 @@ out_fail: · 2188 unmodified lines | ||
| 2189 | 2189 | nvme_rdma_reconnect_or_remove(ctrl, ret); |
| 2190 | 2190 | } |
| 2191 | 2191 | |
| 2192 | +static bool nvme_rdma_supports_pci_p2pdma(struct nvme_ctrl *ctrl) | |
| 2193 | +{ | |
| 2194 | + struct nvme_rdma_ctrl *r_ctrl = to_rdma_ctrl(ctrl); | |
| 2195 | + | |
| 2196 | + return ib_dma_pci_p2p_dma_supported(r_ctrl->device->dev); | |
| 2197 | +} | |
| 2198 | + | |
| 2192 | 2199 | static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { |
| 2193 | 2200 | .name = "rdma", |
| 2194 | 2201 | .module = THIS_MODULE, |
| @@ -2203,6 +2210,7 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { · 8 unmodified lines | ||
| 2203 | 2210 | .get_address = nvmf_get_address, |
| 2204 | 2211 | .stop_ctrl = nvme_rdma_stop_ctrl, |
| 2205 | 2212 | .get_virt_boundary = nvme_get_virt_boundary, |
| 2213 | + .supports_pci_p2pdma = nvme_rdma_supports_pci_p2pdma, | |
| 2206 | 2214 | }; |
| 2207 | 2215 | |
| 2208 | 2216 | /* |
| @@ -2432,3 +2440,4 @@ module_exit(nvme_rdma_cleanup_module); · 223 unmodified lines | ||
| 2432 | 2440 | |
| 2433 | 2441 | MODULE_DESCRIPTION("NVMe host RDMA transport driver"); |
| 2434 | 2442 | MODULE_LICENSE("GPL v2"); |
| 2443 | +MODULE_ALIAS("nvme-rdma"); | |
| @@ -883,10 +883,26 @@ static ssize_t tls_keyring_show(struct device *dev, · 882 unmodified lines | ||
| 883 | 883 | } |
| 884 | 884 | static DEVICE_ATTR_RO(tls_keyring); |
| 885 | 885 | |
| 886 | +static ssize_t tls_mode_show(struct device *dev, | |
| 887 | + struct device_attribute *attr, char *buf) | |
| 888 | +{ | |
| 889 | + struct nvme_ctrl *ctrl = dev_get_drvdata(dev); | |
| 890 | + const char *mode; | |
| 891 | + | |
| 892 | + if (ctrl->opts->tls) | |
| 893 | + mode = "tls"; | |
| 894 | + else | |
| 895 | + mode = "concat"; | |
| 896 | + | |
| 897 | + return sysfs_emit(buf, "%s\n", mode); | |
| 898 | +} | |
| 899 | +static DEVICE_ATTR_RO(tls_mode); | |
| 900 | + | |
| 886 | 901 | static struct attribute *nvme_tls_attrs[] = { |
| 887 | 902 | &dev_attr_tls_key.attr, |
| 888 | 903 | &dev_attr_tls_configured_key.attr, |
| 889 | 904 | &dev_attr_tls_keyring.attr, |
| 905 | + &dev_attr_tls_mode.attr, | |
| 890 | 906 | NULL, |
| 891 | 907 | }; |
| 892 | 908 | |
| @@ -908,6 +924,9 @@ static umode_t nvme_tls_attrs_are_visible(struct kobject *kobj, · 15 unmodified lines | ||
| 908 | 924 | if (a == &dev_attr_tls_keyring.attr && |
| 909 | 925 | !ctrl->opts->keyring) |
| 910 | 926 | return 0; |
| 927 | + if (a == &dev_attr_tls_mode.attr && | |
| 928 | + !ctrl->opts->tls && !ctrl->opts->concat) | |
| 929 | + return 0; | |
| 911 | 930 | |
| 912 | 931 | return a->mode; |
| 913 | 932 | } |
| @@ -1438,18 +1438,32 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) · 1437 unmodified lines | ||
| 1438 | 1438 | { |
| 1439 | 1439 | struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); |
| 1440 | 1440 | struct nvme_tcp_queue *queue = &ctrl->queues[qid]; |
| 1441 | − unsigned int noreclaim_flag; | |
| 1441 | + unsigned int noio_flag; | |
| 1442 | 1442 | |
| 1443 | 1443 | if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) |
| 1444 | 1444 | return; |
| 1445 | 1445 | |
| 1446 | 1446 | page_frag_cache_drain(&queue->pf_cache); |
| 1447 | 1447 | |
| 1448 | − noreclaim_flag = memalloc_noreclaim_save(); | |
| 1449 | − /* ->sock will be released by fput() */ | |
| 1450 | − fput(queue->sock->file); | |
| 1448 | + /** | |
| 1449 | + * Prevent memory reclaim from triggering block I/O during socket | |
| 1450 | + * teardown. The socket release path fput -> tcp_close -> | |
| 1451 | + * tcp_disconnect -> tcp_send_active_reset may allocate memory, and | |
| 1452 | + * allowing reclaim to issue I/O could deadlock if we're being called | |
| 1453 | + * from block device teardown (e.g., del_gendisk -> elevator cleanup) | |
| 1454 | + * which holds locks that the I/O completion path needs. | |
| 1455 | + */ | |
| 1456 | + noio_flag = memalloc_noio_save(); | |
| 1457 | + | |
| 1458 | + /** | |
| 1459 | + * Release the socket synchronously. During reset in | |
| 1460 | + * nvme_reset_ctrl_work(), queue teardown is immediately followed by | |
| 1461 | + * re-allocation. fput() defers socket cleanup to delayed_fput_work | |
| 1462 | + * in workqueue context, which can race with new queue setup. | |
| 1463 | + */ | |
| 1464 | + __fput_sync(queue->sock->file); | |
| 1451 | 1465 | queue->sock = NULL; |
| 1452 | − memalloc_noreclaim_restore(noreclaim_flag); | |
| 1466 | + memalloc_noio_restore(noio_flag); | |
| 1453 | 1467 | |
| 1454 | 1468 | kfree(queue->pdu); |
| 1455 | 1469 | mutex_destroy(&queue->send_mutex); |
| @@ -1901,8 +1915,8 @@ err_init_connect: · 445 unmodified lines | ||
| 1901 | 1915 | err_rcv_pdu: |
| 1902 | 1916 | kfree(queue->pdu); |
| 1903 | 1917 | err_sock: |
| 1904 | − /* ->sock will be released by fput() */ | |
| 1905 | − fput(queue->sock->file); | |
| 1918 | + /* Use sync variant - see nvme_tcp_free_queue() for explanation */ | |
| 1919 | + __fput_sync(queue->sock->file); | |
| 1906 | 1920 | queue->sock = NULL; |
| 1907 | 1921 | err_destroy_mutex: |
| 1908 | 1922 | mutex_destroy(&queue->send_mutex); |
| @@ -3071,3 +3085,4 @@ module_exit(nvme_tcp_cleanup_module); · 1162 unmodified lines | ||
| 3071 | 3085 | |
| 3072 | 3086 | MODULE_DESCRIPTION("NVMe host TCP transport driver"); |
| 3073 | 3087 | MODULE_LICENSE("GPL v2"); |
| 3088 | +MODULE_ALIAS("nvme-tcp"); | |
| @@ -687,12 +687,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) · 686 unmodified lines | ||
| 687 | 687 | id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL | |
| 688 | 688 | NVME_CTRL_CMIC_ANA; |
| 689 | 689 | |
| 690 | − /* Limit MDTS according to transport capability */ | |
| 691 | − if (ctrl->ops->get_mdts) | |
| 692 | − id->mdts = ctrl->ops->get_mdts(ctrl); | |
| 693 | − else | |
| 694 | − id->mdts = 0; | |
| 695 | − | |
| 690 | + /* Limit MDTS according to port config or transport capability */ | |
| 691 | + id->mdts = nvmet_ctrl_mdts(req); | |
| 696 | 692 | id->cntlid = cpu_to_le16(ctrl->cntlid); |
| 697 | 693 | id->ver = cpu_to_le32(ctrl->subsys->ver); |
| 698 | 694 | |
| @@ -229,9 +229,6 @@ out_unlock: · 228 unmodified lines | ||
| 229 | 229 | void nvmet_auth_sq_free(struct nvmet_sq *sq) |
| 230 | 230 | { |
| 231 | 231 | cancel_delayed_work(&sq->auth_expired_work); |
| 232 | −#ifdef CONFIG_NVME_TARGET_TCP_TLS | |
| 233 | − sq->tls_key = NULL; | |
| 234 | −#endif | |
| 235 | 232 | kfree(sq->dhchap_c1); |
| 236 | 233 | sq->dhchap_c1 = NULL; |
| 237 | 234 | kfree(sq->dhchap_c2); |
| @@ -402,11 +399,12 @@ int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, · 164 unmodified lines | ||
| 402 | 399 | put_unaligned_le16(req->sq->dhchap_tid, buf); |
| 403 | 400 | nvme_auth_hmac_update(&hmac, buf, 2); |
| 404 | 401 | |
| 405 | − memset(buf, 0, 4); | |
| 402 | + *buf = req->sq->sc_c; | |
| 406 | 403 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 407 | 404 | nvme_auth_hmac_update(&hmac, "Controller", 10); |
| 408 | 405 | nvme_auth_hmac_update(&hmac, ctrl->subsys->subsysnqn, |
| 409 | 406 | strlen(ctrl->subsys->subsysnqn)); |
| 407 | + memset(buf, 0, 4); | |
| 410 | 408 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 411 | 409 | nvme_auth_hmac_update(&hmac, ctrl->hostnqn, strlen(ctrl->hostnqn)); |
| 412 | 410 | nvme_auth_hmac_final(&hmac, response); |
| @@ -449,18 +447,19 @@ int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, · 36 unmodified lines | ||
| 449 | 447 | struct nvmet_ctrl *ctrl = req->sq->ctrl; |
| 450 | 448 | int ret; |
| 451 | 449 | |
| 452 | − req->sq->dhchap_skey_len = ctrl->dh_keysize; | |
| 450 | + req->sq->dhchap_skey_len = nvme_auth_hmac_hash_len(ctrl->shash_id); | |
| 453 | 451 | req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL); |
| 454 | 452 | if (!req->sq->dhchap_skey) |
| 455 | 453 | return -ENOMEM; |
| 456 | − ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm, | |
| 457 | − pkey, pkey_size, | |
| 458 | − req->sq->dhchap_skey, | |
| 459 | − req->sq->dhchap_skey_len); | |
| 454 | + ret = nvme_auth_gen_session_key(ctrl->dh_tfm, | |
| 455 | + pkey, pkey_size, | |
| 456 | + req->sq->dhchap_skey, | |
| 457 | + req->sq->dhchap_skey_len, | |
| 458 | + ctrl->shash_id); | |
| 460 | 459 | if (ret) |
| 461 | − pr_debug("failed to compute shared secret, err %d\n", ret); | |
| 460 | + pr_debug("failed to compute session key, err %d\n", ret); | |
| 462 | 461 | else |
| 463 | − pr_debug("%s: shared secret %*ph\n", __func__, | |
| 462 | + pr_debug("%s: session key %*ph\n", __func__, | |
| 464 | 463 | (int)req->sq->dhchap_skey_len, |
| 465 | 464 | req->sq->dhchap_skey); |
| 466 | 465 | |
| @@ -301,6 +301,31 @@ static ssize_t nvmet_param_max_queue_size_store(struct config_item *item, · 300 unmodified lines | ||
| 301 | 301 | |
| 302 | 302 | CONFIGFS_ATTR(nvmet_, param_max_queue_size); |
| 303 | 303 | |
| 304 | +static ssize_t nvmet_param_mdts_show(struct config_item *item, char *page) | |
| 305 | +{ | |
| 306 | + struct nvmet_port *port = to_nvmet_port(item); | |
| 307 | + | |
| 308 | + return snprintf(page, PAGE_SIZE, "%d\n", port->mdts); | |
| 309 | +} | |
| 310 | + | |
| 311 | +static ssize_t nvmet_param_mdts_store(struct config_item *item, | |
| 312 | + const char *page, size_t count) | |
| 313 | +{ | |
| 314 | + struct nvmet_port *port = to_nvmet_port(item); | |
| 315 | + int ret; | |
| 316 | + | |
| 317 | + if (nvmet_is_port_enabled(port, __func__)) | |
| 318 | + return -EACCES; | |
| 319 | + ret = kstrtoint(page, 0, &port->mdts); | |
| 320 | + if (ret) { | |
| 321 | + pr_err("Invalid value '%s' for mdts\n", page); | |
| 322 | + return -EINVAL; | |
| 323 | + } | |
| 324 | + return count; | |
| 325 | +} | |
| 326 | + | |
| 327 | +CONFIGFS_ATTR(nvmet_, param_mdts); | |
| 328 | + | |
| 304 | 329 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
| 305 | 330 | static ssize_t nvmet_param_pi_enable_show(struct config_item *item, |
| 306 | 331 | char *page) |
| @@ -1995,6 +2020,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = { · 1688 unmodified lines | ||
| 1995 | 2020 | &nvmet_attr_addr_tsas, |
| 1996 | 2021 | &nvmet_attr_param_inline_data_size, |
| 1997 | 2022 | &nvmet_attr_param_max_queue_size, |
| 2023 | + &nvmet_attr_param_mdts, | |
| 1998 | 2024 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
| 1999 | 2025 | &nvmet_attr_param_pi_enable, |
| 2000 | 2026 | #endif |
| @@ -2053,6 +2079,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group, · 52 unmodified lines | ||
| 2053 | 2079 | INIT_LIST_HEAD(&port->referrals); |
| 2054 | 2080 | port->inline_data_size = -1; /* < 0 == let the transport choose */ |
| 2055 | 2081 | port->max_queue_size = -1; /* < 0 == let the transport choose */ |
| 2082 | + port->mdts = -1; /* < 0 == let the transport choose */ | |
| 2056 | 2083 | |
| 2057 | 2084 | port->disc_addr.trtype = NVMF_TRTYPE_MAX; |
| 2058 | 2085 | port->disc_addr.portid = cpu_to_le16(portid); |
| @@ -370,6 +370,14 @@ int nvmet_enable_port(struct nvmet_port *port) · 369 unmodified lines | ||
| 370 | 370 | NVMET_MIN_QUEUE_SIZE, |
| 371 | 371 | NVMET_MAX_QUEUE_SIZE); |
| 372 | 372 | |
| 373 | + /* | |
| 374 | + * If the transport didn't set the mdts properly, then clamp it to the | |
| 375 | + * target limits. Also set default values in case the transport didn't | |
| 376 | + * set it at all. | |
| 377 | + */ | |
| 378 | + if (port->mdts < 0 || port->mdts > NVMET_MAX_MDTS) | |
| 379 | + port->mdts = 0; | |
| 380 | + | |
| 373 | 381 | port->enabled = true; |
| 374 | 382 | port->tr_ops = ops; |
| 375 | 383 | return 0; |
| @@ -1743,7 +1751,7 @@ static void nvmet_ctrl_free(struct kref *ref) · 1367 unmodified lines | ||
| 1743 | 1751 | |
| 1744 | 1752 | nvmet_stop_keep_alive_timer(ctrl); |
| 1745 | 1753 | |
| 1746 | − flush_work(&ctrl->async_event_work); | |
| 1754 | + cancel_work_sync(&ctrl->async_event_work); | |
| 1747 | 1755 | cancel_work_sync(&ctrl->fatal_err_work); |
| 1748 | 1756 | |
| 1749 | 1757 | nvmet_destroy_auth(ctrl); |
| @@ -395,10 +395,9 @@ done: · 394 unmodified lines | ||
| 395 | 395 | goto complete; |
| 396 | 396 | } |
| 397 | 397 | /* Final states, clear up variables */ |
| 398 | − if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { | |
| 399 | − nvmet_auth_sq_free(req->sq); | |
| 398 | + nvmet_auth_sq_free(req->sq); | |
| 399 | + if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) | |
| 400 | 400 | nvmet_ctrl_fatal_error(ctrl); |
| 401 | − } | |
| 402 | 401 | |
| 403 | 402 | complete: |
| 404 | 403 | nvmet_req_complete(req, status); |
| @@ -574,7 +573,9 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) · 169 unmodified lines | ||
| 574 | 573 | status = nvmet_copy_to_sgl(req, 0, d, al); |
| 575 | 574 | kfree(d); |
| 576 | 575 | done: |
| 577 | − if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { | |
| 576 | + if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2) | |
| 577 | + nvmet_auth_sq_free(req->sq); | |
| 578 | + else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { | |
| 578 | 579 | nvmet_auth_sq_free(req->sq); |
| 579 | 580 | nvmet_ctrl_fatal_error(ctrl); |
| 580 | 581 | } |
| @@ -214,6 +214,7 @@ struct nvmet_port { · 213 unmodified lines | ||
| 214 | 214 | bool enabled; |
| 215 | 215 | int inline_data_size; |
| 216 | 216 | int max_queue_size; |
| 217 | + int mdts; | |
| 217 | 218 | const struct nvmet_fabrics_ops *tr_ops; |
| 218 | 219 | bool pi_enable; |
| 219 | 220 | }; |
| @@ -673,6 +674,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type, · 453 unmodified lines | ||
| 673 | 674 | #define NVMET_MAX_QUEUE_SIZE 1024 |
| 674 | 675 | #define NVMET_NR_QUEUES 128 |
| 675 | 676 | #define NVMET_MAX_CMD(ctrl) (NVME_CAP_MQES(ctrl->cap) + 1) |
| 677 | +#define NVMET_MAX_MDTS 255 | |
| 676 | 678 | |
| 677 | 679 | /* |
| 678 | 680 | * Nice round number that makes a list of nsids fit into a page. |
| @@ -761,6 +763,17 @@ static inline bool nvmet_is_pci_ctrl(struct nvmet_ctrl *ctrl) · 82 unmodified lines | ||
| 761 | 763 | return ctrl->port->disc_addr.trtype == NVMF_TRTYPE_PCI; |
| 762 | 764 | } |
| 763 | 765 | |
| 766 | +/* Limit MDTS according to port config or transport capability */ | |
| 767 | +static inline u8 nvmet_ctrl_mdts(struct nvmet_req *req) | |
| 768 | +{ | |
| 769 | + struct nvmet_ctrl *ctrl = req->sq->ctrl; | |
| 770 | + u8 mdts = req->port->mdts; | |
| 771 | + | |
| 772 | + if (!ctrl->ops->get_mdts) | |
| 773 | + return mdts; | |
| 774 | + return min_not_zero(ctrl->ops->get_mdts(ctrl), mdts); | |
| 775 | +} | |
| 776 | + | |
| 764 | 777 | #ifdef CONFIG_NVME_TARGET_PASSTHRU |
| 765 | 778 | void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys); |
| 766 | 779 | int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys); |
| @@ -349,9 +349,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) · 348 unmodified lines | ||
| 349 | 349 | cmd->req.sg = NULL; |
| 350 | 350 | } |
| 351 | 351 | |
| 352 | −static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); | |
| 353 | − | |
| 354 | −static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) | |
| 352 | +static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) | |
| 355 | 353 | { |
| 356 | 354 | struct bio_vec *iov = cmd->iov; |
| 357 | 355 | struct scatterlist *sg; |
| @@ -364,22 +362,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) · 6 unmodified lines | ||
| 364 | 362 | offset = cmd->rbytes_done; |
| 365 | 363 | cmd->sg_idx = offset / PAGE_SIZE; |
| 366 | 364 | sg_offset = offset % PAGE_SIZE; |
| 367 | − if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { | |
| 368 | − nvmet_tcp_fatal_error(cmd->queue); | |
| 369 | − return; | |
| 370 | − } | |
| 365 | + if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) | |
| 366 | + return -EPROTO; | |
| 367 | + | |
| 371 | 368 | sg = &cmd->req.sg[cmd->sg_idx]; |
| 372 | 369 | sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; |
| 373 | 370 | |
| 374 | 371 | while (length) { |
| 375 | − if (!sg_remaining) { | |
| 376 | − nvmet_tcp_fatal_error(cmd->queue); | |
| 377 | − return; | |
| 378 | − } | |
| 379 | − if (!sg->length || sg->length <= sg_offset) { | |
| 380 | − nvmet_tcp_fatal_error(cmd->queue); | |
| 381 | − return; | |
| 382 | − } | |
| 372 | + if (!sg_remaining) | |
| 373 | + return -EPROTO; | |
| 374 | + | |
| 375 | + if (!sg->length || sg->length <= sg_offset) | |
| 376 | + return -EPROTO; | |
| 377 | + | |
| 383 | 378 | u32 iov_len = min_t(u32, length, sg->length - sg_offset); |
| 384 | 379 | |
| 385 | 380 | bvec_set_page(iov, sg_page(sg), iov_len, |
| @@ -394,24 +389,29 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) · 8 unmodified lines | ||
| 394 | 389 | |
| 395 | 390 | iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, |
| 396 | 391 | nr_pages, cmd->pdu_len); |
| 397 | −} | |
| 398 | − | |
| 399 | −static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) | |
| 400 | −{ | |
| 401 | − queue->rcv_state = NVMET_TCP_RECV_ERR; | |
| 402 | − if (queue->nvme_sq.ctrl) | |
| 403 | − nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); | |
| 404 | − else | |
| 405 | − kernel_sock_shutdown(queue->sock, SHUT_RDWR); | |
| 392 | + return 0; | |
| 406 | 393 | } |
| 407 | 394 | |
| 408 | 395 | static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) |
| 409 | 396 | { |
| 397 | + /* | |
| 398 | + * Keep rcv_state at RECV_ERR even for the internal -ESHUTDOWN path. | |
| 399 | + * nvmet_tcp_handle_icreq() can return -ESHUTDOWN after the ICReq has | |
| 400 | + * already been consumed and queue teardown has started. | |
| 401 | + * | |
| 402 | + * If nvmet_tcp_data_ready() or nvmet_tcp_write_space() queues | |
| 403 | + * nvmet_tcp_io_work() again before nvmet_tcp_release_queue_work() | |
| 404 | + * cancels it, the queue must not keep that old receive state. | |
| 405 | + * Otherwise the next nvmet_tcp_io_work() run can reach | |
| 406 | + * nvmet_tcp_done_recv_pdu() and try to handle the same ICReq again. | |
| 407 | + * | |
| 408 | + * That is why queue->rcv_state needs to be updated before we return. | |
| 409 | + */ | |
| 410 | 410 | queue->rcv_state = NVMET_TCP_RECV_ERR; |
| 411 | − if (status == -EPIPE || status == -ECONNRESET) | |
| 411 | + if (status == -EPIPE || status == -ECONNRESET || !queue->nvme_sq.ctrl) | |
| 412 | 412 | kernel_sock_shutdown(queue->sock, SHUT_RDWR); |
| 413 | 413 | else |
| 414 | − nvmet_tcp_fatal_error(queue); | |
| 414 | + nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); | |
| 415 | 415 | } |
| 416 | 416 | |
| 417 | 417 | static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd) |
| @@ -887,7 +887,6 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) · 469 unmodified lines | ||
| 887 | 887 | if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) { |
| 888 | 888 | pr_err("bad nvme-tcp pdu length (%d)\n", |
| 889 | 889 | le32_to_cpu(icreq->hdr.plen)); |
| 890 | − nvmet_tcp_fatal_error(queue); | |
| 891 | 890 | return -EPROTO; |
| 892 | 891 | } |
| 893 | 892 | |
| @@ -922,16 +921,29 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) · 28 unmodified lines | ||
| 922 | 921 | iov.iov_len = sizeof(*icresp); |
| 923 | 922 | ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); |
| 924 | 923 | if (ret < 0) { |
| 924 | + spin_lock_bh(&queue->state_lock); | |
| 925 | + if (queue->state == NVMET_TCP_Q_DISCONNECTING) { | |
| 926 | + spin_unlock_bh(&queue->state_lock); | |
| 927 | + return -ESHUTDOWN; | |
| 928 | + } | |
| 925 | 929 | queue->state = NVMET_TCP_Q_FAILED; |
| 930 | + spin_unlock_bh(&queue->state_lock); | |
| 926 | 931 | return ret; /* queue removal will cleanup */ |
| 927 | 932 | } |
| 928 | 933 | |
| 934 | + spin_lock_bh(&queue->state_lock); | |
| 935 | + if (queue->state == NVMET_TCP_Q_DISCONNECTING) { | |
| 936 | + spin_unlock_bh(&queue->state_lock); | |
| 937 | + /* Tell nvmet_tcp_socket_error() teardown is in progress. */ | |
| 938 | + return -ESHUTDOWN; | |
| 939 | + } | |
| 929 | 940 | queue->state = NVMET_TCP_Q_LIVE; |
| 941 | + spin_unlock_bh(&queue->state_lock); | |
| 930 | 942 | nvmet_prepare_receive_pdu(queue); |
| 931 | 943 | return 0; |
| 932 | 944 | } |
| 933 | 945 | |
| 934 | −static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, | |
| 946 | +static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, | |
| 935 | 947 | struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) |
| 936 | 948 | { |
| 937 | 949 | size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); |
| @@ -947,19 +959,22 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, · 9 unmodified lines | ||
| 947 | 959 | if (!nvme_is_write(cmd->req.cmd) || !data_len || |
| 948 | 960 | data_len > cmd->req.port->inline_data_size) { |
| 949 | 961 | nvmet_prepare_receive_pdu(queue); |
| 950 | − return; | |
| 962 | + return 0; | |
| 951 | 963 | } |
| 952 | 964 | |
| 953 | 965 | ret = nvmet_tcp_map_data(cmd); |
| 954 | 966 | if (unlikely(ret)) { |
| 955 | 967 | pr_err("queue %d: failed to map data\n", queue->idx); |
| 956 | − nvmet_tcp_fatal_error(queue); | |
| 957 | − return; | |
| 968 | + return -EPROTO; | |
| 958 | 969 | } |
| 959 | 970 | |
| 960 | 971 | queue->rcv_state = NVMET_TCP_RECV_DATA; |
| 961 | − nvmet_tcp_build_pdu_iovec(cmd); | |
| 962 | 972 | cmd->flags |= NVMET_TCP_F_INIT_FAILED; |
| 973 | + ret = nvmet_tcp_build_pdu_iovec(cmd); | |
| 974 | + if (unlikely(ret)) | |
| 975 | + pr_err("queue %d: failed to build PDU iovec\n", queue->idx); | |
| 976 | + | |
| 977 | + return ret; | |
| 963 | 978 | } |
| 964 | 979 | |
| 965 | 980 | static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) |
| @@ -1011,7 +1026,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) · 45 unmodified lines | ||
| 1011 | 1026 | goto err_proto; |
| 1012 | 1027 | } |
| 1013 | 1028 | cmd->pdu_recv = 0; |
| 1014 | − nvmet_tcp_build_pdu_iovec(cmd); | |
| 1029 | + if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { | |
| 1030 | + pr_err("queue %d: failed to build PDU iovec\n", queue->idx); | |
| 1031 | + goto err_proto; | |
| 1032 | + } | |
| 1015 | 1033 | queue->cmd = cmd; |
| 1016 | 1034 | queue->rcv_state = NVMET_TCP_RECV_DATA; |
| 1017 | 1035 | |
| @@ -1019,7 +1037,6 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) · 1 unmodified line | ||
| 1019 | 1037 | |
| 1020 | 1038 | err_proto: |
| 1021 | 1039 | /* FIXME: use proper transport errors */ |
| 1022 | − nvmet_tcp_fatal_error(queue); | |
| 1023 | 1040 | return -EPROTO; |
| 1024 | 1041 | } |
| 1025 | 1042 | |
| @@ -1034,7 +1051,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) · 8 unmodified lines | ||
| 1034 | 1051 | if (hdr->type != nvme_tcp_icreq) { |
| 1035 | 1052 | pr_err("unexpected pdu type (%d) before icreq\n", |
| 1036 | 1053 | hdr->type); |
| 1037 | − nvmet_tcp_fatal_error(queue); | |
| 1038 | 1054 | return -EPROTO; |
| 1039 | 1055 | } |
| 1040 | 1056 | return nvmet_tcp_handle_icreq(queue); |
| @@ -1043,7 +1059,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) · 2 unmodified lines | ||
| 1043 | 1059 | if (unlikely(hdr->type == nvme_tcp_icreq)) { |
| 1044 | 1060 | pr_err("queue %d: received icreq pdu in state %d\n", |
| 1045 | 1061 | queue->idx, queue->state); |
| 1046 | − nvmet_tcp_fatal_error(queue); | |
| 1047 | 1062 | return -EPROTO; |
| 1048 | 1063 | } |
| 1049 | 1064 | |
| @@ -1060,7 +1075,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) · 10 unmodified lines | ||
| 1060 | 1075 | pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d", |
| 1061 | 1076 | queue->idx, queue->nr_cmds, queue->send_list_len, |
| 1062 | 1077 | nvme_cmd->common.opcode); |
| 1063 | − nvmet_tcp_fatal_error(queue); | |
| 1064 | 1078 | return -ENOMEM; |
| 1065 | 1079 | } |
| 1066 | 1080 | |
| @@ -1074,17 +1088,16 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) · 7 unmodified lines | ||
| 1074 | 1088 | le32_to_cpu(req->cmd->common.dptr.sgl.length), |
| 1075 | 1089 | le16_to_cpu(req->cqe->status)); |
| 1076 | 1090 | |
| 1077 | − nvmet_tcp_handle_req_failure(queue, queue->cmd, req); | |
| 1078 | − return 0; | |
| 1091 | + return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); | |
| 1079 | 1092 | } |
| 1080 | 1093 | |
| 1081 | 1094 | ret = nvmet_tcp_map_data(queue->cmd); |
| 1082 | 1095 | if (unlikely(ret)) { |
| 1083 | 1096 | pr_err("queue %d: failed to map data\n", queue->idx); |
| 1084 | 1097 | if (nvmet_tcp_has_inline_data(queue->cmd)) |
| 1085 | − nvmet_tcp_fatal_error(queue); | |
| 1086 | − else | |
| 1087 | − nvmet_req_complete(req, ret); | |
| 1098 | + return -EPROTO; | |
| 1099 | + | |
| 1100 | + nvmet_req_complete(req, ret); | |
| 1088 | 1101 | ret = -EAGAIN; |
| 1089 | 1102 | goto out; |
| 1090 | 1103 | } |
| @@ -1092,8 +1105,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) · 1 unmodified line | ||
| 1092 | 1105 | if (nvmet_tcp_need_data_in(queue->cmd)) { |
| 1093 | 1106 | if (nvmet_tcp_has_inline_data(queue->cmd)) { |
| 1094 | 1107 | queue->rcv_state = NVMET_TCP_RECV_DATA; |
| 1095 | − nvmet_tcp_build_pdu_iovec(queue->cmd); | |
| 1096 | − return 0; | |
| 1108 | + ret = nvmet_tcp_build_pdu_iovec(queue->cmd); | |
| 1109 | + if (unlikely(ret)) | |
| 1110 | + pr_err("queue %d: failed to build PDU iovec\n", | |
| 1111 | + queue->idx); | |
| 1112 | + return ret; | |
| 1097 | 1113 | } |
| 1098 | 1114 | /* send back R2T */ |
| 1099 | 1115 | nvmet_tcp_queue_response(&queue->cmd->req); |
| @@ -1204,7 +1220,6 @@ recv: · 104 unmodified lines | ||
| 1204 | 1220 | |
| 1205 | 1221 | if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) { |
| 1206 | 1222 | pr_err("unexpected pdu type %d\n", hdr->type); |
| 1207 | − nvmet_tcp_fatal_error(queue); | |
| 1208 | 1223 | return -EIO; |
| 1209 | 1224 | } |
| 1210 | 1225 | |
| @@ -1218,16 +1233,12 @@ recv: · 7 unmodified lines | ||
| 1218 | 1233 | } |
| 1219 | 1234 | |
| 1220 | 1235 | if (queue->hdr_digest && |
| 1221 | − nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) { | |
| 1222 | − nvmet_tcp_fatal_error(queue); /* fatal */ | |
| 1236 | + nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) | |
| 1223 | 1237 | return -EPROTO; |
| 1224 | − } | |
| 1225 | 1238 | |
| 1226 | 1239 | if (queue->data_digest && |
| 1227 | − nvmet_tcp_check_ddgst(queue, &queue->pdu)) { | |
| 1228 | − nvmet_tcp_fatal_error(queue); /* fatal */ | |
| 1240 | + nvmet_tcp_check_ddgst(queue, &queue->pdu)) | |
| 1229 | 1241 | return -EPROTO; |
| 1230 | − } | |
| 1231 | 1242 | |
| 1232 | 1243 | return nvmet_tcp_done_recv_pdu(queue); |
| 1233 | 1244 | } |
| @@ -1310,9 +1321,9 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) · 76 unmodified lines | ||
| 1310 | 1321 | queue->idx, cmd->req.cmd->common.command_id, |
| 1311 | 1322 | queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), |
| 1312 | 1323 | le32_to_cpu(cmd->exp_ddgst)); |
| 1313 | − nvmet_req_uninit(&cmd->req); | |
| 1324 | + if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED)) | |
| 1325 | + nvmet_req_uninit(&cmd->req); | |
| 1314 | 1326 | nvmet_tcp_free_cmd_buffers(cmd); |
| 1315 | − nvmet_tcp_fatal_error(queue); | |
| 1316 | 1327 | ret = -EPROTO; |
| 1317 | 1328 | goto out; |
| 1318 | 1329 | } |
| @@ -69,7 +69,6 @@ bool nvmet_bdev_zns_enable(struct nvmet_ns *ns) · 68 unmodified lines | ||
| 69 | 69 | void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) |
| 70 | 70 | { |
| 71 | 71 | u8 zasl = req->sq->ctrl->subsys->zasl; |
| 72 | − struct nvmet_ctrl *ctrl = req->sq->ctrl; | |
| 73 | 72 | struct nvme_id_ctrl_zns *id; |
| 74 | 73 | u16 status; |
| 75 | 74 | |
| @@ -79,10 +78,7 @@ void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) · 3 unmodified lines | ||
| 79 | 78 | goto out; |
| 80 | 79 | } |
| 81 | 80 | |
| 82 | − if (ctrl->ops->get_mdts) | |
| 83 | − id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl); | |
| 84 | − else | |
| 85 | − id->zasl = zasl; | |
| 81 | + id->zasl = min_not_zero(nvmet_ctrl_mdts(req), zasl); | |
| 86 | 82 | |
| 87 | 83 | status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id)); |
| 88 | 84 | |
| @@ -1231,6 +1231,7 @@ config REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY · 1230 unmodified lines | ||
| 1231 | 1231 | tristate "Raspberry Pi 7-inch touchscreen panel ATTINY regulator" |
| 1232 | 1232 | depends on ARM || ARM64 || COMPILE_TEST |
| 1233 | 1233 | depends on BACKLIGHT_CLASS_DEVICE |
| 1234 | + depends on GPIOLIB | |
| 1234 | 1235 | depends on I2C |
| 1235 | 1236 | select REGMAP_I2C |
| 1236 | 1237 | help |
| @@ -85,14 +85,6 @@ config HMC_DRV · 84 unmodified lines | ||
| 85 | 85 | transfer cache size from its default value 0.5MB to N bytes. If N |
| 86 | 86 | is zero, then no caching is performed. |
| 87 | 87 | |
| 88 | −config SCLP_OFB | |
| 89 | − def_bool n | |
| 90 | − prompt "Support for Open-for-Business SCLP Event" | |
| 91 | − depends on S390 | |
| 92 | − help | |
| 93 | − This option enables the Open-for-Business interface to the s390 | |
| 94 | − Service Element. | |
| 95 | − | |
| 96 | 88 | config S390_UV_UAPI |
| 97 | 89 | def_tristate m |
| 98 | 90 | prompt "Ultravisor userspace API" |
| @@ -80,14 +80,11 @@ static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) · 79 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | static struct sclp_register sclp_conf_register = |
| 82 | 82 | { |
| 83 | −#ifdef CONFIG_SCLP_OFB | |
| 84 | 83 | .send_mask = EVTYP_CONFMGMDATA_MASK, |
| 85 | −#endif | |
| 86 | 84 | .receive_mask = EVTYP_CONFMGMDATA_MASK, |
| 87 | 85 | .receiver_fn = sclp_conf_receiver_fn, |
| 88 | 86 | }; |
| 89 | 87 | |
| 90 | −#ifdef CONFIG_SCLP_OFB | |
| 91 | 88 | static int sclp_ofb_send_req(char *ev_data, size_t len) |
| 92 | 89 | { |
| 93 | 90 | static DEFINE_MUTEX(send_mutex); |
| @@ -143,11 +140,9 @@ static const struct bin_attribute ofb_bin_attr = { · 49 unmodified lines | ||
| 143 | 140 | }, |
| 144 | 141 | .write = sysfs_ofb_data_write, |
| 145 | 142 | }; |
| 146 | −#endif | |
| 147 | 143 | |
| 148 | 144 | static int __init sclp_ofb_setup(void) |
| 149 | 145 | { |
| 150 | −#ifdef CONFIG_SCLP_OFB | |
| 151 | 146 | struct kset *ofb_kset; |
| 152 | 147 | int rc; |
| 153 | 148 | |
| @@ -159,7 +154,6 @@ static int __init sclp_ofb_setup(void) · 5 unmodified lines | ||
| 159 | 154 | kset_unregister(ofb_kset); |
| 160 | 155 | return rc; |
| 161 | 156 | } |
| 162 | −#endif | |
| 163 | 157 | return 0; |
| 164 | 158 | } |
| 165 | 159 | |
| @@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) · 394 unmodified lines | ||
| 395 | 395 | |
| 396 | 396 | switch (req_op(rq)) { |
| 397 | 397 | case REQ_OP_WRITE: |
| 398 | − if (!cd->writeable) | |
| 398 | + if (get_disk_ro(cd->disk)) | |
| 399 | 399 | goto out; |
| 400 | 400 | SCpnt->cmnd[0] = WRITE_10; |
| 401 | 401 | cd->cdi.media_written = 1; |
| @@ -681,6 +681,7 @@ static int sr_probe(struct scsi_device *sdev) · 279 unmodified lines | ||
| 681 | 681 | error = -ENOMEM; |
| 682 | 682 | if (get_capabilities(cd)) |
| 683 | 683 | goto fail_minor; |
| 684 | + cdrom_probe_write_features(&cd->cdi); | |
| 684 | 685 | sr_vendor_init(cd); |
| 685 | 686 | |
| 686 | 687 | set_capacity(disk, cd->capacity); |
| @@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd) · 212 unmodified lines | ||
| 899 | 900 | /*else I don't think it can close its tray |
| 900 | 901 | cd->cdi.mask |= CDC_CLOSE_TRAY; */ |
| 901 | 902 | |
| 902 | − /* | |
| 903 | − * if DVD-RAM, MRW-W or CD-RW, we are randomly writable | |
| 904 | − */ | |
| 905 | − if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != | |
| 906 | − (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { | |
| 907 | − cd->writeable = 1; | |
| 908 | − } | |
| 909 | − | |
| 910 | 903 | kfree(buffer); |
| 911 | 904 | return 0; |
| 912 | 905 | } |
| @@ -35,7 +35,6 @@ typedef struct scsi_cd { · 34 unmodified lines | ||
| 35 | 35 | struct scsi_device *device; |
| 36 | 36 | unsigned int vendor; /* vendor code, see sr_vendor.c */ |
| 37 | 37 | unsigned long ms_offset; /* for reading multisession-CD's */ |
| 38 | − unsigned writeable : 1; | |
| 39 | 38 | unsigned use:1; /* is this device still supportable */ |
| 40 | 39 | unsigned xa_flag:1; /* CD has XA sectors ? */ |
| 41 | 40 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ |
| @@ -546,7 +546,7 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) · 545 unmodified lines | ||
| 546 | 546 | if (desc->info.length > SPI_NAND_CACHE_SIZE) |
| 547 | 547 | return -E2BIG; |
| 548 | 548 | |
| 549 | − if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl)) | |
| 549 | + if (!airoha_snand_supports_op(desc->mem, desc->info.op_tmpl)) | |
| 550 | 550 | return -EOPNOTSUPP; |
| 551 | 551 | |
| 552 | 552 | return 0; |
| @@ -572,7 +572,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, · 19 unmodified lines | ||
| 572 | 572 | * DUALIO and QUADIO opcodes are not supported by the spi controller, |
| 573 | 573 | * replace them with supported opcodes. |
| 574 | 574 | */ |
| 575 | − opcode = desc->info.op_tmpl.cmd.opcode; | |
| 575 | + opcode = desc->info.op_tmpl->cmd.opcode; | |
| 576 | 576 | switch (opcode) { |
| 577 | 577 | case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: |
| 578 | 578 | case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: |
| @@ -761,7 +761,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, · 182 unmodified lines | ||
| 761 | 761 | /* minimum oob size is 64 */ |
| 762 | 762 | bytes = round_up(offs + len, 64); |
| 763 | 763 | |
| 764 | − opcode = desc->info.op_tmpl.cmd.opcode; | |
| 764 | + opcode = desc->info.op_tmpl->cmd.opcode; | |
| 765 | 765 | switch (opcode) { |
| 766 | 766 | case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: |
| 767 | 767 | case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: |
| @@ -794,6 +794,7 @@ static int aml_spisg_probe(struct platform_device *pdev) · 793 unmodified lines | ||
| 794 | 794 | |
| 795 | 795 | dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX); |
| 796 | 796 | |
| 797 | + init_completion(&spisg->completion); | |
| 797 | 798 | ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg); |
| 798 | 799 | if (ret) { |
| 799 | 800 | dev_err(&pdev->dev, "irq request failed\n"); |
| @@ -806,8 +807,6 @@ static int aml_spisg_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 806 | 807 | goto out_clk; |
| 807 | 808 | } |
| 808 | 809 | |
| 809 | − init_completion(&spisg->completion); | |
| 810 | − | |
| 811 | 810 | pm_runtime_put(&spisg->pdev->dev); |
| 812 | 811 | |
| 813 | 812 | return 0; |
| @@ -697,7 +697,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) · 696 unmodified lines | ||
| 697 | 697 | { |
| 698 | 698 | struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 699 | 699 | struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)]; |
| 700 | − struct spi_mem_op *op = &desc->info.op_tmpl; | |
| 700 | + struct spi_mem_op *op = desc->info.op_tmpl; | |
| 701 | 701 | u32 ctl_val; |
| 702 | 702 | int ret = 0; |
| 703 | 703 | |
| @@ -769,7 +769,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, · 65 unmodified lines | ||
| 769 | 769 | if (chip->ahb_window_size < offset + len || chip->force_user_mode) { |
| 770 | 770 | int ret; |
| 771 | 771 | |
| 772 | − ret = aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf); | |
| 772 | + ret = aspeed_spi_read_user(chip, desc->info.op_tmpl, offset, len, buf); | |
| 773 | 773 | if (ret < 0) |
| 774 | 774 | return ret; |
| 775 | 775 | } else { |
| @@ -201,7 +201,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi) · 200 unmodified lines | ||
| 201 | 201 | * then spi control did't work thoroughly, add one byte delay |
| 202 | 202 | */ |
| 203 | 203 | if (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV) |
| 204 | − usleep_range(10, 10); | |
| 204 | + udelay(10); | |
| 205 | 205 | if (xspi->tx_buf) |
| 206 | 206 | ax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++); |
| 207 | 207 | else |
| @@ -1860,14 +1860,10 @@ static int cqspi_probe(struct platform_device *pdev) · 1859 unmodified lines | ||
| 1860 | 1860 | if (irq < 0) |
| 1861 | 1861 | return -ENXIO; |
| 1862 | 1862 | |
| 1863 | − ret = pm_runtime_set_active(dev); | |
| 1864 | − if (ret) | |
| 1865 | − return ret; | |
| 1866 | − | |
| 1867 | 1863 | ret = clk_bulk_prepare_enable(CLK_QSPI_NUM, cqspi->clks); |
| 1868 | 1864 | if (ret) { |
| 1869 | 1865 | dev_err(dev, "Cannot enable QSPI clocks.\n"); |
| 1870 | − goto disable_rpm; | |
| 1866 | + return ret; | |
| 1871 | 1867 | } |
| 1872 | 1868 | |
| 1873 | 1869 | /* Obtain QSPI reset control */ |
| @@ -1962,10 +1958,11 @@ static int cqspi_probe(struct platform_device *pdev) · 88 unmodified lines | ||
| 1962 | 1958 | cqspi->sclk = 0; |
| 1963 | 1959 | |
| 1964 | 1960 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { |
| 1965 | − pm_runtime_enable(dev); | |
| 1966 | 1961 | pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); |
| 1967 | 1962 | pm_runtime_use_autosuspend(dev); |
| 1968 | 1963 | pm_runtime_get_noresume(dev); |
| 1964 | + pm_runtime_set_active(dev); | |
| 1965 | + pm_runtime_enable(dev); | |
| 1969 | 1966 | } |
| 1970 | 1967 | |
| 1971 | 1968 | host->num_chipselect = cqspi->num_chipselect; |
| @@ -1977,7 +1974,7 @@ static int cqspi_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1977 | 1974 | ret = cqspi_request_mmap_dma(cqspi); |
| 1978 | 1975 | if (ret == -EPROBE_DEFER) { |
| 1979 | 1976 | dev_err_probe(&pdev->dev, ret, "Failed to request mmap DMA\n"); |
| 1980 | − goto disable_controller; | |
| 1977 | + goto disable_rpm; | |
| 1981 | 1978 | } |
| 1982 | 1979 | } |
| 1983 | 1980 | |
| @@ -1995,14 +1992,16 @@ static int cqspi_probe(struct platform_device *pdev) · 11 unmodified lines | ||
| 1995 | 1992 | release_dma_chan: |
| 1996 | 1993 | if (cqspi->rx_chan) |
| 1997 | 1994 | dma_release_channel(cqspi->rx_chan); |
| 1998 | −disable_controller: | |
| 1999 | − cqspi_controller_enable(cqspi, 0); | |
| 2000 | −disable_clks: | |
| 2001 | − if (pm_runtime_get_sync(&pdev->dev) >= 0) | |
| 2002 | − clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); | |
| 2003 | 1995 | disable_rpm: |
| 2004 | − if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) | |
| 1996 | + if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { | |
| 2005 | 1997 | pm_runtime_disable(dev); |
| 1998 | + pm_runtime_set_suspended(dev); | |
| 1999 | + pm_runtime_put_noidle(dev); | |
| 2000 | + pm_runtime_dont_use_autosuspend(dev); | |
| 2001 | + } | |
| 2002 | + cqspi_controller_enable(cqspi, 0); | |
| 2003 | +disable_clks: | |
| 2004 | + clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); | |
| 2006 | 2005 | |
| 2007 | 2006 | return ret; |
| 2008 | 2007 | } |
| @@ -2026,18 +2025,19 @@ static void cqspi_remove(struct platform_device *pdev) · 17 unmodified lines | ||
| 2026 | 2025 | if (cqspi->rx_chan) |
| 2027 | 2026 | dma_release_channel(cqspi->rx_chan); |
| 2028 | 2027 | |
| 2029 | − cqspi_controller_enable(cqspi, 0); | |
| 2030 | − | |
| 2031 | − | |
| 2032 | 2028 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) |
| 2033 | 2029 | ret = pm_runtime_get_sync(&pdev->dev); |
| 2034 | 2030 | |
| 2035 | − if (ret >= 0) | |
| 2031 | + if (ret >= 0) { | |
| 2032 | + cqspi_controller_enable(cqspi, 0); | |
| 2036 | 2033 | clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); |
| 2034 | + } | |
| 2037 | 2035 | |
| 2038 | 2036 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { |
| 2039 | − pm_runtime_put_sync(&pdev->dev); | |
| 2040 | 2037 | pm_runtime_disable(&pdev->dev); |
| 2038 | + pm_runtime_set_suspended(&pdev->dev); | |
| 2039 | + pm_runtime_put_noidle(&pdev->dev); | |
| 2040 | + pm_runtime_dont_use_autosuspend(&pdev->dev); | |
| 2041 | 2041 | } |
| 2042 | 2042 | } |
| 2043 | 2043 | |
| @@ -741,7 +741,6 @@ static int cdns_spi_probe(struct platform_device *pdev) · 740 unmodified lines | ||
| 741 | 741 | /* Set to default valid value */ |
| 742 | 742 | ctlr->max_speed_hz = xspi->clk_rate / 4; |
| 743 | 743 | xspi->speed_hz = ctlr->max_speed_hz; |
| 744 | − pm_runtime_put_autosuspend(&pdev->dev); | |
| 745 | 744 | } else { |
| 746 | 745 | ctlr->mode_bits |= SPI_NO_CS; |
| 747 | 746 | ctlr->target_abort = cdns_target_abort; |
| @@ -752,12 +751,17 @@ static int cdns_spi_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 752 | 751 | goto clk_dis_all; |
| 753 | 752 | } |
| 754 | 753 | |
| 754 | + if (!spi_controller_is_target(ctlr)) | |
| 755 | + pm_runtime_put_autosuspend(&pdev->dev); | |
| 756 | + | |
| 755 | 757 | return ret; |
| 756 | 758 | |
| 757 | 759 | clk_dis_all: |
| 758 | 760 | if (!spi_controller_is_target(ctlr)) { |
| 759 | 761 | pm_runtime_disable(&pdev->dev); |
| 760 | 762 | pm_runtime_set_suspended(&pdev->dev); |
| 763 | + pm_runtime_put_noidle(&pdev->dev); | |
| 764 | + pm_runtime_dont_use_autosuspend(&pdev->dev); | |
| 761 | 765 | } |
| 762 | 766 | remove_ctlr: |
| 763 | 767 | spi_controller_put(ctlr); |
| @@ -776,16 +780,23 @@ static void cdns_spi_remove(struct platform_device *pdev) · 12 unmodified lines | ||
| 776 | 780 | { |
| 777 | 781 | struct spi_controller *ctlr = platform_get_drvdata(pdev); |
| 778 | 782 | struct cdns_spi *xspi = spi_controller_get_devdata(ctlr); |
| 783 | + int ret = 0; | |
| 784 | + | |
| 785 | + if (!spi_controller_is_target(ctlr)) | |
| 786 | + ret = pm_runtime_get_sync(&pdev->dev); | |
| 779 | 787 | |
| 780 | 788 | spi_controller_get(ctlr); |
| 781 | 789 | |
| 782 | 790 | spi_unregister_controller(ctlr); |
| 783 | 791 | |
| 784 | − cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE); | |
| 792 | + if (ret >= 0) | |
| 793 | + cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE); | |
| 785 | 794 | |
| 786 | 795 | if (!spi_controller_is_target(ctlr)) { |
| 787 | 796 | pm_runtime_disable(&pdev->dev); |
| 788 | 797 | pm_runtime_set_suspended(&pdev->dev); |
| 798 | + pm_runtime_put_noidle(&pdev->dev); | |
| 799 | + pm_runtime_dont_use_autosuspend(&pdev->dev); | |
| 789 | 800 | } |
| 790 | 801 | |
| 791 | 802 | spi_controller_put(ctlr); |
| @@ -814,7 +814,7 @@ static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) · 813 unmodified lines | ||
| 814 | 814 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 815 | 815 | const struct intel_spi_mem_op *iop; |
| 816 | 816 | |
| 817 | − iop = intel_spi_match_mem_op(ispi, &desc->info.op_tmpl); | |
| 817 | + iop = intel_spi_match_mem_op(ispi, desc->info.op_tmpl); | |
| 818 | 818 | if (!iop) |
| 819 | 819 | return -EOPNOTSUPP; |
| 820 | 820 | |
| @@ -827,7 +827,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, · 6 unmodified lines | ||
| 827 | 827 | { |
| 828 | 828 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 829 | 829 | const struct intel_spi_mem_op *iop = desc->priv; |
| 830 | − struct spi_mem_op op = desc->info.op_tmpl; | |
| 830 | + struct spi_mem_op op = *desc->info.op_tmpl; | |
| 831 | 831 | int ret; |
| 832 | 832 | |
| 833 | 833 | /* Fill in the gaps */ |
| @@ -844,7 +844,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs · 10 unmodified lines | ||
| 844 | 844 | { |
| 845 | 845 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 846 | 846 | const struct intel_spi_mem_op *iop = desc->priv; |
| 847 | − struct spi_mem_op op = desc->info.op_tmpl; | |
| 847 | + struct spi_mem_op op = *desc->info.op_tmpl; | |
| 848 | 848 | int ret; |
| 849 | 849 | |
| 850 | 850 | op.addr.val = offs; |
| @@ -647,7 +647,7 @@ EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration); · 646 unmodified lines | ||
| 647 | 647 | static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, |
| 648 | 648 | u64 offs, size_t len, void *buf) |
| 649 | 649 | { |
| 650 | − struct spi_mem_op op = desc->info.op_tmpl; | |
| 650 | + struct spi_mem_op op = *desc->info.op_tmpl; | |
| 651 | 651 | int ret; |
| 652 | 652 | |
| 653 | 653 | op.addr.val = desc->info.offset + offs; |
| @@ -667,7 +667,7 @@ static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, · 13 unmodified lines | ||
| 667 | 667 | static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, |
| 668 | 668 | u64 offs, size_t len, const void *buf) |
| 669 | 669 | { |
| 670 | − struct spi_mem_op op = desc->info.op_tmpl; | |
| 670 | + struct spi_mem_op op = *desc->info.op_tmpl; | |
| 671 | 671 | int ret; |
| 672 | 672 | |
| 673 | 673 | op.addr.val = desc->info.offset + offs; |
| @@ -706,19 +706,37 @@ spi_mem_dirmap_create(struct spi_mem *mem, · 32 unmodified lines | ||
| 706 | 706 | int ret = -ENOTSUPP; |
| 707 | 707 | |
| 708 | 708 | /* Make sure the number of address cycles is between 1 and 8 bytes. */ |
| 709 | − if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8) | |
| 709 | + if (!info->primary_op_tmpl.addr.nbytes || info->primary_op_tmpl.addr.nbytes > 8) | |
| 710 | 710 | return ERR_PTR(-EINVAL); |
| 711 | 711 | |
| 712 | 712 | /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */ |
| 713 | − if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA) | |
| 713 | + if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA) | |
| 714 | 714 | return ERR_PTR(-EINVAL); |
| 715 | 715 | |
| 716 | + /* Apply similar constraints to the secondary template */ | |
| 717 | + if (info->secondary_op_tmpl.cmd.opcode) { | |
| 718 | + if (!info->secondary_op_tmpl.addr.nbytes || | |
| 719 | + info->secondary_op_tmpl.addr.nbytes > 8) | |
| 720 | + return ERR_PTR(-EINVAL); | |
| 721 | + | |
| 722 | + if (info->secondary_op_tmpl.data.dir == SPI_MEM_NO_DATA) | |
| 723 | + return ERR_PTR(-EINVAL); | |
| 724 | + | |
| 725 | + if (!spi_mem_supports_op(mem, &info->secondary_op_tmpl)) | |
| 726 | + return ERR_PTR(-EOPNOTSUPP); | |
| 727 | + | |
| 728 | + if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create && | |
| 729 | + !spi_mem_controller_is_capable(ctlr, secondary_op_tmpl)) | |
| 730 | + return ERR_PTR(-EOPNOTSUPP); | |
| 731 | + } | |
| 732 | + | |
| 716 | 733 | desc = kzalloc_obj(*desc); |
| 717 | 734 | if (!desc) |
| 718 | 735 | return ERR_PTR(-ENOMEM); |
| 719 | 736 | |
| 720 | 737 | desc->mem = mem; |
| 721 | 738 | desc->info = *info; |
| 739 | + desc->info.op_tmpl = &desc->info.primary_op_tmpl; | |
| 722 | 740 | if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) { |
| 723 | 741 | ret = spi_mem_access_start(mem); |
| 724 | 742 | if (ret) { |
| @@ -733,7 +751,7 @@ spi_mem_dirmap_create(struct spi_mem *mem, · 8 unmodified lines | ||
| 733 | 751 | |
| 734 | 752 | if (ret) { |
| 735 | 753 | desc->nodirmap = true; |
| 736 | − if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) | |
| 754 | + if (!spi_mem_supports_op(desc->mem, &desc->info.primary_op_tmpl)) | |
| 737 | 755 | ret = -EOPNOTSUPP; |
| 738 | 756 | else |
| 739 | 757 | ret = 0; |
| @@ -857,7 +875,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, · 117 unmodified lines | ||
| 857 | 875 | struct spi_controller *ctlr = desc->mem->spi->controller; |
| 858 | 876 | ssize_t ret; |
| 859 | 877 | |
| 860 | − if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) | |
| 878 | + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) | |
| 861 | 879 | return -EINVAL; |
| 862 | 880 | |
| 863 | 881 | if (!len) |
| @@ -903,7 +921,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, · 39 unmodified lines | ||
| 903 | 921 | struct spi_controller *ctlr = desc->mem->spi->controller; |
| 904 | 922 | ssize_t ret; |
| 905 | 923 | |
| 906 | − if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT) | |
| 924 | + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_OUT) | |
| 907 | 925 | return -EINVAL; |
| 908 | 926 | |
| 909 | 927 | if (!len) |
| @@ -403,20 +403,20 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, · 402 unmodified lines | ||
| 403 | 403 | if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) |
| 404 | 404 | return -EINVAL; |
| 405 | 405 | |
| 406 | − writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), | |
| 406 | + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.swap16), | |
| 407 | 407 | mxic->regs + HC_CFG); |
| 408 | 408 | |
| 409 | − writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), | |
| 409 | + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), | |
| 410 | 410 | mxic->regs + LRD_CFG); |
| 411 | 411 | writel(desc->info.offset + offs, mxic->regs + LRD_ADDR); |
| 412 | 412 | len = min_t(size_t, len, mxic->linear.size); |
| 413 | 413 | writel(len, mxic->regs + LRD_RANGE); |
| 414 | − writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | | |
| 414 | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | | |
| 415 | 415 | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | |
| 416 | 416 | LMODE_EN, |
| 417 | 417 | mxic->regs + LRD_CTRL); |
| 418 | 418 | |
| 419 | − if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { | |
| 419 | + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { | |
| 420 | 420 | ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, |
| 421 | 421 | NAND_PAGE_READ, |
| 422 | 422 | mxic->linear.dma + offs); |
| @@ -448,20 +448,20 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, · 25 unmodified lines | ||
| 448 | 448 | if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) |
| 449 | 449 | return -EINVAL; |
| 450 | 450 | |
| 451 | − writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), | |
| 451 | + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.swap16), | |
| 452 | 452 | mxic->regs + HC_CFG); |
| 453 | 453 | |
| 454 | − writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), | |
| 454 | + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), | |
| 455 | 455 | mxic->regs + LWR_CFG); |
| 456 | 456 | writel(desc->info.offset + offs, mxic->regs + LWR_ADDR); |
| 457 | 457 | len = min_t(size_t, len, mxic->linear.size); |
| 458 | 458 | writel(len, mxic->regs + LWR_RANGE); |
| 459 | − writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | | |
| 459 | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | | |
| 460 | 460 | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | |
| 461 | 461 | LMODE_EN, |
| 462 | 462 | mxic->regs + LWR_CTRL); |
| 463 | 463 | |
| 464 | − if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { | |
| 464 | + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { | |
| 465 | 465 | ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, |
| 466 | 466 | NAND_PAGE_WRITE, |
| 467 | 467 | mxic->linear.dma + offs); |
| @@ -509,7 +509,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) · 41 unmodified lines | ||
| 509 | 509 | if (desc->info.offset + desc->info.length > U32_MAX) |
| 510 | 510 | return -EINVAL; |
| 511 | 511 | |
| 512 | − if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) | |
| 512 | + if (!mxic_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) | |
| 513 | 513 | return -EOPNOTSUPP; |
| 514 | 514 | |
| 515 | 515 | return 0; |
| @@ -299,11 +299,11 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, · 298 unmodified lines | ||
| 299 | 299 | for (i = 0 ; i < len ; i++) |
| 300 | 300 | *(buf_rx + i) = ioread8(src + i); |
| 301 | 301 | } else { |
| 302 | − if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth || | |
| 303 | − desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes || | |
| 304 | − desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode || | |
| 305 | − desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes) | |
| 306 | − npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); | |
| 302 | + if (desc->info.op_tmpl->addr.buswidth != fiu->drd_op.addr.buswidth || | |
| 303 | + desc->info.op_tmpl->dummy.nbytes != fiu->drd_op.dummy.nbytes || | |
| 304 | + desc->info.op_tmpl->cmd.opcode != fiu->drd_op.cmd.opcode || | |
| 305 | + desc->info.op_tmpl->addr.nbytes != fiu->drd_op.addr.nbytes) | |
| 306 | + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); | |
| 307 | 307 | |
| 308 | 308 | memcpy_fromio(buf_rx, src, len); |
| 309 | 309 | } |
| @@ -609,7 +609,7 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) · 299 unmodified lines | ||
| 609 | 609 | } |
| 610 | 610 | |
| 611 | 611 | if (!fiu->spix_mode && |
| 612 | − desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) { | |
| 612 | + desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) { | |
| 613 | 613 | desc->nodirmap = true; |
| 614 | 614 | return 0; |
| 615 | 615 | } |
| @@ -644,9 +644,9 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) · 28 unmodified lines | ||
| 644 | 644 | NPCM_FIU_CFG_FIU_FIX); |
| 645 | 645 | } |
| 646 | 646 | |
| 647 | − if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) { | |
| 647 | + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) { | |
| 648 | 648 | if (!fiu->spix_mode) |
| 649 | − npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); | |
| 649 | + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); | |
| 650 | 650 | else |
| 651 | 651 | npcm_fiux_set_direct_rd(fiu); |
| 652 | 652 | |
| @@ -98,7 +98,6 @@ · 97 unmodified lines | ||
| 98 | 98 | #define CR0_FRF_MICROWIRE 0x2 |
| 99 | 99 | |
| 100 | 100 | #define CR0_XFM_OFFSET 18 |
| 101 | −#define CR0_XFM_MASK (0x03 << SPI_XFM_OFFSET) | |
| 102 | 101 | #define CR0_XFM_TR 0x0 |
| 103 | 102 | #define CR0_XFM_TO 0x1 |
| 104 | 103 | #define CR0_XFM_RO 0x2 |
| @@ -109,8 +108,6 @@ · 4 unmodified lines | ||
| 109 | 108 | |
| 110 | 109 | #define CR0_SOI_OFFSET 23 |
| 111 | 110 | |
| 112 | −#define CR0_MTM_OFFSET 0x21 | |
| 113 | − | |
| 114 | 111 | /* Bit fields in SER, 2bit */ |
| 115 | 112 | #define SER_MASK 0x3 |
| 116 | 113 | |
| @@ -357,7 +354,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) · 240 unmodified lines | ||
| 357 | 354 | struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
| 358 | 355 | |
| 359 | 356 | /* When int_cs_inactive comes, spi target abort */ |
| 360 | − if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { | |
| 357 | + if (rs->cs_inactive && | |
| 358 | + (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { | |
| 361 | 359 | ctlr->target_abort(ctlr); |
| 362 | 360 | writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); |
| 363 | 361 | writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); |
| @@ -83,7 +83,7 @@ static ssize_t xspi_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, · 82 unmodified lines | ||
| 83 | 83 | if (offs + desc->info.offset + len > U32_MAX) |
| 84 | 84 | return -EINVAL; |
| 85 | 85 | |
| 86 | − rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); | |
| 86 | + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); | |
| 87 | 87 | |
| 88 | 88 | return xspi_dirmap_write(rpc->dev, offs, len, buf); |
| 89 | 89 | } |
| @@ -97,7 +97,7 @@ static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, · 7 unmodified lines | ||
| 97 | 97 | if (offs + desc->info.offset + len > U32_MAX) |
| 98 | 98 | return -EINVAL; |
| 99 | 99 | |
| 100 | − rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); | |
| 100 | + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); | |
| 101 | 101 | |
| 102 | 102 | return rpcif_dirmap_read(rpc->dev, offs, len, buf); |
| 103 | 103 | } |
| @@ -110,13 +110,13 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) · 6 unmodified lines | ||
| 110 | 110 | if (desc->info.offset + desc->info.length > U32_MAX) |
| 111 | 111 | return -EINVAL; |
| 112 | 112 | |
| 113 | − if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) | |
| 113 | + if (!rpcif_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) | |
| 114 | 114 | return -EOPNOTSUPP; |
| 115 | 115 | |
| 116 | 116 | if (!rpc->dirmap) |
| 117 | 117 | return -EOPNOTSUPP; |
| 118 | 118 | |
| 119 | − if (!rpc->xspi && desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) | |
| 119 | + if (!rpc->xspi && desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) | |
| 120 | 120 | return -EOPNOTSUPP; |
| 121 | 121 | |
| 122 | 122 | return 0; |
| @@ -579,7 +579,7 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz) · 578 unmodified lines | ||
| 579 | 579 | rspi->info->find_pclk_rate(rspi->pclk, hz, &best_clock); |
| 580 | 580 | |
| 581 | 581 | if (!best_clock.clk_rate) |
| 582 | − return -EINVAL; | |
| 582 | + return 0; | |
| 583 | 583 | |
| 584 | 584 | ret = clk_set_rate(best_clock.clk, best_clock.clk_rate); |
| 585 | 585 | if (ret) |
| @@ -602,11 +602,11 @@ static int stm32_ospi_dirmap_create(struct spi_mem_dirmap_desc *desc) · 601 unmodified lines | ||
| 602 | 602 | { |
| 603 | 603 | struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 604 | 604 | |
| 605 | − if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) | |
| 605 | + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) | |
| 606 | 606 | return -EOPNOTSUPP; |
| 607 | 607 | |
| 608 | 608 | /* Should never happen, as mm_base == null is an error probe exit condition */ |
| 609 | − if (!ospi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) | |
| 609 | + if (!ospi->mm_base && desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) | |
| 610 | 610 | return -EOPNOTSUPP; |
| 611 | 611 | |
| 612 | 612 | if (!ospi->mm_size) |
| @@ -633,7 +633,7 @@ static ssize_t stm32_ospi_dirmap_read(struct spi_mem_dirmap_desc *desc, · 20 unmodified lines | ||
| 633 | 633 | * spi_mem_op template with offs, len and *buf in order to get |
| 634 | 634 | * all needed transfer information into struct spi_mem_op |
| 635 | 635 | */ |
| 636 | − memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); | |
| 636 | + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); | |
| 637 | 637 | dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); |
| 638 | 638 | |
| 639 | 639 | op.data.nbytes = len; |
| @@ -506,11 +506,11 @@ static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) · 505 unmodified lines | ||
| 506 | 506 | { |
| 507 | 507 | struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 508 | 508 | |
| 509 | − if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) | |
| 509 | + if (desc->info.op_tmpl->data.dir == SPI_MEM_DATA_OUT) | |
| 510 | 510 | return -EOPNOTSUPP; |
| 511 | 511 | |
| 512 | 512 | /* should never happen, as mm_base == null is an error probe exit condition */ |
| 513 | − if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) | |
| 513 | + if (!qspi->mm_base && desc->info.op_tmpl->data.dir == SPI_MEM_DATA_IN) | |
| 514 | 514 | return -EOPNOTSUPP; |
| 515 | 515 | |
| 516 | 516 | if (!qspi->mm_size) |
| @@ -536,7 +536,7 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, · 19 unmodified lines | ||
| 536 | 536 | * spi_mem_op template with offs, len and *buf in order to get |
| 537 | 537 | * all needed transfer information into struct spi_mem_op |
| 538 | 538 | */ |
| 539 | − memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); | |
| 539 | + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); | |
| 540 | 540 | dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); |
| 541 | 541 | |
| 542 | 542 | op.data.nbytes = len; |
| @@ -377,7 +377,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) · 376 unmodified lines | ||
| 377 | 377 | struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); |
| 378 | 378 | int cs = spi_get_chipselect(desc->mem->spi, 0); |
| 379 | 379 | |
| 380 | − if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) | |
| 380 | + if (desc->info.op_tmpl->data.dir != SPI_MEM_DATA_IN) | |
| 381 | 381 | return -EOPNOTSUPP; |
| 382 | 382 | |
| 383 | 383 | /* |
| @@ -1620,6 +1620,12 @@ static void privcmd_close(struct vm_area_struct *vma) · 1619 unmodified lines | ||
| 1620 | 1620 | kvfree(pages); |
| 1621 | 1621 | } |
| 1622 | 1622 | |
| 1623 | +static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr) | |
| 1624 | +{ | |
| 1625 | + /* Forbid splitting, avoids double free via privcmd_close(). */ | |
| 1626 | + return -EINVAL; | |
| 1627 | +} | |
| 1628 | + | |
| 1623 | 1629 | static vm_fault_t privcmd_fault(struct vm_fault *vmf) |
| 1624 | 1630 | { |
| 1625 | 1631 | printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", |
| @@ -1631,6 +1637,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf) · 5 unmodified lines | ||
| 1631 | 1637 | |
| 1632 | 1638 | static const struct vm_operations_struct privcmd_vm_ops = { |
| 1633 | 1639 | .close = privcmd_close, |
| 1640 | + .may_split = privcmd_may_split, | |
| 1634 | 1641 | .fault = privcmd_fault |
| 1635 | 1642 | }; |
| 1636 | 1643 | |
| @@ -366,6 +366,8 @@ static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer) · 365 unmodified lines | ||
| 366 | 366 | ret = sprintf(buffer, "<denied>"); |
| 367 | 367 | return ret; |
| 368 | 368 | } |
| 369 | + if (ret > PAGE_SIZE) | |
| 370 | + return -ENOSPC; | |
| 369 | 371 | |
| 370 | 372 | buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL); |
| 371 | 373 | if (!buildid) |
| @@ -373,8 +375,10 @@ static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer) · 1 unmodified line | ||
| 373 | 375 | |
| 374 | 376 | buildid->len = ret; |
| 375 | 377 | ret = HYPERVISOR_xen_version(XENVER_build_id, buildid); |
| 376 | − if (ret > 0) | |
| 377 | − ret = sprintf(buffer, "%s", buildid->buf); | |
| 378 | + if (ret > 0) { | |
| 379 | + /* Build id is binary, not a string. */ | |
| 380 | + memcpy(buffer, buildid->buf, ret); | |
| 381 | + } | |
| 378 | 382 | kfree(buildid); |
| 379 | 383 | |
| 380 | 384 | return ret; |
| @@ -4641,7 +4641,8 @@ int try_release_extent_buffer(struct folio *folio) · 4640 unmodified lines | ||
| 4641 | 4641 | * to read the block we will not block on anything. |
| 4642 | 4642 | */ |
| 4643 | 4643 | void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, |
| 4644 | − u64 bytenr, u64 owner_root, u64 gen, int level) | |
| 4644 | + u64 bytenr, u64 owner_root, u64 gen, int level, | |
| 4645 | + const struct btrfs_key *first_key) | |
| 4645 | 4646 | { |
| 4646 | 4647 | struct btrfs_tree_parent_check check = { |
| 4647 | 4648 | .level = level, |
| @@ -4650,6 +4651,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, · 2 unmodified lines | ||
| 4650 | 4651 | struct extent_buffer *eb; |
| 4651 | 4652 | int ret; |
| 4652 | 4653 | |
| 4654 | + if (first_key) { | |
| 4655 | + memcpy(&check.first_key, first_key, sizeof(struct btrfs_key)); | |
| 4656 | + check.has_first_key = true; | |
| 4657 | + } | |
| 4658 | + | |
| 4653 | 4659 | eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); |
| 4654 | 4660 | if (IS_ERR(eb)) |
| 4655 | 4661 | return; |
| @@ -4677,9 +4683,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, · 21 unmodified lines | ||
| 4677 | 4683 | */ |
| 4678 | 4684 | void btrfs_readahead_node_child(struct extent_buffer *node, int slot) |
| 4679 | 4685 | { |
| 4686 | + struct btrfs_key node_key; | |
| 4687 | + | |
| 4688 | + btrfs_node_key_to_cpu(node, &node_key, slot); | |
| 4680 | 4689 | btrfs_readahead_tree_block(node->fs_info, |
| 4681 | 4690 | btrfs_node_blockptr(node, slot), |
| 4682 | 4691 | btrfs_header_owner(node), |
| 4683 | 4692 | btrfs_node_ptr_generation(node, slot), |
| 4684 | − btrfs_header_level(node) - 1); | |
| 4693 | + btrfs_header_level(node) - 1, | |
| 4694 | + &node_key); | |
| 4685 | 4695 | } |
| @@ -287,7 +287,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb) · 286 unmodified lines | ||
| 287 | 287 | } |
| 288 | 288 | |
| 289 | 289 | void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, |
| 290 | − u64 bytenr, u64 owner_root, u64 gen, int level); | |
| 290 | + u64 bytenr, u64 owner_root, u64 gen, int level, | |
| 291 | + const struct btrfs_key *first_key); | |
| 291 | 292 | void btrfs_readahead_node_child(struct extent_buffer *node, int slot); |
| 292 | 293 | |
| 293 | 294 | /* Note: this can be used in for loops without caching the value in a variable. */ |
| @@ -259,7 +259,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, · 258 unmodified lines | ||
| 259 | 259 | nr++; |
| 260 | 260 | path->slots[0]--; |
| 261 | 261 | } else { |
| 262 | − ASSERT(0); | |
| 262 | + btrfs_err(fs_info, "unexpected free space tree key type %u", | |
| 263 | + found_key.type); | |
| 264 | + ret = -EUCLEAN; | |
| 265 | + btrfs_abort_transaction(trans, ret); | |
| 266 | + goto out; | |
| 263 | 267 | } |
| 264 | 268 | } |
| 265 | 269 | |
| @@ -405,7 +409,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans, · 139 unmodified lines | ||
| 405 | 409 | |
| 406 | 410 | nr++; |
| 407 | 411 | } else { |
| 408 | − ASSERT(0); | |
| 412 | + btrfs_err(fs_info, "unexpected free space tree key type %u", | |
| 413 | + found_key.type); | |
| 414 | + ret = -EUCLEAN; | |
| 415 | + btrfs_abort_transaction(trans, ret); | |
| 416 | + goto out; | |
| 409 | 417 | } |
| 410 | 418 | } |
| 411 | 419 | |
| @@ -1518,7 +1526,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans, · 1106 unmodified lines | ||
| 1518 | 1526 | nr++; |
| 1519 | 1527 | path->slots[0]--; |
| 1520 | 1528 | } else { |
| 1521 | − ASSERT(0); | |
| 1529 | + btrfs_err(trans->fs_info, "unexpected free space tree key type %u", | |
| 1530 | + found_key.type); | |
| 1531 | + ret = -EUCLEAN; | |
| 1532 | + btrfs_abort_transaction(trans, ret); | |
| 1533 | + return ret; | |
| 1522 | 1534 | } |
| 1523 | 1535 | } |
| 1524 | 1536 | |
| @@ -1153,7 +1153,7 @@ out_free_reserve: · 1152 unmodified lines | ||
| 1153 | 1153 | NULL, &cached, |
| 1154 | 1154 | EXTENT_LOCKED | EXTENT_DELALLOC | |
| 1155 | 1155 | EXTENT_DELALLOC_NEW | |
| 1156 | − EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, | |
| 1156 | + EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, | |
| 1157 | 1157 | PAGE_UNLOCK | PAGE_START_WRITEBACK | |
| 1158 | 1158 | PAGE_END_WRITEBACK); |
| 1159 | 1159 | if (async_extent->cb) |
| @@ -4959,6 +4959,8 @@ static int btrfs_rmdir(struct inode *vfs_dir, struct dentry *dentry) · 3799 unmodified lines | ||
| 4959 | 4959 | if (ret) |
| 4960 | 4960 | goto out; |
| 4961 | 4961 | |
| 4962 | + btrfs_record_unlink_dir(trans, dir, inode, false); | |
| 4963 | + | |
| 4962 | 4964 | /* now the directory is empty */ |
| 4963 | 4965 | ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name); |
| 4964 | 4966 | if (!ret) |
| @@ -5102,7 +5102,6 @@ static int btrfs_ioctl_subvol_sync(struct btrfs_fs_info *fs_info, void __user *a · 5101 unmodified lines | ||
| 5102 | 5102 | return 0; |
| 5103 | 5103 | } |
| 5104 | 5104 | |
| 5105 | −#ifdef CONFIG_BTRFS_EXPERIMENTAL | |
| 5106 | 5105 | static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg) |
| 5107 | 5106 | { |
| 5108 | 5107 | int ret = 0; |
| @@ -5134,10 +5133,12 @@ static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg · 25 unmodified lines | ||
| 5134 | 5133 | case BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH: |
| 5135 | 5134 | btrfs_force_shutdown(fs_info); |
| 5136 | 5135 | break; |
| 5136 | + default: | |
| 5137 | + ret = -EINVAL; | |
| 5138 | + break; | |
| 5137 | 5139 | } |
| 5138 | 5140 | return ret; |
| 5139 | 5141 | } |
| 5140 | −#endif | |
| 5141 | 5142 | |
| 5142 | 5143 | long btrfs_ioctl(struct file *file, unsigned int |
| 5143 | 5144 | cmd, unsigned long arg) |
| @@ -5294,10 +5295,8 @@ long btrfs_ioctl(struct file *file, unsigned int · 150 unmodified lines | ||
| 5294 | 5295 | #endif |
| 5295 | 5296 | case BTRFS_IOC_SUBVOL_SYNC_WAIT: |
| 5296 | 5297 | return btrfs_ioctl_subvol_sync(fs_info, argp); |
| 5297 | −#ifdef CONFIG_BTRFS_EXPERIMENTAL | |
| 5298 | 5298 | case BTRFS_IOC_SHUTDOWN: |
| 5299 | 5299 | return btrfs_ioctl_shutdown(fs_info, arg); |
| 5300 | −#endif | |
| 5301 | 5300 | } |
| 5302 | 5301 | |
| 5303 | 5302 | return -ENOTTY; |
| @@ -45,8 +45,11 @@ static int btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans, · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { |
| 47 | 47 | struct btrfs_raid_stride *stride = &extent->strides[i]; |
| 48 | + u64 devid; | |
| 48 | 49 | u64 phys; |
| 49 | 50 | |
| 51 | + devid = btrfs_raid_stride_devid(leaf, stride); | |
| 52 | + btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid); | |
| 50 | 53 | phys = btrfs_raid_stride_physical(leaf, stride) + frontpad; |
| 51 | 54 | btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys); |
| 52 | 55 | } |
| @@ -95,14 +98,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 42 unmodified lines | ||
| 95 | 98 | while (1) { |
| 96 | 99 | key.objectid = start; |
| 97 | 100 | key.type = BTRFS_RAID_STRIPE_KEY; |
| 98 | − key.offset = 0; | |
| 101 | + key.offset = (u64)-1; | |
| 99 | 102 | |
| 100 | 103 | ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1); |
| 101 | 104 | if (ret < 0) |
| 102 | 105 | break; |
| 103 | 106 | |
| 104 | − if (path->slots[0] == btrfs_header_nritems(path->nodes[0])) | |
| 105 | − path->slots[0]--; | |
| 107 | + /* | |
| 108 | + * Search with offset=(u64)-1 ensures we land on the correct | |
| 109 | + * leaf even when the target entry is the first item on a leaf. | |
| 110 | + * Since no real entry has offset=(u64)-1, ret is always 1 and | |
| 111 | + * slot points past the last entry with objectid==start (or | |
| 112 | + * past the end of the leaf if that entry is the last item). | |
| 113 | + * Back up one slot to find the actual entry. | |
| 114 | + */ | |
| 115 | + if (path->slots[0] == 0) { | |
| 116 | + /* No entry with objectid <= start exists. */ | |
| 117 | + ret = 0; | |
| 118 | + break; | |
| 119 | + } | |
| 120 | + path->slots[0]--; | |
| 106 | 121 | |
| 107 | 122 | leaf = path->nodes[0]; |
| 108 | 123 | slot = path->slots[0]; |
| @@ -123,7 +138,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 14 unmodified lines | ||
| 123 | 138 | */ |
| 124 | 139 | if (found_start > start) { |
| 125 | 140 | if (slot == 0) { |
| 126 | − ret = btrfs_previous_item(stripe_root, path, start, | |
| 141 | + ret = btrfs_previous_item(stripe_root, path, 0, | |
| 127 | 142 | BTRFS_RAID_STRIPE_KEY); |
| 128 | 143 | if (ret) { |
| 129 | 144 | if (ret > 0) |
| @@ -139,7 +154,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 9 unmodified lines | ||
| 139 | 154 | btrfs_item_key_to_cpu(leaf, &key, slot); |
| 140 | 155 | found_start = key.objectid; |
| 141 | 156 | found_end = found_start + key.offset; |
| 142 | − ASSERT(found_start <= start); | |
| 157 | + if (found_start > start || found_end <= start) { | |
| 158 | + ret = -ENOENT; | |
| 159 | + break; | |
| 160 | + } | |
| 143 | 161 | } |
| 144 | 162 | |
| 145 | 163 | if (key.type != BTRFS_RAID_STRIPE_KEY) |
| @@ -176,9 +194,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 30 unmodified lines | ||
| 176 | 194 | |
| 177 | 195 | /* The "right" item. */ |
| 178 | 196 | ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); |
| 197 | + if (ret == -EAGAIN) { | |
| 198 | + btrfs_release_path(path); | |
| 199 | + continue; | |
| 200 | + } | |
| 179 | 201 | if (ret) |
| 180 | 202 | break; |
| 181 | 203 | |
| 204 | + /* | |
| 205 | + * btrfs_duplicate_item() may have triggered a leaf | |
| 206 | + * split via setup_leaf_for_split(), so we must refresh | |
| 207 | + * our leaf pointer from the path. | |
| 208 | + */ | |
| 209 | + leaf = path->nodes[0]; | |
| 182 | 210 | item_size = btrfs_item_size(leaf, path->slots[0]); |
| 183 | 211 | extent = btrfs_item_ptr(leaf, path->slots[0], |
| 184 | 212 | struct btrfs_stripe_extent); |
| @@ -195,8 +223,9 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 10 unmodified lines | ||
| 195 | 223 | /* The "left" item. */ |
| 196 | 224 | path->slots[0]--; |
| 197 | 225 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); |
| 198 | − btrfs_partially_delete_raid_extent(trans, path, &key, | |
| 199 | − diff_start, 0); | |
| 226 | + ret = btrfs_partially_delete_raid_extent(trans, path, | |
| 227 | + &key, | |
| 228 | + diff_start, 0); | |
| 200 | 229 | break; |
| 201 | 230 | } |
| 202 | 231 | |
| @@ -212,8 +241,11 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 9 unmodified lines | ||
| 212 | 241 | if (found_start < start) { |
| 213 | 242 | u64 diff_start = start - found_start; |
| 214 | 243 | |
| 215 | − btrfs_partially_delete_raid_extent(trans, path, &key, | |
| 216 | − diff_start, 0); | |
| 244 | + ret = btrfs_partially_delete_raid_extent(trans, path, | |
| 245 | + &key, | |
| 246 | + diff_start, 0); | |
| 247 | + if (ret) | |
| 248 | + break; | |
| 217 | 249 | |
| 218 | 250 | start += (key.offset - diff_start); |
| 219 | 251 | length -= (key.offset - diff_start); |
| @@ -236,9 +268,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le · 16 unmodified lines | ||
| 236 | 268 | if (found_end > end) { |
| 237 | 269 | u64 diff_end = found_end - end; |
| 238 | 270 | |
| 239 | − btrfs_partially_delete_raid_extent(trans, path, &key, | |
| 240 | − key.offset - length, | |
| 241 | − length); | |
| 271 | + ret = btrfs_partially_delete_raid_extent(trans, path, | |
| 272 | + &key, | |
| 273 | + key.offset - length, | |
| 274 | + length); | |
| 242 | 275 | ASSERT(key.offset - diff_end == length); |
| 243 | 276 | break; |
| 244 | 277 | } |
| @@ -2607,7 +2607,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, · 2606 unmodified lines | ||
| 2607 | 2607 | if (!block->key_ready) |
| 2608 | 2608 | btrfs_readahead_tree_block(fs_info, block->bytenr, |
| 2609 | 2609 | block->owner, 0, |
| 2610 | − block->level); | |
| 2610 | + block->level, NULL); | |
| 2611 | 2611 | } |
| 2612 | 2612 | |
| 2613 | 2613 | /* Get first keys */ |
| @@ -3876,7 +3876,7 @@ static int add_remap_tree_entries(struct btrfs_trans_handle *trans, struct btrfs · 1262 unmodified lines | ||
| 3876 | 3876 | ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch); |
| 3877 | 3877 | btrfs_release_path(path); |
| 3878 | 3878 | |
| 3879 | − if (num_entries <= max_items) | |
| 3879 | + if (ret || num_entries <= max_items) | |
| 3880 | 3880 | break; |
| 3881 | 3881 | |
| 3882 | 3882 | num_entries -= max_items; |
| @@ -4174,6 +4174,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info, · 291 unmodified lines | ||
| 4174 | 4174 | return ret; |
| 4175 | 4175 | } |
| 4176 | 4176 | |
| 4177 | + if (ins.offset < length) { | |
| 4178 | + spin_lock(&sinfo->lock); | |
| 4179 | + btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - length); | |
| 4180 | + spin_unlock(&sinfo->lock); | |
| 4181 | + } | |
| 4182 | + | |
| 4177 | 4183 | dest_addr = ins.objectid; |
| 4178 | 4184 | dest_length = ins.offset; |
| 4179 | 4185 | |
| @@ -5000,6 +5006,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info, · 820 unmodified lines | ||
| 5000 | 5006 | return ret; |
| 5001 | 5007 | } |
| 5002 | 5008 | |
| 5009 | + if (ins.offset < remap_length) { | |
| 5010 | + spin_lock(&sinfo->lock); | |
| 5011 | + btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - remap_length); | |
| 5012 | + spin_unlock(&sinfo->lock); | |
| 5013 | + } | |
| 5014 | + | |
| 5003 | 5015 | made_reservation = true; |
| 5004 | 5016 | |
| 5005 | 5017 | new_addr = ins.objectid; |
| @@ -5023,21 +5035,27 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info, · 17 unmodified lines | ||
| 5023 | 5035 | |
| 5024 | 5036 | if (bg_needs_free_space) { |
| 5025 | 5037 | ret = btrfs_add_block_group_free_space(trans, dest_bg); |
| 5026 | − if (ret) | |
| 5038 | + if (ret) { | |
| 5039 | + btrfs_abort_transaction(trans, ret); | |
| 5027 | 5040 | goto fail; |
| 5041 | + } | |
| 5028 | 5042 | } |
| 5029 | 5043 | |
| 5030 | 5044 | ret = copy_remapped_data(fs_info, start, new_addr, length); |
| 5031 | − if (ret) | |
| 5045 | + if (ret) { | |
| 5046 | + btrfs_abort_transaction(trans, ret); | |
| 5032 | 5047 | goto fail; |
| 5048 | + } | |
| 5033 | 5049 | |
| 5034 | 5050 | ret = btrfs_remove_from_free_space_tree(trans, new_addr, length); |
| 5035 | − if (ret) | |
| 5051 | + if (ret) { | |
| 5052 | + btrfs_abort_transaction(trans, ret); | |
| 5036 | 5053 | goto fail; |
| 5054 | + } | |
| 5037 | 5055 | |
| 5038 | 5056 | ret = add_remap_entry(trans, path, src_bg, start, new_addr, length); |
| 5039 | 5057 | if (ret) { |
| 5040 | − btrfs_add_to_free_space_tree(trans, new_addr, length); | |
| 5058 | + btrfs_abort_transaction(trans, ret); | |
| 5041 | 5059 | goto fail; |
| 5042 | 5060 | } |
| 5043 | 5061 | |
| @@ -24,7 +24,7 @@ isofs_export_iget(struct super_block *sb, · 23 unmodified lines | ||
| 24 | 24 | { |
| 25 | 25 | struct inode *inode; |
| 26 | 26 | |
| 27 | − if (block == 0) | |
| 27 | + if (block == 0 || block >= ISOFS_SB(sb)->s_nzones) | |
| 28 | 28 | return ERR_PTR(-ESTALE); |
| 29 | 29 | inode = isofs_iget(sb, block, offset); |
| 30 | 30 | if (IS_ERR(inode)) |
| @@ -10,20 +10,13 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/gfp.h> |
| 11 | 11 | #include "isofs.h" |
| 12 | 12 | |
| 13 | −/* | |
| 14 | − * ok, we cannot use strncmp, as the name is not in our data space. | |
| 15 | − * Thus we'll have to use isofs_match. No big problem. Match also makes | |
| 16 | − * some sanity tests. | |
| 17 | − */ | |
| 18 | 13 | static int |
| 19 | 14 | isofs_cmp(struct dentry *dentry, const char *compare, int dlen) |
| 20 | 15 | { |
| 21 | − struct qstr qstr; | |
| 22 | − qstr.name = compare; | |
| 23 | − qstr.len = dlen; | |
| 24 | 16 | if (likely(!dentry->d_op)) |
| 25 | 17 | return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen); |
| 26 | − return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr); | |
| 18 | + return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, | |
| 19 | + &QSTR_LEN(compare, dlen)); | |
| 27 | 20 | } |
| 28 | 21 | |
| 29 | 22 | /* |
| @@ -101,6 +101,15 @@ static int rock_continue(struct rock_state *rs) · 100 unmodified lines | ||
| 101 | 101 | goto out; |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | + if ((unsigned)rs->cont_extent >= ISOFS_SB(rs->inode->i_sb)->s_nzones) { | |
| 105 | + printk(KERN_NOTICE "rock: corrupted directory entry. " | |
| 106 | + "extent=%u out of volume (nzones=%lu)\n", | |
| 107 | + (unsigned)rs->cont_extent, | |
| 108 | + ISOFS_SB(rs->inode->i_sb)->s_nzones); | |
| 109 | + ret = -EIO; | |
| 110 | + goto out; | |
| 111 | + } | |
| 112 | + | |
| 104 | 113 | if (rs->cont_extent) { |
| 105 | 114 | struct buffer_head *bh; |
| 106 | 115 | |
| @@ -457,7 +457,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, · 456 unmodified lines | ||
| 457 | 457 | /* |
| 458 | 458 | * Unlike file_handle, type and len of struct fanotify_fh are u8. |
| 459 | 459 | * Traditionally, filesystem return handle_type < 0xff, but there |
| 460 | − * is no enforecement for that in vfs. | |
| 460 | + * is no enforcement for that in vfs. | |
| 461 | 461 | */ |
| 462 | 462 | BUILD_BUG_ON(MAX_HANDLE_SZ > 0xff || FILEID_INVALID > 0xff); |
| 463 | 463 | if (type <= 0 || type >= FILEID_INVALID || fh_len != dwords << 2) |
| @@ -388,7 +388,7 @@ static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector · 387 unmodified lines | ||
| 388 | 388 | return hlist_entry_safe(node, struct fsnotify_mark, obj_list); |
| 389 | 389 | } |
| 390 | 390 | |
| 391 | −static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark) | |
| 391 | +struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark) | |
| 392 | 392 | { |
| 393 | 393 | struct hlist_node *node = NULL; |
| 394 | 394 | |
| @@ -238,7 +238,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn, · 237 unmodified lines | ||
| 238 | 238 | return inode; |
| 239 | 239 | } |
| 240 | 240 | |
| 241 | −static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) | |
| 241 | +/* | |
| 242 | + * Calculate mask of events for a list of marks. | |
| 243 | + * | |
| 244 | + * Return true if any of the attached marks want to hold an inode reference. | |
| 245 | + */ | |
| 246 | +static bool __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) | |
| 242 | 247 | { |
| 243 | 248 | u32 new_mask = 0; |
| 244 | 249 | bool want_iref = false; |
| @@ -262,6 +267,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) · 17 unmodified lines | ||
| 262 | 267 | */ |
| 263 | 268 | WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask); |
| 264 | 269 | |
| 270 | + return want_iref; | |
| 271 | +} | |
| 272 | + | |
| 273 | +/* | |
| 274 | + * Calculate mask of events for a list of marks after attach/modify mark | |
| 275 | + * and get an inode reference for the connector if needed. | |
| 276 | + * | |
| 277 | + * A concurrent add of evictable mark and detach of non-evictable mark can | |
| 278 | + * lead to __fsnotify_recalc_mask() returning false want_iref, but in this | |
| 279 | + * case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called | |
| 280 | + * from fsnotify_put_mark(). | |
| 281 | + */ | |
| 282 | +static void fsnotify_recalc_mask_set_iref(struct fsnotify_mark_connector *conn) | |
| 283 | +{ | |
| 284 | + bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF; | |
| 285 | + bool want_iref = __fsnotify_recalc_mask(conn) || has_iref; | |
| 286 | + | |
| 287 | + (void) fsnotify_update_iref(conn, want_iref); | |
| 288 | +} | |
| 289 | + | |
| 290 | +/* | |
| 291 | + * Calculate mask of events for a list of marks after detach mark | |
| 292 | + * and return the inode object if its reference is no longer needed. | |
| 293 | + */ | |
| 294 | +static void *fsnotify_recalc_mask_clear_iref(struct fsnotify_mark_connector *conn) | |
| 295 | +{ | |
| 296 | + bool want_iref = __fsnotify_recalc_mask(conn); | |
| 297 | + | |
| 265 | 298 | return fsnotify_update_iref(conn, want_iref); |
| 266 | 299 | } |
| 267 | 300 | |
| @@ -298,7 +331,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) · 30 unmodified lines | ||
| 298 | 331 | |
| 299 | 332 | spin_lock(&conn->lock); |
| 300 | 333 | update_children = !fsnotify_conn_watches_children(conn); |
| 301 | − __fsnotify_recalc_mask(conn); | |
| 334 | + fsnotify_recalc_mask_set_iref(conn); | |
| 302 | 335 | update_children &= fsnotify_conn_watches_children(conn); |
| 303 | 336 | spin_unlock(&conn->lock); |
| 304 | 337 | /* |
| @@ -419,7 +452,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) · 114 unmodified lines | ||
| 419 | 452 | /* Update watched objects after detaching mark */ |
| 420 | 453 | if (sb) |
| 421 | 454 | fsnotify_update_sb_watchers(sb, conn); |
| 422 | − objp = __fsnotify_recalc_mask(conn); | |
| 455 | + objp = fsnotify_recalc_mask_clear_iref(conn); | |
| 423 | 456 | type = conn->type; |
| 424 | 457 | } |
| 425 | 458 | WRITE_ONCE(mark->connector, NULL); |
| @@ -457,9 +490,6 @@ EXPORT_SYMBOL_GPL(fsnotify_put_mark); · 31 unmodified lines | ||
| 457 | 490 | */ |
| 458 | 491 | static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) |
| 459 | 492 | { |
| 460 | − if (!mark) | |
| 461 | − return true; | |
| 462 | − | |
| 463 | 493 | if (refcount_inc_not_zero(&mark->refcnt)) { |
| 464 | 494 | spin_lock(&mark->lock); |
| 465 | 495 | if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) { |
| @@ -500,15 +530,22 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) · 34 unmodified lines | ||
| 500 | 530 | int type; |
| 501 | 531 | |
| 502 | 532 | fsnotify_foreach_iter_type(type) { |
| 533 | + struct fsnotify_mark *mark = iter_info->marks[type]; | |
| 534 | + | |
| 503 | 535 | /* This can fail if mark is being removed */ |
| 504 | − if (!fsnotify_get_mark_safe(iter_info->marks[type])) { | |
| 505 | − __release(&fsnotify_mark_srcu); | |
| 506 | − goto fail; | |
| 536 | + while (mark && !fsnotify_get_mark_safe(mark)) { | |
| 537 | + if (mark->group == iter_info->current_group) { | |
| 538 | + __release(&fsnotify_mark_srcu); | |
| 539 | + goto fail; | |
| 540 | + } | |
| 541 | + /* This is a mark in an unrelated group, skip */ | |
| 542 | + mark = fsnotify_next_mark(mark); | |
| 543 | + iter_info->marks[type] = mark; | |
| 507 | 544 | } |
| 508 | 545 | } |
| 509 | 546 | |
| 510 | 547 | /* |
| 511 | − * Now that both marks are pinned by refcount in the inode / vfsmount | |
| 548 | + * Now that all marks are pinned by refcount in the inode / vfsmount / etc | |
| 512 | 549 | * lists, we can drop SRCU lock, and safely resume the list iteration |
| 513 | 550 | * once userspace returns. |
| 514 | 551 | */ |
| @@ -125,7 +125,7 @@ int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, · 124 unmodified lines | ||
| 125 | 125 | struct address_space *mapping; |
| 126 | 126 | struct folio *folio; |
| 127 | 127 | u8 *kaddr; |
| 128 | − int pos, len; | |
| 128 | + int pos, len, err; | |
| 129 | 129 | u8 bit; |
| 130 | 130 | struct ntfs_inode *ni = NTFS_I(vi); |
| 131 | 131 | struct ntfs_volume *vol = ni->vol; |
| @@ -201,8 +201,10 @@ int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, · 69 unmodified lines | ||
| 201 | 201 | |
| 202 | 202 | /* If we are not in the last page, deal with all subsequent pages. */ |
| 203 | 203 | while (index < end_index) { |
| 204 | − if (cnt <= 0) | |
| 204 | + if (cnt <= 0) { | |
| 205 | + err = -EIO; | |
| 205 | 206 | goto rollback; |
| 207 | + } | |
| 206 | 208 | |
| 207 | 209 | /* Update @index and get the next folio. */ |
| 208 | 210 | folio_mark_dirty(folio); |
| @@ -214,6 +216,7 @@ int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, · 5 unmodified lines | ||
| 214 | 216 | ntfs_error(vi->i_sb, |
| 215 | 217 | "Failed to map subsequent page (error %li), aborting.", |
| 216 | 218 | PTR_ERR(folio)); |
| 219 | + err = PTR_ERR(folio); | |
| 217 | 220 | goto rollback; |
| 218 | 221 | } |
| 219 | 222 | |
| @@ -265,7 +268,7 @@ rollback: · 45 unmodified lines | ||
| 265 | 268 | * - @count - @cnt is the number of bits that have been modified |
| 266 | 269 | */ |
| 267 | 270 | if (is_rollback) |
| 268 | − return PTR_ERR(folio); | |
| 271 | + return err; | |
| 269 | 272 | if (count != cnt) |
| 270 | 273 | pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt, |
| 271 | 274 | value ? 0 : 1, true); |
| @@ -274,14 +277,14 @@ rollback: · 2 unmodified lines | ||
| 274 | 277 | if (!pos) { |
| 275 | 278 | /* Rollback was successful. */ |
| 276 | 279 | ntfs_error(vi->i_sb, |
| 277 | − "Failed to map subsequent page (error %li), aborting.", | |
| 278 | − PTR_ERR(folio)); | |
| 280 | + "Failed to map subsequent page (error %i), aborting.", | |
| 281 | + err); | |
| 279 | 282 | } else { |
| 280 | 283 | /* Rollback failed. */ |
| 281 | 284 | ntfs_error(vi->i_sb, |
| 282 | − "Failed to map subsequent page (error %li) and rollback failed (error %i). Aborting and leaving inconsistent metadata. Unmount and run chkdsk.", | |
| 283 | − PTR_ERR(folio), pos); | |
| 285 | + "Failed to map subsequent page (error %i) and rollback failed (error %i). Aborting and leaving inconsistent metadata. Unmount and run chkdsk.", | |
| 286 | + err, pos); | |
| 284 | 287 | NVolSetErrors(NTFS_SB(vi->i_sb)); |
| 285 | 288 | } |
| 286 | − return PTR_ERR(folio); | |
| 289 | + return err; | |
| 287 | 290 | } |
| @@ -911,8 +911,8 @@ static int ntfs_readdir(struct file *file, struct dir_context *actor) · 910 unmodified lines | ||
| 911 | 911 | |
| 912 | 912 | if (next->flags & INDEX_ENTRY_NODE) { |
| 913 | 913 | next = ntfs_index_walk_down(next, ictx); |
| 914 | − if (!next) { | |
| 915 | − err = -EIO; | |
| 914 | + if (IS_ERR(next)) { | |
| 915 | + err = PTR_ERR(next); | |
| 916 | 916 | goto out; |
| 917 | 917 | } |
| 918 | 918 | } |
| @@ -920,7 +920,14 @@ static int ntfs_readdir(struct file *file, struct dir_context *actor) · 1 unmodified line | ||
| 920 | 920 | if (next && !(next->flags & INDEX_ENTRY_END)) |
| 921 | 921 | goto nextdir; |
| 922 | 922 | |
| 923 | − while ((next = ntfs_index_next(next, ictx)) != NULL) { | |
| 923 | + while (1) { | |
| 924 | + next = ntfs_index_next(next, ictx); | |
| 925 | + if (IS_ERR(next)) { | |
| 926 | + err = PTR_ERR(next); | |
| 927 | + goto out; | |
| 928 | + } | |
| 929 | + if (!next) | |
| 930 | + break; | |
| 924 | 931 | nextdir: |
| 925 | 932 | /* Check the consistency of an index entry */ |
| 926 | 933 | if (ntfs_index_entry_inconsistent(ictx, vol, next, COLLATION_FILE_NAME, |
| @@ -1969,15 +1969,19 @@ err_out: · 1968 unmodified lines | ||
| 1969 | 1969 | struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_index_context *ictx) |
| 1970 | 1970 | { |
| 1971 | 1971 | struct index_entry *entry; |
| 1972 | + struct index_block *ib; | |
| 1972 | 1973 | s64 vcn; |
| 1973 | 1974 | |
| 1974 | 1975 | entry = ie; |
| 1975 | 1976 | do { |
| 1976 | 1977 | vcn = ntfs_ie_get_vcn(entry); |
| 1977 | 1978 | if (ictx->is_in_root) { |
| 1979 | + ib = kvzalloc(ictx->block_size, GFP_NOFS); | |
| 1980 | + if (!ib) | |
| 1981 | + return ERR_PTR(-ENOMEM); | |
| 1978 | 1982 | /* down from level zero */ |
| 1979 | 1983 | ictx->ir = NULL; |
| 1980 | − ictx->ib = kvzalloc(ictx->block_size, GFP_NOFS); | |
| 1984 | + ictx->ib = ib; | |
| 1981 | 1985 | ictx->pindex = 1; |
| 1982 | 1986 | ictx->is_in_root = false; |
| 1983 | 1987 | } else { |
| @@ -1991,8 +1995,8 @@ struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_ind · 7 unmodified lines | ||
| 1991 | 1995 | ictx->entry = ntfs_ie_get_first(&ictx->ib->index); |
| 1992 | 1996 | entry = ictx->entry; |
| 1993 | 1997 | } else |
| 1994 | − entry = NULL; | |
| 1995 | − } while (entry && (entry->flags & INDEX_ENTRY_NODE)); | |
| 1998 | + entry = ERR_PTR(-EIO); | |
| 1999 | + } while (!IS_ERR(entry) && (entry->flags & INDEX_ENTRY_NODE)); | |
| 1996 | 2000 | |
| 1997 | 2001 | return entry; |
| 1998 | 2002 | } |
| @@ -2097,10 +2101,15 @@ struct index_entry *ntfs_index_next(struct index_entry *ie, struct ntfs_index_co · 98 unmodified lines | ||
| 2097 | 2101 | |
| 2098 | 2102 | /* walk down if it has a subnode */ |
| 2099 | 2103 | if (flags & INDEX_ENTRY_NODE) { |
| 2100 | − if (!ictx->ia_ni) | |
| 2104 | + if (!ictx->ia_ni) { | |
| 2101 | 2105 | ictx->ia_ni = ntfs_ia_open(ictx, ictx->idx_ni); |
| 2106 | + if (!ictx->ia_ni) | |
| 2107 | + return ERR_PTR(-EIO); | |
| 2108 | + } | |
| 2102 | 2109 | |
| 2103 | 2110 | next = ntfs_index_walk_down(next, ictx); |
| 2111 | + if (IS_ERR(next)) | |
| 2112 | + return next; | |
| 2104 | 2113 | } else { |
| 2105 | 2114 | |
| 2106 | 2115 | /* walk up it has no subnode, nor data */ |
| @@ -788,8 +788,7 @@ static int ntfs_write_iomap_end_resident(struct inode *inode, loff_t pos, · 787 unmodified lines | ||
| 788 | 788 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 789 | 789 | if (!ctx) { |
| 790 | 790 | written = -ENOMEM; |
| 791 | − mutex_unlock(&ni->mrec_lock); | |
| 792 | − return written; | |
| 791 | + goto err_out; | |
| 793 | 792 | } |
| 794 | 793 | |
| 795 | 794 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
| @@ -810,7 +809,8 @@ static int ntfs_write_iomap_end_resident(struct inode *inode, loff_t pos, · 14 unmodified lines | ||
| 810 | 809 | memcpy(kattr + pos, iomap_inline_data(iomap, pos), written); |
| 811 | 810 | mark_mft_record_dirty(ctx->ntfs_ino); |
| 812 | 811 | err_out: |
| 813 | − ntfs_attr_put_search_ctx(ctx); | |
| 812 | + if (ctx) | |
| 813 | + ntfs_attr_put_search_ctx(ctx); | |
| 814 | 814 | put_page(ipage); |
| 815 | 815 | mutex_unlock(&ni->mrec_lock); |
| 816 | 816 | return written; |
| @@ -945,7 +945,8 @@ search: · 944 unmodified lines | ||
| 945 | 945 | |
| 946 | 946 | ni_mrec = actx->base_mrec ? actx->base_mrec : actx->mrec; |
| 947 | 947 | ni_mrec->link_count = cpu_to_le16(le16_to_cpu(ni_mrec->link_count) - 1); |
| 948 | − drop_nlink(VFS_I(ni)); | |
| 948 | + if (!S_ISDIR(VFS_I(ni)->i_mode)) | |
| 949 | + drop_nlink(VFS_I(ni)); | |
| 949 | 950 | |
| 950 | 951 | mark_mft_record_dirty(ni); |
| 951 | 952 | if (looking_for_dos_name) { |
| @@ -955,6 +956,13 @@ search: · 3 unmodified lines | ||
| 955 | 956 | goto search; |
| 956 | 957 | } |
| 957 | 958 | |
| 959 | + /* | |
| 960 | + * For directories, Drop VFS nlink only when mft record link count | |
| 961 | + * becomes zero. Because we fixes VFS nlink to 1 for directories. | |
| 962 | + */ | |
| 963 | + if (S_ISDIR(VFS_I(ni)->i_mode) && !le16_to_cpu(ni_mrec->link_count)) | |
| 964 | + drop_nlink(VFS_I(ni)); | |
| 965 | + | |
| 958 | 966 | /* |
| 959 | 967 | * If hard link count is not equal to zero then we are done. In other |
| 960 | 968 | * case there are no reference to this inode left, so we should free all |
| @@ -1221,7 +1229,8 @@ static int __ntfs_link(struct ntfs_inode *ni, struct ntfs_inode *dir_ni, · 260 unmodified lines | ||
| 1221 | 1229 | } |
| 1222 | 1230 | /* Increment hard links count. */ |
| 1223 | 1231 | ni_mrec->link_count = cpu_to_le16(le16_to_cpu(ni_mrec->link_count) + 1); |
| 1224 | − inc_nlink(VFS_I(ni)); | |
| 1232 | + if (!S_ISDIR(vi->i_mode)) | |
| 1233 | + inc_nlink(VFS_I(ni)); | |
| 1225 | 1234 | |
| 1226 | 1235 | /* Done! */ |
| 1227 | 1236 | mark_mft_record_dirty(ni); |
| @@ -505,7 +505,6 @@ int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, · 504 unmodified lines | ||
| 505 | 505 | struct reparse_point *reparse; |
| 506 | 506 | struct wsl_link_reparse_data *data; |
| 507 | 507 | |
| 508 | − utarget = (char *)NULL; | |
| 509 | 508 | len = ntfs_ucstonls(ni->vol, target, target_len, &utarget, 0); |
| 510 | 509 | if (len <= 0) |
| 511 | 510 | return -EINVAL; |
| @@ -514,7 +513,7 @@ int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, · 2 unmodified lines | ||
| 514 | 513 | reparse = kvzalloc(reparse_len, GFP_NOFS); |
| 515 | 514 | if (!reparse) { |
| 516 | 515 | err = -ENOMEM; |
| 517 | − kvfree(utarget); | |
| 516 | + kfree(utarget); | |
| 518 | 517 | } else { |
| 519 | 518 | data = (struct wsl_link_reparse_data *)reparse->reparse_data; |
| 520 | 519 | reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; |
| @@ -528,6 +527,8 @@ int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, · 7 unmodified lines | ||
| 528 | 527 | kvfree(reparse); |
| 529 | 528 | if (!err) |
| 530 | 529 | ni->target = utarget; |
| 530 | + else | |
| 531 | + kfree(utarget); | |
| 531 | 532 | } |
| 532 | 533 | return err; |
| 533 | 534 | } |
| @@ -15,6 +15,8 @@ · 14 unmodified lines | ||
| 15 | 15 | * Copyright (c) 2007-2022 Jean-Pierre Andre |
| 16 | 16 | */ |
| 17 | 17 | |
| 18 | +#include <linux/overflow.h> | |
| 19 | + | |
| 18 | 20 | #include "ntfs.h" |
| 19 | 21 | #include "attrib.h" |
| 20 | 22 | |
| @@ -739,6 +741,7 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume * · 718 unmodified lines | ||
| 739 | 741 | int rlsize; /* Size of runlist buffer. */ |
| 740 | 742 | u16 rlpos; /* Current runlist position in units of struct runlist_elements. */ |
| 741 | 743 | u8 b; /* Current byte offset in buf. */ |
| 744 | + u64 lowest_vcn; /* Raw on-disk lowest_vcn. */ | |
| 742 | 745 | |
| 743 | 746 | #ifdef DEBUG |
| 744 | 747 | /* Make sure attr exists and is non-resident. */ |
| @@ -747,8 +750,14 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume * · 2 unmodified lines | ||
| 747 | 750 | return ERR_PTR(-EINVAL); |
| 748 | 751 | } |
| 749 | 752 | #endif |
| 753 | + lowest_vcn = le64_to_cpu(attr->data.non_resident.lowest_vcn); | |
| 754 | + /* Validate lowest_vcn from on-disk metadata to ensure it is sane. */ | |
| 755 | + if (overflows_type(lowest_vcn, vcn)) { | |
| 756 | + ntfs_error(vol->sb, "Invalid lowest_vcn in mapping pairs."); | |
| 757 | + return ERR_PTR(-EIO); | |
| 758 | + } | |
| 750 | 759 | /* Start at vcn = lowest_vcn and lcn 0. */ |
| 751 | − vcn = le64_to_cpu(attr->data.non_resident.lowest_vcn); | |
| 760 | + vcn = lowest_vcn; | |
| 752 | 761 | lcn = 0; |
| 753 | 762 | /* Get start of the mapping pairs array. */ |
| 754 | 763 | buf = (u8 *)attr + |
| @@ -823,8 +832,17 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume * · 68 unmodified lines | ||
| 823 | 832 | * element. |
| 824 | 833 | */ |
| 825 | 834 | rl[rlpos].length = deltaxcn; |
| 826 | − /* Increment the current vcn by the current run length. */ | |
| 827 | − vcn += deltaxcn; | |
| 835 | + /* | |
| 836 | + * Increment the current vcn by the current run length. | |
| 837 | + * Guard against s64 overflow from a crafted mapping | |
| 838 | + * pairs array to preserve the monotonically-increasing | |
| 839 | + * vcn invariant. | |
| 840 | + */ | |
| 841 | + if (unlikely(check_add_overflow(vcn, deltaxcn, &vcn))) { | |
| 842 | + ntfs_error(vol->sb, "VCN overflow in mapping pairs array."); | |
| 843 | + goto err_out; | |
| 844 | + } | |
| 845 | + | |
| 828 | 846 | /* |
| 829 | 847 | * There might be no lcn change at all, as is the case for |
| 830 | 848 | * sparse clusters on NTFS 3.0+, in which case we set the lcn |
| @@ -89,7 +89,6 @@ int cifs_handle_standard(struct TCP_Server_Info *server, · 88 unmodified lines | ||
| 89 | 89 | struct mid_q_entry *mid); |
| 90 | 90 | char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep); |
| 91 | 91 | int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); |
| 92 | −int smb3_parse_opt(const char *options, const char *key, char **val); | |
| 93 | 92 | int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); |
| 94 | 93 | bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); |
| 95 | 94 | int cifs_discard_remaining_data(struct TCP_Server_Info *server); |
| @@ -536,37 +536,6 @@ cifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_contex · 535 unmodified lines | ||
| 536 | 536 | return 0; |
| 537 | 537 | } |
| 538 | 538 | |
| 539 | −int smb3_parse_opt(const char *options, const char *key, char **val) | |
| 540 | −{ | |
| 541 | − int rc = -ENOENT; | |
| 542 | − char *opts, *orig, *p; | |
| 543 | − | |
| 544 | − orig = opts = kstrdup(options, GFP_KERNEL); | |
| 545 | − if (!opts) | |
| 546 | − return -ENOMEM; | |
| 547 | − | |
| 548 | − while ((p = strsep(&opts, ","))) { | |
| 549 | − char *nval; | |
| 550 | − | |
| 551 | − if (!*p) | |
| 552 | − continue; | |
| 553 | − if (strncasecmp(p, key, strlen(key))) | |
| 554 | − continue; | |
| 555 | − nval = strchr(p, '='); | |
| 556 | − if (nval) { | |
| 557 | − if (nval == p) | |
| 558 | − continue; | |
| 559 | − *nval++ = 0; | |
| 560 | − *val = kstrdup(nval, GFP_KERNEL); | |
| 561 | − rc = !*val ? -ENOMEM : 0; | |
| 562 | − goto out; | |
| 563 | − } | |
| 564 | − } | |
| 565 | −out: | |
| 566 | − kfree(orig); | |
| 567 | − return rc; | |
| 568 | −} | |
| 569 | − | |
| 570 | 539 | /* |
| 571 | 540 | * Remove duplicate path delimiters. Windows is supposed to do that |
| 572 | 541 | * but there are some bugs that prevent rename from working if there are |
| @@ -230,7 +230,7 @@ replay_again: · 229 unmodified lines | ||
| 230 | 230 | num_rqst = 0; |
| 231 | 231 | server = cifs_pick_channel(ses); |
| 232 | 232 | |
| 233 | − vars = kzalloc_obj(*vars, GFP_ATOMIC); | |
| 233 | + vars = kzalloc_obj(*vars, GFP_KERNEL); | |
| 234 | 234 | if (vars == NULL) { |
| 235 | 235 | rc = -ENOMEM; |
| 236 | 236 | goto out; |
| @@ -111,10 +111,21 @@ smb2_add_credits(struct TCP_Server_Info *server, · 110 unmodified lines | ||
| 111 | 111 | cifs_trace_rw_credits_zero_in_flight); |
| 112 | 112 | } |
| 113 | 113 | server->in_flight--; |
| 114 | + | |
| 115 | + /* | |
| 116 | + * Rebalance credits when an op drains in_flight. For session setup, | |
| 117 | + * do this only when the total accumulated credits are high enough (>2) | |
| 118 | + * so that a newly established secondary channel can reserve credits for | |
| 119 | + * echoes and oplocks. We expect this to happen at the end of the final | |
| 120 | + * session setup response. | |
| 121 | + */ | |
| 114 | 122 | if (server->in_flight == 0 && |
| 115 | 123 | ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) && |
| 116 | 124 | ((optype & CIFS_OP_MASK) != CIFS_SESS_OP)) |
| 117 | 125 | rc = change_conf(server); |
| 126 | + else if (server->in_flight == 0 && | |
| 127 | + ((optype & CIFS_OP_MASK) == CIFS_SESS_OP) && *val > 2) | |
| 128 | + rc = change_conf(server); | |
| 118 | 129 | /* |
| 119 | 130 | * Sometimes server returns 0 credits on oplock break ack - we need to |
| 120 | 131 | * rebalance credits in this case. |
| @@ -540,24 +540,54 @@ out: · 539 unmodified lines | ||
| 540 | 540 | |
| 541 | 541 | static void stop_sessions(void) |
| 542 | 542 | { |
| 543 | − struct ksmbd_conn *conn; | |
| 543 | + struct ksmbd_conn *conn, *target; | |
| 544 | 544 | struct ksmbd_transport *t; |
| 545 | + bool any; | |
| 545 | 546 | int bkt; |
| 546 | 547 | |
| 548 | + /* | |
| 549 | + * Serialised via init_lock; no concurrent stop_sessions() can | |
| 550 | + * touch conn->stop_called, so writing it under the read lock is | |
| 551 | + * safe. | |
| 552 | + */ | |
| 547 | 553 | again: |
| 554 | + target = NULL; | |
| 555 | + any = false; | |
| 548 | 556 | down_read(&conn_list_lock); |
| 549 | 557 | hash_for_each(conn_list, bkt, conn, hlist) { |
| 550 | − t = conn->transport; | |
| 551 | − ksmbd_conn_set_exiting(conn); | |
| 552 | − if (t->ops->shutdown) { | |
| 553 | − up_read(&conn_list_lock); | |
| 558 | + any = true; | |
| 559 | + if (conn->stop_called) | |
| 560 | + continue; | |
| 561 | + atomic_inc(&conn->refcnt); | |
| 562 | + conn->stop_called = true; | |
| 563 | + /* | |
| 564 | + * Mark the connection EXITING while still holding the | |
| 565 | + * read lock so the selection and the status transition | |
| 566 | + * happen together. Do not regress a connection that has | |
| 567 | + * already advanced to RELEASING on its own (e.g. the | |
| 568 | + * handler exited its receive loop for an unrelated | |
| 569 | + * reason). | |
| 570 | + */ | |
| 571 | + if (READ_ONCE(conn->status) != KSMBD_SESS_RELEASING) | |
| 572 | + ksmbd_conn_set_exiting(conn); | |
| 573 | + target = conn; | |
| 574 | + break; | |
| 575 | + } | |
| 576 | + up_read(&conn_list_lock); | |
| 577 | + | |
| 578 | + if (target) { | |
| 579 | + t = target->transport; | |
| 580 | + if (t->ops->shutdown) | |
| 554 | 581 | t->ops->shutdown(t); |
| 555 | − down_read(&conn_list_lock); | |
| 582 | + if (atomic_dec_and_test(&target->refcnt)) { | |
| 583 | + ida_destroy(&target->async_ida); | |
| 584 | + t->ops->free_transport(t); | |
| 585 | + kfree(target); | |
| 556 | 586 | } |
| 587 | + goto again; | |
| 557 | 588 | } |
| 558 | − up_read(&conn_list_lock); | |
| 559 | 589 | |
| 560 | − if (!hash_empty(conn_list)) { | |
| 590 | + if (any) { | |
| 561 | 591 | msleep(100); |
| 562 | 592 | goto again; |
| 563 | 593 | } |
| @@ -49,6 +49,7 @@ struct ksmbd_conn { · 48 unmodified lines | ||
| 49 | 49 | struct mutex srv_mutex; |
| 50 | 50 | int status; |
| 51 | 51 | unsigned int cli_cap; |
| 52 | + bool stop_called; | |
| 52 | 53 | union { |
| 53 | 54 | __be32 inet_addr; |
| 54 | 55 | #if IS_ENABLED(CONFIG_IPV6) |
| @@ -3946,7 +3946,13 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, · 3945 unmodified lines | ||
| 3946 | 3946 | goto free_conv_name; |
| 3947 | 3947 | } |
| 3948 | 3948 | |
| 3949 | − struct_sz = readdir_info_level_struct_sz(info_level) + conv_len; | |
| 3949 | + struct_sz = readdir_info_level_struct_sz(info_level); | |
| 3950 | + if (struct_sz == -EOPNOTSUPP) { | |
| 3951 | + rc = -EINVAL; | |
| 3952 | + goto free_conv_name; | |
| 3953 | + } | |
| 3954 | + | |
| 3955 | + struct_sz += conv_len; | |
| 3950 | 3956 | next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT); |
| 3951 | 3957 | d_info->last_entry_off_align = next_entry_offset - struct_sz; |
| 3952 | 3958 | |
| @@ -230,8 +230,12 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, · 229 unmodified lines | ||
| 230 | 230 | } |
| 231 | 231 | |
| 232 | 232 | /* Verify the descriptor CRC */ |
| 233 | − if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize || | |
| 234 | − le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, | |
| 233 | + if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize) { | |
| 234 | + udf_err(sb, "block %u: CRC length %u exceeds block size\n", | |
| 235 | + block, le16_to_cpu(tag_p->descCRCLength)); | |
| 236 | + goto error_out; | |
| 237 | + } | |
| 238 | + if (le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, | |
| 235 | 239 | bh->b_data + sizeof(struct tag), |
| 236 | 240 | le16_to_cpu(tag_p->descCRCLength))) |
| 237 | 241 | return bh; |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/property.h> |
| 18 | 18 | #include <linux/types.h> |
| 19 | 19 | |
| 20 | +struct notifier_block; | |
| 21 | + | |
| 20 | 22 | struct acpi_handle_list { |
| 21 | 23 | u32 count; |
| 22 | 24 | acpi_handle *handles; |
| @@ -1386,6 +1386,12 @@ enum acpi_einj_command_status { · 1385 unmodified lines | ||
| 1386 | 1386 | #define ACPI_EINJ_CXL_MEM_FATAL (1<<17) |
| 1387 | 1387 | #define ACPI_EINJ_VENDOR_DEFINED (1<<31) |
| 1388 | 1388 | |
| 1389 | +/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */ | |
| 1390 | + | |
| 1391 | +#define ACPI_EINJV2_PROCESSOR (1) | |
| 1392 | +#define ACPI_EINJV2_MEMORY (1<<1) | |
| 1393 | +#define ACPI_EINJV2_PCIE (1<<2) | |
| 1394 | + | |
| 1389 | 1395 | /******************************************************************************* |
| 1390 | 1396 | * |
| 1391 | 1397 | * ERST - Error Record Serialization Table (ACPI 4.0) |
| @@ -273,6 +273,12 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); · 272 unmodified lines | ||
| 273 | 273 | int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); |
| 274 | 274 | bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper, |
| 275 | 275 | const struct drm_gem_object *obj); |
| 276 | +#else | |
| 277 | +static inline bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper, | |
| 278 | + const struct drm_gem_object *obj) | |
| 279 | +{ | |
| 280 | + return false; | |
| 281 | +} | |
| 276 | 282 | #endif |
| 277 | 283 | |
| 278 | 284 | #endif |
| @@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, · 107 unmodified lines | ||
| 108 | 108 | extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, |
| 109 | 109 | unsigned int clearing); |
| 110 | 110 | |
| 111 | +extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); | |
| 111 | 112 | extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); |
| 112 | 113 | extern void unregister_cdrom(struct cdrom_device_info *cdi); |
| 113 | 114 | |
| @@ -322,13 +322,13 @@ struct dma_buf { · 321 unmodified lines | ||
| 322 | 322 | * @vmapping_counter: |
| 323 | 323 | * |
| 324 | 324 | * Used internally to refcnt the vmaps returned by dma_buf_vmap(). |
| 325 | − * Protected by @lock. | |
| 325 | + * Protected by @resv. | |
| 326 | 326 | */ |
| 327 | 327 | unsigned vmapping_counter; |
| 328 | 328 | |
| 329 | 329 | /** |
| 330 | 330 | * @vmap_ptr: |
| 331 | − * The current vmap ptr if @vmapping_counter > 0. Protected by @lock. | |
| 331 | + * The current vmap ptr if @vmapping_counter > 0. Protected by @resv. | |
| 332 | 332 | */ |
| 333 | 333 | struct iosys_map vmap_ptr; |
| 334 | 334 | |
| @@ -286,6 +286,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin, · 285 unmodified lines | ||
| 286 | 286 | |
| 287 | 287 | int dpll_device_change_ntf(struct dpll_device *dpll); |
| 288 | 288 | |
| 289 | +int __dpll_pin_change_ntf(struct dpll_pin *pin); | |
| 289 | 290 | int dpll_pin_change_ntf(struct dpll_pin *pin); |
| 290 | 291 | |
| 291 | 292 | int register_dpll_notifier(struct notifier_block *nb); |
| @@ -915,6 +915,7 @@ extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, · 914 unmodified lines | ||
| 915 | 915 | unsigned int obj_type); |
| 916 | 916 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); |
| 917 | 917 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); |
| 918 | +struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark); | |
| 918 | 919 | extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); |
| 919 | 920 | extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); |
| 920 | 921 | |
| @@ -45,6 +45,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg); · 44 unmodified lines | ||
| 45 | 45 | int mbox_flush(struct mbox_chan *chan, unsigned long timeout); |
| 46 | 46 | void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */ |
| 47 | 47 | bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */ |
| 48 | +unsigned int mbox_chan_tx_slots_available(struct mbox_chan *chan); /* atomic */ | |
| 48 | 49 | void mbox_free_channel(struct mbox_chan *chan); /* may sleep */ |
| 49 | 50 | |
| 50 | 51 | #endif /* __MAILBOX_CLIENT_H */ |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | #ifndef __MAILBOX_CONTROLLER_H |
| 4 | 4 | #define __MAILBOX_CONTROLLER_H |
| 5 | 5 | |
| 6 | +#include <linux/bits.h> | |
| 6 | 7 | #include <linux/completion.h> |
| 7 | 8 | #include <linux/device.h> |
| 8 | 9 | #include <linux/hrtimer.h> |
| @@ -11,6 +12,13 @@ · 2 unmodified lines | ||
| 11 | 12 | |
| 12 | 13 | struct mbox_chan; |
| 13 | 14 | |
| 15 | +/* Sentinel value distinguishing "no active request" from "NULL message data" */ | |
| 16 | +#define MBOX_NO_MSG ((void *)-1) | |
| 17 | + | |
| 18 | +#define MBOX_TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ | |
| 19 | +#define MBOX_TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ | |
| 20 | +#define MBOX_TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ | |
| 21 | + | |
| 14 | 22 | /** |
| 15 | 23 | * struct mbox_chan_ops - methods to control mailbox channels |
| 16 | 24 | * @send_data: The API asks the MBOX controller driver, in atomic |
| @@ -54,10 +62,10 @@ struct mbox_chan_ops { · 37 unmodified lines | ||
| 54 | 62 | |
| 55 | 63 | /** |
| 56 | 64 | * struct mbox_controller - Controller of a class of communication channels |
| 57 | − * @dev: Device backing this controller | |
| 58 | − * @ops: Operators that work on each communication chan | |
| 59 | − * @chans: Array of channels | |
| 60 | − * @num_chans: Number of channels in the 'chans' array. | |
| 65 | + * @dev: Device backing this controller. Required. | |
| 66 | + * @ops: Operators that work on each communication chan. Required. | |
| 67 | + * @chans: Array of channels. Required. | |
| 68 | + * @num_chans: Number of channels in the 'chans' array. Required. | |
| 61 | 69 | * @txdone_irq: Indicates if the controller can report to API when |
| 62 | 70 | * the last transmitted data was read by the remote. |
| 63 | 71 | * Eg, if it has some TX ACK irq. |
| @@ -70,6 +78,7 @@ struct mbox_chan_ops { · 6 unmodified lines | ||
| 70 | 78 | * @of_xlate: Controller driver specific mapping of channel via DT |
| 71 | 79 | * @poll_hrt: API private. hrtimer used to poll for TXDONE on all |
| 72 | 80 | * channels. |
| 81 | + * @poll_hrt_lock: API private. Lock protecting access to poll_hrt. | |
| 73 | 82 | * @node: API private. To hook into list of controllers. |
| 74 | 83 | */ |
| 75 | 84 | struct mbox_controller { |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | /* |
| 5 | 5 | * Maple Tree - An RCU-safe adaptive tree for storing ranges |
| 6 | 6 | * Copyright (c) 2018-2022 Oracle |
| 7 | − * Authors: Liam R. Howlett <Liam.Howlett@Oracle.com> | |
| 7 | + * Authors: Liam R. Howlett <liam@infradead.org> | |
| 8 | 8 | * Matthew Wilcox <willy@infradead.org> |
| 9 | 9 | */ |
| 10 | 10 | |
| @@ -4391,7 +4391,7 @@ static inline void mmap_action_map_kernel_pages_full(struct vm_area_desc *desc, · 4390 unmodified lines | ||
| 4391 | 4391 | |
| 4392 | 4392 | int mmap_action_prepare(struct vm_area_desc *desc); |
| 4393 | 4393 | int mmap_action_complete(struct vm_area_struct *vma, |
| 4394 | − struct mmap_action *action); | |
| 4394 | + struct mmap_action *action, bool is_compat); | |
| 4395 | 4395 | |
| 4396 | 4396 | /* Look up the first VMA which exactly match the interval vm_start ... vm_end */ |
| 4397 | 4397 | static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm, |
| @@ -226,6 +226,7 @@ struct mr_table_ops { · 225 unmodified lines | ||
| 226 | 226 | |
| 227 | 227 | /** |
| 228 | 228 | * struct mr_table - a multicast routing table |
| 229 | + * @work: used for table destruction | |
| 229 | 230 | * @list: entry within a list of multicast routing tables |
| 230 | 231 | * @net: net where this table belongs |
| 231 | 232 | * @ops: protocol specific operations |
| @@ -243,6 +244,7 @@ struct mr_table_ops { · 11 unmodified lines | ||
| 243 | 244 | * @mroute_reg_vif_num: PIM-device vif index |
| 244 | 245 | */ |
| 245 | 246 | struct mr_table { |
| 247 | + struct rcu_work work; | |
| 246 | 248 | struct list_head list; |
| 247 | 249 | possible_net_t net; |
| 248 | 250 | struct mr_table_ops ops; |
| @@ -274,6 +276,7 @@ void vif_device_init(struct vif_device *v, · 25 unmodified lines | ||
| 274 | 276 | unsigned short flags, |
| 275 | 277 | unsigned short get_iflink_mask); |
| 276 | 278 | |
| 279 | +void mr_table_free(struct mr_table *mrt); | |
| 277 | 280 | struct mr_table * |
| 278 | 281 | mr_table_alloc(struct net *net, u32 id, |
| 279 | 282 | struct mr_table_ops *ops, |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | #ifndef __MTD_NAND_QPIC_COMMON_H__ |
| 10 | 10 | #define __MTD_NAND_QPIC_COMMON_H__ |
| 11 | 11 | |
| 12 | +#include <linux/mtd/rawnand.h> | |
| 13 | + | |
| 12 | 14 | /* NANDc reg offsets */ |
| 13 | 15 | #define NAND_FLASH_CMD 0x00 |
| 14 | 16 | #define NAND_ADDR0 0x04 |
| @@ -394,7 +396,7 @@ struct qcom_nand_controller { · 379 unmodified lines | ||
| 394 | 396 | |
| 395 | 397 | const struct qcom_nandc_props *props; |
| 396 | 398 | |
| 397 | − struct nand_controller *controller; | |
| 399 | + struct nand_controller controller; | |
| 398 | 400 | struct qpic_spi_nand *qspi; |
| 399 | 401 | struct list_head host_list; |
| 400 | 402 | |
| @@ -290,6 +290,12 @@ · 289 unmodified lines | ||
| 290 | 290 | SPI_MEM_OP_NO_DUMMY, \ |
| 291 | 291 | SPI_MEM_OP_NO_DATA) |
| 292 | 292 | |
| 293 | +#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \ | |
| 294 | + SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \ | |
| 295 | + SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \ | |
| 296 | + SPI_MEM_OP_NO_DUMMY, \ | |
| 297 | + SPI_MEM_OP_NO_DATA) | |
| 298 | + | |
| 293 | 299 | #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ |
| 294 | 300 | SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ |
| 295 | 301 | SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ |
| @@ -483,6 +489,7 @@ struct spinand_ecc_info { · 187 unmodified lines | ||
| 483 | 489 | #define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) |
| 484 | 490 | #define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) |
| 485 | 491 | #define SPINAND_NO_RAW_ACCESS BIT(4) |
| 492 | +#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5) | |
| 486 | 493 | |
| 487 | 494 | /** |
| 488 | 495 | * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure |
| @@ -576,6 +583,7 @@ enum spinand_bus_interface { · 87 unmodified lines | ||
| 576 | 583 | * @op_variants.read_cache: variants of the read-cache operation |
| 577 | 584 | * @op_variants.write_cache: variants of the write-cache operation |
| 578 | 585 | * @op_variants.update_cache: variants of the update-cache operation |
| 586 | + * @op_variants.cont_read_cache: variants of the continuous read-cache operation | |
| 579 | 587 | * @vendor_ops: vendor specific operations |
| 580 | 588 | * @select_target: function used to select a target/die. Required only for |
| 581 | 589 | * multi-die chips |
| @@ -585,6 +593,7 @@ enum spinand_bus_interface { · 3 unmodified lines | ||
| 585 | 593 | * @user_otp: SPI NAND user OTP info. |
| 586 | 594 | * @read_retries: the number of read retry modes supported |
| 587 | 595 | * @set_read_retry: enable/disable read retry for data recovery |
| 596 | + * @set_randomizer: enable/disable randomizer support | |
| 588 | 597 | * |
| 589 | 598 | * Each SPI NAND manufacturer driver should have a spinand_info table |
| 590 | 599 | * describing all the chips supported by the driver. |
| @@ -600,6 +609,7 @@ struct spinand_info { · 9 unmodified lines | ||
| 600 | 609 | const struct spinand_op_variants *read_cache; |
| 601 | 610 | const struct spinand_op_variants *write_cache; |
| 602 | 611 | const struct spinand_op_variants *update_cache; |
| 612 | + const struct spinand_op_variants *cont_read_cache; | |
| 603 | 613 | } op_variants; |
| 604 | 614 | const struct spinand_op_variants *vendor_ops; |
| 605 | 615 | int (*select_target)(struct spinand_device *spinand, |
| @@ -613,6 +623,8 @@ struct spinand_info { · 7 unmodified lines | ||
| 613 | 623 | unsigned int read_retries; |
| 614 | 624 | int (*set_read_retry)(struct spinand_device *spinand, |
| 615 | 625 | unsigned int read_retry); |
| 626 | + int (*set_randomizer)(struct spinand_device *spinand, | |
| 627 | + bool enable); | |
| 616 | 628 | }; |
| 617 | 629 | |
| 618 | 630 | #define SPINAND_ID(__method, ...) \ |
| @@ -629,6 +641,14 @@ struct spinand_info { · 10 unmodified lines | ||
| 629 | 641 | .update_cache = __update, \ |
| 630 | 642 | } |
| 631 | 643 | |
| 644 | +#define SPINAND_INFO_OP_VARIANTS_WITH_CONT(__read, __write, __update, __cont_read) \ | |
| 645 | + { \ | |
| 646 | + .read_cache = __read, \ | |
| 647 | + .write_cache = __write, \ | |
| 648 | + .update_cache = __update, \ | |
| 649 | + .cont_read_cache = __cont_read, \ | |
| 650 | + } | |
| 651 | + | |
| 632 | 652 | #define SPINAND_INFO_VENDOR_OPS(__ops) \ |
| 633 | 653 | .vendor_ops = __ops |
| 634 | 654 | |
| @@ -669,6 +689,9 @@ struct spinand_info { · 34 unmodified lines | ||
| 669 | 689 | .read_retries = __read_retries, \ |
| 670 | 690 | .set_read_retry = __set_read_retry |
| 671 | 691 | |
| 692 | +#define SPINAND_RANDOMIZER(__set_randomizer) \ | |
| 693 | + .set_randomizer = __set_randomizer | |
| 694 | + | |
| 672 | 695 | #define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \ |
| 673 | 696 | __flags, ...) \ |
| 674 | 697 | { \ |
| @@ -684,8 +707,6 @@ struct spinand_info { · 9 unmodified lines | ||
| 684 | 707 | struct spinand_dirmap { |
| 685 | 708 | struct spi_mem_dirmap_desc *wdesc; |
| 686 | 709 | struct spi_mem_dirmap_desc *rdesc; |
| 687 | − struct spi_mem_dirmap_desc *wdesc_ecc; | |
| 688 | − struct spi_mem_dirmap_desc *rdesc_ecc; | |
| 689 | 710 | }; |
| 690 | 711 | |
| 691 | 712 | /** |
| @@ -702,6 +723,7 @@ struct spinand_dirmap { · 10 unmodified lines | ||
| 702 | 723 | * @read_cache: read cache op template |
| 703 | 724 | * @write_cache: write cache op template |
| 704 | 725 | * @update_cache: update cache op template |
| 726 | + * @cont_read_cache: continuous read cache op template (optional) | |
| 705 | 727 | */ |
| 706 | 728 | struct spinand_mem_ops { |
| 707 | 729 | struct spi_mem_op reset; |
| @@ -716,6 +738,7 @@ struct spinand_mem_ops { · 8 unmodified lines | ||
| 716 | 738 | const struct spi_mem_op *read_cache; |
| 717 | 739 | const struct spi_mem_op *write_cache; |
| 718 | 740 | const struct spi_mem_op *update_cache; |
| 741 | + const struct spi_mem_op *cont_read_cache; | |
| 719 | 742 | }; |
| 720 | 743 | |
| 721 | 744 | /** |
| @@ -754,6 +777,7 @@ struct spinand_mem_ops { · 32 unmodified lines | ||
| 754 | 777 | * @user_otp: SPI NAND user OTP info. |
| 755 | 778 | * @read_retries: the number of read retry modes supported |
| 756 | 779 | * @set_read_retry: Enable/disable the read retry feature |
| 780 | + * @set_randomizer: Enable/disable the randomizer feature | |
| 757 | 781 | */ |
| 758 | 782 | struct spinand_device { |
| 759 | 783 | struct nand_device base; |
| @@ -787,6 +811,8 @@ struct spinand_device { · 27 unmodified lines | ||
| 787 | 811 | bool cont_read_possible; |
| 788 | 812 | int (*set_cont_read)(struct spinand_device *spinand, |
| 789 | 813 | bool enable); |
| 814 | + int (*set_randomizer)(struct spinand_device *spinand, | |
| 815 | + bool enable); | |
| 790 | 816 | |
| 791 | 817 | const struct spinand_fact_otp *fact_otp; |
| 792 | 818 | const struct spinand_user_otp *user_otp; |
| @@ -862,6 +888,8 @@ static inline void spinand_set_of_node(struct spinand_device *spinand, · 69 unmodified lines | ||
| 862 | 888 | nanddev_set_of_node(&spinand->base, np); |
| 863 | 889 | } |
| 864 | 890 | |
| 891 | +bool spinand_op_is_odtr(const struct spi_mem_op *op); | |
| 892 | + | |
| 865 | 893 | int spinand_match_and_init(struct spinand_device *spinand, |
| 866 | 894 | const struct spinand_info *table, |
| 867 | 895 | unsigned int table_size, |
| @@ -49,9 +49,9 @@ int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len, · 48 unmodified lines | ||
| 49 | 49 | int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid); |
| 50 | 50 | int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm, |
| 51 | 51 | u8 *host_key, size_t host_key_len); |
| 52 | −int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm, | |
| 53 | − const u8 *ctrl_key, size_t ctrl_key_len, | |
| 54 | − u8 *sess_key, size_t sess_key_len); | |
| 52 | +int nvme_auth_gen_session_key(struct crypto_kpp *dh_tfm, | |
| 53 | + const u8 *public_key, size_t public_key_len, | |
| 54 | + u8 *sess_key, size_t sess_key_len, u8 hash_id); | |
| 55 | 55 | int nvme_auth_generate_psk(u8 hmac_id, const u8 *skey, size_t skey_len, |
| 56 | 56 | const u8 *c1, const u8 *c2, size_t hash_len, |
| 57 | 57 | u8 **ret_psk, size_t *ret_len); |
| @@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old, · 260 unmodified lines | ||
| 261 | 261 | old->prev = LIST_POISON2; |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | +static inline void __list_splice_rcu(struct list_head *list, | |
| 265 | + struct list_head *prev, | |
| 266 | + struct list_head *next) | |
| 267 | +{ | |
| 268 | + struct list_head *first = list->next; | |
| 269 | + struct list_head *last = list->prev; | |
| 270 | + | |
| 271 | + last->next = next; | |
| 272 | + first->prev = prev; | |
| 273 | + next->prev = last; | |
| 274 | + rcu_assign_pointer(list_next_rcu(prev), first); | |
| 275 | +} | |
| 276 | + | |
| 277 | +/** | |
| 278 | + * list_splice_rcu - splice a non-RCU list into an RCU-protected list, | |
| 279 | + * designed for stacks. | |
| 280 | + * @list: the non RCU-protected list to splice | |
| 281 | + * @head: the place in the existing RCU-protected list to splice | |
| 282 | + * | |
| 283 | + * The list pointed to by @head can be RCU-read traversed concurrently with | |
| 284 | + * this function. | |
| 285 | + */ | |
| 286 | +static inline void list_splice_rcu(struct list_head *list, | |
| 287 | + struct list_head *head) | |
| 288 | +{ | |
| 289 | + if (!list_empty(list)) | |
| 290 | + __list_splice_rcu(list, head, head->next); | |
| 291 | +} | |
| 292 | + | |
| 264 | 293 | /** |
| 265 | 294 | * __list_splice_init_rcu - join an RCU-protected list into an existing list. |
| 266 | 295 | * @list: the RCU-protected list to splice |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/alloc_tag.h> |
| 13 | 13 | #include <linux/atomic.h> |
| 14 | 14 | #include <linux/compiler.h> |
| 15 | +#include <linux/irq_work_types.h> | |
| 15 | 16 | #include <linux/mutex.h> |
| 16 | 17 | #include <linux/workqueue_types.h> |
| 17 | 18 | |
| @@ -49,6 +50,7 @@ typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *arg, · 31 unmodified lines | ||
| 49 | 50 | * @head_offset: Offset of rhash_head in struct to be hashed |
| 50 | 51 | * @max_size: Maximum size while expanding |
| 51 | 52 | * @min_size: Minimum size while shrinking |
| 53 | + * @insecure_elasticity: Set to true to disable chain length checks | |
| 52 | 54 | * @automatic_shrinking: Enable automatic shrinking of tables |
| 53 | 55 | * @hashfn: Hash function (default: jhash2 if !(key_len % 4), or jhash) |
| 54 | 56 | * @obj_hashfn: Function to hash object |
| @@ -61,6 +63,7 @@ struct rhashtable_params { · 6 unmodified lines | ||
| 61 | 63 | u16 head_offset; |
| 62 | 64 | unsigned int max_size; |
| 63 | 65 | u16 min_size; |
| 66 | + bool insecure_elasticity; | |
| 64 | 67 | bool automatic_shrinking; |
| 65 | 68 | rht_hashfn_t hashfn; |
| 66 | 69 | rht_obj_hashfn_t obj_hashfn; |
| @@ -75,6 +78,7 @@ struct rhashtable_params { · 8 unmodified lines | ||
| 75 | 78 | * @p: Configuration parameters |
| 76 | 79 | * @rhlist: True if this is an rhltable |
| 77 | 80 | * @run_work: Deferred worker to expand/shrink asynchronously |
| 81 | + * @run_irq_work: Bounces the @run_work kick through hard IRQ context. | |
| 78 | 82 | * @mutex: Mutex to protect current/future table swapping |
| 79 | 83 | * @lock: Spin lock to protect walker list |
| 80 | 84 | * @nelems: Number of elements in table |
| @@ -86,6 +90,7 @@ struct rhashtable { · 5 unmodified lines | ||
| 86 | 90 | struct rhashtable_params p; |
| 87 | 91 | bool rhlist; |
| 88 | 92 | struct work_struct run_work; |
| 93 | + struct irq_work run_irq_work; | |
| 89 | 94 | struct mutex mutex; |
| 90 | 95 | spinlock_t lock; |
| 91 | 96 | atomic_t nelems; |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | #include <linux/err.h> |
| 22 | 22 | #include <linux/errno.h> |
| 23 | +#include <linux/irq_work.h> | |
| 23 | 24 | #include <linux/jhash.h> |
| 24 | 25 | #include <linux/list_nulls.h> |
| 25 | 26 | #include <linux/workqueue.h> |
| @@ -821,14 +822,15 @@ slow_path: · 795 unmodified lines | ||
| 821 | 822 | goto out; |
| 822 | 823 | } |
| 823 | 824 | |
| 824 | − if (elasticity <= 0) | |
| 825 | + if (elasticity <= 0 && !params.insecure_elasticity) | |
| 825 | 826 | goto slow_path; |
| 826 | 827 | |
| 827 | 828 | data = ERR_PTR(-E2BIG); |
| 828 | 829 | if (unlikely(rht_grow_above_max(ht, tbl))) |
| 829 | 830 | goto out_unlock; |
| 830 | 831 | |
| 831 | − if (unlikely(rht_grow_above_100(ht, tbl))) | |
| 832 | + if (unlikely(rht_grow_above_100(ht, tbl)) && | |
| 833 | + !params.insecure_elasticity) | |
| 832 | 834 | goto slow_path; |
| 833 | 835 | |
| 834 | 836 | /* Inserting at head of list makes unlocking free. */ |
| @@ -846,7 +848,7 @@ slow_path: · 11 unmodified lines | ||
| 846 | 848 | rht_assign_unlock(tbl, bkt, obj, flags); |
| 847 | 849 | |
| 848 | 850 | if (rht_grow_above_75(ht, tbl)) |
| 849 | − schedule_work(&ht->run_work); | |
| 851 | + irq_work_queue(&ht->run_irq_work); | |
| 850 | 852 | |
| 851 | 853 | data = NULL; |
| 852 | 854 | out: |
| @@ -227,6 +227,8 @@ struct spi_mem_op { · 226 unmodified lines | ||
| 227 | 227 | * struct spi_mem_dirmap_info - Direct mapping information |
| 228 | 228 | * @op_tmpl: operation template that should be used by the direct mapping when |
| 229 | 229 | * the memory device is accessed |
| 230 | + * @secondary_op_tmpl: secondary template, may be used as an alternative to the | |
| 231 | + * primary template (decided by the upper layer) | |
| 230 | 232 | * @offset: absolute offset this direct mapping is pointing to |
| 231 | 233 | * @length: length in byte of this direct mapping |
| 232 | 234 | * |
| @@ -237,7 +239,9 @@ struct spi_mem_op { · 4 unmodified lines | ||
| 237 | 239 | * direction is directly encoded in the ->op_tmpl.data.dir field. |
| 238 | 240 | */ |
| 239 | 241 | struct spi_mem_dirmap_info { |
| 240 | − struct spi_mem_op op_tmpl; | |
| 242 | + struct spi_mem_op *op_tmpl; | |
| 243 | + struct spi_mem_op primary_op_tmpl; | |
| 244 | + struct spi_mem_op secondary_op_tmpl; | |
| 241 | 245 | u64 offset; |
| 242 | 246 | u64 length; |
| 243 | 247 | }; |
| @@ -381,12 +385,18 @@ struct spi_controller_mem_ops { · 137 unmodified lines | ||
| 381 | 385 | * @swap16: Supports swapping bytes on a 16 bit boundary when configured in |
| 382 | 386 | * Octal DTR |
| 383 | 387 | * @per_op_freq: Supports per operation frequency switching |
| 388 | + * @no_cs_assertion: The controller may automatically deassert the CS if there | |
| 389 | + * is a pause in the transfer (eg. internal bus contention or | |
| 390 | + * DMA arbitration on an interconnect). Features such as NAND | |
| 391 | + * continuous reads shall not be leveraged. | |
| 384 | 392 | */ |
| 385 | 393 | struct spi_controller_mem_caps { |
| 386 | 394 | bool dtr; |
| 387 | 395 | bool ecc; |
| 388 | 396 | bool swap16; |
| 389 | 397 | bool per_op_freq; |
| 398 | + bool secondary_op_tmpl; | |
| 399 | + bool no_cs_assertion; | |
| 390 | 400 | }; |
| 391 | 401 | |
| 392 | 402 | #define spi_mem_controller_is_capable(ctlr, cap) \ |
| @@ -202,7 +202,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) · 201 unmodified lines | ||
| 202 | 202 | #define TP_CONDITION(args...) args |
| 203 | 203 | |
| 204 | 204 | /* |
| 205 | − * Individual subsystem my have a separate configuration to | |
| 205 | + * Individual subsystem may have a separate configuration to | |
| 206 | 206 | * enable their tracepoints. By default, this file will create |
| 207 | 207 | * the tracepoints if CONFIG_TRACEPOINTS is defined. If a subsystem |
| 208 | 208 | * wants to be able to disable its tracepoints from being created |
| @@ -243,7 +243,7 @@ typedef struct port { · 242 unmodified lines | ||
| 243 | 243 | churn_state_t sm_churn_actor_state; |
| 244 | 244 | churn_state_t sm_churn_partner_state; |
| 245 | 245 | struct slave *slave; /* pointer to the bond slave that this port belongs to */ |
| 246 | − struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ | |
| 246 | + struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */ | |
| 247 | 247 | struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ |
| 248 | 248 | u32 transaction_id; /* continuous number for identification of Marker PDU's; */ |
| 249 | 249 | struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ |
| @@ -1204,12 +1204,15 @@ struct nft_stats { · 1203 unmodified lines | ||
| 1204 | 1204 | struct u64_stats_sync syncp; |
| 1205 | 1205 | }; |
| 1206 | 1206 | |
| 1207 | +#define NFT_HOOK_REMOVE (1 << 0) | |
| 1208 | + | |
| 1207 | 1209 | struct nft_hook { |
| 1208 | 1210 | struct list_head list; |
| 1209 | 1211 | struct list_head ops_list; |
| 1210 | 1212 | struct rcu_head rcu; |
| 1211 | 1213 | char ifname[IFNAMSIZ]; |
| 1212 | 1214 | u8 ifnamelen; |
| 1215 | + u8 flags; | |
| 1213 | 1216 | }; |
| 1214 | 1217 | |
| 1215 | 1218 | struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook, |
| @@ -1664,6 +1667,16 @@ struct nft_trans { · 448 unmodified lines | ||
| 1664 | 1667 | u8 put_net:1; |
| 1665 | 1668 | }; |
| 1666 | 1669 | |
| 1670 | +/** | |
| 1671 | + * struct nft_trans_hook - nf_tables hook update in transaction | |
| 1672 | + * @list: used internally | |
| 1673 | + * @hook: struct nft_hook with the device hook | |
| 1674 | + */ | |
| 1675 | +struct nft_trans_hook { | |
| 1676 | + struct list_head list; | |
| 1677 | + struct nft_hook *hook; | |
| 1678 | +}; | |
| 1679 | + | |
| 1667 | 1680 | /** |
| 1668 | 1681 | * struct nft_trans_binding - nf_tables object with binding support in transaction |
| 1669 | 1682 | * @nft_trans: base structure, MUST be first member |
| @@ -127,6 +127,21 @@ static inline unsigned int net_iov_idx(const struct net_iov *niov) · 126 unmodified lines | ||
| 127 | 127 | return niov - net_iov_owner(niov)->niovs; |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | +/* Initialize a niov: stamp the owning area, the memory provider type, | |
| 131 | + * and the page_type "no type" sentinel expected by the page-type API | |
| 132 | + * (see PAGE_TYPE_OPS in <linux/page-flags.h>) so that | |
| 133 | + * page_pool_set_pp_info() can later call __SetPageNetpp() on a niov | |
| 134 | + * cast to struct page. | |
| 135 | + */ | |
| 136 | +static inline void net_iov_init(struct net_iov *niov, | |
| 137 | + struct net_iov_area *owner, | |
| 138 | + enum net_iov_type type) | |
| 139 | +{ | |
| 140 | + niov->owner = owner; | |
| 141 | + niov->type = type; | |
| 142 | + niov->page_type = UINT_MAX; | |
| 143 | +} | |
| 144 | + | |
| 130 | 145 | /* netmem */ |
| 131 | 146 | |
| 132 | 147 | /** |
| @@ -905,7 +905,8 @@ struct io_uring_buf_reg { · 904 unmodified lines | ||
| 905 | 905 | __u32 ring_entries; |
| 906 | 906 | __u16 bgid; |
| 907 | 907 | __u16 flags; |
| 908 | − __u64 resv[3]; | |
| 908 | + __u32 min_left; | |
| 909 | + __u32 resv[5]; | |
| 909 | 910 | }; |
| 910 | 911 | |
| 911 | 912 | /* argument for IORING_REGISTER_PBUF_STATUS */ |
| @@ -47,7 +47,7 @@ static bool io_kbuf_inc_commit(struct io_buffer_list *bl, int len) · 46 unmodified lines | ||
| 47 | 47 | this_len = min_t(u32, len, buf_len); |
| 48 | 48 | buf_len -= this_len; |
| 49 | 49 | /* Stop looping for invalid buffer length of 0 */ |
| 50 | − if (buf_len || !this_len) { | |
| 50 | + if (buf_len > bl->min_left_sub_one || !this_len) { | |
| 51 | 51 | WRITE_ONCE(buf->addr, READ_ONCE(buf->addr) + this_len); |
| 52 | 52 | WRITE_ONCE(buf->len, buf_len); |
| 53 | 53 | return false; |
| @@ -637,6 +637,10 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) · 583 unmodified lines | ||
| 637 | 637 | if (reg.ring_entries >= 65536) |
| 638 | 638 | return -EINVAL; |
| 639 | 639 | |
| 640 | + /* minimum left byte count is a property of incremental buffers */ | |
| 641 | + if (!(reg.flags & IOU_PBUF_RING_INC) && reg.min_left) | |
| 642 | + return -EINVAL; | |
| 643 | + | |
| 640 | 644 | bl = io_buffer_get_list(ctx, reg.bgid); |
| 641 | 645 | if (bl) { |
| 642 | 646 | /* if mapped buffer ring OR classic exists, don't allow */ |
| @@ -680,10 +684,11 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) · 37 unmodified lines | ||
| 680 | 684 | } |
| 681 | 685 | #endif |
| 682 | 686 | |
| 683 | − bl->nr_entries = reg.ring_entries; | |
| 684 | 687 | bl->mask = reg.ring_entries - 1; |
| 685 | 688 | bl->flags |= IOBL_BUF_RING; |
| 686 | 689 | bl->buf_ring = br; |
| 690 | + if (reg.min_left) | |
| 691 | + bl->min_left_sub_one = reg.min_left - 1; | |
| 687 | 692 | if (reg.flags & IOU_PBUF_RING_INC) |
| 688 | 693 | bl->flags |= IOBL_INC; |
| 689 | 694 | ret = io_buffer_add_list(ctx, bl, reg.bgid); |
| @@ -27,12 +27,18 @@ struct io_buffer_list { · 26 unmodified lines | ||
| 27 | 27 | __u16 bgid; |
| 28 | 28 | |
| 29 | 29 | /* below is for ring provided buffers */ |
| 30 | − __u16 nr_entries; | |
| 31 | 30 | __u16 head; |
| 32 | 31 | __u16 mask; |
| 33 | 32 | |
| 34 | 33 | __u16 flags; |
| 35 | 34 | |
| 35 | + /* | |
| 36 | + * minimum required amount to be left to reuse an incrementally | |
| 37 | + * consumed buffer. If less than this is left at consumption time, | |
| 38 | + * buffer is done and head is incremented to the next buffer. | |
| 39 | + */ | |
| 40 | + __u32 min_left_sub_one; | |
| 41 | + | |
| 36 | 42 | struct io_mapped_region region; |
| 37 | 43 | }; |
| 38 | 44 | |
| @@ -276,6 +276,8 @@ static int io_napi_register_napi(struct io_ring_ctx *ctx, · 275 unmodified lines | ||
| 276 | 276 | /* clean the napi list for new settings */ |
| 277 | 277 | io_napi_free(ctx); |
| 278 | 278 | WRITE_ONCE(ctx->napi_track_mode, napi->op_param); |
| 279 | + /* cap NAPI at 10 msec of spin time */ | |
| 280 | + napi->busy_poll_to = min(10000, napi->busy_poll_to); | |
| 279 | 281 | WRITE_ONCE(ctx->napi_busy_poll_dt, napi->busy_poll_to * NSEC_PER_USEC); |
| 280 | 282 | WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll); |
| 281 | 283 | return 0; |
| @@ -273,8 +273,18 @@ void io_req_task_work_add_remote(struct io_kiocb *req, unsigned flags) · 272 unmodified lines | ||
| 273 | 273 | |
| 274 | 274 | void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx) |
| 275 | 275 | { |
| 276 | − struct llist_node *node = llist_del_all(&ctx->work_llist); | |
| 276 | + struct llist_node *node; | |
| 277 | 277 | |
| 278 | + /* | |
| 279 | + * Running the work items may utilize ->retry_llist as a means | |
| 280 | + * for capping the number of task_work entries run at the same | |
| 281 | + * time. But that list can potentially race with moving the work | |
| 282 | + * from here, if the task is exiting. As any normal task_work | |
| 283 | + * running holds ->uring_lock already, just guard this slow path | |
| 284 | + * with ->uring_lock to avoid racing on ->retry_llist. | |
| 285 | + */ | |
| 286 | + guard(mutex)(&ctx->uring_lock); | |
| 287 | + node = llist_del_all(&ctx->work_llist); | |
| 278 | 288 | __io_fallback_tw(node, false); |
| 279 | 289 | node = llist_del_all(&ctx->retry_llist); |
| 280 | 290 | __io_fallback_tw(node, false); |
| @@ -495,10 +495,9 @@ static int io_zcrx_create_area(struct io_zcrx_ifq *ifq, · 494 unmodified lines | ||
| 495 | 495 | for (i = 0; i < nr_iovs; i++) { |
| 496 | 496 | struct net_iov *niov = &area->nia.niovs[i]; |
| 497 | 497 | |
| 498 | − niov->owner = &area->nia; | |
| 498 | + net_iov_init(niov, &area->nia, NET_IOV_IOURING); | |
| 499 | 499 | area->freelist[i] = i; |
| 500 | 500 | atomic_set(&area->user_refs[i], 0); |
| 501 | − niov->type = NET_IOV_IOURING; | |
| 502 | 501 | } |
| 503 | 502 | |
| 504 | 503 | if (ifq->dev) { |
| @@ -3934,33 +3934,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) · 3933 unmodified lines | ||
| 3934 | 3934 | static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, |
| 3935 | 3935 | size_t nbytes, enum psi_res res) |
| 3936 | 3936 | { |
| 3937 | − struct cgroup_file_ctx *ctx = of->priv; | |
| 3937 | + struct cgroup_file_ctx *ctx; | |
| 3938 | 3938 | struct psi_trigger *new; |
| 3939 | 3939 | struct cgroup *cgrp; |
| 3940 | 3940 | struct psi_group *psi; |
| 3941 | + ssize_t ret = 0; | |
| 3941 | 3942 | |
| 3942 | 3943 | cgrp = cgroup_kn_lock_live(of->kn, false); |
| 3943 | 3944 | if (!cgrp) |
| 3944 | 3945 | return -ENODEV; |
| 3945 | 3946 | |
| 3946 | − cgroup_get(cgrp); | |
| 3947 | − cgroup_kn_unlock(of->kn); | |
| 3947 | + ctx = of->priv; | |
| 3948 | + if (!ctx) { | |
| 3949 | + ret = -ENODEV; | |
| 3950 | + goto out_unlock; | |
| 3951 | + } | |
| 3948 | 3952 | |
| 3949 | 3953 | /* Allow only one trigger per file descriptor */ |
| 3950 | 3954 | if (ctx->psi.trigger) { |
| 3951 | − cgroup_put(cgrp); | |
| 3952 | − return -EBUSY; | |
| 3955 | + ret = -EBUSY; | |
| 3956 | + goto out_unlock; | |
| 3953 | 3957 | } |
| 3954 | 3958 | |
| 3955 | 3959 | psi = cgroup_psi(cgrp); |
| 3956 | 3960 | new = psi_trigger_create(psi, buf, res, of->file, of); |
| 3957 | 3961 | if (IS_ERR(new)) { |
| 3958 | − cgroup_put(cgrp); | |
| 3959 | − return PTR_ERR(new); | |
| 3962 | + ret = PTR_ERR(new); | |
| 3963 | + goto out_unlock; | |
| 3960 | 3964 | } |
| 3961 | 3965 | |
| 3962 | 3966 | smp_store_release(&ctx->psi.trigger, new); |
| 3963 | − cgroup_put(cgrp); | |
| 3967 | + | |
| 3968 | +out_unlock: | |
| 3969 | + cgroup_kn_unlock(of->kn); | |
| 3970 | + if (ret) | |
| 3971 | + return ret; | |
| 3964 | 3972 | |
| 3965 | 3973 | return nbytes; |
| 3966 | 3974 | } |
| @@ -5716,16 +5724,6 @@ static void offline_css(struct cgroup_subsys_state *css) · 1749 unmodified lines | ||
| 5716 | 5724 | RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); |
| 5717 | 5725 | |
| 5718 | 5726 | wake_up_all(&css->cgroup->offline_waitq); |
| 5719 | − | |
| 5720 | − css->cgroup->nr_dying_subsys[ss->id]++; | |
| 5721 | − /* | |
| 5722 | − * Parent css and cgroup cannot be freed until after the freeing | |
| 5723 | − * of child css, see css_free_rwork_fn(). | |
| 5724 | − */ | |
| 5725 | − while ((css = css->parent)) { | |
| 5726 | − css->nr_descendants--; | |
| 5727 | − css->cgroup->nr_dying_subsys[ss->id]++; | |
| 5728 | − } | |
| 5729 | 5727 | } |
| 5730 | 5728 | |
| 5731 | 5729 | /** |
| @@ -6038,6 +6036,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref) · 306 unmodified lines | ||
| 6038 | 6036 | */ |
| 6039 | 6037 | static void kill_css(struct cgroup_subsys_state *css) |
| 6040 | 6038 | { |
| 6039 | + struct cgroup_subsys *ss = css->ss; | |
| 6040 | + | |
| 6041 | 6041 | lockdep_assert_held(&cgroup_mutex); |
| 6042 | 6042 | |
| 6043 | 6043 | if (css->flags & CSS_DYING) |
| @@ -6074,6 +6074,16 @@ static void kill_css(struct cgroup_subsys_state *css) · 30 unmodified lines | ||
| 6074 | 6074 | * css is confirmed to be seen as killed on all CPUs. |
| 6075 | 6075 | */ |
| 6076 | 6076 | percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); |
| 6077 | + | |
| 6078 | + css->cgroup->nr_dying_subsys[ss->id]++; | |
| 6079 | + /* | |
| 6080 | + * Parent css and cgroup cannot be freed until after the freeing | |
| 6081 | + * of child css, see css_free_rwork_fn(). | |
| 6082 | + */ | |
| 6083 | + while ((css = css->parent)) { | |
| 6084 | + css->nr_descendants--; | |
| 6085 | + css->cgroup->nr_dying_subsys[ss->id]++; | |
| 6086 | + } | |
| 6077 | 6087 | } |
| 6078 | 6088 | |
| 6079 | 6089 | /** |
| @@ -168,6 +168,11 @@ struct cpuset { · 167 unmodified lines | ||
| 168 | 168 | int nr_deadline_tasks; |
| 169 | 169 | int nr_migrate_dl_tasks; |
| 170 | 170 | u64 sum_migrate_dl_bw; |
| 171 | + /* | |
| 172 | + * CPU used for temporary DL bandwidth allocation during attach; | |
| 173 | + * -1 if no DL bandwidth was allocated in the current attach. | |
| 174 | + */ | |
| 175 | + int dl_bw_cpu; | |
| 171 | 176 | |
| 172 | 177 | /* Invalid partition error code, not lock protected */ |
| 173 | 178 | enum prs_errcode prs_err; |
| @@ -288,6 +288,7 @@ struct cpuset top_cpuset = { · 287 unmodified lines | ||
| 288 | 288 | .flags = BIT(CS_CPU_EXCLUSIVE) | |
| 289 | 289 | BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE), |
| 290 | 290 | .partition_root_state = PRS_ROOT, |
| 291 | + .dl_bw_cpu = -1, | |
| 291 | 292 | }; |
| 292 | 293 | |
| 293 | 294 | /** |
| @@ -579,6 +580,8 @@ static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs) · 285 unmodified lines | ||
| 579 | 580 | if (!trial) |
| 580 | 581 | return NULL; |
| 581 | 582 | |
| 583 | + trial->dl_bw_cpu = -1; | |
| 584 | + | |
| 582 | 585 | /* Setup cpumask pointer array */ |
| 583 | 586 | cpumask_var_t *pmask[4] = { |
| 584 | 587 | &trial->cpus_allowed, |
| @@ -2980,6 +2983,7 @@ static void reset_migrate_dl_data(struct cpuset *cs) · 2395 unmodified lines | ||
| 2980 | 2983 | { |
| 2981 | 2984 | cs->nr_migrate_dl_tasks = 0; |
| 2982 | 2985 | cs->sum_migrate_dl_bw = 0; |
| 2986 | + cs->dl_bw_cpu = -1; | |
| 2983 | 2987 | } |
| 2984 | 2988 | |
| 2985 | 2989 | /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */ |
| @@ -3056,6 +3060,8 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) · 70 unmodified lines | ||
| 3056 | 3060 | reset_migrate_dl_data(cs); |
| 3057 | 3061 | goto out_unlock; |
| 3058 | 3062 | } |
| 3063 | + | |
| 3064 | + cs->dl_bw_cpu = cpu; | |
| 3059 | 3065 | } |
| 3060 | 3066 | |
| 3061 | 3067 | out_success: |
| @@ -3080,12 +3086,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset) · 18 unmodified lines | ||
| 3080 | 3086 | mutex_lock(&cpuset_mutex); |
| 3081 | 3087 | dec_attach_in_progress_locked(cs); |
| 3082 | 3088 | |
| 3083 | − if (cs->nr_migrate_dl_tasks) { | |
| 3084 | − int cpu = cpumask_any(cs->effective_cpus); | |
| 3089 | + if (cs->dl_bw_cpu >= 0) | |
| 3090 | + dl_bw_free(cs->dl_bw_cpu, cs->sum_migrate_dl_bw); | |
| 3085 | 3091 | |
| 3086 | − dl_bw_free(cpu, cs->sum_migrate_dl_bw); | |
| 3092 | + if (cs->nr_migrate_dl_tasks) | |
| 3087 | 3093 | reset_migrate_dl_data(cs); |
| 3088 | − } | |
| 3089 | 3094 | |
| 3090 | 3095 | mutex_unlock(&cpuset_mutex); |
| 3091 | 3096 | } |
| @@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, · 282 unmodified lines | ||
| 283 | 283 | ret = PTR_ERR(rpool); |
| 284 | 284 | goto err; |
| 285 | 285 | } else { |
| 286 | − new = rpool->resources[index].usage + 1; | |
| 286 | + new = (s64)rpool->resources[index].usage + 1; | |
| 287 | 287 | if (new > rpool->resources[index].max) { |
| 288 | 288 | ret = -EAGAIN; |
| 289 | 289 | goto err; |
| @@ -1951,9 +1951,11 @@ static void rv_task_fork(struct task_struct *p) · 1950 unmodified lines | ||
| 1951 | 1951 | |
| 1952 | 1952 | static bool need_futex_hash_allocate_default(u64 clone_flags) |
| 1953 | 1953 | { |
| 1954 | − if ((clone_flags & (CLONE_THREAD | CLONE_VM)) != (CLONE_THREAD | CLONE_VM)) | |
| 1955 | − return false; | |
| 1956 | − return true; | |
| 1954 | + /* | |
| 1955 | + * Allocate a default futex hash for any sibling that will | |
| 1956 | + * share the parent's mm, except vfork. | |
| 1957 | + */ | |
| 1958 | + return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM; | |
| 1957 | 1959 | } |
| 1958 | 1960 | |
| 1959 | 1961 | /* |
| @@ -2380,10 +2382,6 @@ __latent_entropy struct task_struct *copy_process( · 420 unmodified lines | ||
| 2380 | 2382 | if (retval) |
| 2381 | 2383 | goto bad_fork_cancel_cgroup; |
| 2382 | 2384 | |
| 2383 | − /* | |
| 2384 | − * Allocate a default futex hash for the user process once the first | |
| 2385 | − * thread spawns. | |
| 2386 | − */ | |
| 2387 | 2385 | if (need_futex_hash_allocate_default(clone_flags)) { |
| 2388 | 2386 | retval = futex_hash_allocate_default(); |
| 2389 | 2387 | if (retval) |
| @@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, · 318 unmodified lines | ||
| 319 | 319 | return -EINVAL; |
| 320 | 320 | |
| 321 | 321 | /* Ensure that this does not race against an early wakeup */ |
| 322 | − if (!futex_requeue_pi_prepare(top_waiter, NULL)) | |
| 322 | + if (!futex_requeue_pi_prepare(top_waiter, NULL)) { | |
| 323 | + plist_del(&top_waiter->list, &hb1->chain); | |
| 324 | + futex_hb_waiters_dec(hb1); | |
| 323 | 325 | return -EAGAIN; |
| 326 | + } | |
| 324 | 327 | |
| 325 | 328 | /* |
| 326 | 329 | * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit |
| @@ -722,10 +725,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, · 395 unmodified lines | ||
| 722 | 725 | |
| 723 | 726 | /* |
| 724 | 727 | * We were woken prior to requeue by a timeout or a signal. |
| 725 | − * Unqueue the futex_q and determine which it was. | |
| 728 | + * Conditionally unqueue the futex_q and determine which it was. | |
| 726 | 729 | */ |
| 727 | − plist_del(&q->list, &hb->chain); | |
| 728 | − futex_hb_waiters_dec(hb); | |
| 730 | + if (!plist_node_empty(&q->list)) { | |
| 731 | + plist_del(&q->list, &hb->chain); | |
| 732 | + futex_hb_waiters_dec(hb); | |
| 733 | + } | |
| 729 | 734 | |
| 730 | 735 | /* Handle spurious wakeups gracefully */ |
| 731 | 736 | ret = -EWOULDBLOCK; |
| @@ -762,19 +762,24 @@ int kho_add_subtree(const char *name, void *blob, size_t size) · 761 unmodified lines | ||
| 762 | 762 | goto out_pack; |
| 763 | 763 | } |
| 764 | 764 | |
| 765 | − err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, | |
| 766 | − &phys, sizeof(phys)); | |
| 767 | − if (err < 0) | |
| 768 | − goto out_pack; | |
| 765 | + fdt_err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, | |
| 766 | + &phys, sizeof(phys)); | |
| 767 | + if (fdt_err < 0) | |
| 768 | + goto out_del_node; | |
| 769 | 769 | |
| 770 | − err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME, | |
| 771 | − &size_u64, sizeof(size_u64)); | |
| 772 | − if (err < 0) | |
| 773 | − goto out_pack; | |
| 770 | + fdt_err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME, | |
| 771 | + &size_u64, sizeof(size_u64)); | |
| 772 | + if (fdt_err < 0) | |
| 773 | + goto out_del_node; | |
| 774 | 774 | |
| 775 | 775 | WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob, |
| 776 | 776 | size, false)); |
| 777 | 777 | |
| 778 | + err = 0; | |
| 779 | + goto out_pack; | |
| 780 | + | |
| 781 | +out_del_node: | |
| 782 | + fdt_del_node(root_fdt, off); | |
| 778 | 783 | out_pack: |
| 779 | 784 | fdt_pack(root_fdt); |
| 780 | 785 | |
| @@ -514,11 +514,12 @@ int luo_session_deserialize(void) · 513 unmodified lines | ||
| 514 | 514 | { |
| 515 | 515 | struct luo_session_header *sh = &luo_session_global.incoming; |
| 516 | 516 | static bool is_deserialized; |
| 517 | − static int err; | |
| 517 | + static int saved_err; | |
| 518 | + int err; | |
| 518 | 519 | |
| 519 | 520 | /* If has been deserialized, always return the same error code */ |
| 520 | 521 | if (is_deserialized) |
| 521 | − return err; | |
| 522 | + return saved_err; | |
| 522 | 523 | |
| 523 | 524 | is_deserialized = true; |
| 524 | 525 | if (!sh->active) |
| @@ -547,7 +548,8 @@ int luo_session_deserialize(void) · 22 unmodified lines | ||
| 547 | 548 | pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n", |
| 548 | 549 | (int)sizeof(sh->ser[i].name), |
| 549 | 550 | sh->ser[i].name, session); |
| 550 | − return PTR_ERR(session); | |
| 551 | + err = PTR_ERR(session); | |
| 552 | + goto save_err; | |
| 551 | 553 | } |
| 552 | 554 | |
| 553 | 555 | err = luo_session_insert(sh, session); |
| @@ -555,7 +557,7 @@ int luo_session_deserialize(void) · 1 unmodified line | ||
| 555 | 557 | pr_warn("Failed to insert session [%s] %pe\n", |
| 556 | 558 | session->name, ERR_PTR(err)); |
| 557 | 559 | luo_session_free(session); |
| 558 | − return err; | |
| 560 | + goto save_err; | |
| 559 | 561 | } |
| 560 | 562 | |
| 561 | 563 | scoped_guard(mutex, &session->mutex) { |
| @@ -565,7 +567,7 @@ int luo_session_deserialize(void) · 3 unmodified lines | ||
| 565 | 567 | if (err) { |
| 566 | 568 | pr_warn("Failed to deserialize files for session [%s] %pe\n", |
| 567 | 569 | session->name, ERR_PTR(err)); |
| 568 | − return err; | |
| 570 | + goto save_err; | |
| 569 | 571 | } |
| 570 | 572 | } |
| 571 | 573 | |
| @@ -574,6 +576,9 @@ int luo_session_deserialize(void) · 2 unmodified lines | ||
| 574 | 576 | sh->ser = NULL; |
| 575 | 577 | |
| 576 | 578 | return 0; |
| 579 | +save_err: | |
| 580 | + saved_err = err; | |
| 581 | + return err; | |
| 577 | 582 | } |
| 578 | 583 | |
| 579 | 584 | int luo_session_serialize(void) |
| @@ -4458,6 +4458,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p) · 4457 unmodified lines | ||
| 4458 | 4458 | p->se.nr_migrations = 0; |
| 4459 | 4459 | p->se.vruntime = 0; |
| 4460 | 4460 | p->se.vlag = 0; |
| 4461 | + p->se.rel_deadline = 0; | |
| 4461 | 4462 | INIT_LIST_HEAD(&p->se.group_node); |
| 4462 | 4463 | |
| 4463 | 4464 | /* A delayed task cannot be in clone(). */ |
| @@ -32,6 +32,7 @@ static const struct rhashtable_params scx_sched_hash_params = { · 31 unmodified lines | ||
| 32 | 32 | .key_len = sizeof_field(struct scx_sched, ops.sub_cgroup_id), |
| 33 | 33 | .key_offset = offsetof(struct scx_sched, ops.sub_cgroup_id), |
| 34 | 34 | .head_offset = offsetof(struct scx_sched, hash_node), |
| 35 | + .insecure_elasticity = true, /* inserted under scx_sched_lock */ | |
| 35 | 36 | }; |
| 36 | 37 | |
| 37 | 38 | static struct rhashtable scx_sched_hash; |
| @@ -52,8 +53,6 @@ DEFINE_STATIC_KEY_FALSE(__scx_enabled); · 14 unmodified lines | ||
| 52 | 53 | DEFINE_STATIC_PERCPU_RWSEM(scx_fork_rwsem); |
| 53 | 54 | static atomic_t scx_enable_state_var = ATOMIC_INIT(SCX_DISABLED); |
| 54 | 55 | static DEFINE_RAW_SPINLOCK(scx_bypass_lock); |
| 55 | −static cpumask_var_t scx_bypass_lb_donee_cpumask; | |
| 56 | −static cpumask_var_t scx_bypass_lb_resched_cpumask; | |
| 57 | 56 | static bool scx_init_task_enabled; |
| 58 | 57 | static bool scx_switching_all; |
| 59 | 58 | DEFINE_STATIC_KEY_FALSE(__scx_switched_all); |
| @@ -469,24 +468,35 @@ static inline void update_locked_rq(struct rq *rq) · 409 unmodified lines | ||
| 469 | 468 | __this_cpu_write(scx_locked_rq_state, rq); |
| 470 | 469 | } |
| 471 | 470 | |
| 472 | −#define SCX_CALL_OP(sch, op, rq, args...) \ | |
| 471 | +/* | |
| 472 | + * SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not | |
| 473 | + * clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit. | |
| 474 | + */ | |
| 475 | +#define SCX_CALL_OP(sch, op, locked_rq, args...) \ | |
| 473 | 476 | do { \ |
| 474 | − if (rq) \ | |
| 475 | − update_locked_rq(rq); \ | |
| 477 | + struct rq *__prev_locked_rq; \ | |
| 478 | + \ | |
| 479 | + if (locked_rq) { \ | |
| 480 | + __prev_locked_rq = scx_locked_rq(); \ | |
| 481 | + update_locked_rq(locked_rq); \ | |
| 482 | + } \ | |
| 476 | 483 | (sch)->ops.op(args); \ |
| 477 | − if (rq) \ | |
| 478 | − update_locked_rq(NULL); \ | |
| 484 | + if (locked_rq) \ | |
| 485 | + update_locked_rq(__prev_locked_rq); \ | |
| 479 | 486 | } while (0) |
| 480 | 487 | |
| 481 | −#define SCX_CALL_OP_RET(sch, op, rq, args...) \ | |
| 488 | +#define SCX_CALL_OP_RET(sch, op, locked_rq, args...) \ | |
| 482 | 489 | ({ \ |
| 490 | + struct rq *__prev_locked_rq; \ | |
| 483 | 491 | __typeof__((sch)->ops.op(args)) __ret; \ |
| 484 | 492 | \ |
| 485 | − if (rq) \ | |
| 486 | − update_locked_rq(rq); \ | |
| 493 | + if (locked_rq) { \ | |
| 494 | + __prev_locked_rq = scx_locked_rq(); \ | |
| 495 | + update_locked_rq(locked_rq); \ | |
| 496 | + } \ | |
| 487 | 497 | __ret = (sch)->ops.op(args); \ |
| 488 | − if (rq) \ | |
| 489 | − update_locked_rq(NULL); \ | |
| 498 | + if (locked_rq) \ | |
| 499 | + update_locked_rq(__prev_locked_rq); \ | |
| 490 | 500 | __ret; \ |
| 491 | 501 | }) |
| 492 | 502 | |
| @@ -498,39 +508,39 @@ do { \ · 5 unmodified lines | ||
| 498 | 508 | * those subject tasks. |
| 499 | 509 | * |
| 500 | 510 | * Every SCX_CALL_OP_TASK*() call site invokes its op with @p's rq lock held - |
| 501 | − * either via the @rq argument here, or (for ops.select_cpu()) via @p's pi_lock | |
| 502 | − * held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu. So if | |
| 503 | − * kf_tasks[] is set, @p's scheduler-protected fields are stable. | |
| 511 | + * either via the @locked_rq argument here, or (for ops.select_cpu()) via @p's | |
| 512 | + * pi_lock held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu. | |
| 513 | + * So if kf_tasks[] is set, @p's scheduler-protected fields are stable. | |
| 504 | 514 | * |
| 505 | 515 | * kf_tasks[] can not stack, so task-based SCX ops must not nest. The |
| 506 | 516 | * WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants |
| 507 | 517 | * while a previous one is still in progress. |
| 508 | 518 | */ |
| 509 | −#define SCX_CALL_OP_TASK(sch, op, rq, task, args...) \ | |
| 519 | +#define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...) \ | |
| 510 | 520 | do { \ |
| 511 | 521 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ |
| 512 | 522 | current->scx.kf_tasks[0] = task; \ |
| 513 | − SCX_CALL_OP((sch), op, rq, task, ##args); \ | |
| 523 | + SCX_CALL_OP((sch), op, locked_rq, task, ##args); \ | |
| 514 | 524 | current->scx.kf_tasks[0] = NULL; \ |
| 515 | 525 | } while (0) |
| 516 | 526 | |
| 517 | −#define SCX_CALL_OP_TASK_RET(sch, op, rq, task, args...) \ | |
| 527 | +#define SCX_CALL_OP_TASK_RET(sch, op, locked_rq, task, args...) \ | |
| 518 | 528 | ({ \ |
| 519 | 529 | __typeof__((sch)->ops.op(task, ##args)) __ret; \ |
| 520 | 530 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ |
| 521 | 531 | current->scx.kf_tasks[0] = task; \ |
| 522 | − __ret = SCX_CALL_OP_RET((sch), op, rq, task, ##args); \ | |
| 532 | + __ret = SCX_CALL_OP_RET((sch), op, locked_rq, task, ##args); \ | |
| 523 | 533 | current->scx.kf_tasks[0] = NULL; \ |
| 524 | 534 | __ret; \ |
| 525 | 535 | }) |
| 526 | 536 | |
| 527 | −#define SCX_CALL_OP_2TASKS_RET(sch, op, rq, task0, task1, args...) \ | |
| 537 | +#define SCX_CALL_OP_2TASKS_RET(sch, op, locked_rq, task0, task1, args...) \ | |
| 528 | 538 | ({ \ |
| 529 | 539 | __typeof__((sch)->ops.op(task0, task1, ##args)) __ret; \ |
| 530 | 540 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ |
| 531 | 541 | current->scx.kf_tasks[0] = task0; \ |
| 532 | 542 | current->scx.kf_tasks[1] = task1; \ |
| 533 | − __ret = SCX_CALL_OP_RET((sch), op, rq, task0, task1, ##args); \ | |
| 543 | + __ret = SCX_CALL_OP_RET((sch), op, locked_rq, task0, task1, ##args); \ | |
| 534 | 544 | current->scx.kf_tasks[0] = NULL; \ |
| 535 | 545 | current->scx.kf_tasks[1] = NULL; \ |
| 536 | 546 | __ret; \ |
| @@ -1388,18 +1398,55 @@ static void call_task_dequeue(struct scx_sched *sch, struct rq *rq, · 851 unmodified lines | ||
| 1388 | 1398 | p->scx.flags &= ~SCX_TASK_IN_CUSTODY; |
| 1389 | 1399 | } |
| 1390 | 1400 | |
| 1391 | −static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p, | |
| 1392 | − u64 enq_flags) | |
| 1401 | +static void local_dsq_post_enq(struct scx_sched *sch, struct scx_dispatch_q *dsq, | |
| 1402 | + struct task_struct *p, u64 enq_flags) | |
| 1393 | 1403 | { |
| 1394 | 1404 | struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); |
| 1395 | − bool preempt = false; | |
| 1396 | 1405 | |
| 1397 | − call_task_dequeue(scx_root, rq, p, 0); | |
| 1406 | + call_task_dequeue(sch, rq, p, 0); | |
| 1407 | + | |
| 1408 | + /* | |
| 1409 | + * Note that @rq's lock may be dropped between this enqueue and @p | |
| 1410 | + * actually getting on CPU. This gives higher-class tasks (e.g. RT) | |
| 1411 | + * an opportunity to wake up on @rq and prevent @p from running. | |
| 1412 | + * Here are some concrete examples: | |
| 1413 | + * | |
| 1414 | + * Example 1: | |
| 1415 | + * | |
| 1416 | + * We dispatch two tasks from a single ops.dispatch(): | |
| 1417 | + * - First, a local task to this CPU's local DSQ; | |
| 1418 | + * - Second, a local/remote task to a remote CPU's local DSQ. | |
| 1419 | + * We must drop the local rq lock in order to finish the second | |
| 1420 | + * dispatch. In that time, an RT task can wake up on the local rq. | |
| 1421 | + * | |
| 1422 | + * Example 2: | |
| 1423 | + * | |
| 1424 | + * We dispatch a local/remote task to a remote CPU's local DSQ. | |
| 1425 | + * We must drop the remote rq lock before the dispatched task can run, | |
| 1426 | + * which gives an RT task an opportunity to wake up on the remote rq. | |
| 1427 | + * | |
| 1428 | + * Both examples work the same if we replace dispatching with moving | |
| 1429 | + * the tasks from a user-created DSQ. | |
| 1430 | + * | |
| 1431 | + * We must detect these wakeups so that we can re-enqueue IMMED tasks | |
| 1432 | + * from @rq's local DSQ. scx_wakeup_preempt() serves exactly this | |
| 1433 | + * purpose, but for it to be invoked, we must ensure that we bump | |
| 1434 | + * @rq->next_class to &ext_sched_class if it's currently idle. | |
| 1435 | + * | |
| 1436 | + * wakeup_preempt() does the bumping, and since we only invoke it if | |
| 1437 | + * @rq->next_class is below &ext_sched_class, it will also | |
| 1438 | + * resched_curr(rq). | |
| 1439 | + */ | |
| 1440 | + if (sched_class_above(p->sched_class, rq->next_class)) | |
| 1441 | + wakeup_preempt(rq, p, 0); | |
| 1398 | 1442 | |
| 1399 | 1443 | /* |
| 1400 | 1444 | * If @rq is in balance, the CPU is already vacant and looking for the |
| 1401 | 1445 | * next task to run. No need to preempt or trigger resched after moving |
| 1402 | 1446 | * @p into its local DSQ. |
| 1447 | + * Note that the wakeup_preempt() above may have already triggered | |
| 1448 | + * a resched if @rq->next_class was idle. It's harmless, since | |
| 1449 | + * need_resched is cleared immediately after task pick. | |
| 1403 | 1450 | */ |
| 1404 | 1451 | if (rq->scx.flags & SCX_RQ_IN_BALANCE) |
| 1405 | 1452 | return; |
| @@ -1407,11 +1454,8 @@ static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p · 1 unmodified line | ||
| 1407 | 1454 | if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && |
| 1408 | 1455 | rq->curr->sched_class == &ext_sched_class) { |
| 1409 | 1456 | rq->curr->scx.slice = 0; |
| 1410 | − preempt = true; | |
| 1411 | − } | |
| 1412 | − | |
| 1413 | − if (preempt || sched_class_above(&ext_sched_class, rq->curr->sched_class)) | |
| 1414 | 1457 | resched_curr(rq); |
| 1458 | + } | |
| 1415 | 1459 | } |
| 1416 | 1460 | |
| 1417 | 1461 | static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq, |
| @@ -1494,11 +1538,13 @@ static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq, · 76 unmodified lines | ||
| 1494 | 1538 | if (!(dsq->id & SCX_DSQ_FLAG_BUILTIN)) |
| 1495 | 1539 | rcu_assign_pointer(dsq->first_task, p); |
| 1496 | 1540 | } else { |
| 1497 | − bool was_empty; | |
| 1498 | − | |
| 1499 | − was_empty = list_empty(&dsq->list); | |
| 1541 | + /* | |
| 1542 | + * dsq->list can contain parked BPF iterator cursors, so | |
| 1543 | + * list_empty() here isn't a reliable proxy for "no real | |
| 1544 | + * task in the DSQ". Test dsq->first_task directly. | |
| 1545 | + */ | |
| 1500 | 1546 | list_add_tail(&p->scx.dsq_list.node, &dsq->list); |
| 1501 | − if (was_empty && !(dsq->id & SCX_DSQ_FLAG_BUILTIN)) | |
| 1547 | + if (!dsq->first_task && !(dsq->id & SCX_DSQ_FLAG_BUILTIN)) | |
| 1502 | 1548 | rcu_assign_pointer(dsq->first_task, p); |
| 1503 | 1549 | } |
| 1504 | 1550 | } |
| @@ -1518,7 +1564,7 @@ static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq, · 13 unmodified lines | ||
| 1518 | 1564 | * concurrently in a non-atomic way. |
| 1519 | 1565 | */ |
| 1520 | 1566 | if (is_local) { |
| 1521 | − local_dsq_post_enq(dsq, p, enq_flags); | |
| 1567 | + local_dsq_post_enq(sch, dsq, p, enq_flags); | |
| 1522 | 1568 | } else { |
| 1523 | 1569 | /* |
| 1524 | 1570 | * Task on global/bypass DSQ: leave custody, task on |
| @@ -2129,7 +2175,8 @@ static void wakeup_preempt_scx(struct rq *rq, struct task_struct *p, int wake_fl · 604 unmodified lines | ||
| 2129 | 2175 | schedule_reenq_local(rq, 0); |
| 2130 | 2176 | } |
| 2131 | 2177 | |
| 2132 | −static void move_local_task_to_local_dsq(struct task_struct *p, u64 enq_flags, | |
| 2178 | +static void move_local_task_to_local_dsq(struct scx_sched *sch, | |
| 2179 | + struct task_struct *p, u64 enq_flags, | |
| 2133 | 2180 | struct scx_dispatch_q *src_dsq, |
| 2134 | 2181 | struct rq *dst_rq) |
| 2135 | 2182 | { |
| @@ -2149,7 +2196,7 @@ static void move_local_task_to_local_dsq(struct task_struct *p, u64 enq_flags, · 13 unmodified lines | ||
| 2149 | 2196 | dsq_inc_nr(dst_dsq, p, enq_flags); |
| 2150 | 2197 | p->scx.dsq = dst_dsq; |
| 2151 | 2198 | |
| 2152 | − local_dsq_post_enq(dst_dsq, p, enq_flags); | |
| 2199 | + local_dsq_post_enq(sch, dst_dsq, p, enq_flags); | |
| 2153 | 2200 | } |
| 2154 | 2201 | |
| 2155 | 2202 | /** |
| @@ -2370,7 +2417,7 @@ static struct rq *move_task_between_dsqs(struct scx_sched *sch, · 214 unmodified lines | ||
| 2370 | 2417 | /* @p is going from a non-local DSQ to a local DSQ */ |
| 2371 | 2418 | if (src_rq == dst_rq) { |
| 2372 | 2419 | task_unlink_from_dsq(p, src_dsq); |
| 2373 | − move_local_task_to_local_dsq(p, enq_flags, | |
| 2420 | + move_local_task_to_local_dsq(sch, p, enq_flags, | |
| 2374 | 2421 | src_dsq, dst_rq); |
| 2375 | 2422 | raw_spin_unlock(&src_dsq->lock); |
| 2376 | 2423 | } else { |
| @@ -2423,7 +2470,7 @@ retry: · 46 unmodified lines | ||
| 2423 | 2470 | |
| 2424 | 2471 | if (rq == task_rq) { |
| 2425 | 2472 | task_unlink_from_dsq(p, dsq); |
| 2426 | − move_local_task_to_local_dsq(p, enq_flags, dsq, rq); | |
| 2473 | + move_local_task_to_local_dsq(sch, p, enq_flags, dsq, rq); | |
| 2427 | 2474 | raw_spin_unlock(&dsq->lock); |
| 2428 | 2475 | return true; |
| 2429 | 2476 | } |
| @@ -3183,7 +3230,7 @@ bool scx_prio_less(const struct task_struct *a, const struct task_struct *b, · 753 unmodified lines | ||
| 3183 | 3230 | if (sch_a == sch_b && SCX_HAS_OP(sch_a, core_sched_before) && |
| 3184 | 3231 | !scx_bypassing(sch_a, task_cpu(a))) |
| 3185 | 3232 | return SCX_CALL_OP_2TASKS_RET(sch_a, core_sched_before, |
| 3186 | − NULL, | |
| 3233 | + task_rq(a), | |
| 3187 | 3234 | (struct task_struct *)a, |
| 3188 | 3235 | (struct task_struct *)b); |
| 3189 | 3236 | else |
| @@ -3631,6 +3678,22 @@ static void __scx_disable_and_exit_task(struct scx_sched *sch, · 441 unmodified lines | ||
| 3631 | 3678 | SCX_CALL_OP_TASK(sch, exit_task, task_rq(p), p, &args); |
| 3632 | 3679 | } |
| 3633 | 3680 | |
| 3681 | +/* | |
| 3682 | + * Undo a completed __scx_init_task(sch, p, false) when scx_enable_task() never | |
| 3683 | + * ran. The task state has not been transitioned, so this mirrors the | |
| 3684 | + * SCX_TASK_INIT branch in __scx_disable_and_exit_task(). | |
| 3685 | + */ | |
| 3686 | +static void scx_sub_init_cancel_task(struct scx_sched *sch, struct task_struct *p) | |
| 3687 | +{ | |
| 3688 | + struct scx_exit_task_args args = { .cancelled = true }; | |
| 3689 | + | |
| 3690 | + lockdep_assert_held(&p->pi_lock); | |
| 3691 | + lockdep_assert_rq_held(task_rq(p)); | |
| 3692 | + | |
| 3693 | + if (SCX_HAS_OP(sch, exit_task)) | |
| 3694 | + SCX_CALL_OP_TASK(sch, exit_task, task_rq(p), p, &args); | |
| 3695 | +} | |
| 3696 | + | |
| 3634 | 3697 | static void scx_disable_and_exit_task(struct scx_sched *sch, |
| 3635 | 3698 | struct task_struct *p) |
| 3636 | 3699 | { |
| @@ -3639,11 +3702,12 @@ static void scx_disable_and_exit_task(struct scx_sched *sch, · 2 unmodified lines | ||
| 3639 | 3702 | /* |
| 3640 | 3703 | * If set, @p exited between __scx_init_task() and scx_enable_task() in |
| 3641 | 3704 | * scx_sub_enable() and is initialized for both the associated sched and |
| 3642 | − * its parent. Disable and exit for the child too. | |
| 3705 | + * its parent. Exit for the child too - scx_enable_task() never ran for | |
| 3706 | + * it, so undo only init_task. | |
| 3643 | 3707 | */ |
| 3644 | − if ((p->scx.flags & SCX_TASK_SUB_INIT) && | |
| 3645 | − !WARN_ON_ONCE(!scx_enabling_sub_sched)) { | |
| 3646 | − __scx_disable_and_exit_task(scx_enabling_sub_sched, p); | |
| 3708 | + if (p->scx.flags & SCX_TASK_SUB_INIT) { | |
| 3709 | + if (!WARN_ON_ONCE(!scx_enabling_sub_sched)) | |
| 3710 | + scx_sub_init_cancel_task(scx_enabling_sub_sched, p); | |
| 3647 | 3711 | p->scx.flags &= ~SCX_TASK_SUB_INIT; |
| 3648 | 3712 | } |
| 3649 | 3713 | |
| @@ -4324,9 +4388,10 @@ void scx_cgroup_cancel_attach(struct cgroup_taskset *tset) · 674 unmodified lines | ||
| 4324 | 4388 | |
| 4325 | 4389 | void scx_group_set_weight(struct task_group *tg, unsigned long weight) |
| 4326 | 4390 | { |
| 4327 | − struct scx_sched *sch = scx_root; | |
| 4391 | + struct scx_sched *sch; | |
| 4328 | 4392 | |
| 4329 | 4393 | percpu_down_read(&scx_cgroup_ops_rwsem); |
| 4394 | + sch = scx_root; | |
| 4330 | 4395 | |
| 4331 | 4396 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_weight) && |
| 4332 | 4397 | tg->scx.weight != weight) |
| @@ -4339,9 +4404,10 @@ void scx_group_set_weight(struct task_group *tg, unsigned long weight) · 6 unmodified lines | ||
| 4339 | 4404 | |
| 4340 | 4405 | void scx_group_set_idle(struct task_group *tg, bool idle) |
| 4341 | 4406 | { |
| 4342 | − struct scx_sched *sch = scx_root; | |
| 4407 | + struct scx_sched *sch; | |
| 4343 | 4408 | |
| 4344 | 4409 | percpu_down_read(&scx_cgroup_ops_rwsem); |
| 4410 | + sch = scx_root; | |
| 4345 | 4411 | |
| 4346 | 4412 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle)) |
| 4347 | 4413 | SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle); |
| @@ -4355,9 +4421,10 @@ void scx_group_set_idle(struct task_group *tg, bool idle) · 7 unmodified lines | ||
| 4355 | 4421 | void scx_group_set_bandwidth(struct task_group *tg, |
| 4356 | 4422 | u64 period_us, u64 quota_us, u64 burst_us) |
| 4357 | 4423 | { |
| 4358 | − struct scx_sched *sch = scx_root; | |
| 4424 | + struct scx_sched *sch; | |
| 4359 | 4425 | |
| 4360 | 4426 | percpu_down_read(&scx_cgroup_ops_rwsem); |
| 4427 | + sch = scx_root; | |
| 4361 | 4428 | |
| 4362 | 4429 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_bandwidth) && |
| 4363 | 4430 | (tg->scx.bw_period_us != period_us || |
| @@ -4380,21 +4447,6 @@ static struct cgroup *root_cgroup(void) · 16 unmodified lines | ||
| 4380 | 4447 | return &cgrp_dfl_root.cgrp; |
| 4381 | 4448 | } |
| 4382 | 4449 | |
| 4383 | −static struct cgroup *sch_cgroup(struct scx_sched *sch) | |
| 4384 | −{ | |
| 4385 | − return sch->cgrp; | |
| 4386 | −} | |
| 4387 | − | |
| 4388 | −/* for each descendant of @cgrp including self, set ->scx_sched to @sch */ | |
| 4389 | −static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch) | |
| 4390 | −{ | |
| 4391 | − struct cgroup *pos; | |
| 4392 | − struct cgroup_subsys_state *css; | |
| 4393 | − | |
| 4394 | − cgroup_for_each_live_descendant_pre(pos, css, cgrp) | |
| 4395 | − rcu_assign_pointer(pos->scx_sched, sch); | |
| 4396 | −} | |
| 4397 | − | |
| 4398 | 4450 | static void scx_cgroup_lock(void) |
| 4399 | 4451 | { |
| 4400 | 4452 | #ifdef CONFIG_EXT_GROUP_SCHED |
| @@ -4412,12 +4464,30 @@ static void scx_cgroup_unlock(void) · 11 unmodified lines | ||
| 4412 | 4464 | } |
| 4413 | 4465 | #else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */ |
| 4414 | 4466 | static struct cgroup *root_cgroup(void) { return NULL; } |
| 4415 | −static struct cgroup *sch_cgroup(struct scx_sched *sch) { return NULL; } | |
| 4416 | −static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch) {} | |
| 4417 | 4467 | static void scx_cgroup_lock(void) {} |
| 4418 | 4468 | static void scx_cgroup_unlock(void) {} |
| 4419 | 4469 | #endif /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */ |
| 4420 | 4470 | |
| 4471 | +#ifdef CONFIG_EXT_SUB_SCHED | |
| 4472 | +static struct cgroup *sch_cgroup(struct scx_sched *sch) | |
| 4473 | +{ | |
| 4474 | + return sch->cgrp; | |
| 4475 | +} | |
| 4476 | + | |
| 4477 | +/* for each descendant of @cgrp including self, set ->scx_sched to @sch */ | |
| 4478 | +static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch) | |
| 4479 | +{ | |
| 4480 | + struct cgroup *pos; | |
| 4481 | + struct cgroup_subsys_state *css; | |
| 4482 | + | |
| 4483 | + cgroup_for_each_live_descendant_pre(pos, css, cgrp) | |
| 4484 | + rcu_assign_pointer(pos->scx_sched, sch); | |
| 4485 | +} | |
| 4486 | +#else /* CONFIG_EXT_SUB_SCHED */ | |
| 4487 | +static struct cgroup *sch_cgroup(struct scx_sched *sch) { return NULL; } | |
| 4488 | +static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch) {} | |
| 4489 | +#endif /* CONFIG_EXT_SUB_SCHED */ | |
| 4490 | + | |
| 4421 | 4491 | /* |
| 4422 | 4492 | * Omitted operations: |
| 4423 | 4493 | * |
| @@ -4712,6 +4782,8 @@ static void scx_sched_free_rcu_work(struct work_struct *work) · 288 unmodified lines | ||
| 4712 | 4782 | irq_work_sync(&sch->disable_irq_work); |
| 4713 | 4783 | kthread_destroy_worker(sch->helper); |
| 4714 | 4784 | timer_shutdown_sync(&sch->bypass_lb_timer); |
| 4785 | + free_cpumask_var(sch->bypass_lb_donee_cpumask); | |
| 4786 | + free_cpumask_var(sch->bypass_lb_resched_cpumask); | |
| 4715 | 4787 | |
| 4716 | 4788 | #ifdef CONFIG_EXT_SUB_SCHED |
| 4717 | 4789 | kfree(sch->cgrp_path); |
| @@ -4938,6 +5010,25 @@ void scx_softlockup(u32 dur_s) · 220 unmodified lines | ||
| 4938 | 5010 | smp_processor_id(), dur_s); |
| 4939 | 5011 | } |
| 4940 | 5012 | |
| 5013 | +/* | |
| 5014 | + * scx_hardlockup() runs from NMI and eventually calls scx_claim_exit(), | |
| 5015 | + * which takes scx_sched_lock. scx_sched_lock isn't NMI-safe and grabbing | |
| 5016 | + * it from NMI context can lead to deadlocks. Defer via irq_work; the | |
| 5017 | + * disable path runs off irq_work anyway. | |
| 5018 | + */ | |
| 5019 | +static atomic_t scx_hardlockup_cpu = ATOMIC_INIT(-1); | |
| 5020 | + | |
| 5021 | +static void scx_hardlockup_irq_workfn(struct irq_work *work) | |
| 5022 | +{ | |
| 5023 | + int cpu = atomic_xchg(&scx_hardlockup_cpu, -1); | |
| 5024 | + | |
| 5025 | + if (cpu >= 0 && handle_lockup("hard lockup - CPU %d", cpu)) | |
| 5026 | + printk_deferred(KERN_ERR "sched_ext: Hard lockup - CPU %d, disabling BPF scheduler\n", | |
| 5027 | + cpu); | |
| 5028 | +} | |
| 5029 | + | |
| 5030 | +static DEFINE_IRQ_WORK(scx_hardlockup_irq_work, scx_hardlockup_irq_workfn); | |
| 5031 | + | |
| 4941 | 5032 | /** |
| 4942 | 5033 | * scx_hardlockup - sched_ext hardlockup handler |
| 4943 | 5034 | * |
| @@ -4946,17 +5037,19 @@ void scx_softlockup(u32 dur_s) · 2 unmodified lines | ||
| 4946 | 5037 | * Try kicking out the current scheduler in an attempt to recover the system to |
| 4947 | 5038 | * a good state before taking more drastic actions. |
| 4948 | 5039 | * |
| 4949 | − * Returns %true if sched_ext is enabled and abort was initiated, which may | |
| 4950 | − * resolve the reported hardlockup. %false if sched_ext is not enabled or | |
| 4951 | − * someone else already initiated abort. | |
| 5040 | + * Queues an irq_work; the handle_lockup() call happens in IRQ context (see | |
| 5041 | + * scx_hardlockup_irq_workfn). | |
| 5042 | + * | |
| 5043 | + * Returns %true if sched_ext is enabled and the work was queued, %false | |
| 5044 | + * otherwise. | |
| 4952 | 5045 | */ |
| 4953 | 5046 | bool scx_hardlockup(int cpu) |
| 4954 | 5047 | { |
| 4955 | − if (!handle_lockup("hard lockup - CPU %d", cpu)) | |
| 5048 | + if (!rcu_access_pointer(scx_root)) | |
| 4956 | 5049 | return false; |
| 4957 | 5050 | |
| 4958 | − printk_deferred(KERN_ERR "sched_ext: Hard lockup - CPU %d, disabling BPF scheduler\n", | |
| 4959 | − cpu); | |
| 5051 | + atomic_cmpxchg(&scx_hardlockup_cpu, -1, cpu); | |
| 5052 | + irq_work_queue(&scx_hardlockup_irq_work); | |
| 4960 | 5053 | return true; |
| 4961 | 5054 | } |
| 4962 | 5055 | |
| @@ -5000,6 +5093,15 @@ resume: · 37 unmodified lines | ||
| 5000 | 5093 | if (cpumask_empty(donee_mask)) |
| 5001 | 5094 | break; |
| 5002 | 5095 | |
| 5096 | + /* | |
| 5097 | + * If an earlier pass placed @p on @donor_dsq from a different | |
| 5098 | + * CPU and the donee hasn't consumed it yet, @p is still on the | |
| 5099 | + * previous CPU and task_rq(@p) != @donor_rq. @p can't be moved | |
| 5100 | + * without its rq locked. Skip. | |
| 5101 | + */ | |
| 5102 | + if (task_rq(p) != donor_rq) | |
| 5103 | + continue; | |
| 5104 | + | |
| 5003 | 5105 | donee = cpumask_any_and_distribute(donee_mask, p->cpus_ptr); |
| 5004 | 5106 | if (donee >= nr_cpu_ids) |
| 5005 | 5107 | continue; |
| @@ -5058,8 +5160,8 @@ resume: · 52 unmodified lines | ||
| 5058 | 5160 | static void bypass_lb_node(struct scx_sched *sch, int node) |
| 5059 | 5161 | { |
| 5060 | 5162 | const struct cpumask *node_mask = cpumask_of_node(node); |
| 5061 | − struct cpumask *donee_mask = scx_bypass_lb_donee_cpumask; | |
| 5062 | − struct cpumask *resched_mask = scx_bypass_lb_resched_cpumask; | |
| 5163 | + struct cpumask *donee_mask = sch->bypass_lb_donee_cpumask; | |
| 5164 | + struct cpumask *resched_mask = sch->bypass_lb_resched_cpumask; | |
| 5063 | 5165 | u32 nr_tasks = 0, nr_cpus = 0, nr_balanced = 0; |
| 5064 | 5166 | u32 nr_target, nr_donor_target; |
| 5065 | 5167 | u32 before_min = U32_MAX, before_max = 0; |
| @@ -5698,6 +5800,8 @@ static void scx_sub_disable(struct scx_sched *sch) · 632 unmodified lines | ||
| 5698 | 5800 | |
| 5699 | 5801 | if (sch->ops.exit) |
| 5700 | 5802 | SCX_CALL_OP(sch, exit, NULL, sch->exit_info); |
| 5803 | + if (sch->sub_kset) | |
| 5804 | + kset_unregister(sch->sub_kset); | |
| 5701 | 5805 | kobject_del(&sch->kobj); |
| 5702 | 5806 | } |
| 5703 | 5807 | #else /* CONFIG_EXT_SUB_SCHED */ |
| @@ -5829,6 +5933,10 @@ static void scx_root_disable(struct scx_sched *sch) · 125 unmodified lines | ||
| 5829 | 5933 | * could observe an object of the same name still in the hierarchy when |
| 5830 | 5934 | * the next scheduler is loaded. |
| 5831 | 5935 | */ |
| 5936 | +#ifdef CONFIG_EXT_SUB_SCHED | |
| 5937 | + if (sch->sub_kset) | |
| 5938 | + kset_unregister(sch->sub_kset); | |
| 5939 | +#endif | |
| 5832 | 5940 | kobject_del(&sch->kobj); |
| 5833 | 5941 | |
| 5834 | 5942 | free_kick_syncs(); |
| @@ -5921,6 +6029,25 @@ static void scx_disable(struct scx_sched *sch, enum scx_exit_kind kind) · 86 unmodified lines | ||
| 5921 | 6029 | irq_work_queue(&sch->disable_irq_work); |
| 5922 | 6030 | } |
| 5923 | 6031 | |
| 6032 | +/** | |
| 6033 | + * scx_flush_disable_work - flush the disable work and wait for it to finish | |
| 6034 | + * @sch: the scheduler | |
| 6035 | + * | |
| 6036 | + * sch->disable_work might still not queued, causing kthread_flush_work() | |
| 6037 | + * as a noop. Syncing the irq_work first is required to guarantee the | |
| 6038 | + * kthread work has been queued before waiting for it. | |
| 6039 | + */ | |
| 6040 | +static void scx_flush_disable_work(struct scx_sched *sch) | |
| 6041 | +{ | |
| 6042 | + int kind; | |
| 6043 | + | |
| 6044 | + do { | |
| 6045 | + irq_work_sync(&sch->disable_irq_work); | |
| 6046 | + kthread_flush_work(&sch->disable_work); | |
| 6047 | + kind = atomic_read(&sch->exit_kind); | |
| 6048 | + } while (kind != SCX_EXIT_NONE && kind != SCX_EXIT_DONE); | |
| 6049 | +} | |
| 6050 | + | |
| 5924 | 6051 | static void dump_newline(struct seq_buf *s) |
| 5925 | 6052 | { |
| 5926 | 6053 | trace_sched_ext_dump(""); |
| @@ -6032,9 +6159,8 @@ static void ops_dump_exit(void) · 105 unmodified lines | ||
| 6032 | 6159 | scx_dump_data.cpu = -1; |
| 6033 | 6160 | } |
| 6034 | 6161 | |
| 6035 | −static void scx_dump_task(struct scx_sched *sch, | |
| 6036 | − struct seq_buf *s, struct scx_dump_ctx *dctx, | |
| 6037 | − struct task_struct *p, char marker) | |
| 6162 | +static void scx_dump_task(struct scx_sched *sch, struct seq_buf *s, struct scx_dump_ctx *dctx, | |
| 6163 | + struct rq *rq, struct task_struct *p, char marker) | |
| 6038 | 6164 | { |
| 6039 | 6165 | static unsigned long bt[SCX_EXIT_BT_LEN]; |
| 6040 | 6166 | struct scx_sched *task_sch = scx_task_sched(p); |
| @@ -6075,7 +6201,7 @@ static void scx_dump_task(struct scx_sched *sch, · 34 unmodified lines | ||
| 6075 | 6201 | |
| 6076 | 6202 | if (SCX_HAS_OP(sch, dump_task)) { |
| 6077 | 6203 | ops_dump_init(s, " "); |
| 6078 | − SCX_CALL_OP(sch, dump_task, NULL, dctx, p); | |
| 6204 | + SCX_CALL_OP(sch, dump_task, rq, dctx, p); | |
| 6079 | 6205 | ops_dump_exit(); |
| 6080 | 6206 | } |
| 6081 | 6207 | |
| @@ -6199,8 +6325,7 @@ static void scx_dump_state(struct scx_sched *sch, struct scx_exit_info *ei, · 117 unmodified lines | ||
| 6199 | 6325 | used = seq_buf_used(&ns); |
| 6200 | 6326 | if (SCX_HAS_OP(sch, dump_cpu)) { |
| 6201 | 6327 | ops_dump_init(&ns, " "); |
| 6202 | − SCX_CALL_OP(sch, dump_cpu, NULL, | |
| 6203 | − &dctx, cpu, idle); | |
| 6328 | + SCX_CALL_OP(sch, dump_cpu, rq, &dctx, cpu, idle); | |
| 6204 | 6329 | ops_dump_exit(); |
| 6205 | 6330 | } |
| 6206 | 6331 | |
| @@ -6223,11 +6348,11 @@ static void scx_dump_state(struct scx_sched *sch, struct scx_exit_info *ei, · 16 unmodified lines | ||
| 6223 | 6348 | |
| 6224 | 6349 | if (rq->curr->sched_class == &ext_sched_class && |
| 6225 | 6350 | (dump_all_tasks || scx_task_on_sched(sch, rq->curr))) |
| 6226 | − scx_dump_task(sch, &s, &dctx, rq->curr, '*'); | |
| 6351 | + scx_dump_task(sch, &s, &dctx, rq, rq->curr, '*'); | |
| 6227 | 6352 | |
| 6228 | 6353 | list_for_each_entry(p, &rq->scx.runnable_list, scx.runnable_node) |
| 6229 | 6354 | if (dump_all_tasks || scx_task_on_sched(sch, p)) |
| 6230 | − scx_dump_task(sch, &s, &dctx, p, ' '); | |
| 6355 | + scx_dump_task(sch, &s, &dctx, rq, p, ' '); | |
| 6231 | 6356 | next: |
| 6232 | 6357 | rq_unlock_irqrestore(rq, &rf); |
| 6233 | 6358 | } |
| @@ -6437,6 +6562,15 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops, · 203 unmodified lines | ||
| 6437 | 6562 | init_irq_work(&sch->disable_irq_work, scx_disable_irq_workfn); |
| 6438 | 6563 | kthread_init_work(&sch->disable_work, scx_disable_workfn); |
| 6439 | 6564 | timer_setup(&sch->bypass_lb_timer, scx_bypass_lb_timerfn, 0); |
| 6565 | + | |
| 6566 | + if (!alloc_cpumask_var(&sch->bypass_lb_donee_cpumask, GFP_KERNEL)) { | |
| 6567 | + ret = -ENOMEM; | |
| 6568 | + goto err_stop_helper; | |
| 6569 | + } | |
| 6570 | + if (!alloc_cpumask_var(&sch->bypass_lb_resched_cpumask, GFP_KERNEL)) { | |
| 6571 | + ret = -ENOMEM; | |
| 6572 | + goto err_free_lb_cpumask; | |
| 6573 | + } | |
| 6440 | 6574 | sch->ops = *ops; |
| 6441 | 6575 | rcu_assign_pointer(ops->priv, sch); |
| 6442 | 6576 | |
| @@ -6446,14 +6580,14 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops, · 3 unmodified lines | ||
| 6446 | 6580 | char *buf = kzalloc(PATH_MAX, GFP_KERNEL); |
| 6447 | 6581 | if (!buf) { |
| 6448 | 6582 | ret = -ENOMEM; |
| 6449 | − goto err_stop_helper; | |
| 6583 | + goto err_free_lb_resched; | |
| 6450 | 6584 | } |
| 6451 | 6585 | cgroup_path(cgrp, buf, PATH_MAX); |
| 6452 | 6586 | sch->cgrp_path = kstrdup(buf, GFP_KERNEL); |
| 6453 | 6587 | kfree(buf); |
| 6454 | 6588 | if (!sch->cgrp_path) { |
| 6455 | 6589 | ret = -ENOMEM; |
| 6456 | − goto err_stop_helper; | |
| 6590 | + goto err_free_lb_resched; | |
| 6457 | 6591 | } |
| 6458 | 6592 | |
| 6459 | 6593 | sch->cgrp = cgrp; |
| @@ -6488,10 +6622,12 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops, · 28 unmodified lines | ||
| 6488 | 6622 | #endif /* CONFIG_EXT_SUB_SCHED */ |
| 6489 | 6623 | return sch; |
| 6490 | 6624 | |
| 6491 | −#ifdef CONFIG_EXT_SUB_SCHED | |
| 6625 | +err_free_lb_resched: | |
| 6626 | + free_cpumask_var(sch->bypass_lb_resched_cpumask); | |
| 6627 | +err_free_lb_cpumask: | |
| 6628 | + free_cpumask_var(sch->bypass_lb_donee_cpumask); | |
| 6492 | 6629 | err_stop_helper: |
| 6493 | 6630 | kthread_destroy_worker(sch->helper); |
| 6494 | −#endif | |
| 6495 | 6631 | err_free_pcpu: |
| 6496 | 6632 | for_each_possible_cpu(cpu) { |
| 6497 | 6633 | if (cpu == bypass_fail_cpu) |
| @@ -6510,7 +6646,7 @@ err_free_ei: · 12 unmodified lines | ||
| 6510 | 6646 | err_free_sch: |
| 6511 | 6647 | kfree(sch); |
| 6512 | 6648 | err_put_cgrp: |
| 6513 | −#if defined(CONFIG_EXT_GROUP_SCHED) || defined(CONFIG_EXT_SUB_SCHED) | |
| 6649 | +#ifdef CONFIG_EXT_SUB_SCHED | |
| 6514 | 6650 | cgroup_put(cgrp); |
| 6515 | 6651 | #endif |
| 6516 | 6652 | return ERR_PTR(ret); |
| @@ -6601,7 +6737,7 @@ static void scx_root_enable_workfn(struct kthread_work *work) · 84 unmodified lines | ||
| 6601 | 6737 | if (ret) |
| 6602 | 6738 | goto err_unlock; |
| 6603 | 6739 | |
| 6604 | −#if defined(CONFIG_EXT_GROUP_SCHED) || defined(CONFIG_EXT_SUB_SCHED) | |
| 6740 | +#ifdef CONFIG_EXT_SUB_SCHED | |
| 6605 | 6741 | cgroup_get(cgrp); |
| 6606 | 6742 | #endif |
| 6607 | 6743 | sch = scx_alloc_and_add_sched(ops, cgrp, NULL); |
| @@ -6639,8 +6775,10 @@ static void scx_root_enable_workfn(struct kthread_work *work) · 31 unmodified lines | ||
| 6639 | 6775 | rcu_assign_pointer(scx_root, sch); |
| 6640 | 6776 | |
| 6641 | 6777 | ret = scx_link_sched(sch); |
| 6642 | − if (ret) | |
| 6778 | + if (ret) { | |
| 6779 | + cpus_read_unlock(); | |
| 6643 | 6780 | goto err_disable; |
| 6781 | + } | |
| 6644 | 6782 | |
| 6645 | 6783 | scx_idle_enable(ops); |
| 6646 | 6784 | |
| @@ -6821,7 +6959,7 @@ err_disable: · 174 unmodified lines | ||
| 6821 | 6959 | * completion. sch's base reference will be put by bpf_scx_unreg(). |
| 6822 | 6960 | */ |
| 6823 | 6961 | scx_error(sch, "scx_root_enable() failed (%d)", ret); |
| 6824 | − kthread_flush_work(&sch->disable_work); | |
| 6962 | + scx_flush_disable_work(sch); | |
| 6825 | 6963 | cmd->ret = 0; |
| 6826 | 6964 | } |
| 6827 | 6965 | |
| @@ -7072,23 +7210,30 @@ out_unlock: · 244 unmodified lines | ||
| 7072 | 7210 | abort: |
| 7073 | 7211 | put_task_struct(p); |
| 7074 | 7212 | scx_task_iter_stop(&sti); |
| 7075 | − scx_enabling_sub_sched = NULL; | |
| 7076 | 7213 | |
| 7214 | + /* | |
| 7215 | + * Undo __scx_init_task() for tasks we marked. scx_enable_task() never | |
| 7216 | + * ran for @sch on them, so calling scx_disable_task() here would invoke | |
| 7217 | + * ops.disable() without a matching ops.enable(). scx_enabling_sub_sched | |
| 7218 | + * must stay set until SUB_INIT is cleared from every marked task - | |
| 7219 | + * scx_disable_and_exit_task() reads it when a task exits concurrently. | |
| 7220 | + */ | |
| 7077 | 7221 | scx_task_iter_start(&sti, sch->cgrp); |
| 7078 | 7222 | while ((p = scx_task_iter_next_locked(&sti))) { |
| 7079 | 7223 | if (p->scx.flags & SCX_TASK_SUB_INIT) { |
| 7080 | − __scx_disable_and_exit_task(sch, p); | |
| 7224 | + scx_sub_init_cancel_task(sch, p); | |
| 7081 | 7225 | p->scx.flags &= ~SCX_TASK_SUB_INIT; |
| 7082 | 7226 | } |
| 7083 | 7227 | } |
| 7084 | 7228 | scx_task_iter_stop(&sti); |
| 7229 | + scx_enabling_sub_sched = NULL; | |
| 7085 | 7230 | err_unlock_and_disable: |
| 7086 | 7231 | /* we'll soon enter disable path, keep bypass on */ |
| 7087 | 7232 | scx_cgroup_unlock(); |
| 7088 | 7233 | percpu_up_write(&scx_fork_rwsem); |
| 7089 | 7234 | err_disable: |
| 7090 | 7235 | mutex_unlock(&scx_enable_mutex); |
| 7091 | − kthread_flush_work(&sch->disable_work); | |
| 7236 | + scx_flush_disable_work(sch); | |
| 7092 | 7237 | cmd->ret = 0; |
| 7093 | 7238 | } |
| 7094 | 7239 | |
| @@ -7349,7 +7494,7 @@ static void bpf_scx_unreg(void *kdata, struct bpf_link *link) · 254 unmodified lines | ||
| 7349 | 7494 | struct scx_sched *sch = rcu_dereference_protected(ops->priv, true); |
| 7350 | 7495 | |
| 7351 | 7496 | scx_disable(sch, SCX_EXIT_UNREG); |
| 7352 | − kthread_flush_work(&sch->disable_work); | |
| 7497 | + scx_flush_disable_work(sch); | |
| 7353 | 7498 | RCU_INIT_POINTER(ops->priv, NULL); |
| 7354 | 7499 | kobject_put(&sch->kobj); |
| 7355 | 7500 | } |
| @@ -8033,12 +8178,22 @@ static bool scx_dsq_move(struct bpf_iter_scx_dsq_kern *kit, · 677 unmodified lines | ||
| 8033 | 8178 | struct task_struct *p, u64 dsq_id, u64 enq_flags) |
| 8034 | 8179 | { |
| 8035 | 8180 | struct scx_dispatch_q *src_dsq = kit->dsq, *dst_dsq; |
| 8036 | − struct scx_sched *sch = src_dsq->sched; | |
| 8181 | + struct scx_sched *sch; | |
| 8037 | 8182 | struct rq *this_rq, *src_rq, *locked_rq; |
| 8038 | 8183 | bool dispatched = false; |
| 8039 | 8184 | bool in_balance; |
| 8040 | 8185 | unsigned long flags; |
| 8041 | 8186 | |
| 8187 | + /* | |
| 8188 | + * The verifier considers an iterator slot initialized on any | |
| 8189 | + * KF_ITER_NEW return, so a BPF program may legally reach here after | |
| 8190 | + * bpf_iter_scx_dsq_new() failed and left @kit->dsq NULL. | |
| 8191 | + */ | |
| 8192 | + if (unlikely(!src_dsq)) | |
| 8193 | + return false; | |
| 8194 | + | |
| 8195 | + sch = src_dsq->sched; | |
| 8196 | + | |
| 8042 | 8197 | if (!scx_vet_enq_flags(sch, dsq_id, &enq_flags)) |
| 8043 | 8198 | return false; |
| 8044 | 8199 | |
| @@ -8526,7 +8681,7 @@ __bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice, · 481 unmodified lines | ||
| 8526 | 8681 | |
| 8527 | 8682 | guard(rcu)(); |
| 8528 | 8683 | sch = scx_prog_sched(aux); |
| 8529 | − if (unlikely(!scx_task_on_sched(sch, p))) | |
| 8684 | + if (unlikely(!sch || !scx_task_on_sched(sch, p))) | |
| 8530 | 8685 | return false; |
| 8531 | 8686 | |
| 8532 | 8687 | p->scx.slice = slice; |
| @@ -8549,7 +8704,7 @@ __bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime, · 16 unmodified lines | ||
| 8549 | 8704 | |
| 8550 | 8705 | guard(rcu)(); |
| 8551 | 8706 | sch = scx_prog_sched(aux); |
| 8552 | − if (unlikely(!scx_task_on_sched(sch, p))) | |
| 8707 | + if (unlikely(!sch || !scx_task_on_sched(sch, p))) | |
| 8553 | 8708 | return false; |
| 8554 | 8709 | |
| 8555 | 8710 | p->scx.dsq_vtime = vtime; |
| @@ -8633,11 +8788,12 @@ __bpf_kfunc void scx_bpf_kick_cpu(s32 cpu, u64 flags, const struct bpf_prog_aux · 77 unmodified lines | ||
| 8633 | 8788 | /** |
| 8634 | 8789 | * scx_bpf_dsq_nr_queued - Return the number of queued tasks |
| 8635 | 8790 | * @dsq_id: id of the DSQ |
| 8791 | + * @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs | |
| 8636 | 8792 | * |
| 8637 | 8793 | * Return the number of tasks in the DSQ matching @dsq_id. If not found, |
| 8638 | 8794 | * -%ENOENT is returned. |
| 8639 | 8795 | */ |
| 8640 | −__bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id) | |
| 8796 | +__bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id, const struct bpf_prog_aux *aux) | |
| 8641 | 8797 | { |
| 8642 | 8798 | struct scx_sched *sch; |
| 8643 | 8799 | struct scx_dispatch_q *dsq; |
| @@ -8645,7 +8801,7 @@ __bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id) · 1 unmodified line | ||
| 8645 | 8801 | |
| 8646 | 8802 | preempt_disable(); |
| 8647 | 8803 | |
| 8648 | − sch = rcu_dereference_sched(scx_root); | |
| 8804 | + sch = scx_prog_sched(aux); | |
| 8649 | 8805 | if (unlikely(!sch)) { |
| 8650 | 8806 | ret = -ENODEV; |
| 8651 | 8807 | goto out; |
| @@ -8677,21 +8833,21 @@ out: · 25 unmodified lines | ||
| 8677 | 8833 | /** |
| 8678 | 8834 | * scx_bpf_destroy_dsq - Destroy a custom DSQ |
| 8679 | 8835 | * @dsq_id: DSQ to destroy |
| 8836 | + * @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs | |
| 8680 | 8837 | * |
| 8681 | 8838 | * Destroy the custom DSQ identified by @dsq_id. Only DSQs created with |
| 8682 | 8839 | * scx_bpf_create_dsq() can be destroyed. The caller must ensure that the DSQ is |
| 8683 | 8840 | * empty and no further tasks are dispatched to it. Ignored if called on a DSQ |
| 8684 | 8841 | * which doesn't exist. Can be called from any online scx_ops operations. |
| 8685 | 8842 | */ |
| 8686 | −__bpf_kfunc void scx_bpf_destroy_dsq(u64 dsq_id) | |
| 8843 | +__bpf_kfunc void scx_bpf_destroy_dsq(u64 dsq_id, const struct bpf_prog_aux *aux) | |
| 8687 | 8844 | { |
| 8688 | 8845 | struct scx_sched *sch; |
| 8689 | 8846 | |
| 8690 | − rcu_read_lock(); | |
| 8691 | − sch = rcu_dereference(scx_root); | |
| 8847 | + guard(rcu)(); | |
| 8848 | + sch = scx_prog_sched(aux); | |
| 8692 | 8849 | if (sch) |
| 8693 | 8850 | destroy_dsq(sch, dsq_id); |
| 8694 | − rcu_read_unlock(); | |
| 8695 | 8851 | } |
| 8696 | 8852 | |
| 8697 | 8853 | /** |
| @@ -9445,8 +9601,8 @@ BTF_KFUNCS_START(scx_kfunc_ids_any) · 747 unmodified lines | ||
| 9445 | 9601 | BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_IMPLICIT_ARGS | KF_RCU); |
| 9446 | 9602 | BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_IMPLICIT_ARGS | KF_RCU); |
| 9447 | 9603 | BTF_ID_FLAGS(func, scx_bpf_kick_cpu, KF_IMPLICIT_ARGS) |
| 9448 | −BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued) | |
| 9449 | −BTF_ID_FLAGS(func, scx_bpf_destroy_dsq) | |
| 9604 | +BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued, KF_IMPLICIT_ARGS) | |
| 9605 | +BTF_ID_FLAGS(func, scx_bpf_destroy_dsq, KF_IMPLICIT_ARGS) | |
| 9450 | 9606 | BTF_ID_FLAGS(func, scx_bpf_dsq_peek, KF_IMPLICIT_ARGS | KF_RCU_PROTECTED | KF_RET_NULL) |
| 9451 | 9607 | BTF_ID_FLAGS(func, scx_bpf_dsq_reenq, KF_IMPLICIT_ARGS) |
| 9452 | 9608 | BTF_ID_FLAGS(func, scx_bpf_reenqueue_local___v2, KF_IMPLICIT_ARGS) |
| @@ -9479,6 +9635,7 @@ BTF_KFUNCS_END(scx_kfunc_ids_any) · 26 unmodified lines | ||
| 9479 | 9635 | static const struct btf_kfunc_id_set scx_kfunc_set_any = { |
| 9480 | 9636 | .owner = THIS_MODULE, |
| 9481 | 9637 | .set = &scx_kfunc_ids_any, |
| 9638 | + .filter = scx_kfunc_context_filter, | |
| 9482 | 9639 | }; |
| 9483 | 9640 | |
| 9484 | 9641 | /* |
| @@ -9526,13 +9683,12 @@ static const u32 scx_kf_allow_flags[] = { · 41 unmodified lines | ||
| 9526 | 9683 | }; |
| 9527 | 9684 | |
| 9528 | 9685 | /* |
| 9529 | − * Verifier-time filter for context-sensitive SCX kfuncs. Registered via the | |
| 9530 | − * .filter field on each per-group btf_kfunc_id_set. The BPF core invokes this | |
| 9531 | − * for every kfunc call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or | |
| 9686 | + * Verifier-time filter for SCX kfuncs. Registered via the .filter field on | |
| 9687 | + * each per-group btf_kfunc_id_set. The BPF core invokes this for every kfunc | |
| 9688 | + * call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or | |
| 9532 | 9689 | * BPF_PROG_TYPE_SYSCALL), regardless of which set originally introduced the |
| 9533 | − * kfunc - so the filter must short-circuit on kfuncs it doesn't govern (e.g. | |
| 9534 | − * scx_kfunc_ids_any) by falling through to "allow" when none of the | |
| 9535 | − * context-sensitive sets contain the kfunc. | |
| 9690 | + * kfunc - so the filter must short-circuit on kfuncs it doesn't govern by | |
| 9691 | + * falling through to "allow" when none of the SCX sets contain the kfunc. | |
| 9536 | 9692 | */ |
| 9537 | 9693 | int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id) |
| 9538 | 9694 | { |
| @@ -9541,18 +9697,21 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id) · 2 unmodified lines | ||
| 9541 | 9697 | bool in_enqueue = btf_id_set8_contains(&scx_kfunc_ids_enqueue_dispatch, kfunc_id); |
| 9542 | 9698 | bool in_dispatch = btf_id_set8_contains(&scx_kfunc_ids_dispatch, kfunc_id); |
| 9543 | 9699 | bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id); |
| 9700 | + bool in_idle = btf_id_set8_contains(&scx_kfunc_ids_idle, kfunc_id); | |
| 9701 | + bool in_any = btf_id_set8_contains(&scx_kfunc_ids_any, kfunc_id); | |
| 9544 | 9702 | u32 moff, flags; |
| 9545 | 9703 | |
| 9546 | − /* Not a context-sensitive kfunc (e.g. from scx_kfunc_ids_any) - allow. */ | |
| 9547 | − if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch || in_cpu_release)) | |
| 9704 | + /* Not an SCX kfunc - allow. */ | |
| 9705 | + if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch || | |
| 9706 | + in_cpu_release || in_idle || in_any)) | |
| 9548 | 9707 | return 0; |
| 9549 | 9708 | |
| 9550 | 9709 | /* SYSCALL progs (e.g. BPF test_run()) may call unlocked and select_cpu kfuncs. */ |
| 9551 | 9710 | if (prog->type == BPF_PROG_TYPE_SYSCALL) |
| 9552 | − return (in_unlocked || in_select_cpu) ? 0 : -EACCES; | |
| 9711 | + return (in_unlocked || in_select_cpu || in_idle || in_any) ? 0 : -EACCES; | |
| 9553 | 9712 | |
| 9554 | 9713 | if (prog->type != BPF_PROG_TYPE_STRUCT_OPS) |
| 9555 | − return -EACCES; | |
| 9714 | + return (in_any || in_idle) ? 0 : -EACCES; | |
| 9556 | 9715 | |
| 9557 | 9716 | /* |
| 9558 | 9717 | * add_subprog_and_kfunc() collects all kfunc calls, including dead code |
| @@ -9565,14 +9724,15 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id) · 6 unmodified lines | ||
| 9565 | 9724 | return 0; |
| 9566 | 9725 | |
| 9567 | 9726 | /* |
| 9568 | − * Non-SCX struct_ops: only unlocked kfuncs are safe. The other | |
| 9569 | − * context-sensitive kfuncs assume the rq lock is held by the SCX | |
| 9570 | − * dispatch path, which doesn't apply to other struct_ops users. | |
| 9727 | + * Non-SCX struct_ops: SCX kfuncs are not permitted. | |
| 9571 | 9728 | */ |
| 9572 | 9729 | if (prog->aux->st_ops != &bpf_sched_ext_ops) |
| 9573 | − return in_unlocked ? 0 : -EACCES; | |
| 9730 | + return -EACCES; | |
| 9574 | 9731 | |
| 9575 | 9732 | /* SCX struct_ops: check the per-op allow list. */ |
| 9733 | + if (in_any || in_idle) | |
| 9734 | + return 0; | |
| 9735 | + | |
| 9576 | 9736 | moff = prog->aux->attach_st_ops_member_off; |
| 9577 | 9737 | flags = scx_kf_allow_flags[SCX_MOFF_IDX(moff)]; |
| 9578 | 9738 | |
| @@ -9656,12 +9816,6 @@ static int __init scx_init(void) · 77 unmodified lines | ||
| 9656 | 9816 | return ret; |
| 9657 | 9817 | } |
| 9658 | 9818 | |
| 9659 | − if (!alloc_cpumask_var(&scx_bypass_lb_donee_cpumask, GFP_KERNEL) || | |
| 9660 | − !alloc_cpumask_var(&scx_bypass_lb_resched_cpumask, GFP_KERNEL)) { | |
| 9661 | − pr_err("sched_ext: Failed to allocate cpumasks\n"); | |
| 9662 | − return -ENOMEM; | |
| 9663 | − } | |
| 9664 | − | |
| 9665 | 9819 | return 0; |
| 9666 | 9820 | } |
| 9667 | 9821 | __initcall(scx_init); |
| @@ -927,14 +927,24 @@ static s32 select_cpu_from_kfunc(struct scx_sched *sch, struct task_struct *p, · 926 unmodified lines | ||
| 927 | 927 | * Accessing p->cpus_ptr / p->nr_cpus_allowed needs either @p's rq |
| 928 | 928 | * lock or @p's pi_lock. Three cases: |
| 929 | 929 | * |
| 930 | − * - inside ops.select_cpu(): try_to_wake_up() holds @p's pi_lock. | |
| 930 | + * - inside ops.select_cpu(): try_to_wake_up() holds the wake-up | |
| 931 | + * task's pi_lock; the wake-up task is recorded in kf_tasks[0] | |
| 932 | + * by SCX_CALL_OP_TASK_RET(). | |
| 931 | 933 | * - other rq-locked SCX op: scx_locked_rq() points at the held rq. |
| 932 | 934 | * - truly unlocked (UNLOCKED ops, SYSCALL, non-SCX struct_ops): |
| 933 | 935 | * nothing held, take pi_lock ourselves. |
| 936 | + * | |
| 937 | + * In the first two cases, BPF schedulers may pass an arbitrary task | |
| 938 | + * that the held lock doesn't cover. Refuse those. | |
| 934 | 939 | */ |
| 935 | 940 | if (this_rq()->scx.in_select_cpu) { |
| 941 | + if (!scx_kf_arg_task_ok(sch, p)) | |
| 942 | + return -EINVAL; | |
| 936 | 943 | lockdep_assert_held(&p->pi_lock); |
| 937 | − } else if (!scx_locked_rq()) { | |
| 944 | + } else if (scx_locked_rq()) { | |
| 945 | + if (task_rq(p) != scx_locked_rq()) | |
| 946 | + goto cross_task; | |
| 947 | + } else { | |
| 938 | 948 | raw_spin_lock_irqsave(&p->pi_lock, irq_flags); |
| 939 | 949 | we_locked = true; |
| 940 | 950 | } |
| @@ -960,6 +970,11 @@ static s32 select_cpu_from_kfunc(struct scx_sched *sch, struct task_struct *p, · 19 unmodified lines | ||
| 960 | 970 | raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags); |
| 961 | 971 | |
| 962 | 972 | return cpu; |
| 973 | + | |
| 974 | +cross_task: | |
| 975 | + scx_error(sch, "select_cpu kfunc called cross-task on %s[%d]", | |
| 976 | + p->comm, p->pid); | |
| 977 | + return -EINVAL; | |
| 963 | 978 | } |
| 964 | 979 | |
| 965 | 980 | /** |
| @@ -1467,6 +1482,7 @@ BTF_KFUNCS_END(scx_kfunc_ids_idle) · 501 unmodified lines | ||
| 1467 | 1482 | static const struct btf_kfunc_id_set scx_kfunc_set_idle = { |
| 1468 | 1483 | .owner = THIS_MODULE, |
| 1469 | 1484 | .set = &scx_kfunc_ids_idle, |
| 1485 | + .filter = scx_kfunc_context_filter, | |
| 1470 | 1486 | }; |
| 1471 | 1487 | |
| 1472 | 1488 | /* |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | struct sched_ext_ops; |
| 14 | 14 | |
| 15 | +extern struct btf_id_set8 scx_kfunc_ids_idle; | |
| 15 | 16 | extern struct btf_id_set8 scx_kfunc_ids_select_cpu; |
| 16 | 17 | |
| 17 | 18 | void scx_idle_update_selcpu_topology(struct sched_ext_ops *ops); |
| @@ -1075,6 +1075,8 @@ struct scx_sched { · 1074 unmodified lines | ||
| 1075 | 1075 | struct irq_work disable_irq_work; |
| 1076 | 1076 | struct kthread_work disable_work; |
| 1077 | 1077 | struct timer_list bypass_lb_timer; |
| 1078 | + cpumask_var_t bypass_lb_donee_cpumask; | |
| 1079 | + cpumask_var_t bypass_lb_resched_cpumask; | |
| 1078 | 1080 | struct rcu_work rcu_work; |
| 1079 | 1081 | |
| 1080 | 1082 | /* all ancestors including self */ |
| @@ -847,13 +847,19 @@ static s64 entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 avrunt · 846 unmodified lines | ||
| 847 | 847 | * Similarly, check that the entity didn't gain positive lag when DELAY_ZERO |
| 848 | 848 | * is set. |
| 849 | 849 | * |
| 850 | − * Return true if the lag has been adjusted. | |
| 850 | + * Return true if the vlag has been modified. Specifically: | |
| 851 | + * | |
| 852 | + * se->vlag != avg_vruntime() - se->vruntime | |
| 853 | + * | |
| 854 | + * This can be due to clamping in entity_lag() or clamping due to | |
| 855 | + * sched_delayed. Either way, when vlag is modified and the entity is | |
| 856 | + * retained, the tree needs to be adjusted. | |
| 851 | 857 | */ |
| 852 | 858 | static __always_inline |
| 853 | 859 | bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se) |
| 854 | 860 | { |
| 855 | − s64 vlag = entity_lag(cfs_rq, se, avg_vruntime(cfs_rq)); | |
| 856 | − bool ret; | |
| 861 | + u64 avruntime = avg_vruntime(cfs_rq); | |
| 862 | + s64 vlag = entity_lag(cfs_rq, se, avruntime); | |
| 857 | 863 | |
| 858 | 864 | WARN_ON_ONCE(!se->on_rq); |
| 859 | 865 | |
| @@ -863,10 +869,9 @@ bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se) · 3 unmodified lines | ||
| 863 | 869 | if (sched_feat(DELAY_ZERO)) |
| 864 | 870 | vlag = min(vlag, 0); |
| 865 | 871 | } |
| 866 | − ret = (vlag == se->vlag); | |
| 867 | 872 | se->vlag = vlag; |
| 868 | 873 | |
| 869 | − return ret; | |
| 874 | + return avruntime - vlag != se->vruntime; | |
| 870 | 875 | } |
| 871 | 876 | |
| 872 | 877 | /* |
| @@ -1099,7 +1104,7 @@ static inline void cancel_protect_slice(struct sched_entity *se) · 226 unmodified lines | ||
| 1099 | 1104 | * |
| 1100 | 1105 | * Which allows tree pruning through eligibility. |
| 1101 | 1106 | */ |
| 1102 | −static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect) | |
| 1107 | +static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect) | |
| 1103 | 1108 | { |
| 1104 | 1109 | struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node; |
| 1105 | 1110 | struct sched_entity *se = __pick_first_entity(cfs_rq); |
| @@ -1170,11 +1175,6 @@ found: · 64 unmodified lines | ||
| 1170 | 1175 | return best; |
| 1171 | 1176 | } |
| 1172 | 1177 | |
| 1173 | −static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq) | |
| 1174 | −{ | |
| 1175 | − return __pick_eevdf(cfs_rq, true); | |
| 1176 | −} | |
| 1177 | − | |
| 1178 | 1178 | struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) |
| 1179 | 1179 | { |
| 1180 | 1180 | struct rb_node *last = rb_last(&cfs_rq->tasks_timeline.rb_root); |
| @@ -5749,11 +5749,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags); · 4568 unmodified lines | ||
| 5749 | 5749 | * 4) do not run the "skip" process, if something else is available |
| 5750 | 5750 | */ |
| 5751 | 5751 | static struct sched_entity * |
| 5752 | −pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq) | |
| 5752 | +pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq, bool protect) | |
| 5753 | 5753 | { |
| 5754 | 5754 | struct sched_entity *se; |
| 5755 | 5755 | |
| 5756 | − se = pick_eevdf(cfs_rq); | |
| 5756 | + se = pick_eevdf(cfs_rq, protect); | |
| 5757 | 5757 | if (se->sched_delayed) { |
| 5758 | 5758 | dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); |
| 5759 | 5759 | /* |
| @@ -9027,7 +9027,7 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f · 3267 unmodified lines | ||
| 9027 | 9027 | { |
| 9028 | 9028 | enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK; |
| 9029 | 9029 | struct task_struct *donor = rq->donor; |
| 9030 | − struct sched_entity *se = &donor->se, *pse = &p->se; | |
| 9030 | + struct sched_entity *nse, *se = &donor->se, *pse = &p->se; | |
| 9031 | 9031 | struct cfs_rq *cfs_rq = task_cfs_rq(donor); |
| 9032 | 9032 | int cse_is_idle, pse_is_idle; |
| 9033 | 9033 | |
| @@ -9138,11 +9138,17 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f · 104 unmodified lines | ||
| 9138 | 9138 | } |
| 9139 | 9139 | |
| 9140 | 9140 | pick: |
| 9141 | + nse = pick_next_entity(rq, cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT); | |
| 9142 | + /* If @p has become the most eligible task, force preemption */ | |
| 9143 | + if (nse == pse) | |
| 9144 | + goto preempt; | |
| 9145 | + | |
| 9141 | 9146 | /* |
| 9142 | − * If @p has become the most eligible task, force preemption. | |
| 9147 | + * Because p is enqueued, nse being null can only mean that we | |
| 9148 | + * dequeued a delayed task. | |
| 9143 | 9149 | */ |
| 9144 | − if (__pick_eevdf(cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT) == pse) | |
| 9145 | − goto preempt; | |
| 9150 | + if (!nse) | |
| 9151 | + goto pick; | |
| 9146 | 9152 | |
| 9147 | 9153 | if (sched_feat(RUN_TO_PARITY)) |
| 9148 | 9154 | update_protect_slice(cfs_rq, se); |
| @@ -9179,7 +9185,7 @@ again: · 30 unmodified lines | ||
| 9179 | 9185 | |
| 9180 | 9186 | throttled |= check_cfs_rq_runtime(cfs_rq); |
| 9181 | 9187 | |
| 9182 | − se = pick_next_entity(rq, cfs_rq); | |
| 9188 | + se = pick_next_entity(rq, cfs_rq, true); | |
| 9183 | 9189 | if (!se) |
| 9184 | 9190 | goto again; |
| 9185 | 9191 | cfs_rq = group_cfs_rq(se); |
| @@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void) · 372 unmodified lines | ||
| 373 | 373 | int ret; |
| 374 | 374 | |
| 375 | 375 | ret = register_stat_tracer(&annotated_branch_stats); |
| 376 | − if (!ret) { | |
| 376 | + if (ret) { | |
| 377 | 377 | printk(KERN_WARNING "Warning: could not register " |
| 378 | 378 | "annotated branches stats\n"); |
| 379 | − return 1; | |
| 379 | + return ret; | |
| 380 | 380 | } |
| 381 | 381 | return 0; |
| 382 | 382 | } |
| @@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void) · 55 unmodified lines | ||
| 438 | 438 | int ret; |
| 439 | 439 | |
| 440 | 440 | ret = register_stat_tracer(&all_branch_stats); |
| 441 | − if (!ret) { | |
| 441 | + if (ret) { | |
| 442 | 442 | printk(KERN_WARNING "Warning: could not register " |
| 443 | 443 | "all branches stats\n"); |
| 444 | − return 1; | |
| 444 | + return ret; | |
| 445 | 445 | } |
| 446 | 446 | return 0; |
| 447 | 447 | } |
| @@ -1523,6 +1523,12 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, · 1522 unmodified lines | ||
| 1523 | 1523 | parg->offset = *size; |
| 1524 | 1524 | *size += parg->type->size * (parg->count ?: 1); |
| 1525 | 1525 | |
| 1526 | + if (*size > MAX_PROBE_EVENT_SIZE) { | |
| 1527 | + ret = -E2BIG; | |
| 1528 | + trace_probe_log_err(ctx->offset, EVENT_TOO_BIG); | |
| 1529 | + goto fail; | |
| 1530 | + } | |
| 1531 | + | |
| 1526 | 1532 | if (parg->count) { |
| 1527 | 1533 | len = strlen(parg->type->fmttype) + 6; |
| 1528 | 1534 | parg->fmt = kmalloc(len, GFP_KERNEL); |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | #define MAX_BTF_ARGS_LEN 128 |
| 39 | 39 | #define MAX_DENTRY_ARGS_LEN 256 |
| 40 | 40 | #define MAX_STRING_SIZE PATH_MAX |
| 41 | +#define MAX_PROBE_EVENT_SIZE 3072 | |
| 41 | 42 | |
| 42 | 43 | /* Reserved field names */ |
| 43 | 44 | #define FIELD_STRING_IP "__probe_ip" |
| @@ -561,7 +562,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, · 517 unmodified lines | ||
| 561 | 562 | C(BAD_TYPE4STR, "This type does not fit for string."),\ |
| 562 | 563 | C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\ |
| 563 | 564 | C(TOO_MANY_ARGS, "Too many arguments are specified"), \ |
| 564 | − C(TOO_MANY_EARGS, "Too many entry arguments specified"), | |
| 565 | + C(TOO_MANY_EARGS, "Too many entry arguments specified"), \ | |
| 566 | + C(EVENT_TOO_BIG, "Event too big (too many fields?)"), | |
| 565 | 567 | |
| 566 | 568 | #undef C |
| 567 | 569 | #define C(a, b) TP_ERR_##a |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * Maple Tree implementation |
| 4 | 4 | * Copyright (c) 2018-2022 Oracle Corporation |
| 5 | − * Authors: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 5 | + * Authors: Liam R. Howlett <liam@infradead.org> | |
| 6 | 6 | * Matthew Wilcox <willy@infradead.org> |
| 7 | 7 | * Copyright (c) 2023 ByteDance |
| 8 | 8 | * Author: Peng Zhang <zhangpeng.00@bytedance.com> |
| @@ -441,10 +441,33 @@ static void rht_deferred_worker(struct work_struct *work) · 440 unmodified lines | ||
| 441 | 441 | |
| 442 | 442 | mutex_unlock(&ht->mutex); |
| 443 | 443 | |
| 444 | + /* | |
| 445 | + * Re-arm via @run_work, not @run_irq_work. | |
| 446 | + * rhashtable_free_and_destroy() drains async work as irq_work_sync() | |
| 447 | + * followed by cancel_work_sync(). If this site queued irq_work while | |
| 448 | + * cancel_work_sync() was waiting for us, irq_work_sync() would already | |
| 449 | + * have returned and the stale irq_work could fire post-teardown. | |
| 450 | + * cancel_work_sync() natively handles self-requeue on @run_work. | |
| 451 | + */ | |
| 444 | 452 | if (err) |
| 445 | 453 | schedule_work(&ht->run_work); |
| 446 | 454 | } |
| 447 | 455 | |
| 456 | +/* | |
| 457 | + * Insert-path callers can run under a raw spinlock (e.g. an insecure_elasticity | |
| 458 | + * user). Calling schedule_work() under that lock records caller_lock -> | |
| 459 | + * pool->lock -> pi_lock -> rq->__lock, closing a locking cycle if any of | |
| 460 | + * these is acquired in the reverse direction elsewhere. Bounce through | |
| 461 | + * irq_work so the schedule_work() runs with the caller's lock no longer held. | |
| 462 | + */ | |
| 463 | +static void rht_deferred_irq_work(struct irq_work *irq_work) | |
| 464 | +{ | |
| 465 | + struct rhashtable *ht = container_of(irq_work, struct rhashtable, | |
| 466 | + run_irq_work); | |
| 467 | + | |
| 468 | + schedule_work(&ht->run_work); | |
| 469 | +} | |
| 470 | + | |
| 448 | 471 | static int rhashtable_insert_rehash(struct rhashtable *ht, |
| 449 | 472 | struct bucket_table *tbl) |
| 450 | 473 | { |
| @@ -477,7 +500,7 @@ static int rhashtable_insert_rehash(struct rhashtable *ht, · 26 unmodified lines | ||
| 477 | 500 | if (err == -EEXIST) |
| 478 | 501 | err = 0; |
| 479 | 502 | } else |
| 480 | − schedule_work(&ht->run_work); | |
| 503 | + irq_work_queue(&ht->run_irq_work); | |
| 481 | 504 | |
| 482 | 505 | return err; |
| 483 | 506 | |
| @@ -488,7 +511,7 @@ fail: · 4 unmodified lines | ||
| 488 | 511 | |
| 489 | 512 | /* Schedule async rehash to retry allocation in process context. */ |
| 490 | 513 | if (err == -ENOMEM) |
| 491 | − schedule_work(&ht->run_work); | |
| 514 | + irq_work_queue(&ht->run_irq_work); | |
| 492 | 515 | |
| 493 | 516 | return err; |
| 494 | 517 | } |
| @@ -538,7 +561,7 @@ static void *rhashtable_lookup_one(struct rhashtable *ht, · 43 unmodified lines | ||
| 538 | 561 | return NULL; |
| 539 | 562 | } |
| 540 | 563 | |
| 541 | − if (elasticity <= 0) | |
| 564 | + if (elasticity <= 0 && !ht->p.insecure_elasticity) | |
| 542 | 565 | return ERR_PTR(-EAGAIN); |
| 543 | 566 | |
| 544 | 567 | return ERR_PTR(-ENOENT); |
| @@ -568,7 +591,8 @@ static struct bucket_table *rhashtable_insert_one( · 23 unmodified lines | ||
| 568 | 591 | if (unlikely(rht_grow_above_max(ht, tbl))) |
| 569 | 592 | return ERR_PTR(-E2BIG); |
| 570 | 593 | |
| 571 | − if (unlikely(rht_grow_above_100(ht, tbl))) | |
| 594 | + if (unlikely(rht_grow_above_100(ht, tbl)) && | |
| 595 | + !ht->p.insecure_elasticity) | |
| 572 | 596 | return ERR_PTR(-EAGAIN); |
| 573 | 597 | |
| 574 | 598 | head = rht_ptr(bkt, tbl, hash); |
| @@ -629,7 +653,7 @@ static void *rhashtable_try_insert(struct rhashtable *ht, const void *key, · 54 unmodified lines | ||
| 629 | 653 | rht_unlock(tbl, bkt, flags); |
| 630 | 654 | |
| 631 | 655 | if (inserted && rht_grow_above_75(ht, tbl)) |
| 632 | − schedule_work(&ht->run_work); | |
| 656 | + irq_work_queue(&ht->run_irq_work); | |
| 633 | 657 | } |
| 634 | 658 | } while (!IS_ERR_OR_NULL(new_tbl)); |
| 635 | 659 | |
| @@ -1084,6 +1108,7 @@ int rhashtable_init_noprof(struct rhashtable *ht, · 448 unmodified lines | ||
| 1084 | 1108 | RCU_INIT_POINTER(ht->tbl, tbl); |
| 1085 | 1109 | |
| 1086 | 1110 | INIT_WORK(&ht->run_work, rht_deferred_worker); |
| 1111 | + init_irq_work(&ht->run_irq_work, rht_deferred_irq_work); | |
| 1087 | 1112 | |
| 1088 | 1113 | return 0; |
| 1089 | 1114 | } |
| @@ -1149,6 +1174,7 @@ void rhashtable_free_and_destroy(struct rhashtable *ht, · 59 unmodified lines | ||
| 1149 | 1174 | struct bucket_table *tbl, *next_tbl; |
| 1150 | 1175 | unsigned int i; |
| 1151 | 1176 | |
| 1177 | + irq_work_sync(&ht->run_irq_work); | |
| 1152 | 1178 | cancel_work_sync(&ht->run_work); |
| 1153 | 1179 | |
| 1154 | 1180 | mutex_lock(&ht->mutex); |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * test_maple_tree.c: Test the maple tree API |
| 4 | 4 | * Copyright (c) 2018-2022 Oracle Corporation |
| 5 | − * Author: Liam R. Howlett <Liam.Howlett@Oracle.com> | |
| 5 | + * Author: Liam R. Howlett <liam@infradead.org> | |
| 6 | 6 | * |
| 7 | 7 | * Any tests that only require the interface of the tree. |
| 8 | 8 | */ |
| @@ -4021,6 +4021,6 @@ static void __exit maple_tree_harvest(void) · 4012 unmodified lines | ||
| 4021 | 4021 | |
| 4022 | 4022 | module_init(maple_tree_seed); |
| 4023 | 4023 | module_exit(maple_tree_harvest); |
| 4024 | −MODULE_AUTHOR("Liam R. Howlett <Liam.Howlett@Oracle.com>"); | |
| 4024 | +MODULE_AUTHOR("Liam R. Howlett <liam@infradead.org>"); | |
| 4025 | 4025 | MODULE_DESCRIPTION("maple tree API test module"); |
| 4026 | 4026 | MODULE_LICENSE("GPL"); |
| @@ -161,15 +161,6 @@ module_param(monitor_region_end, ulong, 0600); · 160 unmodified lines | ||
| 161 | 161 | */ |
| 162 | 162 | static unsigned long addr_unit __read_mostly = 1; |
| 163 | 163 | |
| 164 | −/* | |
| 165 | − * PID of the DAMON thread | |
| 166 | − * | |
| 167 | − * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread. | |
| 168 | − * Else, -1. | |
| 169 | − */ | |
| 170 | −static int kdamond_pid __read_mostly = -1; | |
| 171 | −module_param(kdamond_pid, int, 0400); | |
| 172 | − | |
| 173 | 164 | static struct damos_stat damon_lru_sort_hot_stat; |
| 174 | 165 | DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat, |
| 175 | 166 | lru_sort_tried_hot_regions, lru_sorted_hot_regions, |
| @@ -386,12 +377,8 @@ static int damon_lru_sort_turn(bool on) · 210 unmodified lines | ||
| 386 | 377 | { |
| 387 | 378 | int err; |
| 388 | 379 | |
| 389 | − if (!on) { | |
| 390 | − err = damon_stop(&ctx, 1); | |
| 391 | − if (!err) | |
| 392 | − kdamond_pid = -1; | |
| 393 | − return err; | |
| 394 | − } | |
| 380 | + if (!on) | |
| 381 | + return damon_stop(&ctx, 1); | |
| 395 | 382 | |
| 396 | 383 | err = damon_lru_sort_apply_parameters(); |
| 397 | 384 | if (err) |
| @@ -400,9 +387,6 @@ static int damon_lru_sort_turn(bool on) · 2 unmodified lines | ||
| 400 | 387 | err = damon_start(&ctx, 1, true); |
| 401 | 388 | if (err) |
| 402 | 389 | return err; |
| 403 | − kdamond_pid = damon_kdamond_pid(ctx); | |
| 404 | − if (kdamond_pid < 0) | |
| 405 | − return kdamond_pid; | |
| 406 | 390 | return damon_call(ctx, &call_control); |
| 407 | 391 | } |
| 408 | 392 | |
| @@ -430,42 +414,83 @@ module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600); · 21 unmodified lines | ||
| 430 | 414 | MODULE_PARM_DESC(addr_unit, |
| 431 | 415 | "Scale factor for DAMON_LRU_SORT to ops address conversion (default: 1)"); |
| 432 | 416 | |
| 417 | +static bool damon_lru_sort_enabled(void) | |
| 418 | +{ | |
| 419 | + if (!ctx) | |
| 420 | + return false; | |
| 421 | + return damon_is_running(ctx); | |
| 422 | +} | |
| 423 | + | |
| 433 | 424 | static int damon_lru_sort_enabled_store(const char *val, |
| 434 | 425 | const struct kernel_param *kp) |
| 435 | 426 | { |
| 436 | − bool is_enabled = enabled; | |
| 437 | − bool enable; | |
| 438 | 427 | int err; |
| 439 | 428 | |
| 440 | − err = kstrtobool(val, &enable); | |
| 429 | + err = kstrtobool(val, &enabled); | |
| 441 | 430 | if (err) |
| 442 | 431 | return err; |
| 443 | 432 | |
| 444 | − if (is_enabled == enable) | |
| 433 | + if (damon_lru_sort_enabled() == enabled) | |
| 445 | 434 | return 0; |
| 446 | 435 | |
| 447 | 436 | /* Called before init function. The function will handle this. */ |
| 448 | 437 | if (!damon_initialized()) |
| 449 | − goto set_param_out; | |
| 438 | + return 0; | |
| 450 | 439 | |
| 451 | − err = damon_lru_sort_turn(enable); | |
| 452 | − if (err) | |
| 453 | − return err; | |
| 440 | + return damon_lru_sort_turn(enabled); | |
| 441 | +} | |
| 454 | 442 | |
| 455 | −set_param_out: | |
| 456 | − enabled = enable; | |
| 457 | − return err; | |
| 443 | +static int damon_lru_sort_enabled_load(char *buffer, | |
| 444 | + const struct kernel_param *kp) | |
| 445 | +{ | |
| 446 | + return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N'); | |
| 458 | 447 | } |
| 459 | 448 | |
| 460 | 449 | static const struct kernel_param_ops enabled_param_ops = { |
| 461 | 450 | .set = damon_lru_sort_enabled_store, |
| 462 | − .get = param_get_bool, | |
| 451 | + .get = damon_lru_sort_enabled_load, | |
| 463 | 452 | }; |
| 464 | 453 | |
| 465 | 454 | module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); |
| 466 | 455 | MODULE_PARM_DESC(enabled, |
| 467 | 456 | "Enable or disable DAMON_LRU_SORT (default: disabled)"); |
| 468 | 457 | |
| 458 | +static int damon_lru_sort_kdamond_pid_store(const char *val, | |
| 459 | + const struct kernel_param *kp) | |
| 460 | +{ | |
| 461 | + /* | |
| 462 | + * kdamond_pid is read-only, but kernel command line could write it. | |
| 463 | + * Do nothing here. | |
| 464 | + */ | |
| 465 | + return 0; | |
| 466 | +} | |
| 467 | + | |
| 468 | +static int damon_lru_sort_kdamond_pid_load(char *buffer, | |
| 469 | + const struct kernel_param *kp) | |
| 470 | +{ | |
| 471 | + int kdamond_pid = -1; | |
| 472 | + | |
| 473 | + if (ctx) { | |
| 474 | + kdamond_pid = damon_kdamond_pid(ctx); | |
| 475 | + if (kdamond_pid < 0) | |
| 476 | + kdamond_pid = -1; | |
| 477 | + } | |
| 478 | + return sprintf(buffer, "%d\n", kdamond_pid); | |
| 479 | +} | |
| 480 | + | |
| 481 | +static const struct kernel_param_ops kdamond_pid_param_ops = { | |
| 482 | + .set = damon_lru_sort_kdamond_pid_store, | |
| 483 | + .get = damon_lru_sort_kdamond_pid_load, | |
| 484 | +}; | |
| 485 | + | |
| 486 | +/* | |
| 487 | + * PID of the DAMON thread | |
| 488 | + * | |
| 489 | + * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread. | |
| 490 | + * Else, -1. | |
| 491 | + */ | |
| 492 | +module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400); | |
| 493 | + | |
| 469 | 494 | static int __init damon_lru_sort_init(void) |
| 470 | 495 | { |
| 471 | 496 | int err; |
| @@ -144,15 +144,6 @@ static unsigned long addr_unit __read_mostly = 1; · 143 unmodified lines | ||
| 144 | 144 | static bool skip_anon __read_mostly; |
| 145 | 145 | module_param(skip_anon, bool, 0600); |
| 146 | 146 | |
| 147 | −/* | |
| 148 | − * PID of the DAMON thread | |
| 149 | − * | |
| 150 | − * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread. | |
| 151 | − * Else, -1. | |
| 152 | − */ | |
| 153 | −static int kdamond_pid __read_mostly = -1; | |
| 154 | −module_param(kdamond_pid, int, 0400); | |
| 155 | − | |
| 156 | 147 | static struct damos_stat damon_reclaim_stat; |
| 157 | 148 | DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat, |
| 158 | 149 | reclaim_tried_regions, reclaimed_regions, quota_exceeds); |
| @@ -288,12 +279,8 @@ static int damon_reclaim_turn(bool on) · 129 unmodified lines | ||
| 288 | 279 | { |
| 289 | 280 | int err; |
| 290 | 281 | |
| 291 | − if (!on) { | |
| 292 | − err = damon_stop(&ctx, 1); | |
| 293 | − if (!err) | |
| 294 | − kdamond_pid = -1; | |
| 295 | − return err; | |
| 296 | − } | |
| 282 | + if (!on) | |
| 283 | + return damon_stop(&ctx, 1); | |
| 297 | 284 | |
| 298 | 285 | err = damon_reclaim_apply_parameters(); |
| 299 | 286 | if (err) |
| @@ -302,9 +289,6 @@ static int damon_reclaim_turn(bool on) · 2 unmodified lines | ||
| 302 | 289 | err = damon_start(&ctx, 1, true); |
| 303 | 290 | if (err) |
| 304 | 291 | return err; |
| 305 | − kdamond_pid = damon_kdamond_pid(ctx); | |
| 306 | − if (kdamond_pid < 0) | |
| 307 | − return kdamond_pid; | |
| 308 | 292 | return damon_call(ctx, &call_control); |
| 309 | 293 | } |
| 310 | 294 | |
| @@ -332,42 +316,83 @@ module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600); · 21 unmodified lines | ||
| 332 | 316 | MODULE_PARM_DESC(addr_unit, |
| 333 | 317 | "Scale factor for DAMON_RECLAIM to ops address conversion (default: 1)"); |
| 334 | 318 | |
| 319 | +static bool damon_reclaim_enabled(void) | |
| 320 | +{ | |
| 321 | + if (!ctx) | |
| 322 | + return false; | |
| 323 | + return damon_is_running(ctx); | |
| 324 | +} | |
| 325 | + | |
| 335 | 326 | static int damon_reclaim_enabled_store(const char *val, |
| 336 | 327 | const struct kernel_param *kp) |
| 337 | 328 | { |
| 338 | − bool is_enabled = enabled; | |
| 339 | − bool enable; | |
| 340 | 329 | int err; |
| 341 | 330 | |
| 342 | − err = kstrtobool(val, &enable); | |
| 331 | + err = kstrtobool(val, &enabled); | |
| 343 | 332 | if (err) |
| 344 | 333 | return err; |
| 345 | 334 | |
| 346 | − if (is_enabled == enable) | |
| 335 | + if (damon_reclaim_enabled() == enabled) | |
| 347 | 336 | return 0; |
| 348 | 337 | |
| 349 | 338 | /* Called before init function. The function will handle this. */ |
| 350 | 339 | if (!damon_initialized()) |
| 351 | − goto set_param_out; | |
| 340 | + return 0; | |
| 352 | 341 | |
| 353 | − err = damon_reclaim_turn(enable); | |
| 354 | − if (err) | |
| 355 | − return err; | |
| 342 | + return damon_reclaim_turn(enabled); | |
| 343 | +} | |
| 356 | 344 | |
| 357 | −set_param_out: | |
| 358 | − enabled = enable; | |
| 359 | − return err; | |
| 345 | +static int damon_reclaim_enabled_load(char *buffer, | |
| 346 | + const struct kernel_param *kp) | |
| 347 | +{ | |
| 348 | + return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N'); | |
| 360 | 349 | } |
| 361 | 350 | |
| 362 | 351 | static const struct kernel_param_ops enabled_param_ops = { |
| 363 | 352 | .set = damon_reclaim_enabled_store, |
| 364 | − .get = param_get_bool, | |
| 353 | + .get = damon_reclaim_enabled_load, | |
| 365 | 354 | }; |
| 366 | 355 | |
| 367 | 356 | module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); |
| 368 | 357 | MODULE_PARM_DESC(enabled, |
| 369 | 358 | "Enable or disable DAMON_RECLAIM (default: disabled)"); |
| 370 | 359 | |
| 360 | +static int damon_reclaim_kdamond_pid_store(const char *val, | |
| 361 | + const struct kernel_param *kp) | |
| 362 | +{ | |
| 363 | + /* | |
| 364 | + * kdamond_pid is read-only, but kernel command line could write it. | |
| 365 | + * Do nothing here. | |
| 366 | + */ | |
| 367 | + return 0; | |
| 368 | +} | |
| 369 | + | |
| 370 | +static int damon_reclaim_kdamond_pid_load(char *buffer, | |
| 371 | + const struct kernel_param *kp) | |
| 372 | +{ | |
| 373 | + int kdamond_pid = -1; | |
| 374 | + | |
| 375 | + if (ctx) { | |
| 376 | + kdamond_pid = damon_kdamond_pid(ctx); | |
| 377 | + if (kdamond_pid < 0) | |
| 378 | + kdamond_pid = -1; | |
| 379 | + } | |
| 380 | + return sprintf(buffer, "%d\n", kdamond_pid); | |
| 381 | +} | |
| 382 | + | |
| 383 | +static const struct kernel_param_ops kdamond_pid_param_ops = { | |
| 384 | + .set = damon_reclaim_kdamond_pid_store, | |
| 385 | + .get = damon_reclaim_kdamond_pid_load, | |
| 386 | +}; | |
| 387 | + | |
| 388 | +/* | |
| 389 | + * PID of the DAMON thread | |
| 390 | + * | |
| 391 | + * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread. | |
| 392 | + * Else, -1. | |
| 393 | + */ | |
| 394 | +module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400); | |
| 395 | + | |
| 371 | 396 | static int __init damon_reclaim_init(void) |
| 372 | 397 | { |
| 373 | 398 | int err; |
| @@ -19,14 +19,17 @@ · 18 unmodified lines | ||
| 19 | 19 | static int damon_stat_enabled_store( |
| 20 | 20 | const char *val, const struct kernel_param *kp); |
| 21 | 21 | |
| 22 | +static int damon_stat_enabled_load(char *buffer, | |
| 23 | + const struct kernel_param *kp); | |
| 24 | + | |
| 22 | 25 | static const struct kernel_param_ops enabled_param_ops = { |
| 23 | 26 | .set = damon_stat_enabled_store, |
| 24 | − .get = param_get_bool, | |
| 27 | + .get = damon_stat_enabled_load, | |
| 25 | 28 | }; |
| 26 | 29 | |
| 27 | 30 | static bool enabled __read_mostly = IS_ENABLED( |
| 28 | 31 | CONFIG_DAMON_STAT_ENABLED_DEFAULT); |
| 29 | −module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); | |
| 32 | +module_param_cb(enabled, &enabled_param_ops, NULL, 0600); | |
| 30 | 33 | MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT"); |
| 31 | 34 | |
| 32 | 35 | static unsigned long estimated_memory_bandwidth __read_mostly; |
| @@ -273,17 +276,23 @@ static void damon_stat_stop(void) · 240 unmodified lines | ||
| 273 | 276 | damon_stat_context = NULL; |
| 274 | 277 | } |
| 275 | 278 | |
| 279 | +static bool damon_stat_enabled(void) | |
| 280 | +{ | |
| 281 | + if (!damon_stat_context) | |
| 282 | + return false; | |
| 283 | + return damon_is_running(damon_stat_context); | |
| 284 | +} | |
| 285 | + | |
| 276 | 286 | static int damon_stat_enabled_store( |
| 277 | 287 | const char *val, const struct kernel_param *kp) |
| 278 | 288 | { |
| 279 | − bool is_enabled = enabled; | |
| 280 | 289 | int err; |
| 281 | 290 | |
| 282 | 291 | err = kstrtobool(val, &enabled); |
| 283 | 292 | if (err) |
| 284 | 293 | return err; |
| 285 | 294 | |
| 286 | − if (is_enabled == enabled) | |
| 295 | + if (damon_stat_enabled() == enabled) | |
| 287 | 296 | return 0; |
| 288 | 297 | |
| 289 | 298 | if (!damon_initialized()) |
| @@ -293,16 +302,17 @@ static int damon_stat_enabled_store( · 3 unmodified lines | ||
| 293 | 302 | */ |
| 294 | 303 | return 0; |
| 295 | 304 | |
| 296 | − if (enabled) { | |
| 297 | − err = damon_stat_start(); | |
| 298 | − if (err) | |
| 299 | − enabled = false; | |
| 300 | − return err; | |
| 301 | − } | |
| 305 | + if (enabled) | |
| 306 | + return damon_stat_start(); | |
| 302 | 307 | damon_stat_stop(); |
| 303 | 308 | return 0; |
| 304 | 309 | } |
| 305 | 310 | |
| 311 | +static int damon_stat_enabled_load(char *buffer, const struct kernel_param *kp) | |
| 312 | +{ | |
| 313 | + return sprintf(buffer, "%c\n", damon_stat_enabled() ? 'Y' : 'N'); | |
| 314 | +} | |
| 315 | + | |
| 306 | 316 | static int __init damon_stat_init(void) |
| 307 | 317 | { |
| 308 | 318 | int err = 0; |
| @@ -533,9 +533,14 @@ static ssize_t memcg_path_show(struct kobject *kobj, · 532 unmodified lines | ||
| 533 | 533 | { |
| 534 | 534 | struct damon_sysfs_scheme_filter *filter = container_of(kobj, |
| 535 | 535 | struct damon_sysfs_scheme_filter, kobj); |
| 536 | + int len; | |
| 536 | 537 | |
| 537 | − return sysfs_emit(buf, "%s\n", | |
| 538 | + if (!mutex_trylock(&damon_sysfs_lock)) | |
| 539 | + return -EBUSY; | |
| 540 | + len = sysfs_emit(buf, "%s\n", | |
| 538 | 541 | filter->memcg_path ? filter->memcg_path : ""); |
| 542 | + mutex_unlock(&damon_sysfs_lock); | |
| 543 | + return len; | |
| 539 | 544 | } |
| 540 | 545 | |
| 541 | 546 | static ssize_t memcg_path_store(struct kobject *kobj, |
| @@ -550,8 +555,13 @@ static ssize_t memcg_path_store(struct kobject *kobj, · 8 unmodified lines | ||
| 550 | 555 | return -ENOMEM; |
| 551 | 556 | |
| 552 | 557 | strscpy(path, buf, count + 1); |
| 558 | + if (!mutex_trylock(&damon_sysfs_lock)) { | |
| 559 | + kfree(path); | |
| 560 | + return -EBUSY; | |
| 561 | + } | |
| 553 | 562 | kfree(filter->memcg_path); |
| 554 | 563 | filter->memcg_path = path; |
| 564 | + mutex_unlock(&damon_sysfs_lock); | |
| 555 | 565 | return count; |
| 556 | 566 | } |
| 557 | 567 | |
| @@ -1187,8 +1197,13 @@ static ssize_t path_show(struct kobject *kobj, · 629 unmodified lines | ||
| 1187 | 1197 | { |
| 1188 | 1198 | struct damos_sysfs_quota_goal *goal = container_of(kobj, |
| 1189 | 1199 | struct damos_sysfs_quota_goal, kobj); |
| 1200 | + int len; | |
| 1190 | 1201 | |
| 1191 | − return sysfs_emit(buf, "%s\n", goal->path ? goal->path : ""); | |
| 1202 | + if (!mutex_trylock(&damon_sysfs_lock)) | |
| 1203 | + return -EBUSY; | |
| 1204 | + len = sysfs_emit(buf, "%s\n", goal->path ? goal->path : ""); | |
| 1205 | + mutex_unlock(&damon_sysfs_lock); | |
| 1206 | + return len; | |
| 1192 | 1207 | } |
| 1193 | 1208 | |
| 1194 | 1209 | static ssize_t path_store(struct kobject *kobj, |
| @@ -1203,8 +1218,13 @@ static ssize_t path_store(struct kobject *kobj, · 8 unmodified lines | ||
| 1203 | 1218 | return -ENOMEM; |
| 1204 | 1219 | |
| 1205 | 1220 | strscpy(path, buf, count + 1); |
| 1221 | + if (!mutex_trylock(&damon_sysfs_lock)) { | |
| 1222 | + kfree(path); | |
| 1223 | + return -EBUSY; | |
| 1224 | + } | |
| 1206 | 1225 | kfree(goal->path); |
| 1207 | 1226 | goal->path = path; |
| 1227 | + mutex_unlock(&damon_sysfs_lock); | |
| 1208 | 1228 | return count; |
| 1209 | 1229 | } |
| 1210 | 1230 | |
| @@ -204,6 +204,7 @@ void __init hugetlb_cma_reserve(void) · 203 unmodified lines | ||
| 204 | 204 | */ |
| 205 | 205 | per_node = DIV_ROUND_UP(hugetlb_cma_size, |
| 206 | 206 | nodes_weight(hugetlb_bootmem_nodes)); |
| 207 | + per_node = round_up(per_node, PAGE_SIZE << order); | |
| 207 | 208 | pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n", |
| 208 | 209 | hugetlb_cma_size / SZ_1M, per_node / SZ_1M); |
| 209 | 210 | } |
| @@ -805,12 +805,17 @@ static long memcg_state_val_in_pages(int idx, long val) · 804 unmodified lines | ||
| 805 | 805 | * Used in mod_memcg_state() and mod_memcg_lruvec_state() to avoid race with |
| 806 | 806 | * reparenting of non-hierarchical state_locals. |
| 807 | 807 | */ |
| 808 | −static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg) | |
| 808 | +static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg, | |
| 809 | + bool *rcu_locked) | |
| 809 | 810 | { |
| 810 | − if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) | |
| 811 | + /* Rebinding can cause this value to be changed at runtime */ | |
| 812 | + if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) { | |
| 813 | + *rcu_locked = false; | |
| 811 | 814 | return memcg; |
| 815 | + } | |
| 812 | 816 | |
| 813 | 817 | rcu_read_lock(); |
| 818 | + *rcu_locked = true; | |
| 814 | 819 | |
| 815 | 820 | while (memcg_is_dying(memcg)) |
| 816 | 821 | memcg = parent_mem_cgroup(memcg); |
| @@ -818,20 +823,21 @@ static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *me · 1 unmodified line | ||
| 818 | 823 | return memcg; |
| 819 | 824 | } |
| 820 | 825 | |
| 821 | −static inline void get_non_dying_memcg_end(void) | |
| 826 | +static inline void get_non_dying_memcg_end(bool rcu_locked) | |
| 822 | 827 | { |
| 823 | − if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) | |
| 828 | + if (!rcu_locked) | |
| 824 | 829 | return; |
| 825 | 830 | |
| 826 | 831 | rcu_read_unlock(); |
| 827 | 832 | } |
| 828 | 833 | #else |
| 829 | −static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg) | |
| 834 | +static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg, | |
| 835 | + bool *rcu_locked) | |
| 830 | 836 | { |
| 831 | 837 | return memcg; |
| 832 | 838 | } |
| 833 | 839 | |
| 834 | −static inline void get_non_dying_memcg_end(void) | |
| 840 | +static inline void get_non_dying_memcg_end(bool rcu_locked) | |
| 835 | 841 | { |
| 836 | 842 | } |
| 837 | 843 | #endif |
| @@ -865,12 +871,14 @@ static void __mod_memcg_state(struct mem_cgroup *memcg, · 27 unmodified lines | ||
| 865 | 871 | void mod_memcg_state(struct mem_cgroup *memcg, enum memcg_stat_item idx, |
| 866 | 872 | int val) |
| 867 | 873 | { |
| 874 | + bool rcu_locked = false; | |
| 875 | + | |
| 868 | 876 | if (mem_cgroup_disabled()) |
| 869 | 877 | return; |
| 870 | 878 | |
| 871 | − memcg = get_non_dying_memcg_start(memcg); | |
| 879 | + memcg = get_non_dying_memcg_start(memcg, &rcu_locked); | |
| 872 | 880 | __mod_memcg_state(memcg, idx, val); |
| 873 | − get_non_dying_memcg_end(); | |
| 881 | + get_non_dying_memcg_end(rcu_locked); | |
| 874 | 882 | } |
| 875 | 883 | |
| 876 | 884 | #ifdef CONFIG_MEMCG_V1 |
| @@ -933,14 +941,15 @@ static void mod_memcg_lruvec_state(struct lruvec *lruvec, · 56 unmodified lines | ||
| 933 | 941 | struct pglist_data *pgdat = lruvec_pgdat(lruvec); |
| 934 | 942 | struct mem_cgroup_per_node *pn; |
| 935 | 943 | struct mem_cgroup *memcg; |
| 944 | + bool rcu_locked = false; | |
| 936 | 945 | |
| 937 | 946 | pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); |
| 938 | − memcg = get_non_dying_memcg_start(pn->memcg); | |
| 947 | + memcg = get_non_dying_memcg_start(pn->memcg, &rcu_locked); | |
| 939 | 948 | pn = memcg->nodeinfo[pgdat->node_id]; |
| 940 | 949 | |
| 941 | 950 | __mod_memcg_lruvec_state(pn, idx, val); |
| 942 | 951 | |
| 943 | − get_non_dying_memcg_end(); | |
| 952 | + get_non_dying_memcg_end(rcu_locked); | |
| 944 | 953 | } |
| 945 | 954 | |
| 946 | 955 | /** |
| @@ -1835,7 +1835,9 @@ static int balance_dirty_pages(struct bdi_writeback *wb, · 1834 unmodified lines | ||
| 1835 | 1835 | balance_domain_limits(mdtc, strictlimit); |
| 1836 | 1836 | } |
| 1837 | 1837 | |
| 1838 | − if (nr_dirty > gdtc->bg_thresh && !writeback_in_progress(wb)) | |
| 1838 | + if (!writeback_in_progress(wb) && | |
| 1839 | + (nr_dirty > gdtc->bg_thresh || | |
| 1840 | + (strictlimit && gdtc->wb_dirty > gdtc->wb_bg_thresh))) | |
| 1839 | 1841 | wb_start_background_writeback(wb); |
| 1840 | 1842 | |
| 1841 | 1843 | /* |
| @@ -1862,15 +1864,9 @@ free_running: · 20 unmodified lines | ||
| 1862 | 1864 | * Unconditionally start background writeback if it's not |
| 1863 | 1865 | * already in progress. We need to do this because the global |
| 1864 | 1866 | * dirty threshold check above (nr_dirty > gdtc->bg_thresh) |
| 1865 | − * doesn't account for these cases: | |
| 1866 | − * | |
| 1867 | − * a) strictlimit BDIs: throttling is calculated using per-wb | |
| 1868 | − * thresholds. The per-wb threshold can be exceeded even when | |
| 1869 | − * nr_dirty < gdtc->bg_thresh | |
| 1870 | − * | |
| 1871 | − * b) memcg-based throttling: memcg uses its own dirty count and | |
| 1872 | − * thresholds and can trigger throttling even when global | |
| 1873 | − * nr_dirty < gdtc->bg_thresh | |
| 1867 | + * doesn't account for the memcg-based throttling case. memcg | |
| 1868 | + * uses its own dirty count and thresholds and can trigger | |
| 1869 | + * throttling even when global nr_dirty < gdtc->bg_thresh | |
| 1874 | 1870 | * |
| 1875 | 1871 | * Writeback needs to be started else the writer stalls in the |
| 1876 | 1872 | * throttle loop waiting for dirty pages to be written back |
| @@ -7737,6 +7737,11 @@ struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned · 7736 unmodified lines | ||
| 7737 | 7737 | */ |
| 7738 | 7738 | if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) |
| 7739 | 7739 | return NULL; |
| 7740 | + | |
| 7741 | + /* On UP, spin_trylock() always succeeds even when it is locked */ | |
| 7742 | + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) | |
| 7743 | + return NULL; | |
| 7744 | + | |
| 7740 | 7745 | if (!pcp_allowed_order(order)) |
| 7741 | 7746 | return NULL; |
| 7742 | 7747 | |
| @@ -5339,6 +5339,10 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) · 5338 unmodified lines | ||
| 5339 | 5339 | if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) |
| 5340 | 5340 | return NULL; |
| 5341 | 5341 | |
| 5342 | + /* On UP, spin_trylock() always succeeds even when it is locked */ | |
| 5343 | + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) | |
| 5344 | + return NULL; | |
| 5345 | + | |
| 5342 | 5346 | retry: |
| 5343 | 5347 | if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) |
| 5344 | 5348 | return NULL; |
| @@ -443,8 +443,10 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr) · 442 unmodified lines | ||
| 443 | 443 | return ret; |
| 444 | 444 | } |
| 445 | 445 | |
| 446 | −static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio) | |
| 446 | +static int mfill_copy_folio_retry(struct mfill_state *state, | |
| 447 | + struct folio *folio) | |
| 447 | 448 | { |
| 449 | + const struct vm_uffd_ops *orig_ops = vma_uffd_ops(state->vma); | |
| 448 | 450 | unsigned long src_addr = state->src_addr; |
| 449 | 451 | void *kaddr; |
| 450 | 452 | int err; |
| @@ -465,6 +467,14 @@ static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio · 14 unmodified lines | ||
| 465 | 467 | if (err) |
| 466 | 468 | return err; |
| 467 | 469 | |
| 470 | + /* | |
| 471 | + * The VMA type may have changed while the lock was dropped | |
| 472 | + * (e.g. replaced with a hugetlb mapping), making the caller's | |
| 473 | + * ops pointer stale. | |
| 474 | + */ | |
| 475 | + if (vma_uffd_ops(state->vma) != orig_ops) | |
| 476 | + return -EAGAIN; | |
| 477 | + | |
| 468 | 478 | err = mfill_establish_pmd(state); |
| 469 | 479 | if (err) |
| 470 | 480 | return err; |
| @@ -1232,7 +1232,7 @@ int __compat_vma_mmap(struct vm_area_desc *desc, · 1231 unmodified lines | ||
| 1232 | 1232 | /* Update the VMA from the descriptor. */ |
| 1233 | 1233 | compat_set_vma_from_desc(vma, desc); |
| 1234 | 1234 | /* Complete any specified mmap actions. */ |
| 1235 | − return mmap_action_complete(vma, &desc->action); | |
| 1235 | + return mmap_action_complete(vma, &desc->action, /*is_compat=*/true); | |
| 1236 | 1236 | } |
| 1237 | 1237 | EXPORT_SYMBOL(__compat_vma_mmap); |
| 1238 | 1238 | |
| @@ -1389,7 +1389,8 @@ static int call_vma_mapped(struct vm_area_struct *vma) · 150 unmodified lines | ||
| 1389 | 1389 | } |
| 1390 | 1390 | |
| 1391 | 1391 | static int mmap_action_finish(struct vm_area_struct *vma, |
| 1392 | − struct mmap_action *action, int err) | |
| 1392 | + struct mmap_action *action, int err, | |
| 1393 | + bool is_compat) | |
| 1393 | 1394 | { |
| 1394 | 1395 | size_t len; |
| 1395 | 1396 | |
| @@ -1400,8 +1401,12 @@ static int mmap_action_finish(struct vm_area_struct *vma, · 4 unmodified lines | ||
| 1400 | 1401 | |
| 1401 | 1402 | /* do_munmap() might take rmap lock, so release if held. */ |
| 1402 | 1403 | maybe_rmap_unlock_action(vma, action); |
| 1403 | − if (!err) | |
| 1404 | − return 0; | |
| 1404 | + /* | |
| 1405 | + * If this is invoked from the compatibility layer, post-mmap() hook | |
| 1406 | + * logic will handle cleanup for us. | |
| 1407 | + */ | |
| 1408 | + if (!err || is_compat) | |
| 1409 | + return err; | |
| 1405 | 1410 | |
| 1406 | 1411 | /* |
| 1407 | 1412 | * If an error occurs, unmap the VMA altogether and return an error. We |
| @@ -1451,13 +1456,15 @@ EXPORT_SYMBOL(mmap_action_prepare); · 43 unmodified lines | ||
| 1451 | 1456 | * mmap_action_complete - Execute VMA descriptor action. |
| 1452 | 1457 | * @vma: The VMA to perform the action upon. |
| 1453 | 1458 | * @action: The action to perform. |
| 1459 | + * @is_compat: Is this being invoked from the compatibility layer? | |
| 1454 | 1460 | * |
| 1455 | 1461 | * Similar to mmap_action_prepare(). |
| 1456 | 1462 | * |
| 1457 | − * Return: 0 on success, or error, at which point the VMA will be unmapped. | |
| 1463 | + * Return: 0 on success, or error, at which point the VMA will be unmapped if | |
| 1464 | + * !@is_compat. | |
| 1458 | 1465 | */ |
| 1459 | 1466 | int mmap_action_complete(struct vm_area_struct *vma, |
| 1460 | − struct mmap_action *action) | |
| 1467 | + struct mmap_action *action, bool is_compat) | |
| 1461 | 1468 | { |
| 1462 | 1469 | int err = 0; |
| 1463 | 1470 | |
| @@ -1478,7 +1485,7 @@ int mmap_action_complete(struct vm_area_struct *vma, · 14 unmodified lines | ||
| 1478 | 1485 | break; |
| 1479 | 1486 | } |
| 1480 | 1487 | |
| 1481 | − return mmap_action_finish(vma, action, err); | |
| 1488 | + return mmap_action_finish(vma, action, err, is_compat); | |
| 1482 | 1489 | } |
| 1483 | 1490 | EXPORT_SYMBOL(mmap_action_complete); |
| 1484 | 1491 | #else |
| @@ -1500,7 +1507,8 @@ int mmap_action_prepare(struct vm_area_desc *desc) · 15 unmodified lines | ||
| 1500 | 1507 | EXPORT_SYMBOL(mmap_action_prepare); |
| 1501 | 1508 | |
| 1502 | 1509 | int mmap_action_complete(struct vm_area_struct *vma, |
| 1503 | − struct mmap_action *action) | |
| 1510 | + struct mmap_action *action, | |
| 1511 | + bool is_compat) | |
| 1504 | 1512 | { |
| 1505 | 1513 | int err = 0; |
| 1506 | 1514 | |
| @@ -1517,7 +1525,7 @@ int mmap_action_complete(struct vm_area_struct *vma, · 10 unmodified lines | ||
| 1517 | 1525 | break; |
| 1518 | 1526 | } |
| 1519 | 1527 | |
| 1520 | − return mmap_action_finish(vma, action, err); | |
| 1528 | + return mmap_action_finish(vma, action, err, is_compat); | |
| 1521 | 1529 | } |
| 1522 | 1530 | EXPORT_SYMBOL(mmap_action_complete); |
| 1523 | 1531 | #endif |
| @@ -2780,7 +2780,8 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, · 2779 unmodified lines | ||
| 2780 | 2780 | __mmap_complete(&map, vma); |
| 2781 | 2781 | |
| 2782 | 2782 | if (have_mmap_prepare && allocated_new) { |
| 2783 | − error = mmap_action_complete(vma, &desc.action); | |
| 2783 | + error = mmap_action_complete(vma, &desc.action, | |
| 2784 | + /*is_compat=*/false); | |
| 2784 | 2785 | if (error) |
| 2785 | 2786 | return error; |
| 2786 | 2787 | } |
| @@ -4361,7 +4361,7 @@ need_realloc: · 4360 unmodified lines | ||
| 4361 | 4361 | return NULL; |
| 4362 | 4362 | |
| 4363 | 4363 | if (p) { |
| 4364 | − memcpy(n, p, old_size); | |
| 4364 | + memcpy(n, p, min(size, old_size)); | |
| 4365 | 4365 | vfree(p); |
| 4366 | 4366 | } |
| 4367 | 4367 | |
| @@ -297,8 +297,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, · 296 unmodified lines | ||
| 297 | 297 | |
| 298 | 298 | for (i = 0; i < owner->area.num_niovs; i++) { |
| 299 | 299 | niov = &owner->area.niovs[i]; |
| 300 | − niov->type = NET_IOV_DMABUF; | |
| 301 | − niov->owner = &owner->area; | |
| 300 | + net_iov_init(niov, &owner->area, NET_IOV_DMABUF); | |
| 302 | 301 | page_pool_set_dma_addr_netmem(net_iov_to_netmem(niov), |
| 303 | 302 | net_devmem_get_dma_addr(niov)); |
| 304 | 303 | if (direction == DMA_TO_DEVICE) |
| @@ -3210,8 +3210,10 @@ int neigh_xmit(int index, struct net_device *dev, · 3209 unmodified lines | ||
| 3210 | 3210 | |
| 3211 | 3211 | rcu_read_lock(); |
| 3212 | 3212 | tbl = rcu_dereference(neigh_tables[index]); |
| 3213 | − if (!tbl) | |
| 3214 | − goto out_unlock; | |
| 3213 | + if (!tbl) { | |
| 3214 | + rcu_read_unlock(); | |
| 3215 | + goto out_kfree_skb; | |
| 3216 | + } | |
| 3215 | 3217 | if (index == NEIGH_ARP_TABLE) { |
| 3216 | 3218 | u32 key = *((u32 *)addr); |
| 3217 | 3219 | |
| @@ -3227,7 +3229,6 @@ int neigh_xmit(int index, struct net_device *dev, · 9 unmodified lines | ||
| 3227 | 3229 | goto out_kfree_skb; |
| 3228 | 3230 | } |
| 3229 | 3231 | err = READ_ONCE(neigh->output)(neigh, skb); |
| 3230 | −out_unlock: | |
| 3231 | 3232 | rcu_read_unlock(); |
| 3232 | 3233 | } |
| 3233 | 3234 | else if (index == NEIGH_LINK_TABLE) { |
| @@ -3237,11 +3238,10 @@ out_unlock: · 3 unmodified lines | ||
| 3237 | 3238 | goto out_kfree_skb; |
| 3238 | 3239 | err = dev_queue_xmit(skb); |
| 3239 | 3240 | } |
| 3240 | −out: | |
| 3241 | 3241 | return err; |
| 3242 | 3242 | out_kfree_skb: |
| 3243 | 3243 | kfree_skb(skb); |
| 3244 | − goto out; | |
| 3244 | + return err; | |
| 3245 | 3245 | } |
| 3246 | 3246 | EXPORT_SYMBOL(neigh_xmit); |
| 3247 | 3247 | |
| @@ -704,6 +704,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev) · 703 unmodified lines | ||
| 704 | 704 | return 0; |
| 705 | 705 | } |
| 706 | 706 | |
| 707 | +/* | |
| 708 | + * Test whether the caller left np->local_ip unset, so that | |
| 709 | + * netpoll_setup() should auto-populate it from the egress device. | |
| 710 | + * | |
| 711 | + * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), | |
| 712 | + * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, | |
| 713 | + * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — | |
| 714 | + * doing so would misclassify a caller-supplied address as unset and | |
| 715 | + * silently overwrite it with whatever address the device exposes. | |
| 716 | + */ | |
| 717 | +static bool netpoll_local_ip_unset(const struct netpoll *np) | |
| 718 | +{ | |
| 719 | + if (np->ipv6) | |
| 720 | + return ipv6_addr_any(&np->local_ip.in6); | |
| 721 | + return !np->local_ip.ip; | |
| 722 | +} | |
| 723 | + | |
| 707 | 724 | int netpoll_setup(struct netpoll *np) |
| 708 | 725 | { |
| 709 | 726 | struct net *net = current->nsproxy->net_ns; |
| @@ -747,7 +764,7 @@ int netpoll_setup(struct netpoll *np) · 37 unmodified lines | ||
| 747 | 764 | rtnl_lock(); |
| 748 | 765 | } |
| 749 | 766 | |
| 750 | − if (!np->local_ip.ip) { | |
| 767 | + if (netpoll_local_ip_unset(np)) { | |
| 751 | 768 | if (!np->ipv6) { |
| 752 | 769 | err = netpoll_take_ipv4(np, ndev); |
| 753 | 770 | if (err) |
| @@ -327,6 +327,11 @@ static void page_pool_uninit(struct page_pool *pool) · 326 unmodified lines | ||
| 327 | 327 | if (!pool->system) |
| 328 | 328 | free_percpu(pool->recycle_stats); |
| 329 | 329 | #endif |
| 330 | + | |
| 331 | + if (pool->mp_ops) { | |
| 332 | + pool->mp_ops->destroy(pool); | |
| 333 | + static_branch_dec(&page_pool_mem_providers); | |
| 334 | + } | |
| 330 | 335 | } |
| 331 | 336 | |
| 332 | 337 | /** |
| @@ -1146,11 +1151,6 @@ static void __page_pool_destroy(struct page_pool *pool) · 813 unmodified lines | ||
| 1146 | 1151 | page_pool_unlist(pool); |
| 1147 | 1152 | page_pool_uninit(pool); |
| 1148 | 1153 | |
| 1149 | − if (pool->mp_ops) { | |
| 1150 | − pool->mp_ops->destroy(pool); | |
| 1151 | − static_branch_dec(&page_pool_mem_providers); | |
| 1152 | − } | |
| 1153 | − | |
| 1154 | 1154 | kfree(pool); |
| 1155 | 1155 | } |
| 1156 | 1156 | |
| @@ -151,16 +151,6 @@ static struct mr_table *__ipmr_get_table(struct net *net, u32 id) · 150 unmodified lines | ||
| 151 | 151 | return NULL; |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | −static struct mr_table *ipmr_get_table(struct net *net, u32 id) | |
| 155 | −{ | |
| 156 | − struct mr_table *mrt; | |
| 157 | − | |
| 158 | − rcu_read_lock(); | |
| 159 | − mrt = __ipmr_get_table(net, id); | |
| 160 | − rcu_read_unlock(); | |
| 161 | − return mrt; | |
| 162 | −} | |
| 163 | − | |
| 164 | 154 | static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, |
| 165 | 155 | struct mr_table **mrt) |
| 166 | 156 | { |
| @@ -293,7 +283,7 @@ static void __net_exit ipmr_rules_exit_rtnl(struct net *net, · 126 unmodified lines | ||
| 293 | 283 | struct mr_table *mrt, *next; |
| 294 | 284 | |
| 295 | 285 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { |
| 296 | − list_del(&mrt->list); | |
| 286 | + list_del_rcu(&mrt->list); | |
| 297 | 287 | ipmr_free_table(mrt, dev_kill_list); |
| 298 | 288 | } |
| 299 | 289 | } |
| @@ -315,28 +305,30 @@ bool ipmr_rule_default(const struct fib_rule *rule) · 15 unmodified lines | ||
| 315 | 305 | } |
| 316 | 306 | EXPORT_SYMBOL(ipmr_rule_default); |
| 317 | 307 | #else |
| 318 | −#define ipmr_for_each_table(mrt, net) \ | |
| 319 | − for (mrt = net->ipv4.mrt; mrt; mrt = NULL) | |
| 320 | − | |
| 321 | 308 | static struct mr_table *ipmr_mr_table_iter(struct net *net, |
| 322 | 309 | struct mr_table *mrt) |
| 323 | 310 | { |
| 324 | 311 | if (!mrt) |
| 325 | − return net->ipv4.mrt; | |
| 312 | + return rcu_dereference(net->ipv4.mrt); | |
| 326 | 313 | return NULL; |
| 327 | 314 | } |
| 328 | 315 | |
| 329 | −static struct mr_table *ipmr_get_table(struct net *net, u32 id) | |
| 316 | +static struct mr_table *__ipmr_get_table(struct net *net, u32 id) | |
| 330 | 317 | { |
| 331 | − return net->ipv4.mrt; | |
| 318 | + return rcu_dereference_check(net->ipv4.mrt, | |
| 319 | + lockdep_rtnl_is_held() || | |
| 320 | + !rcu_access_pointer(net->ipv4.mrt)); | |
| 332 | 321 | } |
| 333 | 322 | |
| 334 | −#define __ipmr_get_table ipmr_get_table | |
| 323 | +#define ipmr_for_each_table(mrt, net) \ | |
| 324 | + for (mrt = __ipmr_get_table(net, 0); mrt; mrt = NULL) | |
| 335 | 325 | |
| 336 | 326 | static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, |
| 337 | 327 | struct mr_table **mrt) |
| 338 | 328 | { |
| 339 | − *mrt = net->ipv4.mrt; | |
| 329 | + *mrt = rcu_dereference(net->ipv4.mrt); | |
| 330 | + if (!*mrt) | |
| 331 | + return -EAGAIN; | |
| 340 | 332 | return 0; |
| 341 | 333 | } |
| 342 | 334 | |
| @@ -347,7 +339,8 @@ static int __net_init ipmr_rules_init(struct net *net) · 4 unmodified lines | ||
| 347 | 339 | mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); |
| 348 | 340 | if (IS_ERR(mrt)) |
| 349 | 341 | return PTR_ERR(mrt); |
| 350 | − net->ipv4.mrt = mrt; | |
| 342 | + | |
| 343 | + rcu_assign_pointer(net->ipv4.mrt, mrt); | |
| 351 | 344 | return 0; |
| 352 | 345 | } |
| 353 | 346 | |
| @@ -358,9 +351,10 @@ static void __net_exit ipmr_rules_exit(struct net *net) · 4 unmodified lines | ||
| 358 | 351 | static void __net_exit ipmr_rules_exit_rtnl(struct net *net, |
| 359 | 352 | struct list_head *dev_kill_list) |
| 360 | 353 | { |
| 361 | − ipmr_free_table(net->ipv4.mrt, dev_kill_list); | |
| 354 | + struct mr_table *mrt = rcu_dereference_protected(net->ipv4.mrt, 1); | |
| 362 | 355 | |
| 363 | − net->ipv4.mrt = NULL; | |
| 356 | + RCU_INIT_POINTER(net->ipv4.mrt, NULL); | |
| 357 | + ipmr_free_table(mrt, dev_kill_list); | |
| 364 | 358 | } |
| 365 | 359 | |
| 366 | 360 | static int ipmr_rules_dump(struct net *net, struct notifier_block *nb, |
| @@ -381,6 +375,17 @@ bool ipmr_rule_default(const struct fib_rule *rule) · 14 unmodified lines | ||
| 381 | 375 | EXPORT_SYMBOL(ipmr_rule_default); |
| 382 | 376 | #endif |
| 383 | 377 | |
| 378 | +static struct mr_table *ipmr_get_table(struct net *net, u32 id) | |
| 379 | +{ | |
| 380 | + struct mr_table *mrt; | |
| 381 | + | |
| 382 | + rcu_read_lock(); | |
| 383 | + mrt = __ipmr_get_table(net, id); | |
| 384 | + rcu_read_unlock(); | |
| 385 | + | |
| 386 | + return mrt; | |
| 387 | +} | |
| 388 | + | |
| 384 | 389 | static inline int ipmr_hash_cmp(struct rhashtable_compare_arg *arg, |
| 385 | 390 | const void *ptr) |
| 386 | 391 | { |
| @@ -441,12 +446,11 @@ static void ipmr_free_table(struct mr_table *mrt, struct list_head *dev_kill_lis · 54 unmodified lines | ||
| 441 | 446 | |
| 442 | 447 | WARN_ON_ONCE(!mr_can_free_table(net)); |
| 443 | 448 | |
| 444 | − timer_shutdown_sync(&mrt->ipmr_expire_timer); | |
| 445 | 449 | mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC | |
| 446 | 450 | MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC, |
| 447 | 451 | &ipmr_dev_kill_list); |
| 448 | − rhltable_destroy(&mrt->mfc_hash); | |
| 449 | − kfree(mrt); | |
| 452 | + timer_shutdown_sync(&mrt->ipmr_expire_timer); | |
| 453 | + mr_table_free(mrt); | |
| 450 | 454 | |
| 451 | 455 | WARN_ON_ONCE(!net_initialized(net) && !list_empty(&ipmr_dev_kill_list)); |
| 452 | 456 | list_splice(&ipmr_dev_kill_list, dev_kill_list); |
| @@ -1135,12 +1139,19 @@ static int ipmr_cache_report(const struct mr_table *mrt, · 682 unmodified lines | ||
| 1135 | 1139 | static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, |
| 1136 | 1140 | struct sk_buff *skb, struct net_device *dev) |
| 1137 | 1141 | { |
| 1142 | + struct net *net = read_pnet(&mrt->net); | |
| 1138 | 1143 | const struct iphdr *iph = ip_hdr(skb); |
| 1139 | − struct mfc_cache *c; | |
| 1144 | + struct mfc_cache *c = NULL; | |
| 1140 | 1145 | bool found = false; |
| 1141 | 1146 | int err; |
| 1142 | 1147 | |
| 1143 | 1148 | spin_lock_bh(&mfc_unres_lock); |
| 1149 | + | |
| 1150 | + if (!check_net(net)) { | |
| 1151 | + err = -EINVAL; | |
| 1152 | + goto err; | |
| 1153 | + } | |
| 1154 | + | |
| 1144 | 1155 | list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) { |
| 1145 | 1156 | if (c->mfc_mcastgrp == iph->daddr && |
| 1146 | 1157 | c->mfc_origin == iph->saddr) { |
| @@ -1153,10 +1164,8 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, · 6 unmodified lines | ||
| 1153 | 1164 | /* Create a new entry if allowable */ |
| 1154 | 1165 | c = ipmr_cache_alloc_unres(); |
| 1155 | 1166 | if (!c) { |
| 1156 | − spin_unlock_bh(&mfc_unres_lock); | |
| 1157 | − | |
| 1158 | − kfree_skb(skb); | |
| 1159 | − return -ENOBUFS; | |
| 1167 | + err = -ENOBUFS; | |
| 1168 | + goto err; | |
| 1160 | 1169 | } |
| 1161 | 1170 | |
| 1162 | 1171 | /* Fill in the new cache entry */ |
| @@ -1166,17 +1175,8 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, · 3 unmodified lines | ||
| 1166 | 1175 | |
| 1167 | 1176 | /* Reflect first query at mrouted. */ |
| 1168 | 1177 | err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE); |
| 1169 | − | |
| 1170 | − if (err < 0) { | |
| 1171 | − /* If the report failed throw the cache entry | |
| 1172 | − out - Brad Parker | |
| 1173 | − */ | |
| 1174 | − spin_unlock_bh(&mfc_unres_lock); | |
| 1175 | − | |
| 1176 | − ipmr_cache_free(c); | |
| 1177 | − kfree_skb(skb); | |
| 1178 | − return err; | |
| 1179 | − } | |
| 1178 | + if (err < 0) | |
| 1179 | + goto err; | |
| 1180 | 1180 | |
| 1181 | 1181 | atomic_inc(&mrt->cache_resolve_queue_len); |
| 1182 | 1182 | list_add(&c->_c.list, &mrt->mfc_unres_queue); |
| @@ -1189,18 +1189,26 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, · 6 unmodified lines | ||
| 1189 | 1189 | |
| 1190 | 1190 | /* See if we can append the packet */ |
| 1191 | 1191 | if (c->_c.mfc_un.unres.unresolved.qlen > 3) { |
| 1192 | − kfree_skb(skb); | |
| 1192 | + c = NULL; | |
| 1193 | 1193 | err = -ENOBUFS; |
| 1194 | − } else { | |
| 1195 | − if (dev) { | |
| 1196 | − skb->dev = dev; | |
| 1197 | − skb->skb_iif = dev->ifindex; | |
| 1198 | − } | |
| 1199 | − skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); | |
| 1200 | − err = 0; | |
| 1194 | + goto err; | |
| 1195 | + } | |
| 1196 | + | |
| 1197 | + if (dev) { | |
| 1198 | + skb->dev = dev; | |
| 1199 | + skb->skb_iif = dev->ifindex; | |
| 1201 | 1200 | } |
| 1202 | 1201 | |
| 1202 | + skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); | |
| 1203 | + | |
| 1203 | 1204 | spin_unlock_bh(&mfc_unres_lock); |
| 1205 | + return 0; | |
| 1206 | + | |
| 1207 | +err: | |
| 1208 | + spin_unlock_bh(&mfc_unres_lock); | |
| 1209 | + if (c) | |
| 1210 | + ipmr_cache_free(c); | |
| 1211 | + kfree_skb(skb); | |
| 1204 | 1212 | return err; |
| 1205 | 1213 | } |
| 1206 | 1214 | |
| @@ -1346,7 +1354,7 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags, · 139 unmodified lines | ||
| 1346 | 1354 | } |
| 1347 | 1355 | |
| 1348 | 1356 | if (flags & MRT_FLUSH_MFC) { |
| 1349 | − if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { | |
| 1357 | + if (atomic_read(&mrt->cache_resolve_queue_len) != 0 || !check_net(net)) { | |
| 1350 | 1358 | spin_lock_bh(&mfc_unres_lock); |
| 1351 | 1359 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
| 1352 | 1360 | list_del(&c->list); |
| @@ -28,6 +28,20 @@ void vif_device_init(struct vif_device *v, · 27 unmodified lines | ||
| 28 | 28 | v->link = dev->ifindex; |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | +static void __mr_free_table(struct work_struct *work) | |
| 32 | +{ | |
| 33 | + struct mr_table *mrt = container_of(to_rcu_work(work), | |
| 34 | + struct mr_table, work); | |
| 35 | + | |
| 36 | + rhltable_destroy(&mrt->mfc_hash); | |
| 37 | + kfree(mrt); | |
| 38 | +} | |
| 39 | + | |
| 40 | +void mr_table_free(struct mr_table *mrt) | |
| 41 | +{ | |
| 42 | + queue_rcu_work(system_unbound_wq, &mrt->work); | |
| 43 | +} | |
| 44 | + | |
| 31 | 45 | struct mr_table * |
| 32 | 46 | mr_table_alloc(struct net *net, u32 id, |
| 33 | 47 | struct mr_table_ops *ops, |
| @@ -50,6 +64,8 @@ mr_table_alloc(struct net *net, u32 id, · 16 unmodified lines | ||
| 50 | 64 | kfree(mrt); |
| 51 | 65 | return ERR_PTR(err); |
| 52 | 66 | } |
| 67 | + | |
| 68 | + INIT_RCU_WORK(&mrt->work, __mr_free_table); | |
| 53 | 69 | INIT_LIST_HEAD(&mrt->mfc_cache_list); |
| 54 | 70 | INIT_LIST_HEAD(&mrt->mfc_unres_queue); |
| 55 | 71 | |
| @@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, · 109 unmodified lines | ||
| 110 | 110 | arpptr += dev->addr_len; |
| 111 | 111 | memcpy(&src_ipaddr, arpptr, sizeof(u32)); |
| 112 | 112 | arpptr += sizeof(u32); |
| 113 | − tgt_devaddr = arpptr; | |
| 114 | − arpptr += dev->addr_len; | |
| 113 | + | |
| 114 | + if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { | |
| 115 | + if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, | |
| 116 | + sizeof(arpinfo->tgt_devaddr.mask)))) | |
| 117 | + return 0; | |
| 118 | + | |
| 119 | + tgt_devaddr = NULL; | |
| 120 | + } else { | |
| 121 | + tgt_devaddr = arpptr; | |
| 122 | + arpptr += dev->addr_len; | |
| 123 | + } | |
| 115 | 124 | memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); |
| 116 | 125 | |
| 117 | 126 | if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, |
| 118 | 127 | arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, |
| 119 | − dev->addr_len)) || | |
| 128 | + dev->addr_len))) | |
| 129 | + return 0; | |
| 130 | + | |
| 131 | + if (tgt_devaddr && | |
| 120 | 132 | NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, |
| 121 | 133 | arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, |
| 122 | 134 | dev->addr_len))) |
| @@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) · 39 unmodified lines | ||
| 40 | 40 | } |
| 41 | 41 | arpptr += pln; |
| 42 | 42 | if (mangle->flags & ARPT_MANGLE_TDEV) { |
| 43 | + if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && | |
| 44 | + skb->dev->type == ARPHRD_IEEE1394)) | |
| 45 | + return NF_DROP; | |
| 46 | + | |
| 43 | 47 | if (ARPT_DEV_ADDR_LEN_MAX < hln || |
| 44 | 48 | (arpptr + hln > skb_tail_pointer(skb))) |
| 45 | 49 | return NF_DROP; |
| @@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) · 1 unmodified line | ||
| 47 | 51 | } |
| 48 | 52 | arpptr += hln; |
| 49 | 53 | if (mangle->flags & ARPT_MANGLE_TIP) { |
| 54 | + if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && | |
| 55 | + skb->dev->type == ARPHRD_IEEE1394)) | |
| 56 | + return NF_DROP; | |
| 57 | + | |
| 50 | 58 | if (ARPT_MANGLE_ADDR_LEN_MAX < pln || |
| 51 | 59 | (arpptr + pln > skb_tail_pointer(skb))) |
| 52 | 60 | return NF_DROP; |
| @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) · 49 unmodified lines | ||
| 50 | 50 | u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) |
| 51 | 51 | { |
| 52 | 52 | const struct inet_connection_sock *icsk = inet_csk(sk); |
| 53 | − u32 remaining, user_timeout; | |
| 53 | + u32 user_timeout; | |
| 54 | + s32 remaining; | |
| 54 | 55 | s32 elapsed; |
| 55 | 56 | |
| 56 | 57 | user_timeout = READ_ONCE(icsk->icsk_user_timeout); |
| @@ -61,7 +62,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) · 4 unmodified lines | ||
| 61 | 62 | if (unlikely(elapsed < 0)) |
| 62 | 63 | elapsed = 0; |
| 63 | 64 | remaining = msecs_to_jiffies(user_timeout) - elapsed; |
| 64 | − remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN); | |
| 65 | + remaining = max_t(int, remaining, TCP_TIMEOUT_MIN); | |
| 65 | 66 | |
| 66 | 67 | return min_t(u32, remaining, when); |
| 67 | 68 | } |
| @@ -491,6 +491,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) · 490 unmodified lines | ||
| 491 | 491 | struct net *net = dev_net(skb->dev); |
| 492 | 492 | struct inet6_dev *idev; |
| 493 | 493 | struct ipv6hdr *oldhdr; |
| 494 | + unsigned int chdr_len; | |
| 494 | 495 | unsigned char *buf; |
| 495 | 496 | int accept_rpl_seg; |
| 496 | 497 | int i, err; |
| @@ -592,8 +593,10 @@ looped_back: · 95 unmodified lines | ||
| 592 | 593 | skb_pull(skb, ((hdr->hdrlen + 1) << 3)); |
| 593 | 594 | skb_postpull_rcsum(skb, oldhdr, |
| 594 | 595 | sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); |
| 595 | − if (unlikely(!hdr->segments_left)) { | |
| 596 | − if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0, | |
| 596 | + chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3); | |
| 597 | + if (unlikely(!hdr->segments_left || | |
| 598 | + skb_headroom(skb) < chdr_len + skb->mac_len)) { | |
| 599 | + if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0, | |
| 597 | 600 | GFP_ATOMIC)) { |
| 598 | 601 | __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); |
| 599 | 602 | kfree_skb(skb); |
| @@ -603,7 +606,7 @@ looped_back: · 3 unmodified lines | ||
| 603 | 606 | |
| 604 | 607 | oldhdr = ipv6_hdr(skb); |
| 605 | 608 | } |
| 606 | − skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr)); | |
| 609 | + skb_push(skb, chdr_len); | |
| 607 | 610 | skb_reset_network_header(skb); |
| 608 | 611 | skb_mac_header_rebuild(skb); |
| 609 | 612 | skb_set_transport_header(skb, sizeof(struct ipv6hdr)); |
| @@ -287,7 +287,16 @@ static int rpl_input(struct sk_buff *skb) · 286 unmodified lines | ||
| 287 | 287 | |
| 288 | 288 | if (!dst) { |
| 289 | 289 | ip6_route_input(skb); |
| 290 | + | |
| 291 | + /* ip6_route_input() sets a NOREF dst; force a refcount on it | |
| 292 | + * before caching or further use. | |
| 293 | + */ | |
| 294 | + skb_dst_force(skb); | |
| 290 | 295 | dst = skb_dst(skb); |
| 296 | + if (unlikely(!dst)) { | |
| 297 | + err = -ENETUNREACH; | |
| 298 | + goto drop; | |
| 299 | + } | |
| 291 | 300 | |
| 292 | 301 | /* cache only if we don't create a dst reference loop */ |
| 293 | 302 | if (!dst->error && lwtst != dst->lwtstate) { |
| @@ -515,7 +515,16 @@ static int seg6_input_core(struct net *net, struct sock *sk, · 514 unmodified lines | ||
| 515 | 515 | |
| 516 | 516 | if (!dst) { |
| 517 | 517 | ip6_route_input(skb); |
| 518 | + | |
| 519 | + /* ip6_route_input() sets a NOREF dst; force a refcount on it | |
| 520 | + * before caching or further use. | |
| 521 | + */ | |
| 522 | + skb_dst_force(skb); | |
| 518 | 523 | dst = skb_dst(skb); |
| 524 | + if (unlikely(!dst)) { | |
| 525 | + err = -ENETUNREACH; | |
| 526 | + goto drop; | |
| 527 | + } | |
| 519 | 528 | |
| 520 | 529 | /* cache only if we don't create a dst reference loop */ |
| 521 | 530 | if (!dst->error && lwtst != dst->lwtstate) { |
| @@ -1278,6 +1278,7 @@ static void __reset_counters(struct pm_nl_pernet *pernet) · 1277 unmodified lines | ||
| 1278 | 1278 | WRITE_ONCE(pernet->endp_signal_max, 0); |
| 1279 | 1279 | WRITE_ONCE(pernet->endp_subflow_max, 0); |
| 1280 | 1280 | WRITE_ONCE(pernet->endp_laminar_max, 0); |
| 1281 | + WRITE_ONCE(pernet->endp_fullmesh_max, 0); | |
| 1281 | 1282 | pernet->endpoints = 0; |
| 1282 | 1283 | } |
| 1283 | 1284 | |
| @@ -3302,7 +3302,8 @@ bool __mptcp_close(struct sock *sk, long timeout) · 3301 unmodified lines | ||
| 3302 | 3302 | goto cleanup; |
| 3303 | 3303 | } |
| 3304 | 3304 | |
| 3305 | − if (mptcp_data_avail(msk) || timeout < 0) { | |
| 3305 | + if (mptcp_data_avail(msk) || timeout < 0 || | |
| 3306 | + (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { | |
| 3306 | 3307 | /* If the msk has read data, or the caller explicitly ask it, |
| 3307 | 3308 | * do the MPTCP equivalent of TCP reset, aka MPTCP fastclose |
| 3308 | 3309 | */ |
| @@ -159,10 +159,10 @@ static int mptcp_setsockopt_sol_socket_tstamp(struct mptcp_sock *msk, int optnam · 158 unmodified lines | ||
| 159 | 159 | lock_sock(sk); |
| 160 | 160 | mptcp_for_each_subflow(msk, subflow) { |
| 161 | 161 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| 162 | − bool slow = lock_sock_fast(ssk); | |
| 163 | 162 | |
| 164 | − sock_set_timestamp(sk, optname, !!val); | |
| 165 | − unlock_sock_fast(ssk, slow); | |
| 163 | + lock_sock(ssk); | |
| 164 | + sock_set_timestamp(ssk, optname, !!val); | |
| 165 | + release_sock(ssk); | |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | 168 | release_sock(sk); |
| @@ -235,10 +235,10 @@ static int mptcp_setsockopt_sol_socket_timestamping(struct mptcp_sock *msk, · 66 unmodified lines | ||
| 235 | 235 | |
| 236 | 236 | mptcp_for_each_subflow(msk, subflow) { |
| 237 | 237 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| 238 | − bool slow = lock_sock_fast(ssk); | |
| 239 | 238 | |
| 240 | − sock_set_timestamping(sk, optname, timestamping); | |
| 241 | − unlock_sock_fast(ssk, slow); | |
| 239 | + lock_sock(ssk); | |
| 240 | + sock_set_timestamping(ssk, optname, timestamping); | |
| 241 | + release_sock(ssk); | |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | release_sock(sk); |
| @@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, · 465 unmodified lines | ||
| 466 | 466 | if (!ih) |
| 467 | 467 | goto out_unlock; |
| 468 | 468 | |
| 469 | − if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) | |
| 470 | − ct->proto.sctp.init[!dir] = 0; | |
| 471 | − ct->proto.sctp.init[dir] = 1; | |
| 469 | + /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ | |
| 470 | + if (old_state == SCTP_CONNTRACK_NONE || | |
| 471 | + ct->proto.sctp.vtag[!dir] != ih->init_tag) { | |
| 472 | + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) | |
| 473 | + ct->proto.sctp.init[!dir] = 0; | |
| 474 | + ct->proto.sctp.init[dir] = 1; | |
| 475 | + } | |
| 472 | 476 | |
| 473 | 477 | pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); |
| 474 | 478 | ct->proto.sctp.vtag[!dir] = ih->init_tag; |
| @@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, · 180 unmodified lines | ||
| 181 | 181 | return 1; |
| 182 | 182 | } |
| 183 | 183 | |
| 184 | +/* Parse optional port number after IP address. | |
| 185 | + * Returns false on malformed input, true otherwise. | |
| 186 | + * If port is non-NULL, stores parsed port in network byte order. | |
| 187 | + * If no port is present, sets *port to default SIP port. | |
| 188 | + */ | |
| 189 | +static bool sip_parse_port(const char *dptr, const char **endp, | |
| 190 | + const char *limit, __be16 *port) | |
| 191 | +{ | |
| 192 | + unsigned int p = 0; | |
| 193 | + int len = 0; | |
| 194 | + | |
| 195 | + if (dptr >= limit) | |
| 196 | + return false; | |
| 197 | + | |
| 198 | + if (*dptr != ':') { | |
| 199 | + if (port) | |
| 200 | + *port = htons(SIP_PORT); | |
| 201 | + if (endp) | |
| 202 | + *endp = dptr; | |
| 203 | + return true; | |
| 204 | + } | |
| 205 | + | |
| 206 | + dptr++; /* skip ':' */ | |
| 207 | + | |
| 208 | + while (dptr < limit && isdigit(*dptr)) { | |
| 209 | + p = p * 10 + (*dptr - '0'); | |
| 210 | + dptr++; | |
| 211 | + len++; | |
| 212 | + if (len > 5) /* max "65535" */ | |
| 213 | + return false; | |
| 214 | + } | |
| 215 | + | |
| 216 | + if (len == 0) | |
| 217 | + return false; | |
| 218 | + | |
| 219 | + /* reached limit while parsing port */ | |
| 220 | + if (dptr >= limit) | |
| 221 | + return false; | |
| 222 | + | |
| 223 | + if (p < 1024 || p > 65535) | |
| 224 | + return false; | |
| 225 | + | |
| 226 | + if (port) | |
| 227 | + *port = htons(p); | |
| 228 | + | |
| 229 | + if (endp) | |
| 230 | + *endp = dptr; | |
| 231 | + | |
| 232 | + return true; | |
| 233 | +} | |
| 234 | + | |
| 184 | 235 | /* skip ip address. returns its length. */ |
| 185 | 236 | static int epaddr_len(const struct nf_conn *ct, const char *dptr, |
| 186 | 237 | const char *limit, int *shift) |
| @@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, · 6 unmodified lines | ||
| 193 | 244 | return 0; |
| 194 | 245 | } |
| 195 | 246 | |
| 196 | − /* Port number */ | |
| 197 | − if (*dptr == ':') { | |
| 198 | − dptr++; | |
| 199 | − dptr += digits_len(ct, dptr, limit, shift); | |
| 200 | − } | |
| 247 | + if (!sip_parse_port(dptr, &dptr, limit, NULL)) | |
| 248 | + return 0; | |
| 201 | 249 | return dptr - aux; |
| 202 | 250 | } |
| 203 | 251 | |
| @@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, · 24 unmodified lines | ||
| 228 | 276 | return epaddr_len(ct, dptr, limit, shift); |
| 229 | 277 | } |
| 230 | 278 | |
| 279 | +/* simple_strtoul stops after first non-number character. | |
| 280 | + * But as we're not dealing with c-strings, we can't rely on | |
| 281 | + * hitting \r,\n,\0 etc. before moving past end of buffer. | |
| 282 | + * | |
| 283 | + * This is a variant of simple_strtoul, but doesn't require | |
| 284 | + * a c-string. | |
| 285 | + * | |
| 286 | + * If value exceeds UINT_MAX, 0 is returned. | |
| 287 | + */ | |
| 288 | +static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) | |
| 289 | +{ | |
| 290 | + const unsigned int max = sizeof("4294967295"); | |
| 291 | + unsigned int olen = len; | |
| 292 | + const char *s = cp; | |
| 293 | + u64 result = 0; | |
| 294 | + | |
| 295 | + if (len > max) | |
| 296 | + len = max; | |
| 297 | + | |
| 298 | + while (olen > 0 && isdigit(*s)) { | |
| 299 | + unsigned int value; | |
| 300 | + | |
| 301 | + if (len == 0) | |
| 302 | + goto err; | |
| 303 | + | |
| 304 | + value = *s - '0'; | |
| 305 | + result = result * 10 + value; | |
| 306 | + | |
| 307 | + if (result > UINT_MAX) | |
| 308 | + goto err; | |
| 309 | + s++; | |
| 310 | + len--; | |
| 311 | + olen--; | |
| 312 | + } | |
| 313 | + | |
| 314 | + if (endp) | |
| 315 | + *endp = (char *)s; | |
| 316 | + | |
| 317 | + return result; | |
| 318 | +err: | |
| 319 | + if (endp) | |
| 320 | + *endp = (char *)cp; | |
| 321 | + return 0; | |
| 322 | +} | |
| 323 | + | |
| 231 | 324 | /* Parse a SIP request line of the form: |
| 232 | 325 | * |
| 233 | 326 | * Request-Line = Method SP Request-URI SP SIP-Version CRLF |
| @@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, · 7 unmodified lines | ||
| 241 | 334 | { |
| 242 | 335 | const char *start = dptr, *limit = dptr + datalen, *end; |
| 243 | 336 | unsigned int mlen; |
| 244 | − unsigned int p; | |
| 245 | 337 | int shift = 0; |
| 246 | 338 | |
| 247 | 339 | /* Skip method and following whitespace */ |
| @@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, · 19 unmodified lines | ||
| 267 | 359 | |
| 268 | 360 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) |
| 269 | 361 | return -1; |
| 270 | − if (end < limit && *end == ':') { | |
| 271 | − end++; | |
| 272 | − p = simple_strtoul(end, (char **)&end, 10); | |
| 273 | − if (p < 1024 || p > 65535) | |
| 274 | − return -1; | |
| 275 | − *port = htons(p); | |
| 276 | − } else | |
| 277 | − *port = htons(SIP_PORT); | |
| 362 | + if (!sip_parse_port(end, &end, limit, port)) | |
| 363 | + return -1; | |
| 278 | 364 | |
| 279 | 365 | if (end == dptr) |
| 280 | 366 | return 0; |
| @@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, · 228 unmodified lines | ||
| 509 | 595 | union nf_inet_addr *addr, __be16 *port) |
| 510 | 596 | { |
| 511 | 597 | const char *c, *limit = dptr + datalen; |
| 512 | − unsigned int p; | |
| 513 | 598 | int ret; |
| 514 | 599 | |
| 515 | 600 | ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, |
| @@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, · 4 unmodified lines | ||
| 520 | 605 | |
| 521 | 606 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) |
| 522 | 607 | return -1; |
| 523 | − if (*c == ':') { | |
| 524 | − c++; | |
| 525 | − p = simple_strtoul(c, (char **)&c, 10); | |
| 526 | − if (p < 1024 || p > 65535) | |
| 527 | − return -1; | |
| 528 | − *port = htons(p); | |
| 529 | − } else | |
| 530 | − *port = htons(SIP_PORT); | |
| 608 | + if (!sip_parse_port(c, &c, limit, port)) | |
| 609 | + return -1; | |
| 531 | 610 | |
| 532 | 611 | if (dataoff) |
| 533 | 612 | *dataoff = c - dptr; |
| @@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, · 75 unmodified lines | ||
| 609 | 688 | return 0; |
| 610 | 689 | |
| 611 | 690 | start += strlen(name); |
| 612 | − *val = simple_strtoul(start, &end, 0); | |
| 691 | + *val = sip_strtouint(start, limit - start, (char **)&end); | |
| 613 | 692 | if (start == end) |
| 614 | 693 | return -1; |
| 615 | 694 | if (matchoff && matchlen) { |
| @@ -1064,6 +1143,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, · 448 unmodified lines | ||
| 1064 | 1143 | |
| 1065 | 1144 | mediaoff = sdpoff; |
| 1066 | 1145 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { |
| 1146 | + char *end; | |
| 1147 | + | |
| 1067 | 1148 | if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, |
| 1068 | 1149 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, |
| 1069 | 1150 | &mediaoff, &medialen) <= 0) |
| @@ -1079,8 +1160,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, · 9 unmodified lines | ||
| 1079 | 1160 | mediaoff += t->len; |
| 1080 | 1161 | medialen -= t->len; |
| 1081 | 1162 | |
| 1082 | − port = simple_strtoul(*dptr + mediaoff, NULL, 10); | |
| 1083 | − if (port == 0) | |
| 1163 | + port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); | |
| 1164 | + if (port == 0 || *dptr + mediaoff == end) | |
| 1084 | 1165 | continue; |
| 1085 | 1166 | if (port < 1024 || port > 65535) { |
| 1086 | 1167 | nf_ct_helper_log(skb, ct, "wrong port %u", port); |
| @@ -1254,7 +1335,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, · 167 unmodified lines | ||
| 1254 | 1335 | */ |
| 1255 | 1336 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, |
| 1256 | 1337 | &matchoff, &matchlen) > 0) |
| 1257 | − expires = simple_strtoul(*dptr + matchoff, NULL, 10); | |
| 1338 | + expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); | |
| 1258 | 1339 | |
| 1259 | 1340 | ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
| 1260 | 1341 | SIP_HDR_CONTACT, NULL, |
| @@ -1358,7 +1439,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, · 97 unmodified lines | ||
| 1358 | 1439 | |
| 1359 | 1440 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, |
| 1360 | 1441 | &matchoff, &matchlen) > 0) |
| 1361 | − expires = simple_strtoul(*dptr + matchoff, NULL, 10); | |
| 1442 | + expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); | |
| 1362 | 1443 | |
| 1363 | 1444 | while (1) { |
| 1364 | 1445 | unsigned int c_expires = expires; |
| @@ -1418,10 +1499,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, · 53 unmodified lines | ||
| 1418 | 1499 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
| 1419 | 1500 | unsigned int matchoff, matchlen, matchend; |
| 1420 | 1501 | unsigned int code, cseq, i; |
| 1502 | + char *end; | |
| 1421 | 1503 | |
| 1422 | 1504 | if (*datalen < strlen("SIP/2.0 200")) |
| 1423 | 1505 | return NF_ACCEPT; |
| 1424 | − code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); | |
| 1506 | + code = sip_strtouint(*dptr + strlen("SIP/2.0 "), | |
| 1507 | + *datalen - strlen("SIP/2.0 "), NULL); | |
| 1425 | 1508 | if (!code) { |
| 1426 | 1509 | nf_ct_helper_log(skb, ct, "cannot get code"); |
| 1427 | 1510 | return NF_DROP; |
| @@ -1432,8 +1515,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, · 4 unmodified lines | ||
| 1432 | 1515 | nf_ct_helper_log(skb, ct, "cannot parse cseq"); |
| 1433 | 1516 | return NF_DROP; |
| 1434 | 1517 | } |
| 1435 | − cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | |
| 1436 | − if (!cseq && *(*dptr + matchoff) != '0') { | |
| 1518 | + cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); | |
| 1519 | + if (*dptr + matchoff == end) { | |
| 1437 | 1520 | nf_ct_helper_log(skb, ct, "cannot get cseq"); |
| 1438 | 1521 | return NF_DROP; |
| 1439 | 1522 | } |
| @@ -1482,6 +1565,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, · 42 unmodified lines | ||
| 1482 | 1565 | |
| 1483 | 1566 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { |
| 1484 | 1567 | const struct sip_handler *handler; |
| 1568 | + char *end; | |
| 1485 | 1569 | |
| 1486 | 1570 | handler = &sip_handlers[i]; |
| 1487 | 1571 | if (handler->request == NULL) |
| @@ -1498,8 +1582,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, · 10 unmodified lines | ||
| 1498 | 1582 | nf_ct_helper_log(skb, ct, "cannot parse cseq"); |
| 1499 | 1583 | return NF_DROP; |
| 1500 | 1584 | } |
| 1501 | − cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | |
| 1502 | − if (!cseq && *(*dptr + matchoff) != '0') { | |
| 1585 | + cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); | |
| 1586 | + if (*dptr + matchoff == end) { | |
| 1503 | 1587 | nf_ct_helper_log(skb, ct, "cannot get cseq"); |
| 1504 | 1588 | return NF_DROP; |
| 1505 | 1589 | } |
| @@ -1575,7 +1659,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, · 69 unmodified lines | ||
| 1575 | 1659 | &matchoff, &matchlen) <= 0) |
| 1576 | 1660 | break; |
| 1577 | 1661 | |
| 1578 | − clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); | |
| 1662 | + clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); | |
| 1579 | 1663 | if (dptr + matchoff == end) |
| 1580 | 1664 | break; |
| 1581 | 1665 | |
| @@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, · 245 unmodified lines | ||
| 246 | 246 | if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, |
| 247 | 247 | "rport=", &poff, &plen, |
| 248 | 248 | &n) > 0 && |
| 249 | + n >= 1024 && n <= 65535 && | |
| 249 | 250 | htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && |
| 250 | 251 | htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { |
| 251 | 252 | __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; |
| @@ -374,6 +374,38 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook) · 373 unmodified lines | ||
| 374 | 374 | call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu); |
| 375 | 375 | } |
| 376 | 376 | |
| 377 | +static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook) | |
| 378 | +{ | |
| 379 | + list_del_rcu(&hook->list); | |
| 380 | + nft_netdev_hook_free_rcu(hook); | |
| 381 | +} | |
| 382 | + | |
| 383 | +static void nft_trans_hook_destroy(struct nft_trans_hook *trans_hook) | |
| 384 | +{ | |
| 385 | + list_del(&trans_hook->list); | |
| 386 | + kfree(trans_hook); | |
| 387 | +} | |
| 388 | + | |
| 389 | +static void nft_netdev_unregister_trans_hook(struct net *net, | |
| 390 | + const struct nft_table *table, | |
| 391 | + struct list_head *hook_list) | |
| 392 | +{ | |
| 393 | + struct nft_trans_hook *trans_hook, *next; | |
| 394 | + struct nf_hook_ops *ops; | |
| 395 | + struct nft_hook *hook; | |
| 396 | + | |
| 397 | + list_for_each_entry_safe(trans_hook, next, hook_list, list) { | |
| 398 | + hook = trans_hook->hook; | |
| 399 | + | |
| 400 | + if (!(table->flags & NFT_TABLE_F_DORMANT)) { | |
| 401 | + list_for_each_entry(ops, &hook->ops_list, list) | |
| 402 | + nf_unregister_net_hook(net, ops); | |
| 403 | + } | |
| 404 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 405 | + nft_trans_hook_destroy(trans_hook); | |
| 406 | + } | |
| 407 | +} | |
| 408 | + | |
| 377 | 409 | static void nft_netdev_unregister_hooks(struct net *net, |
| 378 | 410 | struct list_head *hook_list, |
| 379 | 411 | bool release_netdev) |
| @@ -384,10 +416,8 @@ static void nft_netdev_unregister_hooks(struct net *net, · 4 unmodified lines | ||
| 384 | 416 | list_for_each_entry_safe(hook, next, hook_list, list) { |
| 385 | 417 | list_for_each_entry(ops, &hook->ops_list, list) |
| 386 | 418 | nf_unregister_net_hook(net, ops); |
| 387 | − if (release_netdev) { | |
| 388 | − list_del(&hook->list); | |
| 389 | − nft_netdev_hook_free_rcu(hook); | |
| 390 | − } | |
| 419 | + if (release_netdev) | |
| 420 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 391 | 421 | } |
| 392 | 422 | } |
| 393 | 423 | |
| @@ -1942,15 +1972,69 @@ static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook) · 1548 unmodified lines | ||
| 1942 | 1972 | return nla_put_string(skb, attr, hook->ifname); |
| 1943 | 1973 | } |
| 1944 | 1974 | |
| 1975 | +struct nft_hook_dump_ctx { | |
| 1976 | + struct nft_hook *first; | |
| 1977 | + int n; | |
| 1978 | +}; | |
| 1979 | + | |
| 1980 | +static int nft_dump_basechain_hook_one(struct sk_buff *skb, | |
| 1981 | + struct nft_hook *hook, | |
| 1982 | + struct nft_hook_dump_ctx *dump_ctx) | |
| 1983 | +{ | |
| 1984 | + if (!dump_ctx->first) | |
| 1985 | + dump_ctx->first = hook; | |
| 1986 | + | |
| 1987 | + if (nft_nla_put_hook_dev(skb, hook)) | |
| 1988 | + return -1; | |
| 1989 | + | |
| 1990 | + dump_ctx->n++; | |
| 1991 | + | |
| 1992 | + return 0; | |
| 1993 | +} | |
| 1994 | + | |
| 1995 | +static int nft_dump_basechain_hook_list(struct sk_buff *skb, | |
| 1996 | + const struct net *net, | |
| 1997 | + const struct list_head *hook_list, | |
| 1998 | + struct nft_hook_dump_ctx *dump_ctx) | |
| 1999 | +{ | |
| 2000 | + struct nft_hook *hook; | |
| 2001 | + int err; | |
| 2002 | + | |
| 2003 | + list_for_each_entry_rcu(hook, hook_list, list, | |
| 2004 | + lockdep_commit_lock_is_held(net)) { | |
| 2005 | + err = nft_dump_basechain_hook_one(skb, hook, dump_ctx); | |
| 2006 | + if (err < 0) | |
| 2007 | + return err; | |
| 2008 | + } | |
| 2009 | + | |
| 2010 | + return 0; | |
| 2011 | +} | |
| 2012 | + | |
| 2013 | +static int nft_dump_basechain_trans_hook_list(struct sk_buff *skb, | |
| 2014 | + const struct list_head *trans_hook_list, | |
| 2015 | + struct nft_hook_dump_ctx *dump_ctx) | |
| 2016 | +{ | |
| 2017 | + struct nft_trans_hook *trans_hook; | |
| 2018 | + int err; | |
| 2019 | + | |
| 2020 | + list_for_each_entry(trans_hook, trans_hook_list, list) { | |
| 2021 | + err = nft_dump_basechain_hook_one(skb, trans_hook->hook, dump_ctx); | |
| 2022 | + if (err < 0) | |
| 2023 | + return err; | |
| 2024 | + } | |
| 2025 | + | |
| 2026 | + return 0; | |
| 2027 | +} | |
| 2028 | + | |
| 1945 | 2029 | static int nft_dump_basechain_hook(struct sk_buff *skb, |
| 1946 | 2030 | const struct net *net, int family, |
| 1947 | 2031 | const struct nft_base_chain *basechain, |
| 1948 | − const struct list_head *hook_list) | |
| 2032 | + const struct list_head *hook_list, | |
| 2033 | + const struct list_head *trans_hook_list) | |
| 1949 | 2034 | { |
| 1950 | 2035 | const struct nf_hook_ops *ops = &basechain->ops; |
| 1951 | − struct nft_hook *hook, *first = NULL; | |
| 2036 | + struct nft_hook_dump_ctx dump_hook_ctx = {}; | |
| 1952 | 2037 | struct nlattr *nest, *nest_devs; |
| 1953 | − int n = 0; | |
| 1954 | 2038 | |
| 1955 | 2039 | nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK); |
| 1956 | 2040 | if (nest == NULL) |
| @@ -1965,23 +2049,23 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, · 8 unmodified lines | ||
| 1965 | 2049 | if (!nest_devs) |
| 1966 | 2050 | goto nla_put_failure; |
| 1967 | 2051 | |
| 1968 | − if (!hook_list) | |
| 2052 | + if (!hook_list && !trans_hook_list) | |
| 1969 | 2053 | hook_list = &basechain->hook_list; |
| 1970 | 2054 | |
| 1971 | − list_for_each_entry_rcu(hook, hook_list, list, | |
| 1972 | − lockdep_commit_lock_is_held(net)) { | |
| 1973 | − if (!first) | |
| 1974 | − first = hook; | |
| 1975 | − | |
| 1976 | − if (nft_nla_put_hook_dev(skb, hook)) | |
| 1977 | − goto nla_put_failure; | |
| 1978 | − n++; | |
| 2055 | + if (hook_list && | |
| 2056 | + nft_dump_basechain_hook_list(skb, net, hook_list, &dump_hook_ctx)) { | |
| 2057 | + goto nla_put_failure; | |
| 2058 | + } else if (trans_hook_list && | |
| 2059 | + nft_dump_basechain_trans_hook_list(skb, trans_hook_list, | |
| 2060 | + &dump_hook_ctx)) { | |
| 2061 | + goto nla_put_failure; | |
| 1979 | 2062 | } |
| 2063 | + | |
| 1980 | 2064 | nla_nest_end(skb, nest_devs); |
| 1981 | 2065 | |
| 1982 | − if (n == 1 && | |
| 1983 | − !hook_is_prefix(first) && | |
| 1984 | − nla_put_string(skb, NFTA_HOOK_DEV, first->ifname)) | |
| 2066 | + if (dump_hook_ctx.n == 1 && | |
| 2067 | + !hook_is_prefix(dump_hook_ctx.first) && | |
| 2068 | + nla_put_string(skb, NFTA_HOOK_DEV, dump_hook_ctx.first->ifname)) | |
| 1985 | 2069 | goto nla_put_failure; |
| 1986 | 2070 | } |
| 1987 | 2071 | nla_nest_end(skb, nest); |
| @@ -1995,7 +2079,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, · 7 unmodified lines | ||
| 1995 | 2079 | u32 portid, u32 seq, int event, u32 flags, |
| 1996 | 2080 | int family, const struct nft_table *table, |
| 1997 | 2081 | const struct nft_chain *chain, |
| 1998 | − const struct list_head *hook_list) | |
| 2082 | + const struct list_head *hook_list, | |
| 2083 | + const struct list_head *trans_hook_list) | |
| 1999 | 2084 | { |
| 2000 | 2085 | struct nlmsghdr *nlh; |
| 2001 | 2086 | |
| @@ -2011,7 +2096,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, · 9 unmodified lines | ||
| 2011 | 2096 | NFTA_CHAIN_PAD)) |
| 2012 | 2097 | goto nla_put_failure; |
| 2013 | 2098 | |
| 2014 | − if (!hook_list && | |
| 2099 | + if (!hook_list && !trans_hook_list && | |
| 2015 | 2100 | (event == NFT_MSG_DELCHAIN || |
| 2016 | 2101 | event == NFT_MSG_DESTROYCHAIN)) { |
| 2017 | 2102 | nlmsg_end(skb, nlh); |
| @@ -2022,7 +2107,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, · 4 unmodified lines | ||
| 2022 | 2107 | const struct nft_base_chain *basechain = nft_base_chain(chain); |
| 2023 | 2108 | struct nft_stats __percpu *stats; |
| 2024 | 2109 | |
| 2025 | − if (nft_dump_basechain_hook(skb, net, family, basechain, hook_list)) | |
| 2110 | + if (nft_dump_basechain_hook(skb, net, family, basechain, | |
| 2111 | + hook_list, trans_hook_list)) | |
| 2026 | 2112 | goto nla_put_failure; |
| 2027 | 2113 | |
| 2028 | 2114 | if (nla_put_be32(skb, NFTA_CHAIN_POLICY, |
| @@ -2058,7 +2144,8 @@ nla_put_failure: · 29 unmodified lines | ||
| 2058 | 2144 | } |
| 2059 | 2145 | |
| 2060 | 2146 | static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event, |
| 2061 | − const struct list_head *hook_list) | |
| 2147 | + const struct list_head *hook_list, | |
| 2148 | + const struct list_head *trans_hook_list) | |
| 2062 | 2149 | { |
| 2063 | 2150 | struct nftables_pernet *nft_net; |
| 2064 | 2151 | struct sk_buff *skb; |
| @@ -2078,7 +2165,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event, · 13 unmodified lines | ||
| 2078 | 2165 | |
| 2079 | 2166 | err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, |
| 2080 | 2167 | event, flags, ctx->family, ctx->table, |
| 2081 | − ctx->chain, hook_list); | |
| 2168 | + ctx->chain, hook_list, trans_hook_list); | |
| 2082 | 2169 | if (err < 0) { |
| 2083 | 2170 | kfree_skb(skb); |
| 2084 | 2171 | goto err; |
| @@ -2124,7 +2211,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb, · 39 unmodified lines | ||
| 2124 | 2211 | NFT_MSG_NEWCHAIN, |
| 2125 | 2212 | NLM_F_MULTI, |
| 2126 | 2213 | table->family, table, |
| 2127 | − chain, NULL) < 0) | |
| 2214 | + chain, NULL, NULL) < 0) | |
| 2128 | 2215 | goto done; |
| 2129 | 2216 | |
| 2130 | 2217 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
| @@ -2178,7 +2265,7 @@ static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info, · 47 unmodified lines | ||
| 2178 | 2265 | |
| 2179 | 2266 | err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid, |
| 2180 | 2267 | info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, |
| 2181 | − 0, family, table, chain, NULL); | |
| 2268 | + 0, family, table, chain, NULL, NULL); | |
| 2182 | 2269 | if (err < 0) |
| 2183 | 2270 | goto err_fill_chain_info; |
| 2184 | 2271 | |
| @@ -2271,10 +2358,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain) · 86 unmodified lines | ||
| 2271 | 2358 | |
| 2272 | 2359 | if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) { |
| 2273 | 2360 | list_for_each_entry_safe(hook, next, |
| 2274 | − &basechain->hook_list, list) { | |
| 2275 | − list_del_rcu(&hook->list); | |
| 2276 | − nft_netdev_hook_free_rcu(hook); | |
| 2277 | − } | |
| 2361 | + &basechain->hook_list, list) | |
| 2362 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 2278 | 2363 | } |
| 2279 | 2364 | module_put(basechain->type->owner); |
| 2280 | 2365 | if (rcu_access_pointer(basechain->stats)) { |
| @@ -2343,8 +2428,12 @@ static struct nft_hook *nft_hook_list_find(struct list_head *hook_list, · 62 unmodified lines | ||
| 2343 | 2428 | |
| 2344 | 2429 | list_for_each_entry(hook, hook_list, list) { |
| 2345 | 2430 | if (!strncmp(hook->ifname, this->ifname, |
| 2346 | − min(hook->ifnamelen, this->ifnamelen))) | |
| 2431 | + min(hook->ifnamelen, this->ifnamelen))) { | |
| 2432 | + if (hook->flags & NFT_HOOK_REMOVE) | |
| 2433 | + continue; | |
| 2434 | + | |
| 2347 | 2435 | return hook; |
| 2436 | + } | |
| 2348 | 2437 | } |
| 2349 | 2438 | |
| 2350 | 2439 | return NULL; |
| @@ -2974,6 +3063,7 @@ err_hooks: · 623 unmodified lines | ||
| 2974 | 3063 | list_for_each_entry(ops, &h->ops_list, list) |
| 2975 | 3064 | nf_unregister_net_hook(ctx->net, ops); |
| 2976 | 3065 | } |
| 3066 | + /* hook.list is on stack, no need for list_del_rcu() */ | |
| 2977 | 3067 | list_del(&h->list); |
| 2978 | 3068 | nft_netdev_hook_free_rcu(h); |
| 2979 | 3069 | } |
| @@ -3102,6 +3192,32 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info, · 122 unmodified lines | ||
| 3102 | 3192 | return nf_tables_addchain(&ctx, family, policy, flags, extack); |
| 3103 | 3193 | } |
| 3104 | 3194 | |
| 3195 | +static int nft_trans_delhook(struct nft_hook *hook, | |
| 3196 | + struct list_head *del_list) | |
| 3197 | +{ | |
| 3198 | + struct nft_trans_hook *trans_hook; | |
| 3199 | + | |
| 3200 | + trans_hook = kmalloc_obj(*trans_hook, GFP_KERNEL); | |
| 3201 | + if (!trans_hook) | |
| 3202 | + return -ENOMEM; | |
| 3203 | + | |
| 3204 | + trans_hook->hook = hook; | |
| 3205 | + list_add_tail(&trans_hook->list, del_list); | |
| 3206 | + hook->flags |= NFT_HOOK_REMOVE; | |
| 3207 | + | |
| 3208 | + return 0; | |
| 3209 | +} | |
| 3210 | + | |
| 3211 | +static void nft_trans_delhook_abort(struct list_head *del_list) | |
| 3212 | +{ | |
| 3213 | + struct nft_trans_hook *trans_hook, *next; | |
| 3214 | + | |
| 3215 | + list_for_each_entry_safe(trans_hook, next, del_list, list) { | |
| 3216 | + trans_hook->hook->flags &= ~NFT_HOOK_REMOVE; | |
| 3217 | + nft_trans_hook_destroy(trans_hook); | |
| 3218 | + } | |
| 3219 | +} | |
| 3220 | + | |
| 3105 | 3221 | static int nft_delchain_hook(struct nft_ctx *ctx, |
| 3106 | 3222 | struct nft_base_chain *basechain, |
| 3107 | 3223 | struct netlink_ext_ack *extack) |
| @@ -3128,7 +3244,10 @@ static int nft_delchain_hook(struct nft_ctx *ctx, · 20 unmodified lines | ||
| 3128 | 3244 | err = -ENOENT; |
| 3129 | 3245 | goto err_chain_del_hook; |
| 3130 | 3246 | } |
| 3131 | − list_move(&hook->list, &chain_del_list); | |
| 3247 | + if (nft_trans_delhook(hook, &chain_del_list) < 0) { | |
| 3248 | + err = -ENOMEM; | |
| 3249 | + goto err_chain_del_hook; | |
| 3250 | + } | |
| 3132 | 3251 | } |
| 3133 | 3252 | |
| 3134 | 3253 | trans = nft_trans_alloc_chain(ctx, NFT_MSG_DELCHAIN); |
| @@ -3148,7 +3267,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx, · 13 unmodified lines | ||
| 3148 | 3267 | return 0; |
| 3149 | 3268 | |
| 3150 | 3269 | err_chain_del_hook: |
| 3151 | − list_splice(&chain_del_list, &basechain->hook_list); | |
| 3270 | + nft_trans_delhook_abort(&chain_del_list); | |
| 3152 | 3271 | nft_chain_release_hook(&chain_hook); |
| 3153 | 3272 | |
| 3154 | 3273 | return err; |
| @@ -8852,10 +8971,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net, · 5697 unmodified lines | ||
| 8852 | 8971 | list_for_each_entry_safe(hook, next, hook_list, list) { |
| 8853 | 8972 | list_for_each_entry(ops, &hook->ops_list, list) |
| 8854 | 8973 | nft_unregister_flowtable_ops(net, flowtable, ops); |
| 8855 | − if (release_netdev) { | |
| 8856 | − list_del(&hook->list); | |
| 8857 | − nft_netdev_hook_free_rcu(hook); | |
| 8858 | − } | |
| 8974 | + if (release_netdev) | |
| 8975 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 8859 | 8976 | } |
| 8860 | 8977 | } |
| 8861 | 8978 | |
| @@ -8926,8 +9043,7 @@ err_unregister_net_hooks: · 64 unmodified lines | ||
| 8926 | 9043 | |
| 8927 | 9044 | nft_unregister_flowtable_ops(net, flowtable, ops); |
| 8928 | 9045 | } |
| 8929 | − list_del_rcu(&hook->list); | |
| 8930 | − nft_netdev_hook_free_rcu(hook); | |
| 9046 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 8931 | 9047 | } |
| 8932 | 9048 | |
| 8933 | 9049 | return err; |
| @@ -8937,9 +9053,25 @@ static void nft_hooks_destroy(struct list_head *hook_list) · 3 unmodified lines | ||
| 8937 | 9053 | { |
| 8938 | 9054 | struct nft_hook *hook, *next; |
| 8939 | 9055 | |
| 8940 | − list_for_each_entry_safe(hook, next, hook_list, list) { | |
| 8941 | − list_del_rcu(&hook->list); | |
| 8942 | − nft_netdev_hook_free_rcu(hook); | |
| 9056 | + list_for_each_entry_safe(hook, next, hook_list, list) | |
| 9057 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 9058 | +} | |
| 9059 | + | |
| 9060 | +static void nft_flowtable_unregister_trans_hook(struct net *net, | |
| 9061 | + struct nft_flowtable *flowtable, | |
| 9062 | + struct list_head *hook_list) | |
| 9063 | +{ | |
| 9064 | + struct nft_trans_hook *trans_hook, *next; | |
| 9065 | + struct nf_hook_ops *ops; | |
| 9066 | + struct nft_hook *hook; | |
| 9067 | + | |
| 9068 | + list_for_each_entry_safe(trans_hook, next, hook_list, list) { | |
| 9069 | + hook = trans_hook->hook; | |
| 9070 | + list_for_each_entry(ops, &hook->ops_list, list) | |
| 9071 | + nft_unregister_flowtable_ops(net, flowtable, ops); | |
| 9072 | + | |
| 9073 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 9074 | + nft_trans_hook_destroy(trans_hook); | |
| 8943 | 9075 | } |
| 8944 | 9076 | } |
| 8945 | 9077 | |
| @@ -9028,8 +9160,7 @@ err_flowtable_update_hook: · 82 unmodified lines | ||
| 9028 | 9160 | nft_unregister_flowtable_ops(ctx->net, |
| 9029 | 9161 | flowtable, ops); |
| 9030 | 9162 | } |
| 9031 | − list_del_rcu(&hook->list); | |
| 9032 | − nft_netdev_hook_free_rcu(hook); | |
| 9163 | + nft_netdev_hook_unlink_free_rcu(hook); | |
| 9033 | 9164 | } |
| 9034 | 9165 | |
| 9035 | 9166 | return err; |
| @@ -9202,7 +9333,10 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx, · 166 unmodified lines | ||
| 9202 | 9333 | err = -ENOENT; |
| 9203 | 9334 | goto err_flowtable_del_hook; |
| 9204 | 9335 | } |
| 9205 | − list_move(&hook->list, &flowtable_del_list); | |
| 9336 | + if (nft_trans_delhook(hook, &flowtable_del_list) < 0) { | |
| 9337 | + err = -ENOMEM; | |
| 9338 | + goto err_flowtable_del_hook; | |
| 9339 | + } | |
| 9206 | 9340 | } |
| 9207 | 9341 | |
| 9208 | 9342 | trans = nft_trans_alloc(ctx, NFT_MSG_DELFLOWTABLE, |
| @@ -9223,7 +9357,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx, · 14 unmodified lines | ||
| 9223 | 9357 | return 0; |
| 9224 | 9358 | |
| 9225 | 9359 | err_flowtable_del_hook: |
| 9226 | − list_splice(&flowtable_del_list, &flowtable->hook_list); | |
| 9360 | + nft_trans_delhook_abort(&flowtable_del_list); | |
| 9227 | 9361 | nft_flowtable_hook_release(&flowtable_hook); |
| 9228 | 9362 | |
| 9229 | 9363 | return err; |
| @@ -9288,8 +9422,10 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, · 58 unmodified lines | ||
| 9288 | 9422 | u32 portid, u32 seq, int event, |
| 9289 | 9423 | u32 flags, int family, |
| 9290 | 9424 | struct nft_flowtable *flowtable, |
| 9291 | − struct list_head *hook_list) | |
| 9425 | + struct list_head *hook_list, | |
| 9426 | + struct list_head *trans_hook_list) | |
| 9292 | 9427 | { |
| 9428 | + struct nft_trans_hook *trans_hook; | |
| 9293 | 9429 | struct nlattr *nest, *nest_devs; |
| 9294 | 9430 | struct nft_hook *hook; |
| 9295 | 9431 | struct nlmsghdr *nlh; |
| @@ -9306,7 +9442,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, · 10 unmodified lines | ||
| 9306 | 9442 | NFTA_FLOWTABLE_PAD)) |
| 9307 | 9443 | goto nla_put_failure; |
| 9308 | 9444 | |
| 9309 | − if (!hook_list && | |
| 9445 | + if (!hook_list && !trans_hook_list && | |
| 9310 | 9446 | (event == NFT_MSG_DELFLOWTABLE || |
| 9311 | 9447 | event == NFT_MSG_DESTROYFLOWTABLE)) { |
| 9312 | 9448 | nlmsg_end(skb, nlh); |
| @@ -9328,13 +9464,20 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, · 15 unmodified lines | ||
| 9328 | 9464 | if (!nest_devs) |
| 9329 | 9465 | goto nla_put_failure; |
| 9330 | 9466 | |
| 9331 | − if (!hook_list) | |
| 9467 | + if (!hook_list && !trans_hook_list) | |
| 9332 | 9468 | hook_list = &flowtable->hook_list; |
| 9333 | 9469 | |
| 9334 | − list_for_each_entry_rcu(hook, hook_list, list, | |
| 9335 | − lockdep_commit_lock_is_held(net)) { | |
| 9336 | − if (nft_nla_put_hook_dev(skb, hook)) | |
| 9337 | − goto nla_put_failure; | |
| 9470 | + if (hook_list) { | |
| 9471 | + list_for_each_entry_rcu(hook, hook_list, list, | |
| 9472 | + lockdep_commit_lock_is_held(net)) { | |
| 9473 | + if (nft_nla_put_hook_dev(skb, hook)) | |
| 9474 | + goto nla_put_failure; | |
| 9475 | + } | |
| 9476 | + } else if (trans_hook_list) { | |
| 9477 | + list_for_each_entry(trans_hook, trans_hook_list, list) { | |
| 9478 | + if (nft_nla_put_hook_dev(skb, trans_hook->hook)) | |
| 9479 | + goto nla_put_failure; | |
| 9480 | + } | |
| 9338 | 9481 | } |
| 9339 | 9482 | nla_nest_end(skb, nest_devs); |
| 9340 | 9483 | nla_nest_end(skb, nest); |
| @@ -9388,7 +9531,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb, · 47 unmodified lines | ||
| 9388 | 9531 | NFT_MSG_NEWFLOWTABLE, |
| 9389 | 9532 | NLM_F_MULTI | NLM_F_APPEND, |
| 9390 | 9533 | table->family, |
| 9391 | − flowtable, NULL) < 0) | |
| 9534 | + flowtable, NULL, NULL) < 0) | |
| 9392 | 9535 | goto done; |
| 9393 | 9536 | |
| 9394 | 9537 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
| @@ -9488,7 +9631,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb, · 93 unmodified lines | ||
| 9488 | 9631 | err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid, |
| 9489 | 9632 | info->nlh->nlmsg_seq, |
| 9490 | 9633 | NFT_MSG_NEWFLOWTABLE, 0, family, |
| 9491 | − flowtable, NULL); | |
| 9634 | + flowtable, NULL, NULL); | |
| 9492 | 9635 | if (err < 0) |
| 9493 | 9636 | goto err_fill_flowtable_info; |
| 9494 | 9637 | |
| @@ -9501,7 +9644,9 @@ err_fill_flowtable_info: · 6 unmodified lines | ||
| 9501 | 9644 | |
| 9502 | 9645 | static void nf_tables_flowtable_notify(struct nft_ctx *ctx, |
| 9503 | 9646 | struct nft_flowtable *flowtable, |
| 9504 | − struct list_head *hook_list, int event) | |
| 9647 | + struct list_head *hook_list, | |
| 9648 | + struct list_head *trans_hook_list, | |
| 9649 | + int event) | |
| 9505 | 9650 | { |
| 9506 | 9651 | struct nftables_pernet *nft_net = nft_pernet(ctx->net); |
| 9507 | 9652 | struct sk_buff *skb; |
| @@ -9521,7 +9666,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, · 13 unmodified lines | ||
| 9521 | 9666 | |
| 9522 | 9667 | err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, |
| 9523 | 9668 | ctx->seq, event, flags, |
| 9524 | − ctx->family, flowtable, hook_list); | |
| 9669 | + ctx->family, flowtable, | |
| 9670 | + hook_list, trans_hook_list); | |
| 9525 | 9671 | if (err < 0) { |
| 9526 | 9672 | kfree_skb(skb); |
| 9527 | 9673 | goto err; |
| @@ -9535,13 +9681,8 @@ err: · 7 unmodified lines | ||
| 9535 | 9681 | |
| 9536 | 9682 | static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) |
| 9537 | 9683 | { |
| 9538 | − struct nft_hook *hook, *next; | |
| 9539 | − | |
| 9540 | 9684 | flowtable->data.type->free(&flowtable->data); |
| 9541 | − list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) { | |
| 9542 | − list_del_rcu(&hook->list); | |
| 9543 | − nft_netdev_hook_free_rcu(hook); | |
| 9544 | − } | |
| 9685 | + nft_hooks_destroy(&flowtable->hook_list); | |
| 9545 | 9686 | kfree(flowtable->name); |
| 9546 | 9687 | module_put(flowtable->data.type->owner); |
| 9547 | 9688 | kfree(flowtable); |
| @@ -10060,9 +10201,7 @@ static void nft_commit_release(struct nft_trans *trans) · 512 unmodified lines | ||
| 10060 | 10201 | break; |
| 10061 | 10202 | case NFT_MSG_DELCHAIN: |
| 10062 | 10203 | case NFT_MSG_DESTROYCHAIN: |
| 10063 | − if (nft_trans_chain_update(trans)) | |
| 10064 | − nft_hooks_destroy(&nft_trans_chain_hooks(trans)); | |
| 10065 | − else | |
| 10204 | + if (!nft_trans_chain_update(trans)) | |
| 10066 | 10205 | nf_tables_chain_destroy(nft_trans_chain(trans)); |
| 10067 | 10206 | break; |
| 10068 | 10207 | case NFT_MSG_DELRULE: |
| @@ -10083,9 +10222,7 @@ static void nft_commit_release(struct nft_trans *trans) · 14 unmodified lines | ||
| 10083 | 10222 | break; |
| 10084 | 10223 | case NFT_MSG_DELFLOWTABLE: |
| 10085 | 10224 | case NFT_MSG_DESTROYFLOWTABLE: |
| 10086 | − if (nft_trans_flowtable_update(trans)) | |
| 10087 | − nft_hooks_destroy(&nft_trans_flowtable_hooks(trans)); | |
| 10088 | − else | |
| 10225 | + if (!nft_trans_flowtable_update(trans)) | |
| 10089 | 10226 | nf_tables_flowtable_destroy(nft_trans_flowtable(trans)); |
| 10090 | 10227 | break; |
| 10091 | 10228 | } |
| @@ -10845,31 +10982,28 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) · 753 unmodified lines | ||
| 10845 | 10982 | if (nft_trans_chain_update(trans)) { |
| 10846 | 10983 | nft_chain_commit_update(nft_trans_container_chain(trans)); |
| 10847 | 10984 | nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, |
| 10848 | − &nft_trans_chain_hooks(trans)); | |
| 10849 | − list_splice(&nft_trans_chain_hooks(trans), | |
| 10850 | − &nft_trans_basechain(trans)->hook_list); | |
| 10985 | + &nft_trans_chain_hooks(trans), NULL); | |
| 10986 | + list_splice_rcu(&nft_trans_chain_hooks(trans), | |
| 10987 | + &nft_trans_basechain(trans)->hook_list); | |
| 10851 | 10988 | /* trans destroyed after rcu grace period */ |
| 10852 | 10989 | } else { |
| 10853 | 10990 | nft_chain_commit_drop_policy(nft_trans_container_chain(trans)); |
| 10854 | 10991 | nft_clear(net, nft_trans_chain(trans)); |
| 10855 | − nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL); | |
| 10992 | + nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL, NULL); | |
| 10856 | 10993 | nft_trans_destroy(trans); |
| 10857 | 10994 | } |
| 10858 | 10995 | break; |
| 10859 | 10996 | case NFT_MSG_DELCHAIN: |
| 10860 | 10997 | case NFT_MSG_DESTROYCHAIN: |
| 10861 | 10998 | if (nft_trans_chain_update(trans)) { |
| 10862 | − nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, | |
| 10999 | + nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, NULL, | |
| 10863 | 11000 | &nft_trans_chain_hooks(trans)); |
| 10864 | − if (!(table->flags & NFT_TABLE_F_DORMANT)) { | |
| 10865 | − nft_netdev_unregister_hooks(net, | |
| 10866 | − &nft_trans_chain_hooks(trans), | |
| 10867 | − true); | |
| 10868 | − } | |
| 11001 | + nft_netdev_unregister_trans_hook(net, table, | |
| 11002 | + &nft_trans_chain_hooks(trans)); | |
| 10869 | 11003 | } else { |
| 10870 | 11004 | nft_chain_del(nft_trans_chain(trans)); |
| 10871 | 11005 | nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, |
| 10872 | − NULL); | |
| 11006 | + NULL, NULL); | |
| 10873 | 11007 | nf_tables_unregister_hook(ctx.net, ctx.table, |
| 10874 | 11008 | nft_trans_chain(trans)); |
| 10875 | 11009 | } |
| @@ -10975,14 +11109,16 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) · 99 unmodified lines | ||
| 10975 | 11109 | nf_tables_flowtable_notify(&ctx, |
| 10976 | 11110 | nft_trans_flowtable(trans), |
| 10977 | 11111 | &nft_trans_flowtable_hooks(trans), |
| 11112 | + NULL, | |
| 10978 | 11113 | NFT_MSG_NEWFLOWTABLE); |
| 10979 | − list_splice(&nft_trans_flowtable_hooks(trans), | |
| 10980 | − &nft_trans_flowtable(trans)->hook_list); | |
| 11114 | + list_splice_rcu(&nft_trans_flowtable_hooks(trans), | |
| 11115 | + &nft_trans_flowtable(trans)->hook_list); | |
| 10981 | 11116 | } else { |
| 10982 | 11117 | nft_clear(net, nft_trans_flowtable(trans)); |
| 10983 | 11118 | nf_tables_flowtable_notify(&ctx, |
| 10984 | 11119 | nft_trans_flowtable(trans), |
| 10985 | 11120 | NULL, |
| 11121 | + NULL, | |
| 10986 | 11122 | NFT_MSG_NEWFLOWTABLE); |
| 10987 | 11123 | } |
| 10988 | 11124 | nft_trans_destroy(trans); |
| @@ -10992,16 +11128,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) · 3 unmodified lines | ||
| 10992 | 11128 | if (nft_trans_flowtable_update(trans)) { |
| 10993 | 11129 | nf_tables_flowtable_notify(&ctx, |
| 10994 | 11130 | nft_trans_flowtable(trans), |
| 11131 | + NULL, | |
| 10995 | 11132 | &nft_trans_flowtable_hooks(trans), |
| 10996 | 11133 | trans->msg_type); |
| 10997 | − nft_unregister_flowtable_net_hooks(net, | |
| 10998 | − nft_trans_flowtable(trans), | |
| 10999 | − &nft_trans_flowtable_hooks(trans)); | |
| 11134 | + nft_flowtable_unregister_trans_hook(net, | |
| 11135 | + nft_trans_flowtable(trans), | |
| 11136 | + &nft_trans_flowtable_hooks(trans)); | |
| 11000 | 11137 | } else { |
| 11001 | 11138 | list_del_rcu(&nft_trans_flowtable(trans)->list); |
| 11002 | 11139 | nf_tables_flowtable_notify(&ctx, |
| 11003 | 11140 | nft_trans_flowtable(trans), |
| 11004 | 11141 | NULL, |
| 11142 | + NULL, | |
| 11005 | 11143 | trans->msg_type); |
| 11006 | 11144 | nft_unregister_flowtable_net_hooks(net, |
| 11007 | 11145 | nft_trans_flowtable(trans), |
| @@ -11165,8 +11303,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) · 157 unmodified lines | ||
| 11165 | 11303 | case NFT_MSG_DELCHAIN: |
| 11166 | 11304 | case NFT_MSG_DESTROYCHAIN: |
| 11167 | 11305 | if (nft_trans_chain_update(trans)) { |
| 11168 | − list_splice(&nft_trans_chain_hooks(trans), | |
| 11169 | − &nft_trans_basechain(trans)->hook_list); | |
| 11306 | + nft_trans_delhook_abort(&nft_trans_chain_hooks(trans)); | |
| 11170 | 11307 | } else { |
| 11171 | 11308 | nft_use_inc_restore(&table->use); |
| 11172 | 11309 | nft_clear(trans->net, nft_trans_chain(trans)); |
| @@ -11280,8 +11417,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) · 107 unmodified lines | ||
| 11280 | 11417 | case NFT_MSG_DELFLOWTABLE: |
| 11281 | 11418 | case NFT_MSG_DESTROYFLOWTABLE: |
| 11282 | 11419 | if (nft_trans_flowtable_update(trans)) { |
| 11283 | − list_splice(&nft_trans_flowtable_hooks(trans), | |
| 11284 | − &nft_trans_flowtable(trans)->hook_list); | |
| 11420 | + nft_trans_delhook_abort(&nft_trans_flowtable_hooks(trans)); | |
| 11285 | 11421 | } else { |
| 11286 | 11422 | nft_use_inc_restore(&table->use); |
| 11287 | 11423 | nft_clear(trans->net, nft_trans_flowtable(trans)); |
| @@ -196,7 +196,8 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv, · 195 unmodified lines | ||
| 196 | 196 | if (err < 0) |
| 197 | 197 | return err; |
| 198 | 198 | |
| 199 | − if (priv->data.data[0] >= BITS_PER_TYPE(u32)) { | |
| 199 | + if (!priv->data.data[0] || | |
| 200 | + priv->data.data[0] >= BITS_PER_TYPE(u32)) { | |
| 200 | 201 | nft_data_release(&priv->data, desc.type); |
| 201 | 202 | return -EINVAL; |
| 202 | 203 | } |
| @@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, · 62 unmodified lines | ||
| 63 | 63 | return 0; |
| 64 | 64 | |
| 65 | 65 | for (i = sp->len - 1; i >= 0; i--) { |
| 66 | − pos = strict ? i - sp->len + 1 : 0; | |
| 66 | + pos = strict ? sp->len - i - 1 : 0; | |
| 67 | 67 | if (pos >= info->len) |
| 68 | 68 | return 0; |
| 69 | 69 | e = &info->pol[pos]; |
| @@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock) · 207 unmodified lines | ||
| 208 | 208 | sa.spn_family = AF_PHONET; |
| 209 | 209 | err = pn_socket_bind(sock, (struct sockaddr_unsized *)&sa, |
| 210 | 210 | sizeof(struct sockaddr_pn)); |
| 211 | − if (err != -EINVAL) | |
| 211 | + /* | |
| 212 | + * pn_socket_bind() also returns -EINVAL when sk_state != TCP_CLOSE | |
| 213 | + * without a prior bind, so -EINVAL alone is not sufficient to infer | |
| 214 | + * that the socket was already bound. Only treat it as "already | |
| 215 | + * bound" when the port is non-zero; otherwise propagate the error | |
| 216 | + * instead of crashing the kernel. | |
| 217 | + */ | |
| 218 | + if (err != -EINVAL || unlikely(!pn_port(pn_sk(sock->sk)->sobject))) | |
| 212 | 219 | return err; |
| 213 | − BUG_ON(!pn_port(pn_sk(sock->sk)->sobject)); | |
| 214 | 220 | return 0; /* socket was already bound */ |
| 215 | 221 | } |
| 216 | 222 | |
| @@ -76,7 +76,7 @@ static const struct genl_split_ops psp_nl_ops[] = { · 75 unmodified lines | ||
| 76 | 76 | .post_doit = psp_device_unlock, |
| 77 | 77 | .policy = psp_dev_set_nl_policy, |
| 78 | 78 | .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA, |
| 79 | − .flags = GENL_CMD_CAP_DO, | |
| 79 | + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, | |
| 80 | 80 | }, |
| 81 | 81 | { |
| 82 | 82 | .cmd = PSP_CMD_KEY_ROTATE, |
| @@ -85,7 +85,7 @@ static const struct genl_split_ops psp_nl_ops[] = { · 2 unmodified lines | ||
| 85 | 85 | .post_doit = psp_device_unlock, |
| 86 | 86 | .policy = psp_key_rotate_nl_policy, |
| 87 | 87 | .maxattr = PSP_A_DEV_ID, |
| 88 | − .flags = GENL_CMD_CAP_DO, | |
| 88 | + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, | |
| 89 | 89 | }, |
| 90 | 90 | { |
| 91 | 91 | .cmd = PSP_CMD_RX_ASSOC, |
| @@ -305,8 +305,13 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, · 304 unmodified lines | ||
| 305 | 305 | |
| 306 | 306 | psd = psp_dev_get_for_sock(socket->sk); |
| 307 | 307 | if (psd) { |
| 308 | − err = psp_dev_check_access(psd, genl_info_net(info)); | |
| 309 | − if (err) { | |
| 308 | + /* Extra care needed here, psp_dev_get_for_sock() only gives | |
| 309 | + * us access to struct psp_dev's memory, which is quite weak. | |
| 310 | + */ | |
| 311 | + mutex_lock(&psd->lock); | |
| 312 | + if (!psp_dev_is_registered(psd) || | |
| 313 | + psp_dev_check_access(psd, genl_info_net(info))) { | |
| 314 | + mutex_unlock(&psd->lock); | |
| 310 | 315 | psp_dev_put(psd); |
| 311 | 316 | psd = NULL; |
| 312 | 317 | } |
| @@ -319,7 +324,6 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, · 6 unmodified lines | ||
| 319 | 324 | |
| 320 | 325 | id = info->attrs[PSP_A_ASSOC_DEV_ID]; |
| 321 | 326 | if (psd) { |
| 322 | − mutex_lock(&psd->lock); | |
| 323 | 327 | if (id && psd->id != nla_get_u32(id)) { |
| 324 | 328 | mutex_unlock(&psd->lock); |
| 325 | 329 | NL_SET_ERR_MSG_ATTR(info->extack, id, |
| @@ -813,7 +813,7 @@ skip_hash: · 812 unmodified lines | ||
| 813 | 813 | i++, k = (k + 1) % CAKE_SET_WAYS) { |
| 814 | 814 | if (q->tags[outer_hash + k] == flow_hash) { |
| 815 | 815 | if (i) |
| 816 | − q->way_hits++; | |
| 816 | + WRITE_ONCE(q->way_hits, q->way_hits + 1); | |
| 817 | 817 | |
| 818 | 818 | if (!q->flows[outer_hash + k].set) { |
| 819 | 819 | /* need to increment host refcnts */ |
| @@ -831,7 +831,7 @@ skip_hash: · 11 unmodified lines | ||
| 831 | 831 | for (i = 0; i < CAKE_SET_WAYS; |
| 832 | 832 | i++, k = (k + 1) % CAKE_SET_WAYS) { |
| 833 | 833 | if (!q->flows[outer_hash + k].set) { |
| 834 | − q->way_misses++; | |
| 834 | + WRITE_ONCE(q->way_misses, q->way_misses + 1); | |
| 835 | 835 | allocate_src = cake_dsrc(flow_mode); |
| 836 | 836 | allocate_dst = cake_ddst(flow_mode); |
| 837 | 837 | goto found; |
| @@ -841,7 +841,7 @@ skip_hash: · 3 unmodified lines | ||
| 841 | 841 | /* With no empty queues, default to the original |
| 842 | 842 | * queue, accept the collision, update the host tags. |
| 843 | 843 | */ |
| 844 | − q->way_collisions++; | |
| 844 | + WRITE_ONCE(q->way_collisions, q->way_collisions + 1); | |
| 845 | 845 | allocate_src = cake_dsrc(flow_mode); |
| 846 | 846 | allocate_dst = cake_ddst(flow_mode); |
| 847 | 847 | |
| @@ -1379,9 +1379,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off) · 531 unmodified lines | ||
| 1379 | 1379 | len -= off; |
| 1380 | 1380 | |
| 1381 | 1381 | if (qd->max_netlen < len) |
| 1382 | − qd->max_netlen = len; | |
| 1382 | + WRITE_ONCE(qd->max_netlen, len); | |
| 1383 | 1383 | if (qd->min_netlen > len) |
| 1384 | − qd->min_netlen = len; | |
| 1384 | + WRITE_ONCE(qd->min_netlen, len); | |
| 1385 | 1385 | |
| 1386 | 1386 | len += q->rate_overhead; |
| 1387 | 1387 | |
| @@ -1401,9 +1401,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off) · 13 unmodified lines | ||
| 1401 | 1401 | } |
| 1402 | 1402 | |
| 1403 | 1403 | if (qd->max_adjlen < len) |
| 1404 | − qd->max_adjlen = len; | |
| 1404 | + WRITE_ONCE(qd->max_adjlen, len); | |
| 1405 | 1405 | if (qd->min_adjlen > len) |
| 1406 | − qd->min_adjlen = len; | |
| 1406 | + WRITE_ONCE(qd->min_adjlen, len); | |
| 1407 | 1407 | |
| 1408 | 1408 | return len; |
| 1409 | 1409 | } |
| @@ -1416,7 +1416,7 @@ static u32 cake_overhead(struct cake_sched_data *q, const struct sk_buff *skb) · 6 unmodified lines | ||
| 1416 | 1416 | u16 segs = qdisc_pkt_segs(skb); |
| 1417 | 1417 | u32 len = qdisc_pkt_len(skb); |
| 1418 | 1418 | |
| 1419 | − q->avg_netoff = cake_ewma(q->avg_netoff, off << 16, 8); | |
| 1419 | + WRITE_ONCE(q->avg_netoff, cake_ewma(q->avg_netoff, off << 16, 8)); | |
| 1420 | 1420 | |
| 1421 | 1421 | if (segs == 1) |
| 1422 | 1422 | return cake_calc_overhead(q, len, off); |
| @@ -1590,16 +1590,17 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) · 167 unmodified lines | ||
| 1590 | 1590 | } |
| 1591 | 1591 | |
| 1592 | 1592 | if (cobalt_queue_full(&flow->cvars, &b->cparams, now)) |
| 1593 | − b->unresponsive_flow_count++; | |
| 1593 | + WRITE_ONCE(b->unresponsive_flow_count, | |
| 1594 | + b->unresponsive_flow_count + 1); | |
| 1594 | 1595 | |
| 1595 | 1596 | len = qdisc_pkt_len(skb); |
| 1596 | 1597 | q->buffer_used -= skb->truesize; |
| 1597 | 1598 | b->backlogs[idx] -= len; |
| 1598 | − b->tin_backlog -= len; | |
| 1599 | + WRITE_ONCE(b->tin_backlog, b->tin_backlog - len); | |
| 1599 | 1600 | sch->qstats.backlog -= len; |
| 1600 | 1601 | |
| 1601 | 1602 | flow->dropped++; |
| 1602 | − b->tin_dropped++; | |
| 1603 | + WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); | |
| 1603 | 1604 | |
| 1604 | 1605 | if (q->config->rate_flags & CAKE_FLAG_INGRESS) |
| 1605 | 1606 | cake_advance_shaper(q, b, skb, now, true); |
| @@ -1795,7 +1796,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 189 unmodified lines | ||
| 1795 | 1796 | } |
| 1796 | 1797 | |
| 1797 | 1798 | if (unlikely(len > b->max_skblen)) |
| 1798 | − b->max_skblen = len; | |
| 1799 | + WRITE_ONCE(b->max_skblen, len); | |
| 1799 | 1800 | |
| 1800 | 1801 | if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) { |
| 1801 | 1802 | struct sk_buff *segs, *nskb; |
| @@ -1819,15 +1820,15 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 17 unmodified lines | ||
| 1819 | 1820 | numsegs++; |
| 1820 | 1821 | slen += segs->len; |
| 1821 | 1822 | q->buffer_used += segs->truesize; |
| 1822 | − b->packets++; | |
| 1823 | + WRITE_ONCE(b->packets, b->packets + 1); | |
| 1823 | 1824 | } |
| 1824 | 1825 | |
| 1825 | 1826 | /* stats */ |
| 1826 | − b->bytes += slen; | |
| 1827 | 1827 | b->backlogs[idx] += slen; |
| 1828 | − b->tin_backlog += slen; | |
| 1829 | 1828 | sch->qstats.backlog += slen; |
| 1830 | 1829 | q->avg_window_bytes += slen; |
| 1830 | + WRITE_ONCE(b->bytes, b->bytes + slen); | |
| 1831 | + WRITE_ONCE(b->tin_backlog, b->tin_backlog + slen); | |
| 1831 | 1832 | |
| 1832 | 1833 | qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); |
| 1833 | 1834 | consume_skb(skb); |
| @@ -1843,10 +1844,10 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 9 unmodified lines | ||
| 1843 | 1844 | ack = cake_ack_filter(q, flow); |
| 1844 | 1845 | |
| 1845 | 1846 | if (ack) { |
| 1846 | − b->ack_drops++; | |
| 1847 | + WRITE_ONCE(b->ack_drops, b->ack_drops + 1); | |
| 1847 | 1848 | sch->qstats.drops++; |
| 1848 | 1849 | ack_pkt_len = qdisc_pkt_len(ack); |
| 1849 | − b->bytes += ack_pkt_len; | |
| 1850 | + WRITE_ONCE(b->bytes, b->bytes + ack_pkt_len); | |
| 1850 | 1851 | q->buffer_used += skb->truesize - ack->truesize; |
| 1851 | 1852 | if (q->config->rate_flags & CAKE_FLAG_INGRESS) |
| 1852 | 1853 | cake_advance_shaper(q, b, ack, now, true); |
| @@ -1859,12 +1860,12 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 6 unmodified lines | ||
| 1859 | 1860 | } |
| 1860 | 1861 | |
| 1861 | 1862 | /* stats */ |
| 1862 | − b->packets++; | |
| 1863 | − b->bytes += len - ack_pkt_len; | |
| 1863 | + WRITE_ONCE(b->packets, b->packets + 1); | |
| 1864 | 1864 | b->backlogs[idx] += len - ack_pkt_len; |
| 1865 | − b->tin_backlog += len - ack_pkt_len; | |
| 1866 | 1865 | sch->qstats.backlog += len - ack_pkt_len; |
| 1867 | 1866 | q->avg_window_bytes += len - ack_pkt_len; |
| 1867 | + WRITE_ONCE(b->bytes, b->bytes + len - ack_pkt_len); | |
| 1868 | + WRITE_ONCE(b->tin_backlog, b->tin_backlog + len - ack_pkt_len); | |
| 1868 | 1869 | } |
| 1869 | 1870 | |
| 1870 | 1871 | if (q->overflow_timeout) |
| @@ -1894,9 +1895,9 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 23 unmodified lines | ||
| 1894 | 1895 | u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC; |
| 1895 | 1896 | |
| 1896 | 1897 | b = div64_u64(b, window_interval); |
| 1897 | − q->avg_peak_bandwidth = | |
| 1898 | − cake_ewma(q->avg_peak_bandwidth, b, | |
| 1899 | − b > q->avg_peak_bandwidth ? 2 : 8); | |
| 1898 | + WRITE_ONCE(q->avg_peak_bandwidth, | |
| 1899 | + cake_ewma(q->avg_peak_bandwidth, b, | |
| 1900 | + b > q->avg_peak_bandwidth ? 2 : 8)); | |
| 1900 | 1901 | q->avg_window_bytes = 0; |
| 1901 | 1902 | q->avg_window_begin = now; |
| 1902 | 1903 | |
| @@ -1917,11 +1918,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 14 unmodified lines | ||
| 1917 | 1918 | if (!flow->set) { |
| 1918 | 1919 | list_add_tail(&flow->flowchain, &b->new_flows); |
| 1919 | 1920 | } else { |
| 1920 | − b->decaying_flow_count--; | |
| 1921 | + WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1); | |
| 1921 | 1922 | list_move_tail(&flow->flowchain, &b->new_flows); |
| 1922 | 1923 | } |
| 1923 | 1924 | flow->set = CAKE_SET_SPARSE; |
| 1924 | − b->sparse_flow_count++; | |
| 1925 | + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count + 1); | |
| 1925 | 1926 | |
| 1926 | 1927 | flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode); |
| 1927 | 1928 | } else if (flow->set == CAKE_SET_SPARSE_WAIT) { |
| @@ -1929,15 +1930,15 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 1 unmodified line | ||
| 1929 | 1930 | * in the bulk rotation. |
| 1930 | 1931 | */ |
| 1931 | 1932 | flow->set = CAKE_SET_BULK; |
| 1932 | − b->sparse_flow_count--; | |
| 1933 | − b->bulk_flow_count++; | |
| 1933 | + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); | |
| 1934 | + WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1); | |
| 1934 | 1935 | |
| 1935 | 1936 | cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 1936 | 1937 | cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 1937 | 1938 | } |
| 1938 | 1939 | |
| 1939 | 1940 | if (q->buffer_used > q->buffer_max_used) |
| 1940 | − q->buffer_max_used = q->buffer_used; | |
| 1941 | + WRITE_ONCE(q->buffer_max_used, q->buffer_used); | |
| 1941 | 1942 | |
| 1942 | 1943 | if (q->buffer_used <= q->buffer_limit) |
| 1943 | 1944 | return NET_XMIT_SUCCESS; |
| @@ -1977,7 +1978,7 @@ static struct sk_buff *cake_dequeue_one(struct Qdisc *sch) · 33 unmodified lines | ||
| 1977 | 1978 | skb = dequeue_head(flow); |
| 1978 | 1979 | len = qdisc_pkt_len(skb); |
| 1979 | 1980 | b->backlogs[q->cur_flow] -= len; |
| 1980 | − b->tin_backlog -= len; | |
| 1981 | + WRITE_ONCE(b->tin_backlog, b->tin_backlog - len); | |
| 1981 | 1982 | sch->qstats.backlog -= len; |
| 1982 | 1983 | q->buffer_used -= skb->truesize; |
| 1983 | 1984 | sch->q.qlen--; |
| @@ -2042,7 +2043,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) · 58 unmodified lines | ||
| 2042 | 2043 | |
| 2043 | 2044 | cake_configure_rates(sch, new_rate, true); |
| 2044 | 2045 | q->last_checked_active = now; |
| 2045 | − q->active_queues = num_active_qs; | |
| 2046 | + WRITE_ONCE(q->active_queues, num_active_qs); | |
| 2046 | 2047 | } |
| 2047 | 2048 | |
| 2048 | 2049 | begin: |
| @@ -2149,8 +2150,8 @@ retry: · 100 unmodified lines | ||
| 2149 | 2150 | */ |
| 2150 | 2151 | if (flow->set == CAKE_SET_SPARSE) { |
| 2151 | 2152 | if (flow->head) { |
| 2152 | − b->sparse_flow_count--; | |
| 2153 | − b->bulk_flow_count++; | |
| 2153 | + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); | |
| 2154 | + WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1); | |
| 2154 | 2155 | |
| 2155 | 2156 | cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2156 | 2157 | cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| @@ -2177,7 +2178,8 @@ retry: · 20 unmodified lines | ||
| 2177 | 2178 | if (!skb) { |
| 2178 | 2179 | /* this queue was actually empty */ |
| 2179 | 2180 | if (cobalt_queue_empty(&flow->cvars, &b->cparams, now)) |
| 2180 | − b->unresponsive_flow_count--; | |
| 2181 | + WRITE_ONCE(b->unresponsive_flow_count, | |
| 2182 | + b->unresponsive_flow_count - 1); | |
| 2181 | 2183 | |
| 2182 | 2184 | if (flow->cvars.p_drop || flow->cvars.count || |
| 2183 | 2185 | ktime_before(now, flow->cvars.drop_next)) { |
| @@ -2187,32 +2189,32 @@ retry: · 3 unmodified lines | ||
| 2187 | 2189 | list_move_tail(&flow->flowchain, |
| 2188 | 2190 | &b->decaying_flows); |
| 2189 | 2191 | if (flow->set == CAKE_SET_BULK) { |
| 2190 | − b->bulk_flow_count--; | |
| 2192 | + WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1); | |
| 2191 | 2193 | |
| 2192 | 2194 | cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2193 | 2195 | cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2194 | 2196 | |
| 2195 | − b->decaying_flow_count++; | |
| 2197 | + WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1); | |
| 2196 | 2198 | } else if (flow->set == CAKE_SET_SPARSE || |
| 2197 | 2199 | flow->set == CAKE_SET_SPARSE_WAIT) { |
| 2198 | − b->sparse_flow_count--; | |
| 2199 | − b->decaying_flow_count++; | |
| 2200 | + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); | |
| 2201 | + WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1); | |
| 2200 | 2202 | } |
| 2201 | 2203 | flow->set = CAKE_SET_DECAYING; |
| 2202 | 2204 | } else { |
| 2203 | 2205 | /* remove empty queue from the flowchain */ |
| 2204 | 2206 | list_del_init(&flow->flowchain); |
| 2205 | 2207 | if (flow->set == CAKE_SET_SPARSE || |
| 2206 | − flow->set == CAKE_SET_SPARSE_WAIT) | |
| 2207 | − b->sparse_flow_count--; | |
| 2208 | − else if (flow->set == CAKE_SET_BULK) { | |
| 2209 | − b->bulk_flow_count--; | |
| 2208 | + flow->set == CAKE_SET_SPARSE_WAIT) { | |
| 2209 | + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); | |
| 2210 | + } else if (flow->set == CAKE_SET_BULK) { | |
| 2211 | + WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1); | |
| 2210 | 2212 | |
| 2211 | 2213 | cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2212 | 2214 | cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2213 | − } else | |
| 2214 | − b->decaying_flow_count--; | |
| 2215 | − | |
| 2215 | + } else { | |
| 2216 | + WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1); | |
| 2217 | + } | |
| 2216 | 2218 | flow->set = CAKE_SET_NONE; |
| 2217 | 2219 | } |
| 2218 | 2220 | goto begin; |
| @@ -2234,7 +2236,7 @@ retry: · 15 unmodified lines | ||
| 2234 | 2236 | b->tin_deficit -= len; |
| 2235 | 2237 | } |
| 2236 | 2238 | flow->dropped++; |
| 2237 | − b->tin_dropped++; | |
| 2239 | + WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); | |
| 2238 | 2240 | qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); |
| 2239 | 2241 | qdisc_qstats_drop(sch); |
| 2240 | 2242 | qdisc_dequeue_drop(sch, skb, reason); |
| @@ -2242,17 +2244,19 @@ retry: · 1 unmodified line | ||
| 2242 | 2244 | goto retry; |
| 2243 | 2245 | } |
| 2244 | 2246 | |
| 2245 | − b->tin_ecn_mark += !!flow->cvars.ecn_marked; | |
| 2247 | + WRITE_ONCE(b->tin_ecn_mark, b->tin_ecn_mark + !!flow->cvars.ecn_marked); | |
| 2246 | 2248 | qdisc_bstats_update(sch, skb); |
| 2247 | 2249 | WRITE_ONCE(q->last_active, now); |
| 2248 | 2250 | |
| 2249 | 2251 | /* collect delay stats */ |
| 2250 | 2252 | delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); |
| 2251 | − b->avge_delay = cake_ewma(b->avge_delay, delay, 8); | |
| 2252 | − b->peak_delay = cake_ewma(b->peak_delay, delay, | |
| 2253 | − delay > b->peak_delay ? 2 : 8); | |
| 2254 | − b->base_delay = cake_ewma(b->base_delay, delay, | |
| 2255 | − delay < b->base_delay ? 2 : 8); | |
| 2253 | + WRITE_ONCE(b->avge_delay, cake_ewma(b->avge_delay, delay, 8)); | |
| 2254 | + WRITE_ONCE(b->peak_delay, | |
| 2255 | + cake_ewma(b->peak_delay, delay, | |
| 2256 | + delay > b->peak_delay ? 2 : 8)); | |
| 2257 | + WRITE_ONCE(b->base_delay, | |
| 2258 | + cake_ewma(b->base_delay, delay, | |
| 2259 | + delay < b->base_delay ? 2 : 8)); | |
| 2256 | 2260 | |
| 2257 | 2261 | len = cake_advance_shaper(q, b, skb, now, false); |
| 2258 | 2262 | flow->deficit -= len; |
| @@ -2329,9 +2333,9 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, · 70 unmodified lines | ||
| 2329 | 2333 | u8 rate_shft = 0; |
| 2330 | 2334 | u64 rate_ns = 0; |
| 2331 | 2335 | |
| 2332 | − b->flow_quantum = 1514; | |
| 2333 | 2336 | if (rate) { |
| 2334 | − b->flow_quantum = max(min(rate >> 12, 1514ULL), 300ULL); | |
| 2337 | + WRITE_ONCE(b->flow_quantum, | |
| 2338 | + max(min(rate >> 12, 1514ULL), 300ULL)); | |
| 2335 | 2339 | rate_shft = 34; |
| 2336 | 2340 | rate_ns = ((u64)NSEC_PER_SEC) << rate_shft; |
| 2337 | 2341 | rate_ns = div64_u64(rate_ns, max(MIN_RATE, rate)); |
| @@ -2339,9 +2343,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, · 1 unmodified line | ||
| 2339 | 2343 | rate_ns >>= 1; |
| 2340 | 2344 | rate_shft--; |
| 2341 | 2345 | } |
| 2342 | − } /* else unlimited, ie. zero delay */ | |
| 2343 | − | |
| 2344 | − b->tin_rate_bps = rate; | |
| 2346 | + } else { | |
| 2347 | + /* else unlimited, ie. zero delay */ | |
| 2348 | + WRITE_ONCE(b->flow_quantum, 1514); | |
| 2349 | + } | |
| 2350 | + WRITE_ONCE(b->tin_rate_bps, rate); | |
| 2345 | 2351 | b->tin_rate_ns = rate_ns; |
| 2346 | 2352 | b->tin_rate_shft = rate_shft; |
| 2347 | 2353 | |
| @@ -2350,10 +2356,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, · 2 unmodified lines | ||
| 2350 | 2356 | |
| 2351 | 2357 | byte_target_ns = (byte_target * rate_ns) >> rate_shft; |
| 2352 | 2358 | |
| 2353 | − b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); | |
| 2354 | − b->cparams.interval = max(rtt_est_ns + | |
| 2355 | − b->cparams.target - target_ns, | |
| 2356 | − b->cparams.target * 2); | |
| 2359 | + WRITE_ONCE(b->cparams.target, | |
| 2360 | + max((byte_target_ns * 3) / 2, target_ns)); | |
| 2361 | + WRITE_ONCE(b->cparams.interval, | |
| 2362 | + max(rtt_est_ns + b->cparams.target - target_ns, | |
| 2363 | + b->cparams.target * 2)); | |
| 2357 | 2364 | b->cparams.mtu_time = byte_target_ns; |
| 2358 | 2365 | b->cparams.p_inc = 1 << 24; /* 1/256 */ |
| 2359 | 2366 | b->cparams.p_dec = 1 << 20; /* 1/4096 */ |
| @@ -2611,25 +2618,27 @@ static void cake_reconfigure(struct Qdisc *sch) · 251 unmodified lines | ||
| 2611 | 2618 | { |
| 2612 | 2619 | struct cake_sched_data *qd = qdisc_priv(sch); |
| 2613 | 2620 | struct cake_sched_config *q = qd->config; |
| 2621 | + u32 buffer_limit; | |
| 2614 | 2622 | |
| 2615 | 2623 | cake_configure_rates(sch, qd->config->rate_bps, false); |
| 2616 | 2624 | |
| 2617 | 2625 | if (q->buffer_config_limit) { |
| 2618 | − qd->buffer_limit = q->buffer_config_limit; | |
| 2626 | + buffer_limit = q->buffer_config_limit; | |
| 2619 | 2627 | } else if (q->rate_bps) { |
| 2620 | 2628 | u64 t = q->rate_bps * q->interval; |
| 2621 | 2629 | |
| 2622 | 2630 | do_div(t, USEC_PER_SEC / 4); |
| 2623 | − qd->buffer_limit = max_t(u32, t, 4U << 20); | |
| 2631 | + buffer_limit = max_t(u32, t, 4U << 20); | |
| 2624 | 2632 | } else { |
| 2625 | − qd->buffer_limit = ~0; | |
| 2633 | + buffer_limit = ~0; | |
| 2626 | 2634 | } |
| 2627 | 2635 | |
| 2628 | 2636 | sch->flags &= ~TCQ_F_CAN_BYPASS; |
| 2629 | 2637 | |
| 2630 | − qd->buffer_limit = min(qd->buffer_limit, | |
| 2631 | − max(sch->limit * psched_mtu(qdisc_dev(sch)), | |
| 2632 | − q->buffer_config_limit)); | |
| 2638 | + WRITE_ONCE(qd->buffer_limit, | |
| 2639 | + min(buffer_limit, | |
| 2640 | + max(sch->limit * psched_mtu(qdisc_dev(sch)), | |
| 2641 | + q->buffer_config_limit))); | |
| 2633 | 2642 | } |
| 2634 | 2643 | |
| 2635 | 2644 | static int cake_config_change(struct cake_sched_config *q, struct nlattr *opt, |
| @@ -2774,10 +2783,10 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt, · 138 unmodified lines | ||
| 2774 | 2783 | return ret; |
| 2775 | 2784 | |
| 2776 | 2785 | if (overhead_changed) { |
| 2777 | − qd->max_netlen = 0; | |
| 2778 | − qd->max_adjlen = 0; | |
| 2779 | − qd->min_netlen = ~0; | |
| 2780 | − qd->min_adjlen = ~0; | |
| 2786 | + WRITE_ONCE(qd->max_netlen, 0); | |
| 2787 | + WRITE_ONCE(qd->max_adjlen, 0); | |
| 2788 | + WRITE_ONCE(qd->min_netlen, ~0); | |
| 2789 | + WRITE_ONCE(qd->min_adjlen, ~0); | |
| 2781 | 2790 | } |
| 2782 | 2791 | |
| 2783 | 2792 | if (qd->tins) { |
| @@ -2995,15 +3004,15 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) · 211 unmodified lines | ||
| 2995 | 3004 | goto nla_put_failure; \ |
| 2996 | 3005 | } while (0) |
| 2997 | 3006 | |
| 2998 | − PUT_STAT_U64(CAPACITY_ESTIMATE64, q->avg_peak_bandwidth); | |
| 2999 | − PUT_STAT_U32(MEMORY_LIMIT, q->buffer_limit); | |
| 3000 | − PUT_STAT_U32(MEMORY_USED, q->buffer_max_used); | |
| 3001 | − PUT_STAT_U32(AVG_NETOFF, ((q->avg_netoff + 0x8000) >> 16)); | |
| 3002 | − PUT_STAT_U32(MAX_NETLEN, q->max_netlen); | |
| 3003 | − PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen); | |
| 3004 | − PUT_STAT_U32(MIN_NETLEN, q->min_netlen); | |
| 3005 | − PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen); | |
| 3006 | − PUT_STAT_U32(ACTIVE_QUEUES, q->active_queues); | |
| 3007 | + PUT_STAT_U64(CAPACITY_ESTIMATE64, READ_ONCE(q->avg_peak_bandwidth)); | |
| 3008 | + PUT_STAT_U32(MEMORY_LIMIT, READ_ONCE(q->buffer_limit)); | |
| 3009 | + PUT_STAT_U32(MEMORY_USED, READ_ONCE(q->buffer_max_used)); | |
| 3010 | + PUT_STAT_U32(AVG_NETOFF, ((READ_ONCE(q->avg_netoff) + 0x8000) >> 16)); | |
| 3011 | + PUT_STAT_U32(MAX_NETLEN, READ_ONCE(q->max_netlen)); | |
| 3012 | + PUT_STAT_U32(MAX_ADJLEN, READ_ONCE(q->max_adjlen)); | |
| 3013 | + PUT_STAT_U32(MIN_NETLEN, READ_ONCE(q->min_netlen)); | |
| 3014 | + PUT_STAT_U32(MIN_ADJLEN, READ_ONCE(q->min_adjlen)); | |
| 3015 | + PUT_STAT_U32(ACTIVE_QUEUES, READ_ONCE(q->active_queues)); | |
| 3007 | 3016 | |
| 3008 | 3017 | #undef PUT_STAT_U32 |
| 3009 | 3018 | #undef PUT_STAT_U64 |
| @@ -3029,38 +3038,38 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) · 19 unmodified lines | ||
| 3029 | 3038 | if (!ts) |
| 3030 | 3039 | goto nla_put_failure; |
| 3031 | 3040 | |
| 3032 | − PUT_TSTAT_U64(THRESHOLD_RATE64, b->tin_rate_bps); | |
| 3033 | − PUT_TSTAT_U64(SENT_BYTES64, b->bytes); | |
| 3034 | − PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); | |
| 3041 | + PUT_TSTAT_U64(THRESHOLD_RATE64, READ_ONCE(b->tin_rate_bps)); | |
| 3042 | + PUT_TSTAT_U64(SENT_BYTES64, READ_ONCE(b->bytes)); | |
| 3043 | + PUT_TSTAT_U32(BACKLOG_BYTES, READ_ONCE(b->tin_backlog)); | |
| 3035 | 3044 | |
| 3036 | 3045 | PUT_TSTAT_U32(TARGET_US, |
| 3037 | − ktime_to_us(ns_to_ktime(b->cparams.target))); | |
| 3046 | + ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); | |
| 3038 | 3047 | PUT_TSTAT_U32(INTERVAL_US, |
| 3039 | − ktime_to_us(ns_to_ktime(b->cparams.interval))); | |
| 3048 | + ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); | |
| 3040 | 3049 | |
| 3041 | − PUT_TSTAT_U32(SENT_PACKETS, b->packets); | |
| 3042 | − PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); | |
| 3043 | − PUT_TSTAT_U32(ECN_MARKED_PACKETS, b->tin_ecn_mark); | |
| 3044 | − PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, b->ack_drops); | |
| 3050 | + PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets)); | |
| 3051 | + PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped)); | |
| 3052 | + PUT_TSTAT_U32(ECN_MARKED_PACKETS, READ_ONCE(b->tin_ecn_mark)); | |
| 3053 | + PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, READ_ONCE(b->ack_drops)); | |
| 3045 | 3054 | |
| 3046 | 3055 | PUT_TSTAT_U32(PEAK_DELAY_US, |
| 3047 | − ktime_to_us(ns_to_ktime(b->peak_delay))); | |
| 3056 | + ktime_to_us(ns_to_ktime(READ_ONCE(b->peak_delay)))); | |
| 3048 | 3057 | PUT_TSTAT_U32(AVG_DELAY_US, |
| 3049 | − ktime_to_us(ns_to_ktime(b->avge_delay))); | |
| 3058 | + ktime_to_us(ns_to_ktime(READ_ONCE(b->avge_delay)))); | |
| 3050 | 3059 | PUT_TSTAT_U32(BASE_DELAY_US, |
| 3051 | − ktime_to_us(ns_to_ktime(b->base_delay))); | |
| 3060 | + ktime_to_us(ns_to_ktime(READ_ONCE(b->base_delay)))); | |
| 3052 | 3061 | |
| 3053 | − PUT_TSTAT_U32(WAY_INDIRECT_HITS, b->way_hits); | |
| 3054 | − PUT_TSTAT_U32(WAY_MISSES, b->way_misses); | |
| 3055 | − PUT_TSTAT_U32(WAY_COLLISIONS, b->way_collisions); | |
| 3062 | + PUT_TSTAT_U32(WAY_INDIRECT_HITS, READ_ONCE(b->way_hits)); | |
| 3063 | + PUT_TSTAT_U32(WAY_MISSES, READ_ONCE(b->way_misses)); | |
| 3064 | + PUT_TSTAT_U32(WAY_COLLISIONS, READ_ONCE(b->way_collisions)); | |
| 3056 | 3065 | |
| 3057 | − PUT_TSTAT_U32(SPARSE_FLOWS, b->sparse_flow_count + | |
| 3058 | − b->decaying_flow_count); | |
| 3059 | − PUT_TSTAT_U32(BULK_FLOWS, b->bulk_flow_count); | |
| 3060 | − PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, b->unresponsive_flow_count); | |
| 3061 | − PUT_TSTAT_U32(MAX_SKBLEN, b->max_skblen); | |
| 3066 | + PUT_TSTAT_U32(SPARSE_FLOWS, READ_ONCE(b->sparse_flow_count) + | |
| 3067 | + READ_ONCE(b->decaying_flow_count)); | |
| 3068 | + PUT_TSTAT_U32(BULK_FLOWS, READ_ONCE(b->bulk_flow_count)); | |
| 3069 | + PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, READ_ONCE(b->unresponsive_flow_count)); | |
| 3070 | + PUT_TSTAT_U32(MAX_SKBLEN, READ_ONCE(b->max_skblen)); | |
| 3062 | 3071 | |
| 3063 | − PUT_TSTAT_U32(FLOW_QUANTUM, b->flow_quantum); | |
| 3072 | + PUT_TSTAT_U32(FLOW_QUANTUM, READ_ONCE(b->flow_quantum)); | |
| 3064 | 3073 | nla_nest_end(d->skb, ts); |
| 3065 | 3074 | } |
| 3066 | 3075 | |
| @@ -3298,10 +3307,10 @@ static int cake_mq_change(struct Qdisc *sch, struct nlattr *opt, · 231 unmodified lines | ||
| 3298 | 3307 | struct cake_sched_data *qd = qdisc_priv(chld); |
| 3299 | 3308 | |
| 3300 | 3309 | if (overhead_changed) { |
| 3301 | − qd->max_netlen = 0; | |
| 3302 | − qd->max_adjlen = 0; | |
| 3303 | − qd->min_netlen = ~0; | |
| 3304 | − qd->min_adjlen = ~0; | |
| 3310 | + WRITE_ONCE(qd->max_netlen, 0); | |
| 3311 | + WRITE_ONCE(qd->max_adjlen, 0); | |
| 3312 | + WRITE_ONCE(qd->min_netlen, ~0); | |
| 3313 | + WRITE_ONCE(qd->min_adjlen, ~0); | |
| 3305 | 3314 | } |
| 3306 | 3315 | |
| 3307 | 3316 | if (qd->tins) { |
| @@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 228 unmodified lines | ||
| 229 | 229 | |
| 230 | 230 | /* Draw a packet at random from queue and compare flow */ |
| 231 | 231 | if (choke_match_random(q, skb, &idx)) { |
| 232 | − q->stats.matched++; | |
| 232 | + WRITE_ONCE(q->stats.matched, q->stats.matched + 1); | |
| 233 | 233 | choke_drop_by_idx(sch, idx, to_free); |
| 234 | 234 | goto congestion_drop; |
| 235 | 235 | } |
| @@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 5 unmodified lines | ||
| 241 | 241 | qdisc_qstats_overlimit(sch); |
| 242 | 242 | if (use_harddrop(q) || !use_ecn(q) || |
| 243 | 243 | !INET_ECN_set_ce(skb)) { |
| 244 | − q->stats.forced_drop++; | |
| 244 | + WRITE_ONCE(q->stats.forced_drop, | |
| 245 | + q->stats.forced_drop + 1); | |
| 245 | 246 | goto congestion_drop; |
| 246 | 247 | } |
| 247 | 248 | |
| 248 | − q->stats.forced_mark++; | |
| 249 | + WRITE_ONCE(q->stats.forced_mark, | |
| 250 | + q->stats.forced_mark + 1); | |
| 249 | 251 | } else if (++q->vars.qcount) { |
| 250 | 252 | if (red_mark_probability(p, &q->vars, q->vars.qavg)) { |
| 251 | 253 | q->vars.qcount = 0; |
| @@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 1 unmodified line | ||
| 253 | 255 | |
| 254 | 256 | qdisc_qstats_overlimit(sch); |
| 255 | 257 | if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { |
| 256 | − q->stats.prob_drop++; | |
| 258 | + WRITE_ONCE(q->stats.prob_drop, | |
| 259 | + q->stats.prob_drop + 1); | |
| 257 | 260 | goto congestion_drop; |
| 258 | 261 | } |
| 259 | 262 | |
| 260 | − q->stats.prob_mark++; | |
| 263 | + WRITE_ONCE(q->stats.prob_mark, | |
| 264 | + q->stats.prob_mark + 1); | |
| 261 | 265 | } |
| 262 | 266 | } else |
| 263 | 267 | q->vars.qR = red_random(p); |
| @@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 8 unmodified lines | ||
| 272 | 276 | return NET_XMIT_SUCCESS; |
| 273 | 277 | } |
| 274 | 278 | |
| 275 | − q->stats.pdrop++; | |
| 279 | + WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); | |
| 276 | 280 | return qdisc_drop(skb, sch, to_free); |
| 277 | 281 | |
| 278 | 282 | congestion_drop: |
| @@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) · 182 unmodified lines | ||
| 461 | 465 | { |
| 462 | 466 | struct choke_sched_data *q = qdisc_priv(sch); |
| 463 | 467 | struct tc_choke_xstats st = { |
| 464 | − .early = q->stats.prob_drop + q->stats.forced_drop, | |
| 465 | − .marked = q->stats.prob_mark + q->stats.forced_mark, | |
| 466 | − .pdrop = q->stats.pdrop, | |
| 467 | − .matched = q->stats.matched, | |
| 468 | + .early = READ_ONCE(q->stats.prob_drop) + | |
| 469 | + READ_ONCE(q->stats.forced_drop), | |
| 470 | + .marked = READ_ONCE(q->stats.prob_mark) + | |
| 471 | + READ_ONCE(q->stats.forced_mark), | |
| 472 | + .pdrop = READ_ONCE(q->stats.pdrop), | |
| 473 | + .matched = READ_ONCE(q->stats.matched), | |
| 468 | 474 | }; |
| 469 | 475 | |
| 470 | 476 | return gnet_stats_copy_app(d, &st, sizeof(st)); |
| @@ -509,18 +509,19 @@ nla_put_failure: · 508 unmodified lines | ||
| 509 | 509 | static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) |
| 510 | 510 | { |
| 511 | 511 | struct fq_pie_sched_data *q = qdisc_priv(sch); |
| 512 | − struct tc_fq_pie_xstats st = { | |
| 513 | − .packets_in = q->stats.packets_in, | |
| 514 | − .overlimit = q->stats.overlimit, | |
| 515 | − .overmemory = q->overmemory, | |
| 516 | − .dropped = q->stats.dropped, | |
| 517 | − .ecn_mark = q->stats.ecn_mark, | |
| 518 | − .new_flow_count = q->new_flow_count, | |
| 519 | − .memory_usage = q->memory_usage, | |
| 520 | − }; | |
| 512 | + struct tc_fq_pie_xstats st = { 0 }; | |
| 521 | 513 | struct list_head *pos; |
| 522 | 514 | |
| 523 | 515 | sch_tree_lock(sch); |
| 516 | + | |
| 517 | + st.packets_in = q->stats.packets_in; | |
| 518 | + st.overlimit = q->stats.overlimit; | |
| 519 | + st.overmemory = q->overmemory; | |
| 520 | + st.dropped = q->stats.dropped; | |
| 521 | + st.ecn_mark = q->stats.ecn_mark; | |
| 522 | + st.new_flow_count = q->new_flow_count; | |
| 523 | + st.memory_usage = q->memory_usage; | |
| 524 | + | |
| 524 | 525 | list_for_each(pos, &q->new_flows) |
| 525 | 526 | st.new_flows_len++; |
| 526 | 527 | |
| @@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q) · 226 unmodified lines | ||
| 227 | 227 | if (rnd < clg->a4) { |
| 228 | 228 | clg->state = LOST_IN_GAP_PERIOD; |
| 229 | 229 | return true; |
| 230 | − } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { | |
| 230 | + } else if (rnd < clg->a1 + clg->a4) { | |
| 231 | 231 | clg->state = LOST_IN_BURST_PERIOD; |
| 232 | 232 | return true; |
| 233 | − } else if (clg->a1 + clg->a4 < rnd) { | |
| 233 | + } else { | |
| 234 | 234 | clg->state = TX_IN_GAP_PERIOD; |
| 235 | 235 | } |
| 236 | 236 | |
| @@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q) · 10 unmodified lines | ||
| 247 | 247 | case LOST_IN_BURST_PERIOD: |
| 248 | 248 | if (rnd < clg->a3) |
| 249 | 249 | clg->state = TX_IN_BURST_PERIOD; |
| 250 | − else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { | |
| 250 | + else if (rnd < clg->a2 + clg->a3) { | |
| 251 | 251 | clg->state = TX_IN_GAP_PERIOD; |
| 252 | − } else if (clg->a2 + clg->a3 < rnd) { | |
| 252 | + } else { | |
| 253 | 253 | clg->state = LOST_IN_BURST_PERIOD; |
| 254 | 254 | return true; |
| 255 | 255 | } |
| @@ -524,7 +524,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 268 unmodified lines | ||
| 524 | 524 | 1 << get_random_u32_below(8); |
| 525 | 525 | } |
| 526 | 526 | |
| 527 | − if (unlikely(q->t_len >= sch->limit)) { | |
| 527 | + if (unlikely(sch->q.qlen >= sch->limit)) { | |
| 528 | 528 | /* re-link segs, so that qdisc_drop_all() frees them all */ |
| 529 | 529 | skb->next = segs; |
| 530 | 530 | qdisc_drop_all(skb, sch, to_free); |
| @@ -659,9 +659,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) · 128 unmodified lines | ||
| 659 | 659 | |
| 660 | 660 | if (!q->slot_dist) |
| 661 | 661 | next_delay = q->slot_config.min_delay + |
| 662 | − (get_random_u32() * | |
| 663 | − (q->slot_config.max_delay - | |
| 664 | − q->slot_config.min_delay) >> 32); | |
| 662 | + mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, | |
| 663 | + get_random_u32(), 32); | |
| 665 | 664 | else |
| 666 | 665 | next_delay = tabledist(q->slot_config.dist_delay, |
| 667 | 666 | (s32)(q->slot_config.dist_jitter), |
| @@ -827,6 +826,39 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) · 159 unmodified lines | ||
| 827 | 826 | return 0; |
| 828 | 827 | } |
| 829 | 828 | |
| 829 | +static int validate_time(const struct nlattr *attr, const char *name, | |
| 830 | + struct netlink_ext_ack *extack) | |
| 831 | +{ | |
| 832 | + if (nla_get_s64(attr) < 0) { | |
| 833 | + NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name); | |
| 834 | + return -EINVAL; | |
| 835 | + } | |
| 836 | + return 0; | |
| 837 | +} | |
| 838 | + | |
| 839 | +static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) | |
| 840 | +{ | |
| 841 | + const struct tc_netem_slot *c = nla_data(attr); | |
| 842 | + | |
| 843 | + if (c->min_delay < 0 || c->max_delay < 0) { | |
| 844 | + NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); | |
| 845 | + return -EINVAL; | |
| 846 | + } | |
| 847 | + if (c->min_delay > c->max_delay) { | |
| 848 | + NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); | |
| 849 | + return -EINVAL; | |
| 850 | + } | |
| 851 | + if (c->dist_delay < 0 || c->dist_jitter < 0) { | |
| 852 | + NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); | |
| 853 | + return -EINVAL; | |
| 854 | + } | |
| 855 | + if (c->max_packets < 0 || c->max_bytes < 0) { | |
| 856 | + NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); | |
| 857 | + return -EINVAL; | |
| 858 | + } | |
| 859 | + return 0; | |
| 860 | +} | |
| 861 | + | |
| 830 | 862 | static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) |
| 831 | 863 | { |
| 832 | 864 | const struct tc_netem_slot *c = nla_data(attr); |
| @@ -1040,6 +1072,24 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, · 207 unmodified lines | ||
| 1040 | 1072 | goto table_free; |
| 1041 | 1073 | } |
| 1042 | 1074 | |
| 1075 | + if (tb[TCA_NETEM_SLOT]) { | |
| 1076 | + ret = validate_slot(tb[TCA_NETEM_SLOT], extack); | |
| 1077 | + if (ret) | |
| 1078 | + goto table_free; | |
| 1079 | + } | |
| 1080 | + | |
| 1081 | + if (tb[TCA_NETEM_LATENCY64]) { | |
| 1082 | + ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack); | |
| 1083 | + if (ret) | |
| 1084 | + goto table_free; | |
| 1085 | + } | |
| 1086 | + | |
| 1087 | + if (tb[TCA_NETEM_JITTER64]) { | |
| 1088 | + ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack); | |
| 1089 | + if (ret) | |
| 1090 | + goto table_free; | |
| 1091 | + } | |
| 1092 | + | |
| 1043 | 1093 | sch_tree_lock(sch); |
| 1044 | 1094 | /* backup q->clg and q->loss_model */ |
| 1045 | 1095 | old_clg = q->clg; |
| @@ -1112,11 +1162,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, · 66 unmodified lines | ||
| 1112 | 1162 | /* capping jitter to the range acceptable by tabledist() */ |
| 1113 | 1163 | q->jitter = min_t(s64, abs(q->jitter), INT_MAX); |
| 1114 | 1164 | |
| 1115 | − if (tb[TCA_NETEM_PRNG_SEED]) | |
| 1165 | + if (tb[TCA_NETEM_PRNG_SEED]) { | |
| 1116 | 1166 | q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); |
| 1117 | − else | |
| 1118 | − q->prng.seed = get_random_u64(); | |
| 1119 | − prandom_seed_state(&q->prng.prng_state, q->prng.seed); | |
| 1167 | + prandom_seed_state(&q->prng.prng_state, q->prng.seed); | |
| 1168 | + } | |
| 1120 | 1169 | |
| 1121 | 1170 | unlock: |
| 1122 | 1171 | sch_tree_unlock(sch); |
| @@ -1139,6 +1188,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, · 16 unmodified lines | ||
| 1139 | 1188 | return -EINVAL; |
| 1140 | 1189 | |
| 1141 | 1190 | q->loss_model = CLG_RANDOM; |
| 1191 | + q->prng.seed = get_random_u64(); | |
| 1192 | + prandom_seed_state(&q->prng.prng_state, q->prng.seed); | |
| 1193 | + | |
| 1142 | 1194 | ret = netem_change(sch, opt, extack); |
| 1143 | 1195 | if (ret) |
| 1144 | 1196 | pr_info("netem: change failed\n"); |
| @@ -634,7 +634,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 633 unmodified lines | ||
| 634 | 634 | queue = skb_get_queue_mapping(skb); |
| 635 | 635 | |
| 636 | 636 | child = q->qdiscs[queue]; |
| 637 | − if (unlikely(!child)) | |
| 637 | + if (unlikely(child == &noop_qdisc)) | |
| 638 | 638 | return qdisc_drop(skb, sch, to_free); |
| 639 | 639 | |
| 640 | 640 | if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { |
| @@ -717,7 +717,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, · 76 unmodified lines | ||
| 717 | 717 | int len; |
| 718 | 718 | u8 tc; |
| 719 | 719 | |
| 720 | − if (unlikely(!child)) | |
| 720 | + if (unlikely(child == &noop_qdisc)) | |
| 721 | 721 | return NULL; |
| 722 | 722 | |
| 723 | 723 | if (TXTIME_ASSIST_IS_ENABLED(q->flags)) |
| @@ -2184,6 +2184,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, · 1460 unmodified lines | ||
| 2184 | 2184 | if (!dev_queue) |
| 2185 | 2185 | return -EINVAL; |
| 2186 | 2186 | |
| 2187 | + if (!new) | |
| 2188 | + new = &noop_qdisc; | |
| 2189 | + | |
| 2187 | 2190 | if (dev->flags & IFF_UP) |
| 2188 | 2191 | dev_deactivate(dev, false); |
| 2189 | 2192 | |
| @@ -2197,14 +2200,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, · 7 unmodified lines | ||
| 2197 | 2200 | *old = q->qdiscs[cl - 1]; |
| 2198 | 2201 | if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { |
| 2199 | 2202 | WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); |
| 2200 | − if (new) | |
| 2203 | + if (new != &noop_qdisc) | |
| 2201 | 2204 | qdisc_refcount_inc(new); |
| 2202 | − if (*old) | |
| 2205 | + if (*old && *old != &noop_qdisc) | |
| 2203 | 2206 | qdisc_put(*old); |
| 2204 | 2207 | } |
| 2205 | 2208 | |
| 2206 | 2209 | q->qdiscs[cl - 1] = new; |
| 2207 | − if (new) | |
| 2210 | + if (new != &noop_qdisc) | |
| 2208 | 2211 | new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; |
| 2209 | 2212 | |
| 2210 | 2213 | if (dev->flags & IFF_UP) |
| @@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( · 1555 unmodified lines | ||
| 1556 | 1556 | /* Tag the variable length parameters. */ |
| 1557 | 1557 | chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); |
| 1558 | 1558 | |
| 1559 | + if (asoc->state >= SCTP_STATE_ESTABLISHED) { | |
| 1560 | + /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ | |
| 1561 | + if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) | |
| 1562 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | |
| 1563 | + } | |
| 1564 | + | |
| 1559 | 1565 | /* Verify the INIT chunk before processing it. */ |
| 1560 | 1566 | err_chunk = NULL; |
| 1561 | 1567 | if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, |
| @@ -188,6 +188,7 @@ int tls_strp_dev_init(void); · 187 unmodified lines | ||
| 188 | 188 | void tls_strp_dev_exit(void); |
| 189 | 189 | |
| 190 | 190 | void tls_strp_done(struct tls_strparser *strp); |
| 191 | +void __tls_strp_done(struct tls_strparser *strp); | |
| 191 | 192 | void tls_strp_stop(struct tls_strparser *strp); |
| 192 | 193 | int tls_strp_init(struct tls_strparser *strp, struct sock *sk); |
| 193 | 194 | void tls_strp_data_ready(struct tls_strparser *strp); |
| @@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp) · 623 unmodified lines | ||
| 624 | 624 | WARN_ON(!strp->stopped); |
| 625 | 625 | |
| 626 | 626 | cancel_work_sync(&strp->work); |
| 627 | + __tls_strp_done(strp); | |
| 628 | +} | |
| 629 | + | |
| 630 | +/* For setup error paths where the strparser was initialized but never armed. */ | |
| 631 | +void __tls_strp_done(struct tls_strparser *strp) | |
| 632 | +{ | |
| 627 | 633 | tls_strp_anchor_free(strp); |
| 628 | 634 | } |
| 629 | 635 | |
| @@ -2624,8 +2624,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) · 2623 unmodified lines | ||
| 2624 | 2624 | void tls_sw_free_resources_rx(struct sock *sk) |
| 2625 | 2625 | { |
| 2626 | 2626 | struct tls_context *tls_ctx = tls_get_ctx(sk); |
| 2627 | + struct tls_sw_context_rx *ctx; | |
| 2628 | + | |
| 2629 | + ctx = tls_sw_ctx_rx(tls_ctx); | |
| 2627 | 2630 | |
| 2628 | 2631 | tls_sw_release_resources_rx(sk); |
| 2632 | + __tls_strp_done(&ctx->strp); | |
| 2629 | 2633 | tls_sw_free_ctx_rx(tls_ctx); |
| 2630 | 2634 | } |
| 2631 | 2635 | |
| @@ -375,10 +375,10 @@ static void hvs_open_connection(struct vmbus_channel *chan) · 374 unmodified lines | ||
| 375 | 375 | } else { |
| 376 | 376 | sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE); |
| 377 | 377 | sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE); |
| 378 | − sndbuf = ALIGN(sndbuf, HV_HYP_PAGE_SIZE); | |
| 378 | + sndbuf = VMBUS_RING_SIZE(sndbuf); | |
| 379 | 379 | rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE); |
| 380 | 380 | rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE); |
| 381 | − rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE); | |
| 381 | + rcvbuf = VMBUS_RING_SIZE(rcvbuf); | |
| 382 | 382 | } |
| 383 | 383 | |
| 384 | 384 | chan->max_pkt_size = HVS_MAX_PKT_SIZE; |
| @@ -2966,7 +2966,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, · 2965 unmodified lines | ||
| 2966 | 2966 | { |
| 2967 | 2967 | const struct cred_security_struct *crsec = selinux_cred(current_cred()); |
| 2968 | 2968 | struct superblock_security_struct *sbsec; |
| 2969 | − struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count); | |
| 2969 | + struct xattr *xattr; | |
| 2970 | 2970 | u32 newsid, clen; |
| 2971 | 2971 | u16 newsclass; |
| 2972 | 2972 | int rc; |
| @@ -2992,6 +2992,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, · 19 unmodified lines | ||
| 2992 | 2992 | !(sbsec->flags & SBLABEL_MNT)) |
| 2993 | 2993 | return -EOPNOTSUPP; |
| 2994 | 2994 | |
| 2995 | + xattr = lsm_get_xattr_slot(xattrs, xattr_count); | |
| 2995 | 2996 | if (xattr) { |
| 2996 | 2997 | rc = security_sid_to_context_force(newsid, |
| 2997 | 2998 | &context, &clen); |
| @@ -3208,15 +3209,13 @@ static inline int task_avdcache_search(struct task_security_struct *tsec, · 210 unmodified lines | ||
| 3208 | 3209 | * @tsec: the task's security state |
| 3209 | 3210 | * @isec: the inode associated with the cache entry |
| 3210 | 3211 | * @avd: the AVD to cache |
| 3211 | − * @audited: the permission audit bitmask to cache | |
| 3212 | 3212 | * |
| 3213 | − * Update the AVD cache in @tsec with the @avdc and @audited info associated | |
| 3213 | + * Update the AVD cache in @tsec with the @avd info associated | |
| 3214 | 3214 | * with @isec. |
| 3215 | 3215 | */ |
| 3216 | 3216 | static inline void task_avdcache_update(struct task_security_struct *tsec, |
| 3217 | 3217 | struct inode_security_struct *isec, |
| 3218 | − struct av_decision *avd, | |
| 3219 | − u32 audited) | |
| 3218 | + struct av_decision *avd) | |
| 3220 | 3219 | { |
| 3221 | 3220 | int spot; |
| 3222 | 3221 | |
| @@ -3228,9 +3227,7 @@ static inline void task_avdcache_update(struct task_security_struct *tsec, · 5 unmodified lines | ||
| 3228 | 3227 | spot = (tsec->avdcache.dir_spot + 1) & (TSEC_AVDC_DIR_SIZE - 1); |
| 3229 | 3228 | tsec->avdcache.dir_spot = spot; |
| 3230 | 3229 | tsec->avdcache.dir[spot].isid = isec->sid; |
| 3231 | − tsec->avdcache.dir[spot].audited = audited; | |
| 3232 | − tsec->avdcache.dir[spot].allowed = avd->allowed; | |
| 3233 | − tsec->avdcache.dir[spot].permissive = avd->flags & AVD_FLAGS_PERMISSIVE; | |
| 3230 | + tsec->avdcache.dir[spot].avd = *avd; | |
| 3234 | 3231 | tsec->avdcache.permissive_neveraudit = |
| 3235 | 3232 | (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT)); |
| 3236 | 3233 | } |
| @@ -3251,6 +3248,7 @@ static int selinux_inode_permission(struct inode *inode, int requested) · 14 unmodified lines | ||
| 3251 | 3248 | struct task_security_struct *tsec; |
| 3252 | 3249 | struct inode_security_struct *isec; |
| 3253 | 3250 | struct avdc_entry *avdc; |
| 3251 | + struct av_decision avd, *avdp = &avd; | |
| 3254 | 3252 | int rc, rc2; |
| 3255 | 3253 | u32 audited, denied; |
| 3256 | 3254 | |
| @@ -3272,23 +3270,21 @@ static int selinux_inode_permission(struct inode *inode, int requested) · 15 unmodified lines | ||
| 3272 | 3270 | rc = task_avdcache_search(tsec, isec, &avdc); |
| 3273 | 3271 | if (likely(!rc)) { |
| 3274 | 3272 | /* Cache hit. */ |
| 3275 | − audited = perms & avdc->audited; | |
| 3276 | − denied = perms & ~avdc->allowed; | |
| 3277 | − if (unlikely(denied && enforcing_enabled() && | |
| 3278 | − !avdc->permissive)) | |
| 3273 | + avdp = &avdc->avd; | |
| 3274 | + denied = perms & ~avdp->allowed; | |
| 3275 | + if (unlikely(denied) && enforcing_enabled() && | |
| 3276 | + !(avdp->flags & AVD_FLAGS_PERMISSIVE)) | |
| 3279 | 3277 | rc = -EACCES; |
| 3280 | 3278 | } else { |
| 3281 | − struct av_decision avd; | |
| 3282 | − | |
| 3283 | 3279 | /* Cache miss. */ |
| 3284 | 3280 | rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, |
| 3285 | − perms, 0, &avd); | |
| 3286 | − audited = avc_audit_required(perms, &avd, rc, | |
| 3287 | − (requested & MAY_ACCESS) ? FILE__AUDIT_ACCESS : 0, | |
| 3288 | − &denied); | |
| 3289 | − task_avdcache_update(tsec, isec, &avd, audited); | |
| 3281 | + perms, 0, avdp); | |
| 3282 | + task_avdcache_update(tsec, isec, avdp); | |
| 3290 | 3283 | } |
| 3291 | 3284 | |
| 3285 | + audited = avc_audit_required(perms, avdp, rc, | |
| 3286 | + (requested & MAY_ACCESS) ? | |
| 3287 | + FILE__AUDIT_ACCESS : 0, &denied); | |
| 3292 | 3288 | if (likely(!audited)) |
| 3293 | 3289 | return rc; |
| 3294 | 3290 | |
| @@ -4920,7 +4916,7 @@ static bool sock_skip_has_perm(u32 sid) · 1625 unmodified lines | ||
| 4920 | 4916 | |
| 4921 | 4917 | static int sock_has_perm(struct sock *sk, u32 perms) |
| 4922 | 4918 | { |
| 4923 | − struct sk_security_struct *sksec = sk->sk_security; | |
| 4919 | + struct sk_security_struct *sksec = selinux_sock(sk); | |
| 4924 | 4920 | struct common_audit_data ad; |
| 4925 | 4921 | struct lsm_network_audit net; |
| 4926 | 4922 | |
| @@ -6227,7 +6223,7 @@ static unsigned int selinux_ip_postroute(void *priv, · 1300 unmodified lines | ||
| 6227 | 6223 | |
| 6228 | 6224 | static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_type) |
| 6229 | 6225 | { |
| 6230 | − struct sk_security_struct *sksec = sk->sk_security; | |
| 6226 | + struct sk_security_struct *sksec = selinux_sock(sk); | |
| 6231 | 6227 | struct common_audit_data ad; |
| 6232 | 6228 | u8 driver; |
| 6233 | 6229 | u8 xperm; |
| @@ -32,9 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | struct avdc_entry { |
| 34 | 34 | u32 isid; /* inode SID */ |
| 35 | − u32 allowed; /* allowed permission bitmask */ | |
| 36 | − u32 audited; /* audited permission bitmask */ | |
| 37 | − bool permissive; /* AVC permissive flag */ | |
| 35 | + struct av_decision avd; /* av decision */ | |
| 38 | 36 | }; |
| 39 | 37 | |
| 40 | 38 | struct cred_security_struct { |
| @@ -2155,10 +2155,16 @@ static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file) · 2154 unmodified lines | ||
| 2155 | 2155 | |
| 2156 | 2156 | psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
| 2157 | 2157 | csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; |
| 2158 | − if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger) | |
| 2159 | − result |= PCM_ENABLE_OUTPUT; | |
| 2160 | − if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger) | |
| 2161 | − result |= PCM_ENABLE_INPUT; | |
| 2158 | + if (psubstream && psubstream->runtime) { | |
| 2159 | + guard(mutex)(&psubstream->runtime->oss.params_lock); | |
| 2160 | + if (psubstream->runtime->oss.trigger) | |
| 2161 | + result |= PCM_ENABLE_OUTPUT; | |
| 2162 | + } | |
| 2163 | + if (csubstream && csubstream->runtime) { | |
| 2164 | + guard(mutex)(&csubstream->runtime->oss.params_lock); | |
| 2165 | + if (csubstream->runtime->oss.trigger) | |
| 2166 | + result |= PCM_ENABLE_INPUT; | |
| 2167 | + } | |
| 2162 | 2168 | return result; |
| 2163 | 2169 | } |
| 2164 | 2170 | |
| @@ -2832,6 +2838,17 @@ static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) · 667 unmodified lines | ||
| 2832 | 2838 | runtime->oss.period_frames; |
| 2833 | 2839 | } |
| 2834 | 2840 | |
| 2841 | +static bool need_input_retrigger(struct snd_pcm_runtime *runtime) | |
| 2842 | +{ | |
| 2843 | + bool ret; | |
| 2844 | + | |
| 2845 | + guard(mutex)(&runtime->oss.params_lock); | |
| 2846 | + ret = runtime->oss.trigger; | |
| 2847 | + if (ret) | |
| 2848 | + runtime->oss.trigger = 0; | |
| 2849 | + return ret; | |
| 2850 | +} | |
| 2851 | + | |
| 2835 | 2852 | static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) |
| 2836 | 2853 | { |
| 2837 | 2854 | struct snd_pcm_oss_file *pcm_oss_file; |
| @@ -2864,11 +2881,11 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) · 26 unmodified lines | ||
| 2864 | 2881 | snd_pcm_oss_capture_ready(csubstream)) |
| 2865 | 2882 | mask |= EPOLLIN | EPOLLRDNORM; |
| 2866 | 2883 | } |
| 2867 | − if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) { | |
| 2884 | + if (ostate != SNDRV_PCM_STATE_RUNNING && | |
| 2885 | + need_input_retrigger(runtime)) { | |
| 2868 | 2886 | struct snd_pcm_oss_file ofile; |
| 2869 | 2887 | memset(&ofile, 0, sizeof(ofile)); |
| 2870 | 2888 | ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; |
| 2871 | − runtime->oss.trigger = 0; | |
| 2872 | 2889 | snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT); |
| 2873 | 2890 | } |
| 2874 | 2891 | } |
| @@ -99,6 +99,9 @@ struct loopback_ops { · 98 unmodified lines | ||
| 99 | 99 | struct loopback_cable { |
| 100 | 100 | spinlock_t lock; |
| 101 | 101 | struct loopback_pcm *streams[2]; |
| 102 | + /* in-flight peer stops running outside cable->lock */ | |
| 103 | + atomic_t stop_count; | |
| 104 | + wait_queue_head_t stop_wait; | |
| 102 | 105 | struct snd_pcm_hardware hw; |
| 103 | 106 | /* flags */ |
| 104 | 107 | unsigned int valid; |
| @@ -366,8 +369,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) · 261 unmodified lines | ||
| 366 | 369 | return 0; |
| 367 | 370 | if (stream == SNDRV_PCM_STREAM_CAPTURE) |
| 368 | 371 | return -EIO; |
| 369 | − else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) | |
| 372 | + else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) { | |
| 373 | + /* close must not free the peer runtime below */ | |
| 374 | + atomic_inc(&cable->stop_count); | |
| 370 | 375 | stop_capture = true; |
| 376 | + } | |
| 371 | 377 | } |
| 372 | 378 | |
| 373 | 379 | setup = get_setup(dpcm_play); |
| @@ -396,8 +402,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) · 22 unmodified lines | ||
| 396 | 402 | } |
| 397 | 403 | } |
| 398 | 404 | |
| 399 | − if (stop_capture) | |
| 405 | + if (stop_capture) { | |
| 400 | 406 | snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING); |
| 407 | + if (atomic_dec_and_test(&cable->stop_count)) | |
| 408 | + wake_up(&cable->stop_wait); | |
| 409 | + } | |
| 401 | 410 | |
| 402 | 411 | return 0; |
| 403 | 412 | } |
| @@ -1049,23 +1058,29 @@ static void free_cable(struct snd_pcm_substream *substream) · 645 unmodified lines | ||
| 1049 | 1058 | struct loopback *loopback = substream->private_data; |
| 1050 | 1059 | int dev = get_cable_index(substream); |
| 1051 | 1060 | struct loopback_cable *cable; |
| 1061 | + struct loopback_pcm *dpcm; | |
| 1062 | + bool other_alive; | |
| 1052 | 1063 | |
| 1053 | 1064 | cable = loopback->cables[substream->number][dev]; |
| 1054 | 1065 | if (!cable) |
| 1055 | 1066 | return; |
| 1056 | − if (cable->streams[!substream->stream]) { | |
| 1057 | − /* other stream is still alive */ | |
| 1058 | − guard(spinlock_irq)(&cable->lock); | |
| 1059 | − cable->streams[substream->stream] = NULL; | |
| 1060 | − } else { | |
| 1061 | − struct loopback_pcm *dpcm = substream->runtime->private_data; | |
| 1062 | 1067 | |
| 1063 | − if (cable->ops && cable->ops->close_cable && dpcm) | |
| 1064 | − cable->ops->close_cable(dpcm); | |
| 1065 | − /* free the cable */ | |
| 1066 | − loopback->cables[substream->number][dev] = NULL; | |
| 1067 | − kfree(cable); | |
| 1068 | + scoped_guard(spinlock_irq, &cable->lock) { | |
| 1069 | + cable->streams[substream->stream] = NULL; | |
| 1070 | + other_alive = cable->streams[!substream->stream]; | |
| 1068 | 1071 | } |
| 1072 | + | |
| 1073 | + /* Pair with the stop_count increment in loopback_check_format(). */ | |
| 1074 | + wait_event(cable->stop_wait, !atomic_read(&cable->stop_count)); | |
| 1075 | + if (other_alive) | |
| 1076 | + return; | |
| 1077 | + | |
| 1078 | + dpcm = substream->runtime->private_data; | |
| 1079 | + if (cable->ops && cable->ops->close_cable && dpcm) | |
| 1080 | + cable->ops->close_cable(dpcm); | |
| 1081 | + /* free the cable */ | |
| 1082 | + loopback->cables[substream->number][dev] = NULL; | |
| 1083 | + kfree(cable); | |
| 1069 | 1084 | } |
| 1070 | 1085 | |
| 1071 | 1086 | static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) |
| @@ -1260,6 +1275,8 @@ static int loopback_open(struct snd_pcm_substream *substream) · 188 unmodified lines | ||
| 1260 | 1275 | goto unlock; |
| 1261 | 1276 | } |
| 1262 | 1277 | spin_lock_init(&cable->lock); |
| 1278 | + atomic_set(&cable->stop_count, 0); | |
| 1279 | + init_waitqueue_head(&cable->stop_wait); | |
| 1263 | 1280 | cable->hw = loopback_pcm_hardware; |
| 1264 | 1281 | if (loopback->timer_source) |
| 1265 | 1282 | cable->ops = &loopback_snd_timer_ops; |
| @@ -7,7 +7,6 @@ snd-hda-codec-cm9825-y := cm9825.o · 6 unmodified lines | ||
| 7 | 7 | snd-hda-codec-analog-y := analog.o |
| 8 | 8 | snd-hda-codec-ca0110-y := ca0110.o |
| 9 | 9 | snd-hda-codec-ca0132-y := ca0132.o |
| 10 | −snd-hda-codec-cmedia-y := cmedia.o | |
| 11 | 10 | snd-hda-codec-conexant-y := conexant.o |
| 12 | 11 | snd-hda-codec-idt-y := sigmatel.o |
| 13 | 12 | snd-hda-codec-senarytech-y := senarytech.o |
| @@ -26,7 +25,6 @@ obj-$(CONFIG_SND_HDA_CODEC_CM9825) += snd-hda-codec-cm9825.o · 12 unmodified lines | ||
| 26 | 25 | obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o |
| 27 | 26 | obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o |
| 28 | 27 | obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o |
| 29 | −obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o | |
| 30 | 28 | obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o |
| 31 | 29 | obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o |
| 32 | 30 | obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o |
| @@ -1175,6 +1175,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) · 1174 unmodified lines | ||
| 1175 | 1175 | static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) |
| 1176 | 1176 | { |
| 1177 | 1177 | struct conexant_spec *spec; |
| 1178 | + struct hda_jack_callback *callback; | |
| 1178 | 1179 | int err; |
| 1179 | 1180 | |
| 1180 | 1181 | codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); |
| @@ -1190,7 +1191,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) · 9 unmodified lines | ||
| 1190 | 1191 | case 0x14f11f86: |
| 1191 | 1192 | case 0x14f11f87: |
| 1192 | 1193 | spec->is_cx11880_sn6140 = true; |
| 1193 | − snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); | |
| 1194 | + callback = snd_hda_jack_detect_enable_callback(codec, 0x19, | |
| 1195 | + cx_update_headset_mic_vref); | |
| 1196 | + if (IS_ERR(callback)) { | |
| 1197 | + err = PTR_ERR(callback); | |
| 1198 | + goto error; | |
| 1199 | + } | |
| 1194 | 1200 | break; |
| 1195 | 1201 | } |
| 1196 | 1202 | |
| @@ -3694,6 +3694,17 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec, · 3693 unmodified lines | ||
| 3694 | 3694 | spec->power_hook = alc287_s4_power_gpio3_default; |
| 3695 | 3695 | spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; |
| 3696 | 3696 | } |
| 3697 | + | |
| 3698 | +static void alc287_fixup_tb_vmaster_led(struct hda_codec *codec, | |
| 3699 | + const struct hda_fixup *fix, int action) | |
| 3700 | +{ | |
| 3701 | + struct alc_spec *spec = codec->spec; | |
| 3702 | + | |
| 3703 | + if (action == HDA_FIXUP_ACT_PRE_PROBE) | |
| 3704 | + spec->gen.vmaster_mute_led = 1; | |
| 3705 | + | |
| 3706 | + alc287_fixup_bind_dacs(codec, fix, action); | |
| 3707 | +} | |
| 3697 | 3708 | /* GPIO2: mute led GPIO3: micmute led */ |
| 3698 | 3709 | static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec, |
| 3699 | 3710 | const struct hda_fixup *fix, int action) |
| @@ -6448,7 +6459,7 @@ static const struct hda_fixup alc269_fixups[] = { · 2748 unmodified lines | ||
| 6448 | 6459 | }, |
| 6449 | 6460 | [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = { |
| 6450 | 6461 | .type = HDA_FIXUP_FUNC, |
| 6451 | − .v.func = alc287_fixup_bind_dacs, | |
| 6462 | + .v.func = alc287_fixup_tb_vmaster_led, | |
| 6452 | 6463 | .chained = true, |
| 6453 | 6464 | .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, |
| 6454 | 6465 | }, |
| @@ -6717,6 +6728,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { · 262 unmodified lines | ||
| 6717 | 6728 | SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), |
| 6718 | 6729 | SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), |
| 6719 | 6730 | SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), |
| 6731 | + SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), | |
| 6720 | 6732 | SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC), |
| 6721 | 6733 | SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), |
| 6722 | 6734 | SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED), |
| @@ -180,11 +180,15 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol, · 179 unmodified lines | ||
| 180 | 180 | { |
| 181 | 181 | struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); |
| 182 | 182 | unsigned int reg_val; |
| 183 | − int i; | |
| 183 | + int i, ret; | |
| 184 | 184 | |
| 185 | 185 | cs35l56_hda_wait_dsp_ready(cs35l56); |
| 186 | 186 | |
| 187 | − regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val); | |
| 187 | + ret = regmap_read(cs35l56->base.regmap, kcontrol->private_value, | |
| 188 | + ®_val); | |
| 189 | + if (ret) | |
| 190 | + return ret; | |
| 191 | + | |
| 188 | 192 | reg_val &= CS35L56_ASP_TXn_SRC_MASK; |
| 189 | 193 | |
| 190 | 194 | for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) { |
| @@ -203,15 +207,20 @@ static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol, · 12 unmodified lines | ||
| 203 | 207 | struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); |
| 204 | 208 | unsigned int item = ucontrol->value.enumerated.item[0]; |
| 205 | 209 | bool changed; |
| 210 | + int ret; | |
| 206 | 211 | |
| 207 | 212 | if (item >= CS35L56_NUM_INPUT_SRC) |
| 208 | 213 | return -EINVAL; |
| 209 | 214 | |
| 210 | 215 | cs35l56_hda_wait_dsp_ready(cs35l56); |
| 211 | 216 | |
| 212 | − regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, | |
| 213 | − CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], | |
| 214 | − &changed); | |
| 217 | + ret = regmap_update_bits_check(cs35l56->base.regmap, | |
| 218 | + kcontrol->private_value, | |
| 219 | + CS35L56_INPUT_MASK, | |
| 220 | + cs35l56_tx_input_values[item], | |
| 221 | + &changed); | |
| 222 | + if (ret) | |
| 223 | + return ret; | |
| 215 | 224 | |
| 216 | 225 | return changed; |
| 217 | 226 | } |
| @@ -967,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev) · 749 unmodified lines | ||
| 967 | 976 | static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) |
| 968 | 977 | { |
| 969 | 978 | /* The cirrus,dev-index property has the wrong values */ |
| 979 | + cs35l56->num_amps = 2; | |
| 970 | 980 | switch (*bus_addr) { |
| 971 | 981 | case 0x30: |
| 972 | 982 | cs35l56->index = 1; |
| @@ -1016,7 +1026,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) · 43 unmodified lines | ||
| 1016 | 1026 | char hid_string[8]; |
| 1017 | 1027 | struct acpi_device *adev; |
| 1018 | 1028 | const char *property, *sub; |
| 1019 | − size_t nval; | |
| 1020 | 1029 | int i, ret; |
| 1021 | 1030 | |
| 1022 | 1031 | /* |
| @@ -1052,13 +1061,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) · 29 unmodified lines | ||
| 1052 | 1061 | ret = -EINVAL; |
| 1053 | 1062 | goto err; |
| 1054 | 1063 | } |
| 1055 | − nval = ret; | |
| 1064 | + cs35l56->num_amps = ret; | |
| 1056 | 1065 | |
| 1057 | − ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); | |
| 1066 | + ret = device_property_read_u32_array(cs35l56->base.dev, property, values, | |
| 1067 | + cs35l56->num_amps); | |
| 1058 | 1068 | if (ret) |
| 1059 | 1069 | goto err; |
| 1060 | 1070 | |
| 1061 | − for (i = 0; i < nval; i++) { | |
| 1071 | + for (i = 0; i < cs35l56->num_amps; i++) { | |
| 1062 | 1072 | if (values[i] == id) { |
| 1063 | 1073 | cs35l56->index = i; |
| 1064 | 1074 | break; |
| @@ -1081,7 +1091,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) · 16 unmodified lines | ||
| 1081 | 1091 | "Read ACPI _SUB failed(%ld): fallback to generic firmware\n", |
| 1082 | 1092 | PTR_ERR(sub)); |
| 1083 | 1093 | } else { |
| 1084 | − ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1); | |
| 1094 | + ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, | |
| 1095 | + cs35l56->num_amps, -1); | |
| 1085 | 1096 | if (ret == -ENOENT) { |
| 1086 | 1097 | cs35l56->system_name = sub; |
| 1087 | 1098 | } else if (ret >= 0) { |
| @@ -26,6 +26,7 @@ struct cs35l56_hda { · 25 unmodified lines | ||
| 26 | 26 | struct work_struct dsp_work; |
| 27 | 27 | |
| 28 | 28 | int index; |
| 29 | + int num_amps; | |
| 29 | 30 | const char *system_name; |
| 30 | 31 | const char *amp_name; |
| 31 | 32 | |
| @@ -132,10 +132,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv, · 131 unmodified lines | ||
| 132 | 132 | int ret, val; |
| 133 | 133 | |
| 134 | 134 | /* |
| 135 | − * In our TAS2781 SPI mode, read/write was masked in last bit of | |
| 136 | − * address, it cause regmap_update_bits() not work as expected. | |
| 135 | + * In TAS2781 SPI mode, when accessing non-book-zero or page numbers | |
| 136 | + * greater than 1 in book 0, an additional byte must be read. The | |
| 137 | + * first byte in such cases is a dummy byte and should be ignored. | |
| 137 | 138 | */ |
| 138 | − ret = tasdevice_dev_read(tas_priv, chn, reg, &val); | |
| 139 | + if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) { | |
| 140 | + unsigned char buf[2]; | |
| 141 | + | |
| 142 | + ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2); | |
| 143 | + val = buf[1]; | |
| 144 | + } else { | |
| 145 | + ret = tasdevice_dev_read(tas_priv, chn, reg, &val); | |
| 146 | + } | |
| 139 | 147 | if (ret < 0) { |
| 140 | 148 | dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); |
| 141 | 149 | return ret; |
| @@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, · 352 unmodified lines | ||
| 353 | 353 | if (hdmi_channel_mapping[ca][1] == 0) { |
| 354 | 354 | int hdmi_slot = 0; |
| 355 | 355 | /* fill actual channel mappings in ALSA channel (i) order */ |
| 356 | − for (i = 0; i < ch_alloc->channels; i++) { | |
| 357 | − while (!WARN_ON(hdmi_slot >= 8) && | |
| 358 | − !ch_alloc->speakers[7 - hdmi_slot]) | |
| 359 | − hdmi_slot++; /* skip zero slots */ | |
| 356 | + for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { | |
| 357 | + while (!ch_alloc->speakers[7 - hdmi_slot]) { | |
| 358 | + /* skip zero slots */ | |
| 359 | + if (++hdmi_slot >= 8) | |
| 360 | + goto out; | |
| 361 | + } | |
| 360 | 362 | |
| 361 | 363 | hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; |
| 362 | 364 | } |
| 365 | + out: | |
| 363 | 366 | /* fill the rest of the slots with ALSA channel 0xf */ |
| 364 | 367 | for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) |
| 365 | 368 | if (!ch_alloc->speakers[7 - hdmi_slot]) |
| @@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) · 173 unmodified lines | ||
| 174 | 174 | acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; |
| 175 | 175 | |
| 176 | 176 | dmi_id = dmi_first_match(acp_quirk_table); |
| 177 | − if (dmi_id && dmi_id->driver_data) | |
| 177 | + if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) | |
| 178 | 178 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; |
| 179 | 179 | |
| 180 | 180 | ret = acp_legacy_dai_links_create(card); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <sound/soc.h> |
| 21 | 21 | #include <linux/input.h> |
| 22 | 22 | #include <linux/module.h> |
| 23 | +#include <linux/dmi.h> | |
| 23 | 24 | |
| 24 | 25 | #include "../../codecs/rt5682.h" |
| 25 | 26 | #include "../../codecs/rt1019.h" |
| @@ -37,15 +38,21 @@ · 11 unmodified lines | ||
| 37 | 38 | #define NAU8821_FREQ_OUT 12288000 |
| 38 | 39 | #define MAX98388_CODEC_DAI "max98388-aif1" |
| 39 | 40 | |
| 40 | −#define TDM_MODE_ENABLE 1 | |
| 41 | − | |
| 42 | 41 | const struct dmi_system_id acp_quirk_table[] = { |
| 43 | 42 | { |
| 44 | 43 | /* Google skyrim proto-0 */ |
| 45 | 44 | .matches = { |
| 46 | 45 | DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"), |
| 47 | 46 | }, |
| 48 | − .driver_data = (void *)TDM_MODE_ENABLE, | |
| 47 | + .driver_data = (void *)QUIRK_TDM_MODE_ENABLE, | |
| 48 | + }, | |
| 49 | + { | |
| 50 | + /* Valve Steam Deck OLED */ | |
| 51 | + .matches = { | |
| 52 | + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), | |
| 53 | + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), | |
| 54 | + }, | |
| 55 | + .driver_data = (void *)QUIRK_REMAP_DMIC_BT, | |
| 49 | 56 | }, |
| 50 | 57 | {} |
| 51 | 58 | }; |
| @@ -1401,6 +1408,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) · 1349 unmodified lines | ||
| 1401 | 1408 | struct snd_soc_dai_link *links; |
| 1402 | 1409 | struct device *dev = card->dev; |
| 1403 | 1410 | struct acp_card_drvdata *drv_data = card->drvdata; |
| 1411 | + const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table); | |
| 1404 | 1412 | int i = 0, num_links = 0; |
| 1405 | 1413 | |
| 1406 | 1414 | if (drv_data->hs_cpu_id) |
| @@ -1572,6 +1580,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) · 165 unmodified lines | ||
| 1572 | 1580 | links[i].codecs = &snd_soc_dummy_dlc; |
| 1573 | 1581 | links[i].num_codecs = 1; |
| 1574 | 1582 | } |
| 1583 | + | |
| 1584 | + if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) | |
| 1585 | + links[i].id = DMIC_BE_ID; | |
| 1575 | 1586 | i++; |
| 1576 | 1587 | } |
| 1577 | 1588 | |
| @@ -1587,6 +1598,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) · 9 unmodified lines | ||
| 1587 | 1598 | links[i].capture_only = 1; |
| 1588 | 1599 | links[i].nonatomic = true; |
| 1589 | 1600 | links[i].no_pcm = 1; |
| 1601 | + | |
| 1602 | + if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) { | |
| 1603 | + links[i].id = BT_BE_ID; | |
| 1604 | + dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n"); | |
| 1605 | + } | |
| 1590 | 1606 | } |
| 1591 | 1607 | |
| 1592 | 1608 | card->dai_link = links; |
| @@ -26,6 +26,10 @@ · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | #define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata) |
| 28 | 28 | |
| 29 | +/* List of DMI quirks - check acp-mach-common.c for usage. */ | |
| 30 | +#define QUIRK_TDM_MODE_ENABLE 1 | |
| 31 | +#define QUIRK_REMAP_DMIC_BT 2 | |
| 32 | + | |
| 29 | 33 | enum be_id { |
| 30 | 34 | HEADSET_BE_ID = 0, |
| 31 | 35 | AMP_BE_ID, |
| @@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev) · 109 unmodified lines | ||
| 110 | 110 | |
| 111 | 111 | acp_card_drvdata = card->drvdata; |
| 112 | 112 | dmi_id = dmi_first_match(acp_quirk_table); |
| 113 | − if (dmi_id && dmi_id->driver_data) | |
| 113 | + if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) | |
| 114 | 114 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; |
| 115 | 115 | |
| 116 | 116 | acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; |
| @@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) · 2495 unmodified lines | ||
| 2496 | 2496 | return status; |
| 2497 | 2497 | } |
| 2498 | 2498 | fc = (struct filter_control *) |
| 2499 | − &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; | |
| 2499 | + ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; | |
| 2500 | 2500 | drvdata->anc_fir_values = (long *)fc->value; |
| 2501 | 2501 | fc = (struct filter_control *) |
| 2502 | − &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; | |
| 2502 | + ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; | |
| 2503 | 2503 | drvdata->anc_iir_values = (long *)fc->value; |
| 2504 | 2504 | fc = (struct filter_control *) |
| 2505 | − &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; | |
| 2505 | + ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; | |
| 2506 | 2506 | drvdata->sid_fir_values = (long *)fc->value; |
| 2507 | 2507 | |
| 2508 | 2508 | snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); |
| @@ -456,8 +456,6 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) · 455 unmodified lines | ||
| 456 | 456 | usleep_range(AW88395_1000_US, AW88395_1000_US + 10); |
| 457 | 457 | gpiod_set_value_cansleep(aw88395->reset_gpio, 1); |
| 458 | 458 | usleep_range(AW88395_1000_US, AW88395_1000_US + 10); |
| 459 | − } else { | |
| 460 | − dev_err(aw88395->aw_pa->dev, "%s failed", __func__); | |
| 461 | 459 | } |
| 462 | 460 | } |
| 463 | 461 | |
| @@ -522,9 +520,10 @@ static int aw88395_i2c_probe(struct i2c_client *i2c) · 58 unmodified lines | ||
| 522 | 520 | i2c_set_clientdata(i2c, aw88395); |
| 523 | 521 | |
| 524 | 522 | aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); |
| 525 | − if (IS_ERR(aw88395->reset_gpio)) | |
| 526 | − dev_info(&i2c->dev, "reset gpio not defined\n"); | |
| 527 | − | |
| 523 | + if (IS_ERR(aw88395->reset_gpio)) { | |
| 524 | + return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio), | |
| 525 | + "failed to get reset gpio\n"); | |
| 526 | + } | |
| 528 | 527 | /* hardware reset */ |
| 529 | 528 | aw88395_hw_reset(aw88395); |
| 530 | 529 | |
| @@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) · 107 unmodified lines | ||
| 108 | 108 | EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED"); |
| 109 | 109 | |
| 110 | 110 | static const struct reg_default cs35l56_reg_defaults[] = { |
| 111 | − /* no defaults for OTP_MEM - first read populates cache */ | |
| 112 | − | |
| 113 | 111 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, |
| 114 | 112 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, |
| 115 | 113 | { CS35L56_ASP1_CONTROL2, 0x18180200 }, |
| @@ -138,8 +136,6 @@ static const struct reg_default cs35l56_reg_defaults[] = { · 22 unmodified lines | ||
| 138 | 136 | }; |
| 139 | 137 | |
| 140 | 138 | static const struct reg_default cs35l63_reg_defaults[] = { |
| 141 | − /* no defaults for OTP_MEM - first read populates cache */ | |
| 142 | − | |
| 143 | 139 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, |
| 144 | 140 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, |
| 145 | 141 | { CS35L56_ASP1_CONTROL2, 0x18180200 }, |
| @@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg) · 136 unmodified lines | ||
| 282 | 278 | case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ |
| 283 | 279 | case CS35L56_BLOCK_ENABLES: /* owned by firmware */ |
| 284 | 280 | case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ |
| 281 | + case CS35L56_OTP_MEM_53: | |
| 282 | + case CS35L56_OTP_MEM_54: | |
| 283 | + case CS35L56_OTP_MEM_55: | |
| 285 | 284 | case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: |
| 286 | 285 | case CS35L56_UPDATE_REGS: |
| 287 | 286 | case CS35L56_REFCLK_INPUT: /* owned by firmware */ |
| @@ -892,7 +892,7 @@ static int es8389_probe(struct snd_soc_component *component) · 891 unmodified lines | ||
| 892 | 892 | return ret; |
| 893 | 893 | } |
| 894 | 894 | |
| 895 | − es8389->mclk = devm_clk_get(component->dev, "mclk"); | |
| 895 | + es8389->mclk = devm_clk_get_optional(component->dev, "mclk"); | |
| 896 | 896 | if (IS_ERR(es8389->mclk)) |
| 897 | 897 | return dev_err_probe(component->dev, PTR_ERR(es8389->mclk), |
| 898 | 898 | "ES8389 is unable to get mclk\n"); |
| @@ -904,6 +904,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg) · 903 unmodified lines | ||
| 904 | 904 | { |
| 905 | 905 | switch (reg) { |
| 906 | 906 | case TAS2764_SW_RST: |
| 907 | + case TAS2764_TEMP: | |
| 907 | 908 | case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: |
| 908 | 909 | case TAS2764_INT_CLK_CFG: |
| 909 | 910 | return true; |
| @@ -624,7 +624,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result) · 623 unmodified lines | ||
| 624 | 624 | /* |
| 625 | 625 | * As per datasheet: divide register by 16 and subtract 93 to get |
| 626 | 626 | * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding |
| 627 | − * errors by subtracting 93 * 16 then multiplying by 1000 / 16. | |
| 627 | + * errors by subtracting 93 * 16 and scaling before dividing. | |
| 628 | 628 | * |
| 629 | 629 | * NOTE: The ADC registers are initialised to 0 on reset. This means |
| 630 | 630 | * that the temperature will read -93 *C until the chip is brought out |
| @@ -633,7 +633,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result) · 2 unmodified lines | ||
| 633 | 633 | * value read back from its registers will be the last value sampled |
| 634 | 634 | * before entering software shutdown. |
| 635 | 635 | */ |
| 636 | − *result = (reading - (93 * 16)) * (1000 / 16); | |
| 636 | + *result = (reading - (93 * 16)) * 1000 / 16; | |
| 637 | 637 | return 0; |
| 638 | 638 | } |
| 639 | 639 | |
| @@ -546,6 +546,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, · 545 unmodified lines | ||
| 546 | 546 | snd_soc_component_update_bits(component, |
| 547 | 547 | WCD937X_DIGITAL_CDC_ANA_CLK_CTL, |
| 548 | 548 | BIT(2), BIT(2)); |
| 549 | + snd_soc_component_update_bits(component, | |
| 550 | + WCD937X_AUX_AUXPA, | |
| 551 | + BIT(4), BIT(4)); | |
| 549 | 552 | snd_soc_component_update_bits(component, |
| 550 | 553 | WCD937X_DIGITAL_CDC_DIG_CLK_CTL, |
| 551 | 554 | BIT(2), BIT(2)); |
| @@ -562,6 +565,9 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, · 10 unmodified lines | ||
| 562 | 565 | snd_soc_component_update_bits(component, |
| 563 | 566 | WCD937X_DIGITAL_CDC_ANA_CLK_CTL, |
| 564 | 567 | BIT(2), 0x00); |
| 568 | + snd_soc_component_update_bits(component, | |
| 569 | + WCD937X_AUX_AUXPA, | |
| 570 | + BIT(4), 0x00); | |
| 565 | 571 | break; |
| 566 | 572 | } |
| 567 | 573 | |
| @@ -730,10 +736,23 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, · 162 unmodified lines | ||
| 730 | 736 | snd_soc_component_update_bits(component, |
| 731 | 737 | WCD937X_ANA_RX_SUPPLIES, |
| 732 | 738 | BIT(1), BIT(1)); |
| 739 | + /* Enable AUX PA related RX supplies */ | |
| 740 | + snd_soc_component_update_bits(component, | |
| 741 | + WCD937X_ANA_RX_SUPPLIES, | |
| 742 | + BIT(6), BIT(6)); | |
| 743 | + snd_soc_component_update_bits(component, | |
| 744 | + WCD937X_ANA_RX_SUPPLIES, | |
| 745 | + BIT(7), BIT(7)); | |
| 733 | 746 | enable_irq(wcd937x->aux_pdm_wd_int); |
| 734 | 747 | break; |
| 735 | 748 | case SND_SOC_DAPM_PRE_PMD: |
| 736 | 749 | disable_irq_nosync(wcd937x->aux_pdm_wd_int); |
| 750 | + snd_soc_component_update_bits(component, | |
| 751 | + WCD937X_ANA_RX_SUPPLIES, | |
| 752 | + BIT(6), 0x00); | |
| 753 | + snd_soc_component_update_bits(component, | |
| 754 | + WCD937X_ANA_RX_SUPPLIES, | |
| 755 | + BIT(7), 0x00); | |
| 737 | 756 | break; |
| 738 | 757 | case SND_SOC_DAPM_POST_PMD: |
| 739 | 758 | usleep_range(2000, 2010); |
| @@ -2051,7 +2070,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { · 1311 unmodified lines | ||
| 2051 | 2070 | wcd937x_get_swr_port, wcd937x_set_swr_port), |
| 2052 | 2071 | SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0, |
| 2053 | 2072 | wcd937x_get_swr_port, wcd937x_set_swr_port), |
| 2054 | − | |
| 2073 | + SOC_SINGLE_EXT("CLSH PA Switch", WCD937X_CLSH, 0, 1, 0, | |
| 2074 | + wcd937x_get_swr_port, wcd937x_set_swr_port), | |
| 2075 | + SOC_SINGLE_EXT("DSD_L Switch", WCD937X_DSD_L, 0, 1, 0, | |
| 2076 | + wcd937x_get_swr_port, wcd937x_set_swr_port), | |
| 2077 | + SOC_SINGLE_EXT("DSD_R Switch", WCD937X_DSD_R, 0, 1, 0, | |
| 2078 | + wcd937x_get_swr_port, wcd937x_set_swr_port), | |
| 2055 | 2079 | SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, |
| 2056 | 2080 | wcd937x_get_swr_port, wcd937x_set_swr_port), |
| 2057 | 2081 | SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0, |
| @@ -170,6 +170,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, · 169 unmodified lines | ||
| 170 | 170 | ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000); |
| 171 | 171 | if (ret) { |
| 172 | 172 | dev_err(card->dev, "Error setting codec sysclk: %d\n", ret); |
| 173 | + clk_disable_unprepare(priv->mclk); | |
| 173 | 174 | return ret; |
| 174 | 175 | } |
| 175 | 176 | } else { |
| @@ -1412,7 +1412,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev · 1411 unmodified lines | ||
| 1412 | 1412 | link_mask |= BIT(peripherals->array[i]->bus->link_id); |
| 1413 | 1413 | |
| 1414 | 1414 | link_num = hweight32(link_mask); |
| 1415 | − links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL); | |
| 1415 | + /* An empty adr_link is needed to terminate the adr_link loop */ | |
| 1416 | + links = devm_kcalloc(sdev->dev, link_num + 1, sizeof(*links), GFP_KERNEL); | |
| 1416 | 1417 | if (!links) |
| 1417 | 1418 | return NULL; |
| 1418 | 1419 | |
| @@ -93,8 +93,8 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s) · 92 unmodified lines | ||
| 93 | 93 | u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val; |
| 94 | 94 | |
| 95 | 95 | sscr_val = SSCR_TRAIL | SSCR_FRF_PSP; |
| 96 | − ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 5) | | |
| 97 | − FIELD_PREP(SSFCR_FIELD_RFT, 5) | | |
| 96 | + ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 0xF) | | |
| 97 | + FIELD_PREP(SSFCR_FIELD_RFT, 0xF) | | |
| 98 | 98 | SSFCR_RSRE | SSFCR_TSRE; |
| 99 | 99 | ssrwt_val = SSRWT_RWOT; |
| 100 | 100 | sspsp_val = SSPSP_SFRMP; |
| @@ -106,6 +106,37 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s) · 5 unmodified lines | ||
| 106 | 106 | writel(0, i2s->base + SSINTEN); |
| 107 | 107 | } |
| 108 | 108 | |
| 109 | +static int spacemit_i2s_startup(struct snd_pcm_substream *substream, | |
| 110 | + struct snd_soc_dai *dai) | |
| 111 | +{ | |
| 112 | + struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); | |
| 113 | + | |
| 114 | + switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | |
| 115 | + case SND_SOC_DAIFMT_I2S: | |
| 116 | + snd_pcm_hw_constraint_minmax(substream->runtime, | |
| 117 | + SNDRV_PCM_HW_PARAM_CHANNELS, | |
| 118 | + 2, 2); | |
| 119 | + snd_pcm_hw_constraint_mask64(substream->runtime, | |
| 120 | + SNDRV_PCM_HW_PARAM_FORMAT, | |
| 121 | + SNDRV_PCM_FMTBIT_S16_LE); | |
| 122 | + break; | |
| 123 | + case SND_SOC_DAIFMT_DSP_A: | |
| 124 | + case SND_SOC_DAIFMT_DSP_B: | |
| 125 | + snd_pcm_hw_constraint_minmax(substream->runtime, | |
| 126 | + SNDRV_PCM_HW_PARAM_CHANNELS, | |
| 127 | + 1, 1); | |
| 128 | + snd_pcm_hw_constraint_mask64(substream->runtime, | |
| 129 | + SNDRV_PCM_HW_PARAM_FORMAT, | |
| 130 | + SNDRV_PCM_FMTBIT_S32_LE); | |
| 131 | + break; | |
| 132 | + default: | |
| 133 | + dev_dbg(i2s->dev, "unexpected format type"); | |
| 134 | + return -EINVAL; | |
| 135 | + } | |
| 136 | + | |
| 137 | + return 0; | |
| 138 | +} | |
| 139 | + | |
| 109 | 140 | static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, |
| 110 | 141 | struct snd_pcm_hw_params *params, |
| 111 | 142 | struct snd_soc_dai *dai) |
| @@ -157,22 +188,9 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, · 45 unmodified lines | ||
| 157 | 188 | dma_data->maxburst = 32; |
| 158 | 189 | dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
| 159 | 190 | } |
| 160 | − | |
| 161 | − snd_pcm_hw_constraint_minmax(substream->runtime, | |
| 162 | − SNDRV_PCM_HW_PARAM_CHANNELS, | |
| 163 | − 1, 2); | |
| 164 | − snd_pcm_hw_constraint_mask64(substream->runtime, | |
| 165 | − SNDRV_PCM_HW_PARAM_FORMAT, | |
| 166 | − SNDRV_PCM_FMTBIT_S16_LE); | |
| 167 | 191 | break; |
| 168 | 192 | case SND_SOC_DAIFMT_DSP_A: |
| 169 | 193 | case SND_SOC_DAIFMT_DSP_B: |
| 170 | − snd_pcm_hw_constraint_minmax(substream->runtime, | |
| 171 | − SNDRV_PCM_HW_PARAM_CHANNELS, | |
| 172 | − 1, 1); | |
| 173 | − snd_pcm_hw_constraint_mask64(substream->runtime, | |
| 174 | − SNDRV_PCM_HW_PARAM_FORMAT, | |
| 175 | − SNDRV_PCM_FMTBIT_S32_LE); | |
| 176 | 194 | break; |
| 177 | 195 | default: |
| 178 | 196 | dev_dbg(i2s->dev, "unexpected format type"); |
| @@ -303,6 +321,7 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai) · 124 unmodified lines | ||
| 303 | 321 | static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { |
| 304 | 322 | .probe = spacemit_i2s_dai_probe, |
| 305 | 323 | .remove = spacemit_i2s_dai_remove, |
| 324 | + .startup = spacemit_i2s_startup, | |
| 306 | 325 | .hw_params = spacemit_i2s_hw_params, |
| 307 | 326 | .set_sysclk = spacemit_i2s_set_sysclk, |
| 308 | 327 | .set_fmt = spacemit_i2s_set_fmt, |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | # Tegra platform Support |
| 3 | 3 | snd-soc-tegra-pcm-y := tegra_pcm.o |
| 4 | −snd-soc-tegra-utils-y += tegra_asoc_utils.o | |
| 5 | 4 | snd-soc-tegra20-ac97-y := tegra20_ac97.o |
| 6 | 5 | snd-soc-tegra20-das-y := tegra20_das.o |
| 7 | 6 | snd-soc-tegra20-i2s-y := tegra20_i2s.o |
| @@ -366,7 +366,7 @@ static int setup_card(struct snd_usb_caiaqdev *cdev) · 365 unmodified lines | ||
| 366 | 366 | |
| 367 | 367 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
| 368 | 368 | ret = snd_usb_caiaq_input_init(cdev); |
| 369 | − if (ret < 0) { | |
| 369 | + if (ret < 0 && ret != -ENODEV) { | |
| 370 | 370 | dev_err(dev, "Unable to set up input system (ret=%d)\n", ret); |
| 371 | 371 | return ret; |
| 372 | 372 | } |
| @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev, · 50 unmodified lines | ||
| 423 | 423 | |
| 424 | 424 | cdev = caiaqdev(card); |
| 425 | 425 | cdev->chip.dev = usb_get_dev(usb_dev); |
| 426 | + card->private_free = card_free; | |
| 426 | 427 | cdev->chip.card = card; |
| 427 | 428 | cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), |
| 428 | 429 | le16_to_cpu(usb_dev->descriptor.idProduct)); |
| @@ -511,10 +512,9 @@ static int init_card(struct snd_usb_caiaqdev *cdev) · 82 unmodified lines | ||
| 511 | 512 | scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)", |
| 512 | 513 | cdev->vendor_name, cdev->product_name, usbpath); |
| 513 | 514 | |
| 514 | − card->private_free = card_free; | |
| 515 | 515 | err = setup_card(cdev); |
| 516 | 516 | if (err < 0) |
| 517 | − return err; | |
| 517 | + goto err_kill_urb; | |
| 518 | 518 | |
| 519 | 519 | return 0; |
| 520 | 520 | |
| @@ -804,7 +804,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) · 803 unmodified lines | ||
| 804 | 804 | |
| 805 | 805 | default: |
| 806 | 806 | /* no input methods supported on this device */ |
| 807 | − ret = -EINVAL; | |
| 807 | + ret = -ENODEV; | |
| 808 | 808 | goto exit_free_idev; |
| 809 | 809 | } |
| 810 | 810 | |
| @@ -974,6 +974,13 @@ static int detect_usb_format(struct ua101 *ua) · 973 unmodified lines | ||
| 974 | 974 | |
| 975 | 975 | ua->capture.channels = fmt_capture->bNrChannels; |
| 976 | 976 | ua->playback.channels = fmt_playback->bNrChannels; |
| 977 | + if (!ua->capture.channels || !ua->playback.channels) { | |
| 978 | + dev_err(&ua->dev->dev, | |
| 979 | + "invalid channel count: capture %u, playback %u\n", | |
| 980 | + ua->capture.channels, ua->playback.channels); | |
| 981 | + return -EINVAL; | |
| 982 | + } | |
| 983 | + | |
| 977 | 984 | ua->capture.frame_bytes = |
| 978 | 985 | fmt_capture->bSubframeSize * ua->capture.channels; |
| 979 | 986 | ua->playback.frame_bytes = |
| @@ -1190,6 +1190,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, · 1189 unmodified lines | ||
| 1190 | 1190 | cval->res = 1; |
| 1191 | 1191 | } |
| 1192 | 1192 | break; |
| 1193 | + | |
| 1194 | + case USB_ID(0x0e6f, 0x024a): /* PDP Riffmaster for PS4 */ | |
| 1195 | + case USB_ID(0x0e6f, 0x0249): /* PDP Riffmaster for PS5 */ | |
| 1196 | + if (!strcmp(kctl->id.name, "PCM Playback Volume")) { | |
| 1197 | + usb_audio_info(chip, | |
| 1198 | + "set volume quirk for PDP Riffmaster for PS4/PS5\n"); | |
| 1199 | + cval->min = -2560; /* Mute under it */ | |
| 1200 | + } | |
| 1201 | + break; | |
| 1202 | + | |
| 1193 | 1203 | case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ |
| 1194 | 1204 | if (!strcmp(kctl->id.name, "PCM Playback Volume")) { |
| 1195 | 1205 | usb_audio_info(chip, |
| @@ -2652,6 +2652,9 @@ YAMAHA_DEVICE(0x7010, "UB99"), · 2651 unmodified lines | ||
| 2652 | 2652 | } |
| 2653 | 2653 | } |
| 2654 | 2654 | }, |
| 2655 | + | |
| 2656 | +#endif /* disabled */ | |
| 2657 | + | |
| 2655 | 2658 | { |
| 2656 | 2659 | /* |
| 2657 | 2660 | * The AudioBox USB advertises S24_3LE as the only supported format |
| @@ -2700,7 +2703,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), · 42 unmodified lines | ||
| 2700 | 2703 | } |
| 2701 | 2704 | } |
| 2702 | 2705 | }, |
| 2703 | −#endif /* disabled */ | |
| 2704 | 2706 | |
| 2705 | 2707 | { |
| 2706 | 2708 | /* |
| @@ -125,7 +125,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, · 124 unmodified lines | ||
| 125 | 125 | |
| 126 | 126 | snd_usb_audioformat_set_sync_ep(chip, fp); |
| 127 | 127 | |
| 128 | − err = snd_usb_add_audio_stream(chip, stream, fp); | |
| 128 | + err = snd_usb_add_audio_stream(chip, stream, fp, NULL); | |
| 129 | 129 | if (err < 0) |
| 130 | 130 | return err; |
| 131 | 131 | |
| @@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) · 78 unmodified lines | ||
| 79 | 79 | static void snd_usb_init_substream(struct snd_usb_stream *as, |
| 80 | 80 | int stream, |
| 81 | 81 | struct audioformat *fp, |
| 82 | − struct snd_usb_power_domain *pd) | |
| 82 | + struct snd_usb_power_domain **pdptr) | |
| 83 | 83 | { |
| 84 | 84 | struct snd_usb_substream *subs = &as->substream[stream]; |
| 85 | 85 | |
| @@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, · 19 unmodified lines | ||
| 105 | 105 | if (fp->channels > subs->channels_max) |
| 106 | 106 | subs->channels_max = fp->channels; |
| 107 | 107 | |
| 108 | − if (pd) { | |
| 109 | − subs->str_pd = pd; | |
| 108 | + if (pdptr && *pdptr) { | |
| 109 | + subs->str_pd = *pdptr; | |
| 110 | + *pdptr = NULL; /* assigned */ | |
| 110 | 111 | /* Initialize Power Domain to idle status D1 */ |
| 111 | − snd_usb_power_domain_set(subs->stream->chip, pd, | |
| 112 | + snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, | |
| 112 | 113 | UAC3_PD_STATE_D1); |
| 113 | 114 | } |
| 114 | 115 | |
| @@ -352,6 +353,8 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor · 237 unmodified lines | ||
| 352 | 353 | if (len < sizeof(*cs_desc)) |
| 353 | 354 | break; |
| 354 | 355 | cs_len = le16_to_cpu(cs_desc->wLength); |
| 356 | + if (cs_len < sizeof(*cs_desc)) | |
| 357 | + break; | |
| 355 | 358 | if (len < cs_len) |
| 356 | 359 | break; |
| 357 | 360 | cs_type = cs_desc->bSegmentType; |
| @@ -492,11 +495,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor · 134 unmodified lines | ||
| 492 | 495 | * if not, create a new pcm stream. note, fp is added to the substream |
| 493 | 496 | * fmt_list and will be freed on the chip instance release. do not free |
| 494 | 497 | * fp or do remove it from the substream fmt_list to avoid double-free. |
| 498 | + * | |
| 499 | + * pdptr is optional and can be NULL. When it's non-NULL and the PD gets | |
| 500 | + * assigned to the stream, *pdptr is cleared to NULL upon return. | |
| 495 | 501 | */ |
| 496 | −static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, | |
| 497 | − int stream, | |
| 498 | − struct audioformat *fp, | |
| 499 | − struct snd_usb_power_domain *pd) | |
| 502 | +int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | |
| 503 | + int stream, | |
| 504 | + struct audioformat *fp, | |
| 505 | + struct snd_usb_power_domain **pdptr) | |
| 500 | 506 | |
| 501 | 507 | { |
| 502 | 508 | struct snd_usb_stream *as; |
| @@ -529,7 +535,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, · 26 unmodified lines | ||
| 529 | 535 | err = snd_pcm_new_stream(as->pcm, stream, 1); |
| 530 | 536 | if (err < 0) |
| 531 | 537 | return err; |
| 532 | − snd_usb_init_substream(as, stream, fp, pd); | |
| 538 | + snd_usb_init_substream(as, stream, fp, pdptr); | |
| 533 | 539 | return add_chmap(as->pcm, stream, subs); |
| 534 | 540 | } |
| 535 | 541 | |
| @@ -558,7 +564,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, · 22 unmodified lines | ||
| 558 | 564 | else |
| 559 | 565 | strscpy(pcm->name, "USB Audio"); |
| 560 | 566 | |
| 561 | − snd_usb_init_substream(as, stream, fp, pd); | |
| 567 | + snd_usb_init_substream(as, stream, fp, pdptr); | |
| 562 | 568 | |
| 563 | 569 | /* |
| 564 | 570 | * Keep using head insertion for M-Audio Audiophile USB (tm) which has a |
| @@ -576,21 +582,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, · 11 unmodified lines | ||
| 576 | 582 | return add_chmap(pcm, stream, &as->substream[stream]); |
| 577 | 583 | } |
| 578 | 584 | |
| 579 | −int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | |
| 580 | − int stream, | |
| 581 | − struct audioformat *fp) | |
| 582 | −{ | |
| 583 | − return __snd_usb_add_audio_stream(chip, stream, fp, NULL); | |
| 584 | −} | |
| 585 | − | |
| 586 | −static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, | |
| 587 | − int stream, | |
| 588 | − struct audioformat *fp, | |
| 589 | − struct snd_usb_power_domain *pd) | |
| 590 | −{ | |
| 591 | − return __snd_usb_add_audio_stream(chip, stream, fp, pd); | |
| 592 | −} | |
| 593 | − | |
| 594 | 585 | static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, |
| 595 | 586 | struct usb_host_interface *alts, |
| 596 | 587 | int protocol, int iface_no) |
| @@ -1003,7 +994,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, · 406 unmodified lines | ||
| 1003 | 994 | * and request Cluster Descriptor |
| 1004 | 995 | */ |
| 1005 | 996 | wLength = le16_to_cpu(hc_header.wLength); |
| 1006 | − if (wLength < sizeof(cluster)) | |
| 997 | + if (wLength < sizeof(*cluster)) | |
| 1007 | 998 | return NULL; |
| 1008 | 999 | cluster = kzalloc(wLength, GFP_KERNEL); |
| 1009 | 1000 | if (!cluster) |
| @@ -1113,8 +1104,7 @@ found_clock: · 103 unmodified lines | ||
| 1113 | 1104 | } |
| 1114 | 1105 | } |
| 1115 | 1106 | |
| 1116 | − if (pd) | |
| 1117 | − *pd_out = pd; | |
| 1107 | + *pd_out = pd; | |
| 1118 | 1108 | |
| 1119 | 1109 | return fp; |
| 1120 | 1110 | } |
| @@ -1129,7 +1119,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, · 8 unmodified lines | ||
| 1129 | 1119 | struct usb_interface_descriptor *altsd; |
| 1130 | 1120 | int i, altno, err, stream; |
| 1131 | 1121 | struct audioformat *fp = NULL; |
| 1132 | − struct snd_usb_power_domain *pd = NULL; | |
| 1133 | 1122 | bool set_iface_first; |
| 1134 | 1123 | int num, protocol; |
| 1135 | 1124 | |
| @@ -1171,6 +1160,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, · 35 unmodified lines | ||
| 1171 | 1160 | if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) |
| 1172 | 1161 | continue; |
| 1173 | 1162 | |
| 1163 | + /* pd may be allocated at snd_usb_get_audioformat_uac3() and | |
| 1164 | + * assigned at snd_usb_add_audio_stream(); otherwise it'll be | |
| 1165 | + * freed automatically by cleanup at each loop. | |
| 1166 | + */ | |
| 1167 | + struct snd_usb_power_domain *pd __free(kfree) = NULL; | |
| 1168 | + | |
| 1174 | 1169 | /* |
| 1175 | 1170 | * Roland audio streaming interfaces are marked with protocols |
| 1176 | 1171 | * 0/1/2, but are UAC 1 compatible. |
| @@ -1226,23 +1221,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, · 49 unmodified lines | ||
| 1226 | 1221 | *has_non_pcm = true; |
| 1227 | 1222 | if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { |
| 1228 | 1223 | audioformat_free(fp); |
| 1229 | − kfree(pd); | |
| 1230 | 1224 | fp = NULL; |
| 1231 | − pd = NULL; | |
| 1232 | 1225 | continue; |
| 1233 | 1226 | } |
| 1234 | 1227 | |
| 1235 | 1228 | snd_usb_audioformat_set_sync_ep(chip, fp); |
| 1236 | 1229 | |
| 1237 | 1230 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); |
| 1238 | − if (protocol == UAC_VERSION_3) | |
| 1239 | − err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); | |
| 1240 | − else | |
| 1241 | − err = snd_usb_add_audio_stream(chip, stream, fp); | |
| 1242 | − | |
| 1231 | + err = snd_usb_add_audio_stream(chip, stream, fp, &pd); | |
| 1243 | 1232 | if (err < 0) { |
| 1244 | 1233 | audioformat_free(fp); |
| 1245 | − kfree(pd); | |
| 1246 | 1234 | return err; |
| 1247 | 1235 | } |
| 1248 | 1236 | |
| @@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, |
| 9 | 9 | int stream, |
| 10 | − struct audioformat *fp); | |
| 10 | + struct audioformat *fp, | |
| 11 | + struct snd_usb_power_domain **pdptr); | |
| 11 | 12 | |
| 12 | 13 | #endif /* __USBAUDIO_STREAM_H */ |
| 13 | 14 | |
| @@ -159,13 +159,7 @@ static s32 pick_direct_dispatch_cpu(struct task_struct *p, s32 prev_cpu) · 158 unmodified lines | ||
| 159 | 159 | |
| 160 | 160 | static struct task_ctx *lookup_task_ctx(struct task_struct *p) |
| 161 | 161 | { |
| 162 | − struct task_ctx *tctx; | |
| 163 | − | |
| 164 | − if (!(tctx = bpf_task_storage_get(&task_ctx_stor, p, 0, 0))) { | |
| 165 | − scx_bpf_error("task_ctx lookup failed"); | |
| 166 | − return NULL; | |
| 167 | − } | |
| 168 | − return tctx; | |
| 162 | + return bpf_task_storage_get(&task_ctx_stor, p, 0, 0); | |
| 169 | 163 | } |
| 170 | 164 | |
| 171 | 165 | s32 BPF_STRUCT_OPS(qmap_select_cpu, struct task_struct *p, |
| @@ -175,7 +169,7 @@ s32 BPF_STRUCT_OPS(qmap_select_cpu, struct task_struct *p, · 3 unmodified lines | ||
| 175 | 169 | s32 cpu; |
| 176 | 170 | |
| 177 | 171 | if (!(tctx = lookup_task_ctx(p))) |
| 178 | − return -ESRCH; | |
| 172 | + return prev_cpu; | |
| 179 | 173 | |
| 180 | 174 | if (p->scx.weight < 2 && !(p->flags & PF_KTHREAD)) |
| 181 | 175 | return prev_cpu; |
| @@ -540,13 +534,9 @@ void BPF_STRUCT_OPS(qmap_dispatch, s32 cpu, struct task_struct *prev) · 358 unmodified lines | ||
| 540 | 534 | */ |
| 541 | 535 | if (prev) { |
| 542 | 536 | tctx = bpf_task_storage_get(&task_ctx_stor, prev, 0, 0); |
| 543 | − if (!tctx) { | |
| 544 | − scx_bpf_error("task_ctx lookup failed"); | |
| 545 | − return; | |
| 546 | − } | |
| 547 | − | |
| 548 | − tctx->core_sched_seq = | |
| 549 | − core_sched_tail_seqs[weight_to_idx(prev->scx.weight)]++; | |
| 537 | + if (tctx) | |
| 538 | + tctx->core_sched_seq = | |
| 539 | + core_sched_tail_seqs[weight_to_idx(prev->scx.weight)]++; | |
| 550 | 540 | } |
| 551 | 541 | } |
| 552 | 542 | |
| @@ -584,10 +574,8 @@ static s64 task_qdist(struct task_struct *p) · 31 unmodified lines | ||
| 584 | 574 | s64 qdist; |
| 585 | 575 | |
| 586 | 576 | tctx = bpf_task_storage_get(&task_ctx_stor, p, 0, 0); |
| 587 | − if (!tctx) { | |
| 588 | − scx_bpf_error("task_ctx lookup failed"); | |
| 577 | + if (!tctx) | |
| 589 | 578 | return 0; |
| 590 | − } | |
| 591 | 579 | |
| 592 | 580 | qdist = tctx->core_sched_seq - core_sched_head_seqs[idx]; |
| 593 | 581 | |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * maple_tree.c: Userspace testing for maple tree test-suite |
| 4 | 4 | * Copyright (c) 2018-2022 Oracle Corporation |
| 5 | − * Author: Liam R. Howlett <Liam.Howlett@Oracle.com> | |
| 5 | + * Author: Liam R. Howlett <liam@infradead.org> | |
| 6 | 6 | * |
| 7 | 7 | * Any tests that require internal knowledge of the tree or threads and other |
| 8 | 8 | * difficult to handle in kernel tests. |
| @@ -18,12 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #ifndef NT_ARM_GCS |
| 20 | 20 | #define NT_ARM_GCS 0x410 |
| 21 | − | |
| 22 | −struct user_gcs { | |
| 23 | − __u64 features_enabled; | |
| 24 | − __u64 features_locked; | |
| 25 | − __u64 gcspr_el0; | |
| 26 | −}; | |
| 27 | 21 | #endif |
| 28 | 22 | |
| 29 | 23 | /* Shadow Stack/Guarded Control Stack interface */ |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #include <asm/hwcap.h> |
| 18 | 18 | #include <asm/mman.h> |
| 19 | +#include <asm/ptrace.h> | |
| 19 | 20 | |
| 20 | 21 | #include <linux/compiler.h> |
| 21 | 22 | |
| @@ -211,8 +211,8 @@ Avoid libraries and frameworks · 210 unmodified lines | ||
| 211 | 211 | |
| 212 | 212 | Test files should be relatively self contained. The libraries should |
| 213 | 213 | only include very core or non-trivial code. |
| 214 | −It may be tempting to "factor out" the common code, but fight that urge. | |
| 215 | −Library code increases the barrier of entry, and complexity in general. | |
| 214 | +It may be tempting to "factor out" the common code to lib/py/, but fight that | |
| 215 | +urge. Library code increases the barrier of entry, and complexity in general. | |
| 216 | 216 | |
| 217 | 217 | Avoid mixing test code and boilerplate |
| 218 | 218 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -290,6 +290,12 @@ or:: · 71 unmodified lines | ||
| 290 | 290 | def test(cfg, mode, protocol): |
| 291 | 291 | pass |
| 292 | 292 | |
| 293 | +Linters | |
| 294 | +~~~~~~~ | |
| 295 | + | |
| 296 | +We expect clean ``ruff check`` and ``pylint --disable=R``. | |
| 297 | +The code should be clean, avoid disabling pylint warnings explicitly! | |
| 298 | + | |
| 293 | 299 | Running tests CI-style |
| 294 | 300 | ====================== |
| 295 | 301 | |
| @@ -101,15 +101,15 @@ struct test_params { · 100 unmodified lines | ||
| 101 | 101 | enum vm_mem_backing_src_type backing_src; |
| 102 | 102 | |
| 103 | 103 | /* The amount of memory to allocate for each vCPU. */ |
| 104 | − uint64_t vcpu_memory_bytes; | |
| 104 | + u64 vcpu_memory_bytes; | |
| 105 | 105 | |
| 106 | 106 | /* The number of vCPUs to create in the VM. */ |
| 107 | 107 | int nr_vcpus; |
| 108 | 108 | }; |
| 109 | 109 | |
| 110 | −static uint64_t pread_uint64(int fd, const char *filename, uint64_t index) | |
| 110 | +static u64 pread_u64(int fd, const char *filename, u64 index) | |
| 111 | 111 | { |
| 112 | − uint64_t value; | |
| 112 | + u64 value; | |
| 113 | 113 | off_t offset = index * sizeof(value); |
| 114 | 114 | |
| 115 | 115 | TEST_ASSERT(pread(fd, &value, sizeof(value), offset) == sizeof(value), |
| @@ -123,13 +123,13 @@ static uint64_t pread_uint64(int fd, const char *filename, uint64_t index) · 7 unmodified lines | ||
| 123 | 123 | #define PAGEMAP_PRESENT (1ULL << 63) |
| 124 | 124 | #define PAGEMAP_PFN_MASK ((1ULL << 55) - 1) |
| 125 | 125 | |
| 126 | −static uint64_t lookup_pfn(int pagemap_fd, struct kvm_vm *vm, uint64_t gva) | |
| 126 | +static u64 lookup_pfn(int pagemap_fd, struct kvm_vm *vm, gva_t gva) | |
| 127 | 127 | { |
| 128 | − uint64_t hva = (uint64_t) addr_gva2hva(vm, gva); | |
| 129 | − uint64_t entry; | |
| 130 | − uint64_t pfn; | |
| 128 | + u64 hva = (u64)addr_gva2hva(vm, gva); | |
| 129 | + u64 entry; | |
| 130 | + u64 pfn; | |
| 131 | 131 | |
| 132 | − entry = pread_uint64(pagemap_fd, "pagemap", hva / getpagesize()); | |
| 132 | + entry = pread_u64(pagemap_fd, "pagemap", hva / getpagesize()); | |
| 133 | 133 | if (!(entry & PAGEMAP_PRESENT)) |
| 134 | 134 | return 0; |
| 135 | 135 | |
| @@ -139,16 +139,16 @@ static uint64_t lookup_pfn(int pagemap_fd, struct kvm_vm *vm, uint64_t gva) · 3 unmodified lines | ||
| 139 | 139 | return pfn; |
| 140 | 140 | } |
| 141 | 141 | |
| 142 | −static bool is_page_idle(int page_idle_fd, uint64_t pfn) | |
| 142 | +static bool is_page_idle(int page_idle_fd, u64 pfn) | |
| 143 | 143 | { |
| 144 | − uint64_t bits = pread_uint64(page_idle_fd, "page_idle", pfn / 64); | |
| 144 | + u64 bits = pread_u64(page_idle_fd, "page_idle", pfn / 64); | |
| 145 | 145 | |
| 146 | 146 | return !!((bits >> (pfn % 64)) & 1); |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | −static void mark_page_idle(int page_idle_fd, uint64_t pfn) | |
| 149 | +static void mark_page_idle(int page_idle_fd, u64 pfn) | |
| 150 | 150 | { |
| 151 | − uint64_t bits = 1ULL << (pfn % 64); | |
| 151 | + u64 bits = 1ULL << (pfn % 64); | |
| 152 | 152 | |
| 153 | 153 | TEST_ASSERT(pwrite(page_idle_fd, &bits, 8, 8 * (pfn / 64)) == 8, |
| 154 | 154 | "Set page_idle bits for PFN 0x%" PRIx64, pfn); |
| @@ -174,11 +174,11 @@ static void pageidle_mark_vcpu_memory_idle(struct kvm_vm *vm, · 19 unmodified lines | ||
| 174 | 174 | struct memstress_vcpu_args *vcpu_args) |
| 175 | 175 | { |
| 176 | 176 | int vcpu_idx = vcpu_args->vcpu_idx; |
| 177 | − uint64_t base_gva = vcpu_args->gva; | |
| 178 | − uint64_t pages = vcpu_args->pages; | |
| 179 | − uint64_t page; | |
| 180 | − uint64_t still_idle = 0; | |
| 181 | − uint64_t no_pfn = 0; | |
| 177 | + gva_t base_gva = vcpu_args->gva; | |
| 178 | + u64 pages = vcpu_args->pages; | |
| 179 | + u64 page; | |
| 180 | + u64 still_idle = 0; | |
| 181 | + u64 no_pfn = 0; | |
| 182 | 182 | int page_idle_fd; |
| 183 | 183 | int pagemap_fd; |
| 184 | 184 | |
| @@ -193,8 +193,8 @@ static void pageidle_mark_vcpu_memory_idle(struct kvm_vm *vm, · 8 unmodified lines | ||
| 193 | 193 | TEST_ASSERT(pagemap_fd > 0, "Failed to open pagemap."); |
| 194 | 194 | |
| 195 | 195 | for (page = 0; page < pages; page++) { |
| 196 | − uint64_t gva = base_gva + page * memstress_args.guest_page_size; | |
| 197 | − uint64_t pfn = lookup_pfn(pagemap_fd, vm, gva); | |
| 196 | + gva_t gva = base_gva + page * memstress_args.guest_page_size; | |
| 197 | + u64 pfn = lookup_pfn(pagemap_fd, vm, gva); | |
| 198 | 198 | |
| 199 | 199 | if (!pfn) { |
| 200 | 200 | no_pfn++; |
| @@ -297,10 +297,10 @@ static void lru_gen_mark_memory_idle(struct kvm_vm *vm) · 96 unmodified lines | ||
| 297 | 297 | lru_gen_last_gen = new_gen; |
| 298 | 298 | } |
| 299 | 299 | |
| 300 | −static void assert_ucall(struct kvm_vcpu *vcpu, uint64_t expected_ucall) | |
| 300 | +static void assert_ucall(struct kvm_vcpu *vcpu, u64 expected_ucall) | |
| 301 | 301 | { |
| 302 | 302 | struct ucall uc; |
| 303 | − uint64_t actual_ucall = get_ucall(vcpu, &uc); | |
| 303 | + u64 actual_ucall = get_ucall(vcpu, &uc); | |
| 304 | 304 | |
| 305 | 305 | TEST_ASSERT(expected_ucall == actual_ucall, |
| 306 | 306 | "Guest exited unexpectedly (expected ucall %" PRIu64 |
| @@ -417,7 +417,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) · 110 unmodified lines | ||
| 417 | 417 | */ |
| 418 | 418 | test_pages = params->nr_vcpus * params->vcpu_memory_bytes / |
| 419 | 419 | max(memstress_args.guest_page_size, |
| 420 | − (uint64_t)getpagesize()); | |
| 420 | + (u64)getpagesize()); | |
| 421 | 421 | |
| 422 | 422 | memstress_start_vcpu_threads(nr_vcpus, vcpu_thread_main); |
| 423 | 423 | |
| @@ -78,9 +78,9 @@ static void *test_vcpu_run(void *arg) · 77 unmodified lines | ||
| 78 | 78 | return NULL; |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | −static uint32_t test_get_pcpu(void) | |
| 81 | +static u32 test_get_pcpu(void) | |
| 82 | 82 | { |
| 83 | − uint32_t pcpu; | |
| 83 | + u32 pcpu; | |
| 84 | 84 | unsigned int nproc_conf; |
| 85 | 85 | cpu_set_t online_cpuset; |
| 86 | 86 | |
| @@ -98,7 +98,7 @@ static uint32_t test_get_pcpu(void) · 11 unmodified lines | ||
| 98 | 98 | static int test_migrate_vcpu(unsigned int vcpu_idx) |
| 99 | 99 | { |
| 100 | 100 | int ret; |
| 101 | − uint32_t new_pcpu = test_get_pcpu(); | |
| 101 | + u32 new_pcpu = test_get_pcpu(); | |
| 102 | 102 | |
| 103 | 103 | pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu_idx, new_pcpu); |
| 104 | 104 | |
| @@ -66,7 +66,7 @@ static void test_guest_raz(struct kvm_vcpu *vcpu) · 65 unmodified lines | ||
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | −static uint64_t raz_wi_reg_ids[] = { | |
| 69 | +static u64 raz_wi_reg_ids[] = { | |
| 70 | 70 | KVM_ARM64_SYS_REG(SYS_ID_PFR0_EL1), |
| 71 | 71 | KVM_ARM64_SYS_REG(SYS_ID_PFR1_EL1), |
| 72 | 72 | KVM_ARM64_SYS_REG(SYS_ID_DFR0_EL1), |
| @@ -94,8 +94,8 @@ static void test_user_raz_wi(struct kvm_vcpu *vcpu) · 21 unmodified lines | ||
| 94 | 94 | int i; |
| 95 | 95 | |
| 96 | 96 | for (i = 0; i < ARRAY_SIZE(raz_wi_reg_ids); i++) { |
| 97 | − uint64_t reg_id = raz_wi_reg_ids[i]; | |
| 98 | − uint64_t val; | |
| 97 | + u64 reg_id = raz_wi_reg_ids[i]; | |
| 98 | + u64 val; | |
| 99 | 99 | |
| 100 | 100 | val = vcpu_get_reg(vcpu, reg_id); |
| 101 | 101 | TEST_ASSERT_EQ(val, 0); |
| @@ -111,7 +111,7 @@ static void test_user_raz_wi(struct kvm_vcpu *vcpu) · 9 unmodified lines | ||
| 111 | 111 | } |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | −static uint64_t raz_invariant_reg_ids[] = { | |
| 114 | +static u64 raz_invariant_reg_ids[] = { | |
| 115 | 115 | KVM_ARM64_SYS_REG(SYS_ID_AFR0_EL1), |
| 116 | 116 | KVM_ARM64_SYS_REG(sys_reg(3, 0, 0, 3, 3)), |
| 117 | 117 | KVM_ARM64_SYS_REG(SYS_ID_DFR1_EL1), |
| @@ -123,8 +123,8 @@ static void test_user_raz_invariant(struct kvm_vcpu *vcpu) · 5 unmodified lines | ||
| 123 | 123 | int i, r; |
| 124 | 124 | |
| 125 | 125 | for (i = 0; i < ARRAY_SIZE(raz_invariant_reg_ids); i++) { |
| 126 | − uint64_t reg_id = raz_invariant_reg_ids[i]; | |
| 127 | − uint64_t val; | |
| 126 | + u64 reg_id = raz_invariant_reg_ids[i]; | |
| 127 | + u64 val; | |
| 128 | 128 | |
| 129 | 129 | val = vcpu_get_reg(vcpu, reg_id); |
| 130 | 130 | TEST_ASSERT_EQ(val, 0); |
| @@ -142,7 +142,7 @@ static void test_user_raz_invariant(struct kvm_vcpu *vcpu) · 11 unmodified lines | ||
| 142 | 142 | |
| 143 | 143 | static bool vcpu_aarch64_only(struct kvm_vcpu *vcpu) |
| 144 | 144 | { |
| 145 | − uint64_t val, el0; | |
| 145 | + u64 val, el0; | |
| 146 | 146 | |
| 147 | 147 | val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); |
| 148 | 148 | |
| @@ -56,7 +56,7 @@ static void guest_validate_irq(unsigned int intid, · 55 unmodified lines | ||
| 56 | 56 | struct test_vcpu_shared_data *shared_data) |
| 57 | 57 | { |
| 58 | 58 | enum guest_stage stage = shared_data->guest_stage; |
| 59 | − uint64_t xcnt = 0, xcnt_diff_us, cval = 0; | |
| 59 | + u64 xcnt = 0, xcnt_diff_us, cval = 0; | |
| 60 | 60 | unsigned long xctl = 0; |
| 61 | 61 | unsigned int timer_irq = 0; |
| 62 | 62 | unsigned int accessor; |
| @@ -105,7 +105,7 @@ static void guest_validate_irq(unsigned int intid, · 42 unmodified lines | ||
| 105 | 105 | static void guest_irq_handler(struct ex_regs *regs) |
| 106 | 106 | { |
| 107 | 107 | unsigned int intid = gic_get_and_ack_irq(); |
| 108 | − uint32_t cpu = guest_get_vcpuid(); | |
| 108 | + u32 cpu = guest_get_vcpuid(); | |
| 109 | 109 | struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; |
| 110 | 110 | |
| 111 | 111 | guest_validate_irq(intid, shared_data); |
| @@ -116,7 +116,7 @@ static void guest_irq_handler(struct ex_regs *regs) · 4 unmodified lines | ||
| 116 | 116 | static void guest_run_stage(struct test_vcpu_shared_data *shared_data, |
| 117 | 117 | enum guest_stage stage) |
| 118 | 118 | { |
| 119 | − uint32_t irq_iter, config_iter; | |
| 119 | + u32 irq_iter, config_iter; | |
| 120 | 120 | |
| 121 | 121 | shared_data->guest_stage = stage; |
| 122 | 122 | shared_data->nr_iter = 0; |
| @@ -140,7 +140,7 @@ static void guest_run_stage(struct test_vcpu_shared_data *shared_data, · 17 unmodified lines | ||
| 140 | 140 | |
| 141 | 141 | static void guest_code(void) |
| 142 | 142 | { |
| 143 | − uint32_t cpu = guest_get_vcpuid(); | |
| 143 | + u32 cpu = guest_get_vcpuid(); | |
| 144 | 144 | struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; |
| 145 | 145 | |
| 146 | 146 | local_irq_disable(); |
| @@ -23,25 +23,25 @@ · 22 unmodified lines | ||
| 23 | 23 | #include "vgic.h" |
| 24 | 24 | |
| 25 | 25 | /* Depends on counter width. */ |
| 26 | −static uint64_t CVAL_MAX; | |
| 26 | +static u64 CVAL_MAX; | |
| 27 | 27 | /* tval is a signed 32-bit int. */ |
| 28 | −static const int32_t TVAL_MAX = INT32_MAX; | |
| 29 | −static const int32_t TVAL_MIN = INT32_MIN; | |
| 28 | +static const s32 TVAL_MAX = INT32_MAX; | |
| 29 | +static const s32 TVAL_MIN = INT32_MIN; | |
| 30 | 30 | |
| 31 | 31 | /* After how much time we say there is no IRQ. */ |
| 32 | −static const uint32_t TIMEOUT_NO_IRQ_US = 50000; | |
| 32 | +static const u32 TIMEOUT_NO_IRQ_US = 50000; | |
| 33 | 33 | |
| 34 | 34 | /* Counter value to use as the starting one for most tests. Set to CVAL_MAX/2 */ |
| 35 | −static uint64_t DEF_CNT; | |
| 35 | +static u64 DEF_CNT; | |
| 36 | 36 | |
| 37 | 37 | /* Number of runs. */ |
| 38 | −static const uint32_t NR_TEST_ITERS_DEF = 5; | |
| 38 | +static const u32 NR_TEST_ITERS_DEF = 5; | |
| 39 | 39 | |
| 40 | 40 | /* Default wait test time in ms. */ |
| 41 | −static const uint32_t WAIT_TEST_MS = 10; | |
| 41 | +static const u32 WAIT_TEST_MS = 10; | |
| 42 | 42 | |
| 43 | 43 | /* Default "long" wait test time in ms. */ |
| 44 | −static const uint32_t LONG_WAIT_TEST_MS = 100; | |
| 44 | +static const u32 LONG_WAIT_TEST_MS = 100; | |
| 45 | 45 | |
| 46 | 46 | /* Shared with IRQ handler. */ |
| 47 | 47 | struct test_vcpu_shared_data { |
| @@ -53,9 +53,9 @@ struct test_args { · 5 unmodified lines | ||
| 53 | 53 | /* Virtual or physical timer and counter tests. */ |
| 54 | 54 | enum arch_timer timer; |
| 55 | 55 | /* Delay used for most timer tests. */ |
| 56 | − uint64_t wait_ms; | |
| 56 | + u64 wait_ms; | |
| 57 | 57 | /* Delay used in the test_long_timer_delays test. */ |
| 58 | − uint64_t long_wait_ms; | |
| 58 | + u64 long_wait_ms; | |
| 59 | 59 | /* Number of iterations. */ |
| 60 | 60 | int iterations; |
| 61 | 61 | /* Whether to test the physical timer. */ |
| @@ -82,12 +82,12 @@ enum sync_cmd { · 20 unmodified lines | ||
| 82 | 82 | NO_USERSPACE_CMD, |
| 83 | 83 | }; |
| 84 | 84 | |
| 85 | −typedef void (*sleep_method_t)(enum arch_timer timer, uint64_t usec); | |
| 85 | +typedef void (*sleep_method_t)(enum arch_timer timer, u64 usec); | |
| 86 | 86 | |
| 87 | −static void sleep_poll(enum arch_timer timer, uint64_t usec); | |
| 88 | −static void sleep_sched_poll(enum arch_timer timer, uint64_t usec); | |
| 89 | −static void sleep_in_userspace(enum arch_timer timer, uint64_t usec); | |
| 90 | −static void sleep_migrate(enum arch_timer timer, uint64_t usec); | |
| 87 | +static void sleep_poll(enum arch_timer timer, u64 usec); | |
| 88 | +static void sleep_sched_poll(enum arch_timer timer, u64 usec); | |
| 89 | +static void sleep_in_userspace(enum arch_timer timer, u64 usec); | |
| 90 | +static void sleep_migrate(enum arch_timer timer, u64 usec); | |
| 91 | 91 | |
| 92 | 92 | sleep_method_t sleep_method[] = { |
| 93 | 93 | sleep_poll, |
| @@ -115,14 +115,14 @@ enum timer_view { · 21 unmodified lines | ||
| 115 | 115 | TIMER_TVAL, |
| 116 | 116 | }; |
| 117 | 117 | |
| 118 | −static void assert_irqs_handled(uint32_t n) | |
| 118 | +static void assert_irqs_handled(u32 n) | |
| 119 | 119 | { |
| 120 | 120 | int h = atomic_read(&shared_data.handled); |
| 121 | 121 | |
| 122 | 122 | __GUEST_ASSERT(h == n, "Handled %d IRQS but expected %d", h, n); |
| 123 | 123 | } |
| 124 | 124 | |
| 125 | −static void userspace_cmd(uint64_t cmd) | |
| 125 | +static void userspace_cmd(u64 cmd) | |
| 126 | 126 | { |
| 127 | 127 | GUEST_SYNC_ARGS(cmd, 0, 0, 0, 0); |
| 128 | 128 | } |
| @@ -132,12 +132,12 @@ static void userspace_migrate_vcpu(void) · 3 unmodified lines | ||
| 132 | 132 | userspace_cmd(USERSPACE_MIGRATE_SELF); |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | −static void userspace_sleep(uint64_t usecs) | |
| 135 | +static void userspace_sleep(u64 usecs) | |
| 136 | 136 | { |
| 137 | 137 | GUEST_SYNC_ARGS(USERSPACE_USLEEP, usecs, 0, 0, 0); |
| 138 | 138 | } |
| 139 | 139 | |
| 140 | −static void set_counter(enum arch_timer timer, uint64_t counter) | |
| 140 | +static void set_counter(enum arch_timer timer, u64 counter) | |
| 141 | 141 | { |
| 142 | 142 | GUEST_SYNC_ARGS(SET_COUNTER_VALUE, counter, timer, 0, 0); |
| 143 | 143 | } |
| @@ -146,8 +146,8 @@ static void guest_irq_handler(struct ex_regs *regs) · 2 unmodified lines | ||
| 146 | 146 | { |
| 147 | 147 | unsigned int intid = gic_get_and_ack_irq(); |
| 148 | 148 | enum arch_timer timer; |
| 149 | − uint64_t cnt, cval; | |
| 150 | − uint32_t ctl; | |
| 149 | + u64 cnt, cval; | |
| 150 | + u32 ctl; | |
| 151 | 151 | bool timer_condition, istatus; |
| 152 | 152 | |
| 153 | 153 | if (intid == IAR_SPURIOUS) { |
| @@ -178,8 +178,8 @@ out: · 24 unmodified lines | ||
| 178 | 178 | gic_set_eoi(intid); |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | −static void set_cval_irq(enum arch_timer timer, uint64_t cval_cycles, | |
| 182 | − uint32_t ctl) | |
| 181 | +static void set_cval_irq(enum arch_timer timer, u64 cval_cycles, | |
| 182 | + u32 ctl) | |
| 183 | 183 | { |
| 184 | 184 | atomic_set(&shared_data.handled, 0); |
| 185 | 185 | atomic_set(&shared_data.spurious, 0); |
| @@ -187,8 +187,8 @@ static void set_cval_irq(enum arch_timer timer, uint64_t cval_cycles, · 1 unmodified line | ||
| 187 | 187 | timer_set_ctl(timer, ctl); |
| 188 | 188 | } |
| 189 | 189 | |
| 190 | −static void set_tval_irq(enum arch_timer timer, uint64_t tval_cycles, | |
| 191 | − uint32_t ctl) | |
| 190 | +static void set_tval_irq(enum arch_timer timer, u64 tval_cycles, | |
| 191 | + u32 ctl) | |
| 192 | 192 | { |
| 193 | 193 | atomic_set(&shared_data.handled, 0); |
| 194 | 194 | atomic_set(&shared_data.spurious, 0); |
| @@ -196,7 +196,7 @@ static void set_tval_irq(enum arch_timer timer, uint64_t tval_cycles, · 1 unmodified line | ||
| 196 | 196 | timer_set_ctl(timer, ctl); |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | −static void set_xval_irq(enum arch_timer timer, uint64_t xval, uint32_t ctl, | |
| 199 | +static void set_xval_irq(enum arch_timer timer, u64 xval, u32 ctl, | |
| 200 | 200 | enum timer_view tv) |
| 201 | 201 | { |
| 202 | 202 | switch (tv) { |
| @@ -275,13 +275,13 @@ static void wait_migrate_poll_for_irq(void) · 72 unmodified lines | ||
| 275 | 275 | * Sleep for usec microseconds by polling in the guest or in |
| 276 | 276 | * userspace (e.g. userspace_cmd=USERSPACE_SCHEDULE). |
| 277 | 277 | */ |
| 278 | −static void guest_poll(enum arch_timer test_timer, uint64_t usec, | |
| 278 | +static void guest_poll(enum arch_timer test_timer, u64 usec, | |
| 279 | 279 | enum sync_cmd usp_cmd) |
| 280 | 280 | { |
| 281 | − uint64_t cycles = usec_to_cycles(usec); | |
| 281 | + u64 cycles = usec_to_cycles(usec); | |
| 282 | 282 | /* Whichever timer we are testing with, sleep with the other. */ |
| 283 | 283 | enum arch_timer sleep_timer = 1 - test_timer; |
| 284 | − uint64_t start = timer_get_cntct(sleep_timer); | |
| 284 | + u64 start = timer_get_cntct(sleep_timer); | |
| 285 | 285 | |
| 286 | 286 | while ((timer_get_cntct(sleep_timer) - start) < cycles) { |
| 287 | 287 | if (usp_cmd == NO_USERSPACE_CMD) |
| @@ -291,22 +291,22 @@ static void guest_poll(enum arch_timer test_timer, uint64_t usec, · 3 unmodified lines | ||
| 291 | 291 | } |
| 292 | 292 | } |
| 293 | 293 | |
| 294 | −static void sleep_poll(enum arch_timer timer, uint64_t usec) | |
| 294 | +static void sleep_poll(enum arch_timer timer, u64 usec) | |
| 295 | 295 | { |
| 296 | 296 | guest_poll(timer, usec, NO_USERSPACE_CMD); |
| 297 | 297 | } |
| 298 | 298 | |
| 299 | −static void sleep_sched_poll(enum arch_timer timer, uint64_t usec) | |
| 299 | +static void sleep_sched_poll(enum arch_timer timer, u64 usec) | |
| 300 | 300 | { |
| 301 | 301 | guest_poll(timer, usec, USERSPACE_SCHED_YIELD); |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | −static void sleep_migrate(enum arch_timer timer, uint64_t usec) | |
| 304 | +static void sleep_migrate(enum arch_timer timer, u64 usec) | |
| 305 | 305 | { |
| 306 | 306 | guest_poll(timer, usec, USERSPACE_MIGRATE_SELF); |
| 307 | 307 | } |
| 308 | 308 | |
| 309 | −static void sleep_in_userspace(enum arch_timer timer, uint64_t usec) | |
| 309 | +static void sleep_in_userspace(enum arch_timer timer, u64 usec) | |
| 310 | 310 | { |
| 311 | 311 | userspace_sleep(usec); |
| 312 | 312 | } |
| @@ -315,15 +315,15 @@ static void sleep_in_userspace(enum arch_timer timer, uint64_t usec) · 2 unmodified lines | ||
| 315 | 315 | * Reset the timer state to some nice values like the counter not being close |
| 316 | 316 | * to the edge, and the control register masked and disabled. |
| 317 | 317 | */ |
| 318 | −static void reset_timer_state(enum arch_timer timer, uint64_t cnt) | |
| 318 | +static void reset_timer_state(enum arch_timer timer, u64 cnt) | |
| 319 | 319 | { |
| 320 | 320 | set_counter(timer, cnt); |
| 321 | 321 | timer_set_ctl(timer, CTL_IMASK); |
| 322 | 322 | } |
| 323 | 323 | |
| 324 | −static void test_timer_xval(enum arch_timer timer, uint64_t xval, | |
| 324 | +static void test_timer_xval(enum arch_timer timer, u64 xval, | |
| 325 | 325 | enum timer_view tv, irq_wait_method_t wm, bool reset_state, |
| 326 | − uint64_t reset_cnt) | |
| 326 | + u64 reset_cnt) | |
| 327 | 327 | { |
| 328 | 328 | local_irq_disable(); |
| 329 | 329 | |
| @@ -348,23 +348,23 @@ static void test_timer_xval(enum arch_timer timer, uint64_t xval, · 18 unmodified lines | ||
| 348 | 348 | * the "runner", like: tools/testing/selftests/kselftest/runner.sh. |
| 349 | 349 | */ |
| 350 | 350 | |
| 351 | −static void test_timer_cval(enum arch_timer timer, uint64_t cval, | |
| 351 | +static void test_timer_cval(enum arch_timer timer, u64 cval, | |
| 352 | 352 | irq_wait_method_t wm, bool reset_state, |
| 353 | − uint64_t reset_cnt) | |
| 353 | + u64 reset_cnt) | |
| 354 | 354 | { |
| 355 | 355 | test_timer_xval(timer, cval, TIMER_CVAL, wm, reset_state, reset_cnt); |
| 356 | 356 | } |
| 357 | 357 | |
| 358 | −static void test_timer_tval(enum arch_timer timer, int32_t tval, | |
| 358 | +static void test_timer_tval(enum arch_timer timer, s32 tval, | |
| 359 | 359 | irq_wait_method_t wm, bool reset_state, |
| 360 | − uint64_t reset_cnt) | |
| 360 | + u64 reset_cnt) | |
| 361 | 361 | { |
| 362 | − test_timer_xval(timer, (uint64_t) tval, TIMER_TVAL, wm, reset_state, | |
| 362 | + test_timer_xval(timer, (u64)tval, TIMER_TVAL, wm, reset_state, | |
| 363 | 363 | reset_cnt); |
| 364 | 364 | } |
| 365 | 365 | |
| 366 | −static void test_xval_check_no_irq(enum arch_timer timer, uint64_t xval, | |
| 367 | − uint64_t usec, enum timer_view timer_view, | |
| 366 | +static void test_xval_check_no_irq(enum arch_timer timer, u64 xval, | |
| 367 | + u64 usec, enum timer_view timer_view, | |
| 368 | 368 | sleep_method_t guest_sleep) |
| 369 | 369 | { |
| 370 | 370 | local_irq_disable(); |
| @@ -379,17 +379,17 @@ static void test_xval_check_no_irq(enum arch_timer timer, uint64_t xval, · 8 unmodified lines | ||
| 379 | 379 | assert_irqs_handled(0); |
| 380 | 380 | } |
| 381 | 381 | |
| 382 | −static void test_cval_no_irq(enum arch_timer timer, uint64_t cval, | |
| 383 | − uint64_t usec, sleep_method_t wm) | |
| 382 | +static void test_cval_no_irq(enum arch_timer timer, u64 cval, | |
| 383 | + u64 usec, sleep_method_t wm) | |
| 384 | 384 | { |
| 385 | 385 | test_xval_check_no_irq(timer, cval, usec, TIMER_CVAL, wm); |
| 386 | 386 | } |
| 387 | 387 | |
| 388 | −static void test_tval_no_irq(enum arch_timer timer, int32_t tval, uint64_t usec, | |
| 388 | +static void test_tval_no_irq(enum arch_timer timer, s32 tval, u64 usec, | |
| 389 | 389 | sleep_method_t wm) |
| 390 | 390 | { |
| 391 | − /* tval will be cast to an int32_t in test_xval_check_no_irq */ | |
| 392 | − test_xval_check_no_irq(timer, (uint64_t) tval, usec, TIMER_TVAL, wm); | |
| 391 | + /* tval will be cast to an s32 in test_xval_check_no_irq */ | |
| 392 | + test_xval_check_no_irq(timer, (u64)tval, usec, TIMER_TVAL, wm); | |
| 393 | 393 | } |
| 394 | 394 | |
| 395 | 395 | /* Test masking/unmasking a timer using the timer mask (not the IRQ mask). */ |
| @@ -463,7 +463,7 @@ static void test_timers_fired_multiple_times(enum arch_timer timer) · 67 unmodified lines | ||
| 463 | 463 | * timeout for the wait: we use the wfi instruction. |
| 464 | 464 | */ |
| 465 | 465 | static void test_reprogramming_timer(enum arch_timer timer, irq_wait_method_t wm, |
| 466 | − int32_t delta_1_ms, int32_t delta_2_ms) | |
| 466 | + s32 delta_1_ms, s32 delta_2_ms) | |
| 467 | 467 | { |
| 468 | 468 | local_irq_disable(); |
| 469 | 469 | reset_timer_state(timer, DEF_CNT); |
| @@ -488,7 +488,7 @@ static void test_reprogramming_timer(enum arch_timer timer, irq_wait_method_t wm · 18 unmodified lines | ||
| 488 | 488 | static void test_reprogram_timers(enum arch_timer timer) |
| 489 | 489 | { |
| 490 | 490 | int i; |
| 491 | − uint64_t base_wait = test_args.wait_ms; | |
| 491 | + u64 base_wait = test_args.wait_ms; | |
| 492 | 492 | |
| 493 | 493 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { |
| 494 | 494 | /* |
| @@ -504,8 +504,8 @@ static void test_reprogram_timers(enum arch_timer timer) · 9 unmodified lines | ||
| 504 | 504 | |
| 505 | 505 | static void test_basic_functionality(enum arch_timer timer) |
| 506 | 506 | { |
| 507 | − int32_t tval = (int32_t) msec_to_cycles(test_args.wait_ms); | |
| 508 | − uint64_t cval = DEF_CNT + msec_to_cycles(test_args.wait_ms); | |
| 507 | + s32 tval = (s32)msec_to_cycles(test_args.wait_ms); | |
| 508 | + u64 cval = DEF_CNT + msec_to_cycles(test_args.wait_ms); | |
| 509 | 509 | int i; |
| 510 | 510 | |
| 511 | 511 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { |
| @@ -593,7 +593,7 @@ static void test_set_cnt_after_tval_max(enum arch_timer timer, irq_wait_method_t · 81 unmodified lines | ||
| 593 | 593 | reset_timer_state(timer, DEF_CNT); |
| 594 | 594 | |
| 595 | 595 | set_cval_irq(timer, |
| 596 | − (uint64_t) TVAL_MAX + | |
| 596 | + (u64)TVAL_MAX + | |
| 597 | 597 | msec_to_cycles(test_args.wait_ms) / 2, CTL_ENABLE); |
| 598 | 598 | |
| 599 | 599 | set_counter(timer, TVAL_MAX); |
| @@ -608,7 +608,7 @@ static void test_set_cnt_after_tval_max(enum arch_timer timer, irq_wait_method_t · 8 unmodified lines | ||
| 608 | 608 | /* Test timers set for: cval = now + TVAL_MAX + wait_ms / 2 */ |
| 609 | 609 | static void test_timers_above_tval_max(enum arch_timer timer) |
| 610 | 610 | { |
| 611 | − uint64_t cval; | |
| 611 | + u64 cval; | |
| 612 | 612 | int i; |
| 613 | 613 | |
| 614 | 614 | /* |
| @@ -638,8 +638,8 @@ static void test_timers_above_tval_max(enum arch_timer timer) · 23 unmodified lines | ||
| 638 | 638 | * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and |
| 639 | 639 | * then waits for an IRQ. |
| 640 | 640 | */ |
| 641 | −static void test_set_cnt_after_xval(enum arch_timer timer, uint64_t cnt_1, | |
| 642 | − uint64_t xval, uint64_t cnt_2, | |
| 641 | +static void test_set_cnt_after_xval(enum arch_timer timer, u64 cnt_1, | |
| 642 | + u64 xval, u64 cnt_2, | |
| 643 | 643 | irq_wait_method_t wm, enum timer_view tv) |
| 644 | 644 | { |
| 645 | 645 | local_irq_disable(); |
| @@ -662,8 +662,8 @@ static void test_set_cnt_after_xval(enum arch_timer timer, uint64_t cnt_1, · 16 unmodified lines | ||
| 662 | 662 | * then waits for an IRQ. |
| 663 | 663 | */ |
| 664 | 664 | static void test_set_cnt_after_xval_no_irq(enum arch_timer timer, |
| 665 | − uint64_t cnt_1, uint64_t xval, | |
| 666 | − uint64_t cnt_2, | |
| 665 | + u64 cnt_1, u64 xval, | |
| 666 | + u64 cnt_2, | |
| 667 | 667 | sleep_method_t guest_sleep, |
| 668 | 668 | enum timer_view tv) |
| 669 | 669 | { |
| @@ -684,31 +684,31 @@ static void test_set_cnt_after_xval_no_irq(enum arch_timer timer, · 14 unmodified lines | ||
| 684 | 684 | timer_set_ctl(timer, CTL_IMASK); |
| 685 | 685 | } |
| 686 | 686 | |
| 687 | −static void test_set_cnt_after_tval(enum arch_timer timer, uint64_t cnt_1, | |
| 688 | − int32_t tval, uint64_t cnt_2, | |
| 687 | +static void test_set_cnt_after_tval(enum arch_timer timer, u64 cnt_1, | |
| 688 | + s32 tval, u64 cnt_2, | |
| 689 | 689 | irq_wait_method_t wm) |
| 690 | 690 | { |
| 691 | 691 | test_set_cnt_after_xval(timer, cnt_1, tval, cnt_2, wm, TIMER_TVAL); |
| 692 | 692 | } |
| 693 | 693 | |
| 694 | −static void test_set_cnt_after_cval(enum arch_timer timer, uint64_t cnt_1, | |
| 695 | − uint64_t cval, uint64_t cnt_2, | |
| 694 | +static void test_set_cnt_after_cval(enum arch_timer timer, u64 cnt_1, | |
| 695 | + u64 cval, u64 cnt_2, | |
| 696 | 696 | irq_wait_method_t wm) |
| 697 | 697 | { |
| 698 | 698 | test_set_cnt_after_xval(timer, cnt_1, cval, cnt_2, wm, TIMER_CVAL); |
| 699 | 699 | } |
| 700 | 700 | |
| 701 | 701 | static void test_set_cnt_after_tval_no_irq(enum arch_timer timer, |
| 702 | − uint64_t cnt_1, int32_t tval, | |
| 703 | − uint64_t cnt_2, sleep_method_t wm) | |
| 702 | + u64 cnt_1, s32 tval, | |
| 703 | + u64 cnt_2, sleep_method_t wm) | |
| 704 | 704 | { |
| 705 | 705 | test_set_cnt_after_xval_no_irq(timer, cnt_1, tval, cnt_2, wm, |
| 706 | 706 | TIMER_TVAL); |
| 707 | 707 | } |
| 708 | 708 | |
| 709 | 709 | static void test_set_cnt_after_cval_no_irq(enum arch_timer timer, |
| 710 | − uint64_t cnt_1, uint64_t cval, | |
| 711 | − uint64_t cnt_2, sleep_method_t wm) | |
| 710 | + u64 cnt_1, u64 cval, | |
| 711 | + u64 cnt_2, sleep_method_t wm) | |
| 712 | 712 | { |
| 713 | 713 | test_set_cnt_after_xval_no_irq(timer, cnt_1, cval, cnt_2, wm, |
| 714 | 714 | TIMER_CVAL); |
| @@ -718,7 +718,7 @@ static void test_set_cnt_after_cval_no_irq(enum arch_timer timer, · 3 unmodified lines | ||
| 718 | 718 | static void test_move_counters_ahead_of_timers(enum arch_timer timer) |
| 719 | 719 | { |
| 720 | 720 | int i; |
| 721 | − int32_t tval; | |
| 721 | + s32 tval; | |
| 722 | 722 | |
| 723 | 723 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { |
| 724 | 724 | irq_wait_method_t wm = irq_wait_method[i]; |
| @@ -730,8 +730,7 @@ static void test_move_counters_ahead_of_timers(enum arch_timer timer) · 5 unmodified lines | ||
| 730 | 730 | test_set_cnt_after_tval(timer, 0, -1, DEF_CNT + 1, wm); |
| 731 | 731 | test_set_cnt_after_tval(timer, 0, -1, TVAL_MAX, wm); |
| 732 | 732 | tval = TVAL_MAX; |
| 733 | − test_set_cnt_after_tval(timer, 0, tval, (uint64_t) tval + 1, | |
| 734 | − wm); | |
| 733 | + test_set_cnt_after_tval(timer, 0, tval, (u64)tval + 1, wm); | |
| 735 | 734 | } |
| 736 | 735 | } |
| 737 | 736 | |
| @@ -754,8 +753,8 @@ static void test_move_counters_behind_timers(enum arch_timer timer) · 16 unmodified lines | ||
| 754 | 753 | |
| 755 | 754 | static void test_timers_in_the_past(enum arch_timer timer) |
| 756 | 755 | { |
| 757 | − int32_t tval = -1 * (int32_t) msec_to_cycles(test_args.wait_ms); | |
| 758 | − uint64_t cval; | |
| 756 | + s32 tval = -1 * (s32)msec_to_cycles(test_args.wait_ms); | |
| 757 | + u64 cval; | |
| 759 | 758 | int i; |
| 760 | 759 | |
| 761 | 760 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { |
| @@ -790,8 +789,8 @@ static void test_timers_in_the_past(enum arch_timer timer) · 28 unmodified lines | ||
| 790 | 789 | |
| 791 | 790 | static void test_long_timer_delays(enum arch_timer timer) |
| 792 | 791 | { |
| 793 | − int32_t tval = (int32_t) msec_to_cycles(test_args.long_wait_ms); | |
| 794 | − uint64_t cval = DEF_CNT + msec_to_cycles(test_args.long_wait_ms); | |
| 792 | + s32 tval = (s32)msec_to_cycles(test_args.long_wait_ms); | |
| 793 | + u64 cval = DEF_CNT + msec_to_cycles(test_args.long_wait_ms); | |
| 795 | 794 | int i; |
| 796 | 795 | |
| 797 | 796 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { |
| @@ -846,11 +845,11 @@ static void guest_code(enum arch_timer timer) · 48 unmodified lines | ||
| 846 | 845 | |
| 847 | 846 | static cpu_set_t default_cpuset; |
| 848 | 847 | |
| 849 | −static uint32_t next_pcpu(void) | |
| 848 | +static u32 next_pcpu(void) | |
| 850 | 849 | { |
| 851 | − uint32_t max = get_nprocs(); | |
| 852 | − uint32_t cur = sched_getcpu(); | |
| 853 | − uint32_t next = cur; | |
| 850 | + u32 max = get_nprocs(); | |
| 851 | + u32 cur = sched_getcpu(); | |
| 852 | + u32 next = cur; | |
| 854 | 853 | cpu_set_t cpuset = default_cpuset; |
| 855 | 854 | |
| 856 | 855 | TEST_ASSERT(max > 1, "Need at least two physical cpus"); |
| @@ -862,7 +861,7 @@ static uint32_t next_pcpu(void) · 5 unmodified lines | ||
| 862 | 861 | return next; |
| 863 | 862 | } |
| 864 | 863 | |
| 865 | −static void kvm_set_cntxct(struct kvm_vcpu *vcpu, uint64_t cnt, | |
| 864 | +static void kvm_set_cntxct(struct kvm_vcpu *vcpu, u64 cnt, | |
| 866 | 865 | enum arch_timer timer) |
| 867 | 866 | { |
| 868 | 867 | if (timer == PHYSICAL) |
| @@ -874,7 +873,7 @@ static void kvm_set_cntxct(struct kvm_vcpu *vcpu, uint64_t cnt, · 5 unmodified lines | ||
| 874 | 873 | static void handle_sync(struct kvm_vcpu *vcpu, struct ucall *uc) |
| 875 | 874 | { |
| 876 | 875 | enum sync_cmd cmd = uc->args[1]; |
| 877 | − uint64_t val = uc->args[2]; | |
| 876 | + u64 val = uc->args[2]; | |
| 878 | 877 | enum arch_timer timer = uc->args[3]; |
| 879 | 878 | |
| 880 | 879 | switch (cmd) { |
| @@ -1018,8 +1017,8 @@ static bool parse_args(int argc, char *argv[]) · 137 unmodified lines | ||
| 1018 | 1017 | |
| 1019 | 1018 | static void set_counter_defaults(void) |
| 1020 | 1019 | { |
| 1021 | − const uint64_t MIN_ROLLOVER_SECS = 40ULL * 365 * 24 * 3600; | |
| 1022 | − uint64_t freq = read_sysreg(CNTFRQ_EL0); | |
| 1020 | + const u64 MIN_ROLLOVER_SECS = 40ULL * 365 * 24 * 3600; | |
| 1021 | + u64 freq = read_sysreg(CNTFRQ_EL0); | |
| 1023 | 1022 | int width = ilog2(MIN_ROLLOVER_SECS * freq); |
| 1024 | 1023 | |
| 1025 | 1024 | width = clamp(width, 56, 64); |
| @@ -31,14 +31,14 @@ · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start, hw_bp_ctx; |
| 33 | 33 | extern unsigned char iter_ss_begin, iter_ss_end; |
| 34 | −static volatile uint64_t sw_bp_addr, hw_bp_addr; | |
| 35 | −static volatile uint64_t wp_addr, wp_data_addr; | |
| 36 | −static volatile uint64_t svc_addr; | |
| 37 | −static volatile uint64_t ss_addr[4], ss_idx; | |
| 38 | −#define PC(v) ((uint64_t)&(v)) | |
| 34 | +static volatile u64 sw_bp_addr, hw_bp_addr; | |
| 35 | +static volatile u64 wp_addr, wp_data_addr; | |
| 36 | +static volatile u64 svc_addr; | |
| 37 | +static volatile u64 ss_addr[4], ss_idx; | |
| 38 | +#define PC(v) ((u64)&(v)) | |
| 39 | 39 | |
| 40 | 40 | #define GEN_DEBUG_WRITE_REG(reg_name) \ |
| 41 | −static void write_##reg_name(int num, uint64_t val) \ | |
| 41 | +static void write_##reg_name(int num, u64 val) \ | |
| 42 | 42 | { \ |
| 43 | 43 | switch (num) { \ |
| 44 | 44 | case 0: \ |
| @@ -102,8 +102,8 @@ GEN_DEBUG_WRITE_REG(dbgwvr) · 57 unmodified lines | ||
| 102 | 102 | |
| 103 | 103 | static void reset_debug_state(void) |
| 104 | 104 | { |
| 105 | − uint8_t brps, wrps, i; | |
| 106 | − uint64_t dfr0; | |
| 105 | + u8 brps, wrps, i; | |
| 106 | + u64 dfr0; | |
| 107 | 107 | |
| 108 | 108 | asm volatile("msr daifset, #8"); |
| 109 | 109 | |
| @@ -140,7 +140,7 @@ static void enable_os_lock(void) · 30 unmodified lines | ||
| 140 | 140 | |
| 141 | 141 | static void enable_monitor_debug_exceptions(void) |
| 142 | 142 | { |
| 143 | − uint64_t mdscr; | |
| 143 | + u64 mdscr; | |
| 144 | 144 | |
| 145 | 145 | asm volatile("msr daifclr, #8"); |
| 146 | 146 | |
| @@ -149,9 +149,9 @@ static void enable_monitor_debug_exceptions(void) · 2 unmodified lines | ||
| 149 | 149 | isb(); |
| 150 | 150 | } |
| 151 | 151 | |
| 152 | −static void install_wp(uint8_t wpn, uint64_t addr) | |
| 152 | +static void install_wp(u8 wpn, u64 addr) | |
| 153 | 153 | { |
| 154 | − uint32_t wcr; | |
| 154 | + u32 wcr; | |
| 155 | 155 | |
| 156 | 156 | wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E; |
| 157 | 157 | write_dbgwcr(wpn, wcr); |
| @@ -162,9 +162,9 @@ static void install_wp(uint8_t wpn, uint64_t addr) · 4 unmodified lines | ||
| 162 | 162 | enable_monitor_debug_exceptions(); |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | −static void install_hw_bp(uint8_t bpn, uint64_t addr) | |
| 165 | +static void install_hw_bp(u8 bpn, u64 addr) | |
| 166 | 166 | { |
| 167 | − uint32_t bcr; | |
| 167 | + u32 bcr; | |
| 168 | 168 | |
| 169 | 169 | bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E; |
| 170 | 170 | write_dbgbcr(bpn, bcr); |
| @@ -174,11 +174,10 @@ static void install_hw_bp(uint8_t bpn, uint64_t addr) · 3 unmodified lines | ||
| 174 | 174 | enable_monitor_debug_exceptions(); |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | −static void install_wp_ctx(uint8_t addr_wp, uint8_t ctx_bp, uint64_t addr, | |
| 178 | − uint64_t ctx) | |
| 177 | +static void install_wp_ctx(u8 addr_wp, u8 ctx_bp, u64 addr, u64 ctx) | |
| 179 | 178 | { |
| 180 | − uint32_t wcr; | |
| 181 | − uint64_t ctx_bcr; | |
| 179 | + u32 wcr; | |
| 180 | + u64 ctx_bcr; | |
| 182 | 181 | |
| 183 | 182 | /* Setup a context-aware breakpoint for Linked Context ID Match */ |
| 184 | 183 | ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | |
| @@ -188,7 +187,7 @@ static void install_wp_ctx(uint8_t addr_wp, uint8_t ctx_bp, uint64_t addr, · 3 unmodified lines | ||
| 188 | 187 | |
| 189 | 188 | /* Setup a linked watchpoint (linked to the context-aware breakpoint) */ |
| 190 | 189 | wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E | |
| 191 | − DBGWCR_WT_LINK | ((uint32_t)ctx_bp << DBGWCR_LBN_SHIFT); | |
| 190 | + DBGWCR_WT_LINK | ((u32)ctx_bp << DBGWCR_LBN_SHIFT); | |
| 192 | 191 | write_dbgwcr(addr_wp, wcr); |
| 193 | 192 | write_dbgwvr(addr_wp, addr); |
| 194 | 193 | isb(); |
| @@ -196,10 +195,9 @@ static void install_wp_ctx(uint8_t addr_wp, uint8_t ctx_bp, uint64_t addr, · 1 unmodified line | ||
| 196 | 195 | enable_monitor_debug_exceptions(); |
| 197 | 196 | } |
| 198 | 197 | |
| 199 | −void install_hw_bp_ctx(uint8_t addr_bp, uint8_t ctx_bp, uint64_t addr, | |
| 200 | − uint64_t ctx) | |
| 198 | +void install_hw_bp_ctx(u8 addr_bp, u8 ctx_bp, u64 addr, u64 ctx) | |
| 201 | 199 | { |
| 202 | − uint32_t addr_bcr, ctx_bcr; | |
| 200 | + u32 addr_bcr, ctx_bcr; | |
| 203 | 201 | |
| 204 | 202 | /* Setup a context-aware breakpoint for Linked Context ID Match */ |
| 205 | 203 | ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | |
| @@ -213,7 +211,7 @@ void install_hw_bp_ctx(uint8_t addr_bp, uint8_t ctx_bp, uint64_t addr, · 7 unmodified lines | ||
| 213 | 211 | */ |
| 214 | 212 | addr_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | |
| 215 | 213 | DBGBCR_BT_ADDR_LINK_CTX | |
| 216 | − ((uint32_t)ctx_bp << DBGBCR_LBN_SHIFT); | |
| 214 | + ((u32)ctx_bp << DBGBCR_LBN_SHIFT); | |
| 217 | 215 | write_dbgbcr(addr_bp, addr_bcr); |
| 218 | 216 | write_dbgbvr(addr_bp, addr); |
| 219 | 217 | isb(); |
| @@ -223,7 +221,7 @@ void install_hw_bp_ctx(uint8_t addr_bp, uint8_t ctx_bp, uint64_t addr, · 3 unmodified lines | ||
| 223 | 221 | |
| 224 | 222 | static void install_ss(void) |
| 225 | 223 | { |
| 226 | − uint64_t mdscr; | |
| 224 | + u64 mdscr; | |
| 227 | 225 | |
| 228 | 226 | asm volatile("msr daifclr, #8"); |
| 229 | 227 | |
| @@ -234,9 +232,9 @@ static void install_ss(void) · 4 unmodified lines | ||
| 234 | 232 | |
| 235 | 233 | static volatile char write_data; |
| 236 | 234 | |
| 237 | −static void guest_code(uint8_t bpn, uint8_t wpn, uint8_t ctx_bpn) | |
| 235 | +static void guest_code(u8 bpn, u8 wpn, u8 ctx_bpn) | |
| 238 | 236 | { |
| 239 | − uint64_t ctx = 0xabcdef; /* a random context number */ | |
| 237 | + u64 ctx = 0xabcdef; /* a random context number */ | |
| 240 | 238 | |
| 241 | 239 | /* Software-breakpoint */ |
| 242 | 240 | reset_debug_state(); |
| @@ -377,8 +375,8 @@ static void guest_svc_handler(struct ex_regs *regs) · 134 unmodified lines | ||
| 377 | 375 | |
| 378 | 376 | static void guest_code_ss(int test_cnt) |
| 379 | 377 | { |
| 380 | − uint64_t i; | |
| 381 | − uint64_t bvr, wvr, w_bvr, w_wvr; | |
| 378 | + u64 i; | |
| 379 | + u64 bvr, wvr, w_bvr, w_wvr; | |
| 382 | 380 | |
| 383 | 381 | for (i = 0; i < test_cnt; i++) { |
| 384 | 382 | /* Bits [1:0] of dbg{b,w}vr are RES0 */ |
| @@ -416,12 +414,12 @@ static void guest_code_ss(int test_cnt) · 31 unmodified lines | ||
| 416 | 414 | GUEST_DONE(); |
| 417 | 415 | } |
| 418 | 416 | |
| 419 | −static int debug_version(uint64_t id_aa64dfr0) | |
| 417 | +static int debug_version(u64 id_aa64dfr0) | |
| 420 | 418 | { |
| 421 | 419 | return FIELD_GET(ID_AA64DFR0_EL1_DebugVer, id_aa64dfr0); |
| 422 | 420 | } |
| 423 | 421 | |
| 424 | −static void test_guest_debug_exceptions(uint8_t bpn, uint8_t wpn, uint8_t ctx_bpn) | |
| 422 | +static void test_guest_debug_exceptions(u8 bpn, u8 wpn, u8 ctx_bpn) | |
| 425 | 423 | { |
| 426 | 424 | struct kvm_vcpu *vcpu; |
| 427 | 425 | struct kvm_vm *vm; |
| @@ -468,8 +466,8 @@ void test_single_step_from_userspace(int test_cnt) · 40 unmodified lines | ||
| 468 | 466 | struct kvm_vm *vm; |
| 469 | 467 | struct ucall uc; |
| 470 | 468 | struct kvm_run *run; |
| 471 | − uint64_t pc, cmd; | |
| 472 | − uint64_t test_pc = 0; | |
| 469 | + u64 pc, cmd; | |
| 470 | + u64 test_pc = 0; | |
| 473 | 471 | bool ss_enable = false; |
| 474 | 472 | struct kvm_guest_debug debug = {}; |
| 475 | 473 | |
| @@ -506,7 +504,7 @@ void test_single_step_from_userspace(int test_cnt) · 30 unmodified lines | ||
| 506 | 504 | "Unexpected pc 0x%lx (expected 0x%lx)", |
| 507 | 505 | pc, test_pc); |
| 508 | 506 | |
| 509 | − if ((pc + 4) == (uint64_t)&iter_ss_end) { | |
| 507 | + if ((pc + 4) == (u64)&iter_ss_end) { | |
| 510 | 508 | test_pc = 0; |
| 511 | 509 | debug.control = KVM_GUESTDBG_ENABLE; |
| 512 | 510 | ss_enable = false; |
| @@ -519,8 +517,8 @@ void test_single_step_from_userspace(int test_cnt) · 6 unmodified lines | ||
| 519 | 517 | * iter_ss_end, the pc for the next KVM_EXIT_DEBUG should |
| 520 | 518 | * be the current pc + 4. |
| 521 | 519 | */ |
| 522 | − if ((pc >= (uint64_t)&iter_ss_begin) && | |
| 523 | − (pc < (uint64_t)&iter_ss_end)) | |
| 520 | + if ((pc >= (u64)&iter_ss_begin) && | |
| 521 | + (pc < (u64)&iter_ss_end)) | |
| 524 | 522 | test_pc = pc + 4; |
| 525 | 523 | else |
| 526 | 524 | test_pc = 0; |
| @@ -533,9 +531,9 @@ void test_single_step_from_userspace(int test_cnt) · 6 unmodified lines | ||
| 533 | 531 | * Run debug testing using the various breakpoint#, watchpoint# and |
| 534 | 532 | * context-aware breakpoint# with the given ID_AA64DFR0_EL1 configuration. |
| 535 | 533 | */ |
| 536 | −void test_guest_debug_exceptions_all(uint64_t aa64dfr0) | |
| 534 | +void test_guest_debug_exceptions_all(u64 aa64dfr0) | |
| 537 | 535 | { |
| 538 | − uint8_t brp_num, wrp_num, ctx_brp_num, normal_brp_num, ctx_brp_base; | |
| 536 | + u8 brp_num, wrp_num, ctx_brp_num, normal_brp_num, ctx_brp_base; | |
| 539 | 537 | int b, w, c; |
| 540 | 538 | |
| 541 | 539 | /* Number of breakpoints */ |
| @@ -580,7 +578,7 @@ int main(int argc, char *argv[]) · 38 unmodified lines | ||
| 580 | 578 | struct kvm_vm *vm; |
| 581 | 579 | int opt; |
| 582 | 580 | int ss_iteration = 10000; |
| 583 | − uint64_t aa64dfr0; | |
| 581 | + u64 aa64dfr0; | |
| 584 | 582 | |
| 585 | 583 | vm = vm_create_with_one_vcpu(&vcpu, guest_code); |
| 586 | 584 | aa64dfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1)); |
| @@ -29,9 +29,9 @@ · 28 unmodified lines | ||
| 29 | 29 | #define KVM_REG_ARM_VENDOR_HYP_BMAP_2_RESET_VAL 0 |
| 30 | 30 | |
| 31 | 31 | struct kvm_fw_reg_info { |
| 32 | − uint64_t reg; /* Register definition */ | |
| 33 | − uint64_t max_feat_bit; /* Bit that represents the upper limit of the feature-map */ | |
| 34 | − uint64_t reset_val; /* Reset value for the register */ | |
| 32 | + u64 reg; /* Register definition */ | |
| 33 | + u64 max_feat_bit; /* Bit that represents the upper limit of the feature-map */ | |
| 34 | + u64 reset_val; /* Reset value for the register */ | |
| 35 | 35 | }; |
| 36 | 36 | |
| 37 | 37 | #define FW_REG_INFO(r) \ |
| @@ -59,8 +59,8 @@ enum test_stage { · 21 unmodified lines | ||
| 59 | 59 | static int stage = TEST_STAGE_REG_IFACE; |
| 60 | 60 | |
| 61 | 61 | struct test_hvc_info { |
| 62 | − uint32_t func_id; | |
| 63 | − uint64_t arg1; | |
| 62 | + u32 func_id; | |
| 63 | + u64 arg1; | |
| 64 | 64 | }; |
| 65 | 65 | |
| 66 | 66 | #define TEST_HVC_INFO(f, a1) \ |
| @@ -152,9 +152,9 @@ static void guest_code(void) · 85 unmodified lines | ||
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | struct st_time { |
| 155 | − uint32_t rev; | |
| 156 | − uint32_t attr; | |
| 157 | − uint64_t st_time; | |
| 155 | + u32 rev; | |
| 156 | + u32 attr; | |
| 157 | + u64 st_time; | |
| 158 | 158 | }; |
| 159 | 159 | |
| 160 | 160 | #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) |
| @@ -162,7 +162,7 @@ struct st_time { · 1 unmodified line | ||
| 162 | 162 | |
| 163 | 163 | static void steal_time_init(struct kvm_vcpu *vcpu) |
| 164 | 164 | { |
| 165 | − uint64_t st_ipa = (ulong)ST_GPA_BASE; | |
| 165 | + u64 st_ipa = (ulong)ST_GPA_BASE; | |
| 166 | 166 | unsigned int gpages; |
| 167 | 167 | |
| 168 | 168 | gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); |
| @@ -174,13 +174,13 @@ static void steal_time_init(struct kvm_vcpu *vcpu) · 5 unmodified lines | ||
| 174 | 174 | |
| 175 | 175 | static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) |
| 176 | 176 | { |
| 177 | − uint64_t val; | |
| 177 | + u64 val; | |
| 178 | 178 | unsigned int i; |
| 179 | 179 | int ret; |
| 180 | 180 | |
| 181 | 181 | for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { |
| 182 | 182 | const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; |
| 183 | − uint64_t set_val; | |
| 183 | + u64 set_val; | |
| 184 | 184 | |
| 185 | 185 | /* First 'read' should be the reset value for the reg */ |
| 186 | 186 | val = vcpu_get_reg(vcpu, reg_info->reg); |
| @@ -229,7 +229,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) · 42 unmodified lines | ||
| 229 | 229 | |
| 230 | 230 | static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) |
| 231 | 231 | { |
| 232 | − uint64_t val; | |
| 232 | + u64 val; | |
| 233 | 233 | unsigned int i; |
| 234 | 234 | int ret; |
| 235 | 235 | |
| @@ -13,7 +13,7 @@ static volatile bool sys64, undef; · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #define __check_sr_read(r) \ |
| 15 | 15 | ({ \ |
| 16 | − uint64_t val; \ | |
| 16 | + u64 val; \ | |
| 17 | 17 | \ |
| 18 | 18 | sys64 = false; \ |
| 19 | 19 | undef = false; \ |
| @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) · 81 unmodified lines | ||
| 101 | 101 | { |
| 102 | 102 | struct kvm_vcpu *vcpu; |
| 103 | 103 | struct kvm_vm *vm; |
| 104 | − uint64_t mmfr2; | |
| 104 | + u64 mmfr2; | |
| 105 | 105 | |
| 106 | 106 | test_disable_default_vgic(); |
| 107 | 107 | |
| @@ -15,7 +15,7 @@ static volatile bool handled; · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #define __check_sr_read(r) \ |
| 17 | 17 | ({ \ |
| 18 | − uint64_t val; \ | |
| 18 | + u64 val; \ | |
| 19 | 19 | \ |
| 20 | 20 | handled = false; \ |
| 21 | 21 | dsb(sy); \ |
| @@ -33,7 +33,7 @@ static volatile bool handled; · 11 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | #define __check_gicv5_gicr_op(r) \ |
| 35 | 35 | ({ \ |
| 36 | − uint64_t val; \ | |
| 36 | + u64 val; \ | |
| 37 | 37 | \ |
| 38 | 38 | handled = false; \ |
| 39 | 39 | dsb(sy); \ |
| @@ -82,7 +82,7 @@ static volatile bool handled; · 42 unmodified lines | ||
| 82 | 82 | |
| 83 | 83 | static void guest_code_gicv3(void) |
| 84 | 84 | { |
| 85 | − uint64_t val; | |
| 85 | + u64 val; | |
| 86 | 86 | |
| 87 | 87 | /* |
| 88 | 88 | * Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having |
| @@ -262,7 +262,7 @@ int main(int argc, char *argv[]) · 173 unmodified lines | ||
| 262 | 262 | struct kvm_vcpu *vcpu; |
| 263 | 263 | struct kvm_vm *vm; |
| 264 | 264 | bool has_v3, has_v5; |
| 265 | − uint64_t pfr; | |
| 265 | + u64 pfr; | |
| 266 | 266 | |
| 267 | 267 | test_disable_default_vgic(); |
| 268 | 268 | |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #define TEST_PTE_GVA 0xb0000000 |
| 24 | 24 | #define TEST_DATA 0x0123456789ABCDEF |
| 25 | 25 | |
| 26 | −static uint64_t *guest_test_memory = (uint64_t *)TEST_GVA; | |
| 26 | +static u64 *guest_test_memory = (u64 *)TEST_GVA; | |
| 27 | 27 | |
| 28 | 28 | #define CMD_NONE (0) |
| 29 | 29 | #define CMD_SKIP_TEST (1ULL << 1) |
| @@ -48,7 +48,7 @@ static struct event_cnt { · 18 unmodified lines | ||
| 48 | 48 | |
| 49 | 49 | struct test_desc { |
| 50 | 50 | const char *name; |
| 51 | − uint64_t mem_mark_cmd; | |
| 51 | + u64 mem_mark_cmd; | |
| 52 | 52 | /* Skip the test if any prepare function returns false */ |
| 53 | 53 | bool (*guest_prepare[PREPARE_FN_NR])(void); |
| 54 | 54 | void (*guest_test)(void); |
| @@ -59,8 +59,8 @@ struct test_desc { · 4 unmodified lines | ||
| 59 | 59 | void (*iabt_handler)(struct ex_regs *regs); |
| 60 | 60 | void (*mmio_handler)(struct kvm_vm *vm, struct kvm_run *run); |
| 61 | 61 | void (*fail_vcpu_run_handler)(int ret); |
| 62 | − uint32_t pt_memslot_flags; | |
| 63 | − uint32_t data_memslot_flags; | |
| 62 | + u32 pt_memslot_flags; | |
| 63 | + u32 data_memslot_flags; | |
| 64 | 64 | bool skip; |
| 65 | 65 | struct event_cnt expected_events; |
| 66 | 66 | }; |
| @@ -70,9 +70,9 @@ struct test_params { · 3 unmodified lines | ||
| 70 | 70 | struct test_desc *test_desc; |
| 71 | 71 | }; |
| 72 | 72 | |
| 73 | −static inline void flush_tlb_page(uint64_t vaddr) | |
| 73 | +static inline void flush_tlb_page(gva_t gva) | |
| 74 | 74 | { |
| 75 | − uint64_t page = vaddr >> 12; | |
| 75 | + gva_t page = gva >> 12; | |
| 76 | 76 | |
| 77 | 77 | dsb(ishst); |
| 78 | 78 | asm volatile("tlbi vaae1is, %0" :: "r" (page)); |
| @@ -82,7 +82,7 @@ static inline void flush_tlb_page(uint64_t vaddr) · 3 unmodified lines | ||
| 82 | 82 | |
| 83 | 83 | static void guest_write64(void) |
| 84 | 84 | { |
| 85 | − uint64_t val; | |
| 85 | + u64 val; | |
| 86 | 86 | |
| 87 | 87 | WRITE_ONCE(*guest_test_memory, TEST_DATA); |
| 88 | 88 | val = READ_ONCE(*guest_test_memory); |
| @@ -92,8 +92,8 @@ static void guest_write64(void) · 3 unmodified lines | ||
| 92 | 92 | /* Check the system for atomic instructions. */ |
| 93 | 93 | static bool guest_check_lse(void) |
| 94 | 94 | { |
| 95 | − uint64_t isar0 = read_sysreg(id_aa64isar0_el1); | |
| 96 | − uint64_t atomic; | |
| 95 | + u64 isar0 = read_sysreg(id_aa64isar0_el1); | |
| 96 | + u64 atomic; | |
| 97 | 97 | |
| 98 | 98 | atomic = FIELD_GET(ID_AA64ISAR0_EL1_ATOMIC, isar0); |
| 99 | 99 | return atomic >= 2; |
| @@ -101,8 +101,8 @@ static bool guest_check_lse(void) · 1 unmodified line | ||
| 101 | 101 | |
| 102 | 102 | static bool guest_check_dc_zva(void) |
| 103 | 103 | { |
| 104 | − uint64_t dczid = read_sysreg(dczid_el0); | |
| 105 | − uint64_t dzp = FIELD_GET(DCZID_EL0_DZP, dczid); | |
| 104 | + u64 dczid = read_sysreg(dczid_el0); | |
| 105 | + u64 dzp = FIELD_GET(DCZID_EL0_DZP, dczid); | |
| 106 | 106 | |
| 107 | 107 | return dzp == 0; |
| 108 | 108 | } |
| @@ -110,7 +110,7 @@ static bool guest_check_dc_zva(void) · 1 unmodified line | ||
| 110 | 110 | /* Compare and swap instruction. */ |
| 111 | 111 | static void guest_cas(void) |
| 112 | 112 | { |
| 113 | − uint64_t val; | |
| 113 | + u64 val; | |
| 114 | 114 | |
| 115 | 115 | GUEST_ASSERT(guest_check_lse()); |
| 116 | 116 | asm volatile(".arch_extension lse\n" |
| @@ -122,7 +122,7 @@ static void guest_cas(void) · 5 unmodified lines | ||
| 122 | 122 | |
| 123 | 123 | static void guest_read64(void) |
| 124 | 124 | { |
| 125 | − uint64_t val; | |
| 125 | + u64 val; | |
| 126 | 126 | |
| 127 | 127 | val = READ_ONCE(*guest_test_memory); |
| 128 | 128 | GUEST_ASSERT_EQ(val, 0); |
| @@ -131,7 +131,7 @@ static void guest_read64(void) · 2 unmodified lines | ||
| 131 | 131 | /* Address translation instruction */ |
| 132 | 132 | static void guest_at(void) |
| 133 | 133 | { |
| 134 | − uint64_t par; | |
| 134 | + u64 par; | |
| 135 | 135 | |
| 136 | 136 | asm volatile("at s1e1r, %0" :: "r" (guest_test_memory)); |
| 137 | 137 | isb(); |
| @@ -148,7 +148,7 @@ static void guest_at(void) · 10 unmodified lines | ||
| 148 | 148 | */ |
| 149 | 149 | static void guest_dc_zva(void) |
| 150 | 150 | { |
| 151 | − uint16_t val; | |
| 151 | + u16 val; | |
| 152 | 152 | |
| 153 | 153 | asm volatile("dc zva, %0" :: "r" (guest_test_memory)); |
| 154 | 154 | dsb(ish); |
| @@ -164,8 +164,8 @@ static void guest_dc_zva(void) · 9 unmodified lines | ||
| 164 | 164 | */ |
| 165 | 165 | static void guest_ld_preidx(void) |
| 166 | 166 | { |
| 167 | − uint64_t val; | |
| 168 | − uint64_t addr = TEST_GVA - 8; | |
| 167 | + u64 val; | |
| 168 | + u64 addr = TEST_GVA - 8; | |
| 169 | 169 | |
| 170 | 170 | /* |
| 171 | 171 | * This ends up accessing "TEST_GVA + 8 - 8", where "TEST_GVA - 8" is |
| @@ -179,8 +179,8 @@ static void guest_ld_preidx(void) · 7 unmodified lines | ||
| 179 | 179 | |
| 180 | 180 | static void guest_st_preidx(void) |
| 181 | 181 | { |
| 182 | − uint64_t val = TEST_DATA; | |
| 183 | − uint64_t addr = TEST_GVA - 8; | |
| 182 | + u64 val = TEST_DATA; | |
| 183 | + u64 addr = TEST_GVA - 8; | |
| 184 | 184 | |
| 185 | 185 | asm volatile("str %0, [%1, #8]!" |
| 186 | 186 | : "+r" (val), "+r" (addr)); |
| @@ -191,8 +191,8 @@ static void guest_st_preidx(void) · 4 unmodified lines | ||
| 191 | 191 | |
| 192 | 192 | static bool guest_set_ha(void) |
| 193 | 193 | { |
| 194 | − uint64_t mmfr1 = read_sysreg(id_aa64mmfr1_el1); | |
| 195 | − uint64_t hadbs, tcr; | |
| 194 | + u64 mmfr1 = read_sysreg(id_aa64mmfr1_el1); | |
| 195 | + u64 hadbs, tcr; | |
| 196 | 196 | |
| 197 | 197 | /* Skip if HA is not supported. */ |
| 198 | 198 | hadbs = FIELD_GET(ID_AA64MMFR1_EL1_HAFDBS, mmfr1); |
| @@ -208,7 +208,7 @@ static bool guest_set_ha(void) · 9 unmodified lines | ||
| 208 | 208 | |
| 209 | 209 | static bool guest_clear_pte_af(void) |
| 210 | 210 | { |
| 211 | − *((uint64_t *)TEST_PTE_GVA) &= ~PTE_AF; | |
| 211 | + *((u64 *)TEST_PTE_GVA) &= ~PTE_AF; | |
| 212 | 212 | flush_tlb_page(TEST_GVA); |
| 213 | 213 | |
| 214 | 214 | return true; |
| @@ -217,7 +217,7 @@ static bool guest_clear_pte_af(void) · 2 unmodified lines | ||
| 217 | 217 | static void guest_check_pte_af(void) |
| 218 | 218 | { |
| 219 | 219 | dsb(ish); |
| 220 | − GUEST_ASSERT_EQ(*((uint64_t *)TEST_PTE_GVA) & PTE_AF, PTE_AF); | |
| 220 | + GUEST_ASSERT_EQ(*((u64 *)TEST_PTE_GVA) & PTE_AF, PTE_AF); | |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | static void guest_check_write_in_dirty_log(void) |
| @@ -302,26 +302,26 @@ static void no_iabt_handler(struct ex_regs *regs) · 78 unmodified lines | ||
| 302 | 302 | static struct uffd_args { |
| 303 | 303 | char *copy; |
| 304 | 304 | void *hva; |
| 305 | − uint64_t paging_size; | |
| 305 | + u64 paging_size; | |
| 306 | 306 | } pt_args, data_args; |
| 307 | 307 | |
| 308 | 308 | /* Returns true to continue the test, and false if it should be skipped. */ |
| 309 | 309 | static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg, |
| 310 | 310 | struct uffd_args *args) |
| 311 | 311 | { |
| 312 | − uint64_t addr = msg->arg.pagefault.address; | |
| 313 | − uint64_t flags = msg->arg.pagefault.flags; | |
| 312 | + u64 addr = msg->arg.pagefault.address; | |
| 313 | + u64 flags = msg->arg.pagefault.flags; | |
| 314 | 314 | struct uffdio_copy copy; |
| 315 | 315 | int ret; |
| 316 | 316 | |
| 317 | 317 | TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING, |
| 318 | 318 | "The only expected UFFD mode is MISSING"); |
| 319 | − TEST_ASSERT_EQ(addr, (uint64_t)args->hva); | |
| 319 | + TEST_ASSERT_EQ(addr, (u64)args->hva); | |
| 320 | 320 | |
| 321 | 321 | pr_debug("uffd fault: addr=%p write=%d\n", |
| 322 | 322 | (void *)addr, !!(flags & UFFD_PAGEFAULT_FLAG_WRITE)); |
| 323 | 323 | |
| 324 | − copy.src = (uint64_t)args->copy; | |
| 324 | + copy.src = (u64)args->copy; | |
| 325 | 325 | copy.dst = addr; |
| 326 | 326 | copy.len = args->paging_size; |
| 327 | 327 | copy.mode = 0; |
| @@ -407,7 +407,7 @@ static bool punch_hole_in_backing_store(struct kvm_vm *vm, · 79 unmodified lines | ||
| 407 | 407 | struct userspace_mem_region *region) |
| 408 | 408 | { |
| 409 | 409 | void *hva = (void *)region->region.userspace_addr; |
| 410 | − uint64_t paging_size = region->region.memory_size; | |
| 410 | + u64 paging_size = region->region.memory_size; | |
| 411 | 411 | int ret, fd = region->fd; |
| 412 | 412 | |
| 413 | 413 | if (fd != -1) { |
| @@ -438,7 +438,7 @@ static void mmio_on_test_gpa_handler(struct kvm_vm *vm, struct kvm_run *run) · 24 unmodified lines | ||
| 438 | 438 | |
| 439 | 439 | static void mmio_no_handler(struct kvm_vm *vm, struct kvm_run *run) |
| 440 | 440 | { |
| 441 | − uint64_t data; | |
| 441 | + u64 data; | |
| 442 | 442 | |
| 443 | 443 | memcpy(&data, run->mmio.data, sizeof(data)); |
| 444 | 444 | pr_debug("addr=%lld len=%d w=%d data=%lx\n", |
| @@ -449,11 +449,11 @@ static void mmio_no_handler(struct kvm_vm *vm, struct kvm_run *run) · 4 unmodified lines | ||
| 449 | 449 | |
| 450 | 450 | static bool check_write_in_dirty_log(struct kvm_vm *vm, |
| 451 | 451 | struct userspace_mem_region *region, |
| 452 | − uint64_t host_pg_nr) | |
| 452 | + u64 host_pg_nr) | |
| 453 | 453 | { |
| 454 | 454 | unsigned long *bmap; |
| 455 | 455 | bool first_page_dirty; |
| 456 | − uint64_t size = region->region.memory_size; | |
| 456 | + u64 size = region->region.memory_size; | |
| 457 | 457 | |
| 458 | 458 | /* getpage_size() is not always equal to vm->page_size */ |
| 459 | 459 | bmap = bitmap_zalloc(size / getpagesize()); |
| @@ -468,7 +468,7 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd) · 8 unmodified lines | ||
| 468 | 468 | { |
| 469 | 469 | struct userspace_mem_region *data_region, *pt_region; |
| 470 | 470 | bool continue_test = true; |
| 471 | − uint64_t pte_gpa, pte_pg; | |
| 471 | + u64 pte_gpa, pte_pg; | |
| 472 | 472 | |
| 473 | 473 | data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); |
| 474 | 474 | pt_region = vm_get_mem_region(vm, MEM_REGION_PT); |
| @@ -510,7 +510,7 @@ void fail_vcpu_run_mmio_no_syndrome_handler(int ret) · 35 unmodified lines | ||
| 510 | 510 | events.fail_vcpu_runs += 1; |
| 511 | 511 | } |
| 512 | 512 | |
| 513 | −typedef uint32_t aarch64_insn_t; | |
| 513 | +typedef u32 aarch64_insn_t; | |
| 514 | 514 | extern aarch64_insn_t __exec_test[2]; |
| 515 | 515 | |
| 516 | 516 | noinline void __return_0x77(void) |
| @@ -525,7 +525,7 @@ noinline void __return_0x77(void) · 8 unmodified lines | ||
| 525 | 525 | */ |
| 526 | 526 | static void load_exec_code_for_test(struct kvm_vm *vm) |
| 527 | 527 | { |
| 528 | − uint64_t *code; | |
| 528 | + u64 *code; | |
| 529 | 529 | struct userspace_mem_region *region; |
| 530 | 530 | void *hva; |
| 531 | 531 | |
| @@ -552,7 +552,7 @@ static void setup_abort_handlers(struct kvm_vm *vm, struct kvm_vcpu *vcpu, · 20 unmodified lines | ||
| 552 | 552 | static void setup_gva_maps(struct kvm_vm *vm) |
| 553 | 553 | { |
| 554 | 554 | struct userspace_mem_region *region; |
| 555 | − uint64_t pte_gpa; | |
| 555 | + u64 pte_gpa; | |
| 556 | 556 | |
| 557 | 557 | region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); |
| 558 | 558 | /* Map TEST_GVA first. This will install a new PTE. */ |
| @@ -574,12 +574,12 @@ enum pf_test_memslots { · 15 unmodified lines | ||
| 574 | 574 | */ |
| 575 | 575 | static void setup_memslots(struct kvm_vm *vm, struct test_params *p) |
| 576 | 576 | { |
| 577 | − uint64_t backing_src_pagesz = get_backing_src_pagesz(p->src_type); | |
| 578 | − uint64_t guest_page_size = vm->page_size; | |
| 579 | − uint64_t max_gfn = vm_compute_max_gfn(vm); | |
| 577 | + u64 backing_src_pagesz = get_backing_src_pagesz(p->src_type); | |
| 578 | + u64 guest_page_size = vm->page_size; | |
| 579 | + u64 max_gfn = vm_compute_max_gfn(vm); | |
| 580 | 580 | /* Enough for 2M of code when using 4K guest pages. */ |
| 581 | − uint64_t code_npages = 512; | |
| 582 | − uint64_t pt_size, data_size, data_gpa; | |
| 581 | + u64 code_npages = 512; | |
| 582 | + u64 pt_size, data_size, data_gpa; | |
| 583 | 583 | |
| 584 | 584 | /* |
| 585 | 585 | * This test requires 1 pgd, 2 pud, 4 pmd, and 6 pte pages when using |
| @@ -22,8 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #define CPU_ON_ENTRY_ADDR 0xfeedf00dul |
| 23 | 23 | #define CPU_ON_CONTEXT_ID 0xdeadc0deul |
| 24 | 24 | |
| 25 | −static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, | |
| 26 | − uint64_t context_id) | |
| 25 | +static u64 psci_cpu_on(u64 target_cpu, u64 entry_addr, u64 context_id) | |
| 27 | 26 | { |
| 28 | 27 | struct arm_smccc_res res; |
| 29 | 28 | |
| @@ -33,8 +32,7 @@ static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, · 3 unmodified lines | ||
| 33 | 32 | return res.a0; |
| 34 | 33 | } |
| 35 | 34 | |
| 36 | −static uint64_t psci_affinity_info(uint64_t target_affinity, | |
| 37 | − uint64_t lowest_affinity_level) | |
| 35 | +static u64 psci_affinity_info(u64 target_affinity, u64 lowest_affinity_level) | |
| 38 | 36 | { |
| 39 | 37 | struct arm_smccc_res res; |
| 40 | 38 | |
| @@ -44,7 +42,7 @@ static uint64_t psci_affinity_info(uint64_t target_affinity, · 3 unmodified lines | ||
| 44 | 42 | return res.a0; |
| 45 | 43 | } |
| 46 | 44 | |
| 47 | −static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id) | |
| 45 | +static u64 psci_system_suspend(u64 entry_addr, u64 context_id) | |
| 48 | 46 | { |
| 49 | 47 | struct arm_smccc_res res; |
| 50 | 48 | |
| @@ -54,7 +52,7 @@ static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id) · 3 unmodified lines | ||
| 54 | 52 | return res.a0; |
| 55 | 53 | } |
| 56 | 54 | |
| 57 | −static uint64_t psci_system_off2(uint64_t type, uint64_t cookie) | |
| 55 | +static u64 psci_system_off2(u64 type, u64 cookie) | |
| 58 | 56 | { |
| 59 | 57 | struct arm_smccc_res res; |
| 60 | 58 | |
| @@ -63,7 +61,7 @@ static uint64_t psci_system_off2(uint64_t type, uint64_t cookie) · 2 unmodified lines | ||
| 63 | 61 | return res.a0; |
| 64 | 62 | } |
| 65 | 63 | |
| 66 | −static uint64_t psci_features(uint32_t func_id) | |
| 64 | +static u64 psci_features(u32 func_id) | |
| 67 | 65 | { |
| 68 | 66 | struct arm_smccc_res res; |
| 69 | 67 | |
| @@ -110,7 +108,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) · 40 unmodified lines | ||
| 110 | 108 | |
| 111 | 109 | static void assert_vcpu_reset(struct kvm_vcpu *vcpu) |
| 112 | 110 | { |
| 113 | − uint64_t obs_pc, obs_x0; | |
| 111 | + u64 obs_pc, obs_x0; | |
| 114 | 112 | |
| 115 | 113 | obs_pc = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc)); |
| 116 | 114 | obs_x0 = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.regs[0])); |
| @@ -123,9 +121,9 @@ static void assert_vcpu_reset(struct kvm_vcpu *vcpu) · 6 unmodified lines | ||
| 123 | 121 | obs_x0, CPU_ON_CONTEXT_ID); |
| 124 | 122 | } |
| 125 | 123 | |
| 126 | −static void guest_test_cpu_on(uint64_t target_cpu) | |
| 124 | +static void guest_test_cpu_on(u64 target_cpu) | |
| 127 | 125 | { |
| 128 | − uint64_t target_state; | |
| 126 | + u64 target_state; | |
| 129 | 127 | |
| 130 | 128 | GUEST_ASSERT(!psci_cpu_on(target_cpu, CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID)); |
| 131 | 129 | |
| @@ -142,7 +140,7 @@ static void guest_test_cpu_on(uint64_t target_cpu) · 10 unmodified lines | ||
| 142 | 140 | static void host_test_cpu_on(void) |
| 143 | 141 | { |
| 144 | 142 | struct kvm_vcpu *source, *target; |
| 145 | − uint64_t target_mpidr; | |
| 143 | + u64 target_mpidr; | |
| 146 | 144 | struct kvm_vm *vm; |
| 147 | 145 | struct ucall uc; |
| 148 | 146 | |
| @@ -166,7 +164,7 @@ static void host_test_cpu_on(void) · 17 unmodified lines | ||
| 166 | 164 | |
| 167 | 165 | static void guest_test_system_suspend(void) |
| 168 | 166 | { |
| 169 | − uint64_t ret; | |
| 167 | + u64 ret; | |
| 170 | 168 | |
| 171 | 169 | /* assert that SYSTEM_SUSPEND is discoverable */ |
| 172 | 170 | GUEST_ASSERT(!psci_features(PSCI_1_0_FN_SYSTEM_SUSPEND)); |
| @@ -200,7 +198,7 @@ static void host_test_system_suspend(void) · 27 unmodified lines | ||
| 200 | 198 | |
| 201 | 199 | static void guest_test_system_off2(void) |
| 202 | 200 | { |
| 203 | − uint64_t ret; | |
| 201 | + u64 ret; | |
| 204 | 202 | |
| 205 | 203 | /* assert that SYSTEM_OFF2 is discoverable */ |
| 206 | 204 | GUEST_ASSERT(psci_features(PSCI_1_3_FN_SYSTEM_OFF2) & |
| @@ -238,7 +236,7 @@ static void host_test_system_off2(void) · 31 unmodified lines | ||
| 238 | 236 | { |
| 239 | 237 | struct kvm_vcpu *source, *target; |
| 240 | 238 | struct kvm_mp_state mps; |
| 241 | − uint64_t psci_version = 0; | |
| 239 | + u64 psci_version = 0; | |
| 242 | 240 | int nr_shutdowns = 0; |
| 243 | 241 | struct kvm_run *run; |
| 244 | 242 | struct ucall uc; |
| @@ -51,18 +51,16 @@ · 50 unmodified lines | ||
| 51 | 51 | #define EINJ_OFFSET 0x01234badUL |
| 52 | 52 | #define EINJ_GVA ((START_GVA) + (EINJ_OFFSET)) |
| 53 | 53 | |
| 54 | −static vm_paddr_t einj_gpa; | |
| 54 | +static gpa_t einj_gpa; | |
| 55 | 55 | static void *einj_hva; |
| 56 | −static uint64_t einj_hpa; | |
| 56 | +static u64 einj_hpa; | |
| 57 | 57 | static bool far_invalid; |
| 58 | 58 | |
| 59 | −static uint64_t translate_to_host_paddr(unsigned long vaddr) | |
| 59 | +static u64 translate_hva_to_hpa(unsigned long hva) | |
| 60 | 60 | { |
| 61 | − uint64_t pinfo; | |
| 62 | − int64_t offset = vaddr / getpagesize() * sizeof(pinfo); | |
| 61 | + u64 pinfo; | |
| 62 | + s64 offset = hva / getpagesize() * sizeof(pinfo); | |
| 63 | 63 | int fd; |
| 64 | − uint64_t page_addr; | |
| 65 | − uint64_t paddr; | |
| 66 | 64 | |
| 67 | 65 | fd = open("/proc/self/pagemap", O_RDONLY); |
| 68 | 66 | if (fd < 0) |
| @@ -77,12 +75,11 @@ static uint64_t translate_to_host_paddr(unsigned long vaddr) · 8 unmodified lines | ||
| 77 | 75 | if ((pinfo & PAGE_PRESENT) == 0) |
| 78 | 76 | ksft_exit_fail_perror("Page not present"); |
| 79 | 77 | |
| 80 | − page_addr = (pinfo & PAGE_PHYSICAL) << MIN_PAGE_SHIFT; | |
| 81 | − paddr = page_addr + (vaddr & (getpagesize() - 1)); | |
| 82 | − return paddr; | |
| 78 | + return ((pinfo & PAGE_PHYSICAL) << MIN_PAGE_SHIFT) + | |
| 79 | + (hva & (getpagesize() - 1)); | |
| 83 | 80 | } |
| 84 | 81 | |
| 85 | −static void write_einj_entry(const char *einj_path, uint64_t val) | |
| 82 | +static void write_einj_entry(const char *einj_path, u64 val) | |
| 86 | 83 | { |
| 87 | 84 | char cmd[256] = {0}; |
| 88 | 85 | FILE *cmdfile = NULL; |
| @@ -96,7 +93,7 @@ static void write_einj_entry(const char *einj_path, uint64_t val) · 7 unmodified lines | ||
| 96 | 93 | ksft_exit_fail_perror("Failed to write EINJ entry"); |
| 97 | 94 | } |
| 98 | 95 | |
| 99 | −static void inject_uer(uint64_t paddr) | |
| 96 | +static void inject_uer(u64 hpa) | |
| 100 | 97 | { |
| 101 | 98 | if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) |
| 102 | 99 | ksft_test_result_skip("EINJ table no available in firmware"); |
| @@ -106,7 +103,7 @@ static void inject_uer(uint64_t paddr) · 3 unmodified lines | ||
| 106 | 103 | |
| 107 | 104 | write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER); |
| 108 | 105 | write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER); |
| 109 | − write_einj_entry(EINJ_ADDR, paddr); | |
| 106 | + write_einj_entry(EINJ_ADDR, hpa); | |
| 110 | 107 | write_einj_entry(EINJ_MASK, ~0x0UL); |
| 111 | 108 | write_einj_entry(EINJ_NOTRIGGER, 1); |
| 112 | 109 | write_einj_entry(EINJ_DOIT, 1); |
| @@ -145,10 +142,10 @@ static void setup_sigbus_handler(void) · 32 unmodified lines | ||
| 145 | 142 | |
| 146 | 143 | static void guest_code(void) |
| 147 | 144 | { |
| 148 | − uint64_t guest_data; | |
| 145 | + u64 guest_data; | |
| 149 | 146 | |
| 150 | 147 | /* Consumes error will cause a SEA. */ |
| 151 | − guest_data = *(uint64_t *)EINJ_GVA; | |
| 148 | + guest_data = *(u64 *)EINJ_GVA; | |
| 152 | 149 | |
| 153 | 150 | GUEST_FAIL("Poison not protected by SEA: gva=%#lx, guest_data=%#lx\n", |
| 154 | 151 | EINJ_GVA, guest_data); |
| @@ -253,8 +250,8 @@ static struct kvm_vm *vm_create_with_sea_handler(struct kvm_vcpu **vcpu) · 98 unmodified lines | ||
| 253 | 250 | size_t backing_page_size; |
| 254 | 251 | size_t guest_page_size; |
| 255 | 252 | size_t alignment; |
| 256 | − uint64_t num_guest_pages; | |
| 257 | − vm_paddr_t start_gpa; | |
| 253 | + u64 num_guest_pages; | |
| 254 | + gpa_t start_gpa; | |
| 258 | 255 | enum vm_mem_backing_src_type src_type = VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB; |
| 259 | 256 | struct kvm_vm *vm; |
| 260 | 257 | |
| @@ -278,7 +275,7 @@ static struct kvm_vm *vm_create_with_sea_handler(struct kvm_vcpu **vcpu) · 17 unmodified lines | ||
| 278 | 275 | vm_userspace_mem_region_add( |
| 279 | 276 | /*vm=*/vm, |
| 280 | 277 | /*src_type=*/src_type, |
| 281 | − /*guest_paddr=*/start_gpa, | |
| 278 | + /*gpa=*/start_gpa, | |
| 282 | 279 | /*slot=*/1, |
| 283 | 280 | /*npages=*/num_guest_pages, |
| 284 | 281 | /*flags=*/0); |
| @@ -292,18 +289,18 @@ static struct kvm_vm *vm_create_with_sea_handler(struct kvm_vcpu **vcpu) · 7 unmodified lines | ||
| 292 | 289 | |
| 293 | 290 | static void vm_inject_memory_uer(struct kvm_vm *vm) |
| 294 | 291 | { |
| 295 | − uint64_t guest_data; | |
| 292 | + u64 guest_data; | |
| 296 | 293 | |
| 297 | 294 | einj_gpa = addr_gva2gpa(vm, EINJ_GVA); |
| 298 | 295 | einj_hva = addr_gva2hva(vm, EINJ_GVA); |
| 299 | 296 | |
| 300 | 297 | /* Populate certain data before injecting UER. */ |
| 301 | − *(uint64_t *)einj_hva = 0xBAADCAFE; | |
| 302 | − guest_data = *(uint64_t *)einj_hva; | |
| 298 | + *(u64 *)einj_hva = 0xBAADCAFE; | |
| 299 | + guest_data = *(u64 *)einj_hva; | |
| 303 | 300 | ksft_print_msg("Before EINJect: data=%#lx\n", |
| 304 | 301 | guest_data); |
| 305 | 302 | |
| 306 | − einj_hpa = translate_to_host_paddr((unsigned long)einj_hva); | |
| 303 | + einj_hpa = translate_hva_to_hpa((unsigned long)einj_hva); | |
| 307 | 304 | |
| 308 | 305 | ksft_print_msg("EINJ_GVA=%#lx, einj_gpa=%#lx, einj_hva=%p, einj_hpa=%#lx\n", |
| 309 | 306 | EINJ_GVA, einj_gpa, einj_hva, einj_hpa); |
| @@ -30,20 +30,20 @@ struct reg_ftr_bits { · 29 unmodified lines | ||
| 30 | 30 | char *name; |
| 31 | 31 | bool sign; |
| 32 | 32 | enum ftr_type type; |
| 33 | − uint8_t shift; | |
| 34 | − uint64_t mask; | |
| 33 | + u8 shift; | |
| 34 | + u64 mask; | |
| 35 | 35 | /* |
| 36 | 36 | * For FTR_EXACT, safe_val is used as the exact safe value. |
| 37 | 37 | * For FTR_LOWER_SAFE, safe_val is used as the minimal safe value. |
| 38 | 38 | */ |
| 39 | − int64_t safe_val; | |
| 39 | + s64 safe_val; | |
| 40 | 40 | |
| 41 | 41 | /* Allowed to be changed by the host after run */ |
| 42 | 42 | bool mutable; |
| 43 | 43 | }; |
| 44 | 44 | |
| 45 | 45 | struct test_feature_reg { |
| 46 | − uint32_t reg; | |
| 46 | + u32 reg; | |
| 47 | 47 | const struct reg_ftr_bits *ftr_bits; |
| 48 | 48 | }; |
| 49 | 49 | |
| @@ -275,9 +275,9 @@ static void guest_code(void) · 225 unmodified lines | ||
| 275 | 275 | } |
| 276 | 276 | |
| 277 | 277 | /* Return a safe value to a given ftr_bits an ftr value */ |
| 278 | −uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) | |
| 278 | +u64 get_safe_value(const struct reg_ftr_bits *ftr_bits, u64 ftr) | |
| 279 | 279 | { |
| 280 | − uint64_t ftr_max = ftr_bits->mask >> ftr_bits->shift; | |
| 280 | + u64 ftr_max = ftr_bits->mask >> ftr_bits->shift; | |
| 281 | 281 | |
| 282 | 282 | TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features"); |
| 283 | 283 | |
| @@ -329,16 +329,16 @@ uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) · 45 unmodified lines | ||
| 329 | 329 | } |
| 330 | 330 | |
| 331 | 331 | /* Return an invalid value to a given ftr_bits an ftr value */ |
| 332 | −uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) | |
| 332 | +u64 get_invalid_value(const struct reg_ftr_bits *ftr_bits, u64 ftr) | |
| 333 | 333 | { |
| 334 | − uint64_t ftr_max = ftr_bits->mask >> ftr_bits->shift; | |
| 334 | + u64 ftr_max = ftr_bits->mask >> ftr_bits->shift; | |
| 335 | 335 | |
| 336 | 336 | TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features"); |
| 337 | 337 | |
| 338 | 338 | if (ftr_bits->sign == FTR_UNSIGNED) { |
| 339 | 339 | switch (ftr_bits->type) { |
| 340 | 340 | case FTR_EXACT: |
| 341 | − ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1); | |
| 341 | + ftr = max((u64)ftr_bits->safe_val + 1, ftr + 1); | |
| 342 | 342 | break; |
| 343 | 343 | case FTR_LOWER_SAFE: |
| 344 | 344 | ftr++; |
| @@ -358,7 +358,7 @@ uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) · 13 unmodified lines | ||
| 358 | 358 | } else if (ftr != ftr_max) { |
| 359 | 359 | switch (ftr_bits->type) { |
| 360 | 360 | case FTR_EXACT: |
| 361 | − ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1); | |
| 361 | + ftr = max((u64)ftr_bits->safe_val + 1, ftr + 1); | |
| 362 | 362 | break; |
| 363 | 363 | case FTR_LOWER_SAFE: |
| 364 | 364 | ftr++; |
| @@ -382,12 +382,12 @@ uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr) · 17 unmodified lines | ||
| 382 | 382 | return ftr; |
| 383 | 383 | } |
| 384 | 384 | |
| 385 | −static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg, | |
| 386 | − const struct reg_ftr_bits *ftr_bits) | |
| 385 | +static u64 test_reg_set_success(struct kvm_vcpu *vcpu, u64 reg, | |
| 386 | + const struct reg_ftr_bits *ftr_bits) | |
| 387 | 387 | { |
| 388 | − uint8_t shift = ftr_bits->shift; | |
| 389 | − uint64_t mask = ftr_bits->mask; | |
| 390 | − uint64_t val, new_val, ftr; | |
| 388 | + u8 shift = ftr_bits->shift; | |
| 389 | + u64 mask = ftr_bits->mask; | |
| 390 | + u64 val, new_val, ftr; | |
| 391 | 391 | |
| 392 | 392 | val = vcpu_get_reg(vcpu, reg); |
| 393 | 393 | ftr = (val & mask) >> shift; |
| @@ -405,12 +405,12 @@ static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg, · 11 unmodified lines | ||
| 405 | 405 | return new_val; |
| 406 | 406 | } |
| 407 | 407 | |
| 408 | −static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg, | |
| 408 | +static void test_reg_set_fail(struct kvm_vcpu *vcpu, u64 reg, | |
| 409 | 409 | const struct reg_ftr_bits *ftr_bits) |
| 410 | 410 | { |
| 411 | − uint8_t shift = ftr_bits->shift; | |
| 412 | − uint64_t mask = ftr_bits->mask; | |
| 413 | − uint64_t val, old_val, ftr; | |
| 411 | + u8 shift = ftr_bits->shift; | |
| 412 | + u64 mask = ftr_bits->mask; | |
| 413 | + u64 val, old_val, ftr; | |
| 414 | 414 | int r; |
| 415 | 415 | |
| 416 | 416 | val = vcpu_get_reg(vcpu, reg); |
| @@ -431,7 +431,7 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg, · 14 unmodified lines | ||
| 431 | 431 | TEST_ASSERT_EQ(val, old_val); |
| 432 | 432 | } |
| 433 | 433 | |
| 434 | −static uint64_t test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 434 | +static u64 test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 435 | 435 | |
| 436 | 436 | #define encoding_to_range_idx(encoding) \ |
| 437 | 437 | KVM_ARM_FEATURE_ID_RANGE_IDX(sys_reg_Op0(encoding), sys_reg_Op1(encoding), \ |
| @@ -441,7 +441,7 @@ static uint64_t test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE]; · 3 unmodified lines | ||
| 441 | 441 | |
| 442 | 442 | static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only) |
| 443 | 443 | { |
| 444 | − uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 444 | + u64 masks[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 445 | 445 | struct reg_mask_range range = { |
| 446 | 446 | .addr = (__u64)masks, |
| 447 | 447 | }; |
| @@ -458,8 +458,8 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only) · 10 unmodified lines | ||
| 458 | 458 | |
| 459 | 459 | for (int i = 0; i < ARRAY_SIZE(test_regs); i++) { |
| 460 | 460 | const struct reg_ftr_bits *ftr_bits = test_regs[i].ftr_bits; |
| 461 | − uint32_t reg_id = test_regs[i].reg; | |
| 462 | − uint64_t reg = KVM_ARM64_SYS_REG(reg_id); | |
| 461 | + u32 reg_id = test_regs[i].reg; | |
| 462 | + u64 reg = KVM_ARM64_SYS_REG(reg_id); | |
| 463 | 463 | int idx; |
| 464 | 464 | |
| 465 | 465 | /* Get the index to masks array for the idreg */ |
| @@ -489,11 +489,11 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only) · 23 unmodified lines | ||
| 489 | 489 | #define MPAM_IDREG_TEST 6 |
| 490 | 490 | static void test_user_set_mpam_reg(struct kvm_vcpu *vcpu) |
| 491 | 491 | { |
| 492 | − uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 492 | + u64 masks[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 493 | 493 | struct reg_mask_range range = { |
| 494 | 494 | .addr = (__u64)masks, |
| 495 | 495 | }; |
| 496 | − uint64_t val; | |
| 496 | + u64 val; | |
| 497 | 497 | int idx, err; |
| 498 | 498 | |
| 499 | 499 | /* |
| @@ -584,13 +584,13 @@ static void test_user_set_mpam_reg(struct kvm_vcpu *vcpu) · 84 unmodified lines | ||
| 584 | 584 | #define MTE_IDREG_TEST 1 |
| 585 | 585 | static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) |
| 586 | 586 | { |
| 587 | − uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 587 | + u64 masks[KVM_ARM_FEATURE_ID_RANGE_SIZE]; | |
| 588 | 588 | struct reg_mask_range range = { |
| 589 | 589 | .addr = (__u64)masks, |
| 590 | 590 | }; |
| 591 | − uint64_t val; | |
| 592 | − uint64_t mte; | |
| 593 | − uint64_t mte_frac; | |
| 591 | + u64 val; | |
| 592 | + u64 mte; | |
| 593 | + u64 mte_frac; | |
| 594 | 594 | int idx, err; |
| 595 | 595 | |
| 596 | 596 | val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1)); |
| @@ -644,7 +644,7 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) · 47 unmodified lines | ||
| 644 | 644 | ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n"); |
| 645 | 645 | } |
| 646 | 646 | |
| 647 | −static uint64_t reset_mutable_bits(uint32_t id, uint64_t val) | |
| 647 | +static u64 reset_mutable_bits(u32 id, u64 val) | |
| 648 | 648 | { |
| 649 | 649 | struct test_feature_reg *reg = NULL; |
| 650 | 650 | |
| @@ -674,7 +674,7 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu) · 23 unmodified lines | ||
| 674 | 674 | struct ucall uc; |
| 675 | 675 | |
| 676 | 676 | while (!done) { |
| 677 | − uint64_t val; | |
| 677 | + u64 val; | |
| 678 | 678 | |
| 679 | 679 | vcpu_run(vcpu); |
| 680 | 680 | |
| @@ -707,7 +707,7 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu) · 26 unmodified lines | ||
| 707 | 707 | |
| 708 | 708 | static void test_clidr(struct kvm_vcpu *vcpu) |
| 709 | 709 | { |
| 710 | − uint64_t clidr; | |
| 710 | + u64 clidr; | |
| 711 | 711 | int level; |
| 712 | 712 | |
| 713 | 713 | clidr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CLIDR_EL1)); |
| @@ -772,10 +772,10 @@ static void test_vcpu_non_ftr_id_regs(struct kvm_vcpu *vcpu) · 58 unmodified lines | ||
| 772 | 772 | ksft_test_result_pass("%s\n", __func__); |
| 773 | 773 | } |
| 774 | 774 | |
| 775 | −static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encoding) | |
| 775 | +static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, u32 encoding) | |
| 776 | 776 | { |
| 777 | 777 | size_t idx = encoding_to_range_idx(encoding); |
| 778 | − uint64_t observed; | |
| 778 | + u64 observed; | |
| 779 | 779 | |
| 780 | 780 | observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding)); |
| 781 | 781 | TEST_ASSERT_EQ(reset_mutable_bits(encoding, test_reg_vals[idx]), |
| @@ -808,7 +808,7 @@ int main(void) · 26 unmodified lines | ||
| 808 | 808 | struct kvm_vcpu *vcpu; |
| 809 | 809 | struct kvm_vm *vm; |
| 810 | 810 | bool aarch64_only; |
| 811 | − uint64_t val, el0; | |
| 811 | + u64 val, el0; | |
| 812 | 812 | int test_cnt, i, j; |
| 813 | 813 | |
| 814 | 814 | TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES)); |
| @@ -37,7 +37,7 @@ static bool test_runs_at_el2(void) · 36 unmodified lines | ||
| 37 | 37 | for (conduit = test_runs_at_el2() ? SMC_INSN : HVC_INSN; \ |
| 38 | 38 | conduit <= SMC_INSN; conduit++) |
| 39 | 39 | |
| 40 | −static void guest_main(uint32_t func_id, enum smccc_conduit conduit) | |
| 40 | +static void guest_main(u32 func_id, enum smccc_conduit conduit) | |
| 41 | 41 | { |
| 42 | 42 | struct arm_smccc_res res; |
| 43 | 43 | |
| @@ -49,7 +49,7 @@ static void guest_main(uint32_t func_id, enum smccc_conduit conduit) · 5 unmodified lines | ||
| 49 | 49 | GUEST_SYNC(res.a0); |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | −static int __set_smccc_filter(struct kvm_vm *vm, uint32_t start, uint32_t nr_functions, | |
| 52 | +static int __set_smccc_filter(struct kvm_vm *vm, u32 start, u32 nr_functions, | |
| 53 | 53 | enum kvm_smccc_filter_action action) |
| 54 | 54 | { |
| 55 | 55 | struct kvm_smccc_filter filter = { |
| @@ -62,7 +62,7 @@ static int __set_smccc_filter(struct kvm_vm *vm, uint32_t start, uint32_t nr_fun · 6 unmodified lines | ||
| 62 | 62 | KVM_ARM_VM_SMCCC_FILTER, &filter); |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | −static void set_smccc_filter(struct kvm_vm *vm, uint32_t start, uint32_t nr_functions, | |
| 65 | +static void set_smccc_filter(struct kvm_vm *vm, u32 start, u32 nr_functions, | |
| 66 | 66 | enum kvm_smccc_filter_action action) |
| 67 | 67 | { |
| 68 | 68 | int ret = __set_smccc_filter(vm, start, nr_functions, action); |
| @@ -112,7 +112,7 @@ static void test_filter_reserved_range(void) · 43 unmodified lines | ||
| 112 | 112 | { |
| 113 | 113 | struct kvm_vcpu *vcpu; |
| 114 | 114 | struct kvm_vm *vm = setup_vm(&vcpu); |
| 115 | − uint32_t smc64_fn; | |
| 115 | + u32 smc64_fn; | |
| 116 | 116 | int r; |
| 117 | 117 | |
| 118 | 118 | r = __set_smccc_filter(vm, ARM_SMCCC_ARCH_WORKAROUND_1, |
| @@ -217,7 +217,7 @@ static void test_filter_denied(void) · 98 unmodified lines | ||
| 217 | 217 | } |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | −static void expect_call_fwd_to_user(struct kvm_vcpu *vcpu, uint32_t func_id, | |
| 220 | +static void expect_call_fwd_to_user(struct kvm_vcpu *vcpu, u32 func_id, | |
| 221 | 221 | enum smccc_conduit conduit) |
| 222 | 222 | { |
| 223 | 223 | struct kvm_run *run = vcpu->run; |
| @@ -19,7 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | #define NR_VCPUS 4 |
| 21 | 21 | |
| 22 | −#define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset) | |
| 22 | +#define REG_OFFSET(vcpu, offset) (((u64)vcpu << 32) | offset) | |
| 23 | 23 | |
| 24 | 24 | #define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2) |
| 25 | 25 | #define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3) |
| @@ -27,10 +27,10 @@ · 1 unmodified line | ||
| 27 | 27 | struct vm_gic { |
| 28 | 28 | struct kvm_vm *vm; |
| 29 | 29 | int gic_fd; |
| 30 | − uint32_t gic_dev_type; | |
| 30 | + u32 gic_dev_type; | |
| 31 | 31 | }; |
| 32 | 32 | |
| 33 | −static uint64_t max_phys_size; | |
| 33 | +static u64 max_phys_size; | |
| 34 | 34 | |
| 35 | 35 | /* |
| 36 | 36 | * Helpers to access a redistributor register and verify the ioctl() failed or |
| @@ -39,17 +39,17 @@ static uint64_t max_phys_size; · 2 unmodified lines | ||
| 39 | 39 | static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset, |
| 40 | 40 | int want, const char *msg) |
| 41 | 41 | { |
| 42 | − uint32_t ignored_val; | |
| 42 | + u32 ignored_val; | |
| 43 | 43 | int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, |
| 44 | 44 | REG_OFFSET(vcpu, offset), &ignored_val); |
| 45 | 45 | |
| 46 | 46 | TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want); |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | −static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want, | |
| 49 | +static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, u32 want, | |
| 50 | 50 | const char *msg) |
| 51 | 51 | { |
| 52 | − uint32_t val; | |
| 52 | + u32 val; | |
| 53 | 53 | |
| 54 | 54 | kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, |
| 55 | 55 | REG_OFFSET(vcpu, offset), &val); |
| @@ -71,8 +71,8 @@ static int run_vcpu(struct kvm_vcpu *vcpu) · 15 unmodified lines | ||
| 71 | 71 | return __vcpu_run(vcpu) ? -errno : 0; |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | −static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, | |
| 75 | − uint32_t nr_vcpus, | |
| 74 | +static struct vm_gic vm_gic_create_with_vcpus(u32 gic_dev_type, | |
| 75 | + u32 nr_vcpus, | |
| 76 | 76 | struct kvm_vcpu *vcpus[]) |
| 77 | 77 | { |
| 78 | 78 | struct vm_gic v; |
| @@ -84,7 +84,7 @@ static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, · 5 unmodified lines | ||
| 84 | 84 | return v; |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | −static struct vm_gic vm_gic_create_barebones(uint32_t gic_dev_type) | |
| 87 | +static struct vm_gic vm_gic_create_barebones(u32 gic_dev_type) | |
| 88 | 88 | { |
| 89 | 89 | struct vm_gic v; |
| 90 | 90 | |
| @@ -103,9 +103,9 @@ static void vm_gic_destroy(struct vm_gic *v) · 12 unmodified lines | ||
| 103 | 103 | } |
| 104 | 104 | |
| 105 | 105 | struct vgic_region_attr { |
| 106 | − uint64_t attr; | |
| 107 | − uint64_t size; | |
| 108 | − uint64_t alignment; | |
| 106 | + u64 attr; | |
| 107 | + u64 size; | |
| 108 | + u64 alignment; | |
| 109 | 109 | }; |
| 110 | 110 | |
| 111 | 111 | struct vgic_region_attr gic_v3_dist_region = { |
| @@ -143,7 +143,7 @@ struct vgic_region_attr gic_v2_cpu_region = { · 31 unmodified lines | ||
| 143 | 143 | static void subtest_dist_rdist(struct vm_gic *v) |
| 144 | 144 | { |
| 145 | 145 | int ret; |
| 146 | − uint64_t addr; | |
| 146 | + u64 addr; | |
| 147 | 147 | struct vgic_region_attr rdist; /* CPU interface in GICv2*/ |
| 148 | 148 | struct vgic_region_attr dist; |
| 149 | 149 | |
| @@ -223,7 +223,7 @@ static void subtest_dist_rdist(struct vm_gic *v) · 73 unmodified lines | ||
| 223 | 223 | /* Test the new REDIST region API */ |
| 224 | 224 | static void subtest_v3_redist_regions(struct vm_gic *v) |
| 225 | 225 | { |
| 226 | − uint64_t addr, expected_addr; | |
| 226 | + u64 addr, expected_addr; | |
| 227 | 227 | int ret; |
| 228 | 228 | |
| 229 | 229 | ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, |
| @@ -332,7 +332,7 @@ static void subtest_v3_redist_regions(struct vm_gic *v) · 102 unmodified lines | ||
| 332 | 332 | * VGIC KVM device is created and initialized before the secondary CPUs |
| 333 | 333 | * get created |
| 334 | 334 | */ |
| 335 | −static void test_vgic_then_vcpus(uint32_t gic_dev_type) | |
| 335 | +static void test_vgic_then_vcpus(u32 gic_dev_type) | |
| 336 | 336 | { |
| 337 | 337 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 338 | 338 | struct vm_gic v; |
| @@ -353,7 +353,7 @@ static void test_vgic_then_vcpus(uint32_t gic_dev_type) · 14 unmodified lines | ||
| 353 | 353 | } |
| 354 | 354 | |
| 355 | 355 | /* All the VCPUs are created before the VGIC KVM device gets initialized */ |
| 356 | −static void test_vcpus_then_vgic(uint32_t gic_dev_type) | |
| 356 | +static void test_vcpus_then_vgic(u32 gic_dev_type) | |
| 357 | 357 | { |
| 358 | 358 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 359 | 359 | struct vm_gic v; |
| @@ -408,7 +408,7 @@ static void test_v3_new_redist_regions(void) · 48 unmodified lines | ||
| 408 | 408 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 409 | 409 | void *dummy = NULL; |
| 410 | 410 | struct vm_gic v; |
| 411 | − uint64_t addr; | |
| 411 | + u64 addr; | |
| 412 | 412 | int ret; |
| 413 | 413 | |
| 414 | 414 | v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); |
| @@ -460,7 +460,7 @@ static void test_v3_new_redist_regions(void) · 45 unmodified lines | ||
| 460 | 460 | static void test_v3_typer_accesses(void) |
| 461 | 461 | { |
| 462 | 462 | struct vm_gic v; |
| 463 | − uint64_t addr; | |
| 463 | + u64 addr; | |
| 464 | 464 | int ret, i; |
| 465 | 465 | |
| 466 | 466 | v.vm = vm_create(NR_VCPUS); |
| @@ -518,7 +518,7 @@ static void test_v3_typer_accesses(void) · 51 unmodified lines | ||
| 518 | 518 | } |
| 519 | 519 | |
| 520 | 520 | static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus, |
| 521 | − uint32_t vcpuids[]) | |
| 521 | + u32 vcpuids[]) | |
| 522 | 522 | { |
| 523 | 523 | struct vm_gic v; |
| 524 | 524 | int i; |
| @@ -544,9 +544,9 @@ static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus, · 19 unmodified lines | ||
| 544 | 544 | */ |
| 545 | 545 | static void test_v3_last_bit_redist_regions(void) |
| 546 | 546 | { |
| 547 | − uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 }; | |
| 547 | + u32 vcpuids[] = { 0, 3, 5, 4, 1, 2 }; | |
| 548 | 548 | struct vm_gic v; |
| 549 | − uint64_t addr; | |
| 549 | + u64 addr; | |
| 550 | 550 | |
| 551 | 551 | v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids); |
| 552 | 552 | |
| @@ -578,9 +578,9 @@ static void test_v3_last_bit_redist_regions(void) · 25 unmodified lines | ||
| 578 | 578 | /* Test last bit with legacy region */ |
| 579 | 579 | static void test_v3_last_bit_single_rdist(void) |
| 580 | 580 | { |
| 581 | − uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 }; | |
| 581 | + u32 vcpuids[] = { 0, 3, 5, 4, 1, 2 }; | |
| 582 | 582 | struct vm_gic v; |
| 583 | − uint64_t addr; | |
| 583 | + u64 addr; | |
| 584 | 584 | |
| 585 | 585 | v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids); |
| 586 | 586 | |
| @@ -606,7 +606,7 @@ static void test_v3_redist_ipa_range_check_at_vcpu_run(void) · 19 unmodified lines | ||
| 606 | 606 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 607 | 607 | struct vm_gic v; |
| 608 | 608 | int ret, i; |
| 609 | − uint64_t addr; | |
| 609 | + u64 addr; | |
| 610 | 610 | |
| 611 | 611 | v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus); |
| 612 | 612 | |
| @@ -638,7 +638,7 @@ static void test_v3_its_region(void) · 25 unmodified lines | ||
| 638 | 638 | { |
| 639 | 639 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 640 | 640 | struct vm_gic v; |
| 641 | − uint64_t addr; | |
| 641 | + u64 addr; | |
| 642 | 642 | int its_fd, ret; |
| 643 | 643 | |
| 644 | 644 | v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); |
| @@ -717,11 +717,11 @@ static void test_v3_nassgicap(void) · 72 unmodified lines | ||
| 717 | 717 | /* |
| 718 | 718 | * Returns 0 if it's possible to create GIC device of a given type (V2 or V3). |
| 719 | 719 | */ |
| 720 | −int test_kvm_device(uint32_t gic_dev_type) | |
| 720 | +int test_kvm_device(u32 gic_dev_type) | |
| 721 | 721 | { |
| 722 | 722 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 723 | 723 | struct vm_gic v; |
| 724 | − uint32_t other; | |
| 724 | + u32 other; | |
| 725 | 725 | int ret; |
| 726 | 726 | |
| 727 | 727 | v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus); |
| @@ -968,7 +968,7 @@ static void test_v3_sysregs(void) · 240 unmodified lines | ||
| 968 | 968 | kvm_vm_free(vm); |
| 969 | 969 | } |
| 970 | 970 | |
| 971 | −void run_tests(uint32_t gic_dev_type) | |
| 971 | +void run_tests(u32 gic_dev_type) | |
| 972 | 972 | { |
| 973 | 973 | test_vcpus_then_vgic(gic_dev_type); |
| 974 | 974 | test_vgic_then_vcpus(gic_dev_type); |
| @@ -24,12 +24,12 @@ · 23 unmodified lines | ||
| 24 | 24 | * function. |
| 25 | 25 | */ |
| 26 | 26 | struct test_args { |
| 27 | − uint32_t nr_irqs; /* number of KVM supported IRQs. */ | |
| 27 | + u32 nr_irqs; /* number of KVM supported IRQs. */ | |
| 28 | 28 | bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */ |
| 29 | 29 | bool level_sensitive; /* 1 is level, 0 is edge */ |
| 30 | 30 | int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */ |
| 31 | 31 | bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */ |
| 32 | − uint32_t shared_data; | |
| 32 | + u32 shared_data; | |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | 35 | /* |
| @@ -64,15 +64,15 @@ typedef enum { · 28 unmodified lines | ||
| 64 | 64 | |
| 65 | 65 | struct kvm_inject_args { |
| 66 | 66 | kvm_inject_cmd cmd; |
| 67 | − uint32_t first_intid; | |
| 68 | − uint32_t num; | |
| 67 | + u32 first_intid; | |
| 68 | + u32 num; | |
| 69 | 69 | int level; |
| 70 | 70 | bool expect_failure; |
| 71 | 71 | }; |
| 72 | 72 | |
| 73 | 73 | /* Used on the guest side to perform the hypercall. */ |
| 74 | −static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, | |
| 75 | − uint32_t num, int level, bool expect_failure); | |
| 74 | +static void kvm_inject_call(kvm_inject_cmd cmd, u32 first_intid, | |
| 75 | + u32 num, int level, bool expect_failure); | |
| 76 | 76 | |
| 77 | 77 | /* Used on the host side to get the hypercall info. */ |
| 78 | 78 | static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc, |
| @@ -133,8 +133,8 @@ static struct kvm_inject_desc set_active_fns[] = { · 54 unmodified lines | ||
| 133 | 133 | for_each_supported_inject_fn((args), (t), (f)) |
| 134 | 134 | |
| 135 | 135 | /* Shared between the guest main thread and the IRQ handlers. */ |
| 136 | −volatile uint64_t irq_handled; | |
| 137 | −volatile uint32_t irqnr_received[MAX_SPI + 1]; | |
| 136 | +volatile u64 irq_handled; | |
| 137 | +volatile u32 irqnr_received[MAX_SPI + 1]; | |
| 138 | 138 | |
| 139 | 139 | static void reset_stats(void) |
| 140 | 140 | { |
| @@ -145,25 +145,25 @@ static void reset_stats(void) · 4 unmodified lines | ||
| 145 | 145 | irqnr_received[i] = 0; |
| 146 | 146 | } |
| 147 | 147 | |
| 148 | −static uint64_t gic_read_ap1r0(void) | |
| 148 | +static u64 gic_read_ap1r0(void) | |
| 149 | 149 | { |
| 150 | − uint64_t reg = read_sysreg_s(SYS_ICC_AP1R0_EL1); | |
| 150 | + u64 reg = read_sysreg_s(SYS_ICC_AP1R0_EL1); | |
| 151 | 151 | |
| 152 | 152 | dsb(sy); |
| 153 | 153 | return reg; |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | −static void gic_write_ap1r0(uint64_t val) | |
| 156 | +static void gic_write_ap1r0(u64 val) | |
| 157 | 157 | { |
| 158 | 158 | write_sysreg_s(val, SYS_ICC_AP1R0_EL1); |
| 159 | 159 | isb(); |
| 160 | 160 | } |
| 161 | 161 | |
| 162 | −static void guest_set_irq_line(uint32_t intid, uint32_t level); | |
| 162 | +static void guest_set_irq_line(u32 intid, u32 level); | |
| 163 | 163 | |
| 164 | 164 | static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive) |
| 165 | 165 | { |
| 166 | − uint32_t intid = gic_get_and_ack_irq(); | |
| 166 | + u32 intid = gic_get_and_ack_irq(); | |
| 167 | 167 | |
| 168 | 168 | if (intid == IAR_SPURIOUS) |
| 169 | 169 | return; |
| @@ -189,8 +189,8 @@ static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive) · 19 unmodified lines | ||
| 189 | 189 | GUEST_ASSERT(!gic_irq_get_pending(intid)); |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | −static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, | |
| 193 | − uint32_t num, int level, bool expect_failure) | |
| 192 | +static void kvm_inject_call(kvm_inject_cmd cmd, u32 first_intid, | |
| 193 | + u32 num, int level, bool expect_failure) | |
| 194 | 194 | { |
| 195 | 195 | struct kvm_inject_args args = { |
| 196 | 196 | .cmd = cmd, |
| @@ -204,7 +204,7 @@ static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, · 7 unmodified lines | ||
| 204 | 204 | |
| 205 | 205 | #define GUEST_ASSERT_IAR_EMPTY() \ |
| 206 | 206 | do { \ |
| 207 | − uint32_t _intid; \ | |
| 207 | + u32 _intid; \ | |
| 208 | 208 | _intid = gic_get_and_ack_irq(); \ |
| 209 | 209 | GUEST_ASSERT(_intid == IAR_SPURIOUS); \ |
| 210 | 210 | } while (0) |
| @@ -237,13 +237,13 @@ static void reset_priorities(struct test_args *args) · 26 unmodified lines | ||
| 237 | 237 | gic_set_priority(i, IRQ_DEFAULT_PRIO_REG); |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | −static void guest_set_irq_line(uint32_t intid, uint32_t level) | |
| 240 | +static void guest_set_irq_line(u32 intid, u32 level) | |
| 241 | 241 | { |
| 242 | 242 | kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false); |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | 245 | static void test_inject_fail(struct test_args *args, |
| 246 | − uint32_t intid, kvm_inject_cmd cmd) | |
| 246 | + u32 intid, kvm_inject_cmd cmd) | |
| 247 | 247 | { |
| 248 | 248 | reset_stats(); |
| 249 | 249 | |
| @@ -255,10 +255,10 @@ static void test_inject_fail(struct test_args *args, · 5 unmodified lines | ||
| 255 | 255 | } |
| 256 | 256 | |
| 257 | 257 | static void guest_inject(struct test_args *args, |
| 258 | − uint32_t first_intid, uint32_t num, | |
| 259 | − kvm_inject_cmd cmd) | |
| 258 | + u32 first_intid, u32 num, | |
| 259 | + kvm_inject_cmd cmd) | |
| 260 | 260 | { |
| 261 | − uint32_t i; | |
| 261 | + u32 i; | |
| 262 | 262 | |
| 263 | 263 | reset_stats(); |
| 264 | 264 | |
| @@ -292,10 +292,10 @@ static void guest_inject(struct test_args *args, · 27 unmodified lines | ||
| 292 | 292 | * deactivated yet. |
| 293 | 293 | */ |
| 294 | 294 | static void guest_restore_active(struct test_args *args, |
| 295 | − uint32_t first_intid, uint32_t num, | |
| 296 | − kvm_inject_cmd cmd) | |
| 295 | + u32 first_intid, u32 num, | |
| 296 | + kvm_inject_cmd cmd) | |
| 297 | 297 | { |
| 298 | − uint32_t prio, intid, ap1r; | |
| 298 | + u32 prio, intid, ap1r; | |
| 299 | 299 | int i; |
| 300 | 300 | |
| 301 | 301 | /* |
| @@ -342,9 +342,9 @@ static void guest_restore_active(struct test_args *args, · 40 unmodified lines | ||
| 342 | 342 | * This function should only be used in test_inject_preemption (with IRQs |
| 343 | 343 | * masked). |
| 344 | 344 | */ |
| 345 | −static uint32_t wait_for_and_activate_irq(void) | |
| 345 | +static u32 wait_for_and_activate_irq(void) | |
| 346 | 346 | { |
| 347 | − uint32_t intid; | |
| 347 | + u32 intid; | |
| 348 | 348 | |
| 349 | 349 | do { |
| 350 | 350 | asm volatile("wfi" : : : "memory"); |
| @@ -360,11 +360,11 @@ static uint32_t wait_for_and_activate_irq(void) · 9 unmodified lines | ||
| 360 | 360 | * interrupts for the whole test. |
| 361 | 361 | */ |
| 362 | 362 | static void test_inject_preemption(struct test_args *args, |
| 363 | − uint32_t first_intid, int num, | |
| 363 | + u32 first_intid, int num, | |
| 364 | 364 | const unsigned long *exclude, |
| 365 | 365 | kvm_inject_cmd cmd) |
| 366 | 366 | { |
| 367 | − uint32_t intid, prio, step = KVM_PRIO_STEPS; | |
| 367 | + u32 intid, prio, step = KVM_PRIO_STEPS; | |
| 368 | 368 | int i; |
| 369 | 369 | |
| 370 | 370 | /* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs |
| @@ -379,7 +379,7 @@ static void test_inject_preemption(struct test_args *args, · 8 unmodified lines | ||
| 379 | 379 | local_irq_disable(); |
| 380 | 380 | |
| 381 | 381 | for (i = 0; i < num; i++) { |
| 382 | − uint32_t tmp; | |
| 382 | + u32 tmp; | |
| 383 | 383 | intid = i + first_intid; |
| 384 | 384 | |
| 385 | 385 | if (exclude && test_bit(i, exclude)) |
| @@ -431,7 +431,7 @@ static void test_inject_preemption(struct test_args *args, · 45 unmodified lines | ||
| 431 | 431 | |
| 432 | 432 | static void test_injection(struct test_args *args, struct kvm_inject_desc *f) |
| 433 | 433 | { |
| 434 | − uint32_t nr_irqs = args->nr_irqs; | |
| 434 | + u32 nr_irqs = args->nr_irqs; | |
| 435 | 435 | |
| 436 | 436 | if (f->sgi) { |
| 437 | 437 | guest_inject(args, MIN_SGI, 1, f->cmd); |
| @@ -451,7 +451,7 @@ static void test_injection(struct test_args *args, struct kvm_inject_desc *f) · 13 unmodified lines | ||
| 451 | 451 | static void test_injection_failure(struct test_args *args, |
| 452 | 452 | struct kvm_inject_desc *f) |
| 453 | 453 | { |
| 454 | − uint32_t bad_intid[] = { args->nr_irqs, 1020, 1024, 1120, 5120, ~0U, }; | |
| 454 | + u32 bad_intid[] = { args->nr_irqs, 1020, 1024, 1120, 5120, ~0U, }; | |
| 455 | 455 | int i; |
| 456 | 456 | |
| 457 | 457 | for (i = 0; i < ARRAY_SIZE(bad_intid); i++) |
| @@ -490,7 +490,7 @@ static void test_restore_active(struct test_args *args, struct kvm_inject_desc * · 32 unmodified lines | ||
| 490 | 490 | |
| 491 | 491 | static void guest_code(struct test_args *args) |
| 492 | 492 | { |
| 493 | − uint32_t i, nr_irqs = args->nr_irqs; | |
| 493 | + u32 i, nr_irqs = args->nr_irqs; | |
| 494 | 494 | bool level_sensitive = args->level_sensitive; |
| 495 | 495 | struct kvm_inject_desc *f, *inject_fns; |
| 496 | 496 | |
| @@ -529,8 +529,8 @@ static void guest_code(struct test_args *args) · 32 unmodified lines | ||
| 529 | 529 | GUEST_DONE(); |
| 530 | 530 | } |
| 531 | 531 | |
| 532 | −static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level, | |
| 533 | − struct test_args *test_args, bool expect_failure) | |
| 532 | +static void kvm_irq_line_check(struct kvm_vm *vm, u32 intid, int level, | |
| 533 | + struct test_args *test_args, bool expect_failure) | |
| 534 | 534 | { |
| 535 | 535 | int ret; |
| 536 | 536 | |
| @@ -548,8 +548,8 @@ static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level, · 11 unmodified lines | ||
| 548 | 548 | } |
| 549 | 549 | } |
| 550 | 550 | |
| 551 | −void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level, | |
| 552 | − bool expect_failure) | |
| 551 | +void kvm_irq_set_level_info_check(int gic_fd, u32 intid, int level, | |
| 552 | + bool expect_failure) | |
| 553 | 553 | { |
| 554 | 554 | if (!expect_failure) { |
| 555 | 555 | kvm_irq_set_level_info(gic_fd, intid, level); |
| @@ -573,17 +573,18 @@ void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level, · 17 unmodified lines | ||
| 573 | 573 | } |
| 574 | 574 | |
| 575 | 575 | static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm, |
| 576 | − uint32_t intid, uint32_t num, uint32_t kvm_max_routes, | |
| 577 | − bool expect_failure) | |
| 576 | + u32 intid, u32 num, | |
| 577 | + u32 kvm_max_routes, | |
| 578 | + bool expect_failure) | |
| 578 | 579 | { |
| 579 | 580 | struct kvm_irq_routing *routing; |
| 580 | 581 | int ret; |
| 581 | − uint64_t i; | |
| 582 | + u64 i; | |
| 582 | 583 | |
| 583 | 584 | assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES); |
| 584 | 585 | |
| 585 | 586 | routing = kvm_gsi_routing_create(); |
| 586 | − for (i = intid; i < (uint64_t)intid + num; i++) | |
| 587 | + for (i = intid; i < (u64)intid + num; i++) | |
| 587 | 588 | kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI); |
| 588 | 589 | |
| 589 | 590 | if (!expect_failure) { |
| @@ -591,7 +592,7 @@ static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm, · 1 unmodified line | ||
| 591 | 592 | } else { |
| 592 | 593 | ret = _kvm_gsi_routing_write(vm, routing); |
| 593 | 594 | /* The kernel only checks e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS */ |
| 594 | − if (((uint64_t)intid + num - 1 - MIN_SPI) >= KVM_IRQCHIP_NUM_PINS) | |
| 595 | + if (((u64)intid + num - 1 - MIN_SPI) >= KVM_IRQCHIP_NUM_PINS) | |
| 595 | 596 | TEST_ASSERT(ret != 0 && errno == EINVAL, |
| 596 | 597 | "Bad intid %u did not cause KVM_SET_GSI_ROUTING " |
| 597 | 598 | "error: rc: %i errno: %i", intid, ret, errno); |
| @@ -602,7 +603,7 @@ static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm, · 4 unmodified lines | ||
| 602 | 603 | } |
| 603 | 604 | } |
| 604 | 605 | |
| 605 | −static void kvm_irq_write_ispendr_check(int gic_fd, uint32_t intid, | |
| 606 | +static void kvm_irq_write_ispendr_check(int gic_fd, u32 intid, | |
| 606 | 607 | struct kvm_vcpu *vcpu, |
| 607 | 608 | bool expect_failure) |
| 608 | 609 | { |
| @@ -618,13 +619,13 @@ static void kvm_irq_write_ispendr_check(int gic_fd, uint32_t intid, · 9 unmodified lines | ||
| 618 | 619 | } |
| 619 | 620 | |
| 620 | 621 | static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, |
| 621 | − uint32_t intid, uint32_t num, uint32_t kvm_max_routes, | |
| 622 | − bool expect_failure) | |
| 622 | + u32 intid, u32 num, u32 kvm_max_routes, | |
| 623 | + bool expect_failure) | |
| 623 | 624 | { |
| 624 | 625 | int fd[MAX_SPI]; |
| 625 | − uint64_t val; | |
| 626 | + u64 val; | |
| 626 | 627 | int ret, f; |
| 627 | − uint64_t i; | |
| 628 | + u64 i; | |
| 628 | 629 | |
| 629 | 630 | /* |
| 630 | 631 | * There is no way to try injecting an SGI or PPI as the interface |
| @@ -643,29 +644,29 @@ static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, · 12 unmodified lines | ||
| 643 | 644 | * that no actual interrupt was injected for those cases. |
| 644 | 645 | */ |
| 645 | 646 | |
| 646 | − for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) | |
| 647 | + for (f = 0, i = intid; i < (u64)intid + num; i++, f++) | |
| 647 | 648 | fd[f] = kvm_new_eventfd(); |
| 648 | 649 | |
| 649 | − for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) { | |
| 650 | − assert(i <= (uint64_t)UINT_MAX); | |
| 650 | + for (f = 0, i = intid; i < (u64)intid + num; i++, f++) { | |
| 651 | + assert(i <= (u64)UINT_MAX); | |
| 651 | 652 | kvm_assign_irqfd(vm, i - MIN_SPI, fd[f]); |
| 652 | 653 | } |
| 653 | 654 | |
| 654 | − for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) { | |
| 655 | + for (f = 0, i = intid; i < (u64)intid + num; i++, f++) { | |
| 655 | 656 | val = 1; |
| 656 | − ret = write(fd[f], &val, sizeof(uint64_t)); | |
| 657 | − TEST_ASSERT(ret == sizeof(uint64_t), | |
| 657 | + ret = write(fd[f], &val, sizeof(u64)); | |
| 658 | + TEST_ASSERT(ret == sizeof(u64), | |
| 658 | 659 | __KVM_SYSCALL_ERROR("write()", ret)); |
| 659 | 660 | } |
| 660 | 661 | |
| 661 | − for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) | |
| 662 | + for (f = 0, i = intid; i < (u64)intid + num; i++, f++) | |
| 662 | 663 | kvm_close(fd[f]); |
| 663 | 664 | } |
| 664 | 665 | |
| 665 | 666 | /* handles the valid case: intid=0xffffffff num=1 */ |
| 666 | 667 | #define for_each_intid(first, num, tmp, i) \ |
| 667 | 668 | for ((tmp) = (i) = (first); \ |
| 668 | − (tmp) < (uint64_t)(first) + (uint64_t)(num); \ | |
| 669 | + (tmp) < (u64)(first) + (u64)(num); \ | |
| 669 | 670 | (tmp)++, (i)++) |
| 670 | 671 | |
| 671 | 672 | static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd, |
| @@ -673,13 +674,13 @@ static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd, · 1 unmodified line | ||
| 673 | 674 | struct test_args *test_args) |
| 674 | 675 | { |
| 675 | 676 | kvm_inject_cmd cmd = inject_args->cmd; |
| 676 | − uint32_t intid = inject_args->first_intid; | |
| 677 | − uint32_t num = inject_args->num; | |
| 677 | + u32 intid = inject_args->first_intid; | |
| 678 | + u32 num = inject_args->num; | |
| 678 | 679 | int level = inject_args->level; |
| 679 | 680 | bool expect_failure = inject_args->expect_failure; |
| 680 | 681 | struct kvm_vm *vm = vcpu->vm; |
| 681 | − uint64_t tmp; | |
| 682 | − uint32_t i; | |
| 682 | + u64 tmp; | |
| 683 | + u32 i; | |
| 683 | 684 | |
| 684 | 685 | /* handles the valid case: intid=0xffffffff num=1 */ |
| 685 | 686 | assert(intid < UINT_MAX - num || num == 1); |
| @@ -731,7 +732,7 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc, · 45 unmodified lines | ||
| 731 | 732 | struct kvm_inject_args *args) |
| 732 | 733 | { |
| 733 | 734 | struct kvm_inject_args *kvm_args_hva; |
| 734 | − vm_vaddr_t kvm_args_gva; | |
| 735 | + gva_t kvm_args_gva; | |
| 735 | 736 | |
| 736 | 737 | kvm_args_gva = uc->args[1]; |
| 737 | 738 | kvm_args_hva = (struct kvm_inject_args *)addr_gva2hva(vm, kvm_args_gva); |
| @@ -745,14 +746,14 @@ static void print_args(struct test_args *args) · 7 unmodified lines | ||
| 745 | 746 | args->eoi_split); |
| 746 | 747 | } |
| 747 | 748 | |
| 748 | −static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) | |
| 749 | +static void test_vgic(u32 nr_irqs, bool level_sensitive, bool eoi_split) | |
| 749 | 750 | { |
| 750 | 751 | struct ucall uc; |
| 751 | 752 | int gic_fd; |
| 752 | 753 | struct kvm_vcpu *vcpu; |
| 753 | 754 | struct kvm_vm *vm; |
| 754 | 755 | struct kvm_inject_args inject_args; |
| 755 | − vm_vaddr_t args_gva; | |
| 756 | + gva_t args_gva; | |
| 756 | 757 | |
| 757 | 758 | struct test_args args = { |
| 758 | 759 | .nr_irqs = nr_irqs, |
| @@ -770,7 +771,7 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) · 11 unmodified lines | ||
| 770 | 771 | vcpu_init_descriptor_tables(vcpu); |
| 771 | 772 | |
| 772 | 773 | /* Setup the guest args page (so it gets the args). */ |
| 773 | − args_gva = vm_vaddr_alloc_page(vm); | |
| 774 | + args_gva = vm_alloc_page(vm); | |
| 774 | 775 | memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); |
| 775 | 776 | vcpu_args_set(vcpu, 1, args_gva); |
| 776 | 777 | |
| @@ -810,7 +811,7 @@ static void guest_code_asym_dir(struct test_args *args, int cpuid) · 33 unmodified lines | ||
| 810 | 811 | gic_set_priority_mask(CPU_PRIO_MASK); |
| 811 | 812 | |
| 812 | 813 | if (cpuid == 0) { |
| 813 | − uint32_t intid; | |
| 814 | + u32 intid; | |
| 814 | 815 | |
| 815 | 816 | local_irq_disable(); |
| 816 | 817 | |
| @@ -848,7 +849,7 @@ static void guest_code_asym_dir(struct test_args *args, int cpuid) · 31 unmodified lines | ||
| 848 | 849 | |
| 849 | 850 | static void guest_code_group_en(struct test_args *args, int cpuid) |
| 850 | 851 | { |
| 851 | − uint32_t intid; | |
| 852 | + u32 intid; | |
| 852 | 853 | |
| 853 | 854 | gic_init(GIC_V3, 2); |
| 854 | 855 | |
| @@ -896,7 +897,7 @@ static void guest_code_group_en(struct test_args *args, int cpuid) · 41 unmodified lines | ||
| 896 | 897 | |
| 897 | 898 | static void guest_code_timer_spi(struct test_args *args, int cpuid) |
| 898 | 899 | { |
| 899 | − uint32_t intid; | |
| 900 | + u32 intid; | |
| 900 | 901 | u64 val; |
| 901 | 902 | |
| 902 | 903 | gic_init(GIC_V3, 2); |
| @@ -986,7 +987,7 @@ static void test_vgic_two_cpus(void *gcode) · 83 unmodified lines | ||
| 986 | 987 | struct kvm_vcpu *vcpus[2]; |
| 987 | 988 | struct test_args args = {}; |
| 988 | 989 | struct kvm_vm *vm; |
| 989 | − vm_vaddr_t args_gva; | |
| 990 | + gva_t args_gva; | |
| 990 | 991 | int gic_fd, ret; |
| 991 | 992 | |
| 992 | 993 | vm = vm_create_with_vcpus(2, gcode, vcpus); |
| @@ -996,7 +997,7 @@ static void test_vgic_two_cpus(void *gcode) · 3 unmodified lines | ||
| 996 | 997 | vcpu_init_descriptor_tables(vcpus[1]); |
| 997 | 998 | |
| 998 | 999 | /* Setup the guest args page (so it gets the args). */ |
| 999 | − args_gva = vm_vaddr_alloc_page(vm); | |
| 1000 | + args_gva = vm_alloc_page(vm); | |
| 1000 | 1001 | memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); |
| 1001 | 1002 | vcpu_args_set(vcpus[0], 2, args_gva, 0); |
| 1002 | 1003 | vcpu_args_set(vcpus[1], 2, args_gva, 1); |
| @@ -1033,7 +1034,7 @@ static void help(const char *name) · 30 unmodified lines | ||
| 1033 | 1034 | |
| 1034 | 1035 | int main(int argc, char **argv) |
| 1035 | 1036 | { |
| 1036 | − uint32_t nr_irqs = 64; | |
| 1037 | + u32 nr_irqs = 64; | |
| 1037 | 1038 | bool default_args = true; |
| 1038 | 1039 | bool level_sensitive = false; |
| 1039 | 1040 | int opt; |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #define GIC_LPI_OFFSET 8192 |
| 24 | 24 | |
| 25 | 25 | static size_t nr_iterations = 1000; |
| 26 | −static vm_paddr_t gpa_base; | |
| 26 | +static gpa_t gpa_base; | |
| 27 | 27 | |
| 28 | 28 | static struct kvm_vm *vm; |
| 29 | 29 | static struct kvm_vcpu **vcpus; |
| @@ -35,14 +35,14 @@ static struct test_data { · 5 unmodified lines | ||
| 35 | 35 | u32 nr_devices; |
| 36 | 36 | u32 nr_event_ids; |
| 37 | 37 | |
| 38 | − vm_paddr_t device_table; | |
| 39 | − vm_paddr_t collection_table; | |
| 40 | − vm_paddr_t cmdq_base; | |
| 38 | + gpa_t device_table; | |
| 39 | + gpa_t collection_table; | |
| 40 | + gpa_t cmdq_base; | |
| 41 | 41 | void *cmdq_base_va; |
| 42 | − vm_paddr_t itt_tables; | |
| 42 | + gpa_t itt_tables; | |
| 43 | 43 | |
| 44 | − vm_paddr_t lpi_prop_table; | |
| 45 | − vm_paddr_t lpi_pend_tables; | |
| 44 | + gpa_t lpi_prop_table; | |
| 45 | + gpa_t lpi_pend_tables; | |
| 46 | 46 | } test_data = { |
| 47 | 47 | .nr_cpus = 1, |
| 48 | 48 | .nr_devices = 1, |
| @@ -73,7 +73,7 @@ static void guest_setup_its_mappings(void) · 24 unmodified lines | ||
| 73 | 73 | /* Round-robin the LPIs to all of the vCPUs in the VM */ |
| 74 | 74 | coll_id = 0; |
| 75 | 75 | for (device_id = 0; device_id < nr_devices; device_id++) { |
| 76 | − vm_paddr_t itt_base = test_data.itt_tables + (device_id * SZ_64K); | |
| 76 | + gpa_t itt_base = test_data.itt_tables + (device_id * SZ_64K); | |
| 77 | 77 | |
| 78 | 78 | its_send_mapd_cmd(test_data.cmdq_base_va, device_id, |
| 79 | 79 | itt_base, SZ_64K, true); |
| @@ -188,7 +188,7 @@ static void setup_test_data(void) · 108 unmodified lines | ||
| 188 | 188 | size_t pages_per_64k = vm_calc_num_guest_pages(vm->mode, SZ_64K); |
| 189 | 189 | u32 nr_devices = test_data.nr_devices; |
| 190 | 190 | u32 nr_cpus = test_data.nr_cpus; |
| 191 | − vm_paddr_t cmdq_base; | |
| 191 | + gpa_t cmdq_base; | |
| 192 | 192 | |
| 193 | 193 | test_data.device_table = vm_phy_pages_alloc(vm, pages_per_64k, |
| 194 | 194 | gpa_base, |
| @@ -224,7 +224,7 @@ static void setup_gic(void) · 29 unmodified lines | ||
| 224 | 224 | |
| 225 | 225 | static void signal_lpi(u32 device_id, u32 event_id) |
| 226 | 226 | { |
| 227 | − vm_paddr_t db_addr = GITS_BASE_GPA + GITS_TRANSLATER; | |
| 227 | + gpa_t db_addr = GITS_BASE_GPA + GITS_TRANSLATER; | |
| 228 | 228 | |
| 229 | 229 | struct kvm_msi msi = { |
| 230 | 230 | .address_lo = db_addr, |
| @@ -17,10 +17,10 @@ · 16 unmodified lines | ||
| 17 | 17 | struct vm_gic { |
| 18 | 18 | struct kvm_vm *vm; |
| 19 | 19 | int gic_fd; |
| 20 | − uint32_t gic_dev_type; | |
| 20 | + u32 gic_dev_type; | |
| 21 | 21 | }; |
| 22 | 22 | |
| 23 | −static uint64_t max_phys_size; | |
| 23 | +static u64 max_phys_size; | |
| 24 | 24 | |
| 25 | 25 | #define GUEST_CMD_IRQ_CDIA 10 |
| 26 | 26 | #define GUEST_CMD_IRQ_DIEOI 11 |
| @@ -96,7 +96,7 @@ static void vm_gic_destroy(struct vm_gic *v) · 69 unmodified lines | ||
| 96 | 96 | kvm_vm_free(v->vm); |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | −static void test_vgic_v5_ppis(uint32_t gic_dev_type) | |
| 99 | +static void test_vgic_v5_ppis(u32 gic_dev_type) | |
| 100 | 100 | { |
| 101 | 101 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 102 | 102 | struct ucall uc; |
| @@ -173,7 +173,7 @@ done: · 70 unmodified lines | ||
| 173 | 173 | /* |
| 174 | 174 | * Returns 0 if it's possible to create GIC device of a given type (V5). |
| 175 | 175 | */ |
| 176 | −int test_kvm_device(uint32_t gic_dev_type) | |
| 176 | +int test_kvm_device(u32 gic_dev_type) | |
| 177 | 177 | { |
| 178 | 178 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 179 | 179 | struct vm_gic v; |
| @@ -199,7 +199,7 @@ int test_kvm_device(uint32_t gic_dev_type) · 19 unmodified lines | ||
| 199 | 199 | return 0; |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | −void run_tests(uint32_t gic_dev_type) | |
| 202 | +void run_tests(u32 gic_dev_type) | |
| 203 | 203 | { |
| 204 | 204 | pr_info("Test VGICv5 PPIs\n"); |
| 205 | 205 | test_vgic_v5_ppis(gic_dev_type); |
| @@ -33,20 +33,20 @@ struct vpmu_vm { · 32 unmodified lines | ||
| 33 | 33 | static struct vpmu_vm vpmu_vm; |
| 34 | 34 | |
| 35 | 35 | struct pmreg_sets { |
| 36 | − uint64_t set_reg_id; | |
| 37 | − uint64_t clr_reg_id; | |
| 36 | + u64 set_reg_id; | |
| 37 | + u64 clr_reg_id; | |
| 38 | 38 | }; |
| 39 | 39 | |
| 40 | 40 | #define PMREG_SET(set, clr) {.set_reg_id = set, .clr_reg_id = clr} |
| 41 | 41 | |
| 42 | −static uint64_t get_pmcr_n(uint64_t pmcr) | |
| 42 | +static u64 get_pmcr_n(u64 pmcr) | |
| 43 | 43 | { |
| 44 | 44 | return FIELD_GET(ARMV8_PMU_PMCR_N, pmcr); |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | −static uint64_t get_counters_mask(uint64_t n) | |
| 47 | +static u64 get_counters_mask(u64 n) | |
| 48 | 48 | { |
| 49 | − uint64_t mask = BIT(ARMV8_PMU_CYCLE_IDX); | |
| 49 | + u64 mask = BIT(ARMV8_PMU_CYCLE_IDX); | |
| 50 | 50 | |
| 51 | 51 | if (n) |
| 52 | 52 | mask |= GENMASK(n - 1, 0); |
| @@ -89,7 +89,7 @@ static inline void write_sel_evtyper(int sel, unsigned long val) · 36 unmodified lines | ||
| 89 | 89 | |
| 90 | 90 | static void pmu_disable_reset(void) |
| 91 | 91 | { |
| 92 | − uint64_t pmcr = read_sysreg(pmcr_el0); | |
| 92 | + u64 pmcr = read_sysreg(pmcr_el0); | |
| 93 | 93 | |
| 94 | 94 | /* Reset all counters, disabling them */ |
| 95 | 95 | pmcr &= ~ARMV8_PMU_PMCR_E; |
| @@ -169,7 +169,7 @@ struct pmc_accessor pmc_accessors[] = { · 73 unmodified lines | ||
| 169 | 169 | |
| 170 | 170 | #define GUEST_ASSERT_BITMAP_REG(regname, mask, set_expected) \ |
| 171 | 171 | { \ |
| 172 | − uint64_t _tval = read_sysreg(regname); \ | |
| 172 | + u64 _tval = read_sysreg(regname); \ | |
| 173 | 173 | \ |
| 174 | 174 | if (set_expected) \ |
| 175 | 175 | __GUEST_ASSERT((_tval & mask), \ |
| @@ -185,7 +185,7 @@ struct pmc_accessor pmc_accessors[] = { · 9 unmodified lines | ||
| 185 | 185 | * Check if @mask bits in {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers |
| 186 | 186 | * are set or cleared as specified in @set_expected. |
| 187 | 187 | */ |
| 188 | −static void check_bitmap_pmu_regs(uint64_t mask, bool set_expected) | |
| 188 | +static void check_bitmap_pmu_regs(u64 mask, bool set_expected) | |
| 189 | 189 | { |
| 190 | 190 | GUEST_ASSERT_BITMAP_REG(pmcntenset_el0, mask, set_expected); |
| 191 | 191 | GUEST_ASSERT_BITMAP_REG(pmcntenclr_el0, mask, set_expected); |
| @@ -207,7 +207,7 @@ static void check_bitmap_pmu_regs(uint64_t mask, bool set_expected) · 15 unmodified lines | ||
| 207 | 207 | */ |
| 208 | 208 | static void test_bitmap_pmu_regs(int pmc_idx, bool set_op) |
| 209 | 209 | { |
| 210 | − uint64_t pmcr_n, test_bit = BIT(pmc_idx); | |
| 210 | + u64 pmcr_n, test_bit = BIT(pmc_idx); | |
| 211 | 211 | bool set_expected = false; |
| 212 | 212 | |
| 213 | 213 | if (set_op) { |
| @@ -232,7 +232,7 @@ static void test_bitmap_pmu_regs(int pmc_idx, bool set_op) · 18 unmodified lines | ||
| 232 | 232 | */ |
| 233 | 233 | static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx) |
| 234 | 234 | { |
| 235 | − uint64_t write_data, read_data; | |
| 235 | + u64 write_data, read_data; | |
| 236 | 236 | |
| 237 | 237 | /* Disable all PMCs and reset all PMCs to zero. */ |
| 238 | 238 | pmu_disable_reset(); |
| @@ -287,11 +287,11 @@ static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx) · 48 unmodified lines | ||
| 287 | 287 | } |
| 288 | 288 | |
| 289 | 289 | #define INVALID_EC (-1ul) |
| 290 | −uint64_t expected_ec = INVALID_EC; | |
| 290 | +u64 expected_ec = INVALID_EC; | |
| 291 | 291 | |
| 292 | 292 | static void guest_sync_handler(struct ex_regs *regs) |
| 293 | 293 | { |
| 294 | − uint64_t esr, ec; | |
| 294 | + u64 esr, ec; | |
| 295 | 295 | |
| 296 | 296 | esr = read_sysreg(esr_el1); |
| 297 | 297 | ec = ESR_ELx_EC(esr); |
| @@ -351,9 +351,9 @@ static void test_access_invalid_pmc_regs(struct pmc_accessor *acc, int pmc_idx) · 53 unmodified lines | ||
| 351 | 351 | * if reading/writing PMU registers for implemented or unimplemented |
| 352 | 352 | * counters works as expected. |
| 353 | 353 | */ |
| 354 | −static void guest_code(uint64_t expected_pmcr_n) | |
| 354 | +static void guest_code(u64 expected_pmcr_n) | |
| 355 | 355 | { |
| 356 | − uint64_t pmcr, pmcr_n, unimp_mask; | |
| 356 | + u64 pmcr, pmcr_n, unimp_mask; | |
| 357 | 357 | int i, pmc; |
| 358 | 358 | |
| 359 | 359 | __GUEST_ASSERT(expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS, |
| @@ -402,12 +402,12 @@ static void guest_code(uint64_t expected_pmcr_n) · 42 unmodified lines | ||
| 402 | 402 | static void create_vpmu_vm(void *guest_code) |
| 403 | 403 | { |
| 404 | 404 | struct kvm_vcpu_init init; |
| 405 | − uint8_t pmuver, ec; | |
| 406 | − uint64_t dfr0, irq = 23; | |
| 405 | + u8 pmuver, ec; | |
| 406 | + u64 dfr0, irq = 23; | |
| 407 | 407 | struct kvm_device_attr irq_attr = { |
| 408 | 408 | .group = KVM_ARM_VCPU_PMU_V3_CTRL, |
| 409 | 409 | .attr = KVM_ARM_VCPU_PMU_V3_IRQ, |
| 410 | − .addr = (uint64_t)&irq, | |
| 410 | + .addr = (u64)&irq, | |
| 411 | 411 | }; |
| 412 | 412 | |
| 413 | 413 | /* The test creates the vpmu_vm multiple times. Ensure a clean state */ |
| @@ -443,7 +443,7 @@ static void destroy_vpmu_vm(void) · 29 unmodified lines | ||
| 443 | 443 | kvm_vm_free(vpmu_vm.vm); |
| 444 | 444 | } |
| 445 | 445 | |
| 446 | −static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n) | |
| 446 | +static void run_vcpu(struct kvm_vcpu *vcpu, u64 pmcr_n) | |
| 447 | 447 | { |
| 448 | 448 | struct ucall uc; |
| 449 | 449 | |
| @@ -489,9 +489,9 @@ static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool · 39 unmodified lines | ||
| 489 | 489 | * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n, |
| 490 | 490 | * and run the test. |
| 491 | 491 | */ |
| 492 | −static void run_access_test(uint64_t pmcr_n) | |
| 492 | +static void run_access_test(u64 pmcr_n) | |
| 493 | 493 | { |
| 494 | − uint64_t sp; | |
| 494 | + u64 sp; | |
| 495 | 495 | struct kvm_vcpu *vcpu; |
| 496 | 496 | struct kvm_vcpu_init init; |
| 497 | 497 | |
| @@ -514,7 +514,7 @@ static void run_access_test(uint64_t pmcr_n) · 16 unmodified lines | ||
| 514 | 514 | aarch64_vcpu_setup(vcpu, &init); |
| 515 | 515 | vcpu_init_descriptor_tables(vcpu); |
| 516 | 516 | vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1), sp); |
| 517 | − vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); | |
| 517 | + vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (u64)guest_code); | |
| 518 | 518 | |
| 519 | 519 | run_vcpu(vcpu, pmcr_n); |
| 520 | 520 | |
| @@ -531,12 +531,12 @@ static struct pmreg_sets validity_check_reg_sets[] = { · 10 unmodified lines | ||
| 531 | 531 | * Create a VM, and check if KVM handles the userspace accesses of |
| 532 | 532 | * the PMU register sets in @validity_check_reg_sets[] correctly. |
| 533 | 533 | */ |
| 534 | −static void run_pmregs_validity_test(uint64_t pmcr_n) | |
| 534 | +static void run_pmregs_validity_test(u64 pmcr_n) | |
| 535 | 535 | { |
| 536 | 536 | int i; |
| 537 | 537 | struct kvm_vcpu *vcpu; |
| 538 | − uint64_t set_reg_id, clr_reg_id, reg_val; | |
| 539 | − uint64_t valid_counters_mask, max_counters_mask; | |
| 538 | + u64 set_reg_id, clr_reg_id, reg_val; | |
| 539 | + u64 valid_counters_mask, max_counters_mask; | |
| 540 | 540 | |
| 541 | 541 | test_create_vpmu_vm_with_nr_counters(pmcr_n, false); |
| 542 | 542 | vcpu = vpmu_vm.vcpu; |
| @@ -588,7 +588,7 @@ static void run_pmregs_validity_test(uint64_t pmcr_n) · 45 unmodified lines | ||
| 588 | 588 | * the vCPU to @pmcr_n, which is larger than the host value. |
| 589 | 589 | * The attempt should fail as @pmcr_n is too big to set for the vCPU. |
| 590 | 590 | */ |
| 591 | −static void run_error_test(uint64_t pmcr_n) | |
| 591 | +static void run_error_test(u64 pmcr_n) | |
| 592 | 592 | { |
| 593 | 593 | pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n); |
| 594 | 594 | |
| @@ -600,9 +600,9 @@ static void run_error_test(uint64_t pmcr_n) · 5 unmodified lines | ||
| 600 | 600 | * Return the default number of implemented PMU event counters excluding |
| 601 | 601 | * the cycle counter (i.e. PMCR_EL0.N value) for the guest. |
| 602 | 602 | */ |
| 603 | −static uint64_t get_pmcr_n_limit(void) | |
| 603 | +static u64 get_pmcr_n_limit(void) | |
| 604 | 604 | { |
| 605 | − uint64_t pmcr; | |
| 605 | + u64 pmcr; | |
| 606 | 606 | |
| 607 | 607 | create_vpmu_vm(guest_code); |
| 608 | 608 | pmcr = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)); |
| @@ -624,7 +624,7 @@ static bool kvm_supports_nr_counters_attr(void) · 15 unmodified lines | ||
| 624 | 624 | |
| 625 | 625 | int main(void) |
| 626 | 626 | { |
| 627 | − uint64_t i, pmcr_n; | |
| 627 | + u64 i, pmcr_n; | |
| 628 | 628 | |
| 629 | 629 | TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); |
| 630 | 630 | TEST_REQUIRE(kvm_supports_vgic_v3()); |
| @@ -14,16 +14,16 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | struct kvm_coalesced_io { |
| 16 | 16 | struct kvm_coalesced_mmio_ring *ring; |
| 17 | − uint32_t ring_size; | |
| 18 | − uint64_t mmio_gpa; | |
| 19 | − uint64_t *mmio; | |
| 17 | + u32 ring_size; | |
| 18 | + u64 mmio_gpa; | |
| 19 | + u64 *mmio; | |
| 20 | 20 | |
| 21 | 21 | /* |
| 22 | 22 | * x86-only, but define pio_port for all architectures to minimize the |
| 23 | 23 | * amount of #ifdeffery and complexity, without having to sacrifice |
| 24 | 24 | * verbose error messages. |
| 25 | 25 | */ |
| 26 | − uint8_t pio_port; | |
| 26 | + u8 pio_port; | |
| 27 | 27 | }; |
| 28 | 28 | |
| 29 | 29 | static struct kvm_coalesced_io kvm_builtin_io_ring; |
| @@ -70,13 +70,13 @@ static void guest_code(struct kvm_coalesced_io *io) · 40 unmodified lines | ||
| 70 | 70 | |
| 71 | 71 | static void vcpu_run_and_verify_io_exit(struct kvm_vcpu *vcpu, |
| 72 | 72 | struct kvm_coalesced_io *io, |
| 73 | − uint32_t ring_start, | |
| 74 | − uint32_t expected_exit) | |
| 73 | + u32 ring_start, | |
| 74 | + u32 expected_exit) | |
| 75 | 75 | { |
| 76 | 76 | const bool want_pio = expected_exit == KVM_EXIT_IO; |
| 77 | 77 | struct kvm_coalesced_mmio_ring *ring = io->ring; |
| 78 | 78 | struct kvm_run *run = vcpu->run; |
| 79 | − uint32_t pio_value; | |
| 79 | + u32 pio_value; | |
| 80 | 80 | |
| 81 | 81 | WRITE_ONCE(ring->first, ring_start); |
| 82 | 82 | WRITE_ONCE(ring->last, ring_start); |
| @@ -88,13 +88,13 @@ static void vcpu_run_and_verify_io_exit(struct kvm_vcpu *vcpu, · 5 unmodified lines | ||
| 88 | 88 | * data_offset is garbage, e.g. an MMIO gpa. |
| 89 | 89 | */ |
| 90 | 90 | if (run->exit_reason == KVM_EXIT_IO) |
| 91 | − pio_value = *(uint32_t *)((void *)run + run->io.data_offset); | |
| 91 | + pio_value = *(u32 *)((void *)run + run->io.data_offset); | |
| 92 | 92 | else |
| 93 | 93 | pio_value = 0; |
| 94 | 94 | |
| 95 | 95 | TEST_ASSERT((!want_pio && (run->exit_reason == KVM_EXIT_MMIO && run->mmio.is_write && |
| 96 | 96 | run->mmio.phys_addr == io->mmio_gpa && run->mmio.len == 8 && |
| 97 | − *(uint64_t *)run->mmio.data == io->mmio_gpa + io->ring_size - 1)) || | |
| 97 | + *(u64 *)run->mmio.data == io->mmio_gpa + io->ring_size - 1)) || | |
| 98 | 98 | (want_pio && (run->exit_reason == KVM_EXIT_IO && run->io.port == io->pio_port && |
| 99 | 99 | run->io.direction == KVM_EXIT_IO_OUT && run->io.count == 1 && |
| 100 | 100 | pio_value == io->pio_port + io->ring_size - 1)), |
| @@ -105,14 +105,14 @@ static void vcpu_run_and_verify_io_exit(struct kvm_vcpu *vcpu, · 4 unmodified lines | ||
| 105 | 105 | want_pio ? (unsigned long long)io->pio_port : io->mmio_gpa, |
| 106 | 106 | (want_pio ? io->pio_port : io->mmio_gpa) + io->ring_size - 1, run->exit_reason, |
| 107 | 107 | run->exit_reason == KVM_EXIT_MMIO ? "MMIO" : run->exit_reason == KVM_EXIT_IO ? "PIO" : "other", |
| 108 | − run->mmio.phys_addr, run->mmio.is_write, run->mmio.len, *(uint64_t *)run->mmio.data, | |
| 108 | + run->mmio.phys_addr, run->mmio.is_write, run->mmio.len, *(u64 *)run->mmio.data, | |
| 109 | 109 | run->io.port, run->io.direction, run->io.size, run->io.count, pio_value); |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu, |
| 113 | 113 | struct kvm_coalesced_io *io, |
| 114 | − uint32_t ring_start, | |
| 115 | − uint32_t expected_exit) | |
| 114 | + u32 ring_start, | |
| 115 | + u32 expected_exit) | |
| 116 | 116 | { |
| 117 | 117 | struct kvm_coalesced_mmio_ring *ring = io->ring; |
| 118 | 118 | int i; |
| @@ -124,18 +124,18 @@ static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu, · 5 unmodified lines | ||
| 124 | 124 | ring->first, ring->last, io->ring_size, ring_start); |
| 125 | 125 | |
| 126 | 126 | for (i = 0; i < io->ring_size - 1; i++) { |
| 127 | − uint32_t idx = (ring->first + i) % io->ring_size; | |
| 127 | + u32 idx = (ring->first + i) % io->ring_size; | |
| 128 | 128 | struct kvm_coalesced_mmio *entry = &ring->coalesced_mmio[idx]; |
| 129 | 129 | |
| 130 | 130 | #ifdef __x86_64__ |
| 131 | 131 | if (i & 1) |
| 132 | 132 | TEST_ASSERT(entry->phys_addr == io->pio_port && |
| 133 | 133 | entry->len == 4 && entry->pio && |
| 134 | − *(uint32_t *)entry->data == io->pio_port + i, | |
| 134 | + *(u32 *)entry->data == io->pio_port + i, | |
| 135 | 135 | "Wanted 4-byte port I/O 0x%x = 0x%x in entry %u, got %u-byte %s 0x%llx = 0x%x", |
| 136 | 136 | io->pio_port, io->pio_port + i, i, |
| 137 | 137 | entry->len, entry->pio ? "PIO" : "MMIO", |
| 138 | − entry->phys_addr, *(uint32_t *)entry->data); | |
| 138 | + entry->phys_addr, *(u32 *)entry->data); | |
| 139 | 139 | else |
| 140 | 140 | #endif |
| 141 | 141 | TEST_ASSERT(entry->phys_addr == io->mmio_gpa && |
| @@ -143,12 +143,12 @@ static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu, · 1 unmodified line | ||
| 143 | 143 | "Wanted 8-byte MMIO to 0x%lx = %lx in entry %u, got %u-byte %s 0x%llx = 0x%lx", |
| 144 | 144 | io->mmio_gpa, io->mmio_gpa + i, i, |
| 145 | 145 | entry->len, entry->pio ? "PIO" : "MMIO", |
| 146 | − entry->phys_addr, *(uint64_t *)entry->data); | |
| 146 | + entry->phys_addr, *(u64 *)entry->data); | |
| 147 | 147 | } |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | static void test_coalesced_io(struct kvm_vcpu *vcpu, |
| 151 | − struct kvm_coalesced_io *io, uint32_t ring_start) | |
| 151 | + struct kvm_coalesced_io *io, u32 ring_start) | |
| 152 | 152 | { |
| 153 | 153 | struct kvm_coalesced_mmio_ring *ring = io->ring; |
| 154 | 154 | |
| @@ -219,11 +219,11 @@ int main(int argc, char *argv[]) · 64 unmodified lines | ||
| 219 | 219 | * the MMIO GPA identity mapped in the guest. |
| 220 | 220 | */ |
| 221 | 221 | .mmio_gpa = 4ull * SZ_1G, |
| 222 | − .mmio = (uint64_t *)(4ull * SZ_1G), | |
| 222 | + .mmio = (u64 *)(4ull * SZ_1G), | |
| 223 | 223 | .pio_port = 0x80, |
| 224 | 224 | }; |
| 225 | 225 | |
| 226 | − virt_map(vm, (uint64_t)kvm_builtin_io_ring.mmio, kvm_builtin_io_ring.mmio_gpa, 1); | |
| 226 | + virt_map(vm, (u64)kvm_builtin_io_ring.mmio, kvm_builtin_io_ring.mmio_gpa, 1); | |
| 227 | 227 | |
| 228 | 228 | sync_global_to_guest(vm, kvm_builtin_io_ring); |
| 229 | 229 | vcpu_args_set(vcpu, 1, &kvm_builtin_io_ring); |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #ifdef __NR_userfaultfd |
| 25 | 25 | |
| 26 | 26 | static int nr_vcpus = 1; |
| 27 | −static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; | |
| 27 | +static u64 guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; | |
| 28 | 28 | |
| 29 | 29 | static size_t demand_paging_size; |
| 30 | 30 | static char *guest_data_prototype; |
| @@ -58,7 +58,7 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, · 27 unmodified lines | ||
| 58 | 58 | struct uffd_msg *msg) |
| 59 | 59 | { |
| 60 | 60 | pid_t tid = syscall(__NR_gettid); |
| 61 | − uint64_t addr = msg->arg.pagefault.address; | |
| 61 | + u64 addr = msg->arg.pagefault.address; | |
| 62 | 62 | struct timespec start; |
| 63 | 63 | struct timespec ts_diff; |
| 64 | 64 | int r; |
| @@ -68,7 +68,7 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, · 3 unmodified lines | ||
| 68 | 68 | if (uffd_mode == UFFDIO_REGISTER_MODE_MISSING) { |
| 69 | 69 | struct uffdio_copy copy; |
| 70 | 70 | |
| 71 | − copy.src = (uint64_t)guest_data_prototype; | |
| 71 | + copy.src = (u64)guest_data_prototype; | |
| 72 | 72 | copy.dst = addr; |
| 73 | 73 | copy.len = demand_paging_size; |
| 74 | 74 | copy.mode = 0; |
| @@ -138,7 +138,7 @@ struct test_params { · 63 unmodified lines | ||
| 138 | 138 | bool partition_vcpu_memory_access; |
| 139 | 139 | }; |
| 140 | 140 | |
| 141 | −static void prefault_mem(void *alias, uint64_t len) | |
| 141 | +static void prefault_mem(void *alias, u64 len) | |
| 142 | 142 | { |
| 143 | 143 | size_t p; |
| 144 | 144 | |
| @@ -154,7 +154,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) · 9 unmodified lines | ||
| 154 | 154 | struct memstress_vcpu_args *vcpu_args; |
| 155 | 155 | struct test_params *p = arg; |
| 156 | 156 | struct uffd_desc **uffd_descs = NULL; |
| 157 | − uint64_t uffd_region_size; | |
| 157 | + u64 uffd_region_size; | |
| 158 | 158 | struct timespec start; |
| 159 | 159 | struct timespec ts_diff; |
| 160 | 160 | double vcpu_paging_rate; |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #define TEST_HOST_LOOP_N 2UL |
| 25 | 25 | |
| 26 | 26 | static int nr_vcpus = 1; |
| 27 | −static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; | |
| 27 | +static u64 guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; | |
| 28 | 28 | static bool run_vcpus_while_disabling_dirty_logging; |
| 29 | 29 | |
| 30 | 30 | /* Host variables */ |
| @@ -37,7 +37,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) · 6 unmodified lines | ||
| 37 | 37 | { |
| 38 | 38 | struct kvm_vcpu *vcpu = vcpu_args->vcpu; |
| 39 | 39 | int vcpu_idx = vcpu_args->vcpu_idx; |
| 40 | − uint64_t pages_count = 0; | |
| 40 | + u64 pages_count = 0; | |
| 41 | 41 | struct kvm_run *run; |
| 42 | 42 | struct timespec start; |
| 43 | 43 | struct timespec ts_diff; |
| @@ -93,11 +93,11 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) · 49 unmodified lines | ||
| 93 | 93 | |
| 94 | 94 | struct test_params { |
| 95 | 95 | unsigned long iterations; |
| 96 | − uint64_t phys_offset; | |
| 96 | + u64 phys_offset; | |
| 97 | 97 | bool partition_vcpu_memory_access; |
| 98 | 98 | enum vm_mem_backing_src_type backing_src; |
| 99 | 99 | int slots; |
| 100 | − uint32_t write_percent; | |
| 100 | + u32 write_percent; | |
| 101 | 101 | bool random_access; |
| 102 | 102 | }; |
| 103 | 103 | |
| @@ -106,9 +106,9 @@ static void run_test(enum vm_guest_mode mode, void *arg) · 2 unmodified lines | ||
| 106 | 106 | struct test_params *p = arg; |
| 107 | 107 | struct kvm_vm *vm; |
| 108 | 108 | unsigned long **bitmaps; |
| 109 | − uint64_t guest_num_pages; | |
| 110 | − uint64_t host_num_pages; | |
| 111 | − uint64_t pages_per_slot; | |
| 109 | + u64 guest_num_pages; | |
| 110 | + u64 host_num_pages; | |
| 111 | + u64 pages_per_slot; | |
| 112 | 112 | struct timespec start; |
| 113 | 113 | struct timespec ts_diff; |
| 114 | 114 | struct timespec get_dirty_log_total = (struct timespec){0}; |
| @@ -74,11 +74,11 @@ · 73 unmodified lines | ||
| 74 | 74 | * the host. READ/WRITE_ONCE() should also be used with anything |
| 75 | 75 | * that may change. |
| 76 | 76 | */ |
| 77 | −static uint64_t host_page_size; | |
| 78 | −static uint64_t guest_page_size; | |
| 79 | −static uint64_t guest_num_pages; | |
| 80 | −static uint64_t iteration; | |
| 81 | −static uint64_t nr_writes; | |
| 77 | +static u64 host_page_size; | |
| 78 | +static u64 guest_page_size; | |
| 79 | +static u64 guest_num_pages; | |
| 80 | +static u64 iteration; | |
| 81 | +static u64 nr_writes; | |
| 82 | 82 | static bool vcpu_stop; |
| 83 | 83 | |
| 84 | 84 | /* |
| @@ -86,13 +86,13 @@ static bool vcpu_stop; · 1 unmodified line | ||
| 86 | 86 | * This will be set to the topmost valid physical address minus |
| 87 | 87 | * the test memory size. |
| 88 | 88 | */ |
| 89 | −static uint64_t guest_test_phys_mem; | |
| 89 | +static u64 guest_test_phys_mem; | |
| 90 | 90 | |
| 91 | 91 | /* |
| 92 | 92 | * Guest virtual memory offset of the testing memory slot. |
| 93 | 93 | * Must not conflict with identity mapped test code. |
| 94 | 94 | */ |
| 95 | −static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; | |
| 95 | +static u64 guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; | |
| 96 | 96 | |
| 97 | 97 | /* |
| 98 | 98 | * Continuously write to the first 8 bytes of a random pages within |
| @@ -100,10 +100,10 @@ static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; · 1 unmodified line | ||
| 100 | 100 | */ |
| 101 | 101 | static void guest_code(void) |
| 102 | 102 | { |
| 103 | − uint64_t addr; | |
| 103 | + u64 addr; | |
| 104 | 104 | |
| 105 | 105 | #ifdef __s390x__ |
| 106 | − uint64_t i; | |
| 106 | + u64 i; | |
| 107 | 107 | |
| 108 | 108 | /* |
| 109 | 109 | * On s390x, all pages of a 1M segment are initially marked as dirty |
| @@ -113,7 +113,7 @@ static void guest_code(void) · 3 unmodified lines | ||
| 113 | 113 | */ |
| 114 | 114 | for (i = 0; i < guest_num_pages; i++) { |
| 115 | 115 | addr = guest_test_virt_mem + i * guest_page_size; |
| 116 | − vcpu_arch_put_guest(*(uint64_t *)addr, READ_ONCE(iteration)); | |
| 116 | + vcpu_arch_put_guest(*(u64 *)addr, READ_ONCE(iteration)); | |
| 117 | 117 | nr_writes++; |
| 118 | 118 | } |
| 119 | 119 | #endif |
| @@ -125,7 +125,7 @@ static void guest_code(void) · 5 unmodified lines | ||
| 125 | 125 | * guest_page_size; |
| 126 | 126 | addr = align_down(addr, host_page_size); |
| 127 | 127 | |
| 128 | − vcpu_arch_put_guest(*(uint64_t *)addr, READ_ONCE(iteration)); | |
| 128 | + vcpu_arch_put_guest(*(u64 *)addr, READ_ONCE(iteration)); | |
| 129 | 129 | nr_writes++; |
| 130 | 130 | } |
| 131 | 131 | |
| @@ -138,11 +138,11 @@ static bool host_quit; · 6 unmodified lines | ||
| 138 | 138 | |
| 139 | 139 | /* Points to the test VM memory region on which we track dirty logs */ |
| 140 | 140 | static void *host_test_mem; |
| 141 | −static uint64_t host_num_pages; | |
| 141 | +static u64 host_num_pages; | |
| 142 | 142 | |
| 143 | 143 | /* For statistics only */ |
| 144 | −static uint64_t host_dirty_count; | |
| 145 | −static uint64_t host_clear_count; | |
| 144 | +static u64 host_dirty_count; | |
| 145 | +static u64 host_clear_count; | |
| 146 | 146 | |
| 147 | 147 | /* Whether dirty ring reset is requested, or finished */ |
| 148 | 148 | static sem_t sem_vcpu_stop; |
| @@ -169,7 +169,7 @@ static bool dirty_ring_vcpu_ring_full; · 20 unmodified lines | ||
| 169 | 169 | * dirty gfn we've collected, so that if a mismatch of data found later in the |
| 170 | 170 | * verifying process, we let it pass. |
| 171 | 171 | */ |
| 172 | −static uint64_t dirty_ring_last_page = -1ULL; | |
| 172 | +static u64 dirty_ring_last_page = -1ULL; | |
| 173 | 173 | |
| 174 | 174 | /* |
| 175 | 175 | * In addition to the above, it is possible (especially if this |
| @@ -213,7 +213,7 @@ static uint64_t dirty_ring_last_page = -1ULL; · 37 unmodified lines | ||
| 213 | 213 | * and also don't fail when it is reported in the next iteration, together with |
| 214 | 214 | * an outdated iteration count. |
| 215 | 215 | */ |
| 216 | −static uint64_t dirty_ring_prev_iteration_last_page; | |
| 216 | +static u64 dirty_ring_prev_iteration_last_page; | |
| 217 | 217 | |
| 218 | 218 | enum log_mode_t { |
| 219 | 219 | /* Only use KVM_GET_DIRTY_LOG for logging */ |
| @@ -236,7 +236,7 @@ static enum log_mode_t host_log_mode_option = LOG_MODE_ALL; · 16 unmodified lines | ||
| 236 | 236 | /* Logging mode for current run */ |
| 237 | 237 | static enum log_mode_t host_log_mode; |
| 238 | 238 | static pthread_t vcpu_thread; |
| 239 | −static uint32_t test_dirty_ring_count = TEST_DIRTY_RING_COUNT; | |
| 239 | +static u32 test_dirty_ring_count = TEST_DIRTY_RING_COUNT; | |
| 240 | 240 | |
| 241 | 241 | static bool clear_log_supported(void) |
| 242 | 242 | { |
| @@ -255,15 +255,15 @@ static void clear_log_create_vm_done(struct kvm_vm *vm) · 12 unmodified lines | ||
| 255 | 255 | } |
| 256 | 256 | |
| 257 | 257 | static void dirty_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, |
| 258 | − void *bitmap, uint32_t num_pages, | |
| 259 | − uint32_t *unused) | |
| 258 | + void *bitmap, u32 num_pages, | |
| 259 | + u32 *unused) | |
| 260 | 260 | { |
| 261 | 261 | kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | 264 | static void clear_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, |
| 265 | − void *bitmap, uint32_t num_pages, | |
| 266 | − uint32_t *unused) | |
| 265 | + void *bitmap, u32 num_pages, | |
| 266 | + u32 *unused) | |
| 267 | 267 | { |
| 268 | 268 | kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); |
| 269 | 269 | kvm_vm_clear_dirty_log(vcpu->vm, slot, bitmap, 0, num_pages); |
| @@ -297,8 +297,8 @@ static bool dirty_ring_supported(void) · 27 unmodified lines | ||
| 297 | 297 | |
| 298 | 298 | static void dirty_ring_create_vm_done(struct kvm_vm *vm) |
| 299 | 299 | { |
| 300 | − uint64_t pages; | |
| 301 | − uint32_t limit; | |
| 300 | + u64 pages; | |
| 301 | + u32 limit; | |
| 302 | 302 | |
| 303 | 303 | /* |
| 304 | 304 | * We rely on vcpu exit due to full dirty ring state. Adjust |
| @@ -333,12 +333,12 @@ static inline void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn) · 28 unmodified lines | ||
| 333 | 333 | smp_store_release(&gfn->flags, KVM_DIRTY_GFN_F_RESET); |
| 334 | 334 | } |
| 335 | 335 | |
| 336 | −static uint32_t dirty_ring_collect_one(struct kvm_dirty_gfn *dirty_gfns, | |
| 337 | − int slot, void *bitmap, | |
| 338 | − uint32_t num_pages, uint32_t *fetch_index) | |
| 336 | +static u32 dirty_ring_collect_one(struct kvm_dirty_gfn *dirty_gfns, | |
| 337 | + int slot, void *bitmap, | |
| 338 | + u32 num_pages, u32 *fetch_index) | |
| 339 | 339 | { |
| 340 | 340 | struct kvm_dirty_gfn *cur; |
| 341 | − uint32_t count = 0; | |
| 341 | + u32 count = 0; | |
| 342 | 342 | |
| 343 | 343 | while (true) { |
| 344 | 344 | cur = &dirty_gfns[*fetch_index % test_dirty_ring_count]; |
| @@ -359,10 +359,10 @@ static uint32_t dirty_ring_collect_one(struct kvm_dirty_gfn *dirty_gfns, · 14 unmodified lines | ||
| 359 | 359 | } |
| 360 | 360 | |
| 361 | 361 | static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, |
| 362 | − void *bitmap, uint32_t num_pages, | |
| 363 | − uint32_t *ring_buf_idx) | |
| 362 | + void *bitmap, u32 num_pages, | |
| 363 | + u32 *ring_buf_idx) | |
| 364 | 364 | { |
| 365 | − uint32_t count, cleared; | |
| 365 | + u32 count, cleared; | |
| 366 | 366 | |
| 367 | 367 | /* Only have one vcpu */ |
| 368 | 368 | count = dirty_ring_collect_one(vcpu_map_dirty_ring(vcpu), |
| @@ -404,8 +404,8 @@ struct log_mode { · 35 unmodified lines | ||
| 404 | 404 | void (*create_vm_done)(struct kvm_vm *vm); |
| 405 | 405 | /* Hook to collect the dirty pages into the bitmap provided */ |
| 406 | 406 | void (*collect_dirty_pages) (struct kvm_vcpu *vcpu, int slot, |
| 407 | − void *bitmap, uint32_t num_pages, | |
68 more lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 806 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 726 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 258 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 407 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 859 lines aren’t shown here.
This diff is large: its 267 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 246 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 726 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 452 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 243 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 255 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 296 lines aren’t shown here.
This diff is large: its 291 lines aren’t shown here.
This diff is large: its 220 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 211 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.