* 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 | Ahmad Masri <quic_amasri@quicinc.com> <amasri@codeaurora.org> | 19 | Ahmad Masri <quic_amasri@quicinc.com> <amasri@codeaurora.org> |
| 20 | Adam Oldham <oldhamca@gmail.com> | 20 | Adam Oldham <oldhamca@gmail.com> |
| 21 | Adam Radford <aradford@gmail.com> | 21 | Adam Radford <aradford@gmail.com> |
| 22 | Aditya Garg <gargaditya08@proton.me> <gargaditya08@live.com> | ||
| 22 | Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com> | 23 | Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com> |
| 23 | Adrian Bunk <bunk@stusta.de> | 24 | Adrian Bunk <bunk@stusta.de> |
| 24 | Ajay Kaher <ajay.kaher@broadcom.com> <akaher@vmware.com> | 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 | Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com> | 208 | Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com> |
| 208 | Corey Minyard <minyard@acm.org> | 209 | Corey Minyard <minyard@acm.org> |
| 209 | Damian Hobson-Garcia <dhobsong@igel.co.jp> | 210 | Damian Hobson-Garcia <dhobsong@igel.co.jp> |
| 211 | Dan Carpenter <error27@gmail.com> <dan.carpenter@linaro.org> | ||
| 210 | Dan Carpenter <error27@gmail.com> <dan.carpenter@oracle.com> | 212 | Dan Carpenter <error27@gmail.com> <dan.carpenter@oracle.com> |
| 211 | Dan Williams <djbw@kernel.org> <dan.j.williams@intel.com> | 213 | Dan Williams <djbw@kernel.org> <dan.j.williams@intel.com> |
| 212 | Daniel Borkmann <daniel@iogearbox.net> <danborkmann@googlemail.com> | 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 | Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com> | 497 | Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com> |
| 496 | Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com> | 498 | Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com> |
| 497 | Leo Yan <leo.yan@linux.dev> <leo.yan@linaro.org> | 499 | Leo Yan <leo.yan@linux.dev> <leo.yan@linaro.org> |
| 500 | Liam R. Howlett <liam@infradead.org> <Liam.Howlett@oracle.com> | ||
| 498 | Liam Mark <quic_lmark@quicinc.com> <lmark@codeaurora.org> | 501 | Liam Mark <quic_lmark@quicinc.com> <lmark@codeaurora.org> |
| 499 | Linas Vepstas <linas@austin.ibm.com> | 502 | Linas Vepstas <linas@austin.ibm.com> |
| 500 | Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch> | 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 | Linus Walleij <linusw@kernel.org> <linus.walleij@linaro.org> | 508 | Linus Walleij <linusw@kernel.org> <linus.walleij@linaro.org> |
| 506 | Linus Walleij <linusw@kernel.org> <triad@df.lth.se> | 509 | Linus Walleij <linusw@kernel.org> <triad@df.lth.se> |
| 507 | <linux-hardening@vger.kernel.org> <kernel-hardening@lists.openwall.com> | 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 | Li Yang <leoyang.li@nxp.com> <leoli@freescale.com> | 513 | Li Yang <leoyang.li@nxp.com> <leoli@freescale.com> |
| 509 | Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org> | 514 | Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org> |
| 510 | Lior David <quic_liord@quicinc.com> <liord@codeaurora.org> | 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 | Puranjay Mohan <puranjay@kernel.org> <puranjay12@gmail.com> | 692 | Puranjay Mohan <puranjay@kernel.org> <puranjay12@gmail.com> |
| 688 | Qais Yousef <qyousef@layalina.io> <qais.yousef@imgtec.com> | 693 | Qais Yousef <qyousef@layalina.io> <qais.yousef@imgtec.com> |
| 689 | Qais Yousef <qyousef@layalina.io> <qais.yousef@arm.com> | 694 | Qais Yousef <qyousef@layalina.io> <qais.yousef@arm.com> |
| 695 | Qi Zheng <qi.zheng@linux.dev> <zhengqi.arch@bytedance.com> | ||
| 690 | Quentin Monnet <qmo@kernel.org> <quentin.monnet@netronome.com> | 696 | Quentin Monnet <qmo@kernel.org> <quentin.monnet@netronome.com> |
| 691 | Quentin Monnet <qmo@kernel.org> <quentin@isovalent.com> | 697 | Quentin Monnet <qmo@kernel.org> <quentin@isovalent.com> |
| 692 | Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com> | 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 | memory_hugetlb_accounting | 220 | memory_hugetlb_accounting |
| 221 | Count HugeTLB memory usage towards the cgroup's overall | 221 | Count HugeTLB memory usage towards the cgroup's overall |
| 222 | memory usage for the memory controller (for the purpose of | 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 | behavior that could regress existing setups, so it must be | 224 | behavior that could regress existing setups, so it must be |
| 225 | explicitly opted in with this mount option. | 225 | explicitly opted in with this mount option. |
| 226 | 226 | ||
| @@ -24,6 +24,7 @@ properties: · 23 unmodified lines | |||
| 24 | compatible: | 24 | compatible: |
| 25 | items: | 25 | items: |
| 26 | - enum: | 26 | - enum: |
| 27 | - qcom,eliza-ipcc | ||
| 27 | - qcom,glymur-ipcc | 28 | - qcom,glymur-ipcc |
| 28 | - qcom,kaanapali-ipcc | 29 | - qcom,kaanapali-ipcc |
| 29 | - qcom,milos-ipcc | 30 | - qcom,milos-ipcc |
| @@ -23,6 +23,15 @@ properties: · 22 unmodified lines | |||
| 23 | description: | 23 | description: |
| 24 | Contains the chip-select IDs. | 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 | required: | 35 | required: |
| 27 | - reg | 36 | - reg |
| 28 | 37 | ||
| @@ -57,7 +57,7 @@ Mount options unique to the isofs filesystem. · 56 unmodified lines | |||
| 57 | Recommended documents about ISO 9660 standard are located at: | 57 | Recommended documents about ISO 9660 standard are located at: |
| 58 | 58 | ||
| 59 | - http://www.y-adagio.com/ | 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 | Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically | 62 | Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically |
| 63 | identical with ISO 9660.", so it is a valid and gratis substitute of the | 63 | identical with ISO 9660.", so it is a valid and gratis substitute of the |
| @@ -188,6 +188,7 @@ operations: · 187 unmodified lines | |||
| 188 | name: dev-set | 188 | name: dev-set |
| 189 | doc: Set the configuration of a PSP device. | 189 | doc: Set the configuration of a PSP device. |
| 190 | attribute-set: dev | 190 | attribute-set: dev |
| 191 | flags: [admin-perm] | ||
| 191 | do: | 192 | do: |
| 192 | request: | 193 | request: |
| 193 | attributes: | 194 | attributes: |
| @@ -207,6 +208,7 @@ operations: · 13 unmodified lines | |||
| 207 | name: key-rotate | 208 | name: key-rotate |
| 208 | doc: Rotate the device key. | 209 | doc: Rotate the device key. |
| 209 | attribute-set: dev | 210 | attribute-set: dev |
| 211 | flags: [admin-perm] | ||
| 210 | do: | 212 | do: |
| 211 | request: | 213 | request: |
| 212 | attributes: | 214 | attributes: |
| @@ -7873,7 +7873,7 @@ F: drivers/gpu/drm/sun4i/sun8i* · 7872 unmodified lines | |||
| 7873 | 7873 | ||
| 7874 | DRM DRIVER FOR APPLE TOUCH BARS | 7874 | DRM DRIVER FOR APPLE TOUCH BARS |
| 7875 | M: Aun-Ali Zaidi <admin@kodeit.net> | 7875 | M: Aun-Ali Zaidi <admin@kodeit.net> |
| 7876 | M: Aditya Garg <gargaditya08@live.com> | 7876 | M: Aditya Garg <gargaditya08@proton.me> |
| 7877 | L: dri-devel@lists.freedesktop.org | 7877 | L: dri-devel@lists.freedesktop.org |
| 7878 | S: Maintained | 7878 | S: Maintained |
| 7879 | T: git https://gitlab.freedesktop.org/drm/misc/kernel.git | 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 | R: Dave Young <ruirui.yang@linux.dev> | 13860 | R: Dave Young <ruirui.yang@linux.dev> |
| 13861 | L: kexec@lists.infradead.org | 13861 | L: kexec@lists.infradead.org |
| 13862 | S: Maintained | 13862 | S: Maintained |
| 13863 | W: http://lse.sourceforge.net/kdump/ | ||
| 13864 | F: Documentation/admin-guide/kdump/ | 13863 | F: Documentation/admin-guide/kdump/ |
| 13865 | F: fs/proc/vmcore.c | 13864 | F: fs/proc/vmcore.c |
| 13866 | F: include/linux/crash_core.h | 13865 | F: include/linux/crash_core.h |
| @@ -15252,7 +15251,7 @@ M: Andrea Cervesato <andrea.cervesato@suse.com> · 1385 unmodified lines | |||
| 15252 | M: Cyril Hrubis <chrubis@suse.cz> | 15251 | M: Cyril Hrubis <chrubis@suse.cz> |
| 15253 | M: Jan Stancek <jstancek@redhat.com> | 15252 | M: Jan Stancek <jstancek@redhat.com> |
| 15254 | M: Petr Vorel <pvorel@suse.cz> | 15253 | M: Petr Vorel <pvorel@suse.cz> |
| 15255 | M: Li Wang <liwang@redhat.com> | 15254 | M: Li Wang <li.wang@linux.dev> |
| 15256 | M: Yang Xu <xuyang2018.jy@fujitsu.com> | 15255 | M: Yang Xu <xuyang2018.jy@fujitsu.com> |
| 15257 | M: Xiao Yang <yangx.jy@fujitsu.com> | 15256 | M: Xiao Yang <yangx.jy@fujitsu.com> |
| 15258 | L: ltp@lists.linux.it (subscribers-only) | 15257 | L: ltp@lists.linux.it (subscribers-only) |
| @@ -15399,7 +15398,7 @@ F: include/net/netns/mctp.h · 140 unmodified lines | |||
| 15399 | F: net/mctp/ | 15398 | F: net/mctp/ |
| 15400 | 15399 | ||
| 15401 | MAPLE TREE | 15400 | MAPLE TREE |
| 15402 | M: Liam R. Howlett <Liam.Howlett@oracle.com> | 15401 | M: Liam R. Howlett <liam@infradead.org> |
| 15403 | R: Alice Ryhl <aliceryhl@google.com> | 15402 | R: Alice Ryhl <aliceryhl@google.com> |
| 15404 | R: Andrew Ballance <andrewjballance@gmail.com> | 15403 | R: Andrew Ballance <andrewjballance@gmail.com> |
| 15405 | L: maple-tree@lists.infradead.org | 15404 | L: maple-tree@lists.infradead.org |
| @@ -16759,7 +16758,7 @@ MEMORY MANAGEMENT - CORE · 1353 unmodified lines | |||
| 16759 | M: Andrew Morton <akpm@linux-foundation.org> | 16758 | M: Andrew Morton <akpm@linux-foundation.org> |
| 16760 | M: David Hildenbrand <david@kernel.org> | 16759 | M: David Hildenbrand <david@kernel.org> |
| 16761 | R: Lorenzo Stoakes <ljs@kernel.org> | 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 | R: Vlastimil Babka <vbabka@kernel.org> | 16762 | R: Vlastimil Babka <vbabka@kernel.org> |
| 16764 | R: Mike Rapoport <rppt@kernel.org> | 16763 | R: Mike Rapoport <rppt@kernel.org> |
| 16765 | R: Suren Baghdasaryan <surenb@google.com> | 16764 | R: Suren Baghdasaryan <surenb@google.com> |
| @@ -16805,7 +16804,7 @@ F: mm/sparse.c · 39 unmodified lines | |||
| 16805 | F: mm/util.c | 16804 | F: mm/util.c |
| 16806 | F: mm/vmpressure.c | 16805 | F: mm/vmpressure.c |
| 16807 | F: mm/vmstat.c | 16806 | F: mm/vmstat.c |
| 16808 | N: include/linux/page[-_]* | 16807 | N: include\/linux\/page[-_][a-zA-Z]* |
| 16809 | 16808 | ||
| 16810 | MEMORY MANAGEMENT - EXECMEM | 16809 | MEMORY MANAGEMENT - EXECMEM |
| 16811 | M: Andrew Morton <akpm@linux-foundation.org> | 16810 | M: Andrew Morton <akpm@linux-foundation.org> |
| @@ -16895,7 +16894,7 @@ MEMORY MANAGEMENT - MISC · 83 unmodified lines | |||
| 16895 | M: Andrew Morton <akpm@linux-foundation.org> | 16894 | M: Andrew Morton <akpm@linux-foundation.org> |
| 16896 | M: David Hildenbrand <david@kernel.org> | 16895 | M: David Hildenbrand <david@kernel.org> |
| 16897 | R: Lorenzo Stoakes <ljs@kernel.org> | 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 | R: Vlastimil Babka <vbabka@kernel.org> | 16898 | R: Vlastimil Babka <vbabka@kernel.org> |
| 16900 | R: Mike Rapoport <rppt@kernel.org> | 16899 | R: Mike Rapoport <rppt@kernel.org> |
| 16901 | R: Suren Baghdasaryan <surenb@google.com> | 16900 | R: Suren Baghdasaryan <surenb@google.com> |
| @@ -16962,6 +16961,7 @@ S: Maintained · 60 unmodified lines | |||
| 16962 | F: include/linux/compaction.h | 16961 | F: include/linux/compaction.h |
| 16963 | F: include/linux/gfp.h | 16962 | F: include/linux/gfp.h |
| 16964 | F: include/linux/page-isolation.h | 16963 | F: include/linux/page-isolation.h |
| 16964 | F: include/linux/pageblock-flags.h | ||
| 16965 | F: mm/compaction.c | 16965 | F: mm/compaction.c |
| 16966 | F: mm/debug_page_alloc.c | 16966 | F: mm/debug_page_alloc.c |
| 16967 | F: mm/debug_page_ref.c | 16967 | F: mm/debug_page_ref.c |
| @@ -16983,7 +16983,7 @@ M: Andrew Morton <akpm@linux-foundation.org> · 15 unmodified lines | |||
| 16983 | M: Johannes Weiner <hannes@cmpxchg.org> | 16983 | M: Johannes Weiner <hannes@cmpxchg.org> |
| 16984 | R: David Hildenbrand <david@kernel.org> | 16984 | R: David Hildenbrand <david@kernel.org> |
| 16985 | R: Michal Hocko <mhocko@kernel.org> | 16985 | R: Michal Hocko <mhocko@kernel.org> |
| 16986 | R: Qi Zheng <zhengqi.arch@bytedance.com> | 16986 | R: Qi Zheng <qi.zheng@linux.dev> |
| 16987 | R: Shakeel Butt <shakeel.butt@linux.dev> | 16987 | R: Shakeel Butt <shakeel.butt@linux.dev> |
| 16988 | R: Lorenzo Stoakes <ljs@kernel.org> | 16988 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 16989 | L: linux-mm@kvack.org | 16989 | L: linux-mm@kvack.org |
| @@ -16996,7 +16996,7 @@ M: Andrew Morton <akpm@linux-foundation.org> · 6 unmodified lines | |||
| 16996 | M: David Hildenbrand <david@kernel.org> | 16996 | M: David Hildenbrand <david@kernel.org> |
| 16997 | M: Lorenzo Stoakes <ljs@kernel.org> | 16997 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 16998 | R: Rik van Riel <riel@surriel.com> | 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 | R: Vlastimil Babka <vbabka@kernel.org> | 17000 | R: Vlastimil Babka <vbabka@kernel.org> |
| 17001 | R: Harry Yoo <harry@kernel.org> | 17001 | R: Harry Yoo <harry@kernel.org> |
| 17002 | R: Jann Horn <jannh@google.com> | 17002 | R: Jann Horn <jannh@google.com> |
| @@ -17043,7 +17043,7 @@ M: David Hildenbrand <david@kernel.org> · 40 unmodified lines | |||
| 17043 | M: Lorenzo Stoakes <ljs@kernel.org> | 17043 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17044 | R: Zi Yan <ziy@nvidia.com> | 17044 | R: Zi Yan <ziy@nvidia.com> |
| 17045 | R: Baolin Wang <baolin.wang@linux.alibaba.com> | 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 | R: Nico Pache <npache@redhat.com> | 17047 | R: Nico Pache <npache@redhat.com> |
| 17048 | R: Ryan Roberts <ryan.roberts@arm.com> | 17048 | R: Ryan Roberts <ryan.roberts@arm.com> |
| 17049 | R: Dev Jain <dev.jain@arm.com> | 17049 | R: Dev Jain <dev.jain@arm.com> |
| @@ -17081,7 +17081,7 @@ F: tools/testing/selftests/mm/uffd-*.[ch] · 31 unmodified lines | |||
| 17081 | MEMORY MANAGEMENT - RUST | 17081 | MEMORY MANAGEMENT - RUST |
| 17082 | M: Alice Ryhl <aliceryhl@google.com> | 17082 | M: Alice Ryhl <aliceryhl@google.com> |
| 17083 | R: Lorenzo Stoakes <ljs@kernel.org> | 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 | L: linux-mm@kvack.org | 17085 | L: linux-mm@kvack.org |
| 17086 | L: rust-for-linux@vger.kernel.org | 17086 | L: rust-for-linux@vger.kernel.org |
| 17087 | S: Maintained | 17087 | S: Maintained |
| @@ -17095,7 +17095,7 @@ F: rust/kernel/page.rs · 7 unmodified lines | |||
| 17095 | 17095 | ||
| 17096 | MEMORY MAPPING | 17096 | MEMORY MAPPING |
| 17097 | M: Andrew Morton <akpm@linux-foundation.org> | 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 | M: Lorenzo Stoakes <ljs@kernel.org> | 17099 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17100 | R: Vlastimil Babka <vbabka@kernel.org> | 17100 | R: Vlastimil Babka <vbabka@kernel.org> |
| 17101 | R: Jann Horn <jannh@google.com> | 17101 | R: Jann Horn <jannh@google.com> |
| @@ -17127,7 +17127,7 @@ F: tools/testing/vma/ · 25 unmodified lines | |||
| 17127 | MEMORY MAPPING - LOCKING | 17127 | MEMORY MAPPING - LOCKING |
| 17128 | M: Andrew Morton <akpm@linux-foundation.org> | 17128 | M: Andrew Morton <akpm@linux-foundation.org> |
| 17129 | M: Suren Baghdasaryan <surenb@google.com> | 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 | M: Lorenzo Stoakes <ljs@kernel.org> | 17131 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17132 | R: Vlastimil Babka <vbabka@kernel.org> | 17132 | R: Vlastimil Babka <vbabka@kernel.org> |
| 17133 | R: Shakeel Butt <shakeel.butt@linux.dev> | 17133 | R: Shakeel Butt <shakeel.butt@linux.dev> |
| @@ -17142,7 +17142,7 @@ F: mm/mmap_lock.c · 8 unmodified lines | |||
| 17142 | 17142 | ||
| 17143 | MEMORY MAPPING - MADVISE (MEMORY ADVICE) | 17143 | MEMORY MAPPING - MADVISE (MEMORY ADVICE) |
| 17144 | M: Andrew Morton <akpm@linux-foundation.org> | 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 | M: Lorenzo Stoakes <ljs@kernel.org> | 17146 | M: Lorenzo Stoakes <ljs@kernel.org> |
| 17147 | M: David Hildenbrand <david@kernel.org> | 17147 | M: David Hildenbrand <david@kernel.org> |
| 17148 | R: Vlastimil Babka <vbabka@kernel.org> | 17148 | R: Vlastimil Babka <vbabka@kernel.org> |
| @@ -18672,19 +18672,59 @@ F: net/xfrm/ · 1523 unmodified lines | |||
| 18672 | F: tools/testing/selftests/net/ipsec.c | 18672 | F: tools/testing/selftests/net/ipsec.c |
| 18673 | 18673 | ||
| 18674 | NETWORKING [IPv4/IPv6] | 18674 | NETWORKING [IPv4/IPv6] |
| 18675 | M: "David S. Miller" <davem@davemloft.net> | ||
| 18676 | M: David Ahern <dsahern@kernel.org> | 18675 | M: David Ahern <dsahern@kernel.org> |
| 18676 | M: Ido Schimmel <idosch@nvidia.com> | ||
| 18677 | L: netdev@vger.kernel.org | 18677 | L: netdev@vger.kernel.org |
| 18678 | S: Maintained | 18678 | S: Maintained |
| 18679 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git | 18679 | F: Documentation/netlink/specs/rt-addr.yaml |
| 18680 | F: arch/x86/net/* | 18680 | F: Documentation/netlink/specs/rt-neigh.yaml |
| 18681 | F: include/linux/ip.h | 18681 | F: Documentation/netlink/specs/rt-route.yaml |
| 18682 | F: include/linux/ipv6* | 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 | F: include/net/fib* | 18687 | F: include/net/fib* |
| 18688 | F: include/net/if_inet6.h | ||
| 18689 | F: include/net/inetpeer.h | ||
| 18684 | F: include/net/ip* | 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 | F: include/net/route.h | 18695 | F: include/net/route.h |
| 18686 | F: net/ipv4/ | 18696 | F: include/uapi/linux/fib_rules.h |
| 18687 | F: net/ipv6/ | 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 | NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK) | 18729 | NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK) |
| 18690 | M: Paul Moore <paul@paul-moore.com> | 18730 | M: Paul Moore <paul@paul-moore.com> |
| @@ -18819,18 +18859,11 @@ F: Documentation/networking/net_failover.rst · 128 unmodified lines | |||
| 18819 | F: drivers/net/net_failover.c | 18859 | F: drivers/net/net_failover.c |
| 18820 | F: include/net/net_failover.h | 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 | NFC SUBSYSTEM | 18862 | NFC SUBSYSTEM |
| 18832 | L: netdev@vger.kernel.org | 18863 | M: David Heidelberg <david+nfc@ixit.cz> |
| 18833 | S: Orphan | 18864 | L: oe-linux-nfc@lists.linux.dev |
| 18865 | S: Maintained | ||
| 18866 | T: git https://codeberg.org/linux-nfc/linux.git | ||
| 18834 | F: Documentation/devicetree/bindings/net/nfc/ | 18867 | F: Documentation/devicetree/bindings/net/nfc/ |
| 18835 | F: drivers/nfc/ | 18868 | F: drivers/nfc/ |
| 18836 | F: include/net/nfc/ | 18869 | F: include/net/nfc/ |
| @@ -20774,6 +20807,7 @@ M: Dominik Brodowski <linux@dominikbrodowski.net> · 1937 unmodified lines | |||
| 20774 | S: Odd Fixes | 20807 | S: Odd Fixes |
| 20775 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux.git | 20808 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux.git |
| 20776 | F: Documentation/pcmcia/ | 20809 | F: Documentation/pcmcia/ |
| 20810 | F: drivers/net/ethernet/8390/pcnet_cs.c | ||
| 20777 | F: drivers/pcmcia/ | 20811 | F: drivers/pcmcia/ |
| 20778 | F: include/pcmcia/ | 20812 | F: include/pcmcia/ |
| 20779 | F: tools/pcmcia/ | 20813 | F: tools/pcmcia/ |
| @@ -23369,7 +23403,7 @@ RUST [ALLOC] · 2589 unmodified lines | |||
| 23369 | M: Danilo Krummrich <dakr@kernel.org> | 23403 | M: Danilo Krummrich <dakr@kernel.org> |
| 23370 | R: Lorenzo Stoakes <ljs@kernel.org> | 23404 | R: Lorenzo Stoakes <ljs@kernel.org> |
| 23371 | R: Vlastimil Babka <vbabka@kernel.org> | 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 | R: Uladzislau Rezki <urezki@gmail.com> | 23407 | R: Uladzislau Rezki <urezki@gmail.com> |
| 23374 | L: rust-for-linux@vger.kernel.org | 23408 | L: rust-for-linux@vger.kernel.org |
| 23375 | S: Maintained | 23409 | S: Maintained |
| @@ -23521,7 +23555,7 @@ F: drivers/s390/net/ · 145 unmodified lines | |||
| 23521 | 23555 | ||
| 23522 | S390 PCI SUBSYSTEM | 23556 | S390 PCI SUBSYSTEM |
| 23523 | M: Niklas Schnelle <schnelle@linux.ibm.com> | 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 | L: linux-s390@vger.kernel.org | 23559 | L: linux-s390@vger.kernel.org |
| 23526 | S: Supported | 23560 | S: Supported |
| 23527 | F: Documentation/arch/s390/pci.rst | 23561 | F: Documentation/arch/s390/pci.rst |
| @@ -24314,7 +24348,7 @@ F: include/media/i2c/rj54n1cb0c.h · 786 unmodified lines | |||
| 24314 | SHRINKER | 24348 | SHRINKER |
| 24315 | M: Andrew Morton <akpm@linux-foundation.org> | 24349 | M: Andrew Morton <akpm@linux-foundation.org> |
| 24316 | M: Dave Chinner <david@fromorbit.com> | 24350 | M: Dave Chinner <david@fromorbit.com> |
| 24317 | R: Qi Zheng <zhengqi.arch@bytedance.com> | 24351 | R: Qi Zheng <qi.zheng@linux.dev> |
| 24318 | R: Roman Gushchin <roman.gushchin@linux.dev> | 24352 | R: Roman Gushchin <roman.gushchin@linux.dev> |
| 24319 | R: Muchun Song <muchun.song@linux.dev> | 24353 | R: Muchun Song <muchun.song@linux.dev> |
| 24320 | L: linux-mm@kvack.org | 24354 | L: linux-mm@kvack.org |
| @@ -24764,6 +24798,7 @@ SOFTWARE RAID (Multiple Disks) SUPPORT · 443 unmodified lines | |||
| 24764 | M: Song Liu <song@kernel.org> | 24798 | M: Song Liu <song@kernel.org> |
| 24765 | M: Yu Kuai <yukuai@fnnas.com> | 24799 | M: Yu Kuai <yukuai@fnnas.com> |
| 24766 | R: Li Nan <linan122@huawei.com> | 24800 | R: Li Nan <linan122@huawei.com> |
| 24801 | R: Xiao Ni <xiao@kernel.org> | ||
| 24767 | L: linux-raid@vger.kernel.org | 24802 | L: linux-raid@vger.kernel.org |
| 24768 | S: Supported | 24803 | S: Supported |
| 24769 | Q: https://patchwork.kernel.org/project/linux-raid/list/ | 24804 | Q: https://patchwork.kernel.org/project/linux-raid/list/ |
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | VERSION = 7 | 2 | VERSION = 7 |
| 3 | PATCHLEVEL = 1 | 3 | PATCHLEVEL = 1 |
| 4 | SUBLEVEL = 0 | 4 | SUBLEVEL = 0 |
| 5 | EXTRAVERSION = -rc1 | 5 | EXTRAVERSION = -rc2 |
| 6 | NAME = Baby Opossum Posse | 6 | NAME = Baby Opossum Posse |
| 7 | 7 | ||
| 8 | # *DOCUMENTATION* | 8 | # *DOCUMENTATION* |
| @@ -40,7 +40,7 @@ static __always_inline void __pmr_local_irq_enable(void) · 39 unmodified lines | |||
| 40 | barrier(); | 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 | if (system_uses_irq_prio_masking()) { | 45 | if (system_uses_irq_prio_masking()) { |
| 46 | __pmr_local_irq_enable(); | 46 | __pmr_local_irq_enable(); |
| @@ -68,7 +68,7 @@ static __always_inline void __pmr_local_irq_disable(void) · 21 unmodified lines | |||
| 68 | barrier(); | 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 | if (system_uses_irq_prio_masking()) { | 73 | if (system_uses_irq_prio_masking()) { |
| 74 | __pmr_local_irq_disable(); | 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 | * Save the current interrupt enable state. | 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 | if (system_uses_irq_prio_masking()) { | 95 | if (system_uses_irq_prio_masking()) { |
| 96 | return __pmr_local_save_flags(); | 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 | return flags != GIC_PRIO_IRQON; | 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 | if (system_uses_irq_prio_masking()) { | 114 | if (system_uses_irq_prio_masking()) { |
| 115 | return __pmr_irqs_disabled_flags(flags); | 115 | return __pmr_irqs_disabled_flags(flags); |
| @@ -128,7 +128,7 @@ static __always_inline bool __pmr_irqs_disabled(void) · 12 unmodified lines | |||
| 128 | return __pmr_irqs_disabled_flags(__pmr_local_save_flags()); | 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 | if (system_uses_irq_prio_masking()) { | 133 | if (system_uses_irq_prio_masking()) { |
| 134 | return __pmr_irqs_disabled(); | 134 | return __pmr_irqs_disabled(); |
| @@ -160,7 +160,7 @@ static __always_inline unsigned long __pmr_local_irq_save(void) · 25 unmodified lines | |||
| 160 | return flags; | 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 | if (system_uses_irq_prio_masking()) { | 165 | if (system_uses_irq_prio_masking()) { |
| 166 | return __pmr_local_irq_save(); | 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 | * restore saved IRQ state | 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 | if (system_uses_irq_prio_masking()) { | 192 | if (system_uses_irq_prio_masking()) { |
| 193 | __pmr_local_irq_restore(flags); | 193 | __pmr_local_irq_restore(flags); |
| @@ -68,7 +68,12 @@ · 67 unmodified lines | |||
| 68 | #define KERNEL_SEGMENT_COUNT 5 | 68 | #define KERNEL_SEGMENT_COUNT 5 |
| 69 | 69 | ||
| 70 | #if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN | 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 | * The initial ID map consists of the kernel image, mapped as two separate | 78 | * The initial ID map consists of the kernel image, mapped as two separate |
| 74 | * segments, and may appear misaligned wrt the swapper block size. This means | 79 | * segments, and may appear misaligned wrt the swapper block size. This means |
| @@ -50,6 +50,9 @@ · 49 unmodified lines | |||
| 50 | 50 | ||
| 51 | #include <linux/mm.h> | 51 | #include <linux/mm.h> |
| 52 | 52 | ||
| 53 | #define MARKER(m) \ | ||
| 54 | m, __after_##m = m - 1 | ||
| 55 | |||
| 53 | enum __kvm_host_smccc_func { | 56 | enum __kvm_host_smccc_func { |
| 54 | /* Hypercalls that are unavailable once pKVM has finalised. */ | 57 | /* Hypercalls that are unavailable once pKVM has finalised. */ |
| 55 | /* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */ | 58 | /* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */ |
| @@ -59,8 +62,10 @@ enum __kvm_host_smccc_func { · 3 unmodified lines | |||
| 59 | __KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs, | 62 | __KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs, |
| 60 | __KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs, | 63 | __KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs, |
| 61 | __KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config, | 64 | __KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config, |
| 65 | |||
| 66 | MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM), | ||
| 67 | |||
| 62 | __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize, | 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 | /* Hypercalls that are always available and common to [nh]VHE/pKVM. */ | 70 | /* Hypercalls that are always available and common to [nh]VHE/pKVM. */ |
| 66 | __KVM_HOST_SMCCC_FUNC___kvm_adjust_pc, | 71 | __KVM_HOST_SMCCC_FUNC___kvm_adjust_pc, |
| @@ -72,11 +77,20 @@ enum __kvm_host_smccc_func { · 5 unmodified lines | |||
| 72 | __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range, | 77 | __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range, |
| 73 | __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context, | 78 | __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context, |
| 74 | __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff, | 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 | __KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs, | 88 | __KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs, |
| 76 | __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs, | 89 | __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs, |
| 77 | __KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr, | 90 | __KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr, |
| 78 | __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr, | 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 | /* Hypercalls that are available only when pKVM has finalised. */ | 95 | /* Hypercalls that are available only when pKVM has finalised. */ |
| 82 | __KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp, | 96 | __KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp, |
| @@ -100,14 +114,8 @@ enum __kvm_host_smccc_func { · 17 unmodified lines | |||
| 100 | __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load, | 114 | __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load, |
| 101 | __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put, | 115 | __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put, |
| 102 | __KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid, | 116 | __KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid, |
| 103 | __KVM_HOST_SMCCC_FUNC___tracing_load, | 117 | |
| 104 | __KVM_HOST_SMCCC_FUNC___tracing_unload, | 118 | MARKER(__KVM_HOST_SMCCC_FUNC_MAX) |
| 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, | ||
| 111 | }; | 119 | }; |
| 112 | 120 | ||
| 113 | #define DECLARE_KVM_VHE_SYM(sym) extern char sym[] | 121 | #define DECLARE_KVM_VHE_SYM(sym) extern char sym[] |
| @@ -450,9 +450,6 @@ struct kvm_vcpu_fault_info { · 449 unmodified lines | |||
| 450 | r = __VNCR_START__ + ((VNCR_ ## r) / 8), \ | 450 | r = __VNCR_START__ + ((VNCR_ ## r) / 8), \ |
| 451 | __after_##r = __MAX__(__before_##r - 1, r) | 451 | __after_##r = __MAX__(__before_##r - 1, r) |
| 452 | 452 | ||
| 453 | #define MARKER(m) \ | ||
| 454 | m, __after_##m = m - 1 | ||
| 455 | |||
| 456 | enum vcpu_sysreg { | 453 | enum vcpu_sysreg { |
| 457 | __INVALID_SYSREG__, /* 0 is reserved as an invalid value */ | 454 | __INVALID_SYSREG__, /* 0 is reserved as an invalid value */ |
| 458 | MPIDR_EL1, /* MultiProcessor Affinity Register */ | 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 | #define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f)) | 1545 | #define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f)) |
| 1549 | #define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f)) | 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 | int kvm_trng_call(struct kvm_vcpu *vcpu); | 1550 | int kvm_trng_call(struct kvm_vcpu *vcpu); |
| 1554 | #ifdef CONFIG_KVM | 1551 | #ifdef CONFIG_KVM |
| @@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, · 195 unmodified lines | |||
| 196 | loc += *opcode++ * code_alignment_factor; | 196 | loc += *opcode++ * code_alignment_factor; |
| 197 | loc += (*opcode++ << 8) * code_alignment_factor; | 197 | loc += (*opcode++ << 8) * code_alignment_factor; |
| 198 | loc += (*opcode++ << 16) * code_alignment_factor; | 198 | loc += (*opcode++ << 16) * code_alignment_factor; |
| 199 | loc += (*opcode++ << 24) * code_alignment_factor; | 199 | loc += ((u64)*opcode++ << 24) * code_alignment_factor; |
| 200 | size -= 4; | 200 | size -= 4; |
| 201 | break; | 201 | break; |
| 202 | 202 | ||
| 203 | case DW_CFA_def_cfa: | 203 | case DW_CFA_def_cfa: |
| 204 | case DW_CFA_offset_extended: | 204 | case DW_CFA_offset_extended: |
| @@ -67,6 +67,9 @@ struct rt_sigframe_user_layout { · 66 unmodified lines | |||
| 67 | unsigned long end_offset; | 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 | * Holds any EL0-controlled state that influences unprivileged memory accesses. | 74 | * Holds any EL0-controlled state that influences unprivileged memory accesses. |
| 72 | * This includes both accesses done in userspace and uaccess done in the kernel. | 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 | * This state needs to be carefully managed to ensure that it doesn't cause | 77 | * This state needs to be carefully managed to ensure that it doesn't cause |
| 75 | * uaccess to fail when setting up the signal frame, and the signal handler | 78 | * uaccess to fail when setting up the signal frame, and the signal handler |
| 76 | * itself also expects a well-defined state when entered. | 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 | struct user_access_state { | 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) | 90 | #define UA_STATE_HAS_POR_EL0 BIT(0) |
| 83 | #define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16) | 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 | * Save the user access state into ua_state and reset it to disable any | 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 | for (int pkey = 0; pkey < arch_max_pkey(); pkey++) | 119 | for (int pkey = 0; pkey < arch_max_pkey(); pkey++) |
| 95 | por_enable_all |= POR_ELx_PERM_PREP(pkey, POE_RWX); | 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 | write_sysreg_s(por_enable_all, SYS_POR_EL0); | 123 | write_sysreg_s(por_enable_all, SYS_POR_EL0); |
| 99 | /* | 124 | /* |
| 100 | * No ISB required as we can tolerate spurious Overlay faults - | 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 | static void restore_user_access_state(const struct user_access_state *ua_state) | 148 | static void restore_user_access_state(const struct user_access_state *ua_state) |
| 124 | { | 149 | { |
| 125 | if (system_supports_poe()) | 150 | u64 por_el0; |
| 126 | write_sysreg_s(ua_state->por_el0, SYS_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 | static void init_user_layout(struct rt_sigframe_user_layout *user) | 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 | static int preserve_poe_context(struct poe_context __user *ctx, | 360 | static int preserve_poe_context(struct poe_context __user *ctx, |
| 334 | const struct user_access_state *ua_state) | 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 | __put_user_error(POE_MAGIC, &ctx->head.magic, err); | 370 | __put_user_error(POE_MAGIC, &ctx->head.magic, err); |
| 339 | __put_user_error(sizeof(*ctx), &ctx->head.size, err); | 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 | return err; | 374 | return err; |
| 343 | } | 375 | } |
| @@ -353,7 +385,7 @@ static int restore_poe_context(struct user_ctxs *user, · 9 unmodified lines | |||
| 353 | 385 | ||
| 354 | __get_user_error(por_el0, &(user->poe->por_el0), err); | 386 | __get_user_error(por_el0, &(user->poe->por_el0), err); |
| 355 | if (!err) | 387 | if (!err) |
| 356 | ua_state->por_el0 = por_el0; | 388 | set_ua_state_por_el0(ua_state, por_el0); |
| 357 | 389 | ||
| 358 | return err; | 390 | return err; |
| 359 | } | 391 | } |
| @@ -1095,7 +1127,7 @@ SYSCALL_DEFINE0(rt_sigreturn) · 735 unmodified lines | |||
| 1095 | { | 1127 | { |
| 1096 | struct pt_regs *regs = current_pt_regs(); | 1128 | struct pt_regs *regs = current_pt_regs(); |
| 1097 | struct rt_sigframe __user *frame; | 1129 | struct rt_sigframe __user *frame; |
| 1098 | struct user_access_state ua_state; | 1130 | struct user_access_state ua_state = {}; |
| 1099 | 1131 | ||
| 1100 | /* Always make any pending restarted system calls return -EINTR */ | 1132 | /* Always make any pending restarted system calls return -EINTR */ |
| 1101 | current->restart_block.fn = do_no_restart_syscall; | 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 | struct rt_sigframe_user_layout user; | 1540 | struct rt_sigframe_user_layout user; |
| 1509 | struct rt_sigframe __user *frame; | 1541 | struct rt_sigframe __user *frame; |
| 1510 | struct user_access_state ua_state; | 1542 | struct user_access_state ua_state = {}; |
| 1511 | int err = 0; | 1543 | int err = 0; |
| 1512 | 1544 | ||
| 1513 | fpsimd_save_and_flush_current_state(); | 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 | bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF | HCR_VSE); | 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 | return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) | 831 | return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) |
| 828 | && !kvm_arm_vcpu_stopped(v) && !v->arch.pause); | 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 | #define FEAT_SPE ID_AA64DFR0_EL1, PMSVer, IMP | 133 | #define FEAT_SPE ID_AA64DFR0_EL1, PMSVer, IMP |
| 134 | #define FEAT_SPE_FnE ID_AA64DFR0_EL1, PMSVer, V1P2 | ||
| 135 | #define FEAT_BRBE ID_AA64DFR0_EL1, BRBE, IMP | 134 | #define FEAT_BRBE ID_AA64DFR0_EL1, BRBE, IMP |
| 136 | #define FEAT_TRC_SR ID_AA64DFR0_EL1, TraceVer, IMP | 135 | #define FEAT_TRC_SR ID_AA64DFR0_EL1, TraceVer, IMP |
| 137 | #define FEAT_PMUv3 ID_AA64DFR0_EL1, PMUVer, IMP | 136 | #define FEAT_PMUv3 ID_AA64DFR0_EL1, PMUVer, IMP |
| @@ -192,7 +191,7 @@ struct reg_feat_map_desc { · 54 unmodified lines | |||
| 192 | #define FEAT_SRMASK ID_AA64MMFR4_EL1, SRMASK, IMP | 191 | #define FEAT_SRMASK ID_AA64MMFR4_EL1, SRMASK, IMP |
| 193 | #define FEAT_PoPS ID_AA64MMFR4_EL1, PoPS, IMP | 192 | #define FEAT_PoPS ID_AA64MMFR4_EL1, PoPS, IMP |
| 194 | #define FEAT_PFAR ID_AA64PFR1_EL1, PFAR, IMP | 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 | #define FEAT_PMUv3_SS ID_AA64DFR0_EL1, PMSS, IMP | 195 | #define FEAT_PMUv3_SS ID_AA64DFR0_EL1, PMSS, IMP |
| 197 | #define FEAT_SEBEP ID_AA64DFR0_EL1, SEBEP, IMP | 196 | #define FEAT_SEBEP ID_AA64DFR0_EL1, SEBEP, IMP |
| 198 | #define FEAT_EBEP ID_AA64DFR1_EL1, EBEP, IMP | 197 | #define FEAT_EBEP ID_AA64DFR1_EL1, EBEP, IMP |
| @@ -283,7 +282,7 @@ static bool feat_anerr(struct kvm *kvm) · 84 unmodified lines | |||
| 283 | static bool feat_sme_smps(struct kvm *kvm) | 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 | * look at the guest's view of SMIDR_EL1. Funnily enough, this | 286 | * look at the guest's view of SMIDR_EL1. Funnily enough, this |
| 288 | * is not captured in the JSON file, but only as a note in the | 287 | * is not captured in the JSON file, but only as a note in the |
| 289 | * ARM ARM. | 288 | * ARM ARM. |
| @@ -295,17 +294,27 @@ static bool feat_sme_smps(struct kvm *kvm) · 5 unmodified lines | |||
| 295 | static bool feat_spe_fds(struct kvm *kvm) | 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 | * look at the guest's view of PMSIDR_EL1. | 298 | * look at the guest's view of PMSIDR_EL1. |
| 300 | */ | 299 | */ |
| 301 | return (kvm_has_feat(kvm, FEAT_SPEv1p4) && | 300 | return (kvm_has_feat(kvm, FEAT_SPEv1p4) && |
| 302 | (read_sysreg_s(SYS_PMSIDR_EL1) & PMSIDR_EL1_FDS)); | 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 | static bool feat_trbe_mpam(struct kvm *kvm) | 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 | * this really should look at the guest's view of TRBIDR_EL1. | 318 | * this really should look at the guest's view of TRBIDR_EL1. |
| 310 | */ | 319 | */ |
| 311 | return (kvm_has_feat(kvm, FEAT_TRBE) && | 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 | HDFGRTR_EL2_PMBPTR_EL1 | | 546 | HDFGRTR_EL2_PMBPTR_EL1 | |
| 538 | HDFGRTR_EL2_PMBLIMITR_EL1, | 547 | HDFGRTR_EL2_PMBLIMITR_EL1, |
| 539 | FEAT_SPE), | 548 | FEAT_SPE), |
| 540 | NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE), | 549 | NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, feat_spe_fne), |
| 541 | NEEDS_FEAT(HDFGRTR_EL2_nBRBDATA | | 550 | NEEDS_FEAT(HDFGRTR_EL2_nBRBDATA | |
| 542 | HDFGRTR_EL2_nBRBCTL | | 551 | HDFGRTR_EL2_nBRBCTL | |
| 543 | HDFGRTR_EL2_nBRBIDR, | 552 | HDFGRTR_EL2_nBRBIDR, |
| @@ -605,7 +614,7 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = { · 61 unmodified lines | |||
| 605 | HDFGWTR_EL2_PMBPTR_EL1 | | 614 | HDFGWTR_EL2_PMBPTR_EL1 | |
| 606 | HDFGWTR_EL2_PMBLIMITR_EL1, | 615 | HDFGWTR_EL2_PMBLIMITR_EL1, |
| 607 | FEAT_SPE), | 616 | FEAT_SPE), |
| 608 | NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE), | 617 | NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, feat_spe_fne), |
| 609 | NEEDS_FEAT(HDFGWTR_EL2_nBRBDATA | | 618 | NEEDS_FEAT(HDFGWTR_EL2_nBRBDATA | |
| 610 | HDFGWTR_EL2_nBRBCTL, | 619 | HDFGWTR_EL2_nBRBCTL, |
| 611 | FEAT_BRBE), | 620 | FEAT_BRBE), |
| @@ -709,6 +709,14 @@ static const hcall_t host_hcall[] = { · 708 unmodified lines | |||
| 709 | HANDLE_FUNC(__kvm_tlb_flush_vmid_range), | 709 | HANDLE_FUNC(__kvm_tlb_flush_vmid_range), |
| 710 | HANDLE_FUNC(__kvm_flush_cpu_context), | 710 | HANDLE_FUNC(__kvm_flush_cpu_context), |
| 711 | HANDLE_FUNC(__kvm_timer_set_cntvoff), | 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 | HANDLE_FUNC(__vgic_v3_save_aprs), | 720 | HANDLE_FUNC(__vgic_v3_save_aprs), |
| 713 | HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs), | 721 | HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs), |
| 714 | HANDLE_FUNC(__vgic_v5_save_apr), | 722 | HANDLE_FUNC(__vgic_v5_save_apr), |
| @@ -735,22 +743,16 @@ static const hcall_t host_hcall[] = { · 20 unmodified lines | |||
| 735 | HANDLE_FUNC(__pkvm_vcpu_load), | 743 | HANDLE_FUNC(__pkvm_vcpu_load), |
| 736 | HANDLE_FUNC(__pkvm_vcpu_put), | 744 | HANDLE_FUNC(__pkvm_vcpu_put), |
| 737 | HANDLE_FUNC(__pkvm_tlb_flush_vmid), | 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 | static void handle_host_hcall(struct kvm_cpu_context *host_ctxt) | 748 | static void handle_host_hcall(struct kvm_cpu_context *host_ctxt) |
| 749 | { | 749 | { |
| 750 | DECLARE_REG(unsigned long, id, host_ctxt, 0); | 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 | hcall_t hfn; | 752 | hcall_t hfn; |
| 753 | 753 | ||
| 754 | BUILD_BUG_ON(ARRAY_SIZE(host_hcall) != __KVM_HOST_SMCCC_FUNC_MAX); | ||
| 755 | |||
| 754 | /* | 756 | /* |
| 755 | * If pKVM has been initialised then reject any calls to the | 757 | * If pKVM has been initialised then reject any calls to the |
| 756 | * early "privileged" hypercalls. Note that we cannot reject | 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 | if (static_branch_unlikely(&kvm_protected_mode_initialized)) { | 765 | if (static_branch_unlikely(&kvm_protected_mode_initialized)) { |
| 764 | hcall_min = __KVM_HOST_SMCCC_FUNC_MIN_PKVM; | 766 | hcall_min = __KVM_HOST_SMCCC_FUNC_MIN_PKVM; |
| 765 | } else { | 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 | id &= ~ARM_SMCCC_CALL_HINTS; | 771 | id &= ~ARM_SMCCC_CALL_HINTS; |
| 770 | id -= KVM_HOST_SMCCC_ID(0); | 772 | id -= KVM_HOST_SMCCC_ID(0); |
| 771 | 773 | ||
| 772 | if (unlikely(id < hcall_min || id > hcall_max || | 774 | if (unlikely(id < hcall_min || id >= hcall_max)) |
| 773 | id >= ARRAY_SIZE(host_hcall))) { | ||
| 774 | goto inval; | 775 | goto inval; |
| 775 | } | ||
| 776 | 776 | ||
| 777 | hfn = host_hcall[id]; | 777 | hfn = host_hcall[id]; |
| 778 | if (unlikely(!hfn)) | 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 | func_id &= ~ARM_SMCCC_CALL_HINTS; | 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 | handled = kvm_host_psci_handler(host_ctxt, func_id); | 813 | handled = kvm_host_psci_handler(host_ctxt, func_id); |
| 810 | if (!handled) | 814 | if (!handled) |
| @@ -266,7 +266,8 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle, · 265 unmodified lines | |||
| 266 | if (hyp_vm->kvm.created_vcpus <= vcpu_idx) | 266 | if (hyp_vm->kvm.created_vcpus <= vcpu_idx) |
| 267 | goto unlock; | 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 | if (!hyp_vcpu) | 271 | if (!hyp_vcpu) |
| 271 | goto unlock; | 272 | goto unlock; |
| 272 | 273 | ||
| @@ -860,12 +861,30 @@ err_unpin_kvm: · 587 unmodified lines | |||
| 860 | * the page-aligned size of 'struct pkvm_hyp_vcpu'. | 861 | * the page-aligned size of 'struct pkvm_hyp_vcpu'. |
| 861 | * Return 0 on success, negative error code on failure. | 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 | int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu, | 883 | int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu, |
| 864 | unsigned long vcpu_hva) | 884 | unsigned long vcpu_hva) |
| 865 | { | 885 | { |
| 866 | struct pkvm_hyp_vcpu *hyp_vcpu; | 886 | struct pkvm_hyp_vcpu *hyp_vcpu; |
| 867 | struct pkvm_hyp_vm *hyp_vm; | 887 | struct pkvm_hyp_vm *hyp_vm; |
| 868 | unsigned int idx; | ||
| 869 | int ret; | 888 | int ret; |
| 870 | 889 | ||
| 871 | hyp_vcpu = map_donated_memory(vcpu_hva, sizeof(*hyp_vcpu)); | 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 | if (ret) | 903 | if (ret) |
| 885 | goto unlock; | 904 | goto unlock; |
| 886 | 905 | ||
| 887 | idx = hyp_vcpu->vcpu.vcpu_idx; | 906 | ret = register_hyp_vcpu(hyp_vm, hyp_vcpu); |
| 888 | if (idx >= hyp_vm->kvm.created_vcpus) { | 907 | if (ret) { |
| 889 | ret = -EINVAL; | 908 | unpin_host_vcpu(host_vcpu); |
| 890 | goto unlock; | 909 | unpin_host_sve_state(hyp_vcpu); |
| 891 | } | ||
| 892 | |||
| 893 | if (hyp_vm->vcpus[idx]) { | ||
| 894 | ret = -EINVAL; | ||
| 895 | goto unlock; | ||
| 896 | } | 910 | } |
| 897 | |||
| 898 | hyp_vm->vcpus[idx] = hyp_vcpu; | ||
| 899 | unlock: | 911 | unlock: |
| 900 | hyp_spin_unlock(&vm_table_lock); | 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 | pkvm_pgtable.mm_ops = &pkvm_pgtable_mm_ops; | 313 | pkvm_pgtable.mm_ops = &pkvm_pgtable_mm_ops; |
| 314 | 314 | ||
| 315 | ret = fix_host_ownership(); | 315 | ret = fix_hyp_pgtable_refcnt(); |
| 316 | if (ret) | 316 | if (ret) |
| 317 | goto out; | 317 | goto out; |
| 318 | 318 | ||
| 319 | ret = fix_hyp_pgtable_refcnt(); | 319 | ret = hyp_create_fixmap(); |
| 320 | if (ret) | 320 | if (ret) |
| 321 | goto out; | 321 | goto out; |
| 322 | 322 | ||
| 323 | ret = hyp_create_fixmap(); | 323 | ret = fix_host_ownership(); |
| 324 | if (ret) | 324 | if (ret) |
| 325 | goto out; | 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 | * migration from old kernels to new kernels with legacy | 91 | * migration from old kernels to new kernels with legacy |
| 92 | * userspace. | 92 | * userspace. |
| 93 | */ | 93 | */ |
| 94 | reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg); | 94 | reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val); |
| 95 | switch (reg) { | 95 | switch (reg) { |
| 96 | case KVM_VGIC_IMP_REV_2: | 96 | case KVM_VGIC_IMP_REV_2: |
| 97 | case KVM_VGIC_IMP_REV_3: | 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 | if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK) | 194 | if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK) |
| 195 | return -EINVAL; | 195 | return -EINVAL; |
| 196 | 196 | ||
| 197 | reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg); | 197 | reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val); |
| 198 | switch (reg) { | 198 | switch (reg) { |
| 199 | case KVM_VGIC_IMP_REV_2: | 199 | case KVM_VGIC_IMP_REV_2: |
| 200 | case KVM_VGIC_IMP_REV_3: | 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 | char *buffer; | 1415 | char *buffer; |
| 1416 | 1416 | ||
| 1417 | if (!user_len) | ||
| 1418 | return ERR_PTR(-EINVAL); | ||
| 1419 | |||
| 1417 | buffer = memdup_user_nul(user_buf, user_len); | 1420 | buffer = memdup_user_nul(user_buf, user_len); |
| 1418 | if (IS_ERR(buffer)) | 1421 | if (IS_ERR(buffer)) |
| 1419 | return buffer; | 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 | char input_buf[1]; | 1587 | char input_buf[1]; |
| 1585 | int rc = user_len; | 1588 | int rc = user_len; |
| 1586 | 1589 | ||
| 1590 | if (!user_len) { | ||
| 1591 | rc = -EINVAL; | ||
| 1592 | goto out; | ||
| 1593 | } | ||
| 1594 | |||
| 1587 | if (user_len > 0x10000) | 1595 | if (user_len > 0x10000) |
| 1588 | user_len = 0x10000; | 1596 | user_len = 0x10000; |
| 1589 | if (*offset != 0) { | 1597 | if (*offset != 0) { |
| @@ -438,7 +438,7 @@ void do_secure_storage_access(struct pt_regs *regs) · 437 unmodified lines | |||
| 438 | panic("Unexpected PGM 0x3d with TEID bit 61=0"); | 438 | panic("Unexpected PGM 0x3d with TEID bit 61=0"); |
| 439 | } | 439 | } |
| 440 | if (is_kernel_fault(regs)) { | 440 | if (is_kernel_fault(regs)) { |
| 441 | folio = phys_to_folio(addr); | 441 | folio = virt_to_folio((void *)addr); |
| 442 | if (unlikely(!folio_try_get(folio))) | 442 | if (unlikely(!folio_try_get(folio))) |
| 443 | return; | 443 | return; |
| 444 | rc = uv_convert_from_secure(folio_to_phys(folio)); | 444 | rc = uv_convert_from_secure(folio_to_phys(folio)); |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | |||
| 7 | /* | 7 | /* |
| 8 | * This is set up by the setup-routine at boot-time | 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 | #define PARAM boot_params_page | 11 | #define PARAM boot_params_page |
| 12 | 12 | ||
| 13 | #define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000)) | 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 | auth = crypto_spawn_ahash_alg(&ctx->auth); | 390 | auth = crypto_spawn_ahash_alg(&ctx->auth); |
| 391 | auth_base = &auth->base; | 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 | err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), | 398 | err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), |
| 394 | crypto_attr_alg_name(tb[2]), 0, mask); | 399 | crypto_attr_alg_name(tb[2]), 0, mask); |
| 395 | if (err) | 400 | if (err) |
| @@ -605,15 +605,12 @@ static umode_t acpi_tad_attr_is_visible(struct kobject *kobj, · 604 unmodified lines | |||
| 605 | return 0; | 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 | .attrs = acpi_tad_attrs, | 609 | .attrs = acpi_tad_attrs, |
| 610 | .is_visible = acpi_tad_attr_is_visible, | 610 | .is_visible = acpi_tad_attr_is_visible, |
| 611 | }; | 611 | }; |
| 612 | 612 | ||
| 613 | static const struct attribute_group *acpi_tad_attr_groups[] = { | 613 | __ATTRIBUTE_GROUPS(acpi_tad); |
| 614 | &acpi_tad_attr_group, | ||
| 615 | NULL, | ||
| 616 | }; | ||
| 617 | 614 | ||
| 618 | #ifdef CONFIG_RTC_CLASS | 615 | #ifdef CONFIG_RTC_CLASS |
| 619 | /* RTC class device interface */ | 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 | acpi_tad_rt_to_tm(&rt, &tm_now); | 681 | acpi_tad_rt_to_tm(&rt, &tm_now); |
| 685 | 682 | ||
| 686 | value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time), | 683 | value = rtc_tm_to_time64(&t->time) - rtc_tm_to_time64(&tm_now); |
| 687 | rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC); | 684 | if (value <= 0 || value >= U32_MAX) |
| 688 | if (value <= 0 || value > U32_MAX) | ||
| 689 | return -EINVAL; | 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 | if (retval != ACPI_TAD_WAKE_DISABLED) { | 745 | if (retval != ACPI_TAD_WAKE_DISABLED) { |
| 750 | t->enabled = 1; | 746 | t->enabled = 1; |
| 751 | t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now), | 747 | rtc_time64_to_tm(rtc_tm_to_time64(&tm_now) + retval, &t->time); |
| 752 | (u64)retval * NSEC_PER_SEC)); | ||
| 753 | } else { | 748 | } else { |
| 754 | t->enabled = 0; | 749 | t->enabled = 0; |
| 755 | t->time = tm_now; | 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 | return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED); | 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 | struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); | 796 | struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); |
| 802 | 797 | ||
| 803 | device_init_wakeup(dev, false); | 798 | device_init_wakeup(dev, false); |
| @@ -824,6 +819,7 @@ static int acpi_tad_probe(struct platform_device *pdev) · 20 unmodified lines | |||
| 824 | struct acpi_tad_driver_data *dd; | 819 | struct acpi_tad_driver_data *dd; |
| 825 | acpi_status status; | 820 | acpi_status status; |
| 826 | unsigned long long caps; | 821 | unsigned long long caps; |
| 822 | int ret; | ||
| 827 | 823 | ||
| 828 | /* | 824 | /* |
| 829 | * Initialization failure messages are mostly about firmware issues, so | 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 | 862 | * The platform bus type probe callback tells the ACPI PM domain to |
| 867 | * device, so set the runtime PM status of it to "active". | 863 | * power up the device, so set the runtime PM status of it to "active". |
| 868 | */ | 864 | */ |
| 869 | pm_runtime_set_active(dev); | 865 | pm_runtime_set_active(dev); |
| 870 | pm_runtime_enable(dev); | 866 | pm_runtime_enable(dev); |
| 871 | pm_runtime_suspend(dev); | 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 | if (caps & ACPI_TAD_RT) | 877 | if (caps & ACPI_TAD_RT) |
| 874 | acpi_tad_register_rtc(dev, caps); | 878 | acpi_tad_register_rtc(dev, caps); |
| 875 | 879 | ||
| @@ -885,10 +889,9 @@ static struct platform_driver acpi_tad_driver = { · 9 unmodified lines | |||
| 885 | .driver = { | 889 | .driver = { |
| 886 | .name = "acpi-tad", | 890 | .name = "acpi-tad", |
| 887 | .acpi_match_table = acpi_tad_ids, | 891 | .acpi_match_table = acpi_tad_ids, |
| 888 | .dev_groups = acpi_tad_attr_groups, | 892 | .dev_groups = acpi_tad_groups, |
| 889 | }, | 893 | }, |
| 890 | .probe = acpi_tad_probe, | 894 | .probe = acpi_tad_probe, |
| 891 | .remove = acpi_tad_remove, | ||
| 892 | }; | 895 | }; |
| 893 | MODULE_DEVICE_TABLE(acpi, acpi_tad_ids); | 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 | return NULL; | 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 | /* Execute instructions in trigger error action table */ | 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 | u64 param1, u64 param2) | 416 | u64 param1, u64 param2) |
| 407 | { | 417 | { |
| 408 | struct acpi_einj_trigger trigger_tab; | 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 | * This will cause resource conflict with regular memory. So | 490 | * This will cause resource conflict with regular memory. So |
| 481 | * remove it from trigger table resources. | 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 | struct apei_resources addr_resources; | 494 | struct apei_resources addr_resources; |
| 485 | 495 | ||
| 486 | apei_resources_init(&addr_resources); | 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 | return rc; | 670 | return rc; |
| 661 | trigger_paddr = apei_exec_ctx_get_output(&ctx); | 671 | trigger_paddr = apei_exec_ctx_get_output(&ctx); |
| 662 | if (notrigger == 0) { | 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 | if (rc) | 674 | if (rc) |
| 665 | return rc; | 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 | SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2))) | 728 | SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2))) |
| 719 | return -EINVAL; | 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 | /* check if type is a valid EINJv2 error type */ | 739 | /* check if type is a valid EINJv2 error type */ |
| 722 | if (is_v2) { | 740 | if (is_v2) { |
| 723 | if (!(type & available_error_type_v2)) | 741 | if (!(type & available_error_type_v2)) |
| 724 | return -EINVAL; | 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 | /* ensure param1/param2 existed */ | 745 | /* ensure param1/param2 existed */ |
| 732 | if (!(param_extension || acpi5)) | 746 | if (!(param_extension || acpi5)) |
| 733 | goto inject; | 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 | 750 | * We need extra sanity checks for memory errors. |
| 745 | * via the einj_cxl_rch_error_inject() path as that does the proper | 751 | * Other types leap directly to injection. |
| 746 | * validation of the given RCRB base (MMIO) address. | ||
| 747 | */ | 752 | */ |
| 748 | if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) | 753 | if (!is_memory_injection(type, flags)) |
| 749 | return -EINVAL; | 754 | goto inject; |
| 750 | 755 | ||
| 751 | /* | 756 | /* |
| 752 | * Disallow crazy address masks that give BIOS leeway to pick | 757 | * Disallow crazy address masks that give BIOS leeway to pick |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | static int psci_acpi_cpu_init_idle(unsigned int cpu) | 17 | static int psci_acpi_cpu_init_idle(unsigned int cpu) |
| 18 | { | 18 | { |
| 19 | int i, count; | 19 | int i; |
| 20 | struct acpi_lpi_state *lpi; | 20 | struct acpi_lpi_state *lpi; |
| 21 | struct acpi_processor *pr = per_cpu(processors, cpu); | 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 | if (!psci_ops.cpu_suspend) | 30 | if (!psci_ops.cpu_suspend) |
| 31 | return -EOPNOTSUPP; | 31 | return -EOPNOTSUPP; |
| 32 | 32 | ||
| 33 | count = pr->power.count - 1; | 33 | for (i = 1; i < pr->power.count; i++) { |
| 34 | if (count <= 0) | ||
| 35 | return -ENODEV; | ||
| 36 | |||
| 37 | for (i = 0; i < count; i++) { | ||
| 38 | u32 state; | 34 | u32 state; |
| 39 | 35 | ||
| 40 | lpi = &pr->power.lpi_states[i + 1]; | 36 | lpi = &pr->power.lpi_states[i]; |
| 41 | /* | 37 | /* |
| 42 | * Only bits[31:0] represent a PSCI power_state while | 38 | * Only bits[31:0] represent a PSCI power_state while |
| 43 | * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification | 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 | end: | 362 | end: |
| 363 | if (cmd == CMD_WRITE) { | 363 | if (cmd == CMD_WRITE) { |
| 364 | if (unlikely(ret)) { | 364 | if (unlikely(ret)) { |
| 365 | for_each_online_cpu(i) { | 365 | for_each_possible_cpu(i) { |
| 366 | struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i); | 366 | struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i); |
| 367 | 367 | ||
| 368 | if (!desc) | 368 | if (!desc) |
| @@ -524,13 +524,13 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data) · 155 unmodified lines | |||
| 524 | else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) | 524 | else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) |
| 525 | cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY; | 525 | cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY; |
| 526 | 526 | ||
| 527 | for_each_online_cpu(i) { | 527 | for_each_possible_cpu(i) { |
| 528 | if (i == cpu) | 528 | if (i == cpu) |
| 529 | continue; | 529 | continue; |
| 530 | 530 | ||
| 531 | match_cpc_ptr = per_cpu(cpc_desc_ptr, i); | 531 | match_cpc_ptr = per_cpu(cpc_desc_ptr, i); |
| 532 | if (!match_cpc_ptr) | 532 | if (!match_cpc_ptr) |
| 533 | goto err_fault; | 533 | continue; |
| 534 | 534 | ||
| 535 | match_pdomain = &(match_cpc_ptr->domain_info); | 535 | match_pdomain = &(match_cpc_ptr->domain_info); |
| 536 | if (match_pdomain->domain != pdomain->domain) | 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 | DMI_MATCH(DMI_PRODUCT_NAME, "82K8"), | 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 | * x86 android tablets which directly control the backlight through | 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 | kfree(pi); | 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 | static const struct bus_type pata_parport_bus_type = { | 462 | static const struct bus_type pata_parport_bus_type = { |
| 468 | .name = DRV_NAME, | 463 | .name = DRV_NAME, |
| 469 | }; | 464 | }; |
| 470 | 465 | ||
| 471 | static struct device pata_parport_bus = { | 466 | static struct device *pata_parport_bus; |
| 472 | .init_name = DRV_NAME, | ||
| 473 | .release = pata_parport_bus_release, | ||
| 474 | }; | ||
| 475 | 467 | ||
| 476 | static const struct scsi_host_template pata_parport_sht = { | 468 | static const struct scsi_host_template pata_parport_sht = { |
| 477 | PATA_PARPORT_SHT("pata_parport") | 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 | /* set up pi->dev before pi_probe_unit() so it can use dev_printk() */ | 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 | pi->dev.bus = &pata_parport_bus_type; | 514 | pi->dev.bus = &pata_parport_bus_type; |
| 523 | pi->dev.driver = &pr->driver; | 515 | pi->dev.driver = &pr->driver; |
| 524 | pi->dev.release = pata_parport_dev_release; | 516 | pi->dev.release = pata_parport_dev_release; |
| @@ -780,8 +772,9 @@ static __init int pata_parport_init(void) · 255 unmodified lines | |||
| 780 | return error; | 772 | return error; |
| 781 | } | 773 | } |
| 782 | 774 | ||
| 783 | error = device_register(&pata_parport_bus); | 775 | pata_parport_bus = root_device_register(DRV_NAME); |
| 784 | if (error) { | 776 | if (IS_ERR(pata_parport_bus)) { |
| 777 | error = PTR_ERR(pata_parport_bus); | ||
| 785 | pr_err("failed to register pata_parport bus, error: %d\n", error); | 778 | pr_err("failed to register pata_parport bus, error: %d\n", error); |
| 786 | goto out_unregister_bus; | 779 | goto out_unregister_bus; |
| 787 | } | 780 | } |
| @@ -811,7 +804,7 @@ out_remove_del: · 23 unmodified lines | |||
| 811 | out_remove_new: | 804 | out_remove_new: |
| 812 | bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device); | 805 | bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device); |
| 813 | out_unregister_dev: | 806 | out_unregister_dev: |
| 814 | device_unregister(&pata_parport_bus); | 807 | root_device_unregister(pata_parport_bus); |
| 815 | out_unregister_bus: | 808 | out_unregister_bus: |
| 816 | bus_unregister(&pata_parport_bus_type); | 809 | bus_unregister(&pata_parport_bus_type); |
| 817 | return error; | 810 | return error; |
| @@ -822,7 +815,7 @@ static __exit void pata_parport_exit(void) · 4 unmodified lines | |||
| 822 | parport_unregister_driver(&pata_parport_driver); | 815 | parport_unregister_driver(&pata_parport_driver); |
| 823 | bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device); | 816 | bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device); |
| 824 | bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device); | 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 | bus_unregister(&pata_parport_bus_type); | 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 | ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size); | 172 | ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size); |
| 173 | if (ret == -ENODATA) { | 173 | if (ret == -ENODATA) { |
| 174 | if (!deferrable) | 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 | ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx); | 177 | ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx); |
| 178 | if (ret) | 178 | if (ret) |
| @@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) · 630 unmodified lines | |||
| 631 | 631 | ||
| 632 | WARN_ON(!cdo->generic_packet); | 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 | cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); | 644 | cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); |
| 635 | mutex_lock(&cdrom_mutex); | 645 | mutex_lock(&cdrom_mutex); |
| 636 | list_add(&cdi->list, &cdrom_list); | 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 | return 0; | 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 | static int cdrom_media_erasable(struct cdrom_device_info *cdi) | 793 | static int cdrom_media_erasable(struct cdrom_device_info *cdi) |
| 746 | { | 794 | { |
| 747 | disc_information di; | 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 | static int cdrom_open_write(struct cdrom_device_info *cdi) | 943 | static int cdrom_open_write(struct cdrom_device_info *cdi) |
| 896 | { | 944 | { |
| 897 | int mrw, mrw_write, ram_write; | ||
| 898 | int ret = 1; | 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 | if (CDROM_CAN(CDC_MRW_W)) | 947 | if (CDROM_CAN(CDC_MRW_W)) |
| 925 | ret = cdrom_mrw_open_write(cdi); | 948 | ret = cdrom_mrw_open_write(cdi); |
| 926 | else if (CDROM_CAN(CDC_DVD_RAM)) | 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 | return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); | 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 | int __dpll_pin_change_ntf(struct dpll_pin *pin) | 911 | int __dpll_pin_change_ntf(struct dpll_pin *pin) |
| 904 | { | 912 | { |
| 913 | lockdep_assert_held(&dpll_lock); | ||
| 905 | dpll_pin_notify(pin, DPLL_PIN_CHANGED); | 914 | dpll_pin_notify(pin, DPLL_PIN_CHANGED); |
| 906 | return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); | 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 | * dpll_pin_change_ntf - notify that the pin has been changed | 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 | int dpll_pin_create_ntf(struct dpll_pin *pin); | 11 | int dpll_pin_create_ntf(struct dpll_pin *pin); |
| 12 | 12 | ||
| 13 | int dpll_pin_delete_ntf(struct dpll_pin *pin); | 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 | * that checks whether the PSP is running. A solution for those issues | 2839 | * that checks whether the PSP is running. A solution for those issues |
| 2840 | * in the APU is to trigger a GPU reset, but this should be done during | 2840 | * in the APU is to trigger a GPU reset, but this should be done during |
| 2841 | * the unload phase to avoid adding boot latency and screen flicker. | 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 | r = amdgpu_asic_reset(adev); | 2848 | r = amdgpu_asic_reset(adev); |
| 2845 | if (r) | 2849 | if (r) |
| 2846 | dev_err(adev->dev, "asic reset on %s failed\n", __func__); | 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 | case IP_VERSION(11, 5, 1): | 3090 | case IP_VERSION(11, 5, 1): |
| 3091 | case IP_VERSION(11, 5, 2): | 3091 | case IP_VERSION(11, 5, 2): |
| 3092 | case IP_VERSION(11, 5, 3): | 3092 | case IP_VERSION(11, 5, 3): |
| 3093 | adev->family = AMDGPU_FAMILY_GC_11_5_0; | ||
| 3094 | break; | ||
| 3095 | case IP_VERSION(11, 5, 4): | 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 | break; | 3095 | break; |
| 3098 | case IP_VERSION(12, 0, 0): | 3096 | case IP_VERSION(12, 0, 0): |
| 3099 | case IP_VERSION(12, 0, 1): | 3097 | case IP_VERSION(12, 0, 1): |
| @@ -3158,8 +3158,10 @@ static int __init amdgpu_init(void) · 3157 unmodified lines | |||
| 3158 | amdgpu_register_atpx_handler(); | 3158 | amdgpu_register_atpx_handler(); |
| 3159 | amdgpu_acpi_detect(); | 3159 | amdgpu_acpi_detect(); |
| 3160 | 3160 | ||
| 3161 | /* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */ | 3161 | /* Ignore KFD init failures when CONFIG_HSA_AMD is not set. */ |
| 3162 | amdgpu_amdkfd_init(); | 3162 | r = amdgpu_amdkfd_init(); |
| 3163 | if (r && r != -ENOENT) | ||
| 3164 | goto error_fence; | ||
| 3163 | 3165 | ||
| 3164 | if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) { | 3166 | if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) { |
| 3165 | add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); | 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 | mc->gart_start = max_mc_address - mc->gart_size + 1; | 314 | mc->gart_start = max_mc_address - mc->gart_size + 1; |
| 315 | break; | 315 | break; |
| 316 | case AMDGPU_GART_PLACEMENT_LOW: | 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 | break; | 321 | break; |
| 319 | case AMDGPU_GART_PLACEMENT_BEST_FIT: | 322 | case AMDGPU_GART_PLACEMENT_BEST_FIT: |
| 320 | default: | 323 | default: |
| @@ -873,68 +873,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) · 872 unmodified lines | |||
| 873 | ? -EFAULT : 0; | 873 | ? -EFAULT : 0; |
| 874 | } | 874 | } |
| 875 | case AMDGPU_INFO_READ_MMR_REG: { | 875 | case AMDGPU_INFO_READ_MMR_REG: { |
| 876 | int ret = 0; | ||
| 877 | unsigned int n, alloc_size; | ||
| 878 | uint32_t *regs; | ||
| 879 | unsigned int se_num = (info->read_mmr_reg.instance >> | 876 | unsigned int se_num = (info->read_mmr_reg.instance >> |
| 880 | AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & | 877 | AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & |
| 881 | AMDGPU_INFO_MMR_SE_INDEX_MASK; | 878 | AMDGPU_INFO_MMR_SE_INDEX_MASK; |
| 882 | unsigned int sh_num = (info->read_mmr_reg.instance >> | 879 | unsigned int sh_num = (info->read_mmr_reg.instance >> |
| 883 | AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & | 880 | AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & |
| 884 | AMDGPU_INFO_MMR_SH_INDEX_MASK; | 881 | AMDGPU_INFO_MMR_SH_INDEX_MASK; |
| 885 | 882 | unsigned int alloc_size; | |
| 886 | if (!down_read_trylock(&adev->reset_domain->sem)) | 883 | uint32_t *regs; |
| 887 | return -ENOENT; | 884 | int ret; |
| 888 | 885 | ||
| 889 | /* set full masks if the userspace set all bits | 886 | /* set full masks if the userspace set all bits |
| 890 | * in the bitfields | 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 | se_num = 0xffffffff; | 890 | se_num = 0xffffffff; |
| 894 | } else if (se_num >= AMDGPU_GFX_MAX_SE) { | 891 | else if (se_num >= AMDGPU_GFX_MAX_SE) |
| 895 | ret = -EINVAL; | 892 | return -EINVAL; |
| 896 | goto out; | ||
| 897 | } | ||
| 898 | 893 | ||
| 899 | if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { | 894 | if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) |
| 900 | sh_num = 0xffffffff; | 895 | sh_num = 0xffffffff; |
| 901 | } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { | 896 | else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) |
| 902 | ret = -EINVAL; | 897 | return -EINVAL; |
| 903 | goto out; | ||
| 904 | } | ||
| 905 | 898 | ||
| 906 | if (info->read_mmr_reg.count > 128) { | 899 | if (info->read_mmr_reg.count > 128) |
| 907 | ret = -EINVAL; | 900 | return -EINVAL; |
| 908 | goto out; | ||
| 909 | } | ||
| 910 | 901 | ||
| 911 | regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); | 902 | regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), |
| 912 | if (!regs) { | 903 | GFP_KERNEL); |
| 913 | ret = -ENOMEM; | 904 | if (!regs) |
| 914 | goto out; | 905 | return -ENOMEM; |
| 915 | } | ||
| 916 | 906 | ||
| 907 | down_read(&adev->reset_domain->sem); | ||
| 917 | alloc_size = info->read_mmr_reg.count * sizeof(*regs); | 908 | alloc_size = info->read_mmr_reg.count * sizeof(*regs); |
| 918 | |||
| 919 | amdgpu_gfx_off_ctrl(adev, false); | 909 | amdgpu_gfx_off_ctrl(adev, false); |
| 910 | ret = 0; | ||
| 920 | for (i = 0; i < info->read_mmr_reg.count; i++) { | 911 | for (i = 0; i < info->read_mmr_reg.count; i++) { |
| 921 | if (amdgpu_asic_read_register(adev, se_num, sh_num, | 912 | if (amdgpu_asic_read_register(adev, se_num, sh_num, |
| 922 | info->read_mmr_reg.dword_offset + i, | 913 | info->read_mmr_reg.dword_offset + i, |
| 923 | ®s[i])) { | 914 | ®s[i])) { |
| 924 | DRM_DEBUG_KMS("unallowed offset %#x\n", | 915 | DRM_DEBUG_KMS("unallowed offset %#x\n", |
| 925 | info->read_mmr_reg.dword_offset + i); | 916 | info->read_mmr_reg.dword_offset + i); |
| 926 | kfree(regs); | ||
| 927 | amdgpu_gfx_off_ctrl(adev, true); | ||
| 928 | ret = -EFAULT; | 917 | ret = -EFAULT; |
| 929 | goto out; | 918 | break; |
| 930 | } | 919 | } |
| 931 | } | 920 | } |
| 932 | amdgpu_gfx_off_ctrl(adev, true); | 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 | up_read(&adev->reset_domain->sem); | 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 | return ret; | 929 | return ret; |
| 939 | } | 930 | } |
| 940 | case AMDGPU_INFO_DEV_INFO: { | 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 | if (!control || amdgpu_bad_page_threshold == 0) | 1950 | if (!control || amdgpu_bad_page_threshold == 0) |
| 1951 | return; | 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 | if (amdgpu_dpm_send_rma_reason(adev)) | 1954 | if (amdgpu_dpm_send_rma_reason(adev)) |
| 1955 | dev_warn(adev->dev, "Unable to send out-of-band RMA CPER"); | 1955 | dev_warn(adev->dev, "Unable to send out-of-band RMA CPER"); |
| 1956 | else | 1956 | else |
| @@ -75,6 +75,9 @@ static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, · 74 unmodified lines | |||
| 75 | unsigned int type, | 75 | unsigned int type, |
| 76 | uint64_t size_in_page) | 76 | uint64_t size_in_page) |
| 77 | { | 77 | { |
| 78 | if (!size_in_page) | ||
| 79 | return 0; | ||
| 80 | |||
| 78 | return ttm_range_man_init(&adev->mman.bdev, type, | 81 | return ttm_range_man_init(&adev->mman.bdev, type, |
| 79 | false, size_in_page); | 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 | msecs_to_jiffies(timeout_ms)); | 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 | static void amdgpu_userq_init_hang_detect_work(struct amdgpu_usermode_queue *queue) | 221 | static void amdgpu_userq_init_hang_detect_work(struct amdgpu_usermode_queue *queue) |
| 209 | { | 222 | { |
| 210 | INIT_DELAYED_WORK(&queue->hang_detect_work, amdgpu_userq_hang_detect_work); | 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 | #endif | 656 | #endif |
| 644 | amdgpu_userq_detect_and_reset_queues(uq_mgr); | 657 | amdgpu_userq_detect_and_reset_queues(uq_mgr); |
| 645 | r = amdgpu_userq_unmap_helper(queue); | 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 | atomic_dec(&uq_mgr->userq_count[queue->queue_type]); | 659 | atomic_dec(&uq_mgr->userq_count[queue->queue_type]); |
| 653 | amdgpu_userq_cleanup(queue); | 660 | amdgpu_userq_cleanup(queue); |
| 654 | mutex_unlock(&uq_mgr->userq_mutex); | 661 | mutex_unlock(&uq_mgr->userq_mutex); |
| @@ -1187,7 +1194,7 @@ retry_lock: · 532 unmodified lines | |||
| 1187 | bo = range->bo; | 1194 | bo = range->bo; |
| 1188 | ret = amdgpu_ttm_tt_get_user_pages(bo, range); | 1195 | ret = amdgpu_ttm_tt_get_user_pages(bo, range); |
| 1189 | if (ret) | 1196 | if (ret) |
| 1190 | goto unlock_all; | 1197 | goto free_ranges; |
| 1191 | } | 1198 | } |
| 1192 | 1199 | ||
| 1193 | invalidated = true; | 1200 | invalidated = true; |
| @@ -1214,6 +1221,7 @@ retry_lock: · 20 unmodified lines | |||
| 1214 | 1221 | ||
| 1215 | unlock_all: | 1222 | unlock_all: |
| 1216 | drm_exec_fini(&exec); | 1223 | drm_exec_fini(&exec); |
| 1224 | free_ranges: | ||
| 1217 | xa_for_each(&xa, tmp_key, range) { | 1225 | xa_for_each(&xa, tmp_key, range) { |
| 1218 | if (!range) | 1226 | if (!range) |
| 1219 | continue; | 1227 | continue; |
| @@ -156,6 +156,7 @@ void amdgpu_userq_reset_work(struct work_struct *work); · 155 unmodified lines | |||
| 156 | void amdgpu_userq_pre_reset(struct amdgpu_device *adev); | 156 | void amdgpu_userq_pre_reset(struct amdgpu_device *adev); |
| 157 | int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost); | 157 | int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost); |
| 158 | void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue); | 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 | int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, | 161 | int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, |
| 161 | struct amdgpu_usermode_queue *queue, | 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 | is_compute_context = vm->is_compute_context; | 3024 | is_compute_context = vm->is_compute_context; |
| 3025 | 3025 | ||
| 3026 | if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid, | 3026 | if (is_compute_context) { |
| 3027 | node_id, addr >> PAGE_SHIFT, ts, write_fault)) { | 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 | amdgpu_bo_unreserve(root); | 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 | amdgpu_bo_unref(&root); | 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 | addr /= AMDGPU_GPU_PAGE_SIZE; | 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 | DRM_DEBUG("IH: CP EOP\n"); | 6523 | DRM_DEBUG("IH: CP EOP\n"); |
| 6524 | 6524 | ||
| 6525 | if (adev->enable_mes && doorbell_offset) { | 6525 | if (adev->enable_mes && doorbell_offset) { |
| 6526 | struct amdgpu_usermode_queue *queue; | 6526 | amdgpu_userq_process_fence_irq(adev, doorbell_offset); |
| 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); | ||
| 6535 | } else { | 6527 | } else { |
| 6536 | me_id = (entry->ring_id & 0x0c) >> 2; | 6528 | me_id = (entry->ring_id & 0x0c) >> 2; |
| 6537 | pipe_id = (entry->ring_id & 0x03) >> 0; | 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 | DRM_DEBUG("IH: CP EOP\n"); | 4854 | DRM_DEBUG("IH: CP EOP\n"); |
| 4855 | 4855 | ||
| 4856 | if (adev->enable_mes && doorbell_offset) { | 4856 | if (adev->enable_mes && doorbell_offset) { |
| 4857 | struct xarray *xa = &adev->userq_doorbell_xa; | 4857 | amdgpu_userq_process_fence_irq(adev, doorbell_offset); |
| 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); | ||
| 4866 | } else { | 4858 | } else { |
| 4867 | me_id = (entry->ring_id & 0x0c) >> 2; | 4859 | me_id = (entry->ring_id & 0x0c) >> 2; |
| 4868 | pipe_id = (entry->ring_id & 0x03) >> 0; | 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 | DRM_DEBUG("IH: CP EOP\n"); | 3643 | DRM_DEBUG("IH: CP EOP\n"); |
| 3644 | 3644 | ||
| 3645 | if (adev->enable_mes && doorbell_offset) { | 3645 | if (adev->enable_mes && doorbell_offset) { |
| 3646 | struct xarray *xa = &adev->userq_doorbell_xa; | 3646 | amdgpu_userq_process_fence_irq(adev, doorbell_offset); |
| 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); | ||
| 3656 | } else { | 3647 | } else { |
| 3657 | me_id = (entry->ring_id & 0x0c) >> 2; | 3648 | me_id = (entry->ring_id & 0x0c) >> 2; |
| 3658 | pipe_id = (entry->ring_id & 0x03) >> 0; | 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 | mutex_unlock(&adev->grbm_idx_mutex); | 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 | static void gfx_v6_0_config_init(struct amdgpu_device *adev) | 1639 | static void gfx_v6_0_config_init(struct amdgpu_device *adev) |
| 1575 | { | 1640 | { |
| 1576 | adev->gfx.config.double_offchip_lds_buf = 0; | 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 | gfx_v6_0_tiling_mode_table_init(adev); | 1794 | gfx_v6_0_tiling_mode_table_init(adev); |
| 1730 | 1795 | ||
| 1731 | gfx_v6_0_setup_rb(adev); | 1796 | gfx_v6_0_setup_rb(adev); |
| 1797 | gfx_v6_0_setup_tcc(adev); | ||
| 1732 | 1798 | ||
| 1733 | gfx_v6_0_setup_spi(adev); | 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 | static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { | 802 | static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { |
| 803 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 803 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 804 | .align_mask = 0xf, | 804 | .align_mask = 0xf, |
| 805 | .no_user_fence = true, | ||
| 805 | .get_rptr = jpeg_v2_0_dec_ring_get_rptr, | 806 | .get_rptr = jpeg_v2_0_dec_ring_get_rptr, |
| 806 | .get_wptr = jpeg_v2_0_dec_ring_get_wptr, | 807 | .get_wptr = jpeg_v2_0_dec_ring_get_wptr, |
| 807 | .set_wptr = jpeg_v2_0_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { | 693 | static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { |
| 694 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 694 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 695 | .align_mask = 0xf, | 695 | .align_mask = 0xf, |
| 696 | .no_user_fence = true, | ||
| 696 | .get_rptr = jpeg_v2_5_dec_ring_get_rptr, | 697 | .get_rptr = jpeg_v2_5_dec_ring_get_rptr, |
| 697 | .get_wptr = jpeg_v2_5_dec_ring_get_wptr, | 698 | .get_wptr = jpeg_v2_5_dec_ring_get_wptr, |
| 698 | .set_wptr = jpeg_v2_5_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { | 725 | static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { |
| 725 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 726 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 726 | .align_mask = 0xf, | 727 | .align_mask = 0xf, |
| 728 | .no_user_fence = true, | ||
| 727 | .get_rptr = jpeg_v2_5_dec_ring_get_rptr, | 729 | .get_rptr = jpeg_v2_5_dec_ring_get_rptr, |
| 728 | .get_wptr = jpeg_v2_5_dec_ring_get_wptr, | 730 | .get_wptr = jpeg_v2_5_dec_ring_get_wptr, |
| 729 | .set_wptr = jpeg_v2_5_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { | 594 | static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { |
| 595 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 595 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 596 | .align_mask = 0xf, | 596 | .align_mask = 0xf, |
| 597 | .no_user_fence = true, | ||
| 597 | .get_rptr = jpeg_v3_0_dec_ring_get_rptr, | 598 | .get_rptr = jpeg_v3_0_dec_ring_get_rptr, |
| 598 | .get_wptr = jpeg_v3_0_dec_ring_get_wptr, | 599 | .get_wptr = jpeg_v3_0_dec_ring_get_wptr, |
| 599 | .set_wptr = jpeg_v3_0_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { | 759 | static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { |
| 760 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 760 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 761 | .align_mask = 0xf, | 761 | .align_mask = 0xf, |
| 762 | .no_user_fence = true, | ||
| 762 | .get_rptr = jpeg_v4_0_dec_ring_get_rptr, | 763 | .get_rptr = jpeg_v4_0_dec_ring_get_rptr, |
| 763 | .get_wptr = jpeg_v4_0_dec_ring_get_wptr, | 764 | .get_wptr = jpeg_v4_0_dec_ring_get_wptr, |
| 764 | .set_wptr = jpeg_v4_0_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { | 1219 | static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { |
| 1220 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 1220 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 1221 | .align_mask = 0xf, | 1221 | .align_mask = 0xf, |
| 1222 | .no_user_fence = true, | ||
| 1222 | .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, | 1223 | .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, |
| 1223 | .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, | 1224 | .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, |
| 1224 | .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { | 804 | static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { |
| 805 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 805 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 806 | .align_mask = 0xf, | 806 | .align_mask = 0xf, |
| 807 | .no_user_fence = true, | ||
| 807 | .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, | 808 | .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, |
| 808 | .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, | 809 | .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, |
| 809 | .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { | 680 | static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { |
| 681 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 681 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 682 | .align_mask = 0xf, | 682 | .align_mask = 0xf, |
| 683 | .no_user_fence = true, | ||
| 683 | .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, | 684 | .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, |
| 684 | .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, | 685 | .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, |
| 685 | .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { | 884 | static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { |
| 885 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 885 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 886 | .align_mask = 0xf, | 886 | .align_mask = 0xf, |
| 887 | .no_user_fence = true, | ||
| 887 | .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, | 888 | .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, |
| 888 | .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, | 889 | .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, |
| 889 | .set_wptr = jpeg_v5_0_1_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v5_0_2_dec_ring_vm_funcs = { | 703 | static const struct amdgpu_ring_funcs jpeg_v5_0_2_dec_ring_vm_funcs = { |
| 704 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 704 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 705 | .align_mask = 0xf, | 705 | .align_mask = 0xf, |
| 706 | .no_user_fence = true, | ||
| 706 | .get_rptr = jpeg_v5_0_2_dec_ring_get_rptr, | 707 | .get_rptr = jpeg_v5_0_2_dec_ring_get_rptr, |
| 707 | .get_wptr = jpeg_v5_0_2_dec_ring_get_wptr, | 708 | .get_wptr = jpeg_v5_0_2_dec_ring_get_wptr, |
| 708 | .set_wptr = jpeg_v5_0_2_dec_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = { | 661 | static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = { |
| 662 | .type = AMDGPU_RING_TYPE_VCN_JPEG, | 662 | .type = AMDGPU_RING_TYPE_VCN_JPEG, |
| 663 | .align_mask = 0xf, | 663 | .align_mask = 0xf, |
| 664 | .no_user_fence = true, | ||
| 664 | .get_rptr = jpeg_v5_3_0_dec_ring_get_rptr, | 665 | .get_rptr = jpeg_v5_3_0_dec_ring_get_rptr, |
| 665 | .get_wptr = jpeg_v5_3_0_dec_ring_get_wptr, | 666 | .get_wptr = jpeg_v5_3_0_dec_ring_get_wptr, |
| 666 | .set_wptr = jpeg_v5_3_0_dec_ring_set_wptr, | 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 | u32 doorbell_offset = entry->src_data[0]; | 1662 | u32 doorbell_offset = entry->src_data[0]; |
| 1663 | 1663 | ||
| 1664 | if (adev->enable_mes && doorbell_offset) { | 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 | doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; | 1665 | doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; |
| 1670 | 1666 | amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 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); | ||
| 1676 | } | 1667 | } |
| 1677 | 1668 | ||
| 1678 | return 0; | 1669 | return 0; |
| @@ -1594,17 +1594,8 @@ static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev, · 1593 unmodified lines | |||
| 1594 | u32 doorbell_offset = entry->src_data[0]; | 1594 | u32 doorbell_offset = entry->src_data[0]; |
| 1595 | 1595 | ||
| 1596 | if (adev->enable_mes && doorbell_offset) { | 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 | doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; | 1597 | doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; |
| 1602 | 1598 | amdgpu_userq_process_fence_irq(adev, doorbell_offset); | |
| 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); | ||
| 1608 | } | 1599 | } |
| 1609 | 1600 | ||
| 1610 | return 0; | 1601 | return 0; |
| @@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) · 241 unmodified lines | |||
| 242 | uint64_t addr; | 242 | uint64_t addr; |
| 243 | uint32_t size; | 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 | /* program the VCPU memory controller bits 0-27 */ | 249 | /* program the VCPU memory controller bits 0-27 */ |
| 246 | addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; | 250 | addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; |
| 247 | size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; | 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 | int i; | 288 | int i; |
| 285 | uint32_t keysel = adev->uvd.keyselect; | 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 | WREG32(mmUVD_FW_START, keysel); | 297 | WREG32(mmUVD_FW_START, keysel); |
| 288 | 298 | ||
| 289 | for (i = 0; i < 10; ++i) { | 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 | static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { | 2113 | static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { |
| 2114 | .type = AMDGPU_RING_TYPE_VCN_DEC, | 2114 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 2115 | .align_mask = 0xf, | 2115 | .align_mask = 0xf, |
| 2116 | .no_user_fence = true, | ||
| 2116 | .secure_submission_supported = true, | 2117 | .secure_submission_supported = true, |
| 2117 | .get_rptr = vcn_v2_0_dec_ring_get_rptr, | 2118 | .get_rptr = vcn_v2_0_dec_ring_get_rptr, |
| 2118 | .get_wptr = vcn_v2_0_dec_ring_get_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 2146 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 2146 | .align_mask = 0x3f, | 2147 | .align_mask = 0x3f, |
| 2147 | .nop = VCN_ENC_CMD_NO_OP, | 2148 | .nop = VCN_ENC_CMD_NO_OP, |
| 2149 | .no_user_fence = true, | ||
| 2148 | .get_rptr = vcn_v2_0_enc_ring_get_rptr, | 2150 | .get_rptr = vcn_v2_0_enc_ring_get_rptr, |
| 2149 | .get_wptr = vcn_v2_0_enc_ring_get_wptr, | 2151 | .get_wptr = vcn_v2_0_enc_ring_get_wptr, |
| 2150 | .set_wptr = vcn_v2_0_enc_ring_set_wptr, | 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 | static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { | 1778 | static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { |
| 1779 | .type = AMDGPU_RING_TYPE_VCN_DEC, | 1779 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 1780 | .align_mask = 0xf, | 1780 | .align_mask = 0xf, |
| 1781 | .no_user_fence = true, | ||
| 1781 | .secure_submission_supported = true, | 1782 | .secure_submission_supported = true, |
| 1782 | .get_rptr = vcn_v2_5_dec_ring_get_rptr, | 1783 | .get_rptr = vcn_v2_5_dec_ring_get_rptr, |
| 1783 | .get_wptr = vcn_v2_5_dec_ring_get_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 1880 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1880 | .align_mask = 0x3f, | 1881 | .align_mask = 0x3f, |
| 1881 | .nop = VCN_ENC_CMD_NO_OP, | 1882 | .nop = VCN_ENC_CMD_NO_OP, |
| 1883 | .no_user_fence = true, | ||
| 1882 | .get_rptr = vcn_v2_5_enc_ring_get_rptr, | 1884 | .get_rptr = vcn_v2_5_enc_ring_get_rptr, |
| 1883 | .get_wptr = vcn_v2_5_enc_ring_get_wptr, | 1885 | .get_wptr = vcn_v2_5_enc_ring_get_wptr, |
| 1884 | .set_wptr = vcn_v2_5_enc_ring_set_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_DEC, | 1856 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 1857 | .align_mask = 0x3f, | 1857 | .align_mask = 0x3f, |
| 1858 | .nop = VCN_DEC_SW_CMD_NO_OP, | 1858 | .nop = VCN_DEC_SW_CMD_NO_OP, |
| 1859 | .no_user_fence = true, | ||
| 1859 | .secure_submission_supported = true, | 1860 | .secure_submission_supported = true, |
| 1860 | .get_rptr = vcn_v3_0_dec_ring_get_rptr, | 1861 | .get_rptr = vcn_v3_0_dec_ring_get_rptr, |
| 1861 | .get_wptr = vcn_v3_0_dec_ring_get_wptr, | 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 | for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { | 1974 | for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { |
| 1974 | uint32_t offset, size, *create; | 1975 | uint32_t offset, size, *create; |
| 1976 | uint64_t buf_end; | ||
| 1975 | 1977 | ||
| 1976 | if (msg[0] != RDECODE_MESSAGE_CREATE) | 1978 | if (msg[0] != RDECODE_MESSAGE_CREATE) |
| 1977 | continue; | 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 | offset = msg[1]; | 1981 | offset = msg[1]; |
| 1980 | size = msg[2]; | 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 | DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); | 1986 | DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); |
| 1984 | r = -EINVAL; | 1987 | r = -EINVAL; |
| 1985 | goto out; | 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 | static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { | 2039 | static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { |
| 2037 | .type = AMDGPU_RING_TYPE_VCN_DEC, | 2040 | .type = AMDGPU_RING_TYPE_VCN_DEC, |
| 2038 | .align_mask = 0xf, | 2041 | .align_mask = 0xf, |
| 2042 | .no_user_fence = true, | ||
| 2039 | .secure_submission_supported = true, | 2043 | .secure_submission_supported = true, |
| 2040 | .get_rptr = vcn_v3_0_dec_ring_get_rptr, | 2044 | .get_rptr = vcn_v3_0_dec_ring_get_rptr, |
| 2041 | .get_wptr = vcn_v3_0_dec_ring_get_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 2142 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 2139 | .align_mask = 0x3f, | 2143 | .align_mask = 0x3f, |
| 2140 | .nop = VCN_ENC_CMD_NO_OP, | 2144 | .nop = VCN_ENC_CMD_NO_OP, |
| 2145 | .no_user_fence = true, | ||
| 2141 | .get_rptr = vcn_v3_0_enc_ring_get_rptr, | 2146 | .get_rptr = vcn_v3_0_enc_ring_get_rptr, |
| 2142 | .get_wptr = vcn_v3_0_enc_ring_get_wptr, | 2147 | .get_wptr = vcn_v3_0_enc_ring_get_wptr, |
| 2143 | .set_wptr = vcn_v3_0_enc_ring_set_wptr, | 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 | for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { | 1890 | for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { |
| 1891 | uint32_t offset, size, *create; | 1891 | uint32_t offset, size, *create; |
| 1892 | uint64_t buf_end; | ||
| 1892 | 1893 | ||
| 1893 | if (msg[0] != RDECODE_MESSAGE_CREATE) | 1894 | if (msg[0] != RDECODE_MESSAGE_CREATE) |
| 1894 | continue; | 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 | offset = msg[1]; | 1897 | offset = msg[1]; |
| 1897 | size = msg[2]; | 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 | DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); | 1902 | DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); |
| 1901 | r = -EINVAL; | 1903 | r = -EINVAL; |
| 1902 | goto out; | 1904 | goto out; |
| @@ -1994,6 +1996,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { · 91 unmodified lines | |||
| 1994 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 1996 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1995 | .align_mask = 0x3f, | 1997 | .align_mask = 0x3f, |
| 1996 | .nop = VCN_ENC_CMD_NO_OP, | 1998 | .nop = VCN_ENC_CMD_NO_OP, |
| 1999 | .no_user_fence = true, | ||
| 1997 | .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), | 2000 | .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), |
| 1998 | .get_rptr = vcn_v4_0_unified_ring_get_rptr, | 2001 | .get_rptr = vcn_v4_0_unified_ring_get_rptr, |
| 1999 | .get_wptr = vcn_v4_0_unified_ring_get_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 1775 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1776 | .align_mask = 0x3f, | 1776 | .align_mask = 0x3f, |
| 1777 | .nop = VCN_ENC_CMD_NO_OP, | 1777 | .nop = VCN_ENC_CMD_NO_OP, |
| 1778 | .no_user_fence = true, | ||
| 1778 | .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, | 1779 | .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, |
| 1779 | .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, | 1780 | .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, |
| 1780 | .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 1483 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1484 | .align_mask = 0x3f, | 1484 | .align_mask = 0x3f, |
| 1485 | .nop = VCN_ENC_CMD_NO_OP, | 1485 | .nop = VCN_ENC_CMD_NO_OP, |
| 1486 | .no_user_fence = true, | ||
| 1486 | .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, | 1487 | .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, |
| 1487 | .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, | 1488 | .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, |
| 1488 | .set_wptr = vcn_v4_0_5_unified_ring_set_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 1207 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1208 | .align_mask = 0x3f, | 1208 | .align_mask = 0x3f, |
| 1209 | .nop = VCN_ENC_CMD_NO_OP, | 1209 | .nop = VCN_ENC_CMD_NO_OP, |
| 1210 | .no_user_fence = true, | ||
| 1210 | .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, | 1211 | .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, |
| 1211 | .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, | 1212 | .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, |
| 1212 | .set_wptr = vcn_v5_0_0_unified_ring_set_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 1419 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 1420 | .align_mask = 0x3f, | 1420 | .align_mask = 0x3f, |
| 1421 | .nop = VCN_ENC_CMD_NO_OP, | 1421 | .nop = VCN_ENC_CMD_NO_OP, |
| 1422 | .no_user_fence = true, | ||
| 1422 | .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, | 1423 | .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, |
| 1423 | .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, | 1424 | .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, |
| 1424 | .set_wptr = vcn_v5_0_1_unified_ring_set_wptr, | 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 | .type = AMDGPU_RING_TYPE_VCN_ENC, | 994 | .type = AMDGPU_RING_TYPE_VCN_ENC, |
| 995 | .align_mask = 0x3f, | 995 | .align_mask = 0x3f, |
| 996 | .nop = VCN_ENC_CMD_NO_OP, | 996 | .nop = VCN_ENC_CMD_NO_OP, |
| 997 | .no_user_fence = true, | ||
| 997 | .get_rptr = vcn_v5_0_2_unified_ring_get_rptr, | 998 | .get_rptr = vcn_v5_0_2_unified_ring_get_rptr, |
| 998 | .get_wptr = vcn_v5_0_2_unified_ring_get_wptr, | 999 | .get_wptr = vcn_v5_0_2_unified_ring_get_wptr, |
| 999 | .set_wptr = vcn_v5_0_2_unified_ring_set_wptr, | 1000 | .set_wptr = vcn_v5_0_2_unified_ring_set_wptr, |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
| 26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
| 27 | #include <linux/file.h> | 27 | #include <linux/file.h> |
| 28 | #include <linux/overflow.h> | ||
| 28 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
| 29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 30 | #include <linux/uaccess.h> | 31 | #include <linux/uaccess.h> |
| @@ -1695,6 +1696,16 @@ static int kfd_ioctl_smi_events(struct file *filep, · 1664 unmodified lines | |||
| 1695 | return kfd_smi_event_open(pdd->dev, &args->anon_fd); | 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 | #if IS_ENABLED(CONFIG_HSA_AMD_SVM) | 1709 | #if IS_ENABLED(CONFIG_HSA_AMD_SVM) |
| 1699 | 1710 | ||
| 1700 | static int kfd_ioctl_set_xnack_mode(struct file *filep, | 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 | #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \ | 3221 | #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \ |
| 3211 | [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \ | 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 | /** Ioctl table */ | 3229 | /** Ioctl table */ |
| 3215 | static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { | 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 | AMDKFD_IOCTL_DEF(AMDKFD_IOC_SMI_EVENTS, | 3321 | AMDKFD_IOCTL_DEF(AMDKFD_IOC_SMI_EVENTS, |
| 3307 | kfd_ioctl_smi_events, 0), | 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 | AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_XNACK_MODE, | 3327 | AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_XNACK_MODE, |
| 3312 | kfd_ioctl_set_xnack_mode, 0), | 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 | memset(kdata, 0, usize); | 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 | retcode = func(filep, process, kdata); | 3456 | retcode = func(filep, process, kdata); |
| 3435 | 3457 | ||
| 3436 | if (cmd & IOC_OUT) | 3458 | if (cmd & IOC_OUT) |
| @@ -1047,10 +1047,13 @@ extern struct srcu_struct kfd_processes_srcu; · 1046 unmodified lines | |||
| 1047 | typedef int amdkfd_ioctl_t(struct file *filep, struct kfd_process *p, | 1047 | typedef int amdkfd_ioctl_t(struct file *filep, struct kfd_process *p, |
| 1048 | void *data); | 1048 | void *data); |
| 1049 | 1049 | ||
| 1050 | typedef int amdkfd_ioctl_validate_t(void *kdata, unsigned int usize); | ||
| 1051 | |||
| 1050 | struct amdkfd_ioctl_desc { | 1052 | struct amdkfd_ioctl_desc { |
| 1051 | unsigned int cmd; | 1053 | unsigned int cmd; |
| 1052 | int flags; | 1054 | int flags; |
| 1053 | amdkfd_ioctl_t *func; | 1055 | amdkfd_ioctl_t *func; |
| 1056 | amdkfd_ioctl_validate_t *validate; | ||
| 1054 | unsigned int cmd_drv; | 1057 | unsigned int cmd_drv; |
| 1055 | const char *name; | 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 | pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last, | 1367 | pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last, |
| 1368 | gpu_start, gpu_end); | 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 | return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start, | 1375 | return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start, |
| 1370 | gpu_end, init_pte_value, 0, 0, NULL, NULL, | 1376 | gpu_end, init_pte_value, 0, 0, NULL, NULL, |
| 1371 | fence); | 1377 | fence); |
| @@ -1443,6 +1449,11 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, · 71 unmodified lines | |||
| 1443 | pr_debug("svms 0x%p [0x%lx 0x%lx] readonly %d\n", prange->svms, | 1449 | pr_debug("svms 0x%p [0x%lx 0x%lx] readonly %d\n", prange->svms, |
| 1444 | last_start, last_start + npages - 1, readonly); | 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 | for (i = offset; i < offset + npages; i++) { | 1457 | for (i = offset; i < offset + npages; i++) { |
| 1447 | uint64_t gpu_start; | 1458 | uint64_t gpu_start; |
| 1448 | uint64_t gpu_end; | 1459 | uint64_t gpu_end; |
| @@ -1903,7 +1903,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) · 1902 unmodified lines | |||
| 1903 | goto error; | 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 | init_data.asic_id.pci_revision_id = adev->pdev->revision; | 1912 | init_data.asic_id.pci_revision_id = adev->pdev->revision; |
| 1909 | init_data.asic_id.hw_internal_rev = adev->external_rev_id; | 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 | if (acrtc_state) { | 9408 | if (acrtc_state) { |
| 9405 | timing = &acrtc_state->stream->timing; | 9409 | timing = &acrtc_state->stream->timing; |
| 9406 | 9410 | ||
| 9407 | if (amdgpu_ip_version(adev, DCE_HWIP, 0) < | 9411 | if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= |
| 9408 | IP_VERSION(3, 5, 0) || | 9412 | IP_VERSION(3, 2, 0) && |
| 9409 | !(adev->flags & AMD_IS_APU)) { | 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 | * Older HW and DGPU have issues with instant off; | 9427 | * Older HW and DGPU have issues with instant off; |
| 9412 | * use a 2 frame offdelay. | 9428 | * use a 2 frame offdelay. |
| @@ -1032,6 +1032,45 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector) · 1031 unmodified lines | |||
| 1032 | return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector); | 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 | void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps) | 1074 | void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps) |
| 1036 | { | 1075 | { |
| 1037 | edid_caps->scdc_present = hdmi->scdc.supported; | 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 | if (link->aux_mode) | 1092 | if (link->aux_mode) |
| 1054 | ddc = &aconnector->dm_dp_aux.aux.ddc; | 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 | else | 1097 | else |
| 1056 | ddc = &aconnector->i2c->base; | 1098 | ddc = &aconnector->i2c->base; |
| 1057 | 1099 | ||
| @@ -1065,6 +1107,8 @@ enum dc_edid_status dm_helpers_read_local_edid( · 7 unmodified lines | |||
| 1065 | drm_edid = dm_helpers_read_acpi_edid(aconnector); | 1107 | drm_edid = dm_helpers_read_acpi_edid(aconnector); |
| 1066 | if (drm_edid) | 1108 | if (drm_edid) |
| 1067 | drm_info(connector->dev, "Using ACPI provided EDID for %s\n", connector->name); | 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 | else | 1112 | else |
| 1069 | drm_edid = drm_edid_read_ddc(connector, ddc); | 1113 | drm_edid = drm_edid_read_ddc(connector, ddc); |
| 1070 | drm_edid_connector_update(connector, drm_edid); | 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 | static enum bp_result bios_parser_dac_load_detection( | 795 | static enum bp_result bios_parser_dac_load_detection( |
| 796 | struct dc_bios *dcb, | 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 | struct bios_parser *bp = BP_FROM_DCB(dcb); | 800 | struct bios_parser *bp = BP_FROM_DCB(dcb); |
| 800 | struct dc_context *ctx = dcb->ctx; | 801 | struct dc_context *ctx = dcb->ctx; |
| 801 | struct bp_load_detection_parameters bp_params = {0}; | 802 | struct bp_load_detection_parameters bp_params = {0}; |
| 803 | struct bp_external_encoder_control ext_cntl = {0}; | ||
| 802 | enum bp_result bp_result = BP_RESULT_UNSUPPORTED; | 804 | enum bp_result bp_result = BP_RESULT_UNSUPPORTED; |
| 803 | uint32_t bios_0_scratch; | 805 | uint32_t bios_0_scratch; |
| 804 | uint32_t device_id_mask = 0; | 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 | bp_params.engine_id = engine_id; | 827 | bp_params.engine_id = engine_id; |
| 826 | bp_result = bp->cmd_tbl.dac_load_detection(bp, &bp_params); | 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 | if (bp_result != BP_RESULT_OK) | 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 | return BP_RESULT_FAILURE; | 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 | static enum bp_result get_embedded_panel_info_v1_2( | 1370 | static enum bp_result get_embedded_panel_info_v1_2( |
| 1308 | struct bios_parser *bp, | 1371 | struct bios_parser *bp, |
| 1309 | struct embedded_panel_info *info) | 1372 | struct embedded_panel_info *info) |
| @@ -1420,6 +1483,10 @@ static enum bp_result get_embedded_panel_info_v1_2( · 110 unmodified lines | |||
| 1420 | if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) | 1483 | if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) |
| 1421 | info->lcd_timing.misc_info.API_ENABLED = true; | 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 | return BP_RESULT_OK; | 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 | (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & | 1612 | (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & |
| 1546 | lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; | 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 | return BP_RESULT_OK; | 1619 | return BP_RESULT_OK; |
| 1549 | } | 1620 | } |
| 1550 | 1621 | ||
| @@ -1682,7 +1682,7 @@ struct dc_scratch_space { · 1681 unmodified lines | |||
| 1682 | struct dc_link_training_overrides preferred_training_settings; | 1682 | struct dc_link_training_overrides preferred_training_settings; |
| 1683 | struct dp_audio_test_data audio_test_data; | 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 | uint8_t hpd_src; | 1687 | uint8_t hpd_src; |
| 1688 | 1688 | ||
| @@ -102,7 +102,8 @@ struct dc_vbios_funcs { · 101 unmodified lines | |||
| 102 | struct bp_external_encoder_control *cntl); | 102 | struct bp_external_encoder_control *cntl); |
| 103 | enum bp_result (*dac_load_detection)( | 103 | enum bp_result (*dac_load_detection)( |
| 104 | struct dc_bios *bios, | 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 | enum bp_result (*transmitter_control)( | 107 | enum bp_result (*transmitter_control)( |
| 107 | struct dc_bios *bios, | 108 | struct dc_bios *bios, |
| 108 | struct bp_transmitter_control *cntl); | 109 | struct bp_transmitter_control *cntl); |
| @@ -1102,7 +1102,9 @@ void dce110_link_encoder_hw_init( · 1101 unmodified lines | |||
| 1102 | ASSERT(result == BP_RESULT_OK); | 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 | /* reinitialize HPD. | 1109 | /* reinitialize HPD. |
| 1108 | * hpd_initialize() will pass DIG_FE id to HW context. | 1110 | * hpd_initialize() will pass DIG_FE id to HW context. |
| @@ -40,8 +40,8 @@ · 39 unmodified lines | |||
| 40 | #define FN(reg_name, field_name) \ | 40 | #define FN(reg_name, field_name) \ |
| 41 | mcif_wb30->mcif_wb_shift->field_name, mcif_wb30->mcif_wb_mask->field_name | 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 | 43 | #define MCIF_ADDR(addr) ((uint32_t)((((unsigned long long)(addr) & 0xffffffffffULL) + 0xFEULL) >> 8)) |
| 44 | #define MCIF_ADDR_HIGH(addr) (unsigned long long)addr >> 40 | 44 | #define MCIF_ADDR_HIGH(addr) ((uint32_t)(((unsigned long long)(addr)) >> 40)) |
| 45 | 45 | ||
| 46 | /* wbif programming guide: | 46 | /* wbif programming guide: |
| 47 | * 1. set up wbif parameter: | 47 | * 1. set up wbif parameter: |
| @@ -646,6 +646,9 @@ failure: · 645 unmodified lines | |||
| 646 | enum gpio_ddc_line dal_ddc_get_line( | 646 | enum gpio_ddc_line dal_ddc_get_line( |
| 647 | const struct ddc *ddc) | 647 | const struct ddc *ddc) |
| 648 | { | 648 | { |
| 649 | if (!ddc) | ||
| 650 | return GPIO_DDC_LINE_UNKNOWN; | ||
| 651 | |||
| 649 | return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data); | 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 | static void | 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 | struct dc_bios *bios = link->ctx->dc_bios; | 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; | 696 | bp_result = bios->funcs->external_encoder_control(bios, &ext_cntl); |
| 675 | encoder_control.engine_id = link->link_enc->analog_engine; | 697 | |
| 676 | encoder_control.pixel_clock = pipe_ctx->stream->timing.pix_clk_100hz / 10; | 698 | if (bp_result != BP_RESULT_OK) |
| 677 | bios->funcs->encoder_control(bios, &encoder_control); | 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 | static bool | 709 | static bool |
| @@ -684,7 +713,8 @@ dce110_dac_load_detect(struct dc_link *link) · 3 unmodified lines | |||
| 684 | struct link_encoder *link_enc = link->link_enc; | 713 | struct link_encoder *link_enc = link->link_enc; |
| 685 | enum bp_result bp_result; | 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 | return bp_result == BP_RESULT_OK; | 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 | uint32_t early_control = 0; | 730 | uint32_t early_control = 0; |
| 701 | struct timing_generator *tg = pipe_ctx->stream_res.tg; | 731 | struct timing_generator *tg = pipe_ctx->stream_res.tg; |
| 702 | 732 | ||
| 703 | link_hwss->setup_stream_attribute(pipe_ctx); | ||
| 704 | link_hwss->setup_stream_encoder(pipe_ctx); | 733 | link_hwss->setup_stream_encoder(pipe_ctx); |
| 705 | 734 | ||
| 706 | dc->hwss.update_info_frame(pipe_ctx); | 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 | tg->funcs->set_early_control(tg, early_control); | 749 | tg->funcs->set_early_control(tg, early_control); |
| 721 | 750 | ||
| 722 | if (dc_is_rgb_signal(pipe_ctx->stream->signal)) | 751 | if (link->ext_enc_id.id) |
| 723 | dce110_dac_encoder_control(pipe_ctx, true); | 752 | dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_ENABLE, link, timing); |
| 724 | } | 753 | } |
| 725 | 754 | ||
| 726 | static enum bp_result link_transmitter_control( | 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 | link_enc->transmitter - TRANSMITTER_UNIPHY_A); | 1248 | link_enc->transmitter - TRANSMITTER_UNIPHY_A); |
| 1220 | } | 1249 | } |
| 1221 | 1250 | ||
| 1222 | if (dc_is_rgb_signal(pipe_ctx->stream->signal)) | 1251 | if (link->ext_enc_id.id) |
| 1223 | dce110_dac_encoder_control(pipe_ctx, false); | 1252 | dce110_external_encoder_control(EXTERNAL_ENCODER_CONTROL_DISABLE, link, NULL); |
| 1224 | } | 1253 | } |
| 1225 | 1254 | ||
| 1226 | void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, | 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 | return DC_OK; | 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 | enum dc_status dce110_apply_single_controller_ctx_to_hw( | 1636 | enum dc_status dce110_apply_single_controller_ctx_to_hw( |
| 1624 | struct pipe_ctx *pipe_ctx, | 1637 | struct pipe_ctx *pipe_ctx, |
| @@ -1639,10 +1652,6 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw( · 14 unmodified lines | |||
| 1639 | hws->funcs.disable_stream_gating(dc, pipe_ctx); | 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 | if (pipe_ctx->stream_res.audio != NULL) { | 1655 | if (pipe_ctx->stream_res.audio != NULL) { |
| 1647 | struct audio_output audio_output = {0}; | 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 | pipe_ctx->stream_res.tg->funcs->set_static_screen_control( | 1731 | pipe_ctx->stream_res.tg->funcs->set_static_screen_control( |
| 1723 | pipe_ctx->stream_res.tg, event_triggers, 2); | 1732 | pipe_ctx->stream_res.tg, event_triggers, 2); |
| 1724 | 1733 | ||
| 1725 | if (!dc_is_virtual_signal(pipe_ctx->stream->signal) && | 1734 | if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) |
| 1726 | !dc_is_rgb_signal(pipe_ctx->stream->signal)) | ||
| 1727 | pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( | 1735 | pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( |
| 1728 | pipe_ctx->stream_res.stream_enc, | 1736 | pipe_ctx->stream_res.stream_enc, |
| 1729 | pipe_ctx->stream_res.tg->inst); | 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 | link->phy_state.symclk_state = SYMCLK_ON_TX_ON; | 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 | void dce110_enable_dp_link_output( | 3396 | void dce110_enable_dp_link_output( |
| 3380 | struct dc_link *link, | 3397 | struct dc_link *link, |
| 3381 | const struct link_resource *link_res, | 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 | if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) { | 3448 | if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) { |
| 3427 | if (dc->clk_mgr->funcs->notify_link_rate_change) | 3449 | if (dc->clk_mgr->funcs->notify_link_rate_change) |
| 3428 | dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); | 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 | .enable_lvds_link_output = dce110_enable_lvds_link_output, | 3535 | .enable_lvds_link_output = dce110_enable_lvds_link_output, |
| 3514 | .enable_tmds_link_output = dce110_enable_tmds_link_output, | 3536 | .enable_tmds_link_output = dce110_enable_tmds_link_output, |
| 3515 | .enable_dp_link_output = dce110_enable_dp_link_output, | 3537 | .enable_dp_link_output = dce110_enable_dp_link_output, |
| 3538 | .enable_analog_link_output = dce110_enable_analog_link_output, | ||
| 3516 | .disable_link_output = dce110_disable_link_output, | 3539 | .disable_link_output = dce110_disable_link_output, |
| 3517 | .dac_load_detect = dce110_dac_load_detect, | 3540 | .dac_load_detect = dce110_dac_load_detect, |
| 3541 | .prepare_ddc = dce110_prepare_ddc, | ||
| 3518 | }; | 3542 | }; |
| 3519 | 3543 | ||
| 3520 | static const struct hwseq_private_funcs dce110_private_funcs = { | 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 | goto ddc_create_fail; | 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 | DC_ERROR("Failed to get I2C info for connector!\n"); | 574 | DC_ERROR("Failed to get I2C info for connector!\n"); |
| 573 | goto ddc_create_fail; | 575 | goto ddc_create_fail; |
| 574 | } | 576 | } |
| @@ -753,7 +753,8 @@ static struct link_encoder *dce60_link_encoder_create( · 752 unmodified lines | |||
| 753 | enc_init_data, | 753 | enc_init_data, |
| 754 | &link_enc_feature, | 754 | &link_enc_feature, |
| 755 | &link_enc_regs[link_regs_id], | 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 | enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? | 758 | enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? |
| 758 | NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); | 759 | NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); |
| 759 | return &enc110->base; | 760 | return &enc110->base; |
| @@ -760,7 +760,8 @@ static struct link_encoder *dce80_link_encoder_create( · 759 unmodified lines | |||
| 760 | enc_init_data, | 760 | enc_init_data, |
| 761 | &link_enc_feature, | 761 | &link_enc_feature, |
| 762 | &link_enc_regs[link_regs_id], | 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 | enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? | 765 | enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? |
| 765 | NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); | 766 | NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); |
| 766 | return &enc110->base; | 767 | return &enc110->base; |
| @@ -153,6 +153,10 @@ struct embedded_panel_info { · 152 unmodified lines | |||
| 153 | uint32_t drr_enabled; | 153 | uint32_t drr_enabled; |
| 154 | uint32_t min_drr_refresh_rate; | 154 | uint32_t min_drr_refresh_rate; |
| 155 | bool realtek_eDPToLVDS; | 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 | struct dc_firmware_info { | 162 | struct dc_firmware_info { |
| @@ -425,6 +425,7 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) · 424 unmodified lines | |||
| 425 | dpm_table->dpm_levels[0].enabled = true; | 425 | dpm_table->dpm_levels[0].enabled = true; |
| 426 | dpm_table->dpm_levels[1].value = pptable->GfxclkFmax; | 426 | dpm_table->dpm_levels[1].value = pptable->GfxclkFmax; |
| 427 | dpm_table->dpm_levels[1].enabled = true; | 427 | dpm_table->dpm_levels[1].enabled = true; |
| 428 | dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; | ||
| 428 | } else { | 429 | } else { |
| 429 | dpm_table->count = 1; | 430 | dpm_table->count = 1; |
| 430 | dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; | 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 | /* gfxclk dpm table setup */ | 1129 | /* gfxclk dpm table setup */ |
| 1130 | dpm_table = &dpm_context->dpm_tables.gfx_table; | 1130 | dpm_table = &dpm_context->dpm_tables.gfx_table; |
| 1131 | dpm_table->clk_type = SMU_GFXCLK; | 1131 | dpm_table->clk_type = SMU_GFXCLK; |
| 1132 | dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; | ||
| 1132 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { | 1133 | if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { |
| 1133 | /* In the case of gfxclk, only fine-grained dpm is honored. | 1134 | /* In the case of gfxclk, only fine-grained dpm is honored. |
| 1134 | * Get min/max values from FW. | 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 | level_index = 1; | 1370 | level_index = 1; |
| 1371 | } | 1371 | } |
| 1372 | 1372 | ||
| 1373 | if (!is_fine_grained) { | 1373 | if (!is_fine_grained || count == 1) { |
| 1374 | for (i = 0; i < count; i++) { | 1374 | for (i = 0; i < count; i++) { |
| 1375 | freq_match = !is_deep_sleep && | 1375 | freq_match = !is_deep_sleep && |
| 1376 | smu_cmn_freqs_match( | 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 | * @crtc: The displaying CRTC | 835 | * @crtc: The displaying CRTC |
| 836 | * @set_palette: Callback for programming the hardware gamma LUT | 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 | for (i = 0; i < info->num_planes; i++) { | 174 | for (i = 0; i < info->num_planes; i++) { |
| 175 | unsigned int width = mode_cmd->width / (i ? info->hsub : 1); | 175 | unsigned int width = drm_format_info_plane_width(info, mode_cmd->width, i); |
| 176 | unsigned int height = mode_cmd->height / (i ? info->vsub : 1); | 176 | unsigned int height = drm_format_info_plane_height(info, mode_cmd->height, i); |
| 177 | unsigned int min_size; | 177 | unsigned int min_size; |
| 178 | 178 | ||
| 179 | objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); | 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 | &pvr_fw_trace_fops); | 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 | &pvr_fw_trace_mask_fops); | 562 | &pvr_fw_trace_mask_fops); |
| 563 | } | 563 | } |
| @@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data) · 349 unmodified lines | |||
| 350 | struct pci_dev *pcidev = data; | 350 | struct pci_dev *pcidev = data; |
| 351 | 351 | ||
| 352 | pci_disable_device(pcidev); | 352 | pci_disable_device(pcidev); |
| 353 | pci_dev_put(pcidev); | ||
| 353 | } | 354 | } |
| 354 | 355 | ||
| 355 | static int ofdrm_device_init_pci(struct ofdrm_device *odev) | 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 | if (ret) { | 376 | if (ret) { |
| 376 | drm_err(dev, "pci_enable_device(%s) failed: %d\n", | 377 | drm_err(dev, "pci_enable_device(%s) failed: %d\n", |
| 377 | dev_name(&pcidev->dev), ret); | 378 | dev_name(&pcidev->dev), ret); |
| 379 | pci_dev_put(pcidev); | ||
| 378 | return ret; | 380 | return ret; |
| 379 | } | 381 | } |
| 380 | ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); | 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 | frames_size + | 353 | frames_size + |
| 354 | sizeof(struct appletbdrm_fb_request_footer), 16); | 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 | if (!appletbdrm_state->request) | 358 | if (!appletbdrm_state->request) |
| 359 | return -ENOMEM; | 359 | return -ENOMEM; |
| @@ -543,7 +543,7 @@ static void appletbdrm_primary_plane_destroy_state(struct drm_plane *plane, · 183 unmodified lines | |||
| 543 | { | 543 | { |
| 544 | struct appletbdrm_plane_state *appletbdrm_state = to_appletbdrm_plane_state(state); | 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 | kfree(appletbdrm_state->response); | 547 | kfree(appletbdrm_state->response); |
| 548 | 548 | ||
| 549 | __drm_gem_destroy_shadow_plane_state(&appletbdrm_state->base); | 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 | return unode->urb; | 285 | return unode->urb; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | #define GET_URB_TIMEOUT HZ | ||
| 289 | struct urb *udl_get_urb(struct udl_device *udl) | 288 | struct urb *udl_get_urb(struct udl_device *udl) |
| 290 | { | 289 | { |
| 291 | struct urb *urb; | 290 | struct urb *urb; |
| 292 | 291 | ||
| 293 | spin_lock_irq(&udl->urbs.lock); | 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 | spin_unlock_irq(&udl->urbs.lock); | 294 | spin_unlock_irq(&udl->urbs.lock); |
| 296 | return urb; | 295 | return urb; |
| 297 | } | 296 | } |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <drm/drm_gem_framebuffer_helper.h> | 21 | #include <drm/drm_gem_framebuffer_helper.h> |
| 22 | #include <drm/drm_gem_shmem_helper.h> | 22 | #include <drm/drm_gem_shmem_helper.h> |
| 23 | #include <drm/drm_modeset_helper_vtables.h> | 23 | #include <drm/drm_modeset_helper_vtables.h> |
| 24 | #include <drm/drm_print.h> | ||
| 24 | #include <drm/drm_probe_helper.h> | 25 | #include <drm/drm_probe_helper.h> |
| 25 | #include <drm/drm_vblank.h> | 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 | return; | 343 | return; |
| 343 | 344 | ||
| 344 | urb = udl_get_urb(udl); | 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 | goto out; | 348 | goto out; |
| 349 | } | ||
| 347 | 350 | ||
| 348 | buf = (char *)urb->transfer_buffer; | 351 | buf = (char *)urb->transfer_buffer; |
| 349 | buf = udl_vidreg_lock(buf); | 352 | buf = udl_vidreg_lock(buf); |
| @@ -88,6 +88,7 @@ xe-y += xe_bb.o \ · 87 unmodified lines | |||
| 88 | xe_irq.o \ | 88 | xe_irq.o \ |
| 89 | xe_late_bind_fw.o \ | 89 | xe_late_bind_fw.o \ |
| 90 | xe_lrc.o \ | 90 | xe_lrc.o \ |
| 91 | xe_mem_pool.o \ | ||
| 91 | xe_migrate.o \ | 92 | xe_migrate.o \ |
| 92 | xe_mmio.o \ | 93 | xe_mmio.o \ |
| 93 | xe_mmio_gem.o \ | 94 | xe_mmio_gem.o \ |
| @@ -583,7 +583,7 @@ · 582 unmodified lines | |||
| 583 | #define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32) | 583 | #define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32) |
| 584 | #define LSCFE_SAME_ADDRESS_ATOMICS_COALESCING_DISABLE REG_BIT(35 - 32) | 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 | #define CPSS_AWARE_DIS REG_BIT(3) | 587 | #define CPSS_AWARE_DIS REG_BIT(3) |
| 588 | 588 | ||
| 589 | #define SARB_CHICKEN1 XE_REG_MCR(0xe90c) | 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 | /* XE_BO_FLAG_GGTTx requires XE_BO_FLAG_GGTT also be set */ | 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 | return ERR_PTR(-EINVAL); | 2327 | return ERR_PTR(-EINVAL); |
| 2328 | } | ||
| 2327 | 2329 | ||
| 2328 | if (flags & (XE_BO_FLAG_VRAM_MASK | XE_BO_FLAG_STOLEN) && | 2330 | if (flags & (XE_BO_FLAG_VRAM_MASK | XE_BO_FLAG_STOLEN) && |
| 2329 | !(flags & XE_BO_FLAG_IGNORE_MIN_PAGE_SIZE) && | 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 | alignment = SZ_4K >> PAGE_SHIFT; | 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 | return ERR_PTR(-EINVAL); | 2349 | return ERR_PTR(-EINVAL); |
| 2350 | } | ||
| 2347 | 2351 | ||
| 2348 | if (!bo) { | 2352 | if (!bo) { |
| 2349 | bo = xe_bo_alloc(); | 2353 | bo = xe_bo_alloc(); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include "xe_ggtt_types.h" | 18 | #include "xe_ggtt_types.h" |
| 19 | 19 | ||
| 20 | struct xe_device; | 20 | struct xe_device; |
| 21 | struct xe_mem_pool_node; | ||
| 21 | struct xe_vm; | 22 | struct xe_vm; |
| 22 | 23 | ||
| 23 | #define XE_BO_MAX_PLACEMENTS 3 | 24 | #define XE_BO_MAX_PLACEMENTS 3 |
| @@ -88,7 +89,7 @@ struct xe_bo { · 64 unmodified lines | |||
| 88 | bool ccs_cleared; | 89 | bool ccs_cleared; |
| 89 | 90 | ||
| 90 | /** @bb_ccs: BB instructions of CCS read/write. Valid only for VF */ | 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 | * @cpu_caching: CPU caching mode. Currently only used for userspace | 95 | * @cpu_caching: CPU caching mode. Currently only used for userspace |
| @@ -258,6 +258,13 @@ out_unlock: · 257 unmodified lines | |||
| 258 | return ERR_PTR(ret); | 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 | static struct drm_gem_object * | 268 | static struct drm_gem_object * |
| 262 | xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, | 269 | xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, |
| 263 | struct dma_buf *dma_buf) | 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 | int ret = 0; | 278 | int ret = 0; |
| 272 | 279 | ||
| 273 | dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm); | 280 | dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm); |
| 274 | if (!dummy_obj) | 281 | if (!dummy_obj) { |
| 282 | xe_bo_free(storage); | ||
| 275 | return ERR_PTR(-ENOMEM); | 283 | return ERR_PTR(-ENOMEM); |
| 284 | } | ||
| 276 | 285 | ||
| 277 | dummy_obj->resv = resv; | 286 | dummy_obj->resv = resv; |
| 278 | xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {}, ret) { | 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 | if (ret) | 290 | if (ret) |
| 282 | break; | 291 | break; |
| 283 | 292 | ||
| 293 | /* xe_bo_init_locked() frees storage on error */ | ||
| 284 | bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size, | 294 | bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size, |
| 285 | 0, /* Will require 1way or 2way for vm_bind */ | 295 | 0, /* Will require 1way or 2way for vm_bind */ |
| 286 | ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec); | 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 | goto out_err; | 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 | obj = xe_dma_buf_init_obj(dev, bo, dma_buf); | 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 | return obj; | 388 | return obj; |
| 375 | 389 | } | |
| 376 | |||
| 377 | get_dma_buf(dma_buf); | 390 | get_dma_buf(dma_buf); |
| 378 | obj->import_attach = attach; | 391 | obj->import_attach = attach; |
| 379 | return obj; | 392 | return obj; |
| @@ -869,14 +869,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file) · 868 unmodified lines | |||
| 869 | struct xe_eu_stall_data_stream *stream = file->private_data; | 869 | struct xe_eu_stall_data_stream *stream = file->private_data; |
| 870 | struct xe_gt *gt = stream->gt; | 870 | struct xe_gt *gt = stream->gt; |
| 871 | 871 | ||
| 872 | drm_dev_put(>->tile->xe->drm); | ||
| 873 | |||
| 874 | mutex_lock(>->eu_stall->stream_lock); | 872 | mutex_lock(>->eu_stall->stream_lock); |
| 875 | xe_eu_stall_disable_locked(stream); | 873 | xe_eu_stall_disable_locked(stream); |
| 876 | xe_eu_stall_data_buf_destroy(stream); | 874 | xe_eu_stall_data_buf_destroy(stream); |
| 877 | xe_eu_stall_stream_free(stream); | 875 | xe_eu_stall_stream_free(stream); |
| 878 | mutex_unlock(>->eu_stall->stream_lock); | 876 | mutex_unlock(>->eu_stall->stream_lock); |
| 879 | 877 | ||
| 878 | drm_dev_put(>->tile->xe->drm); | ||
| 879 | |||
| 880 | return 0; | 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 | if (q->vm && q->hwe->hw_engine_group) { | 1405 | if (q->vm && q->hwe->hw_engine_group) { |
| 1406 | err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q); | 1406 | err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q); |
| 1407 | if (err) | 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 | /* user id alloc must always be last in ioctl to prevent UAF */ | 1416 | /* user id alloc must always be last in ioctl to prevent UAF */ |
| 1417 | err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL); | 1417 | err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL); |
| 1418 | if (err) | 1418 | if (err) |
| 1419 | goto kill_exec_queue; | 1419 | goto del_hw_engine_group; |
| 1420 | 1420 | ||
| 1421 | args->exec_queue_id = id; | 1421 | args->exec_queue_id = id; |
| 1422 | 1422 | ||
| 1423 | return 0; | 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 | kill_exec_queue: | 1428 | kill_exec_queue: |
| 1426 | xe_exec_queue_kill(q); | 1429 | xe_exec_queue_kill(q); |
| 1427 | delete_queue_group: | 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 | void xe_exec_queue_tlb_inval_last_fence_put_unlocked(struct xe_exec_queue *q, | 1763 | void xe_exec_queue_tlb_inval_last_fence_put_unlocked(struct xe_exec_queue *q, |
| 1761 | unsigned int type) | 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 | type == XE_EXEC_QUEUE_TLB_INVAL_PRIMARY_GT); | 1767 | type == XE_EXEC_QUEUE_TLB_INVAL_PRIMARY_GT); |
| 1765 | 1768 | ||
| 1766 | dma_fence_put(q->tlb_inval[type].last_fence); | 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 | &rd_offset); | 166 | &rd_offset); |
| 167 | if (err) { | 167 | if (err) { |
| 168 | xe_gt_err(gt, "HuC: invalid GSC reply for version query (err=%d)\n", err); | 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 | compat->major = version_query_rd(xe, &bo->vmap, rd_offset, proj_major); | 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 | static void guc_submit_fini(void *arg) | 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 | struct xe_guc *guc = arg; | 263 | struct xe_guc *guc = arg; |
| 277 | struct xe_exec_queue *q; | 264 | struct xe_exec_queue *q; |
| 278 | unsigned long index; | 265 | unsigned long index; |
| 279 | 266 | ||
| 267 | /* Drop any wedged queue refs */ | ||
| 280 | mutex_lock(&guc->submission_state.lock); | 268 | mutex_lock(&guc->submission_state.lock); |
| 281 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { | 269 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { |
| 282 | if (exec_queue_wedged(q)) { | 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 | mutex_unlock(&guc->submission_state.lock); | 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 | static const struct xe_exec_queue_ops guc_exec_queue_ops; | 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 | void xe_guc_submit_wedge(struct xe_guc *guc) | 1316 | void xe_guc_submit_wedge(struct xe_guc *guc) |
| 1321 | { | 1317 | { |
| 1322 | struct xe_device *xe = guc_to_xe(guc); | 1318 | struct xe_device *xe = guc_to_xe(guc); |
| 1323 | struct xe_gt *gt = guc_to_gt(guc); | ||
| 1324 | struct xe_exec_queue *q; | 1319 | struct xe_exec_queue *q; |
| 1325 | unsigned long index; | 1320 | unsigned long index; |
| 1326 | int err; | ||
| 1327 | 1321 | ||
| 1328 | xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode); | 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 | return; | 1329 | return; |
| 1336 | 1330 | ||
| 1337 | if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { | 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 | mutex_lock(&guc->submission_state.lock); | 1332 | mutex_lock(&guc->submission_state.lock); |
| 1348 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) | 1333 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) |
| 1349 | if (xe_exec_queue_get_unless_zero(q)) | 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 | if (xe_gt_WARN_ON(lrc->gt, max_len < 3)) | 1214 | if (xe_gt_WARN_ON(lrc->gt, max_len < 3)) |
| 1215 | return -ENOSPC; | 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 | *cmd++ = CS_DEBUG_MODE2(0).addr; | 1218 | *cmd++ = CS_DEBUG_MODE2(0).addr; |
| 1219 | *cmd++ = REG_MASKED_FIELD_ENABLE(INSTRUCTION_STATE_CACHE_INVALIDATE); | 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 | #include "xe_hw_engine.h" | 29 | #include "xe_hw_engine.h" |
| 30 | #include "xe_lrc.h" | 30 | #include "xe_lrc.h" |
| 31 | #include "xe_map.h" | 31 | #include "xe_map.h" |
| 32 | #include "xe_mem_pool.h" | ||
| 32 | #include "xe_mocs.h" | 33 | #include "xe_mocs.h" |
| 33 | #include "xe_printk.h" | 34 | #include "xe_printk.h" |
| 34 | #include "xe_pt.h" | 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 | u32 batch_size, batch_size_allocated; | 1167 | u32 batch_size, batch_size_allocated; |
| 1167 | struct xe_device *xe = gt_to_xe(gt); | 1168 | struct xe_device *xe = gt_to_xe(gt); |
| 1168 | struct xe_res_cursor src_it, ccs_it; | 1169 | struct xe_res_cursor src_it, ccs_it; |
| 1170 | struct xe_mem_pool *bb_pool; | ||
| 1169 | struct xe_sriov_vf_ccs_ctx *ctx; | 1171 | struct xe_sriov_vf_ccs_ctx *ctx; |
| 1170 | struct xe_sa_manager *bb_pool; | ||
| 1171 | u64 size = xe_bo_size(src_bo); | 1172 | u64 size = xe_bo_size(src_bo); |
| 1172 | struct xe_bb *bb = NULL; | 1173 | struct xe_mem_pool_node *bb; |
| 1173 | u64 src_L0, src_L0_ofs; | 1174 | u64 src_L0, src_L0_ofs; |
| 1175 | struct xe_bb xe_bb_tmp; | ||
| 1174 | u32 src_L0_pt; | 1176 | u32 src_L0_pt; |
| 1175 | int err; | 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 | size -= src_L0; | 1210 | size -= src_L0; |
| 1209 | } | 1211 | } |
| 1210 | 1212 | ||
| 1211 | bb = xe_bb_alloc(gt); | 1213 | bb = xe_mem_pool_alloc_node(); |
| 1212 | if (IS_ERR(bb)) | 1214 | if (IS_ERR(bb)) |
| 1213 | return PTR_ERR(bb); | 1215 | return PTR_ERR(bb); |
| 1214 | 1216 | ||
| 1215 | bb_pool = ctx->mem.ccs_bb_pool; | 1217 | bb_pool = ctx->mem.ccs_bb_pool; |
| 1216 | scoped_guard(mutex, xe_sa_bo_swap_guard(bb_pool)) { | 1218 | scoped_guard(mutex, xe_mem_pool_bo_swap_guard(bb_pool)) { |
| 1217 | xe_sa_bo_swap_shadow(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 | if (err) { | 1222 | if (err) { |
| 1221 | xe_gt_err(gt, "BB allocation failed.\n"); | 1223 | xe_gt_err(gt, "BB allocation failed.\n"); |
| 1222 | xe_bb_free(bb, NULL); | 1224 | kfree(bb); |
| 1223 | return err; | 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 | size = xe_bo_size(src_bo); | 1229 | size = xe_bo_size(src_bo); |
| 1228 | batch_size = 0; | 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 | * Emit PTE and copy commands here. | 1234 | * Emit PTE and copy commands here. |
| 1232 | * The CCS copy command can only support limited size. If the size to be | 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 | xe_assert(xe, IS_ALIGNED(ccs_it.start, PAGE_SIZE)); | 1258 | xe_assert(xe, IS_ALIGNED(ccs_it.start, PAGE_SIZE)); |
| 1256 | batch_size += EMIT_COPY_CCS_DW; | 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); | 1265 | xe_bb_tmp.len = emit_flush_invalidate(xe_bb_tmp.cs, xe_bb_tmp.len, |
| 1263 | flush_flags = xe_migrate_ccs_copy(m, bb, src_L0_ofs, src_is_pltt, | 1266 | flush_flags); |
| 1267 | flush_flags = xe_migrate_ccs_copy(m, &xe_bb_tmp, src_L0_ofs, src_is_pltt, | ||
| 1264 | src_L0_ofs, dst_is_pltt, | 1268 | src_L0_ofs, dst_is_pltt, |
| 1265 | src_L0, ccs_ofs, true); | 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 | size -= src_L0; | 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 | src_bo->bb_ccs[read_write] = bb; | 1278 | src_bo->bb_ccs[read_write] = bb; |
| 1273 | 1279 | ||
| 1274 | xe_sriov_vf_ccs_rw_update_bb_addr(ctx); | 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 | return 0; | 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 | void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, | 1303 | void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, |
| 1298 | enum xe_sriov_vf_ccs_rw_ctxs read_write) | 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 | struct xe_device *xe = xe_bo_device(src_bo); | 1307 | struct xe_device *xe = xe_bo_device(src_bo); |
| 1308 | struct xe_mem_pool *bb_pool; | ||
| 1302 | struct xe_sriov_vf_ccs_ctx *ctx; | 1309 | struct xe_sriov_vf_ccs_ctx *ctx; |
| 1303 | struct xe_sa_manager *bb_pool; | ||
| 1304 | u32 *cs; | 1310 | u32 *cs; |
| 1305 | 1311 | ||
| 1306 | xe_assert(xe, IS_SRIOV_VF(xe)); | 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 | ctx = &xe->sriov.vf.ccs.contexts[read_write]; | 1314 | ctx = &xe->sriov.vf.ccs.contexts[read_write]; |
| 1309 | bb_pool = ctx->mem.ccs_bb_pool; | 1315 | bb_pool = ctx->mem.ccs_bb_pool; |
| 1310 | 1316 | ||
| 1311 | guard(mutex) (xe_sa_bo_swap_guard(bb_pool)); | 1317 | scoped_guard(mutex, xe_mem_pool_bo_swap_guard(bb_pool)) { |
| 1312 | xe_sa_bo_swap_shadow(bb_pool); | 1318 | xe_mem_pool_swap_shadow_locked(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 | 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); | 1324 | xe_mem_pool_sync_shadow_locked(bb); |
| 1321 | src_bo->bb_ccs[read_write] = NULL; | 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 | static const struct xe_graphics_desc graphics_xe3p_lpg = { | 119 | static const struct xe_graphics_desc graphics_xe3p_lpg = { |
| 120 | XE2_GFX_FEATURES, | 120 | XE2_GFX_FEATURES, |
| 121 | .has_indirect_ring_state = 1, | ||
| 121 | .multi_queue_engine_class_mask = BIT(XE_ENGINE_CLASS_COPY) | BIT(XE_ENGINE_CLASS_COMPUTE), | 122 | .multi_queue_engine_class_mask = BIT(XE_ENGINE_CLASS_COPY) | BIT(XE_ENGINE_CLASS_COMPUTE), |
| 122 | .num_geometry_xecore_fuse_regs = 3, | 123 | .num_geometry_xecore_fuse_regs = 3, |
| 123 | .num_compute_xecore_fuse_regs = 3, | 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 | range_start = reg & REG_GENMASK(25, range_bit); | 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 | switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) { | 231 | switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) { |
| 232 | case RING_FORCE_TO_NONPRIV_ACCESS_RW: | 232 | case RING_FORCE_TO_NONPRIV_ACCESS_RW: |
| @@ -14,9 +14,9 @@ · 13 unmodified lines | |||
| 14 | #include "xe_guc.h" | 14 | #include "xe_guc.h" |
| 15 | #include "xe_guc_submit.h" | 15 | #include "xe_guc_submit.h" |
| 16 | #include "xe_lrc.h" | 16 | #include "xe_lrc.h" |
| 17 | #include "xe_mem_pool.h" | ||
| 17 | #include "xe_migrate.h" | 18 | #include "xe_migrate.h" |
| 18 | #include "xe_pm.h" | 19 | #include "xe_pm.h" |
| 19 | #include "xe_sa.h" | ||
| 20 | #include "xe_sriov_printk.h" | 20 | #include "xe_sriov_printk.h" |
| 21 | #include "xe_sriov_vf.h" | 21 | #include "xe_sriov_vf.h" |
| 22 | #include "xe_sriov_vf_ccs.h" | 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 | static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) | 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 | struct xe_device *xe = tile_to_xe(tile); | 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 | u64 bb_pool_size; | 147 | u64 bb_pool_size; |
| 147 | int offset, err; | 148 | int err; |
| 148 | 149 | ||
| 149 | bb_pool_size = get_ccs_bb_pool_size(xe); | 150 | bb_pool_size = get_ccs_bb_pool_size(xe); |
| 150 | xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n", | 151 | xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n", |
| 151 | ctx->ctx_id ? "Restore" : "Save", bb_pool_size / SZ_1M); | 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 | pool = xe_mem_pool_init(tile, bb_pool_size, sizeof(u32), |
| 154 | XE_SA_BO_MANAGER_FLAG_SHADOW); | 155 | XE_MEM_POOL_BO_FLAG_INIT_SHADOW_COPY); |
| 155 | 156 | if (IS_ERR(pool)) { | |
| 156 | if (IS_ERR(sa_manager)) { | 157 | xe_sriov_err(xe, "xe_mem_pool_init failed with error: %pe\n", |
| 157 | xe_sriov_err(xe, "Suballocator init failed with error: %pe\n", | 158 | pool); |
| 158 | sa_manager); | 159 | err = PTR_ERR(pool); |
| 159 | err = PTR_ERR(sa_manager); | ||
| 160 | return err; | 160 | return err; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | offset = 0; | 163 | pool_cpu_addr = xe_mem_pool_cpu_addr(pool); |
| 164 | xe_map_memset(xe, &sa_manager->bo->vmap, offset, MI_NOOP, | 164 | memset(pool_cpu_addr, 0, bb_pool_size); |
| 165 | bb_pool_size); | ||
| 166 | xe_map_memset(xe, &sa_manager->shadow->vmap, offset, MI_NOOP, | ||
| 167 | bb_pool_size); | ||
| 168 | 165 | ||
| 169 | offset = bb_pool_size - sizeof(u32); | 166 | last_dw_addr = pool_cpu_addr + (bb_pool_size / sizeof(u32)) - 1; |
| 170 | xe_map_wr(xe, &sa_manager->bo->vmap, offset, u32, MI_BATCH_BUFFER_END); | 167 | *last_dw_addr = MI_BATCH_BUFFER_END; |
| 171 | xe_map_wr(xe, &sa_manager->shadow->vmap, offset, u32, 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 | return 0; | 179 | return 0; |
| 176 | } | 180 | } |
| 177 | 181 | ||
| 178 | static void ccs_rw_update_ring(struct xe_sriov_vf_ccs_ctx *ctx) | 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 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); | 185 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); |
| 182 | u32 dw[10], i = 0; | 186 | u32 dw[10], i = 0; |
| 183 | 187 | ||
| @@ -388,7 +392,7 @@ err_ret: · 204 unmodified lines | |||
| 388 | #define XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET (2 * sizeof(u32)) | 392 | #define XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET (2 * sizeof(u32)) |
| 389 | void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx) | 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 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); | 396 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); |
| 393 | struct xe_device *xe = gt_to_xe(ctx->mig_q->gt); | 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 | struct xe_device *xe = xe_bo_device(bo); | 416 | struct xe_device *xe = xe_bo_device(bo); |
| 413 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; | 417 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; |
| 414 | struct xe_sriov_vf_ccs_ctx *ctx; | 418 | struct xe_sriov_vf_ccs_ctx *ctx; |
| 419 | struct xe_mem_pool_node *bb; | ||
| 415 | struct xe_tile *tile; | 420 | struct xe_tile *tile; |
| 416 | struct xe_bb *bb; | ||
| 417 | int err = 0; | 421 | int err = 0; |
| 418 | 422 | ||
| 419 | xe_assert(xe, IS_VF_CCS_READY(xe)); | 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 | struct xe_device *xe = xe_bo_device(bo); | 450 | struct xe_device *xe = xe_bo_device(bo); |
| 447 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; | 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 | xe_assert(xe, IS_VF_CCS_READY(xe)); | 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 | void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p) | 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 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; | 478 | enum xe_sriov_vf_ccs_rw_ctxs ctx_id; |
| 479 | struct xe_mem_pool *bb_pool; | ||
| 476 | 480 | ||
| 477 | if (!IS_VF_CCS_READY(xe)) | 481 | if (!IS_VF_CCS_READY(xe)) |
| 478 | return; | 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 | drm_printf(p, "ccs %s bb suballoc info\n", ctx_id ? "write" : "read"); | 490 | drm_printf(p, "ccs %s bb suballoc info\n", ctx_id ? "write" : "read"); |
| 487 | drm_printf(p, "-------------------------\n"); | 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 | drm_puts(p, "\n"); | 493 | drm_puts(p, "\n"); |
| 490 | } | 494 | } |
| 491 | } | 495 | } |
| @@ -17,9 +17,6 @@ enum xe_sriov_vf_ccs_rw_ctxs { · 16 unmodified lines | |||
| 17 | XE_SRIOV_VF_CCS_CTX_COUNT | 17 | XE_SRIOV_VF_CCS_CTX_COUNT |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | struct xe_migrate; | ||
| 21 | struct xe_sa_manager; | ||
| 22 | |||
| 23 | /** | 20 | /** |
| 24 | * struct xe_sriov_vf_ccs_ctx - VF CCS migration context data. | 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 | /** @mem: memory data */ | 30 | /** @mem: memory data */ |
| 34 | struct { | 31 | struct { |
| 35 | /** @mem.ccs_bb_pool: Pool from which batch buffers are allocated. */ | 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 | } mem; | 34 | } mem; |
| 38 | }; | 35 | }; |
| 39 | 36 | ||
| @@ -97,7 +97,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { · 96 unmodified lines | |||
| 97 | { XE_RTP_NAME("Tuning: Set STLB Bank Hash Mode to 4KB"), | 97 | { XE_RTP_NAME("Tuning: Set STLB Bank Hash Mode to 4KB"), |
| 98 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3510, XE_RTP_END_VERSION_UNDEFINED), | 98 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3510, XE_RTP_END_VERSION_UNDEFINED), |
| 99 | IS_INTEGRATED), | 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 | BANK_HASH_4KB_MODE)) | 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 | op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || | 3658 | op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || |
| 3659 | XE_IOCTL_DBG(xe, coh_mode == XE_COH_NONE && | 3659 | XE_IOCTL_DBG(xe, coh_mode == XE_COH_NONE && |
| 3660 | op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || | 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 | XE_IOCTL_DBG(xe, xe_device_is_l2_flush_optimized(xe) && | 3663 | XE_IOCTL_DBG(xe, xe_device_is_l2_flush_optimized(xe) && |
| 3662 | (op == DRM_XE_VM_BIND_OP_MAP_USERPTR || | 3664 | (op == DRM_XE_VM_BIND_OP_MAP_USERPTR || |
| 3663 | is_cpu_addr_mirror) && | 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 | int ret = 0; | 4158 | int ret = 0; |
| 4157 | 4159 | ||
| 4158 | if (XE_IOCTL_DBG(xe, (args->reserved[0] || args->reserved[1] || | 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 | return -EINVAL; | 4163 | return -EINVAL; |
| 4161 | 4164 | ||
| 4162 | vm = xe_vm_lookup(xef, args->vm_id); | 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 | return 0; | 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 | static bool check_bo_args_are_sane(struct xe_vm *vm, struct xe_vma **vmas, | 663 | static bool check_bo_args_are_sane(struct xe_vm *vm, struct xe_vma **vmas, |
| 625 | int num_vmas, u32 atomic_val) | 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 | if (madvise_range.has_bo_vmas) { | 800 | if (madvise_range.has_bo_vmas) { |
| 754 | if (args->type == DRM_XE_MEM_RANGE_ATTR_ATOMIC) { | 801 | if (args->type == DRM_XE_MEM_RANGE_ATTR_ATOMIC) { |
| 755 | if (!check_bo_args_are_sane(vm, madvise_range.vmas, | 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 | XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), | 743 | XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), |
| 744 | XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS)) | 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 | { XE_RTP_NAME("14021490052"), | 746 | { XE_RTP_NAME("14021490052"), |
| 755 | XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), | 747 | XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), |
| 756 | XE_RTP_ACTIONS(SET(FF_MODE, | 748 | XE_RTP_ACTIONS(SET(FF_MODE, |
| @@ -12,8 +12,6 @@ · 11 unmodified lines | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
| 14 | 14 | ||
| 15 | #include "mailbox.h" | ||
| 16 | |||
| 17 | /* | 15 | /* |
| 18 | * The maximum transmission size is 32 words or 128 bytes. | 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 | int index = cp->index, ret; | 403 | int index = cp->index, ret; |
| 406 | u32 val; | 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 | dev_name(priv->dev), chan); | 407 | dev_name(priv->dev), chan); |
| 410 | if (ret) { | 408 | if (ret) { |
| 411 | dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); | 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 | switch (cp->type) { | 413 | switch (cp->type) { |
| 416 | case CIX_MBOX_TYPE_DB: | 414 | case CIX_MBOX_TYPE_DB: |
| 417 | /* Overwrite txdone_method for DB channel */ | 415 | /* Overwrite txdone_method for DB channel */ |
| 418 | chan->txdone_method = TXDONE_BY_ACK; | 416 | chan->txdone_method = MBOX_TXDONE_BY_ACK; |
| 419 | fallthrough; | 417 | fallthrough; |
| 420 | case CIX_MBOX_TYPE_REG: | 418 | case CIX_MBOX_TYPE_REG: |
| 421 | if (priv->dir == CIX_MBOX_TX) { | 419 | if (priv->dir == CIX_MBOX_TX) { |
| @@ -99,7 +99,6 @@ static int exynos_mbox_probe(struct platform_device *pdev) · 98 unmodified lines | |||
| 99 | struct mbox_controller *mbox; | 99 | struct mbox_controller *mbox; |
| 100 | struct mbox_chan *chans; | 100 | struct mbox_chan *chans; |
| 101 | struct clk *pclk; | 101 | struct clk *pclk; |
| 102 | int i; | ||
| 103 | 102 | ||
| 104 | exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL); | 103 | exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL); |
| 105 | if (!exynos_mbox) | 104 | if (!exynos_mbox) |
| @@ -129,9 +128,6 @@ static int exynos_mbox_probe(struct platform_device *pdev) · 23 unmodified lines | |||
| 129 | mbox->ops = &exynos_mbox_chan_ops; | 128 | mbox->ops = &exynos_mbox_chan_ops; |
| 130 | mbox->of_xlate = exynos_mbox_of_xlate; | 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 | exynos_mbox->mbox = mbox; | 131 | exynos_mbox->mbox = mbox; |
| 136 | 132 | ||
| 137 | platform_set_drvdata(pdev, exynos_mbox); | 133 | platform_set_drvdata(pdev, exynos_mbox); |
| @@ -15,8 +15,6 @@ · 14 unmodified lines | |||
| 15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | 17 | ||
| 18 | #include "mailbox.h" | ||
| 19 | |||
| 20 | #define MBOX_CHAN_MAX 32 | 18 | #define MBOX_CHAN_MAX 32 |
| 21 | 19 | ||
| 22 | #define MBOX_RX 0x0 | 20 | #define MBOX_RX 0x0 |
| @@ -79,12 +79,12 @@ struct hi6220_mbox { · 78 unmodified lines | |||
| 79 | /* region for mailbox */ | 79 | /* region for mailbox */ |
| 80 | void __iomem *base; | 80 | void __iomem *base; |
| 81 | 81 | ||
| 82 | unsigned int chan_num; | ||
| 83 | struct hi6220_mbox_chan *mchan; | ||
| 84 | |||
| 85 | void *irq_map_chan[MBOX_CHAN_MAX]; | 82 | void *irq_map_chan[MBOX_CHAN_MAX]; |
| 86 | struct mbox_chan *chan; | 83 | struct mbox_chan *chan; |
| 87 | struct mbox_controller controller; | 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 | static void mbox_set_state(struct hi6220_mbox *mbox, | 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 | struct hi6220_mbox *mbox; | 267 | struct hi6220_mbox *mbox; |
| 268 | int i, err; | 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 | if (!mbox) | 271 | if (!mbox) |
| 272 | return -ENOMEM; | 272 | return -ENOMEM; |
| 273 | 273 | ||
| 274 | mbox->dev = dev; | ||
| 275 | mbox->chan_num = MBOX_CHAN_MAX; | 274 | mbox->chan_num = MBOX_CHAN_MAX; |
| 276 | mbox->mchan = devm_kcalloc(dev, | 275 | mbox->dev = dev; |
| 277 | mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL); | ||
| 278 | if (!mbox->mchan) | ||
| 279 | return -ENOMEM; | ||
| 280 | 276 | ||
| 281 | mbox->chan = devm_kcalloc(dev, | 277 | mbox->chan = devm_kcalloc(dev, |
| 282 | mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL); | 278 | mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL); |
| @@ -23,8 +23,6 @@ · 22 unmodified lines | |||
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
| 25 | 25 | ||
| 26 | #include "mailbox.h" | ||
| 27 | |||
| 28 | #define IMX_MU_CHANS 24 | 26 | #define IMX_MU_CHANS 24 |
| 29 | /* TX0/RX0/RXDB[0-3] */ | 27 | /* TX0/RX0/RXDB[0-3] */ |
| 30 | #define IMX_MU_SCU_CHANS 6 | 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 | p_chan = &mbox->chans[chan]; | 732 | p_chan = &mbox->chans[chan]; |
| 735 | 733 | ||
| 736 | if (type == IMX_MU_TYPE_TXDB_V2) | 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 | return p_chan; | 737 | return p_chan; |
| 740 | } | 738 | } |
| @@ -21,8 +21,6 @@ · 20 unmodified lines | |||
| 21 | #include <linux/property.h> | 21 | #include <linux/property.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | 23 | ||
| 24 | #include "mailbox.h" | ||
| 25 | |||
| 26 | #define STI_MBOX_INST_MAX 4 /* RAM saving: Max supported instances */ | 24 | #define STI_MBOX_INST_MAX 4 /* RAM saving: Max supported instances */ |
| 27 | #define STI_MBOX_CHAN_MAX 20 /* RAM saving: Max supported channels */ | 25 | #define STI_MBOX_CHAN_MAX 20 /* RAM saving: Max supported channels */ |
| 28 | 26 | ||
| @@ -28,8 +28,6 @@ · 27 unmodified lines | |||
| 28 | #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ | 28 | #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ |
| 29 | (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) | 29 | (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) |
| 30 | 30 | ||
| 31 | static bool mbox_data_ready; | ||
| 32 | |||
| 33 | struct mbox_test_device { | 31 | struct mbox_test_device { |
| 34 | struct device *dev; | 32 | struct device *dev; |
| 35 | void __iomem *tx_mmio; | 33 | void __iomem *tx_mmio; |
| @@ -42,6 +40,7 @@ struct mbox_test_device { · 6 unmodified lines | |||
| 42 | spinlock_t lock; | 40 | spinlock_t lock; |
| 43 | struct mutex mutex; | 41 | struct mutex mutex; |
| 44 | wait_queue_head_t waitq; | 42 | wait_queue_head_t waitq; |
| 43 | bool data_ready; | ||
| 45 | struct fasync_struct *async_queue; | 44 | struct fasync_struct *async_queue; |
| 46 | struct dentry *root_debugfs_dir; | 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 | unsigned long flags; | 161 | unsigned long flags; |
| 163 | 162 | ||
| 164 | spin_lock_irqsave(&tdev->lock, flags); | 163 | spin_lock_irqsave(&tdev->lock, flags); |
| 165 | data_ready = mbox_data_ready; | 164 | data_ready = tdev->data_ready; |
| 166 | spin_unlock_irqrestore(&tdev->lock, flags); | 165 | spin_unlock_irqrestore(&tdev->lock, flags); |
| 167 | 166 | ||
| 168 | return data_ready; | 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 | *(touser + l) = '\0'; | 226 | *(touser + l) = '\0'; |
| 228 | 227 | ||
| 229 | memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); | 228 | memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); |
| 230 | mbox_data_ready = false; | 229 | tdev->data_ready = false; |
| 231 | 230 | ||
| 232 | spin_unlock_irqrestore(&tdev->lock, flags); | 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 | message, MBOX_MAX_MSG_LEN); | 296 | message, MBOX_MAX_MSG_LEN); |
| 298 | memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); | 297 | memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); |
| 299 | } | 298 | } |
| 300 | mbox_data_ready = true; | 299 | tdev->data_ready = true; |
| 301 | spin_unlock_irqrestore(&tdev->lock, flags); | 300 | spin_unlock_irqrestore(&tdev->lock, flags); |
| 302 | 301 | ||
| 303 | wake_up_interruptible(&tdev->waitq); | 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 | client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); | 336 | client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); |
| 338 | if (!client) | 337 | if (!client) |
| 339 | return ERR_PTR(-ENOMEM); | 338 | return NULL; |
| 340 | 339 | ||
| 341 | client->dev = &pdev->dev; | 340 | client->dev = &pdev->dev; |
| 342 | client->rx_callback = mbox_test_receive_message; | 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 | return channel; | 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 | static int mbox_test_probe(struct platform_device *pdev) | 375 | static int mbox_test_probe(struct platform_device *pdev) |
| 359 | { | 376 | { |
| 360 | struct mbox_test_device *tdev; | 377 | struct mbox_test_device *tdev; |
| 361 | struct resource *res; | ||
| 362 | resource_size_t size; | ||
| 363 | int ret; | 378 | int ret; |
| 364 | 379 | ||
| 365 | tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); | 380 | tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); |
| 366 | if (!tdev) | 381 | if (!tdev) |
| 367 | return -ENOMEM; | 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 | /* It's okay for MMIO to be NULL */ | 390 | /* It's okay for MMIO to be NULL */ |
| 370 | tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); | 391 | tdev->tx_mmio = mbox_test_ioremap(pdev, 0); |
| 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 | } | ||
| 378 | 392 | ||
| 379 | /* If specified, second reg entry is Rx MMIO */ | 393 | /* If specified, second reg entry is Rx MMIO */ |
| 380 | tdev->rx_mmio = devm_platform_get_and_ioremap_resource(pdev, 1, &res); | 394 | tdev->rx_mmio = mbox_test_ioremap(pdev, 1); |
| 381 | if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { | 395 | if (!tdev->rx_mmio) |
| 382 | size = resource_size(res); | ||
| 383 | tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); | ||
| 384 | } else if (IS_ERR(tdev->rx_mmio)) { | ||
| 385 | tdev->rx_mmio = tdev->tx_mmio; | 396 | tdev->rx_mmio = tdev->tx_mmio; |
| 386 | } | ||
| 387 | 397 | ||
| 388 | tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); | 398 | tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); |
| 389 | tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); | 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 | return -EPROBE_DEFER; | 402 | return -EPROBE_DEFER; |
| 393 | 403 | ||
| 394 | /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ | 404 | /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ |
| 395 | if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) | 405 | if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) |
| 396 | tdev->rx_channel = tdev->tx_channel; | 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 | if (tdev->rx_channel) { | 408 | if (tdev->rx_channel) { |
| 405 | tdev->rx_buffer = devm_kzalloc(&pdev->dev, | 409 | tdev->rx_buffer = devm_kzalloc(&pdev->dev, |
| 406 | MBOX_MAX_MSG_LEN, GFP_KERNEL); | 410 | MBOX_MAX_MSG_LEN, GFP_KERNEL); |
| 407 | if (!tdev->rx_buffer) | 411 | if (!tdev->rx_buffer) { |
| 408 | return -ENOMEM; | 412 | ret = -ENOMEM; |
| 413 | goto err_free_chans; | ||
| 414 | } | ||
| 409 | } | 415 | } |
| 410 | 416 | ||
| 411 | ret = mbox_test_add_debugfs(pdev, tdev); | 417 | ret = mbox_test_add_debugfs(pdev, tdev); |
| 412 | if (ret) | 418 | if (ret) |
| 413 | return ret; | 419 | goto err_free_chans; |
| 414 | 420 | ||
| 415 | init_waitqueue_head(&tdev->waitq); | ||
| 416 | dev_info(&pdev->dev, "Successfully registered\n"); | 421 | dev_info(&pdev->dev, "Successfully registered\n"); |
| 417 | 422 | ||
| 418 | return 0; | 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 | static void mbox_test_remove(struct platform_device *pdev) | 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 | if (tdev->tx_channel) | 439 | if (tdev->tx_channel) |
| 428 | mbox_free_channel(tdev->tx_channel); | 440 | mbox_free_channel(tdev->tx_channel); |
| 429 | if (tdev->rx_channel) | 441 | if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) |
| 430 | mbox_free_channel(tdev->rx_channel); | 442 | mbox_free_channel(tdev->rx_channel); |
| 431 | } | 443 | } |
| 432 | 444 | ||
| @@ -18,8 +18,6 @@ · 17 unmodified lines | |||
| 18 | #include <linux/property.h> | 18 | #include <linux/property.h> |
| 19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
| 20 | 20 | ||
| 21 | #include "mailbox.h" | ||
| 22 | |||
| 23 | static LIST_HEAD(mbox_cons); | 21 | static LIST_HEAD(mbox_cons); |
| 24 | static DEFINE_MUTEX(con_mutex); | 22 | static DEFINE_MUTEX(con_mutex); |
| 25 | 23 | ||
| @@ -52,7 +50,7 @@ static void msg_submit(struct mbox_chan *chan) · 26 unmodified lines | |||
| 52 | int err = -EBUSY; | 50 | int err = -EBUSY; |
| 53 | 51 | ||
| 54 | scoped_guard(spinlock_irqsave, &chan->lock) { | 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 | break; | 54 | break; |
| 57 | 55 | ||
| 58 | count = chan->msg_count; | 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 | /* kick start the timer immediately to avoid delays */ | 76 | /* kick start the timer immediately to avoid delays */ |
| 79 | scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock) | 77 | scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock) |
| 80 | hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); | 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 | scoped_guard(spinlock_irqsave, &chan->lock) { | 86 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 89 | mssg = chan->active_req; | 87 | mssg = chan->active_req; |
| 90 | chan->active_req = NULL; | 88 | chan->active_req = MBOX_NO_MSG; |
| 91 | } | 89 | } |
| 92 | 90 | ||
| 93 | /* Submit next message */ | 91 | /* Submit next message */ |
| 94 | msg_submit(chan); | 92 | msg_submit(chan); |
| 95 | 93 | ||
| 96 | if (!mssg) | 94 | if (mssg == MBOX_NO_MSG) |
| 97 | return; | 95 | return; |
| 98 | 96 | ||
| 99 | /* Notify the client */ | 97 | /* Notify the client */ |
| @@ -114,7 +112,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) · 14 unmodified lines | |||
| 114 | for (i = 0; i < mbox->num_chans; i++) { | 112 | for (i = 0; i < mbox->num_chans; i++) { |
| 115 | struct mbox_chan *chan = &mbox->chans[i]; | 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 | txdone = chan->mbox->ops->last_tx_done(chan); | 116 | txdone = chan->mbox->ops->last_tx_done(chan); |
| 119 | if (txdone) | 117 | if (txdone) |
| 120 | tx_tick(chan, 0); | 118 | tx_tick(chan, 0); |
| @@ -164,7 +162,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_received_data); · 43 unmodified lines | |||
| 164 | */ | 162 | */ |
| 165 | void mbox_chan_txdone(struct mbox_chan *chan, int r) | 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 | dev_err(chan->mbox->dev, | 166 | dev_err(chan->mbox->dev, |
| 169 | "Controller can't run the TX ticker\n"); | 167 | "Controller can't run the TX ticker\n"); |
| 170 | return; | 168 | return; |
| @@ -185,7 +183,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_txdone); · 14 unmodified lines | |||
| 185 | */ | 183 | */ |
| 186 | void mbox_client_txdone(struct mbox_chan *chan, int r) | 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 | dev_err(chan->mbox->dev, "Client can't run the TX ticker\n"); | 187 | dev_err(chan->mbox->dev, "Client can't run the TX ticker\n"); |
| 190 | return; | 188 | return; |
| 191 | } | 189 | } |
| @@ -218,6 +216,29 @@ bool mbox_client_peek_data(struct mbox_chan *chan) · 26 unmodified lines | |||
| 218 | } | 216 | } |
| 219 | EXPORT_SYMBOL_GPL(mbox_client_peek_data); | 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 | * mbox_send_message - For client to submit a message to be | 243 | * mbox_send_message - For client to submit a message to be |
| 223 | * sent to the remote. | 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 | int t; | 268 | int t; |
| 248 | 269 | ||
| 249 | if (!chan || !chan->cl) | 270 | if (!chan || !chan->cl || mssg == MBOX_NO_MSG) |
| 250 | return -EINVAL; | 271 | return -EINVAL; |
| 251 | 272 | ||
| 252 | t = add_to_rbuf(chan, mssg); | 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 | scoped_guard(spinlock_irqsave, &chan->lock) { | 340 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 320 | chan->msg_free = 0; | 341 | chan->msg_free = 0; |
| 321 | chan->msg_count = 0; | 342 | chan->msg_count = 0; |
| 322 | chan->active_req = NULL; | 343 | chan->active_req = MBOX_NO_MSG; |
| 323 | chan->cl = cl; | 344 | chan->cl = cl; |
| 324 | init_completion(&chan->tx_complete); | 345 | init_completion(&chan->tx_complete); |
| 325 | 346 | ||
| 326 | if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) | 347 | if (chan->txdone_method == MBOX_TXDONE_BY_POLL && cl->knows_txdone) |
| 327 | chan->txdone_method = TXDONE_BY_ACK; | 348 | chan->txdone_method = MBOX_TXDONE_BY_ACK; |
| 328 | } | 349 | } |
| 329 | 350 | ||
| 330 | if (chan->mbox->ops->startup) { | 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 | * @chan: The mailbox channel to bind the client to. | 366 | * @chan: The mailbox channel to bind the client to. |
| 346 | * @cl: Identity of the client requesting the channel. | 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 | /* The queued TX requests are simply aborted, no callbacks are made */ | 498 | /* The queued TX requests are simply aborted, no callbacks are made */ |
| 478 | scoped_guard(spinlock_irqsave, &chan->lock) { | 499 | scoped_guard(spinlock_irqsave, &chan->lock) { |
| 479 | chan->cl = NULL; | 500 | chan->cl = NULL; |
| 480 | chan->active_req = NULL; | 501 | chan->active_req = MBOX_NO_MSG; |
| 481 | if (chan->txdone_method == TXDONE_BY_ACK) | 502 | if (chan->txdone_method == MBOX_TXDONE_BY_ACK) |
| 482 | chan->txdone_method = TXDONE_BY_POLL; | 503 | chan->txdone_method = MBOX_TXDONE_BY_POLL; |
| 483 | } | 504 | } |
| 484 | 505 | ||
| 485 | module_put(chan->mbox->dev->driver->owner); | 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 | int i, txdone; | 527 | int i, txdone; |
| 507 | 528 | ||
| 508 | /* Sanity check */ | 529 | if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) |
| 509 | if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) | ||
| 510 | return -EINVAL; | 530 | return -EINVAL; |
| 511 | 531 | ||
| 512 | if (mbox->txdone_irq) | 532 | if (mbox->txdone_irq) |
| 513 | txdone = TXDONE_BY_IRQ; | 533 | txdone = MBOX_TXDONE_BY_IRQ; |
| 514 | else if (mbox->txdone_poll) | 534 | else if (mbox->txdone_poll) |
| 515 | txdone = TXDONE_BY_POLL; | 535 | txdone = MBOX_TXDONE_BY_POLL; |
| 516 | else /* It has to be ACK then */ | 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 | if (!mbox->ops->last_tx_done) { | 541 | if (!mbox->ops->last_tx_done) { |
| 522 | dev_err(mbox->dev, "last_tx_done method is absent\n"); | 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 | chan->cl = NULL; | 553 | chan->cl = NULL; |
| 534 | chan->mbox = mbox; | 554 | chan->mbox = mbox; |
| 555 | chan->active_req = MBOX_NO_MSG; | ||
| 535 | chan->txdone_method = txdone; | 556 | chan->txdone_method = txdone; |
| 536 | spin_lock_init(&chan->lock); | 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 | if (curr_pa == end_pa - CMDQ_INST_SIZE || | 493 | if (curr_pa == end_pa - CMDQ_INST_SIZE || |
| 494 | curr_pa == end_pa) { | 494 | curr_pa == end_pa) { |
| 495 | /* set to this task directly */ | 495 | /* set to this task directly */ |
| 496 | writel(task->pa_base >> cmdq->pdata->shift, | 496 | gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata); |
| 497 | thread->base + CMDQ_THR_CURR_ADDR); | 497 | writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR); |
| 498 | } else { | 498 | } else { |
| 499 | cmdq_task_insert_into_thread(task); | 499 | cmdq_task_insert_into_thread(task); |
| 500 | smp_mb(); /* modify jump before enable thread */ | 500 | smp_mb(); /* modify jump before enable thread */ |
| 501 | } | 501 | } |
| 502 | writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, | 502 | gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata); |
| 503 | thread->base + CMDQ_THR_END_ADDR); | 503 | writel(gce_addr, thread->base + CMDQ_THR_END_ADDR); |
| 504 | cmdq_thread_resume(thread); | 504 | cmdq_thread_resume(thread); |
| 505 | } | 505 | } |
| 506 | list_move_tail(&task->list_entry, &thread->task_busy_list); | 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 | cmdq->mbox.ops = &cmdq_mbox_chan_ops; | 728 | cmdq->mbox.ops = &cmdq_mbox_chan_ops; |
| 729 | cmdq->mbox.of_xlate = cmdq_xlate; | 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 | cmdq->mbox.txdone_irq = false; | 732 | cmdq->mbox.txdone_irq = false; |
| 733 | cmdq->mbox.txdone_poll = false; | 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 | const struct of_phandle_args *sp) | 50 | const struct of_phandle_args *sp) |
| 51 | { | 51 | { |
| 52 | if (sp->args_count) | 52 | if (sp->args_count) |
| 53 | return NULL; | 53 | return ERR_PTR(-EINVAL); |
| 54 | 54 | ||
| 55 | return &mbox->chans[0]; | 55 | return &mbox->chans[0]; |
| 56 | } | 56 | } |
| @@ -22,8 +22,6 @@ · 21 unmodified lines | |||
| 22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
| 23 | #include <linux/mailbox_controller.h> | 23 | #include <linux/mailbox_controller.h> |
| 24 | 24 | ||
| 25 | #include "mailbox.h" | ||
| 26 | |||
| 27 | #define MAILBOX_REVISION 0x000 | 25 | #define MAILBOX_REVISION 0x000 |
| 28 | #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) | 26 | #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) |
| 29 | #define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) | 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 | if (mbox->send_no_irq) | 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 | omap_mbox_enable_irq(mbox, IRQ_RX); | 243 | omap_mbox_enable_irq(mbox, IRQ_RX); |
| 246 | 244 | ||
| @@ -59,8 +59,6 @@ · 58 unmodified lines | |||
| 59 | #include <linux/io-64-nonatomic-lo-hi.h> | 59 | #include <linux/io-64-nonatomic-lo-hi.h> |
| 60 | #include <acpi/pcc.h> | 60 | #include <acpi/pcc.h> |
| 61 | 61 | ||
| 62 | #include "mailbox.h" | ||
| 63 | |||
| 64 | #define MBOX_IRQ_NAME "pcc-mbox" | 62 | #define MBOX_IRQ_NAME "pcc-mbox" |
| 65 | 63 | ||
| 66 | /** | 64 | /** |
| @@ -46,7 +46,7 @@ struct rockchip_mbox { · 45 unmodified lines | |||
| 46 | /* The maximum size of buf for each channel */ | 46 | /* The maximum size of buf for each channel */ |
| 47 | u32 buf_size; | 47 | u32 buf_size; |
| 48 | 48 | ||
| 49 | struct rockchip_mbox_chan *chans; | 49 | struct rockchip_mbox_chan chans[]; |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | static int rockchip_mbox_send_data(struct mbox_chan *chan, void *data) | 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 | drv_data = (const struct rockchip_mbox_data *) device_get_match_data(&pdev->dev); | 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 | if (!mb) | 177 | if (!mb) |
| 178 | return -ENOMEM; | 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 | mb->mbox.chans = devm_kcalloc(&pdev->dev, drv_data->num_chans, | 180 | mb->mbox.chans = devm_kcalloc(&pdev->dev, drv_data->num_chans, |
| 186 | sizeof(*mb->mbox.chans), GFP_KERNEL); | 181 | sizeof(*mb->mbox.chans), GFP_KERNEL); |
| 187 | if (!mb->mbox.chans) | 182 | if (!mb->mbox.chans) |
| @@ -16,8 +16,6 @@ · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | #include <dt-bindings/mailbox/tegra186-hsp.h> | 17 | #include <dt-bindings/mailbox/tegra186-hsp.h> |
| 18 | 18 | ||
| 19 | #include "mailbox.h" | ||
| 20 | |||
| 21 | #define HSP_INT_IE(x) (0x100 + ((x) * 4)) | 19 | #define HSP_INT_IE(x) (0x100 + ((x) * 4)) |
| 22 | #define HSP_INT_IV 0x300 | 20 | #define HSP_INT_IV 0x300 |
| 23 | #define HSP_INT_IR 0x304 | 21 | #define HSP_INT_IR 0x304 |
| @@ -497,7 +495,7 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, · 473 unmodified lines | |||
| 497 | mbox_chan_txdone(chan, 0); | 495 | mbox_chan_txdone(chan, 0); |
| 498 | 496 | ||
| 499 | /* Wait until channel is empty */ | 497 | /* Wait until channel is empty */ |
| 500 | if (chan->active_req != NULL) | 498 | if (chan->active_req != MBOX_NO_MSG) |
| 501 | continue; | 499 | continue; |
| 502 | 500 | ||
| 503 | return 0; | 501 | return 0; |
| @@ -516,7 +514,7 @@ static int tegra_hsp_mailbox_startup(struct mbox_chan *chan) · 12 unmodified lines | |||
| 516 | struct tegra_hsp *hsp = mb->channel.hsp; | 514 | struct tegra_hsp *hsp = mb->channel.hsp; |
| 517 | unsigned long flags; | 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 | * Shared mailboxes start out as consumers by default. FULL and EMPTY | 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 | static struct workqueue_struct *md_bitmap_wq; | 218 | static struct workqueue_struct *md_bitmap_wq; |
| 219 | static struct attribute_group md_bitmap_internal_group; | ||
| 219 | 220 | ||
| 220 | static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, | 221 | static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, |
| 221 | int chunksize, bool init); | 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 | return __bitmap_resize(bitmap, blocks, chunksize, false); | 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 | static ssize_t | 2608 | static ssize_t |
| 2584 | location_show(struct mddev *mddev, char *page) | 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 | goto out; | 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 | mddev->bitmap_info.offset = 0; | 2651 | mddev->bitmap_info.offset = 0; |
| 2623 | if (mddev->bitmap_info.file) { | 2652 | if (mddev->bitmap_info.file) { |
| 2624 | struct file *f = mddev->bitmap_info.file; | 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 | mddev->bitmap_info.offset = offset; | 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 | if (rv) | 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 | if (rv) { | 2696 | if (rv) { |
| 2663 | mddev->bitmap_info.offset = 0; | 2697 | mddev->bitmap_info.offset = 0; |
| 2664 | bitmap_destroy(mddev); | 2698 | goto load_err; |
| 2665 | goto out; | ||
| 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 | if (!mddev->external) { | 2707 | if (!mddev->external) { |
| @@ -2679,6 +2717,22 @@ out: · 9 unmodified lines | |||
| 2679 | if (rv) | 2717 | if (rv) |
| 2680 | return rv; | 2718 | return rv; |
| 2681 | return len; | 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 | static struct md_sysfs_entry bitmap_location = | 2738 | static struct md_sysfs_entry bitmap_location = |
| @@ -2955,8 +3009,12 @@ static struct md_sysfs_entry max_backlog_used = · 270 unmodified lines | |||
| 2955 | __ATTR(max_backlog_used, S_IRUGO | S_IWUSR, | 3009 | __ATTR(max_backlog_used, S_IRUGO | S_IWUSR, |
| 2956 | behind_writes_used_show, behind_writes_used_reset); | 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 | &bitmap_location.attr, | 3013 | &bitmap_location.attr, |
| 3014 | NULL | ||
| 3015 | }; | ||
| 3016 | |||
| 3017 | static struct attribute *md_bitmap_internal_attrs[] = { | ||
| 2960 | &bitmap_space.attr, | 3018 | &bitmap_space.attr, |
| 2961 | &bitmap_timeout.attr, | 3019 | &bitmap_timeout.attr, |
| 2962 | &bitmap_backlog.attr, | 3020 | &bitmap_backlog.attr, |
| @@ -2967,9 +3025,41 @@ static struct attribute *md_bitmap_attrs[] = { · 4 unmodified lines | |||
| 2967 | NULL | 3025 | NULL |
| 2968 | }; | 3026 | }; |
| 2969 | 3027 | ||
| 2970 | static struct attribute_group md_bitmap_group = { | 3028 | static struct attribute_group md_bitmap_common_group = { |
| 2971 | .name = "bitmap", | 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 | static struct bitmap_operations bitmap_ops = { | 3065 | static struct bitmap_operations bitmap_ops = { |
| @@ -3013,21 +3103,38 @@ static struct bitmap_operations bitmap_ops = { · 37 unmodified lines | |||
| 3013 | .set_pages = bitmap_set_pages, | 3103 | .set_pages = bitmap_set_pages, |
| 3014 | .free = md_bitmap_free, | 3104 | .free = md_bitmap_free, |
| 3015 | 3105 | ||
| 3016 | .group = &md_bitmap_group, | 3106 | .groups = bitmap_groups, |
| 3017 | }; | 3107 | }; |
| 3018 | 3108 | ||
| 3019 | int md_bitmap_init(void) | 3109 | int md_bitmap_init(void) |
| 3020 | { | 3110 | { |
| 3111 | int err; | ||
| 3112 | |||
| 3021 | md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND, | 3113 | md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND, |
| 3022 | 0); | 3114 | 0); |
| 3023 | if (!md_bitmap_wq) | 3115 | if (!md_bitmap_wq) |
| 3024 | return -ENOMEM; | 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 | void md_bitmap_exit(void) | 3135 | void md_bitmap_exit(void) |
| 3030 | { | 3136 | { |
| 3031 | destroy_workqueue(md_bitmap_wq); | ||
| 3032 | unregister_md_submodule(&bitmap_ops.head); | 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 | void (*set_pages)(void *data, unsigned long pages); | 125 | void (*set_pages)(void *data, unsigned long pages); |
| 126 | void (*free)(void *data); | 126 | void (*free)(void *data); |
| 127 | 127 | ||
| 128 | struct attribute_group *group; | 128 | const struct attribute_group **groups; |
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | /* the bitmap API */ | 131 | /* the bitmap API */ |
| @@ -1738,6 +1738,11 @@ static struct attribute_group md_llbitmap_group = { · 1737 unmodified lines | |||
| 1738 | .attrs = md_llbitmap_attrs, | 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 | static struct bitmap_operations llbitmap_ops = { | 1746 | static struct bitmap_operations llbitmap_ops = { |
| 1742 | .head = { | 1747 | .head = { |
| 1743 | .type = MD_BITMAP, | 1748 | .type = MD_BITMAP, |
| @@ -1774,7 +1779,7 @@ static struct bitmap_operations llbitmap_ops = { · 30 unmodified lines | |||
| 1774 | .dirty_bits = llbitmap_dirty_bits, | 1779 | .dirty_bits = llbitmap_dirty_bits, |
| 1775 | .write_all = llbitmap_write_all, | 1780 | .write_all = llbitmap_write_all, |
| 1776 | 1781 | ||
| 1777 | .group = &md_llbitmap_group, | 1782 | .groups = md_llbitmap_groups, |
| 1778 | }; | 1783 | }; |
| 1779 | 1784 | ||
| 1780 | int md_llbitmap_init(void) | 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 | check_suspended: | 397 | check_suspended: |
| 398 | if (is_suspended(mddev, bio)) { | 398 | if (is_suspended(mddev, bio)) { |
| 399 | DEFINE_WAIT(__wait); | ||
| 400 | /* Bail out if REQ_NOWAIT is set for the bio */ | 399 | /* Bail out if REQ_NOWAIT is set for the bio */ |
| 401 | if (bio->bi_opf & REQ_NOWAIT) { | 400 | if (bio->bi_opf & REQ_NOWAIT) { |
| 402 | bio_wouldblock_error(bio); | 401 | bio_wouldblock_error(bio); |
| 403 | return true; | 402 | return true; |
| 404 | } | 403 | } |
| 405 | for (;;) { | 404 | wait_event(mddev->sb_wait, !is_suspended(mddev, bio)); |
| 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); | ||
| 413 | } | 405 | } |
| 414 | if (!percpu_ref_tryget_live(&mddev->active_io)) | 406 | if (!percpu_ref_tryget_live(&mddev->active_io)) |
| 415 | goto check_suspended; | 407 | goto check_suspended; |
| 416 | 408 | ||
| 417 | if (!mddev->pers->make_request(mddev, bio)) { | 409 | if (!mddev->pers->make_request(mddev, bio)) { |
| 418 | percpu_ref_put(&mddev->active_io); | 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 | return false; | 412 | return false; |
| 421 | goto check_suspended; | 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 | static void no_op(struct percpu_ref *r) {} | 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 | struct md_submodule_head *head; | 710 | struct md_submodule_head *head; |
| 694 | 711 | ||
| 695 | if (mddev->bitmap_id == ID_BITMAP_NONE || | 712 | if (mddev->bitmap_ops && |
| 696 | (old && old->head.id == mddev->bitmap_id)) | 713 | mddev->bitmap_ops->head.id == mddev->bitmap_id) |
| 697 | return true; | 714 | return true; |
| 698 | 715 | ||
| 699 | xa_lock(&md_submodule); | 716 | xa_lock(&md_submodule); |
| @@ -711,18 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) · 11 unmodified lines | |||
| 711 | 728 | ||
| 712 | mddev->bitmap_ops = (void *)head; | 729 | mddev->bitmap_ops = (void *)head; |
| 713 | xa_unlock(&md_submodule); | 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 | return true; | 731 | return true; |
| 727 | 732 | ||
| 728 | err: | 733 | err: |
| @@ -730,15 +735,6 @@ err: · 1 unmodified line | |||
| 730 | return false; | 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 | int mddev_init(struct mddev *mddev) | 738 | int mddev_init(struct mddev *mddev) |
| 743 | { | 739 | { |
| 744 | int err = 0; | 740 | int err = 0; |
| @@ -4279,7 +4275,7 @@ bitmap_type_show(struct mddev *mddev, char *page) · 3534 unmodified lines | |||
| 4279 | 4275 | ||
| 4280 | xa_lock(&md_submodule); | 4276 | xa_lock(&md_submodule); |
| 4281 | xa_for_each(&md_submodule, i, head) { | 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 | continue; | 4279 | continue; |
| 4284 | 4280 | ||
| 4285 | if (mddev->bitmap_id == head->id) | 4281 | if (mddev->bitmap_id == head->id) |
| @@ -6059,10 +6055,7 @@ static struct attribute *md_default_attrs[] = { · 1773 unmodified lines | |||
| 6059 | &md_logical_block_size.attr, | 6055 | &md_logical_block_size.attr, |
| 6060 | NULL, | 6056 | NULL, |
| 6061 | }; | 6057 | }; |
| 6062 | 6058 | ATTRIBUTE_GROUPS(md_default); | |
| 6063 | static const struct attribute_group md_default_group = { | ||
| 6064 | .attrs = md_default_attrs, | ||
| 6065 | }; | ||
| 6066 | 6059 | ||
| 6067 | static struct attribute *md_redundancy_attrs[] = { | 6060 | static struct attribute *md_redundancy_attrs[] = { |
| 6068 | &md_scan_mode.attr, | 6061 | &md_scan_mode.attr, |
| @@ -6087,11 +6080,6 @@ static const struct attribute_group md_redundancy_group = { · 18 unmodified lines | |||
| 6087 | .attrs = md_redundancy_attrs, | 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 | static ssize_t | 6083 | static ssize_t |
| 6096 | md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | 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 | static const struct kobj_type md_ktype = { | 6162 | static const struct kobj_type md_ktype = { |
| 6175 | .release = md_kobj_release, | 6163 | .release = md_kobj_release, |
| 6176 | .sysfs_ops = &md_sysfs_ops, | 6164 | .sysfs_ops = &md_sysfs_ops, |
| 6177 | .default_groups = md_attr_groups, | 6165 | .default_groups = md_default_groups, |
| 6178 | }; | 6166 | }; |
| 6179 | 6167 | ||
| 6180 | int mdp_major = 0; | 6168 | int mdp_major = 0; |
| @@ -6539,7 +6527,7 @@ out: · 358 unmodified lines | |||
| 6539 | return id; | 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 | enum md_submodule_id orig_id = mddev->bitmap_id; | 6532 | enum md_submodule_id orig_id = mddev->bitmap_id; |
| 6545 | enum md_submodule_id sb_id; | 6533 | enum md_submodule_id sb_id; |
| @@ -6548,8 +6536,10 @@ static int md_bitmap_create(struct mddev *mddev) · 2 unmodified lines | |||
| 6548 | if (mddev->bitmap_id == ID_BITMAP_NONE) | 6536 | if (mddev->bitmap_id == ID_BITMAP_NONE) |
| 6549 | return -EINVAL; | 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 | return -ENOENT; | 6541 | return -ENOENT; |
| 6542 | } | ||
| 6553 | 6543 | ||
| 6554 | err = mddev->bitmap_ops->create(mddev); | 6544 | err = mddev->bitmap_ops->create(mddev); |
| 6555 | if (!err) | 6545 | if (!err) |
| @@ -6560,37 +6550,72 @@ static int md_bitmap_create(struct mddev *mddev) · 4 unmodified lines | |||
| 6560 | * doesn't match, and mdadm is not the latest version to set | 6550 | * doesn't match, and mdadm is not the latest version to set |
| 6561 | * bitmap_type, set bitmap_ops based on the disk version. | 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 | sb_id = md_bitmap_get_id_from_sb(mddev); | 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 | return err; | 6558 | return err; |
| 6559 | } | ||
| 6568 | 6560 | ||
| 6569 | pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", | 6561 | pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", |
| 6570 | mdname(mddev), orig_id, sb_id); | 6562 | mdname(mddev), orig_id, sb_id); |
| 6571 | 6563 | ||
| 6572 | mddev->bitmap_id = sb_id; | 6564 | mddev->bitmap_id = sb_id; |
| 6573 | if (!mddev_set_bitmap_ops(mddev)) { | 6565 | if (!mddev_set_bitmap_ops_nosysfs(mddev)) { |
| 6574 | mddev->bitmap_id = orig_id; | 6566 | mddev->bitmap_id = orig_id; |
| 6575 | return -ENOENT; | 6567 | return -ENOENT; |
| 6576 | } | 6568 | } |
| 6577 | 6569 | ||
| 6578 | err = mddev->bitmap_ops->create(mddev); | 6570 | err = mddev->bitmap_ops->create(mddev); |
| 6579 | if (err) { | 6571 | if (err) { |
| 6580 | mddev_clear_bitmap_ops(mddev); | 6572 | mddev->bitmap_ops = NULL; |
| 6581 | mddev->bitmap_id = orig_id; | 6573 | mddev->bitmap_id = orig_id; |
| 6582 | } | 6574 | } |
| 6583 | 6575 | ||
| 6584 | return err; | 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 | if (!md_bitmap_registered(mddev)) | 6595 | if (!md_bitmap_registered(mddev)) |
| 6590 | return; | 6596 | return; |
| 6591 | 6597 | ||
| 6592 | mddev->bitmap_ops->destroy(mddev); | 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 | int md_run(struct mddev *mddev) | 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 | /* dm-raid expect sync_thread to be frozen until resume */ | 6740 | /* dm-raid expect sync_thread to be frozen until resume */ |
| 6716 | if (mddev->gendisk) | 6741 | if (!mddev_is_dm(mddev)) |
| 6717 | mddev->recovery = 0; | 6742 | mddev->recovery = 0; |
| 6718 | 6743 | ||
| 6719 | /* may be over-ridden by personality */ | 6744 | /* may be over-ridden by personality */ |
| @@ -6802,6 +6827,10 @@ int md_run(struct mddev *mddev) · 82 unmodified lines | |||
| 6802 | if (mddev->sb_flags) | 6827 | if (mddev->sb_flags) |
| 6803 | md_update_sb(mddev, 0); | 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 | md_new_event(); | 6834 | md_new_event(); |
| 6806 | return 0; | 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 | int err = 0; | 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 | return -EINVAL; | 7781 | return -EINVAL; |
| 7752 | 7782 | ||
| 7753 | if (mddev->pers) { | 7783 | if (mddev->pers) { |
| @@ -7812,10 +7842,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd) · 58 unmodified lines | |||
| 7812 | 7842 | ||
| 7813 | if (err) { | 7843 | if (err) { |
| 7814 | md_bitmap_destroy(mddev); | 7844 | md_bitmap_destroy(mddev); |
| 7845 | md_bitmap_set_none(mddev); | ||
| 7815 | fd = -1; | 7846 | fd = -1; |
| 7816 | } | 7847 | } |
| 7817 | } else if (fd < 0) { | 7848 | } else if (fd < 0) { |
| 7818 | md_bitmap_destroy(mddev); | 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 | mddev->bitmap_info.default_offset; | 8154 | mddev->bitmap_info.default_offset; |
| 8123 | mddev->bitmap_info.space = | 8155 | mddev->bitmap_info.space = |
| 8124 | mddev->bitmap_info.default_space; | 8156 | mddev->bitmap_info.default_space; |
| 8157 | mddev->bitmap_id = ID_BITMAP; | ||
| 8125 | rv = md_bitmap_create(mddev); | 8158 | rv = md_bitmap_create(mddev); |
| 8126 | if (!rv) | 8159 | if (!rv) |
| 8127 | rv = mddev->bitmap_ops->load(mddev); | 8160 | rv = mddev->bitmap_ops->load(mddev); |
| 8128 | 8161 | ||
| 8129 | if (rv) | 8162 | if (rv) { |
| 8130 | md_bitmap_destroy(mddev); | 8163 | md_bitmap_destroy(mddev); |
| 8164 | mddev->bitmap_info.offset = 0; | ||
| 8165 | md_bitmap_set_none(mddev); | ||
| 8166 | } | ||
| 8131 | } else { | 8167 | } else { |
| 8132 | struct md_bitmap_stats stats; | 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 | md_bitmap_destroy(mddev); | 8192 | md_bitmap_destroy(mddev); |
| 8157 | mddev->bitmap_info.offset = 0; | 8193 | mddev->bitmap_info.offset = 0; |
| 8194 | md_bitmap_set_none(mddev); | ||
| 8158 | } | 8195 | } |
| 8159 | } | 8196 | } |
| 8160 | md_update_sb(mddev, 1); | 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 | static void md_end_clone_io(struct bio *bio) | 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 | struct bio *orig_bio = md_io_clone->orig_bio; | 9383 | struct bio *orig_bio = md_io_clone->orig_bio; |
| 9346 | struct mddev *mddev = md_io_clone->mddev; | 9384 | struct mddev *mddev = md_io_clone->mddev; |
| 9385 | struct completion *reshape_completion = bio->bi_private; | ||
| 9347 | 9386 | ||
| 9348 | if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) | 9387 | if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false)) |
| 9349 | md_bitmap_end(mddev, md_io_clone); | 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 | bio_end_io_acct(orig_bio, md_io_clone->start_time); | 9394 | bio_end_io_acct(orig_bio, md_io_clone->start_time); |
| 9356 | 9395 | ||
| 9357 | bio_put(bio); | 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 | percpu_ref_put(&mddev->active_io); | 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 | clone->bi_end_io = md_end_clone_io; | 9424 | clone->bi_end_io = md_end_clone_io; |
| 9383 | clone->bi_private = md_io_clone; | 9425 | clone->bi_private = NULL; |
| 9384 | *bio = clone; | 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 | EXPORT_SYMBOL_GPL(md_account_bio); | 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 | /* md_allow_write(mddev) | 9436 | /* md_allow_write(mddev) |
| 9415 | * Calling this ensures that the array is marked 'active' so that writes | 9437 | * Calling this ensures that the array is marked 'active' so that writes |
| 9416 | * may proceed without blocking. It is important to call this before | 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 | void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev, | 920 | void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev, |
| 921 | struct bio *bio, sector_t start, sector_t size); | 921 | struct bio *bio, sector_t start, sector_t size); |
| 922 | void md_account_bio(struct mddev *mddev, struct bio **bio); | 922 | void md_account_bio(struct mddev *mddev, struct bio **bio); |
| 923 | void md_free_cloned_bio(struct bio *bio); | ||
| 924 | 923 | ||
| 925 | extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio); | 924 | extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio); |
| 926 | void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev, | 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 | extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev); | 934 | extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev); |
| 936 | extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors); | 935 | extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors); |
| 937 | extern int md_check_no_bitmap(struct mddev *mddev); | 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 | extern int md_integrity_register(struct mddev *mddev); | 940 | extern int md_integrity_register(struct mddev *mddev); |
| 939 | extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); | 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 | static inline void mddev_suspend_and_lock_nointr(struct mddev *mddev) | 1017 | static inline void mddev_suspend_and_lock_nointr(struct mddev *mddev) |
| 1016 | { | 1018 | { |
| 1017 | mddev_suspend(mddev, false); | 1019 | mddev_suspend(mddev, false); |
| 1018 | mutex_lock(&mddev->reconfig_mutex); | 1020 | mddev_lock_nointr(mddev); |
| 1019 | } | 1021 | } |
| 1020 | 1022 | ||
| 1021 | static inline void mddev_unlock_and_resume(struct mddev *mddev) | 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 | if (le32_to_cpu(n->header.nr_entries) == 1) { | 491 | if (le32_to_cpu(n->header.nr_entries) == 1) { |
| 492 | struct dm_block *child; | 492 | struct dm_block *child; |
| 493 | int is_shared; | ||
| 493 | dm_block_t b = value64(n, 0); | 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 | r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child); | 500 | r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child); |
| 496 | if (r) | 501 | if (r) |
| 497 | return r; | 502 | return r; |
| 498 | 503 | ||
| 504 | if (is_shared) | ||
| 505 | inc_children(info->tm, dm_block_data(child), vt); | ||
| 506 | |||
| 499 | memcpy(n, dm_block_data(child), | 507 | memcpy(n, dm_block_data(child), |
| 500 | dm_bm_block_size(dm_tm_get_bm(info->tm))); | 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 | * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is | 293 | * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is |
| 294 | * submitted to the underlying disks, hence don't record badblocks or retry | 294 | * submitted to the underlying disks, hence don't record badblocks or retry |
| 295 | * in this case. | 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 | static inline bool raid1_should_handle_error(struct bio *bio) | 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 | mddev->cluster_ops->area_resyncing(mddev, WRITE, | 1510 | mddev->cluster_ops->area_resyncing(mddev, WRITE, |
| 1511 | bio->bi_iter.bi_sector, bio_end_sector(bio))) { | 1511 | bio->bi_iter.bi_sector, bio_end_sector(bio))) { |
| 1512 | 1512 | ||
| 1513 | DEFINE_WAIT(w); | ||
| 1514 | if (bio->bi_opf & REQ_NOWAIT) { | 1513 | if (bio->bi_opf & REQ_NOWAIT) { |
| 1515 | bio_wouldblock_error(bio); | 1514 | bio_wouldblock_error(bio); |
| 1516 | return; | 1515 | return; |
| 1517 | } | 1516 | } |
| 1518 | for (;;) { | 1517 | wait_event_idle(conf->wait_barrier, |
| 1519 | prepare_to_wait(&conf->wait_barrier, | 1518 | !mddev->cluster_ops->area_resyncing(mddev, WRITE, |
| 1520 | &w, TASK_IDLE); | 1519 | bio->bi_iter.bi_sector, |
| 1521 | if (!mddev->cluster_ops->area_resyncing(mddev, WRITE, | 1520 | bio_end_sector(bio))); |
| 1522 | bio->bi_iter.bi_sector, | ||
| 1523 | bio_end_sector(bio))) | ||
| 1524 | break; | ||
| 1525 | schedule(); | ||
| 1526 | } | ||
| 1527 | finish_wait(&conf->wait_barrier, &w); | ||
| 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 | nc = layout & 255; | 3791 | nc = layout & 255; |
| 3792 | fc = (layout >> 8) & 255; | 3792 | fc = (layout >> 8) & 255; |
| 3793 | fo = layout & (1<<16); | 3793 | fo = layout & (1<<16); |
| 3794 | if (!nc || !fc) | ||
| 3795 | return -1; | ||
| 3794 | geo->raid_disks = disks; | 3796 | geo->raid_disks = disks; |
| 3795 | geo->near_copies = nc; | 3797 | geo->near_copies = nc; |
| 3796 | geo->far_copies = fc; | 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 | mempool_free(ctx, conf->ctx_pool); | 6218 | mempool_free(ctx, conf->ctx_pool); |
| 6219 | if (res == STRIPE_WAIT_RESHAPE) { | 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 | return false; | 6226 | return false; |
| 6222 | } | 6227 | } |
| 6223 | 6228 | ||
| @@ -71,7 +71,7 @@ config MTD_NAND_AU1550 · 70 unmodified lines | |||
| 71 | 71 | ||
| 72 | config MTD_NAND_NDFC | 72 | config MTD_NAND_NDFC |
| 73 | tristate "IBM/MCC 4xx NAND controller" | 73 | tristate "IBM/MCC 4xx NAND controller" |
| 74 | depends on 4xx | 74 | depends on 44x || COMPILE_TEST |
| 75 | select MTD_NAND_ECC_SW_HAMMING | 75 | select MTD_NAND_ECC_SW_HAMMING |
| 76 | select MTD_NAND_ECC_SW_HAMMING_SMC | 76 | select MTD_NAND_ECC_SW_HAMMING_SMC |
| 77 | help | 77 | help |
| @@ -175,7 +175,7 @@ void nand_select_target(struct nand_chip *chip, unsigned int cs) · 174 unmodified lines | |||
| 175 | * cs should always lie between 0 and nanddev_ntargets(), when that's | 175 | * cs should always lie between 0 and nanddev_ntargets(), when that's |
| 176 | * not the case it's a bug and the caller should be fixed. | 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 | return; | 179 | return; |
| 180 | 180 | ||
| 181 | chip->cur_cs = cs; | 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 | return nand_exec_op(chip, &op); | 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 */ | 1221 | /* block is expected to be very small */ |
| 1222 | return (lun * pages_per_lun) + pages_per_lun - 1; | 1222 | return (block * ppb) + ppb - 1; |
| 1223 | } | 1223 | } |
| 1224 | 1224 | ||
| 1225 | static void rawnand_cap_cont_reads(struct nand_chip *chip) | 1225 | static void rawnand_cap_cont_reads(struct nand_chip *chip) |
| 1226 | { | 1226 | { |
| 1227 | struct nand_memory_organization *memorg; | 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 | memorg = nanddev_get_memorg(&chip->base); | 1230 | memorg = nanddev_get_memorg(&chip->base); |
| 1231 | ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun; | 1231 | ppb = memorg->pages_per_eraseblock; |
| 1232 | first_lun = chip->cont_read.first_page / ppl; | 1232 | first_block = chip->cont_read.first_page / ppb; |
| 1233 | last_lun = chip->cont_read.last_page / ppl; | 1233 | last_block = chip->cont_read.last_page / ppb; |
| 1234 | 1234 | ||
| 1235 | /* Prevent sequential cache reads across LUN boundaries */ | 1235 | /* Prevent sequential cache reads across block boundaries */ |
| 1236 | if (first_lun != last_lun) | 1236 | if (first_block != last_block) |
| 1237 | chip->cont_read.pause_page = rawnand_last_page_of_lun(ppl, first_lun); | 1237 | chip->cont_read.pause_page = rawnand_last_page_of_block(ppb, first_block); |
| 1238 | else | 1238 | else |
| 1239 | chip->cont_read.pause_page = chip->cont_read.last_page; | 1239 | chip->cont_read.pause_page = chip->cont_read.last_page; |
| 1240 | 1240 | ||
| 1241 | if (chip->cont_read.first_page == chip->cont_read.pause_page) { | 1241 | if (chip->cont_read.first_page == chip->cont_read.pause_page) { |
| 1242 | chip->cont_read.first_page++; | 1242 | chip->cont_read.first_page++; |
| 1243 | chip->cont_read.pause_page = min(chip->cont_read.last_page, | 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 | if (chip->cont_read.first_page >= chip->cont_read.last_page) | 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 | uint32_t ccr; | 44 | uint32_t ccr; |
| 45 | struct ndfc_controller *ndfc = nand_get_controller_data(nchip); | 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 | if (chip >= 0) { | 48 | if (chip >= 0) { |
| 49 | ccr &= ~NDFC_CCR_BS_MASK; | 49 | ccr &= ~NDFC_CCR_BS_MASK; |
| 50 | ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); | 50 | ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); |
| 51 | } else | 51 | } else |
| 52 | ccr |= NDFC_CCR_RESET_CE; | 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 | static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) | 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 | struct ndfc_controller *ndfc = nand_get_controller_data(chip); | 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 | static void ndfc_enable_hwecc(struct nand_chip *chip, int mode) | 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 | uint32_t ccr; | 78 | uint32_t ccr; |
| 79 | struct ndfc_controller *ndfc = nand_get_controller_data(chip); | 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 | ccr |= NDFC_CCR_RESET_ECC; | 82 | ccr |= NDFC_CCR_RESET_ECC; |
| 83 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); | 83 | iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR); |
| 84 | wmb(); | 84 | wmb(); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| @@ -92,7 +92,7 @@ static int ndfc_calculate_ecc(struct nand_chip *chip, · 5 unmodified lines | |||
| 92 | uint8_t *p = (uint8_t *)&ecc; | 92 | uint8_t *p = (uint8_t *)&ecc; |
| 93 | 93 | ||
| 94 | wmb(); | 94 | wmb(); |
| 95 | ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); | 95 | ecc = ioread32be(ndfc->ndfcbase + NDFC_ECC); |
| 96 | /* The NDFC uses Smart Media (SMC) bytes order */ | 96 | /* The NDFC uses Smart Media (SMC) bytes order */ |
| 97 | ecc_code[0] = p[1]; | 97 | ecc_code[0] = p[1]; |
| 98 | ecc_code[1] = p[2]; | 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 | uint32_t *p = (uint32_t *) buf; | 114 | uint32_t *p = (uint32_t *) buf; |
| 115 | 115 | ||
| 116 | for(;len > 0; len -= 4) | 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 | static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) | 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 | uint32_t *p = (uint32_t *) buf; | 123 | uint32_t *p = (uint32_t *) buf; |
| 124 | 124 | ||
| 125 | for(;len > 0; len -= 4) | 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 | if (reg) | 223 | if (reg) |
| 224 | ccr |= be32_to_cpup(reg); | 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 | /* Set the bank settings if given */ | 228 | /* Set the bank settings if given */ |
| 229 | reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); | 229 | reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL); |
| 230 | if (reg) { | 230 | if (reg) { |
| 231 | int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); | 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 | err = ndfc_chip_init(ndfc, ofdev->dev.of_node); | 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 | nfc->controller.ops = &pl35x_nandc_ops; | 1155 | nfc->controller.ops = &pl35x_nandc_ops; |
| 1156 | INIT_LIST_HEAD(&nfc->chips); | 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 | if (IS_ERR(nfc->conf_regs)) | 1159 | if (IS_ERR(nfc->conf_regs)) |
| 1160 | return PTR_ERR(nfc->conf_regs); | 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 | static struct qcom_nand_controller * | 128 | static struct qcom_nand_controller * |
| 129 | get_qcom_nand_controller(struct nand_chip *chip) | 129 | get_qcom_nand_controller(struct nand_chip *chip) |
| 130 | { | 130 | { |
| 131 | return (struct qcom_nand_controller *) | 131 | return container_of(chip->controller, struct qcom_nand_controller, |
| 132 | ((u8 *)chip->controller - sizeof(struct qcom_nand_controller)); | 132 | controller); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | static u32 nandc_read(struct qcom_nand_controller *nandc, int offset) | 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 | u32 nand_ctrl; | 2035 | u32 nand_ctrl; |
| 2036 | 2036 | ||
| 2037 | nand_controller_init(nandc->controller); | 2037 | nand_controller_init(&nandc->controller); |
| 2038 | nandc->controller->ops = &qcom_nandc_ops; | 2038 | nandc->controller.ops = &qcom_nandc_ops; |
| 2039 | 2039 | ||
| 2040 | /* kill onenand */ | 2040 | /* kill onenand */ |
| 2041 | if (!nandc->props->nandc_part_of_qpic) | 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 | chip->legacy.block_bad = qcom_nandc_block_bad; | 2175 | chip->legacy.block_bad = qcom_nandc_block_bad; |
| 2176 | chip->legacy.block_markbad = qcom_nandc_block_markbad; | 2176 | chip->legacy.block_markbad = qcom_nandc_block_markbad; |
| 2177 | 2177 | ||
| 2178 | chip->controller = nandc->controller; | 2178 | chip->controller = &nandc->controller; |
| 2179 | chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA | | 2179 | chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA | |
| 2180 | NAND_SKIP_BBTSCAN; | 2180 | NAND_SKIP_BBTSCAN; |
| 2181 | 2181 | ||
| @@ -2256,21 +2256,17 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) · 74 unmodified lines | |||
| 2256 | static int qcom_nandc_probe(struct platform_device *pdev) | 2256 | static int qcom_nandc_probe(struct platform_device *pdev) |
| 2257 | { | 2257 | { |
| 2258 | struct qcom_nand_controller *nandc; | 2258 | struct qcom_nand_controller *nandc; |
| 2259 | struct nand_controller *controller; | ||
| 2260 | const void *dev_data; | 2259 | const void *dev_data; |
| 2261 | struct device *dev = &pdev->dev; | 2260 | struct device *dev = &pdev->dev; |
| 2262 | struct resource *res; | 2261 | struct resource *res; |
| 2263 | int ret; | 2262 | int ret; |
| 2264 | 2263 | ||
| 2265 | nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller), | 2264 | nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL); |
| 2266 | GFP_KERNEL); | ||
| 2267 | if (!nandc) | 2265 | if (!nandc) |
| 2268 | return -ENOMEM; | 2266 | return -ENOMEM; |
| 2269 | controller = (struct nand_controller *)&nandc[1]; | ||
| 2270 | 2267 | ||
| 2271 | platform_set_drvdata(pdev, nandc); | 2268 | platform_set_drvdata(pdev, nandc); |
| 2272 | nandc->dev = dev; | 2269 | nandc->dev = dev; |
| 2273 | nandc->controller = controller; | ||
| 2274 | 2270 | ||
| 2275 | dev_data = of_device_get_match_data(dev); | 2271 | dev_data = of_device_get_match_data(dev); |
| 2276 | if (!dev_data) { | 2272 | if (!dev_data) { |
| @@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr) · 99 unmodified lines | |||
| 100 | return op; | 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 | struct spi_mem_op | 114 | struct spi_mem_op |
| 104 | spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr) | 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 | struct nand_device *nand = spinand_to_nand(spinand); | 465 | struct nand_device *nand = spinand_to_nand(spinand); |
| 455 | unsigned int row = nanddev_pos_to_row(nand, &req->pos); | 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 | return spi_mem_exec_op(spinand->spimem, &op); | 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) | 504 | rdesc = spinand->dirmaps[req->pos.plane].rdesc; |
| 491 | 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 | else | 514 | else |
| 493 | rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc; | 515 | rdesc->info.op_tmpl->data.ecc = false; |
| 494 | 516 | ||
| 495 | if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) | 517 | if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) |
| 496 | column |= req->pos.plane << fls(nanddev_page_size(nand)); | 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 | req->ooblen); | 601 | req->ooblen); |
| 580 | } | 602 | } |
| 581 | 603 | ||
| 582 | if (req->mode == MTD_OPS_RAW) | 604 | wdesc = spinand->dirmaps[req->pos.plane].wdesc; |
| 583 | 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 | else | 609 | else |
| 585 | wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc; | 610 | wdesc->info.op_tmpl->data.ecc = false; |
| 586 | 611 | ||
| 587 | if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) | 612 | if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) |
| 588 | column |= req->pos.plane << fls(nanddev_page_size(nand)); | 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 | * Each data read must be a multiple of 4-bytes and full pages should be read; | 903 | * Each data read must be a multiple of 4-bytes and full pages should be read; |
| 879 | * otherwise, the data output might get out of sequence from one read command | 904 | * otherwise, the data output might get out of sequence from one read command |
| 880 | * to another. | 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 | nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { | 913 | nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { |
| 883 | ret = spinand_select_target(spinand, iter.req.pos.target); | 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 | struct nand_device *nand = spinand_to_nand(spinand); | 966 | struct nand_device *nand = spinand_to_nand(spinand); |
| 936 | enum nand_ecc_engine_type engine_type = nand->ecc.ctx.conf.engine_type; | 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 | /* OOBs cannot be retrieved so external/on-host ECC engine won't work */ | 970 | /* OOBs cannot be retrieved so external/on-host ECC engine won't work */ |
| 939 | if (spinand->set_cont_read && | 971 | 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 | |||
| 944 | /* | 972 | /* |
| 945 | * Ensure continuous read is disabled on probe. | 973 | * Ensure continuous read is disabled on probe. |
| 946 | * Some devices retain this state across soft reset, | 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 | * in false positive returns from spinand_isbad(). | 976 | * in false positive returns from spinand_isbad(). |
| 949 | */ | 977 | */ |
| 950 | spinand_cont_read_enable(spinand, false); | 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 | nanddev_offs_to_pos(nand, from, &start_pos); | 1001 | nanddev_offs_to_pos(nand, from, &start_pos); |
| 969 | nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos); | 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 | return start_pos.page < end_pos.page; | 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 | * its spi controller, use regular reading | 1242 | * its spi controller, use regular reading |
| 1223 | */ | 1243 | */ |
| 1224 | spinand->cont_read_possible = false; | 1244 | spinand->cont_read_possible = false; |
| 1245 | memset(&info->secondary_op_tmpl, 0, sizeof(info->secondary_op_tmpl)); | ||
| 1225 | 1246 | ||
| 1226 | info->length = nanddev_page_size(nand) + | 1247 | info->length = nanddev_page_size(nand) + |
| 1227 | nanddev_per_page_oobsize(nand); | 1248 | nanddev_per_page_oobsize(nand); |
| @@ -1238,12 +1259,31 @@ static int spinand_create_dirmap(struct spinand_device *spinand, · 10 unmodified lines | |||
| 1238 | struct nand_device *nand = spinand_to_nand(spinand); | 1259 | struct nand_device *nand = spinand_to_nand(spinand); |
| 1239 | struct spi_mem_dirmap_info info = { 0 }; | 1260 | struct spi_mem_dirmap_info info = { 0 }; |
| 1240 | struct spi_mem_dirmap_desc *desc; | 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 | /* The plane number is passed in MSB just above the column address */ | 1280 | /* The plane number is passed in MSB just above the column address */ |
| 1243 | info.offset = plane << fls(nand->memorg.pagesize); | 1281 | info.offset = plane << fls(nand->memorg.pagesize); |
| 1244 | 1282 | ||
| 1283 | /* Write descriptor */ | ||
| 1245 | info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); | 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 | desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, | 1287 | desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, |
| 1248 | spinand->spimem, &info); | 1288 | spinand->spimem, &info); |
| 1249 | if (IS_ERR(desc)) | 1289 | if (IS_ERR(desc)) |
| @@ -1251,37 +1291,18 @@ static int spinand_create_dirmap(struct spinand_device *spinand, · 1 unmodified line | |||
| 1251 | 1291 | ||
| 1252 | spinand->dirmaps[plane].wdesc = desc; | 1292 | spinand->dirmaps[plane].wdesc = desc; |
| 1253 | 1293 | ||
| 1254 | info.op_tmpl = *spinand->op_templates->read_cache; | 1294 | /* Read descriptor */ |
| 1255 | desc = spinand_create_rdesc(spinand, &info); | 1295 | info.primary_op_tmpl = *spinand->op_templates->read_cache; |
| 1256 | if (IS_ERR(desc)) | 1296 | info.primary_op_tmpl.data.ecc = enable_ecc; |
| 1257 | return PTR_ERR(desc); | 1297 | if (secondary_op) { |
| 1258 | 1298 | info.secondary_op_tmpl = *spinand->op_templates->cont_read_cache; | |
| 1259 | spinand->dirmaps[plane].rdesc = desc; | 1299 | info.secondary_op_tmpl.data.ecc = enable_ecc; |
| 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; | ||
| 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 | desc = spinand_create_rdesc(spinand, &info); | 1301 | desc = spinand_create_rdesc(spinand, &info); |
| 1281 | if (IS_ERR(desc)) | 1302 | if (IS_ERR(desc)) |
| 1282 | return PTR_ERR(desc); | 1303 | return PTR_ERR(desc); |
| 1283 | 1304 | ||
| 1284 | spinand->dirmaps[plane].rdesc_ecc = desc; | 1305 | spinand->dirmaps[plane].rdesc = desc; |
| 1285 | 1306 | ||
| 1286 | return 0; | 1307 | return 0; |
| 1287 | } | 1308 | } |
| @@ -1307,6 +1328,22 @@ static int spinand_create_dirmaps(struct spinand_device *spinand) · 19 unmodified lines | |||
| 1307 | return 0; | 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 | static const struct nand_ops spinand_ops = { | 1347 | static const struct nand_ops spinand_ops = { |
| 1311 | .erase = spinand_erase, | 1348 | .erase = spinand_erase, |
| 1312 | .markbad = spinand_markbad, | 1349 | .markbad = spinand_markbad, |
| @@ -1407,7 +1444,7 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand) · 94 unmodified lines | |||
| 1407 | return spinand->manufacturer->ops->cleanup(spinand); | 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 | return op->cmd.dtr && op->cmd.buswidth == 8; | 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 | if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase)) | 1526 | if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase)) |
| 1490 | return -EOPNOTSUPP; | 1527 | return -EOPNOTSUPP; |
| 1491 | 1528 | ||
| 1492 | tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0); | 1529 | if (spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ) |
| 1493 | if (!spi_mem_supports_op(spinand->spimem, &tmpl->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 | return -EOPNOTSUPP; | 1534 | return -EOPNOTSUPP; |
| 1535 | } | ||
| 1495 | 1536 | ||
| 1496 | tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0); | 1537 | tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0); |
| 1497 | if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec)) | 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 | spinand->user_otp = &table[i].user_otp; | 1635 | spinand->user_otp = &table[i].user_otp; |
| 1595 | spinand->read_retries = table[i].read_retries; | 1636 | spinand->read_retries = table[i].read_retries; |
| 1596 | spinand->set_read_retry = table[i].set_read_retry; | 1637 | spinand->set_read_retry = table[i].set_read_retry; |
| 1638 | spinand->set_randomizer = table[i].set_randomizer; | ||
| 1597 | 1639 | ||
| 1598 | /* I/O variants selection with single-spi SDR commands */ | 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 | if (ret) | 1664 | if (ret) |
| 1623 | return ret; | 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 | /* I/O variants selection with octo-spi DDR commands (optional) */ | 1694 | /* I/O variants selection with octo-spi DDR commands (optional) */ |
| 1626 | 1695 | ||
| 1627 | ret = spinand_init_odtr_instruction_set(spinand); | 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 | info->op_variants.update_cache); | 1713 | info->op_variants.update_cache); |
| 1645 | spinand->odtr_op_templates.update_cache = op; | 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 | return 0; | 1725 | return 0; |
| 1648 | } | 1726 | } |
| 1649 | 1727 | ||
| @@ -1881,6 +1959,9 @@ static int spinand_init(struct spinand_device *spinand) · 231 unmodified lines | |||
| 1881 | * ECC initialization must have happened previously. | 1959 | * ECC initialization must have happened previously. |
| 1882 | */ | 1960 | */ |
| 1883 | spinand_cont_read_init(spinand); | 1961 | spinand_cont_read_init(spinand); |
| 1962 | ret = spinand_randomizer_init(spinand); | ||
| 1963 | if (ret) | ||
| 1964 | goto err_cleanup_nanddev; | ||
| 1884 | 1965 | ||
| 1885 | mtd->_read_oob = spinand_mtd_read; | 1966 | mtd->_read_oob = spinand_mtd_read; |
| 1886 | mtd->_write_oob = spinand_mtd_write; | 1967 | mtd->_write_oob = spinand_mtd_write; |
| @@ -14,6 +14,8 @@ · 13 unmodified lines | |||
| 14 | #define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr) | 14 | #define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr) |
| 15 | #define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr) | 15 | #define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr) |
| 16 | #define MACRONIX_CFG_CONT_READ BIT(2) | 16 | #define MACRONIX_CFG_CONT_READ BIT(2) |
| 17 | #define MACRONIX_CFG_RANDOMIZER_EN BIT(1) | ||
| 18 | #define MACRONIX_FEATURE_ADDR_RANDOMIZER 0x10 | ||
| 17 | #define MACRONIX_FEATURE_ADDR_READ_RETRY 0x70 | 19 | #define MACRONIX_FEATURE_ADDR_READ_RETRY 0x70 |
| 18 | #define MACRONIX_NUM_READ_RETRY_MODES 5 | 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 | return spi_mem_exec_op(spinand->spimem, &op); | 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 | static const struct spinand_info macronix_spinand_table[] = { | 181 | static const struct spinand_info macronix_spinand_table[] = { |
| 174 | SPINAND_INFO("MX35LF1GE4AB", | 182 | SPINAND_INFO("MX35LF1GE4AB", |
| 175 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12), | 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 | SPINAND_HAS_QE_BIT, | 239 | SPINAND_HAS_QE_BIT, |
| 232 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), | 240 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 233 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35LF2G24AD", | 244 | SPINAND_INFO("MX35LF2G24AD", |
| 236 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03), | 245 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03), |
| 237 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), | 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 | SPINAND_HAS_PROG_PLANE_SELECT_BIT, | 252 | SPINAND_HAS_PROG_PLANE_SELECT_BIT, |
| 244 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), | 253 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 245 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35LF2G24AD-Z4I8", | 257 | SPINAND_INFO("MX35LF2G24AD-Z4I8", |
| 248 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03), | 258 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03), |
| 249 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), | 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 | SPINAND_HAS_QE_BIT, | 264 | SPINAND_HAS_QE_BIT, |
| 255 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), | 265 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 256 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35LF4G24AD", | 269 | SPINAND_INFO("MX35LF4G24AD", |
| 259 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03), | 270 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03), |
| 260 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1), | 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 | SPINAND_HAS_PROG_PLANE_SELECT_BIT, | 277 | SPINAND_HAS_PROG_PLANE_SELECT_BIT, |
| 267 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), | 278 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 268 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35LF4G24AD-Z4I8", | 282 | SPINAND_INFO("MX35LF4G24AD-Z4I8", |
| 271 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03), | 283 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03), |
| 272 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), | 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 | SPINAND_HAS_QE_BIT, | 289 | SPINAND_HAS_QE_BIT, |
| 278 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), | 290 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), |
| 279 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX31LF1GE4BC", | 294 | SPINAND_INFO("MX31LF1GE4BC", |
| 282 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), | 295 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), |
| 283 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), | 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 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, | 340 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 328 | macronix_ecc_get_status), | 341 | macronix_ecc_get_status), |
| 329 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35UF4G24AD-Z4I8", | 345 | SPINAND_INFO("MX35UF4G24AD-Z4I8", |
| 332 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03), | 346 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03), |
| 333 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), | 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 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, | 354 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 341 | macronix_ecc_get_status), | 355 | macronix_ecc_get_status), |
| 342 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35UF4GE4AD", | 359 | SPINAND_INFO("MX35UF4GE4AD", |
| 345 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03), | 360 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03), |
| 346 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), | 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 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, | 396 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 382 | macronix_ecc_get_status), | 397 | macronix_ecc_get_status), |
| 383 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35UF2G24AD-Z4I8", | 401 | SPINAND_INFO("MX35UF2G24AD-Z4I8", |
| 386 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03), | 402 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03), |
| 387 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), | 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 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, | 410 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 395 | macronix_ecc_get_status), | 411 | macronix_ecc_get_status), |
| 396 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35UF2GE4AD", | 415 | SPINAND_INFO("MX35UF2GE4AD", |
| 399 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03), | 416 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03), |
| 400 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), | 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 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, | 461 | SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, |
| 445 | macronix_ecc_get_status), | 462 | macronix_ecc_get_status), |
| 446 | SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, | 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 | SPINAND_INFO("MX35UF1GE4AD", | 466 | SPINAND_INFO("MX35UF1GE4AD", |
| 449 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03), | 467 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03), |
| 450 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), | 468 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), |
| @@ -15,9 +15,11 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | #define SPINAND_MFR_WINBOND 0xEF | 16 | #define SPINAND_MFR_WINBOND 0xEF |
| 17 | 17 | ||
| 18 | #define WINBOND_CFG_HFREQ BIT(0) | ||
| 18 | #define WINBOND_CFG_BUF_READ BIT(3) | 19 | #define WINBOND_CFG_BUF_READ BIT(3) |
| 19 | 20 | ||
| 20 | #define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4) | 21 | #define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4) |
| 22 | #define W25W35NXXJW_STATUS_ECC_MULT_UNCOR (3 << 4) | ||
| 21 | 23 | ||
| 22 | #define W25N0XJW_SR4 0xD0 | 24 | #define W25N0XJW_SR4 0xD0 |
| 23 | #define W25N0XJW_SR4_HS BIT(2) | 25 | #define W25N0XJW_SR4_HS BIT(2) |
| @@ -29,6 +31,105 @@ · 5 unmodified lines | |||
| 29 | #define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7 | 31 | #define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7 |
| 30 | #define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01 | 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 | * "X2" in the core is equivalent to "dual output" in the datasheets, | 134 | * "X2" in the core is equivalent to "dual output" in the datasheets, |
| 34 | * "X4" in the core is equivalent to "quad output" in the datasheets. | 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 | SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), | 150 | SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), |
| 50 | SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); | 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 | static SPINAND_OP_VARIANTS(write_cache_octal_variants, | 166 | static SPINAND_OP_VARIANTS(write_cache_octal_variants, |
| 53 | SPINAND_PROG_LOAD_8D_8D_8D_OP(true, 0, NULL, 0), | 167 | SPINAND_PROG_LOAD_8D_8D_8D_OP(true, 0, NULL, 0), |
| 54 | SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0), | 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 | SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), | 189 | SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), |
| 76 | SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ)); | 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 | static SPINAND_OP_VARIANTS(read_cache_variants, | 206 | static SPINAND_OP_VARIANTS(read_cache_variants, |
| 79 | SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), | 207 | SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), |
| 80 | SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), | 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 | #define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \ | 228 | #define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \ |
| 101 | SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \ | 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 | SPI_MEM_OP_NO_DUMMY, \ | 231 | SPI_MEM_OP_NO_DUMMY, \ |
| 104 | SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8)) | 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 | return -EINVAL; | 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 | static int w25n0xjw_hs_cfg(struct spinand_device *spinand, | 510 | static int w25n0xjw_hs_cfg(struct spinand_device *spinand, |
| 330 | enum spinand_bus_interface iface) | 511 | enum spinand_bus_interface iface) |
| 331 | { | 512 | { |
| 332 | const struct spi_mem_op *op; | 513 | const struct spi_mem_op *op; |
| 333 | bool hs; | ||
| 334 | u8 sr4; | ||
| 335 | int ret; | ||
| 336 | 514 | ||
| 337 | if (iface != SSDR) | 515 | if (iface != SSDR) |
| 338 | return -EOPNOTSUPP; | 516 | return -EOPNOTSUPP; |
| 339 | 517 | ||
| 340 | /* | 518 | /* |
| 341 | * SDR dual and quad I/O operations over 104MHz require the HS bit to | 519 | * At this stage, we do not yet know the continuous read template, nor |
| 342 | * enable a few more dummy cycles. | 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 | op = spinand->op_templates->read_cache; | 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) | 527 | return w25n0xjw_set_sr4_hs(spinand, w25n0xjw_op_needs_hs(op)); |
| 359 | sr4 |= W25N0XJW_SR4_HS; | 528 | } |
| 360 | else | ||
| 361 | sr4 &= ~W25N0XJW_SR4_HS; | ||
| 362 | 529 | ||
| 363 | ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); | 530 | static int w25n0xjw_set_cont_read(struct spinand_device *spinand, bool enable) |
| 364 | if (ret) | 531 | { |
| 365 | return ret; | 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 | static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val) | 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 | return 0; | 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 | static const struct spinand_info winbond_spinand_table[] = { | 633 | static const struct spinand_info winbond_spinand_table[] = { |
| 455 | /* 512M-bit densities */ | 634 | /* 512M-bit densities */ |
| 456 | SPINAND_INFO("W25N512GW", /* 1.8V */ | 635 | SPINAND_INFO("W25N512GW", /* 1.8V */ |
| @@ -485,12 +664,14 @@ static const struct spinand_info winbond_spinand_table[] = { · 28 unmodified lines | |||
| 485 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), | 664 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), |
| 486 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), | 665 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), |
| 487 | NAND_ECCREQ(1, 512), | 666 | NAND_ECCREQ(1, 512), |
| 488 | SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, | 667 | SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_dual_quad_dtr_variants, |
| 489 | &write_cache_variants, | 668 | &write_cache_variants, |
| 490 | &update_cache_variants), | 669 | &update_cache_variants, |
| 670 | &cont_read_cache_dual_quad_dtr_variants), | ||
| 491 | SPINAND_HAS_QE_BIT, | 671 | SPINAND_HAS_QE_BIT, |
| 492 | SPINAND_ECCINFO(&w25n01jw_ooblayout, NULL), | 672 | SPINAND_ECCINFO(&w25n01jw_ooblayout, w25w35nxxjw_ecc_get_status), |
| 493 | SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), | 673 | SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg), |
| 674 | SPINAND_CONT_READ(w25n0xjw_set_cont_read)), | ||
| 494 | SPINAND_INFO("W25N01KV", /* 3.3V */ | 675 | SPINAND_INFO("W25N01KV", /* 3.3V */ |
| 495 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), | 676 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), |
| 496 | NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), | 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 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21), | 685 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21), |
| 505 | NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1), | 686 | NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1), |
| 506 | NAND_ECCREQ(1, 512), | 687 | NAND_ECCREQ(1, 512), |
| 507 | SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, | 688 | SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, |
| 508 | &write_cache_octal_variants, | 689 | &write_cache_octal_variants, |
| 509 | &update_cache_octal_variants), | 690 | &update_cache_octal_variants, |
| 691 | &cont_read_cache_octal_variants), | ||
| 510 | 0, | 692 | 0, |
| 511 | SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), | 693 | SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), |
| 512 | SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), | 694 | SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), |
| 513 | SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), | 695 | SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), |
| 514 | SPINAND_INFO("W35N02JW", /* 1.8V */ | 696 | SPINAND_CONT_READ(w35n0xjw_set_cont_read)), |
| 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)), | ||
| 536 | /* 2G-bit densities */ | 697 | /* 2G-bit densities */ |
| 537 | SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ | 698 | SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ |
| 538 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), | 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 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22), | 710 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22), |
| 550 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1), | 711 | NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1), |
| 551 | NAND_ECCREQ(1, 512), | 712 | NAND_ECCREQ(1, 512), |
| 552 | SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, | 713 | SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_dual_quad_dtr_variants, |
| 553 | &write_cache_variants, | 714 | &write_cache_variants, |
| 554 | &update_cache_variants), | 715 | &update_cache_variants, |
| 716 | &cont_read_cache_dual_quad_dtr_variants), | ||
| 555 | SPINAND_HAS_QE_BIT, | 717 | SPINAND_HAS_QE_BIT, |
| 556 | SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), | 718 | SPINAND_ECCINFO(&w25m02gv_ooblayout, w25w35nxxjw_ecc_get_status), |
| 557 | SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), | 719 | SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg), |
| 720 | SPINAND_CONT_READ(w25n0xjw_set_cont_read)), | ||
| 558 | SPINAND_INFO("W25N02KV", /* 3.3V */ | 721 | SPINAND_INFO("W25N02KV", /* 3.3V */ |
| 559 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), | 722 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), |
| 560 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), | 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 | &update_cache_variants), | 736 | &update_cache_variants), |
| 574 | 0, | 737 | 0, |
| 575 | SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), | 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 | /* 4G-bit densities */ | 752 | /* 4G-bit densities */ |
| 577 | SPINAND_INFO("W25N04KV", /* 3.3V */ | 753 | SPINAND_INFO("W25N04KV", /* 3.3V */ |
| 578 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), | 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 | &update_cache_variants), | 768 | &update_cache_variants), |
| 593 | 0, | 769 | 0, |
| 594 | SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), | 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 | static int winbond_spinand_init(struct spinand_device *spinand) | 786 | static int winbond_spinand_init(struct spinand_device *spinand) |
| @@ -3711,14 +3711,15 @@ EXPORT_SYMBOL_GPL(spi_nor_scan); · 3710 unmodified lines | |||
| 3711 | static int spi_nor_create_read_dirmap(struct spi_nor *nor) | 3711 | static int spi_nor_create_read_dirmap(struct spi_nor *nor) |
| 3712 | { | 3712 | { |
| 3713 | struct spi_mem_dirmap_info info = { | 3713 | struct spi_mem_dirmap_info info = { |
| 3714 | .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), | 3714 | .op_tmpl = &info.primary_op_tmpl, |
| 3715 | SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), | 3715 | .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), |
| 3716 | SPI_MEM_OP_DUMMY(nor->read_dummy, 0), | 3716 | SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), |
| 3717 | SPI_MEM_OP_DATA_IN(0, NULL, 0)), | 3717 | SPI_MEM_OP_DUMMY(nor->read_dummy, 0), |
| 3718 | SPI_MEM_OP_DATA_IN(0, NULL, 0)), | ||
| 3718 | .offset = 0, | 3719 | .offset = 0, |
| 3719 | .length = nor->params->size, | 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 | spi_nor_spimem_setup_op(nor, op, nor->read_proto); | 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 | static int spi_nor_create_write_dirmap(struct spi_nor *nor) | 3743 | static int spi_nor_create_write_dirmap(struct spi_nor *nor) |
| 3743 | { | 3744 | { |
| 3744 | struct spi_mem_dirmap_info info = { | 3745 | struct spi_mem_dirmap_info info = { |
| 3745 | .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), | 3746 | .op_tmpl = &info.primary_op_tmpl, |
| 3746 | SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), | 3747 | .primary_op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), |
| 3747 | SPI_MEM_OP_NO_DUMMY, | 3748 | SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), |
| 3748 | SPI_MEM_OP_DATA_OUT(0, NULL, 0)), | 3749 | SPI_MEM_OP_NO_DUMMY, |
| 3750 | SPI_MEM_OP_DATA_OUT(0, NULL, 0)), | ||
| 3749 | .offset = 0, | 3751 | .offset = 0, |
| 3750 | .length = nor->params->size, | 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 | if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) | 3756 | if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) |
| 3755 | op->addr.nbytes = 0; | 3757 | op->addr.nbytes = 0; |
| @@ -1,5 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | ||
| 3 | #include <linux/array_size.h> | ||
| 3 | #include <linux/debugfs.h> | 4 | #include <linux/debugfs.h> |
| 4 | #include <linux/math64.h> | 5 | #include <linux/math64.h> |
| 5 | #include <linux/mtd/spi-nor.h> | 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 | seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes); | 99 | seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes); |
| 99 | 100 | ||
| 100 | seq_puts(s, "flags\t\t"); | 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 | seq_puts(s, "\n"); | 104 | seq_puts(s, "\n"); |
| 103 | 105 | ||
| 104 | seq_puts(s, "\nopcodes\n"); | 106 | seq_puts(s, "\nopcodes\n"); |
| @@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, · 528 unmodified lines | |||
| 529 | struct in6_addr saddr; | 529 | struct in6_addr saddr; |
| 530 | struct socket *sock = rcu_dereference(bareudp->sock); | 530 | struct socket *sock = rcu_dereference(bareudp->sock); |
| 531 | 531 | ||
| 532 | if (!sock) | ||
| 533 | return -ESHUTDOWN; | ||
| 534 | |||
| 532 | dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, | 535 | dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, |
| 533 | 0, &saddr, &info->key, | 536 | 0, &saddr, &info->key, |
| 534 | sport, bareudp->port, info->key.tos, | 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 | static void ad_mux_machine(struct port *port, bool *update_slave_arr) | 1029 | static void ad_mux_machine(struct port *port, bool *update_slave_arr) |
| 1030 | { | 1030 | { |
| 1031 | struct bonding *bond = __get_bond_by_port(port); | 1031 | struct bonding *bond = __get_bond_by_port(port); |
| 1032 | struct aggregator *aggregator; | ||
| 1032 | mux_states_t last_state; | 1033 | mux_states_t last_state; |
| 1033 | 1034 | ||
| 1034 | /* keep current State Machine state to compare later if it was | 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 | last_state = port->sm_mux_state; | 1038 | last_state = port->sm_mux_state; |
| 1038 | 1039 | ||
| 1040 | aggregator = rcu_dereference(port->aggregator); | ||
| 1039 | if (port->sm_vars & AD_PORT_BEGIN) { | 1041 | if (port->sm_vars & AD_PORT_BEGIN) { |
| 1040 | port->sm_mux_state = AD_MUX_DETACHED; | 1042 | port->sm_mux_state = AD_MUX_DETACHED; |
| 1041 | } else { | 1043 | } else { |
| @@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 13 unmodified lines | |||
| 1055 | * cycle to update ready variable, we check | 1057 | * cycle to update ready variable, we check |
| 1056 | * READY_N and update READY here | 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 | port->sm_mux_state = AD_MUX_DETACHED; | 1061 | port->sm_mux_state = AD_MUX_DETACHED; |
| 1060 | break; | 1062 | break; |
| 1061 | } | 1063 | } |
| @@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) · 8 unmodified lines | |||
| 1070 | * update ready variable, we check READY_N and update | 1072 | * update ready variable, we check READY_N and update |
| 1071 | * READY here | 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 | /* if the wait_while_timer expired, and the port is | 1077 | /* if the wait_while_timer expired, and the port is |
| 1076 | * in READY state, move to ATTACHED state | 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 | if ((port->sm_vars & AD_PORT_SELECTED) && | 1088 | if ((port->sm_vars & AD_PORT_SELECTED) && |
| 1087 | (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && | 1089 | (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && |
| 1088 | !__check_agg_selection_timer(port)) { | 1090 | !__check_agg_selection_timer(port)) { |
| 1089 | if (port->aggregator->is_active) { | 1091 | if (aggregator->is_active) { |
| 1090 | int state = AD_MUX_COLLECTING_DISTRIBUTING; | 1092 | int state = AD_MUX_COLLECTING_DISTRIBUTING; |
| 1091 | 1093 | ||
| 1092 | if (!bond->params.coupled_control) | 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 | * cycle to update ready variable, we check | 1104 | * cycle to update ready variable, we check |
| 1103 | * READY_N and update READY here | 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 | port->sm_mux_state = AD_MUX_DETACHED; | 1108 | port->sm_mux_state = AD_MUX_DETACHED; |
| 1107 | } else if (port->aggregator->is_active) { | 1109 | } else if (aggregator->is_active) { |
| 1108 | port->actor_oper_port_state |= | 1110 | port->actor_oper_port_state |= |
| 1109 | LACP_STATE_SYNCHRONIZATION; | 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 | * sure that a collecting distributing | 1117 | * sure that a collecting distributing |
| 1116 | * port in an active aggregator is enabled | 1118 | * port in an active aggregator is enabled |
| 1117 | */ | 1119 | */ |
| 1118 | if (port->aggregator->is_active && | 1120 | if (aggregator->is_active && |
| 1119 | !__port_is_collecting_distributing(port)) { | 1121 | !__port_is_collecting_distributing(port)) { |
| 1120 | __enable_port(port); | 1122 | __enable_port(port); |
| 1121 | *update_slave_arr = true; | 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 | struct slave *slave = port->slave; | 1137 | struct slave *slave = port->slave; |
| 1136 | 1138 | ||
| 1137 | if (port->aggregator->is_active && | 1139 | if (aggregator->is_active && |
| 1138 | bond_is_slave_rx_disabled(slave)) { | 1140 | bond_is_slave_rx_disabled(slave)) { |
| 1139 | ad_enable_collecting(port); | 1141 | ad_enable_collecting(port); |
| 1140 | *update_slave_arr = true; | 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 | * sure that a collecting distributing | 1156 | * sure that a collecting distributing |
| 1155 | * port in an active aggregator is enabled | 1157 | * port in an active aggregator is enabled |
| 1156 | */ | 1158 | */ |
| 1157 | if (port->aggregator && | 1159 | if (aggregator && |
| 1158 | port->aggregator->is_active && | 1160 | aggregator->is_active && |
| 1159 | !__port_is_collecting_distributing(port)) { | 1161 | !__port_is_collecting_distributing(port)) { |
| 1160 | __enable_port(port); | 1162 | __enable_port(port); |
| 1161 | *update_slave_arr = true; | 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 | port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); | 1189 | port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); |
| 1188 | break; | 1190 | break; |
| 1189 | case AD_MUX_ATTACHED: | 1191 | case AD_MUX_ATTACHED: |
| 1190 | if (port->aggregator->is_active) | 1192 | if (aggregator->is_active) |
| 1191 | port->actor_oper_port_state |= | 1193 | port->actor_oper_port_state |= |
| 1192 | LACP_STATE_SYNCHRONIZATION; | 1194 | LACP_STATE_SYNCHRONIZATION; |
| 1193 | else | 1195 | else |
| @@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) · 367 unmodified lines | |||
| 1561 | bond = __get_bond_by_port(port); | 1563 | bond = __get_bond_by_port(port); |
| 1562 | 1564 | ||
| 1563 | /* if the port is connected to other aggregator, detach it */ | 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 | /* detach the port from its former aggregator */ | 1568 | /* detach the port from its former aggregator */ |
| 1566 | temp_aggregator = port->aggregator; | ||
| 1567 | for (curr_port = temp_aggregator->lag_ports; curr_port; | 1569 | for (curr_port = temp_aggregator->lag_ports; curr_port; |
| 1568 | last_port = curr_port, | 1570 | last_port = curr_port, |
| 1569 | curr_port = curr_port->next_port_in_aggregator) { | 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 | /* clear the port's relations to this | 1588 | /* clear the port's relations to this |
| 1587 | * aggregator | 1589 | * aggregator |
| 1588 | */ | 1590 | */ |
| 1589 | port->aggregator = NULL; | 1591 | RCU_INIT_POINTER(port->aggregator, NULL); |
| 1590 | port->next_port_in_aggregator = NULL; | 1592 | port->next_port_in_aggregator = NULL; |
| 1591 | port->actor_port_aggregator_identifier = 0; | 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 | port->slave->bond->dev->name, | 1611 | port->slave->bond->dev->name, |
| 1610 | port->slave->dev->name, | 1612 | port->slave->dev->name, |
| 1611 | port->actor_port_number, | 1613 | port->actor_port_number, |
| 1612 | port->aggregator->aggregator_identifier); | 1614 | temp_aggregator->aggregator_identifier); |
| 1613 | } | 1615 | } |
| 1614 | } | 1616 | } |
| 1615 | /* search on all aggregators for a suitable aggregator for this port */ | 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 | /* attach to the founded aggregator */ | 1637 | /* attach to the founded aggregator */ |
| 1636 | port->aggregator = aggregator; | 1638 | rcu_assign_pointer(port->aggregator, aggregator); |
| 1637 | port->actor_port_aggregator_identifier = | 1639 | port->actor_port_aggregator_identifier = |
| 1638 | port->aggregator->aggregator_identifier; | 1640 | aggregator->aggregator_identifier; |
| 1639 | port->next_port_in_aggregator = aggregator->lag_ports; | 1641 | port->next_port_in_aggregator = aggregator->lag_ports; |
| 1640 | port->aggregator->num_of_ports++; | 1642 | aggregator->num_of_ports++; |
| 1641 | aggregator->lag_ports = port; | 1643 | aggregator->lag_ports = port; |
| 1642 | slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", | 1644 | slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", |
| 1643 | port->actor_port_number, | 1645 | port->actor_port_number, |
| 1644 | port->aggregator->aggregator_identifier); | 1646 | aggregator->aggregator_identifier); |
| 1645 | 1647 | ||
| 1646 | /* mark this port as selected */ | 1648 | /* mark this port as selected */ |
| 1647 | port->sm_vars |= AD_PORT_SELECTED; | 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 | if (!found) { | 1658 | if (!found) { |
| 1657 | if (free_aggregator) { | 1659 | if (free_aggregator) { |
| 1658 | /* assign port a new aggregator */ | 1660 | /* assign port a new aggregator */ |
| 1659 | port->aggregator = free_aggregator; | ||
| 1660 | port->actor_port_aggregator_identifier = | 1661 | port->actor_port_aggregator_identifier = |
| 1661 | port->aggregator->aggregator_identifier; | 1662 | free_aggregator->aggregator_identifier; |
| 1662 | 1663 | ||
| 1663 | /* update the new aggregator's parameters | 1664 | /* update the new aggregator's parameters |
| 1664 | * if port was responsed from the end-user | 1665 | * if port was responsed from the end-user |
| 1665 | */ | 1666 | */ |
| 1666 | if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) | 1667 | if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) |
| 1667 | /* if port is full duplex */ | 1668 | /* if port is full duplex */ |
| 1668 | port->aggregator->is_individual = false; | 1669 | free_aggregator->is_individual = false; |
| 1669 | else | 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 | port->actor_admin_port_key; | 1674 | port->actor_admin_port_key; |
| 1674 | port->aggregator->actor_oper_aggregator_key = | 1675 | free_aggregator->actor_oper_aggregator_key = |
| 1675 | port->actor_oper_port_key; | 1676 | port->actor_oper_port_key; |
| 1676 | port->aggregator->partner_system = | 1677 | free_aggregator->partner_system = |
| 1677 | port->partner_oper.system; | 1678 | port->partner_oper.system; |
| 1678 | port->aggregator->partner_system_priority = | 1679 | free_aggregator->partner_system_priority = |
| 1679 | port->partner_oper.system_priority; | 1680 | port->partner_oper.system_priority; |
| 1680 | port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; | 1681 | free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; |
| 1681 | port->aggregator->receive_state = 1; | 1682 | free_aggregator->receive_state = 1; |
| 1682 | port->aggregator->transmit_state = 1; | 1683 | free_aggregator->transmit_state = 1; |
| 1683 | port->aggregator->lag_ports = port; | 1684 | free_aggregator->lag_ports = port; |
| 1684 | port->aggregator->num_of_ports++; | 1685 | free_aggregator->num_of_ports++; |
| 1686 | |||
| 1687 | rcu_assign_pointer(port->aggregator, free_aggregator); | ||
| 1685 | 1688 | ||
| 1686 | /* mark this port as selected */ | 1689 | /* mark this port as selected */ |
| 1687 | port->sm_vars |= AD_PORT_SELECTED; | 1690 | port->sm_vars |= AD_PORT_SELECTED; |
| 1688 | 1691 | ||
| 1689 | slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", | 1692 | slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", |
| 1690 | port->actor_port_number, | 1693 | port->actor_port_number, |
| 1691 | port->aggregator->aggregator_identifier); | 1694 | free_aggregator->aggregator_identifier); |
| 1692 | } else { | 1695 | } else { |
| 1693 | slave_err(bond->dev, port->slave->dev, | 1696 | slave_err(bond->dev, port->slave->dev, |
| 1694 | "Port %d did not find a suitable aggregator\n", | 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 | * in all aggregator's ports, else set ready=FALSE in all | 1703 | * in all aggregator's ports, else set ready=FALSE in all |
| 1701 | * aggregator's ports | 1704 | * aggregator's ports |
| 1702 | */ | 1705 | */ |
| 1703 | __set_agg_ports_ready(port->aggregator, | 1706 | aggregator = rcu_dereference(port->aggregator); |
| 1704 | __agg_ports_are_ready(port->aggregator)); | 1707 | __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); |
| 1705 | 1708 | ||
| 1706 | aggregator = __get_first_agg(port); | 1709 | ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); |
| 1707 | ad_agg_selection_logic(aggregator, update_slave_arr); | ||
| 1708 | 1710 | ||
| 1709 | if (!port->aggregator->is_active) | 1711 | if (!aggregator->is_active) |
| 1710 | port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; | 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 | static void ad_enable_collecting(struct port *port) | 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 | struct slave *slave = port->slave; | 2083 | struct slave *slave = port->slave; |
| 2080 | 2084 | ||
| 2081 | slave_dbg(slave->bond->dev, slave->dev, | 2085 | slave_dbg(slave->bond->dev, slave->dev, |
| 2082 | "Enabling collecting on port %d (LAG %d)\n", | 2086 | "Enabling collecting on port %d (LAG %d)\n", |
| 2083 | port->actor_port_number, | 2087 | port->actor_port_number, |
| 2084 | port->aggregator->aggregator_identifier); | 2088 | aggregator->aggregator_identifier); |
| 2085 | __enable_collecting_port(port); | 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 | static void ad_disable_distributing(struct port *port, bool *update_slave_arr) | 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 | slave_dbg(port->slave->bond->dev, port->slave->dev, | 2103 | slave_dbg(port->slave->bond->dev, port->slave->dev, |
| 2098 | "Disabling distributing on port %d (LAG %d)\n", | 2104 | "Disabling distributing on port %d (LAG %d)\n", |
| 2099 | port->actor_port_number, | 2105 | port->actor_port_number, |
| 2100 | port->aggregator->aggregator_identifier); | 2106 | aggregator->aggregator_identifier); |
| 2101 | __disable_distributing_port(port); | 2107 | __disable_distributing_port(port); |
| 2102 | /* Slave array needs an update */ | 2108 | /* Slave array needs an update */ |
| 2103 | *update_slave_arr = true; | 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 | static void ad_enable_collecting_distributing(struct port *port, | 2120 | static void ad_enable_collecting_distributing(struct port *port, |
| 2115 | bool *update_slave_arr) | 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 | slave_dbg(port->slave->bond->dev, port->slave->dev, | 2126 | slave_dbg(port->slave->bond->dev, port->slave->dev, |
| 2119 | "Enabling port %d (LAG %d)\n", | 2127 | "Enabling port %d (LAG %d)\n", |
| 2120 | port->actor_port_number, | 2128 | port->actor_port_number, |
| 2121 | port->aggregator->aggregator_identifier); | 2129 | aggregator->aggregator_identifier); |
| 2122 | __enable_port(port); | 2130 | __enable_port(port); |
| 2123 | /* Slave array needs update */ | 2131 | /* Slave array needs update */ |
| 2124 | *update_slave_arr = true; | 2132 | *update_slave_arr = true; |
| @@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port, · 10 unmodified lines | |||
| 2135 | static void ad_disable_collecting_distributing(struct port *port, | 2143 | static void ad_disable_collecting_distributing(struct port *port, |
| 2136 | bool *update_slave_arr) | 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 | slave_dbg(port->slave->bond->dev, port->slave->dev, | 2149 | slave_dbg(port->slave->bond->dev, port->slave->dev, |
| 2140 | "Disabling port %d (LAG %d)\n", | 2150 | "Disabling port %d (LAG %d)\n", |
| 2141 | port->actor_port_number, | 2151 | port->actor_port_number, |
| 2142 | port->aggregator->aggregator_identifier); | 2152 | aggregator->aggregator_identifier); |
| 2143 | __disable_port(port); | 2153 | __disable_port(port); |
| 2144 | /* Slave array needs an update */ | 2154 | /* Slave array needs an update */ |
| 2145 | *update_slave_arr = true; | 2155 | *update_slave_arr = true; |
| @@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave) · 233 unmodified lines | |||
| 2379 | */ | 2389 | */ |
| 2380 | for (temp_port = aggregator->lag_ports; temp_port; | 2390 | for (temp_port = aggregator->lag_ports; temp_port; |
| 2381 | temp_port = temp_port->next_port_in_aggregator) { | 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 | temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; | 2393 | temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; |
| 2384 | } | 2394 | } |
| 2385 | 2395 | ||
| @@ -2848,15 +2858,16 @@ out: · 462 unmodified lines | |||
| 2848 | int __bond_3ad_get_active_agg_info(struct bonding *bond, | 2858 | int __bond_3ad_get_active_agg_info(struct bonding *bond, |
| 2849 | struct ad_info *ad_info) | 2859 | struct ad_info *ad_info) |
| 2850 | { | 2860 | { |
| 2851 | struct aggregator *aggregator = NULL; | 2861 | struct aggregator *aggregator = NULL, *tmp; |
| 2852 | struct list_head *iter; | 2862 | struct list_head *iter; |
| 2853 | struct slave *slave; | 2863 | struct slave *slave; |
| 2854 | struct port *port; | 2864 | struct port *port; |
| 2855 | 2865 | ||
| 2856 | bond_for_each_slave_rcu(bond, slave, iter) { | 2866 | bond_for_each_slave_rcu(bond, slave, iter) { |
| 2857 | port = &(SLAVE_AD_INFO(slave)->port); | 2867 | port = &(SLAVE_AD_INFO(slave)->port); |
| 2858 | if (port->aggregator && port->aggregator->is_active) { | 2868 | tmp = rcu_dereference(port->aggregator); |
| 2859 | aggregator = port->aggregator; | 2869 | if (tmp && tmp->is_active) { |
| 2870 | aggregator = tmp; | ||
| 2860 | break; | 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 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { | 1434 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { |
| 1435 | struct aggregator *agg = | 1435 | struct aggregator *agg = |
| 1436 | SLAVE_AD_INFO(slave)->port.aggregator; | 1436 | rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); |
| 1437 | 1437 | ||
| 1438 | if (agg && | 1438 | if (agg && |
| 1439 | agg->aggregator_identifier != ad_info.aggregator_id) | 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 | spin_unlock_bh(&bond->mode_lock); | 5179 | spin_unlock_bh(&bond->mode_lock); |
| 5180 | agg_id = ad_info.aggregator_id; | 5180 | agg_id = ad_info.aggregator_id; |
| 5181 | } | 5181 | } |
| 5182 | rcu_read_lock(); | ||
| 5182 | bond_for_each_slave(bond, slave, iter) { | 5183 | bond_for_each_slave(bond, slave, iter) { |
| 5183 | if (skipslave == slave) | 5184 | if (skipslave == slave) |
| 5184 | continue; | 5185 | continue; |
| 5185 | 5186 | ||
| 5186 | all_slaves->arr[all_slaves->count++] = slave; | 5187 | all_slaves->arr[all_slaves->count++] = slave; |
| 5187 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { | 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 | if (!agg || agg->aggregator_identifier != agg_id) | 5192 | if (!agg || agg->aggregator_identifier != agg_id) |
| 5192 | continue; | 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 | usable_slaves->arr[usable_slaves->count++] = slave; | 5201 | usable_slaves->arr[usable_slaves->count++] = slave; |
| 5201 | } | 5202 | } |
| 5203 | rcu_read_unlock(); | ||
| 5202 | 5204 | ||
| 5203 | bond_set_slave_arr(bond, usable_slaves, all_slaves); | 5205 | bond_set_slave_arr(bond, usable_slaves, all_slaves); |
| 5204 | return ret; | 5206 | return ret; |
| @@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb, · 65 unmodified lines | |||
| 66 | const struct port *ad_port; | 66 | const struct port *ad_port; |
| 67 | 67 | ||
| 68 | ad_port = &SLAVE_AD_INFO(slave)->port; | 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 | if (agg) { | 71 | if (agg) { |
| 71 | if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, | 72 | if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, |
| 72 | agg->aggregator_identifier)) | 73 | agg->aggregator_identifier)) |
| 73 | goto nla_put_failure; | 74 | goto nla_put_failure_rcu; |
| 74 | if (nla_put_u8(skb, | 75 | if (nla_put_u8(skb, |
| 75 | IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, | 76 | IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, |
| 76 | ad_port->actor_oper_port_state)) | 77 | ad_port->actor_oper_port_state)) |
| 77 | goto nla_put_failure; | 78 | goto nla_put_failure_rcu; |
| 78 | if (nla_put_u16(skb, | 79 | if (nla_put_u16(skb, |
| 79 | IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, | 80 | IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, |
| 80 | ad_port->partner_oper.port_state)) | 81 | ad_port->partner_oper.port_state)) |
| 81 | goto nla_put_failure; | 82 | goto nla_put_failure_rcu; |
| 82 | 83 | ||
| 83 | if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, | 84 | if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, |
| 84 | ad_port->sm_churn_actor_state)) | 85 | ad_port->sm_churn_actor_state)) |
| 85 | goto nla_put_failure; | 86 | goto nla_put_failure_rcu; |
| 86 | if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, | 87 | if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, |
| 87 | ad_port->sm_churn_partner_state)) | 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 | if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, | 93 | if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, |
| 92 | SLAVE_AD_INFO(slave)->port_priority)) | 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 | return 0; | 98 | return 0; |
| 97 | 99 | ||
| 100 | nla_put_failure_rcu: | ||
| 101 | rcu_read_unlock(); | ||
| 98 | nla_put_failure: | 102 | nla_put_failure: |
| 99 | return -EMSGSIZE; | 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 | static void bond_info_show_slave(struct seq_file *seq, | 192 | static void bond_info_show_slave(struct seq_file *seq, |
| 192 | const struct slave *slave) | 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 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { | 216 | if (BOND_MODE(bond) == BOND_MODE_8023AD) { |
| 216 | const struct port *port = &SLAVE_AD_INFO(slave)->port; | 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 | if (agg) { | 220 | if (agg) { |
| 220 | seq_printf(seq, "Aggregator ID: %d\n", | 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 | const struct aggregator *agg; | 62 | const struct aggregator *agg; |
| 63 | 63 | ||
| 64 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { | 64 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { |
| 65 | agg = SLAVE_AD_INFO(slave)->port.aggregator; | 65 | rcu_read_lock(); |
| 66 | if (agg) | 66 | agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); |
| 67 | return sysfs_emit(buf, "%d\n", | 67 | if (agg) { |
| 68 | agg->aggregator_identifier); | 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 | return sysfs_emit(buf, "N/A\n"); | 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 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { | 84 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { |
| 80 | ad_port = &SLAVE_AD_INFO(slave)->port; | 85 | ad_port = &SLAVE_AD_INFO(slave)->port; |
| 81 | if (ad_port->aggregator) | 86 | if (rcu_access_pointer(ad_port->aggregator)) |
| 82 | return sysfs_emit(buf, "%u\n", | 87 | return sysfs_emit(buf, "%u\n", |
| 83 | ad_port->actor_oper_port_state); | 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 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { | 99 | if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { |
| 95 | ad_port = &SLAVE_AD_INFO(slave)->port; | 100 | ad_port = &SLAVE_AD_INFO(slave)->port; |
| 96 | if (ad_port->aggregator) | 101 | if (rcu_access_pointer(ad_port->aggregator)) |
| 97 | return sysfs_emit(buf, "%u\n", | 102 | return sysfs_emit(buf, "%u\n", |
| 98 | ad_port->partner_oper.port_state); | 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 | struct airoha_qdma *qdma = q->qdma; | 848 | struct airoha_qdma *qdma = q->qdma; |
| 849 | struct airoha_eth *eth = qdma->eth; | 849 | struct airoha_eth *eth = qdma->eth; |
| 850 | int i; | 850 | int i, qid = q - &qdma->q_tx[0]; |
| 851 | 851 | ||
| 852 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { | 852 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { |
| 853 | struct airoha_gdm_port *port = eth->ports[i]; | 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) | 862 | for (j = 0; j < port->dev->num_tx_queues; j++) { |
| 856 | netif_tx_wake_all_queues(port->dev); | 863 | if (airoha_qdma_get_txq(qdma, j) != qid) |
| 864 | continue; | ||
| 865 | |||
| 866 | netif_wake_subqueue(port->dev, j); | ||
| 867 | } | ||
| 857 | } | 868 | } |
| 858 | q->txq_stopped = false; | 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 | q->queued--; | 940 | q->queued--; |
| 930 | 941 | ||
| 931 | if (skb) { | 942 | if (skb) { |
| 932 | u16 queue = skb_get_queue_mapping(skb); | ||
| 933 | struct netdev_queue *txq; | 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 | netdev_tx_completed_queue(txq, 1, skb->len); | 946 | netdev_tx_completed_queue(txq, 1, skb->len); |
| 937 | dev_kfree_skb_any(skb); | 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 | struct airoha_gdm_port *port = netdev_priv(dev); | 1748 | struct airoha_gdm_port *port = netdev_priv(dev); |
| 1739 | struct airoha_qdma *qdma = port->qdma; | 1749 | struct airoha_qdma *qdma = port->qdma; |
| 1740 | int i, err; | 1750 | int i; |
| 1741 | 1751 | ||
| 1742 | netif_tx_disable(dev); | 1752 | netif_tx_disable(dev); |
| 1743 | err = airoha_set_vip_for_gdm_port(port, false); | 1753 | airoha_set_vip_for_gdm_port(port, false); |
| 1744 | if (err) | 1754 | for (i = 0; i < dev->num_tx_queues; i++) |
| 1745 | return err; | ||
| 1746 | |||
| 1747 | for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) | ||
| 1748 | netdev_tx_reset_subqueue(dev, i); | 1755 | netdev_tx_reset_subqueue(dev, i); |
| 1749 | 1756 | ||
| 1750 | airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), | 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 | struct netdev_queue *txq; | 2004 | struct netdev_queue *txq; |
| 1998 | struct airoha_queue *q; | 2005 | struct airoha_queue *q; |
| 1999 | LIST_HEAD(tx_list); | 2006 | LIST_HEAD(tx_list); |
| 2007 | int i = 0, qid; | ||
| 2000 | void *data; | 2008 | void *data; |
| 2001 | int i, qid; | ||
| 2002 | u16 index; | 2009 | u16 index; |
| 2003 | u8 fport; | 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 | tag = airoha_get_dsa_tag(skb, dev); | 2013 | tag = airoha_get_dsa_tag(skb, dev); |
| 2007 | 2014 | ||
| 2008 | msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, | 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 | spin_lock_bh(&q->lock); | 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 | nr_frags = 1 + skb_shinfo(skb)->nr_frags; | 2050 | nr_frags = 1 + skb_shinfo(skb)->nr_frags; |
| 2044 | 2051 | ||
| 2045 | if (q->queued + nr_frags >= q->ndesc) { | 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 | list); | 2064 | list); |
| 2058 | index = e - q->entry; | 2065 | index = e - q->entry; |
| 2059 | 2066 | ||
| 2060 | for (i = 0; i < nr_frags; i++) { | 2067 | while (true) { |
| 2061 | struct airoha_qdma_desc *desc = &q->desc[index]; | 2068 | struct airoha_qdma_desc *desc = &q->desc[index]; |
| 2062 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | 2069 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
| 2063 | dma_addr_t addr; | 2070 | dma_addr_t addr; |
| @@ -2069,7 +2076,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 5 unmodified lines | |||
| 2069 | goto error_unmap; | 2076 | goto error_unmap; |
| 2070 | 2077 | ||
| 2071 | list_move_tail(&e->list, &tx_list); | 2078 | list_move_tail(&e->list, &tx_list); |
| 2072 | e->skb = i ? NULL : skb; | 2079 | e->skb = i == nr_frags - 1 ? skb : NULL; |
| 2073 | e->dma_addr = addr; | 2080 | e->dma_addr = addr; |
| 2074 | e->dma_len = len; | 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 | WRITE_ONCE(desc->msg1, cpu_to_le32(msg1)); | 2095 | WRITE_ONCE(desc->msg1, cpu_to_le32(msg1)); |
| 2089 | WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff)); | 2096 | WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff)); |
| 2090 | 2097 | ||
| 2098 | if (++i == nr_frags) | ||
| 2099 | break; | ||
| 2100 | |||
| 2091 | data = skb_frag_address(frag); | 2101 | data = skb_frag_address(frag); |
| 2092 | len = skb_frag_size(frag); | 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 | skb_tx_timestamp(skb); | 2106 | skb_tx_timestamp(skb); |
| 2097 | netdev_tx_sent_queue(txq, skb->len); | 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 | if (netif_xmit_stopped(txq) || !netdev_xmit_more()) | 2113 | if (netif_xmit_stopped(txq) || !netdev_xmit_more()) |
| 2100 | airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), | 2114 | airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), |
| 2101 | TX_RING_CPU_IDX_MASK, | 2115 | TX_RING_CPU_IDX_MASK, |
| 2102 | FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); | 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 | spin_unlock_bh(&q->lock); | 2118 | spin_unlock_bh(&q->lock); |
| 2110 | 2119 | ||
| 2111 | return NETDEV_TX_OK; | 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 | #define airoha_qdma_clear(qdma, offset, val) \ | 631 | #define airoha_qdma_clear(qdma, offset, val) \ |
| 632 | airoha_rmw((qdma)->regs, (offset), (val), 0) | 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 | static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) | 639 | static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) |
| 635 | { | 640 | { |
| 636 | /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. | 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 | return 0; | 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 | static const struct net_device_ops ibmveth_netdev_ops = { | 1780 | static const struct net_device_ops ibmveth_netdev_ops = { |
| 1760 | .ndo_open = ibmveth_open, | 1781 | .ndo_open = ibmveth_open, |
| 1761 | .ndo_stop = ibmveth_close, | 1782 | .ndo_stop = ibmveth_close, |
| @@ -1767,6 +1788,7 @@ static const struct net_device_ops ibmveth_netdev_ops = { · 5 unmodified lines | |||
| 1767 | .ndo_set_features = ibmveth_set_features, | 1788 | .ndo_set_features = ibmveth_set_features, |
| 1768 | .ndo_validate_addr = eth_validate_addr, | 1789 | .ndo_validate_addr = eth_validate_addr, |
| 1769 | .ndo_set_mac_address = ibmveth_set_mac_addr, | 1790 | .ndo_set_mac_address = ibmveth_set_mac_addr, |
| 1791 | .ndo_features_check = ibmveth_features_check, | ||
| 1770 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1792 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| 1771 | .ndo_poll_controller = ibmveth_poll_controller, | 1793 | .ndo_poll_controller = ibmveth_poll_controller, |
| 1772 | #endif | 1794 | #endif |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | |||
| 37 | #define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL | 37 | #define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL |
| 38 | #define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL | 38 | #define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL |
| 39 | 39 | ||
| 40 | #define IBMVETH_MIN_LSO_MSS 224 /* Minimum MSS for LSO */ | ||
| 40 | /* hcall macros */ | 41 | /* hcall macros */ |
| 41 | #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ | 42 | #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ |
| 42 | plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac) | 43 | plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac) |
| @@ -158,11 +158,10 @@ struct iavf_vlan { · 157 unmodified lines | |||
| 158 | enum iavf_vlan_state_t { | 158 | enum iavf_vlan_state_t { |
| 159 | IAVF_VLAN_INVALID, | 159 | IAVF_VLAN_INVALID, |
| 160 | IAVF_VLAN_ADD, /* filter needs to be added */ | 160 | IAVF_VLAN_ADD, /* filter needs to be added */ |
| 161 | IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ | 161 | IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ |
| 162 | IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ | 162 | IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ |
| 163 | IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ | 163 | IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ |
| 164 | IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ | 164 | IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ |
| 165 | IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ | ||
| 166 | }; | 165 | }; |
| 167 | 166 | ||
| 168 | struct iavf_vlan_filter { | 167 | struct iavf_vlan_filter { |
| @@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, · 756 unmodified lines | |||
| 757 | adapter->num_vlan_filters++; | 757 | adapter->num_vlan_filters++; |
| 758 | iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); | 758 | iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); |
| 759 | } else if (f->state == IAVF_VLAN_REMOVE) { | 759 | } else if (f->state == IAVF_VLAN_REMOVE) { |
| 760 | /* Re-add the filter since we cannot tell whether the | 760 | /* DEL not yet sent to PF, cancel it */ |
| 761 | * pending delete has already been processed by the PF. | 761 | f->state = IAVF_VLAN_ACTIVE; |
| 762 | * A duplicate add is harmless. | 762 | } else if (f->state == IAVF_VLAN_REMOVING) { |
| 763 | */ | 763 | /* DEL already sent to PF, re-add after completion */ |
| 764 | f->state = IAVF_VLAN_ADD; | 764 | f->state = IAVF_VLAN_ADD; |
| 765 | iavf_schedule_aq_request(adapter, | 765 | iavf_schedule_aq_request(adapter, |
| 766 | IAVF_FLAG_AQ_ADD_VLAN_FILTER); | 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 | list_del(&f->list); | 791 | list_del(&f->list); |
| 792 | kfree(f); | 792 | kfree(f); |
| 793 | adapter->num_vlan_filters--; | 793 | adapter->num_vlan_filters--; |
| 794 | } else { | 794 | } else if (f->state != IAVF_VLAN_REMOVING) { |
| 795 | f->state = IAVF_VLAN_REMOVE; | 795 | f->state = IAVF_VLAN_REMOVE; |
| 796 | iavf_schedule_aq_request(adapter, | 796 | iavf_schedule_aq_request(adapter, |
| 797 | IAVF_FLAG_AQ_DEL_VLAN_FILTER); | 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 | spin_unlock_bh(&adapter->mac_vlan_list_lock); | 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 | * iavf_get_num_vlans_added - get number of VLANs added | 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 | 1231 | * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark |
| 1250 | * yet and mark other to be removed. | 1232 | * others to be removed. |
| 1251 | * @adapter: board private structure | 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 | struct iavf_mac_filter *f, *ftmp; | 1237 | struct iavf_mac_filter *f, *ftmp; |
| 1257 | 1238 | ||
| 1258 | spin_lock_bh(&adapter->mac_vlan_list_lock); | 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 | spin_unlock_bh(&adapter->mac_vlan_list_lock); | 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 | iavf_napi_disable_all(adapter); | 1347 | iavf_napi_disable_all(adapter); |
| 1372 | iavf_irq_disable(adapter); | 1348 | iavf_irq_disable(adapter); |
| 1373 | 1349 | ||
| 1374 | iavf_clear_mac_vlan_filters(adapter); | 1350 | iavf_clear_mac_filters(adapter); |
| 1375 | iavf_clear_cloud_filters(adapter); | 1351 | iavf_clear_cloud_filters(adapter); |
| 1376 | iavf_clear_fdir_filters(adapter); | 1352 | iavf_clear_fdir_filters(adapter); |
| 1377 | iavf_clear_adv_rss_conf(adapter); | 1353 | iavf_clear_adv_rss_conf(adapter); |
| @@ -1388,8 +1364,6 @@ void iavf_down(struct iavf_adapter *adapter) · 10 unmodified lines | |||
| 1388 | */ | 1364 | */ |
| 1389 | if (!list_empty(&adapter->mac_filter_list)) | 1365 | if (!list_empty(&adapter->mac_filter_list)) |
| 1390 | adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; | 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 | if (!list_empty(&adapter->cloud_filter_list)) | 1367 | if (!list_empty(&adapter->cloud_filter_list)) |
| 1394 | adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; | 1368 | adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; |
| 1395 | if (!list_empty(&adapter->fdir_list_head)) | 1369 | if (!list_empty(&adapter->fdir_list_head)) |
| @@ -4494,8 +4468,6 @@ static int iavf_open(struct net_device *netdev) · 3098 unmodified lines | |||
| 4494 | iavf_add_filter(adapter, adapter->hw.mac.addr); | 4468 | iavf_add_filter(adapter, adapter->hw.mac.addr); |
| 4495 | spin_unlock_bh(&adapter->mac_vlan_list_lock); | 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 | iavf_restore_fdir_filters(adapter); | 4471 | iavf_restore_fdir_filters(adapter); |
| 4500 | 4472 | ||
| 4501 | iavf_configure(adapter); | 4473 | iavf_configure(adapter); |
| @@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) · 745 unmodified lines | |||
| 746 | 746 | ||
| 747 | spin_lock_bh(&adapter->mac_vlan_list_lock); | 747 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| 748 | list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | 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 | list_del(&f->list); | 750 | list_del(&f->list); |
| 751 | kfree(f); | 751 | kfree(f); |
| 752 | adapter->num_vlan_filters--; | 752 | adapter->num_vlan_filters--; |
| @@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) · 59 unmodified lines | |||
| 812 | if (f->state == IAVF_VLAN_ADD) { | 812 | if (f->state == IAVF_VLAN_ADD) { |
| 813 | vvfl->vlan_id[i] = f->vlan.vid; | 813 | vvfl->vlan_id[i] = f->vlan.vid; |
| 814 | i++; | 814 | i++; |
| 815 | f->state = IAVF_VLAN_IS_NEW; | 815 | f->state = IAVF_VLAN_ADDING; |
| 816 | if (i == count) | 816 | if (i == count) |
| 817 | break; | 817 | break; |
| 818 | } | 818 | } |
| @@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) · 55 unmodified lines | |||
| 874 | vlan->tpid = f->vlan.tpid; | 874 | vlan->tpid = f->vlan.tpid; |
| 875 | 875 | ||
| 876 | i++; | 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 | spin_lock_bh(&adapter->mac_vlan_list_lock); | 911 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| 912 | 912 | ||
| 913 | list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | 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 | if (f->state == IAVF_VLAN_REMOVE && | 914 | if (f->state == IAVF_VLAN_REMOVE && |
| 921 | !VLAN_FILTERING_ALLOWED(adapter)) { | 915 | !VLAN_FILTERING_ALLOWED(adapter)) { |
| 922 | list_del(&f->list); | 916 | list_del(&f->list); |
| 923 | kfree(f); | 917 | kfree(f); |
| 924 | adapter->num_vlan_filters--; | 918 | adapter->num_vlan_filters--; |
| 925 | } else if (f->state == IAVF_VLAN_DISABLE && | 919 | } else if (f->state == IAVF_VLAN_REMOVE) { |
| 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) { | ||
| 930 | count++; | 920 | count++; |
| 931 | } | 921 | } |
| 932 | } | 922 | } |
| @@ -958,18 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 25 unmodified lines | |||
| 958 | 948 | ||
| 959 | vvfl->vsi_id = adapter->vsi_res->vsi_id; | 949 | vvfl->vsi_id = adapter->vsi_res->vsi_id; |
| 960 | vvfl->num_elements = count; | 950 | vvfl->num_elements = count; |
| 961 | list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | 951 | list_for_each_entry(f, &adapter->vlan_filter_list, list) { |
| 962 | if (f->state == IAVF_VLAN_DISABLE) { | 952 | if (f->state == IAVF_VLAN_REMOVE) { |
| 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) { | ||
| 969 | vvfl->vlan_id[i] = f->vlan.vid; | 953 | vvfl->vlan_id[i] = f->vlan.vid; |
| 970 | list_del(&f->list); | 954 | f->state = IAVF_VLAN_REMOVING; |
| 971 | kfree(f); | ||
| 972 | adapter->num_vlan_filters--; | ||
| 973 | i++; | 955 | i++; |
| 974 | if (i == count) | 956 | if (i == count) |
| 975 | break; | 957 | break; |
| @@ -1006,9 +988,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 30 unmodified lines | |||
| 1006 | 988 | ||
| 1007 | vvfl_v2->vport_id = adapter->vsi_res->vsi_id; | 989 | vvfl_v2->vport_id = adapter->vsi_res->vsi_id; |
| 1008 | vvfl_v2->num_elements = count; | 990 | vvfl_v2->num_elements = count; |
| 1009 | list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | 991 | list_for_each_entry(f, &adapter->vlan_filter_list, list) { |
| 1010 | if (f->state == IAVF_VLAN_DISABLE || | 992 | if (f->state == IAVF_VLAN_REMOVE) { |
| 1011 | f->state == IAVF_VLAN_REMOVE) { | ||
| 1012 | struct virtchnl_vlan_supported_caps *filtering_support = | 993 | struct virtchnl_vlan_supported_caps *filtering_support = |
| 1013 | &adapter->vlan_v2_caps.filtering.filtering_support; | 994 | &adapter->vlan_v2_caps.filtering.filtering_support; |
| 1014 | struct virtchnl_vlan *vlan; | 995 | struct virtchnl_vlan *vlan; |
| @@ -1022,13 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) · 7 unmodified lines | |||
| 1022 | vlan->tci = f->vlan.vid; | 1003 | vlan->tci = f->vlan.vid; |
| 1023 | vlan->tpid = f->vlan.tpid; | 1004 | vlan->tpid = f->vlan.tpid; |
| 1024 | 1005 | ||
| 1025 | if (f->state == IAVF_VLAN_DISABLE) { | 1006 | f->state = IAVF_VLAN_REMOVING; |
| 1026 | f->state = IAVF_VLAN_INACTIVE; | ||
| 1027 | } else { | ||
| 1028 | list_del(&f->list); | ||
| 1029 | kfree(f); | ||
| 1030 | adapter->num_vlan_filters--; | ||
| 1031 | } | ||
| 1032 | i++; | 1007 | i++; |
| 1033 | if (i == count) | 1008 | if (i == count) |
| 1034 | break; | 1009 | break; |
| @@ -2391,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, · 1356 unmodified lines | |||
| 2391 | ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); | 2366 | ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); |
| 2392 | wake_up(&adapter->vc_waitqueue); | 2367 | wake_up(&adapter->vc_waitqueue); |
| 2393 | break; | 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 | case VIRTCHNL_OP_DEL_ETH_ADDR: | 2369 | case VIRTCHNL_OP_DEL_ETH_ADDR: |
| 2399 | dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", | 2370 | dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", |
| 2400 | iavf_stat_str(&adapter->hw, v_retval)); | 2371 | iavf_stat_str(&adapter->hw, v_retval)); |
| @@ -2905,17 +2876,42 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, · 504 unmodified lines | |||
| 2905 | spin_unlock_bh(&adapter->adv_rss_lock); | 2876 | spin_unlock_bh(&adapter->adv_rss_lock); |
| 2906 | } | 2877 | } |
| 2907 | break; | 2878 | break; |
| 2879 | case VIRTCHNL_OP_ADD_VLAN: | ||
| 2908 | case VIRTCHNL_OP_ADD_VLAN_V2: { | 2880 | case VIRTCHNL_OP_ADD_VLAN_V2: { |
| 2909 | struct iavf_vlan_filter *f; | 2881 | struct iavf_vlan_filter *f; |
| 2910 | 2882 | ||
| 2883 | if (v_retval) | ||
| 2884 | break; | ||
| 2885 | |||
| 2911 | spin_lock_bh(&adapter->mac_vlan_list_lock); | 2886 | spin_lock_bh(&adapter->mac_vlan_list_lock); |
| 2912 | list_for_each_entry(f, &adapter->vlan_filter_list, list) { | 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 | f->state = IAVF_VLAN_ACTIVE; | 2889 | f->state = IAVF_VLAN_ACTIVE; |
| 2915 | } | 2890 | } |
| 2916 | spin_unlock_bh(&adapter->mac_vlan_list_lock); | 2891 | spin_unlock_bh(&adapter->mac_vlan_list_lock); |
| 2917 | } | 2892 | } |
| 2918 | break; | 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 | case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: | 2915 | case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: |
| 2920 | /* PF enabled vlan strip on this VF. | 2916 | /* PF enabled vlan strip on this VF. |
| 2921 | * Update netdev->features if needed to be in sync with ethtool. | 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 | return err; | 1245 | return err; |
| 1246 | } | 1246 | } |
| 1247 | 1247 | ||
| 1248 | ice_init_dev_hw(pf); | ||
| 1249 | |||
| 1248 | /* load MSI-X values */ | 1250 | /* load MSI-X values */ |
| 1249 | ice_set_min_max_msix(pf); | 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 | if (status) | 1126 | if (status) |
| 1127 | goto err_unroll_fltr_mgmt_struct; | 1127 | goto err_unroll_fltr_mgmt_struct; |
| 1128 | 1128 | ||
| 1129 | ice_init_dev_hw(hw->back); | ||
| 1130 | |||
| 1131 | mutex_init(&hw->tnl_lock); | 1129 | mutex_init(&hw->tnl_lock); |
| 1132 | ice_init_chk_recipe_reuse_support(hw); | 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 | extack, ICE_DPLL_PIN_TYPE_INPUT); | 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 | * ice_dpll_sma_direction_set - set direction of SMA pin | 1184 | * ice_dpll_sma_direction_set - set direction of SMA pin |
| 1159 | * @p: pointer to a pin | 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 | enum dpll_pin_direction direction, | 1197 | enum dpll_pin_direction direction, |
| 1172 | struct netlink_ext_ack *extack) | 1198 | struct netlink_ext_ack *extack) |
| 1173 | { | 1199 | { |
| 1200 | struct ice_dplls *d = &p->pf->dplls; | ||
| 1201 | struct ice_dpll_pin *peer; | ||
| 1174 | u8 data; | 1202 | u8 data; |
| 1175 | int ret; | 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 | case ICE_DPLL_PIN_SW_2_IDX: | 1217 | case ICE_DPLL_PIN_SW_2_IDX: |
| 1190 | if (direction == DPLL_PIN_DIRECTION_INPUT) { | 1218 | if (direction == DPLL_PIN_DIRECTION_INPUT) { |
| 1191 | data &= ~ICE_SMA2_DIR_EN; | 1219 | data &= ~ICE_SMA2_DIR_EN; |
| 1220 | data |= ICE_SMA2_UFL2_RX_DIS; | ||
| 1192 | } else { | 1221 | } else { |
| 1193 | data &= ~ICE_SMA2_TX_EN; | 1222 | data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS); |
| 1194 | data |= ICE_SMA2_DIR_EN; | 1223 | data |= ICE_SMA2_DIR_EN; |
| 1195 | } | 1224 | } |
| 1196 | break; | 1225 | break; |
| @@ -1202,6 +1231,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, · 5 unmodified lines | |||
| 1202 | ret = ice_dpll_pin_state_update(p->pf, p, | 1231 | ret = ice_dpll_pin_state_update(p->pf, p, |
| 1203 | ICE_DPLL_PIN_TYPE_SOFTWARE, | 1232 | ICE_DPLL_PIN_TYPE_SOFTWARE, |
| 1204 | extack); | 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 | return ret; | 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 | data &= ~ICE_SMA1_MASK; | 1310 | data &= ~ICE_SMA1_MASK; |
| 1254 | enable = true; | 1311 | enable = true; |
| 1255 | } else if (state == DPLL_PIN_STATE_DISCONNECTED) { | 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 | data |= ICE_SMA1_TX_EN; | 1321 | data |= ICE_SMA1_TX_EN; |
| 1257 | enable = false; | 1322 | enable = false; |
| 1258 | } else { | 1323 | } else { |
| @@ -1267,6 +1332,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, · 8 unmodified lines | |||
| 1267 | data &= ~ICE_SMA2_UFL2_RX_DIS; | 1332 | data &= ~ICE_SMA2_UFL2_RX_DIS; |
| 1268 | enable = true; | 1333 | enable = true; |
| 1269 | } else if (state == DPLL_PIN_STATE_DISCONNECTED) { | 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 | data |= ICE_SMA2_UFL2_RX_DIS; | 1344 | data |= ICE_SMA2_UFL2_RX_DIS; |
| 1271 | enable = false; | 1345 | enable = false; |
| 1272 | } else { | 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 | unlock: | 1371 | unlock: |
| 1298 | mutex_unlock(&pf->dplls.lock); | 1372 | mutex_unlock(&pf->dplls.lock); |
| 1373 | if (!ret) | ||
| 1374 | ice_dpll_sw_pin_notify_peer(&pf->dplls, p); | ||
| 1299 | 1375 | ||
| 1300 | return ret; | 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 | unlock: | 1491 | unlock: |
| 1416 | mutex_unlock(&pf->dplls.lock); | 1492 | mutex_unlock(&pf->dplls.lock); |
| 1493 | if (!ret) | ||
| 1494 | ice_dpll_sw_pin_notify_peer(&pf->dplls, sma); | ||
| 1417 | 1495 | ||
| 1418 | return ret; | 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 | mutex_lock(&pf->dplls.lock); | 1687 | mutex_lock(&pf->dplls.lock); |
| 1610 | ret = ice_dpll_sma_direction_set(p, direction, extack); | 1688 | ret = ice_dpll_sma_direction_set(p, direction, extack); |
| 1611 | mutex_unlock(&pf->dplls.lock); | 1689 | mutex_unlock(&pf->dplls.lock); |
| 1690 | if (!ret) | ||
| 1691 | ice_dpll_sw_pin_notify_peer(&pf->dplls, p); | ||
| 1612 | 1692 | ||
| 1613 | return ret; | 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 | d->active_input == p->input->pin)) | 1995 | d->active_input == p->input->pin)) |
| 1916 | *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; | 1996 | *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; |
| 1917 | else if (d->phase_offset_monitor_period) | 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 | else | 2002 | else |
| 1920 | *phase_offset = 0; | 2003 | *phase_offset = 0; |
| 1921 | mutex_unlock(&pf->dplls.lock); | 2004 | mutex_unlock(&pf->dplls.lock); |
| @@ -2609,6 +2692,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) · 687 unmodified lines | |||
| 2609 | return pci_get_dsn(pf->pdev); | 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 | * ice_dpll_notify_changes - notify dpll subsystem about changes | 2717 | * ice_dpll_notify_changes - notify dpll subsystem about changes |
| 2614 | * @d: pointer do dpll | 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 | static void ice_dpll_notify_changes(struct ice_dpll *d) | 2722 | static void ice_dpll_notify_changes(struct ice_dpll *d) |
| 2619 | { | 2723 | { |
| 2724 | struct ice_dplls *dplls = &d->pf->dplls; | ||
| 2620 | bool pin_notified = false; | 2725 | bool pin_notified = false; |
| 2621 | 2726 | ||
| 2622 | if (d->prev_dpll_state != d->dpll_state) { | 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 | if (d->prev_input != d->active_input) { | 2731 | if (d->prev_input != d->active_input) { |
| 2627 | if (d->prev_input) | 2732 | if (d->prev_input) |
| 2628 | dpll_pin_change_ntf(d->prev_input); | 2733 | ice_dpll_pin_ntf(dplls, d->prev_input); |
| 2629 | d->prev_input = d->active_input; | 2734 | d->prev_input = d->active_input; |
| 2630 | if (d->active_input) { | 2735 | if (d->active_input) { |
| 2631 | dpll_pin_change_ntf(d->active_input); | 2736 | ice_dpll_pin_ntf(dplls, d->active_input); |
| 2632 | pin_notified = true; | 2737 | pin_notified = true; |
| 2633 | } | 2738 | } |
| 2634 | } | 2739 | } |
| 2635 | if (d->prev_phase_offset != d->phase_offset) { | 2740 | if (d->prev_phase_offset != d->phase_offset) { |
| 2636 | d->prev_phase_offset = d->phase_offset; | 2741 | d->prev_phase_offset = d->phase_offset; |
| 2637 | if (!pin_notified && d->active_input) | 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 | * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes | 2771 | * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes |
| 2772 | * @dplls: pointer to dplls struct | ||
| 2667 | * @pins: array of ice_dpll_pin pointers registered within dpll subsystem | 2773 | * @pins: array of ice_dpll_pin pointers registered within dpll subsystem |
| 2668 | * @pin_num: number of pins | 2774 | * @pin_num: number of pins |
| 2669 | * @phase_offset_ntf_mask: bitmask of pin indexes to notify | 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 | * Context: Must be called while pf->dplls.lock is released. | 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 | u8 pin_num, | 2784 | u8 pin_num, |
| 2678 | u32 phase_offset_ntf_mask) | 2785 | u32 phase_offset_ntf_mask) |
| 2679 | { | 2786 | { |
| 2680 | int i = 0; | 2787 | for (int i = 0; i < pin_num; i++) |
| 2681 | 2788 | if (phase_offset_ntf_mask & BIT(i)) | |
| 2682 | for (i = 0; i < pin_num; i++) | 2789 | ice_dpll_pin_ntf(dplls, pins[i].pin); |
| 2683 | if (phase_offset_ntf_mask & (1 << i)) | ||
| 2684 | dpll_pin_change_ntf(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 | ice_dpll_notify_changes(de); | 2962 | ice_dpll_notify_changes(de); |
| 2858 | ice_dpll_notify_changes(dp); | 2963 | ice_dpll_notify_changes(dp); |
| 2859 | if (phase_offset_ntf) | 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 | phase_offset_ntf); | 2966 | phase_offset_ntf); |
| 2862 | 2967 | ||
| 2863 | resched: | 2968 | resched: |
| @@ -4014,6 +4119,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) · 1150 unmodified lines | |||
| 4014 | struct ice_dpll_pin *pin; | 4119 | struct ice_dpll_pin *pin; |
| 4015 | u32 phase_adj_max, caps; | 4120 | u32 phase_adj_max, caps; |
| 4016 | int i, ret; | 4121 | int i, ret; |
| 4122 | u8 data; | ||
| 4017 | 4123 | ||
| 4018 | if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) | 4124 | if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) |
| 4019 | input_idx_offset = ICE_E810_RCLK_PINS_NUM; | 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 | ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); | 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 | ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, | 4198 | ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, |
| 4077 | NULL); | 4199 | NULL); |
| 4078 | if (ret) | 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 | return err; | 5245 | return err; |
| 5246 | } | 5246 | } |
| 5247 | 5247 | ||
| 5248 | ice_init_dev_hw(pf); | ||
| 5249 | |||
| 5248 | adapter = ice_adapter_get(pdev); | 5250 | adapter = ice_adapter_get(pdev); |
| 5249 | if (IS_ERR(adapter)) { | 5251 | if (IS_ERR(adapter)) { |
| 5250 | err = PTR_ERR(adapter); | 5252 | err = PTR_ERR(adapter); |
| @@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) · 803 unmodified lines | |||
| 804 | ice_vf_ctrl_invalidate_vsi(vf); | 804 | ice_vf_ctrl_invalidate_vsi(vf); |
| 805 | 805 | ||
| 806 | ice_vf_pre_vsi_rebuild(vf); | 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 | ice_vf_post_vsi_rebuild(vf); | 813 | ice_vf_post_vsi_rebuild(vf); |
| 809 | 814 | ||
| 810 | ice_eswitch_attach_vf(pf, vf); | 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 | if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { | 531 | if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { |
| 532 | netif_err(efx, drv, efx->net_dev, | 532 | netif_err(efx, drv, efx->net_dev, |
| 533 | "mcdi MC_CMD_GET_VERSION failed\n"); | 533 | "mcdi MC_CMD_GET_VERSION failed\n"); |
| 534 | return rc; | 534 | return rc ?: -EIO; |
| 535 | } | 535 | } |
| 536 | 536 | ||
| 537 | /* Handle previous output */ | 537 | /* Handle previous output */ |
| @@ -5549,9 +5549,12 @@ read_again: · 5548 unmodified lines | |||
| 5549 | break; | 5549 | break; |
| 5550 | 5550 | ||
| 5551 | /* Prefetch the next RX descriptor */ | 5551 | /* Prefetch the next RX descriptor */ |
| 5552 | rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, | 5552 | next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, |
| 5553 | priv->dma_conf.dma_rx_size); | 5553 | priv->dma_conf.dma_rx_size); |
| 5554 | next_entry = rx_q->cur_rx; | 5554 | if (unlikely(next_entry == rx_q->dirty_rx)) |
| 5555 | break; | ||
| 5556 | |||
| 5557 | rx_q->cur_rx = next_entry; | ||
| 5555 | 5558 | ||
| 5556 | np = stmmac_get_rx_desc(priv, rx_q, next_entry); | 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 | dma_dir = page_pool_get_dma_dir(rx_q->page_pool); | 5690 | dma_dir = page_pool_get_dma_dir(rx_q->page_pool); |
| 5688 | bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; | 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 | if (netif_msg_rx_status(priv)) { | 5693 | if (netif_msg_rx_status(priv)) { |
| 5692 | void *rx_head = stmmac_get_rx_desc(priv, rx_q, 0); | 5694 | void *rx_head = stmmac_get_rx_desc(priv, rx_q, 0); |
| @@ -5733,9 +5735,12 @@ read_again: · 40 unmodified lines | |||
| 5733 | if (unlikely(status & dma_own)) | 5735 | if (unlikely(status & dma_own)) |
| 5734 | break; | 5736 | break; |
| 5735 | 5737 | ||
| 5736 | rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, | 5738 | next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, |
| 5737 | priv->dma_conf.dma_rx_size); | 5739 | priv->dma_conf.dma_rx_size); |
| 5738 | next_entry = rx_q->cur_rx; | 5740 | if (unlikely(next_entry == rx_q->dirty_rx)) |
| 5741 | break; | ||
| 5742 | |||
| 5743 | rx_q->cur_rx = next_entry; | ||
| 5739 | 5744 | ||
| 5740 | np = stmmac_get_rx_desc(priv, rx_q, next_entry); | 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 | u8 *pecp; | 496 | u8 *pecp; |
| 497 | int rc; | 497 | int rc; |
| 498 | 498 | ||
| 499 | fs = mctp_i2c_get_tx_flow_state(midev, skb); | ||
| 500 | |||
| 501 | hdr = (void *)skb_mac_header(skb); | 499 | hdr = (void *)skb_mac_header(skb); |
| 502 | /* Sanity check that packet contents matches skb length, | 500 | /* Sanity check that packet contents matches skb length, |
| 503 | * and can't exceed MCTP_I2C_BUFSZ | 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 | return; | 507 | return; |
| 510 | } | 508 | } |
| 511 | 509 | ||
| 510 | fs = mctp_i2c_get_tx_flow_state(midev, skb); | ||
| 511 | |||
| 512 | if (skb_tailroom(skb) >= 1) { | 512 | if (skb_tailroom(skb) >= 1) { |
| 513 | /* Linear case with space, we can just append the PEC */ | 513 | /* Linear case with space, we can just append the PEC */ |
| 514 | skb_put(skb, 1); | 514 | skb_put(skb, 1); |
| @@ -752,7 +752,7 @@ static ssize_t enabled_store(struct config_item *item, · 751 unmodified lines | |||
| 752 | unregister_netcons_consoles(); | 752 | unregister_netcons_consoles(); |
| 753 | } | 753 | } |
| 754 | 754 | ||
| 755 | ret = strnlen(buf, count); | 755 | ret = count; |
| 756 | /* Deferred cleanup */ | 756 | /* Deferred cleanup */ |
| 757 | netconsole_process_cleanups(); | 757 | netconsole_process_cleanups(); |
| 758 | out_unlock: | 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 | nt->release = release; | 782 | nt->release = release; |
| 783 | 783 | ||
| 784 | ret = strnlen(buf, count); | 784 | ret = count; |
| 785 | out_unlock: | 785 | out_unlock: |
| 786 | dynamic_netconsole_mutex_unlock(); | 786 | dynamic_netconsole_mutex_unlock(); |
| 787 | return ret; | 787 | return ret; |
| @@ -807,7 +807,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf, · 19 unmodified lines | |||
| 807 | goto out_unlock; | 807 | goto out_unlock; |
| 808 | 808 | ||
| 809 | nt->extended = extended; | 809 | nt->extended = extended; |
| 810 | ret = strnlen(buf, count); | 810 | ret = count; |
| 811 | out_unlock: | 811 | out_unlock: |
| 812 | dynamic_netconsole_mutex_unlock(); | 812 | dynamic_netconsole_mutex_unlock(); |
| 813 | return ret; | 813 | return ret; |
| @@ -817,6 +817,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, · 3 unmodified lines | |||
| 817 | size_t count) | 817 | size_t count) |
| 818 | { | 818 | { |
| 819 | struct netconsole_target *nt = to_target(item); | 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 | dynamic_netconsole_mutex_lock(); | 828 | dynamic_netconsole_mutex_lock(); |
| 822 | if (nt->state == STATE_ENABLED) { | 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 | trim_newline(nt->np.dev_name, IFNAMSIZ); | 837 | trim_newline(nt->np.dev_name, IFNAMSIZ); |
| 831 | 838 | ||
| 832 | dynamic_netconsole_mutex_unlock(); | 839 | dynamic_netconsole_mutex_unlock(); |
| 833 | return strnlen(buf, count); | 840 | return count; |
| 834 | } | 841 | } |
| 835 | 842 | ||
| 836 | static ssize_t local_port_store(struct config_item *item, const char *buf, | 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 | ret = kstrtou16(buf, 10, &nt->np.local_port); | 856 | ret = kstrtou16(buf, 10, &nt->np.local_port); |
| 850 | if (ret < 0) | 857 | if (ret < 0) |
| 851 | goto out_unlock; | 858 | goto out_unlock; |
| 852 | ret = strnlen(buf, count); | 859 | ret = count; |
| 853 | out_unlock: | 860 | out_unlock: |
| 854 | dynamic_netconsole_mutex_unlock(); | 861 | dynamic_netconsole_mutex_unlock(); |
| 855 | return ret; | 862 | return ret; |
| @@ -871,7 +878,7 @@ static ssize_t remote_port_store(struct config_item *item, · 15 unmodified lines | |||
| 871 | ret = kstrtou16(buf, 10, &nt->np.remote_port); | 878 | ret = kstrtou16(buf, 10, &nt->np.remote_port); |
| 872 | if (ret < 0) | 879 | if (ret < 0) |
| 873 | goto out_unlock; | 880 | goto out_unlock; |
| 874 | ret = strnlen(buf, count); | 881 | ret = count; |
| 875 | out_unlock: | 882 | out_unlock: |
| 876 | dynamic_netconsole_mutex_unlock(); | 883 | dynamic_netconsole_mutex_unlock(); |
| 877 | return ret; | 884 | return ret; |
| @@ -896,7 +903,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, · 18 unmodified lines | |||
| 896 | goto out_unlock; | 903 | goto out_unlock; |
| 897 | nt->np.ipv6 = !!ipv6; | 904 | nt->np.ipv6 = !!ipv6; |
| 898 | 905 | ||
| 899 | ret = strnlen(buf, count); | 906 | ret = count; |
| 900 | out_unlock: | 907 | out_unlock: |
| 901 | dynamic_netconsole_mutex_unlock(); | 908 | dynamic_netconsole_mutex_unlock(); |
| 902 | return ret; | 909 | return ret; |
| @@ -921,7 +928,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, · 18 unmodified lines | |||
| 921 | goto out_unlock; | 928 | goto out_unlock; |
| 922 | nt->np.ipv6 = !!ipv6; | 929 | nt->np.ipv6 = !!ipv6; |
| 923 | 930 | ||
| 924 | ret = strnlen(buf, count); | 931 | ret = count; |
| 925 | out_unlock: | 932 | out_unlock: |
| 926 | dynamic_netconsole_mutex_unlock(); | 933 | dynamic_netconsole_mutex_unlock(); |
| 927 | return ret; | 934 | return ret; |
| @@ -957,7 +964,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf, · 29 unmodified lines | |||
| 957 | goto out_unlock; | 964 | goto out_unlock; |
| 958 | memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); | 965 | memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); |
| 959 | 966 | ||
| 960 | ret = strnlen(buf, count); | 967 | ret = count; |
| 961 | out_unlock: | 968 | out_unlock: |
| 962 | dynamic_netconsole_mutex_unlock(); | 969 | dynamic_netconsole_mutex_unlock(); |
| 963 | return ret; | 970 | return ret; |
| @@ -1072,26 +1079,30 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, · 108 unmodified lines | |||
| 1072 | size_t count) | 1079 | size_t count) |
| 1073 | { | 1080 | { |
| 1074 | struct userdatum *udm = to_userdatum(item); | 1081 | struct userdatum *udm = to_userdatum(item); |
| 1082 | char old_value[MAX_EXTRADATA_VALUE_LEN]; | ||
| 1075 | struct netconsole_target *nt; | 1083 | struct netconsole_target *nt; |
| 1076 | struct userdata *ud; | 1084 | struct userdata *ud; |
| 1077 | ssize_t ret; | 1085 | ssize_t ret; |
| 1078 | 1086 | ||
| 1079 | if (count > MAX_EXTRADATA_VALUE_LEN) | 1087 | if (count >= MAX_EXTRADATA_VALUE_LEN) |
| 1080 | return -EMSGSIZE; | 1088 | return -EMSGSIZE; |
| 1081 | 1089 | ||
| 1082 | mutex_lock(&netconsole_subsys.su_mutex); | 1090 | mutex_lock(&netconsole_subsys.su_mutex); |
| 1083 | dynamic_netconsole_mutex_lock(); | 1091 | dynamic_netconsole_mutex_lock(); |
| 1084 | 1092 | /* Snapshot for rollback if update_userdata() fails below */ | |
| 1085 | ret = strscpy(udm->value, buf, sizeof(udm->value)); | 1093 | strscpy(old_value, udm->value, sizeof(old_value)); |
| 1086 | if (ret < 0) | 1094 | /* count is bounded above, so strscpy() cannot truncate here */ |
| 1087 | goto out_unlock; | 1095 | strscpy(udm->value, buf, sizeof(udm->value)); |
| 1088 | trim_newline(udm->value, sizeof(udm->value)); | 1096 | trim_newline(udm->value, sizeof(udm->value)); |
| 1089 | 1097 | ||
| 1090 | ud = to_userdata(item->ci_parent); | 1098 | ud = to_userdata(item->ci_parent); |
| 1091 | nt = userdata_to_target(ud); | 1099 | nt = userdata_to_target(ud); |
| 1092 | ret = update_userdata(nt); | 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 | goto out_unlock; | 1104 | goto out_unlock; |
| 1105 | } | ||
| 1095 | ret = count; | 1106 | ret = count; |
| 1096 | out_unlock: | 1107 | out_unlock: |
| 1097 | dynamic_netconsole_mutex_unlock(); | 1108 | dynamic_netconsole_mutex_unlock(); |
| @@ -1133,7 +1144,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item, · 35 unmodified lines | |||
| 1133 | disable_sysdata_feature(nt, SYSDATA_MSGID); | 1144 | disable_sysdata_feature(nt, SYSDATA_MSGID); |
| 1134 | 1145 | ||
| 1135 | unlock_ok: | 1146 | unlock_ok: |
| 1136 | ret = strnlen(buf, count); | 1147 | ret = count; |
| 1137 | dynamic_netconsole_mutex_unlock(); | 1148 | dynamic_netconsole_mutex_unlock(); |
| 1138 | mutex_unlock(&netconsole_subsys.su_mutex); | 1149 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1139 | return ret; | 1150 | return ret; |
| @@ -1162,7 +1173,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item, · 22 unmodified lines | |||
| 1162 | disable_sysdata_feature(nt, SYSDATA_RELEASE); | 1173 | disable_sysdata_feature(nt, SYSDATA_RELEASE); |
| 1163 | 1174 | ||
| 1164 | unlock_ok: | 1175 | unlock_ok: |
| 1165 | ret = strnlen(buf, count); | 1176 | ret = count; |
| 1166 | dynamic_netconsole_mutex_unlock(); | 1177 | dynamic_netconsole_mutex_unlock(); |
| 1167 | mutex_unlock(&netconsole_subsys.su_mutex); | 1178 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1168 | return ret; | 1179 | return ret; |
| @@ -1191,7 +1202,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item, · 22 unmodified lines | |||
| 1191 | disable_sysdata_feature(nt, SYSDATA_TASKNAME); | 1202 | disable_sysdata_feature(nt, SYSDATA_TASKNAME); |
| 1192 | 1203 | ||
| 1193 | unlock_ok: | 1204 | unlock_ok: |
| 1194 | ret = strnlen(buf, count); | 1205 | ret = count; |
| 1195 | dynamic_netconsole_mutex_unlock(); | 1206 | dynamic_netconsole_mutex_unlock(); |
| 1196 | mutex_unlock(&netconsole_subsys.su_mutex); | 1207 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1197 | return ret; | 1208 | return ret; |
| @@ -1225,7 +1236,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item, · 27 unmodified lines | |||
| 1225 | disable_sysdata_feature(nt, SYSDATA_CPU_NR); | 1236 | disable_sysdata_feature(nt, SYSDATA_CPU_NR); |
| 1226 | 1237 | ||
| 1227 | unlock_ok: | 1238 | unlock_ok: |
| 1228 | ret = strnlen(buf, count); | 1239 | ret = count; |
| 1229 | dynamic_netconsole_mutex_unlock(); | 1240 | dynamic_netconsole_mutex_unlock(); |
| 1230 | mutex_unlock(&netconsole_subsys.su_mutex); | 1241 | mutex_unlock(&netconsole_subsys.su_mutex); |
| 1231 | return ret; | 1242 | return ret; |
| @@ -829,7 +829,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) · 828 unmodified lines | |||
| 829 | skb->protocol = htons(ETH_P_IP); | 829 | skb->protocol = htons(ETH_P_IP); |
| 830 | 830 | ||
| 831 | skb_set_network_header(skb, skb->len); | 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 | iph->protocol = IPPROTO_UDP; | 833 | iph->protocol = IPPROTO_UDP; |
| 834 | iph->saddr = in_aton("192.0.2.1"); | 834 | iph->saddr = in_aton("192.0.2.1"); |
| 835 | iph->daddr = in_aton("198.51.100.1"); | 835 | iph->daddr = in_aton("198.51.100.1"); |
| @@ -31,6 +31,7 @@ · 30 unmodified lines | |||
| 31 | #define DP83869_RGMIICTL 0x0032 | 31 | #define DP83869_RGMIICTL 0x0032 |
| 32 | #define DP83869_STRAP_STS1 0x006e | 32 | #define DP83869_STRAP_STS1 0x006e |
| 33 | #define DP83869_RGMIIDCTL 0x0086 | 33 | #define DP83869_RGMIIDCTL 0x0086 |
| 34 | #define DP83869_ANA_PLL_PROG_PI 0x00c6 | ||
| 34 | #define DP83869_RXFCFG 0x0134 | 35 | #define DP83869_RXFCFG 0x0134 |
| 35 | #define DP83869_RXFPMD1 0x0136 | 36 | #define DP83869_RXFPMD1 0x0136 |
| 36 | #define DP83869_RXFPMD2 0x0137 | 37 | #define DP83869_RXFPMD2 0x0137 |
| @@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev) · 789 unmodified lines | |||
| 826 | dp83869_config_port_mirroring(phydev); | 827 | dp83869_config_port_mirroring(phydev); |
| 827 | 828 | ||
| 828 | /* Clock output selection if muxing property is set */ | 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 | ret = phy_modify_mmd(phydev, | 840 | ret = phy_modify_mmd(phydev, |
| 831 | DP83869_DEVADDR, DP83869_IO_MUX_CFG, | 841 | DP83869_DEVADDR, DP83869_IO_MUX_CFG, |
| 832 | DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, | 842 | DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, |
| 833 | dp83869->clk_output_sel << | 843 | dp83869->clk_output_sel << |
| 834 | DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); | 844 | DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); |
| 845 | } | ||
| 835 | 846 | ||
| 836 | if (phy_interface_is_rgmii(phydev)) { | 847 | if (phy_interface_is_rgmii(phydev)) { |
| 837 | ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, | 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 | struct net_device *netdev) | 683 | struct net_device *netdev) |
| 684 | { | 684 | { |
| 685 | rtl8150_t *dev = netdev_priv(netdev); | 685 | rtl8150_t *dev = netdev_priv(netdev); |
| 686 | unsigned int skb_len; | ||
| 686 | int count, res; | 687 | int count, res; |
| 687 | 688 | ||
| 688 | /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ | 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 | return NETDEV_TX_OK; | 695 | return NETDEV_TX_OK; |
| 695 | } | 696 | } |
| 696 | 697 | ||
| 698 | skb_len = skb->len; | ||
| 699 | |||
| 697 | netif_stop_queue(netdev); | 700 | netif_stop_queue(netdev); |
| 698 | dev->tx_skb = skb; | 701 | dev->tx_skb = skb; |
| 699 | usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), | 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 | netdev->stats.tx_errors++; | 710 | netdev->stats.tx_errors++; |
| 708 | netif_start_queue(netdev); | 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 | } else { | 720 | } else { |
| 711 | netdev->stats.tx_packets++; | 721 | netdev->stats.tx_packets++; |
| 712 | netdev->stats.tx_bytes += skb->len; | 722 | netdev->stats.tx_bytes += skb_len; |
| 713 | netif_trans_update(netdev); | 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 | err: | 1035 | err: |
| 1036 | port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; | 1036 | port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; |
| 1037 | synchronize_net(); | ||
| 1037 | return ret; | 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 | /* inverse of do_vrf_add_slave */ | 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 | netdev_upper_dev_unlink(port_dev, dev); | 1060 | netdev_upper_dev_unlink(port_dev, dev); |
| 1059 | port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; | 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 | cycle_netdev(port_dev, NULL); | 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 | static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) | 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 | static void vrf_dev_uninit(struct net_device *dev) | 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 | struct list_head *iter; | 1626 | struct list_head *iter; |
| 1620 | 1627 | ||
| 1621 | netdev_for_each_lower_dev(dev, port_dev, iter) | 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 | vrf_map_unregister_dev(dev); | 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 | goto out; | 1758 | goto out; |
| 1752 | 1759 | ||
| 1753 | vrf_dev = netdev_master_upper_dev_get(dev); | 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 | out: | 1763 | out: |
| 1757 | return NOTIFY_DONE; | 1764 | return NOTIFY_DONE; |
| @@ -317,6 +317,7 @@ · 316 unmodified lines | |||
| 317 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) | 317 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) |
| 318 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) | 318 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) |
| 319 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) | 319 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) |
| 320 | #define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 | ||
| 320 | 321 | ||
| 321 | #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) | 322 | #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) |
| 322 | #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) | 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 | if (ret) | 1301 | if (ret) |
| 1301 | return ret; | 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 | *is_rf_field = true; | 1305 | *is_rf_field = true; |
| 1305 | else | 1306 | else |
| 1306 | *is_rf_field = false; | 1307 | *is_rf_field = false; |
| @@ -351,18 +351,29 @@ struct nvme_dhchap_key *nvme_auth_transform_key( · 350 unmodified lines | |||
| 351 | } | 351 | } |
| 352 | EXPORT_SYMBOL_GPL(nvme_auth_transform_key); | 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 | int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len, | 373 | int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len, |
| 355 | const u8 *challenge, u8 *aug, size_t hlen) | 374 | const u8 *challenge, u8 *aug, size_t hlen) |
| 356 | { | 375 | { |
| 357 | u8 hashed_key[NVME_AUTH_MAX_DIGEST_SIZE]; | 376 | return nvme_auth_hmac(hmac_id, skey, skey_len, challenge, hlen, aug); |
| 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; | ||
| 366 | } | 377 | } |
| 367 | EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge); | 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 | EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey); | 415 | EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey); |
| 405 | 416 | ||
| 406 | int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm, | 417 | /** |
| 407 | const u8 *ctrl_key, size_t ctrl_key_len, | 418 | * nvme_auth_gen_session_key() - Generate an ephemeral session key |
| 408 | u8 *sess_key, size_t sess_key_len) | 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 | struct kpp_request *req; | 436 | struct kpp_request *req; |
| 411 | struct crypto_wait wait; | 437 | struct crypto_wait wait; |
| 412 | struct scatterlist src, dst; | 438 | struct scatterlist src, dst; |
| 439 | u8 *dh_secret; | ||
| 440 | size_t dh_secret_len, hash_len; | ||
| 413 | int ret; | 441 | int ret; |
| 414 | 442 | ||
| 415 | req = kpp_request_alloc(dh_tfm, GFP_KERNEL); | 443 | hash_len = nvme_auth_hmac_hash_len(hash_id); |
| 416 | if (!req) | 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 | return -ENOMEM; | 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 | crypto_init_wait(&wait); | 466 | crypto_init_wait(&wait); |
| 420 | sg_init_one(&src, ctrl_key, ctrl_key_len); | 467 | sg_init_one(&src, public_key, public_key_len); |
| 421 | kpp_request_set_input(req, &src, ctrl_key_len); | 468 | kpp_request_set_input(req, &src, public_key_len); |
| 422 | sg_init_one(&dst, sess_key, sess_key_len); | 469 | sg_init_one(&dst, dh_secret, dh_secret_len); |
| 423 | kpp_request_set_output(req, &dst, sess_key_len); | 470 | kpp_request_set_output(req, &dst, dh_secret_len); |
| 424 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 471 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
| 425 | crypto_req_done, &wait); | 472 | crypto_req_done, &wait); |
| 426 | 473 | ||
| 427 | ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait); | 474 | ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait); |
| 428 | |||
| 429 | kpp_request_free(req); | 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 | return ret; | 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 | int nvme_auth_parse_key(const char *secret, struct nvme_dhchap_key **ret_key) | 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 | static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl) | 1268 | static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl) |
| 1269 | { | 1269 | { |
| 1270 | struct apple_nvme *anv = ctrl_to_apple_nvme(ctrl); | 1270 | put_device(ctrl->dev); |
| 1271 | |||
| 1272 | if (anv->ctrl.admin_q) | ||
| 1273 | blk_put_queue(anv->ctrl.admin_q); | ||
| 1274 | put_device(anv->dev); | ||
| 1275 | } | 1271 | } |
| 1276 | 1272 | ||
| 1277 | static const struct nvme_ctrl_ops nvme_ctrl_ops = { | 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 | put_unaligned_le16(chap->transaction, buf); | 535 | put_unaligned_le16(chap->transaction, buf); |
| 536 | nvme_auth_hmac_update(&hmac, buf, 2); | 536 | nvme_auth_hmac_update(&hmac, buf, 2); |
| 537 | 537 | ||
| 538 | memset(buf, 0, 4); | 538 | *buf = chap->sc_c; |
| 539 | nvme_auth_hmac_update(&hmac, buf, 1); | 539 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 540 | nvme_auth_hmac_update(&hmac, "Controller", 10); | 540 | nvme_auth_hmac_update(&hmac, "Controller", 10); |
| 541 | nvme_auth_hmac_update(&hmac, ctrl->opts->subsysnqn, | 541 | nvme_auth_hmac_update(&hmac, ctrl->opts->subsysnqn, |
| 542 | strlen(ctrl->opts->subsysnqn)); | 542 | strlen(ctrl->opts->subsysnqn)); |
| 543 | memset(buf, 0, 4); | ||
| 543 | nvme_auth_hmac_update(&hmac, buf, 1); | 544 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 544 | nvme_auth_hmac_update(&hmac, ctrl->opts->host->nqn, | 545 | nvme_auth_hmac_update(&hmac, ctrl->opts->host->nqn, |
| 545 | strlen(ctrl->opts->host->nqn)); | 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 | gen_sesskey: | 590 | gen_sesskey: |
| 590 | chap->sess_key_len = chap->host_key_len; | 591 | chap->sess_key_len = chap->hash_len; |
| 591 | chap->sess_key = kmalloc(chap->sess_key_len, GFP_KERNEL); | 592 | chap->sess_key = kmalloc(chap->sess_key_len, GFP_KERNEL); |
| 592 | if (!chap->sess_key) { | 593 | if (!chap->sess_key) { |
| 593 | chap->sess_key_len = 0; | 594 | chap->sess_key_len = 0; |
| @@ -595,16 +596,17 @@ gen_sesskey: · 1 unmodified line | |||
| 595 | return -ENOMEM; | 596 | return -ENOMEM; |
| 596 | } | 597 | } |
| 597 | 598 | ||
| 598 | ret = nvme_auth_gen_shared_secret(chap->dh_tfm, | 599 | ret = nvme_auth_gen_session_key(chap->dh_tfm, |
| 599 | chap->ctrl_key, chap->ctrl_key_len, | 600 | chap->ctrl_key, chap->ctrl_key_len, |
| 600 | chap->sess_key, chap->sess_key_len); | 601 | chap->sess_key, chap->sess_key_len, |
| 602 | chap->hash_id); | ||
| 601 | if (ret) { | 603 | if (ret) { |
| 602 | dev_dbg(ctrl->device, | 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 | chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; | 606 | chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; |
| 605 | return ret; | 607 | return ret; |
| 606 | } | 608 | } |
| 607 | dev_dbg(ctrl->device, "shared secret %*ph\n", | 609 | dev_dbg(ctrl->device, "session key %*ph\n", |
| 608 | (int)chap->sess_key_len, chap->sess_key); | 610 | (int)chap->sess_key_len, chap->sess_key); |
| 609 | return 0; | 611 | return 0; |
| 610 | } | 612 | } |
| @@ -454,11 +454,10 @@ void nvme_end_req(struct request *req) · 453 unmodified lines | |||
| 454 | blk_mq_end_request(req, status); | 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 | struct nvme_ctrl *ctrl = nvme_req(req)->ctrl; | 459 | struct nvme_ctrl *ctrl = nvme_req(req)->ctrl; |
| 460 | 460 | ||
| 461 | trace_nvme_complete_rq(req); | ||
| 462 | nvme_cleanup_cmd(req); | 461 | nvme_cleanup_cmd(req); |
| 463 | 462 | ||
| 464 | /* | 463 | /* |
| @@ -493,6 +492,12 @@ void nvme_complete_rq(struct request *req) · 28 unmodified lines | |||
| 493 | return; | 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 | EXPORT_SYMBOL_GPL(nvme_complete_rq); | 501 | EXPORT_SYMBOL_GPL(nvme_complete_rq); |
| 497 | 502 | ||
| 498 | void nvme_complete_batch_req(struct request *req) | 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 | nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR; | 519 | nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR; |
| 515 | blk_mq_set_request_complete(req); | 520 | blk_mq_set_request_complete(req); |
| 516 | nvme_complete_rq(req); | 521 | __nvme_complete_rq(req); |
| 517 | return BLK_STS_OK; | 522 | return BLK_STS_OK; |
| 518 | } | 523 | } |
| 519 | EXPORT_SYMBOL_GPL(nvme_host_path_error); | 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 | * The device is left in a state where it is also not possible | 3050 | * The device is left in a state where it is also not possible |
| 3046 | * to use "nvme set-feature" to disable APST, but booting with | 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 | .vid = 0x1e0f, | 3054 | .vid = 0x1e0f, |
| 3050 | .mn = "KCD6XVUL6T40", | 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 | mutex_unlock(&ctrl->subsys->lock); | 4088 | mutex_unlock(&ctrl->subsys->lock); |
| 4084 | 4089 | ||
| 4085 | #ifdef CONFIG_NVME_MULTIPATH | 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 | #endif | 4093 | #endif |
| 4088 | return 0; | 4094 | return 0; |
| 4089 | 4095 | ||
| @@ -3968,3 +3968,4 @@ module_exit(nvme_fc_exit_module); · 3967 unmodified lines | |||
| 3968 | 3968 | ||
| 3969 | MODULE_DESCRIPTION("NVMe host FC transport driver"); | 3969 | MODULE_DESCRIPTION("NVMe host FC transport driver"); |
| 3970 | MODULE_LICENSE("GPL v2"); | 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 | bool changed = false; | 231 | bool changed = false; |
| 232 | int node; | 232 | int node; |
| 233 | 233 | ||
| 234 | if (!head) | ||
| 235 | goto out; | ||
| 236 | |||
| 237 | for_each_node(node) { | 234 | for_each_node(node) { |
| 238 | if (ns == rcu_access_pointer(head->current_path[node])) { | 235 | if (ns == rcu_access_pointer(head->current_path[node])) { |
| 239 | rcu_assign_pointer(head->current_path[node], NULL); | 236 | rcu_assign_pointer(head->current_path[node], NULL); |
| 240 | changed = true; | 237 | changed = true; |
| 241 | } | 238 | } |
| 242 | } | 239 | } |
| 243 | out: | ||
| 244 | return changed; | 240 | return changed; |
| 245 | } | 241 | } |
| 246 | 242 | ||
| @@ -2241,6 +2241,7 @@ release_cq: · 2240 unmodified lines | |||
| 2241 | static const struct blk_mq_ops nvme_mq_admin_ops = { | 2241 | static const struct blk_mq_ops nvme_mq_admin_ops = { |
| 2242 | .queue_rq = nvme_queue_rq, | 2242 | .queue_rq = nvme_queue_rq, |
| 2243 | .complete = nvme_pci_complete_rq, | 2243 | .complete = nvme_pci_complete_rq, |
| 2244 | .commit_rqs = nvme_commit_rqs, | ||
| 2244 | .init_hctx = nvme_admin_init_hctx, | 2245 | .init_hctx = nvme_admin_init_hctx, |
| 2245 | .init_request = nvme_pci_init_request, | 2246 | .init_request = nvme_pci_init_request, |
| 2246 | .timeout = nvme_timeout, | 2247 | .timeout = nvme_timeout, |
| @@ -4104,6 +4105,10 @@ static const struct pci_device_id nvme_id_table[] = { · 1857 unmodified lines | |||
| 4104 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, | 4105 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, |
| 4105 | { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ | 4106 | { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ |
| 4106 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, | 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 | { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ | 4112 | { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ |
| 4108 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, | 4113 | .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, |
| 4109 | { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ | 4114 | { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ |
| @@ -2189,6 +2189,13 @@ out_fail: · 2188 unmodified lines | |||
| 2189 | nvme_rdma_reconnect_or_remove(ctrl, ret); | 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 | static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { | 2199 | static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { |
| 2193 | .name = "rdma", | 2200 | .name = "rdma", |
| 2194 | .module = THIS_MODULE, | 2201 | .module = THIS_MODULE, |
| @@ -2203,6 +2210,7 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { · 8 unmodified lines | |||
| 2203 | .get_address = nvmf_get_address, | 2210 | .get_address = nvmf_get_address, |
| 2204 | .stop_ctrl = nvme_rdma_stop_ctrl, | 2211 | .stop_ctrl = nvme_rdma_stop_ctrl, |
| 2205 | .get_virt_boundary = nvme_get_virt_boundary, | 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 | MODULE_DESCRIPTION("NVMe host RDMA transport driver"); | 2441 | MODULE_DESCRIPTION("NVMe host RDMA transport driver"); |
| 2434 | MODULE_LICENSE("GPL v2"); | 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 | static DEVICE_ATTR_RO(tls_keyring); | 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 | static struct attribute *nvme_tls_attrs[] = { | 901 | static struct attribute *nvme_tls_attrs[] = { |
| 887 | &dev_attr_tls_key.attr, | 902 | &dev_attr_tls_key.attr, |
| 888 | &dev_attr_tls_configured_key.attr, | 903 | &dev_attr_tls_configured_key.attr, |
| 889 | &dev_attr_tls_keyring.attr, | 904 | &dev_attr_tls_keyring.attr, |
| 905 | &dev_attr_tls_mode.attr, | ||
| 890 | NULL, | 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 | if (a == &dev_attr_tls_keyring.attr && | 924 | if (a == &dev_attr_tls_keyring.attr && |
| 909 | !ctrl->opts->keyring) | 925 | !ctrl->opts->keyring) |
| 910 | return 0; | 926 | return 0; |
| 927 | if (a == &dev_attr_tls_mode.attr && | ||
| 928 | !ctrl->opts->tls && !ctrl->opts->concat) | ||
| 929 | return 0; | ||
| 911 | 930 | ||
| 912 | return a->mode; | 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 | struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); | 1439 | struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); |
| 1440 | struct nvme_tcp_queue *queue = &ctrl->queues[qid]; | 1440 | struct nvme_tcp_queue *queue = &ctrl->queues[qid]; |
| 1441 | unsigned int noreclaim_flag; | 1441 | unsigned int noio_flag; |
| 1442 | 1442 | ||
| 1443 | if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) | 1443 | if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) |
| 1444 | return; | 1444 | return; |
| 1445 | 1445 | ||
| 1446 | page_frag_cache_drain(&queue->pf_cache); | 1446 | page_frag_cache_drain(&queue->pf_cache); |
| 1447 | 1447 | ||
| 1448 | noreclaim_flag = memalloc_noreclaim_save(); | 1448 | /** |
| 1449 | /* ->sock will be released by fput() */ | 1449 | * Prevent memory reclaim from triggering block I/O during socket |
| 1450 | fput(queue->sock->file); | 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 | queue->sock = NULL; | 1465 | queue->sock = NULL; |
| 1452 | memalloc_noreclaim_restore(noreclaim_flag); | 1466 | memalloc_noio_restore(noio_flag); |
| 1453 | 1467 | ||
| 1454 | kfree(queue->pdu); | 1468 | kfree(queue->pdu); |
| 1455 | mutex_destroy(&queue->send_mutex); | 1469 | mutex_destroy(&queue->send_mutex); |
| @@ -1901,8 +1915,8 @@ err_init_connect: · 445 unmodified lines | |||
| 1901 | err_rcv_pdu: | 1915 | err_rcv_pdu: |
| 1902 | kfree(queue->pdu); | 1916 | kfree(queue->pdu); |
| 1903 | err_sock: | 1917 | err_sock: |
| 1904 | /* ->sock will be released by fput() */ | 1918 | /* Use sync variant - see nvme_tcp_free_queue() for explanation */ |
| 1905 | fput(queue->sock->file); | 1919 | __fput_sync(queue->sock->file); |
| 1906 | queue->sock = NULL; | 1920 | queue->sock = NULL; |
| 1907 | err_destroy_mutex: | 1921 | err_destroy_mutex: |
| 1908 | mutex_destroy(&queue->send_mutex); | 1922 | mutex_destroy(&queue->send_mutex); |
| @@ -3071,3 +3085,4 @@ module_exit(nvme_tcp_cleanup_module); · 1162 unmodified lines | |||
| 3071 | 3085 | ||
| 3072 | MODULE_DESCRIPTION("NVMe host TCP transport driver"); | 3086 | MODULE_DESCRIPTION("NVMe host TCP transport driver"); |
| 3073 | MODULE_LICENSE("GPL v2"); | 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 | id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL | | 687 | id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL | |
| 688 | NVME_CTRL_CMIC_ANA; | 688 | NVME_CTRL_CMIC_ANA; |
| 689 | 689 | ||
| 690 | /* Limit MDTS according to transport capability */ | 690 | /* Limit MDTS according to port config or transport capability */ |
| 691 | if (ctrl->ops->get_mdts) | 691 | id->mdts = nvmet_ctrl_mdts(req); |
| 692 | id->mdts = ctrl->ops->get_mdts(ctrl); | ||
| 693 | else | ||
| 694 | id->mdts = 0; | ||
| 695 | |||
| 696 | id->cntlid = cpu_to_le16(ctrl->cntlid); | 692 | id->cntlid = cpu_to_le16(ctrl->cntlid); |
| 697 | id->ver = cpu_to_le32(ctrl->subsys->ver); | 693 | id->ver = cpu_to_le32(ctrl->subsys->ver); |
| 698 | 694 | ||
| @@ -229,9 +229,6 @@ out_unlock: · 228 unmodified lines | |||
| 229 | void nvmet_auth_sq_free(struct nvmet_sq *sq) | 229 | void nvmet_auth_sq_free(struct nvmet_sq *sq) |
| 230 | { | 230 | { |
| 231 | cancel_delayed_work(&sq->auth_expired_work); | 231 | cancel_delayed_work(&sq->auth_expired_work); |
| 232 | #ifdef CONFIG_NVME_TARGET_TCP_TLS | ||
| 233 | sq->tls_key = NULL; | ||
| 234 | #endif | ||
| 235 | kfree(sq->dhchap_c1); | 232 | kfree(sq->dhchap_c1); |
| 236 | sq->dhchap_c1 = NULL; | 233 | sq->dhchap_c1 = NULL; |
| 237 | kfree(sq->dhchap_c2); | 234 | kfree(sq->dhchap_c2); |
| @@ -402,11 +399,12 @@ int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, · 164 unmodified lines | |||
| 402 | put_unaligned_le16(req->sq->dhchap_tid, buf); | 399 | put_unaligned_le16(req->sq->dhchap_tid, buf); |
| 403 | nvme_auth_hmac_update(&hmac, buf, 2); | 400 | nvme_auth_hmac_update(&hmac, buf, 2); |
| 404 | 401 | ||
| 405 | memset(buf, 0, 4); | 402 | *buf = req->sq->sc_c; |
| 406 | nvme_auth_hmac_update(&hmac, buf, 1); | 403 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 407 | nvme_auth_hmac_update(&hmac, "Controller", 10); | 404 | nvme_auth_hmac_update(&hmac, "Controller", 10); |
| 408 | nvme_auth_hmac_update(&hmac, ctrl->subsys->subsysnqn, | 405 | nvme_auth_hmac_update(&hmac, ctrl->subsys->subsysnqn, |
| 409 | strlen(ctrl->subsys->subsysnqn)); | 406 | strlen(ctrl->subsys->subsysnqn)); |
| 407 | memset(buf, 0, 4); | ||
| 410 | nvme_auth_hmac_update(&hmac, buf, 1); | 408 | nvme_auth_hmac_update(&hmac, buf, 1); |
| 411 | nvme_auth_hmac_update(&hmac, ctrl->hostnqn, strlen(ctrl->hostnqn)); | 409 | nvme_auth_hmac_update(&hmac, ctrl->hostnqn, strlen(ctrl->hostnqn)); |
| 412 | nvme_auth_hmac_final(&hmac, response); | 410 | nvme_auth_hmac_final(&hmac, response); |
| @@ -449,18 +447,19 @@ int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, · 36 unmodified lines | |||
| 449 | struct nvmet_ctrl *ctrl = req->sq->ctrl; | 447 | struct nvmet_ctrl *ctrl = req->sq->ctrl; |
| 450 | int ret; | 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 | req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL); | 451 | req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL); |
| 454 | if (!req->sq->dhchap_skey) | 452 | if (!req->sq->dhchap_skey) |
| 455 | return -ENOMEM; | 453 | return -ENOMEM; |
| 456 | ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm, | 454 | ret = nvme_auth_gen_session_key(ctrl->dh_tfm, |
| 457 | pkey, pkey_size, | 455 | pkey, pkey_size, |
| 458 | req->sq->dhchap_skey, | 456 | req->sq->dhchap_skey, |
| 459 | req->sq->dhchap_skey_len); | 457 | req->sq->dhchap_skey_len, |
| 458 | ctrl->shash_id); | ||
| 460 | if (ret) | 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 | else | 461 | else |
| 463 | pr_debug("%s: shared secret %*ph\n", __func__, | 462 | pr_debug("%s: session key %*ph\n", __func__, |
| 464 | (int)req->sq->dhchap_skey_len, | 463 | (int)req->sq->dhchap_skey_len, |
| 465 | req->sq->dhchap_skey); | 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 | CONFIGFS_ATTR(nvmet_, param_max_queue_size); | 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 | #ifdef CONFIG_BLK_DEV_INTEGRITY | 329 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
| 305 | static ssize_t nvmet_param_pi_enable_show(struct config_item *item, | 330 | static ssize_t nvmet_param_pi_enable_show(struct config_item *item, |
| 306 | char *page) | 331 | char *page) |
| @@ -1995,6 +2020,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = { · 1688 unmodified lines | |||
| 1995 | &nvmet_attr_addr_tsas, | 2020 | &nvmet_attr_addr_tsas, |
| 1996 | &nvmet_attr_param_inline_data_size, | 2021 | &nvmet_attr_param_inline_data_size, |
| 1997 | &nvmet_attr_param_max_queue_size, | 2022 | &nvmet_attr_param_max_queue_size, |
| 2023 | &nvmet_attr_param_mdts, | ||
| 1998 | #ifdef CONFIG_BLK_DEV_INTEGRITY | 2024 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
| 1999 | &nvmet_attr_param_pi_enable, | 2025 | &nvmet_attr_param_pi_enable, |
| 2000 | #endif | 2026 | #endif |
| @@ -2053,6 +2079,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group, · 52 unmodified lines | |||
| 2053 | INIT_LIST_HEAD(&port->referrals); | 2079 | INIT_LIST_HEAD(&port->referrals); |
| 2054 | port->inline_data_size = -1; /* < 0 == let the transport choose */ | 2080 | port->inline_data_size = -1; /* < 0 == let the transport choose */ |
| 2055 | port->max_queue_size = -1; /* < 0 == let the transport choose */ | 2081 | port->max_queue_size = -1; /* < 0 == let the transport choose */ |
| 2082 | port->mdts = -1; /* < 0 == let the transport choose */ | ||
| 2056 | 2083 | ||
| 2057 | port->disc_addr.trtype = NVMF_TRTYPE_MAX; | 2084 | port->disc_addr.trtype = NVMF_TRTYPE_MAX; |
| 2058 | port->disc_addr.portid = cpu_to_le16(portid); | 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 | NVMET_MIN_QUEUE_SIZE, | 370 | NVMET_MIN_QUEUE_SIZE, |
| 371 | NVMET_MAX_QUEUE_SIZE); | 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 | port->enabled = true; | 381 | port->enabled = true; |
| 374 | port->tr_ops = ops; | 382 | port->tr_ops = ops; |
| 375 | return 0; | 383 | return 0; |
| @@ -1743,7 +1751,7 @@ static void nvmet_ctrl_free(struct kref *ref) · 1367 unmodified lines | |||
| 1743 | 1751 | ||
| 1744 | nvmet_stop_keep_alive_timer(ctrl); | 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 | cancel_work_sync(&ctrl->fatal_err_work); | 1755 | cancel_work_sync(&ctrl->fatal_err_work); |
| 1748 | 1756 | ||
| 1749 | nvmet_destroy_auth(ctrl); | 1757 | nvmet_destroy_auth(ctrl); |
| @@ -395,10 +395,9 @@ done: · 394 unmodified lines | |||
| 395 | goto complete; | 395 | goto complete; |
| 396 | } | 396 | } |
| 397 | /* Final states, clear up variables */ | 397 | /* Final states, clear up variables */ |
| 398 | if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) { | 398 | nvmet_auth_sq_free(req->sq); |
| 399 | nvmet_auth_sq_free(req->sq); | 399 | if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) |
| 400 | nvmet_ctrl_fatal_error(ctrl); | 400 | nvmet_ctrl_fatal_error(ctrl); |
| 401 | } | ||
| 402 | 401 | ||
| 403 | complete: | 402 | complete: |
| 404 | nvmet_req_complete(req, status); | 403 | nvmet_req_complete(req, status); |
| @@ -574,7 +573,9 @@ void nvmet_execute_auth_receive(struct nvmet_req *req) · 169 unmodified lines | |||
| 574 | status = nvmet_copy_to_sgl(req, 0, d, al); | 573 | status = nvmet_copy_to_sgl(req, 0, d, al); |
| 575 | kfree(d); | 574 | kfree(d); |
| 576 | done: | 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 | nvmet_auth_sq_free(req->sq); | 579 | nvmet_auth_sq_free(req->sq); |
| 579 | nvmet_ctrl_fatal_error(ctrl); | 580 | nvmet_ctrl_fatal_error(ctrl); |
| 580 | } | 581 | } |
| @@ -214,6 +214,7 @@ struct nvmet_port { · 213 unmodified lines | |||
| 214 | bool enabled; | 214 | bool enabled; |
| 215 | int inline_data_size; | 215 | int inline_data_size; |
| 216 | int max_queue_size; | 216 | int max_queue_size; |
| 217 | int mdts; | ||
| 217 | const struct nvmet_fabrics_ops *tr_ops; | 218 | const struct nvmet_fabrics_ops *tr_ops; |
| 218 | bool pi_enable; | 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 | #define NVMET_MAX_QUEUE_SIZE 1024 | 674 | #define NVMET_MAX_QUEUE_SIZE 1024 |
| 674 | #define NVMET_NR_QUEUES 128 | 675 | #define NVMET_NR_QUEUES 128 |
| 675 | #define NVMET_MAX_CMD(ctrl) (NVME_CAP_MQES(ctrl->cap) + 1) | 676 | #define NVMET_MAX_CMD(ctrl) (NVME_CAP_MQES(ctrl->cap) + 1) |
| 677 | #define NVMET_MAX_MDTS 255 | ||
| 676 | 678 | ||
| 677 | /* | 679 | /* |
| 678 | * Nice round number that makes a list of nsids fit into a page. | 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 | return ctrl->port->disc_addr.trtype == NVMF_TRTYPE_PCI; | 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 | #ifdef CONFIG_NVME_TARGET_PASSTHRU | 777 | #ifdef CONFIG_NVME_TARGET_PASSTHRU |
| 765 | void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys); | 778 | void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys); |
| 766 | int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys); | 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 | cmd->req.sg = NULL; | 349 | cmd->req.sg = NULL; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); | 352 | static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) |
| 353 | |||
| 354 | static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) | ||
| 355 | { | 353 | { |
| 356 | struct bio_vec *iov = cmd->iov; | 354 | struct bio_vec *iov = cmd->iov; |
| 357 | struct scatterlist *sg; | 355 | struct scatterlist *sg; |
| @@ -364,22 +362,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) · 6 unmodified lines | |||
| 364 | offset = cmd->rbytes_done; | 362 | offset = cmd->rbytes_done; |
| 365 | cmd->sg_idx = offset / PAGE_SIZE; | 363 | cmd->sg_idx = offset / PAGE_SIZE; |
| 366 | sg_offset = offset % PAGE_SIZE; | 364 | sg_offset = offset % PAGE_SIZE; |
| 367 | if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { | 365 | if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) |
| 368 | nvmet_tcp_fatal_error(cmd->queue); | 366 | return -EPROTO; |
| 369 | return; | 367 | |
| 370 | } | ||
| 371 | sg = &cmd->req.sg[cmd->sg_idx]; | 368 | sg = &cmd->req.sg[cmd->sg_idx]; |
| 372 | sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; | 369 | sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; |
| 373 | 370 | ||
| 374 | while (length) { | 371 | while (length) { |
| 375 | if (!sg_remaining) { | 372 | if (!sg_remaining) |
| 376 | nvmet_tcp_fatal_error(cmd->queue); | 373 | return -EPROTO; |
| 377 | return; | 374 | |
| 378 | } | 375 | if (!sg->length || sg->length <= sg_offset) |
| 379 | if (!sg->length || sg->length <= sg_offset) { | 376 | return -EPROTO; |
| 380 | nvmet_tcp_fatal_error(cmd->queue); | 377 | |
| 381 | return; | ||
| 382 | } | ||
| 383 | u32 iov_len = min_t(u32, length, sg->length - sg_offset); | 378 | u32 iov_len = min_t(u32, length, sg->length - sg_offset); |
| 384 | 379 | ||
| 385 | bvec_set_page(iov, sg_page(sg), iov_len, | 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 | iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, | 390 | iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, |
| 396 | nr_pages, cmd->pdu_len); | 391 | nr_pages, cmd->pdu_len); |
| 397 | } | 392 | return 0; |
| 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); | ||
| 406 | } | 393 | } |
| 407 | 394 | ||
| 408 | static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) | 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 | queue->rcv_state = NVMET_TCP_RECV_ERR; | 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 | kernel_sock_shutdown(queue->sock, SHUT_RDWR); | 412 | kernel_sock_shutdown(queue->sock, SHUT_RDWR); |
| 413 | else | 413 | else |
| 414 | nvmet_tcp_fatal_error(queue); | 414 | nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd) | 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 | if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) { | 887 | if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) { |
| 888 | pr_err("bad nvme-tcp pdu length (%d)\n", | 888 | pr_err("bad nvme-tcp pdu length (%d)\n", |
| 889 | le32_to_cpu(icreq->hdr.plen)); | 889 | le32_to_cpu(icreq->hdr.plen)); |
| 890 | nvmet_tcp_fatal_error(queue); | ||
| 891 | return -EPROTO; | 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 | iov.iov_len = sizeof(*icresp); | 921 | iov.iov_len = sizeof(*icresp); |
| 923 | ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); | 922 | ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); |
| 924 | if (ret < 0) { | 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 | queue->state = NVMET_TCP_Q_FAILED; | 929 | queue->state = NVMET_TCP_Q_FAILED; |
| 930 | spin_unlock_bh(&queue->state_lock); | ||
| 926 | return ret; /* queue removal will cleanup */ | 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 | queue->state = NVMET_TCP_Q_LIVE; | 940 | queue->state = NVMET_TCP_Q_LIVE; |
| 941 | spin_unlock_bh(&queue->state_lock); | ||
| 930 | nvmet_prepare_receive_pdu(queue); | 942 | nvmet_prepare_receive_pdu(queue); |
| 931 | return 0; | 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 | struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) | 947 | struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) |
| 936 | { | 948 | { |
| 937 | size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); | 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 | if (!nvme_is_write(cmd->req.cmd) || !data_len || | 959 | if (!nvme_is_write(cmd->req.cmd) || !data_len || |
| 948 | data_len > cmd->req.port->inline_data_size) { | 960 | data_len > cmd->req.port->inline_data_size) { |
| 949 | nvmet_prepare_receive_pdu(queue); | 961 | nvmet_prepare_receive_pdu(queue); |
| 950 | return; | 962 | return 0; |
| 951 | } | 963 | } |
| 952 | 964 | ||
| 953 | ret = nvmet_tcp_map_data(cmd); | 965 | ret = nvmet_tcp_map_data(cmd); |
| 954 | if (unlikely(ret)) { | 966 | if (unlikely(ret)) { |
| 955 | pr_err("queue %d: failed to map data\n", queue->idx); | 967 | pr_err("queue %d: failed to map data\n", queue->idx); |
| 956 | nvmet_tcp_fatal_error(queue); | 968 | return -EPROTO; |
| 957 | return; | ||
| 958 | } | 969 | } |
| 959 | 970 | ||
| 960 | queue->rcv_state = NVMET_TCP_RECV_DATA; | 971 | queue->rcv_state = NVMET_TCP_RECV_DATA; |
| 961 | nvmet_tcp_build_pdu_iovec(cmd); | ||
| 962 | cmd->flags |= NVMET_TCP_F_INIT_FAILED; | 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 | static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) | 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 | goto err_proto; | 1026 | goto err_proto; |
| 1012 | } | 1027 | } |
| 1013 | cmd->pdu_recv = 0; | 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 | queue->cmd = cmd; | 1033 | queue->cmd = cmd; |
| 1016 | queue->rcv_state = NVMET_TCP_RECV_DATA; | 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 | err_proto: | 1038 | err_proto: |
| 1021 | /* FIXME: use proper transport errors */ | 1039 | /* FIXME: use proper transport errors */ |
| 1022 | nvmet_tcp_fatal_error(queue); | ||
| 1023 | return -EPROTO; | 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 | if (hdr->type != nvme_tcp_icreq) { | 1051 | if (hdr->type != nvme_tcp_icreq) { |
| 1035 | pr_err("unexpected pdu type (%d) before icreq\n", | 1052 | pr_err("unexpected pdu type (%d) before icreq\n", |
| 1036 | hdr->type); | 1053 | hdr->type); |
| 1037 | nvmet_tcp_fatal_error(queue); | ||
| 1038 | return -EPROTO; | 1054 | return -EPROTO; |
| 1039 | } | 1055 | } |
| 1040 | return nvmet_tcp_handle_icreq(queue); | 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 | if (unlikely(hdr->type == nvme_tcp_icreq)) { | 1059 | if (unlikely(hdr->type == nvme_tcp_icreq)) { |
| 1044 | pr_err("queue %d: received icreq pdu in state %d\n", | 1060 | pr_err("queue %d: received icreq pdu in state %d\n", |
| 1045 | queue->idx, queue->state); | 1061 | queue->idx, queue->state); |
| 1046 | nvmet_tcp_fatal_error(queue); | ||
| 1047 | return -EPROTO; | 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 | pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d", | 1075 | pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d", |
| 1061 | queue->idx, queue->nr_cmds, queue->send_list_len, | 1076 | queue->idx, queue->nr_cmds, queue->send_list_len, |
| 1062 | nvme_cmd->common.opcode); | 1077 | nvme_cmd->common.opcode); |
| 1063 | nvmet_tcp_fatal_error(queue); | ||
| 1064 | return -ENOMEM; | 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 | le32_to_cpu(req->cmd->common.dptr.sgl.length), | 1088 | le32_to_cpu(req->cmd->common.dptr.sgl.length), |
| 1075 | le16_to_cpu(req->cqe->status)); | 1089 | le16_to_cpu(req->cqe->status)); |
| 1076 | 1090 | ||
| 1077 | nvmet_tcp_handle_req_failure(queue, queue->cmd, req); | 1091 | return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); |
| 1078 | return 0; | ||
| 1079 | } | 1092 | } |
| 1080 | 1093 | ||
| 1081 | ret = nvmet_tcp_map_data(queue->cmd); | 1094 | ret = nvmet_tcp_map_data(queue->cmd); |
| 1082 | if (unlikely(ret)) { | 1095 | if (unlikely(ret)) { |
| 1083 | pr_err("queue %d: failed to map data\n", queue->idx); | 1096 | pr_err("queue %d: failed to map data\n", queue->idx); |
| 1084 | if (nvmet_tcp_has_inline_data(queue->cmd)) | 1097 | if (nvmet_tcp_has_inline_data(queue->cmd)) |
| 1085 | nvmet_tcp_fatal_error(queue); | 1098 | return -EPROTO; |
| 1086 | else | 1099 | |
| 1087 | nvmet_req_complete(req, ret); | 1100 | nvmet_req_complete(req, ret); |
| 1088 | ret = -EAGAIN; | 1101 | ret = -EAGAIN; |
| 1089 | goto out; | 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 | if (nvmet_tcp_need_data_in(queue->cmd)) { | 1105 | if (nvmet_tcp_need_data_in(queue->cmd)) { |
| 1093 | if (nvmet_tcp_has_inline_data(queue->cmd)) { | 1106 | if (nvmet_tcp_has_inline_data(queue->cmd)) { |
| 1094 | queue->rcv_state = NVMET_TCP_RECV_DATA; | 1107 | queue->rcv_state = NVMET_TCP_RECV_DATA; |
| 1095 | nvmet_tcp_build_pdu_iovec(queue->cmd); | 1108 | ret = nvmet_tcp_build_pdu_iovec(queue->cmd); |
| 1096 | return 0; | 1109 | if (unlikely(ret)) |
| 1110 | pr_err("queue %d: failed to build PDU iovec\n", | ||
| 1111 | queue->idx); | ||
| 1112 | return ret; | ||
| 1097 | } | 1113 | } |
| 1098 | /* send back R2T */ | 1114 | /* send back R2T */ |
| 1099 | nvmet_tcp_queue_response(&queue->cmd->req); | 1115 | nvmet_tcp_queue_response(&queue->cmd->req); |
| @@ -1204,7 +1220,6 @@ recv: · 104 unmodified lines | |||
| 1204 | 1220 | ||
| 1205 | if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) { | 1221 | if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) { |
| 1206 | pr_err("unexpected pdu type %d\n", hdr->type); | 1222 | pr_err("unexpected pdu type %d\n", hdr->type); |
| 1207 | nvmet_tcp_fatal_error(queue); | ||
| 1208 | return -EIO; | 1223 | return -EIO; |
| 1209 | } | 1224 | } |
| 1210 | 1225 | ||
| @@ -1218,16 +1233,12 @@ recv: · 7 unmodified lines | |||
| 1218 | } | 1233 | } |
| 1219 | 1234 | ||
| 1220 | if (queue->hdr_digest && | 1235 | if (queue->hdr_digest && |
| 1221 | nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) { | 1236 | nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) |
| 1222 | nvmet_tcp_fatal_error(queue); /* fatal */ | ||
| 1223 | return -EPROTO; | 1237 | return -EPROTO; |
| 1224 | } | ||
| 1225 | 1238 | ||
| 1226 | if (queue->data_digest && | 1239 | if (queue->data_digest && |
| 1227 | nvmet_tcp_check_ddgst(queue, &queue->pdu)) { | 1240 | nvmet_tcp_check_ddgst(queue, &queue->pdu)) |
| 1228 | nvmet_tcp_fatal_error(queue); /* fatal */ | ||
| 1229 | return -EPROTO; | 1241 | return -EPROTO; |
| 1230 | } | ||
| 1231 | 1242 | ||
| 1232 | return nvmet_tcp_done_recv_pdu(queue); | 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 | queue->idx, cmd->req.cmd->common.command_id, | 1321 | queue->idx, cmd->req.cmd->common.command_id, |
| 1311 | queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), | 1322 | queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), |
| 1312 | le32_to_cpu(cmd->exp_ddgst)); | 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 | nvmet_tcp_free_cmd_buffers(cmd); | 1326 | nvmet_tcp_free_cmd_buffers(cmd); |
| 1315 | nvmet_tcp_fatal_error(queue); | ||
| 1316 | ret = -EPROTO; | 1327 | ret = -EPROTO; |
| 1317 | goto out; | 1328 | goto out; |
| 1318 | } | 1329 | } |
| @@ -69,7 +69,6 @@ bool nvmet_bdev_zns_enable(struct nvmet_ns *ns) · 68 unmodified lines | |||
| 69 | void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) | 69 | void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) |
| 70 | { | 70 | { |
| 71 | u8 zasl = req->sq->ctrl->subsys->zasl; | 71 | u8 zasl = req->sq->ctrl->subsys->zasl; |
| 72 | struct nvmet_ctrl *ctrl = req->sq->ctrl; | ||
| 73 | struct nvme_id_ctrl_zns *id; | 72 | struct nvme_id_ctrl_zns *id; |
| 74 | u16 status; | 73 | u16 status; |
| 75 | 74 | ||
| @@ -79,10 +78,7 @@ void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req) · 3 unmodified lines | |||
| 79 | goto out; | 78 | goto out; |
| 80 | } | 79 | } |
| 81 | 80 | ||
| 82 | if (ctrl->ops->get_mdts) | 81 | id->zasl = min_not_zero(nvmet_ctrl_mdts(req), zasl); |
| 83 | id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl); | ||
| 84 | else | ||
| 85 | id->zasl = zasl; | ||
| 86 | 82 | ||
| 87 | status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id)); | 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 | tristate "Raspberry Pi 7-inch touchscreen panel ATTINY regulator" | 1231 | tristate "Raspberry Pi 7-inch touchscreen panel ATTINY regulator" |
| 1232 | depends on ARM || ARM64 || COMPILE_TEST | 1232 | depends on ARM || ARM64 || COMPILE_TEST |
| 1233 | depends on BACKLIGHT_CLASS_DEVICE | 1233 | depends on BACKLIGHT_CLASS_DEVICE |
| 1234 | depends on GPIOLIB | ||
| 1234 | depends on I2C | 1235 | depends on I2C |
| 1235 | select REGMAP_I2C | 1236 | select REGMAP_I2C |
| 1236 | help | 1237 | help |
| @@ -85,14 +85,6 @@ config HMC_DRV · 84 unmodified lines | |||
| 85 | transfer cache size from its default value 0.5MB to N bytes. If N | 85 | transfer cache size from its default value 0.5MB to N bytes. If N |
| 86 | is zero, then no caching is performed. | 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 | config S390_UV_UAPI | 88 | config S390_UV_UAPI |
| 97 | def_tristate m | 89 | def_tristate m |
| 98 | prompt "Ultravisor userspace API" | 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 | static struct sclp_register sclp_conf_register = | 81 | static struct sclp_register sclp_conf_register = |
| 82 | { | 82 | { |
| 83 | #ifdef CONFIG_SCLP_OFB | ||
| 84 | .send_mask = EVTYP_CONFMGMDATA_MASK, | 83 | .send_mask = EVTYP_CONFMGMDATA_MASK, |
| 85 | #endif | ||
| 86 | .receive_mask = EVTYP_CONFMGMDATA_MASK, | 84 | .receive_mask = EVTYP_CONFMGMDATA_MASK, |
| 87 | .receiver_fn = sclp_conf_receiver_fn, | 85 | .receiver_fn = sclp_conf_receiver_fn, |
| 88 | }; | 86 | }; |
| 89 | 87 | ||
| 90 | #ifdef CONFIG_SCLP_OFB | ||
| 91 | static int sclp_ofb_send_req(char *ev_data, size_t len) | 88 | static int sclp_ofb_send_req(char *ev_data, size_t len) |
| 92 | { | 89 | { |
| 93 | static DEFINE_MUTEX(send_mutex); | 90 | static DEFINE_MUTEX(send_mutex); |
| @@ -143,11 +140,9 @@ static const struct bin_attribute ofb_bin_attr = { · 49 unmodified lines | |||
| 143 | }, | 140 | }, |
| 144 | .write = sysfs_ofb_data_write, | 141 | .write = sysfs_ofb_data_write, |
| 145 | }; | 142 | }; |
| 146 | #endif | ||
| 147 | 143 | ||
| 148 | static int __init sclp_ofb_setup(void) | 144 | static int __init sclp_ofb_setup(void) |
| 149 | { | 145 | { |
| 150 | #ifdef CONFIG_SCLP_OFB | ||
| 151 | struct kset *ofb_kset; | 146 | struct kset *ofb_kset; |
| 152 | int rc; | 147 | int rc; |
| 153 | 148 | ||
| @@ -159,7 +154,6 @@ static int __init sclp_ofb_setup(void) · 5 unmodified lines | |||
| 159 | kset_unregister(ofb_kset); | 154 | kset_unregister(ofb_kset); |
| 160 | return rc; | 155 | return rc; |
| 161 | } | 156 | } |
| 162 | #endif | ||
| 163 | return 0; | 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 | switch (req_op(rq)) { | 396 | switch (req_op(rq)) { |
| 397 | case REQ_OP_WRITE: | 397 | case REQ_OP_WRITE: |
| 398 | if (!cd->writeable) | 398 | if (get_disk_ro(cd->disk)) |
| 399 | goto out; | 399 | goto out; |
| 400 | SCpnt->cmnd[0] = WRITE_10; | 400 | SCpnt->cmnd[0] = WRITE_10; |
| 401 | cd->cdi.media_written = 1; | 401 | cd->cdi.media_written = 1; |
| @@ -681,6 +681,7 @@ static int sr_probe(struct scsi_device *sdev) · 279 unmodified lines | |||
| 681 | error = -ENOMEM; | 681 | error = -ENOMEM; |
| 682 | if (get_capabilities(cd)) | 682 | if (get_capabilities(cd)) |
| 683 | goto fail_minor; | 683 | goto fail_minor; |
| 684 | cdrom_probe_write_features(&cd->cdi); | ||
| 684 | sr_vendor_init(cd); | 685 | sr_vendor_init(cd); |
| 685 | 686 | ||
| 686 | set_capacity(disk, cd->capacity); | 687 | set_capacity(disk, cd->capacity); |
| @@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd) · 212 unmodified lines | |||
| 899 | /*else I don't think it can close its tray | 900 | /*else I don't think it can close its tray |
| 900 | cd->cdi.mask |= CDC_CLOSE_TRAY; */ | 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 | kfree(buffer); | 903 | kfree(buffer); |
| 911 | return 0; | 904 | return 0; |
| 912 | } | 905 | } |
| @@ -35,7 +35,6 @@ typedef struct scsi_cd { · 34 unmodified lines | |||
| 35 | struct scsi_device *device; | 35 | struct scsi_device *device; |
| 36 | unsigned int vendor; /* vendor code, see sr_vendor.c */ | 36 | unsigned int vendor; /* vendor code, see sr_vendor.c */ |
| 37 | unsigned long ms_offset; /* for reading multisession-CD's */ | 37 | unsigned long ms_offset; /* for reading multisession-CD's */ |
| 38 | unsigned writeable : 1; | ||
| 39 | unsigned use:1; /* is this device still supportable */ | 38 | unsigned use:1; /* is this device still supportable */ |
| 40 | unsigned xa_flag:1; /* CD has XA sectors ? */ | 39 | unsigned xa_flag:1; /* CD has XA sectors ? */ |
| 41 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ | 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 | if (desc->info.length > SPI_NAND_CACHE_SIZE) | 546 | if (desc->info.length > SPI_NAND_CACHE_SIZE) |
| 547 | return -E2BIG; | 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 | return -EOPNOTSUPP; | 550 | return -EOPNOTSUPP; |
| 551 | 551 | ||
| 552 | return 0; | 552 | return 0; |
| @@ -572,7 +572,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, · 19 unmodified lines | |||
| 572 | * DUALIO and QUADIO opcodes are not supported by the spi controller, | 572 | * DUALIO and QUADIO opcodes are not supported by the spi controller, |
| 573 | * replace them with supported opcodes. | 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 | switch (opcode) { | 576 | switch (opcode) { |
| 577 | case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: | 577 | case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: |
| 578 | case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: | 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 | /* minimum oob size is 64 */ | 761 | /* minimum oob size is 64 */ |
| 762 | bytes = round_up(offs + len, 64); | 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 | switch (opcode) { | 765 | switch (opcode) { |
| 766 | case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: | 766 | case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: |
| 767 | case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: | 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 | dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX); | 795 | dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX); |
| 796 | 796 | ||
| 797 | init_completion(&spisg->completion); | ||
| 797 | ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg); | 798 | ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg); |
| 798 | if (ret) { | 799 | if (ret) { |
| 799 | dev_err(&pdev->dev, "irq request failed\n"); | 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 | goto out_clk; | 807 | goto out_clk; |
| 807 | } | 808 | } |
| 808 | 809 | ||
| 809 | init_completion(&spisg->completion); | ||
| 810 | |||
| 811 | pm_runtime_put(&spisg->pdev->dev); | 810 | pm_runtime_put(&spisg->pdev->dev); |
| 812 | 811 | ||
| 813 | return 0; | 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 | struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller); | 698 | struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 699 | struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)]; | 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 | u32 ctl_val; | 701 | u32 ctl_val; |
| 702 | int ret = 0; | 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 | if (chip->ahb_window_size < offset + len || chip->force_user_mode) { | 769 | if (chip->ahb_window_size < offset + len || chip->force_user_mode) { |
| 770 | int ret; | 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 | if (ret < 0) | 773 | if (ret < 0) |
| 774 | return ret; | 774 | return ret; |
| 775 | } else { | 775 | } else { |
| @@ -201,7 +201,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi) · 200 unmodified lines | |||
| 201 | * then spi control did't work thoroughly, add one byte delay | 201 | * then spi control did't work thoroughly, add one byte delay |
| 202 | */ | 202 | */ |
| 203 | if (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV) | 203 | if (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV) |
| 204 | usleep_range(10, 10); | 204 | udelay(10); |
| 205 | if (xspi->tx_buf) | 205 | if (xspi->tx_buf) |
| 206 | ax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++); | 206 | ax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++); |
| 207 | else | 207 | else |
| @@ -1860,14 +1860,10 @@ static int cqspi_probe(struct platform_device *pdev) · 1859 unmodified lines | |||
| 1860 | if (irq < 0) | 1860 | if (irq < 0) |
| 1861 | return -ENXIO; | 1861 | return -ENXIO; |
| 1862 | 1862 | ||
| 1863 | ret = pm_runtime_set_active(dev); | ||
| 1864 | if (ret) | ||
| 1865 | return ret; | ||
| 1866 | |||
| 1867 | ret = clk_bulk_prepare_enable(CLK_QSPI_NUM, cqspi->clks); | 1863 | ret = clk_bulk_prepare_enable(CLK_QSPI_NUM, cqspi->clks); |
| 1868 | if (ret) { | 1864 | if (ret) { |
| 1869 | dev_err(dev, "Cannot enable QSPI clocks.\n"); | 1865 | dev_err(dev, "Cannot enable QSPI clocks.\n"); |
| 1870 | goto disable_rpm; | 1866 | return ret; |
| 1871 | } | 1867 | } |
| 1872 | 1868 | ||
| 1873 | /* Obtain QSPI reset control */ | 1869 | /* Obtain QSPI reset control */ |
| @@ -1962,10 +1958,11 @@ static int cqspi_probe(struct platform_device *pdev) · 88 unmodified lines | |||
| 1962 | cqspi->sclk = 0; | 1958 | cqspi->sclk = 0; |
| 1963 | 1959 | ||
| 1964 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { | 1960 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { |
| 1965 | pm_runtime_enable(dev); | ||
| 1966 | pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); | 1961 | pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT); |
| 1967 | pm_runtime_use_autosuspend(dev); | 1962 | pm_runtime_use_autosuspend(dev); |
| 1968 | pm_runtime_get_noresume(dev); | 1963 | pm_runtime_get_noresume(dev); |
| 1964 | pm_runtime_set_active(dev); | ||
| 1965 | pm_runtime_enable(dev); | ||
| 1969 | } | 1966 | } |
| 1970 | 1967 | ||
| 1971 | host->num_chipselect = cqspi->num_chipselect; | 1968 | host->num_chipselect = cqspi->num_chipselect; |
| @@ -1977,7 +1974,7 @@ static int cqspi_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 1977 | ret = cqspi_request_mmap_dma(cqspi); | 1974 | ret = cqspi_request_mmap_dma(cqspi); |
| 1978 | if (ret == -EPROBE_DEFER) { | 1975 | if (ret == -EPROBE_DEFER) { |
| 1979 | dev_err_probe(&pdev->dev, ret, "Failed to request mmap DMA\n"); | 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 | release_dma_chan: | 1992 | release_dma_chan: |
| 1996 | if (cqspi->rx_chan) | 1993 | if (cqspi->rx_chan) |
| 1997 | dma_release_channel(cqspi->rx_chan); | 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 | disable_rpm: | 1995 | disable_rpm: |
| 2004 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) | 1996 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { |
| 2005 | pm_runtime_disable(dev); | 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 | return ret; | 2006 | return ret; |
| 2008 | } | 2007 | } |
| @@ -2026,18 +2025,19 @@ static void cqspi_remove(struct platform_device *pdev) · 17 unmodified lines | |||
| 2026 | if (cqspi->rx_chan) | 2025 | if (cqspi->rx_chan) |
| 2027 | dma_release_channel(cqspi->rx_chan); | 2026 | dma_release_channel(cqspi->rx_chan); |
| 2028 | 2027 | ||
| 2029 | cqspi_controller_enable(cqspi, 0); | ||
| 2030 | |||
| 2031 | |||
| 2032 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) | 2028 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) |
| 2033 | ret = pm_runtime_get_sync(&pdev->dev); | 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 | clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); | 2033 | clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); |
| 2034 | } | ||
| 2037 | 2035 | ||
| 2038 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { | 2036 | if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { |
| 2039 | pm_runtime_put_sync(&pdev->dev); | ||
| 2040 | pm_runtime_disable(&pdev->dev); | 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 | /* Set to default valid value */ | 741 | /* Set to default valid value */ |
| 742 | ctlr->max_speed_hz = xspi->clk_rate / 4; | 742 | ctlr->max_speed_hz = xspi->clk_rate / 4; |
| 743 | xspi->speed_hz = ctlr->max_speed_hz; | 743 | xspi->speed_hz = ctlr->max_speed_hz; |
| 744 | pm_runtime_put_autosuspend(&pdev->dev); | ||
| 745 | } else { | 744 | } else { |
| 746 | ctlr->mode_bits |= SPI_NO_CS; | 745 | ctlr->mode_bits |= SPI_NO_CS; |
| 747 | ctlr->target_abort = cdns_target_abort; | 746 | ctlr->target_abort = cdns_target_abort; |
| @@ -752,12 +751,17 @@ static int cdns_spi_probe(struct platform_device *pdev) · 4 unmodified lines | |||
| 752 | goto clk_dis_all; | 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 | return ret; | 757 | return ret; |
| 756 | 758 | ||
| 757 | clk_dis_all: | 759 | clk_dis_all: |
| 758 | if (!spi_controller_is_target(ctlr)) { | 760 | if (!spi_controller_is_target(ctlr)) { |
| 759 | pm_runtime_disable(&pdev->dev); | 761 | pm_runtime_disable(&pdev->dev); |
| 760 | pm_runtime_set_suspended(&pdev->dev); | 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 | remove_ctlr: | 766 | remove_ctlr: |
| 763 | spi_controller_put(ctlr); | 767 | spi_controller_put(ctlr); |
| @@ -776,16 +780,23 @@ static void cdns_spi_remove(struct platform_device *pdev) · 12 unmodified lines | |||
| 776 | { | 780 | { |
| 777 | struct spi_controller *ctlr = platform_get_drvdata(pdev); | 781 | struct spi_controller *ctlr = platform_get_drvdata(pdev); |
| 778 | struct cdns_spi *xspi = spi_controller_get_devdata(ctlr); | 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 | spi_controller_get(ctlr); | 788 | spi_controller_get(ctlr); |
| 781 | 789 | ||
| 782 | spi_unregister_controller(ctlr); | 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 | if (!spi_controller_is_target(ctlr)) { | 795 | if (!spi_controller_is_target(ctlr)) { |
| 787 | pm_runtime_disable(&pdev->dev); | 796 | pm_runtime_disable(&pdev->dev); |
| 788 | pm_runtime_set_suspended(&pdev->dev); | 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 | spi_controller_put(ctlr); | 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 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); | 814 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 815 | const struct intel_spi_mem_op *iop; | 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 | if (!iop) | 818 | if (!iop) |
| 819 | return -EOPNOTSUPP; | 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 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); | 828 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 829 | const struct intel_spi_mem_op *iop = desc->priv; | 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 | int ret; | 831 | int ret; |
| 832 | 832 | ||
| 833 | /* Fill in the gaps */ | 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 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); | 845 | struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller); |
| 846 | const struct intel_spi_mem_op *iop = desc->priv; | 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 | int ret; | 848 | int ret; |
| 849 | 849 | ||
| 850 | op.addr.val = offs; | 850 | op.addr.val = offs; |
| @@ -647,7 +647,7 @@ EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration); · 646 unmodified lines | |||
| 647 | static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, | 647 | static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, |
| 648 | u64 offs, size_t len, void *buf) | 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 | int ret; | 651 | int ret; |
| 652 | 652 | ||
| 653 | op.addr.val = desc->info.offset + offs; | 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 | static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, | 667 | static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, |
| 668 | u64 offs, size_t len, const void *buf) | 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 | int ret; | 671 | int ret; |
| 672 | 672 | ||
| 673 | op.addr.val = desc->info.offset + offs; | 673 | op.addr.val = desc->info.offset + offs; |
| @@ -706,19 +706,37 @@ spi_mem_dirmap_create(struct spi_mem *mem, · 32 unmodified lines | |||
| 706 | int ret = -ENOTSUPP; | 706 | int ret = -ENOTSUPP; |
| 707 | 707 | ||
| 708 | /* Make sure the number of address cycles is between 1 and 8 bytes. */ | 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 | return ERR_PTR(-EINVAL); | 710 | return ERR_PTR(-EINVAL); |
| 711 | 711 | ||
| 712 | /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */ | 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 | return ERR_PTR(-EINVAL); | 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 | desc = kzalloc_obj(*desc); | 733 | desc = kzalloc_obj(*desc); |
| 717 | if (!desc) | 734 | if (!desc) |
| 718 | return ERR_PTR(-ENOMEM); | 735 | return ERR_PTR(-ENOMEM); |
| 719 | 736 | ||
| 720 | desc->mem = mem; | 737 | desc->mem = mem; |
| 721 | desc->info = *info; | 738 | desc->info = *info; |
| 739 | desc->info.op_tmpl = &desc->info.primary_op_tmpl; | ||
| 722 | if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) { | 740 | if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) { |
| 723 | ret = spi_mem_access_start(mem); | 741 | ret = spi_mem_access_start(mem); |
| 724 | if (ret) { | 742 | if (ret) { |
| @@ -733,7 +751,7 @@ spi_mem_dirmap_create(struct spi_mem *mem, · 8 unmodified lines | |||
| 733 | 751 | ||
| 734 | if (ret) { | 752 | if (ret) { |
| 735 | desc->nodirmap = true; | 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 | ret = -EOPNOTSUPP; | 755 | ret = -EOPNOTSUPP; |
| 738 | else | 756 | else |
| 739 | ret = 0; | 757 | ret = 0; |
| @@ -857,7 +875,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, · 117 unmodified lines | |||
| 857 | struct spi_controller *ctlr = desc->mem->spi->controller; | 875 | struct spi_controller *ctlr = desc->mem->spi->controller; |
| 858 | ssize_t ret; | 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 | return -EINVAL; | 879 | return -EINVAL; |
| 862 | 880 | ||
| 863 | if (!len) | 881 | if (!len) |
| @@ -903,7 +921,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, · 39 unmodified lines | |||
| 903 | struct spi_controller *ctlr = desc->mem->spi->controller; | 921 | struct spi_controller *ctlr = desc->mem->spi->controller; |
| 904 | ssize_t ret; | 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 | return -EINVAL; | 925 | return -EINVAL; |
| 908 | 926 | ||
| 909 | if (!len) | 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 | if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) | 403 | if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) |
| 404 | return -EINVAL; | 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 | mxic->regs + HC_CFG); | 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 | mxic->regs + LRD_CFG); | 410 | mxic->regs + LRD_CFG); |
| 411 | writel(desc->info.offset + offs, mxic->regs + LRD_ADDR); | 411 | writel(desc->info.offset + offs, mxic->regs + LRD_ADDR); |
| 412 | len = min_t(size_t, len, mxic->linear.size); | 412 | len = min_t(size_t, len, mxic->linear.size); |
| 413 | writel(len, mxic->regs + LRD_RANGE); | 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 | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | | 415 | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | |
| 416 | LMODE_EN, | 416 | LMODE_EN, |
| 417 | mxic->regs + LRD_CTRL); | 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 | ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, | 420 | ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, |
| 421 | NAND_PAGE_READ, | 421 | NAND_PAGE_READ, |
| 422 | mxic->linear.dma + offs); | 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 | if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) | 448 | if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) |
| 449 | return -EINVAL; | 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 | mxic->regs + HC_CFG); | 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 | mxic->regs + LWR_CFG); | 455 | mxic->regs + LWR_CFG); |
| 456 | writel(desc->info.offset + offs, mxic->regs + LWR_ADDR); | 456 | writel(desc->info.offset + offs, mxic->regs + LWR_ADDR); |
| 457 | len = min_t(size_t, len, mxic->linear.size); | 457 | len = min_t(size_t, len, mxic->linear.size); |
| 458 | writel(len, mxic->regs + LWR_RANGE); | 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 | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | | 460 | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | |
| 461 | LMODE_EN, | 461 | LMODE_EN, |
| 462 | mxic->regs + LWR_CTRL); | 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 | ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, | 465 | ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, |
| 466 | NAND_PAGE_WRITE, | 466 | NAND_PAGE_WRITE, |
| 467 | mxic->linear.dma + offs); | 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 | if (desc->info.offset + desc->info.length > U32_MAX) | 509 | if (desc->info.offset + desc->info.length > U32_MAX) |
| 510 | return -EINVAL; | 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 | return -EOPNOTSUPP; | 513 | return -EOPNOTSUPP; |
| 514 | 514 | ||
| 515 | return 0; | 515 | return 0; |
| @@ -299,11 +299,11 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, · 298 unmodified lines | |||
| 299 | for (i = 0 ; i < len ; i++) | 299 | for (i = 0 ; i < len ; i++) |
| 300 | *(buf_rx + i) = ioread8(src + i); | 300 | *(buf_rx + i) = ioread8(src + i); |
| 301 | } else { | 301 | } else { |
| 302 | if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth || | 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 || | 303 | desc->info.op_tmpl->dummy.nbytes != fiu->drd_op.dummy.nbytes || |
| 304 | desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode || | 304 | desc->info.op_tmpl->cmd.opcode != fiu->drd_op.cmd.opcode || |
| 305 | desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes) | 305 | desc->info.op_tmpl->addr.nbytes != fiu->drd_op.addr.nbytes) |
| 306 | npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); | 306 | npcm_fiu_set_drd(fiu, desc->info.op_tmpl); |
| 307 | 307 | ||
| 308 | memcpy_fromio(buf_rx, src, len); | 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 | if (!fiu->spix_mode && | 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 | desc->nodirmap = true; | 613 | desc->nodirmap = true; |
| 614 | return 0; | 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 | NPCM_FIU_CFG_FIU_FIX); | 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 | if (!fiu->spix_mode) | 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 | else | 650 | else |
| 651 | npcm_fiux_set_direct_rd(fiu); | 651 | npcm_fiux_set_direct_rd(fiu); |
| 652 | 652 | ||
| @@ -98,7 +98,6 @@ · 97 unmodified lines | |||
| 98 | #define CR0_FRF_MICROWIRE 0x2 | 98 | #define CR0_FRF_MICROWIRE 0x2 |
| 99 | 99 | ||
| 100 | #define CR0_XFM_OFFSET 18 | 100 | #define CR0_XFM_OFFSET 18 |
| 101 | #define CR0_XFM_MASK (0x03 << SPI_XFM_OFFSET) | ||
| 102 | #define CR0_XFM_TR 0x0 | 101 | #define CR0_XFM_TR 0x0 |
| 103 | #define CR0_XFM_TO 0x1 | 102 | #define CR0_XFM_TO 0x1 |
| 104 | #define CR0_XFM_RO 0x2 | 103 | #define CR0_XFM_RO 0x2 |
| @@ -109,8 +108,6 @@ · 4 unmodified lines | |||
| 109 | 108 | ||
| 110 | #define CR0_SOI_OFFSET 23 | 109 | #define CR0_SOI_OFFSET 23 |
| 111 | 110 | ||
| 112 | #define CR0_MTM_OFFSET 0x21 | ||
| 113 | |||
| 114 | /* Bit fields in SER, 2bit */ | 111 | /* Bit fields in SER, 2bit */ |
| 115 | #define SER_MASK 0x3 | 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 | struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); | 354 | struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
| 358 | 355 | ||
| 359 | /* When int_cs_inactive comes, spi target abort */ | 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 | ctlr->target_abort(ctlr); | 359 | ctlr->target_abort(ctlr); |
| 362 | writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); | 360 | writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); |
| 363 | writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); | 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 | if (offs + desc->info.offset + len > U32_MAX) | 83 | if (offs + desc->info.offset + len > U32_MAX) |
| 84 | return -EINVAL; | 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 | return xspi_dirmap_write(rpc->dev, offs, len, buf); | 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 | if (offs + desc->info.offset + len > U32_MAX) | 97 | if (offs + desc->info.offset + len > U32_MAX) |
| 98 | return -EINVAL; | 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 | return rpcif_dirmap_read(rpc->dev, offs, len, buf); | 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 | if (desc->info.offset + desc->info.length > U32_MAX) | 110 | if (desc->info.offset + desc->info.length > U32_MAX) |
| 111 | return -EINVAL; | 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 | return -EOPNOTSUPP; | 114 | return -EOPNOTSUPP; |
| 115 | 115 | ||
| 116 | if (!rpc->dirmap) | 116 | if (!rpc->dirmap) |
| 117 | return -EOPNOTSUPP; | 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 | return -EOPNOTSUPP; | 120 | return -EOPNOTSUPP; |
| 121 | 121 | ||
| 122 | return 0; | 122 | return 0; |
| @@ -579,7 +579,7 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz) · 578 unmodified lines | |||
| 579 | rspi->info->find_pclk_rate(rspi->pclk, hz, &best_clock); | 579 | rspi->info->find_pclk_rate(rspi->pclk, hz, &best_clock); |
| 580 | 580 | ||
| 581 | if (!best_clock.clk_rate) | 581 | if (!best_clock.clk_rate) |
| 582 | return -EINVAL; | 582 | return 0; |
| 583 | 583 | ||
| 584 | ret = clk_set_rate(best_clock.clk, best_clock.clk_rate); | 584 | ret = clk_set_rate(best_clock.clk, best_clock.clk_rate); |
| 585 | if (ret) | 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 | struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller); | 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 | return -EOPNOTSUPP; | 606 | return -EOPNOTSUPP; |
| 607 | 607 | ||
| 608 | /* Should never happen, as mm_base == null is an error probe exit condition */ | 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 | return -EOPNOTSUPP; | 610 | return -EOPNOTSUPP; |
| 611 | 611 | ||
| 612 | if (!ospi->mm_size) | 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 | * spi_mem_op template with offs, len and *buf in order to get | 633 | * spi_mem_op template with offs, len and *buf in order to get |
| 634 | * all needed transfer information into struct spi_mem_op | 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 | dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); | 637 | dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); |
| 638 | 638 | ||
| 639 | op.data.nbytes = len; | 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 | struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->controller); | 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 | return -EOPNOTSUPP; | 510 | return -EOPNOTSUPP; |
| 511 | 511 | ||
| 512 | /* should never happen, as mm_base == null is an error probe exit condition */ | 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 | return -EOPNOTSUPP; | 514 | return -EOPNOTSUPP; |
| 515 | 515 | ||
| 516 | if (!qspi->mm_size) | 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 | * spi_mem_op template with offs, len and *buf in order to get | 536 | * spi_mem_op template with offs, len and *buf in order to get |
| 537 | * all needed transfer information into struct spi_mem_op | 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 | dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); | 540 | dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); |
| 541 | 541 | ||
| 542 | op.data.nbytes = len; | 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 | struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); | 377 | struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); |
| 378 | int cs = spi_get_chipselect(desc->mem->spi, 0); | 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 | return -EOPNOTSUPP; | 381 | return -EOPNOTSUPP; |
| 382 | 382 | ||
| 383 | /* | 383 | /* |
| @@ -1620,6 +1620,12 @@ static void privcmd_close(struct vm_area_struct *vma) · 1619 unmodified lines | |||
| 1620 | kvfree(pages); | 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 | static vm_fault_t privcmd_fault(struct vm_fault *vmf) | 1629 | static vm_fault_t privcmd_fault(struct vm_fault *vmf) |
| 1624 | { | 1630 | { |
| 1625 | printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", | 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 | static const struct vm_operations_struct privcmd_vm_ops = { | 1638 | static const struct vm_operations_struct privcmd_vm_ops = { |
| 1633 | .close = privcmd_close, | 1639 | .close = privcmd_close, |
| 1640 | .may_split = privcmd_may_split, | ||
| 1634 | .fault = privcmd_fault | 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 | ret = sprintf(buffer, "<denied>"); | 366 | ret = sprintf(buffer, "<denied>"); |
| 367 | return ret; | 367 | return ret; |
| 368 | } | 368 | } |
| 369 | if (ret > PAGE_SIZE) | ||
| 370 | return -ENOSPC; | ||
| 369 | 371 | ||
| 370 | buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL); | 372 | buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL); |
| 371 | if (!buildid) | 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 | buildid->len = ret; | 376 | buildid->len = ret; |
| 375 | ret = HYPERVISOR_xen_version(XENVER_build_id, buildid); | 377 | ret = HYPERVISOR_xen_version(XENVER_build_id, buildid); |
| 376 | if (ret > 0) | 378 | if (ret > 0) { |
| 377 | ret = sprintf(buffer, "%s", buildid->buf); | 379 | /* Build id is binary, not a string. */ |
| 380 | memcpy(buffer, buildid->buf, ret); | ||
| 381 | } | ||
| 378 | kfree(buildid); | 382 | kfree(buildid); |
| 379 | 383 | ||
| 380 | return ret; | 384 | return ret; |
| @@ -4641,7 +4641,8 @@ int try_release_extent_buffer(struct folio *folio) · 4640 unmodified lines | |||
| 4641 | * to read the block we will not block on anything. | 4641 | * to read the block we will not block on anything. |
| 4642 | */ | 4642 | */ |
| 4643 | void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, | 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 | struct btrfs_tree_parent_check check = { | 4647 | struct btrfs_tree_parent_check check = { |
| 4647 | .level = level, | 4648 | .level = level, |
| @@ -4650,6 +4651,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, · 2 unmodified lines | |||
| 4650 | struct extent_buffer *eb; | 4651 | struct extent_buffer *eb; |
| 4651 | int ret; | 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 | eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); | 4659 | eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); |
| 4654 | if (IS_ERR(eb)) | 4660 | if (IS_ERR(eb)) |
| 4655 | return; | 4661 | return; |
| @@ -4677,9 +4683,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, · 21 unmodified lines | |||
| 4677 | */ | 4683 | */ |
| 4678 | void btrfs_readahead_node_child(struct extent_buffer *node, int slot) | 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 | btrfs_readahead_tree_block(node->fs_info, | 4689 | btrfs_readahead_tree_block(node->fs_info, |
| 4681 | btrfs_node_blockptr(node, slot), | 4690 | btrfs_node_blockptr(node, slot), |
| 4682 | btrfs_header_owner(node), | 4691 | btrfs_header_owner(node), |
| 4683 | btrfs_node_ptr_generation(node, slot), | 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 | void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, | 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 | void btrfs_readahead_node_child(struct extent_buffer *node, int slot); | 292 | void btrfs_readahead_node_child(struct extent_buffer *node, int slot); |
| 292 | 293 | ||
| 293 | /* Note: this can be used in for loops without caching the value in a variable. */ | 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 | nr++; | 259 | nr++; |
| 260 | path->slots[0]--; | 260 | path->slots[0]--; |
| 261 | } else { | 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 | nr++; | 410 | nr++; |
| 407 | } else { | 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 | nr++; | 1526 | nr++; |
| 1519 | path->slots[0]--; | 1527 | path->slots[0]--; |
| 1520 | } else { | 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 | NULL, &cached, | 1153 | NULL, &cached, |
| 1154 | EXTENT_LOCKED | EXTENT_DELALLOC | | 1154 | EXTENT_LOCKED | EXTENT_DELALLOC | |
| 1155 | EXTENT_DELALLOC_NEW | | 1155 | EXTENT_DELALLOC_NEW | |
| 1156 | EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, | 1156 | EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, |
| 1157 | PAGE_UNLOCK | PAGE_START_WRITEBACK | | 1157 | PAGE_UNLOCK | PAGE_START_WRITEBACK | |
| 1158 | PAGE_END_WRITEBACK); | 1158 | PAGE_END_WRITEBACK); |
| 1159 | if (async_extent->cb) | 1159 | if (async_extent->cb) |
| @@ -4959,6 +4959,8 @@ static int btrfs_rmdir(struct inode *vfs_dir, struct dentry *dentry) · 3799 unmodified lines | |||
| 4959 | if (ret) | 4959 | if (ret) |
| 4960 | goto out; | 4960 | goto out; |
| 4961 | 4961 | ||
| 4962 | btrfs_record_unlink_dir(trans, dir, inode, false); | ||
| 4963 | |||
| 4962 | /* now the directory is empty */ | 4964 | /* now the directory is empty */ |
| 4963 | ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name); | 4965 | ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name); |
| 4964 | if (!ret) | 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 | return 0; | 5102 | return 0; |
| 5103 | } | 5103 | } |
| 5104 | 5104 | ||
| 5105 | #ifdef CONFIG_BTRFS_EXPERIMENTAL | ||
| 5106 | static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg) | 5105 | static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg) |
| 5107 | { | 5106 | { |
| 5108 | int ret = 0; | 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 | case BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH: | 5133 | case BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH: |
| 5135 | btrfs_force_shutdown(fs_info); | 5134 | btrfs_force_shutdown(fs_info); |
| 5136 | break; | 5135 | break; |
| 5136 | default: | ||
| 5137 | ret = -EINVAL; | ||
| 5138 | break; | ||
| 5137 | } | 5139 | } |
| 5138 | return ret; | 5140 | return ret; |
| 5139 | } | 5141 | } |
| 5140 | #endif | ||
| 5141 | 5142 | ||
| 5142 | long btrfs_ioctl(struct file *file, unsigned int | 5143 | long btrfs_ioctl(struct file *file, unsigned int |
| 5143 | cmd, unsigned long arg) | 5144 | cmd, unsigned long arg) |
| @@ -5294,10 +5295,8 @@ long btrfs_ioctl(struct file *file, unsigned int · 150 unmodified lines | |||
| 5294 | #endif | 5295 | #endif |
| 5295 | case BTRFS_IOC_SUBVOL_SYNC_WAIT: | 5296 | case BTRFS_IOC_SUBVOL_SYNC_WAIT: |
| 5296 | return btrfs_ioctl_subvol_sync(fs_info, argp); | 5297 | return btrfs_ioctl_subvol_sync(fs_info, argp); |
| 5297 | #ifdef CONFIG_BTRFS_EXPERIMENTAL | ||
| 5298 | case BTRFS_IOC_SHUTDOWN: | 5298 | case BTRFS_IOC_SHUTDOWN: |
| 5299 | return btrfs_ioctl_shutdown(fs_info, arg); | 5299 | return btrfs_ioctl_shutdown(fs_info, arg); |
| 5300 | #endif | ||
| 5301 | } | 5300 | } |
| 5302 | 5301 | ||
| 5303 | return -ENOTTY; | 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 | for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { | 46 | for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { |
| 47 | struct btrfs_raid_stride *stride = &extent->strides[i]; | 47 | struct btrfs_raid_stride *stride = &extent->strides[i]; |
| 48 | u64 devid; | ||
| 48 | u64 phys; | 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 | phys = btrfs_raid_stride_physical(leaf, stride) + frontpad; | 53 | phys = btrfs_raid_stride_physical(leaf, stride) + frontpad; |
| 51 | btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys); | 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 | while (1) { | 98 | while (1) { |
| 96 | key.objectid = start; | 99 | key.objectid = start; |
| 97 | key.type = BTRFS_RAID_STRIPE_KEY; | 100 | key.type = BTRFS_RAID_STRIPE_KEY; |
| 98 | key.offset = 0; | 101 | key.offset = (u64)-1; |
| 99 | 102 | ||
| 100 | ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1); | 103 | ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1); |
| 101 | if (ret < 0) | 104 | if (ret < 0) |
| 102 | break; | 105 | break; |
| 103 | 106 | ||
| 104 | if (path->slots[0] == btrfs_header_nritems(path->nodes[0])) | 107 | /* |
| 105 | path->slots[0]--; | 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 | leaf = path->nodes[0]; | 122 | leaf = path->nodes[0]; |
| 108 | slot = path->slots[0]; | 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 | if (found_start > start) { | 139 | if (found_start > start) { |
| 125 | if (slot == 0) { | 140 | if (slot == 0) { |
| 126 | ret = btrfs_previous_item(stripe_root, path, start, | 141 | ret = btrfs_previous_item(stripe_root, path, 0, |
| 127 | BTRFS_RAID_STRIPE_KEY); | 142 | BTRFS_RAID_STRIPE_KEY); |
| 128 | if (ret) { | 143 | if (ret) { |
| 129 | if (ret > 0) | 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 | btrfs_item_key_to_cpu(leaf, &key, slot); | 154 | btrfs_item_key_to_cpu(leaf, &key, slot); |
| 140 | found_start = key.objectid; | 155 | found_start = key.objectid; |
| 141 | found_end = found_start + key.offset; | 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 | if (key.type != BTRFS_RAID_STRIPE_KEY) | 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 | /* The "right" item. */ | 195 | /* The "right" item. */ |
| 178 | ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); | 196 | ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); |
| 197 | if (ret == -EAGAIN) { | ||
| 198 | btrfs_release_path(path); | ||
| 199 | continue; | ||
| 200 | } | ||
| 179 | if (ret) | 201 | if (ret) |
| 180 | break; | 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 | item_size = btrfs_item_size(leaf, path->slots[0]); | 210 | item_size = btrfs_item_size(leaf, path->slots[0]); |
| 183 | extent = btrfs_item_ptr(leaf, path->slots[0], | 211 | extent = btrfs_item_ptr(leaf, path->slots[0], |
| 184 | struct btrfs_stripe_extent); | 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 | /* The "left" item. */ | 223 | /* The "left" item. */ |
| 196 | path->slots[0]--; | 224 | path->slots[0]--; |
| 197 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | 225 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); |
| 198 | btrfs_partially_delete_raid_extent(trans, path, &key, | 226 | ret = btrfs_partially_delete_raid_extent(trans, path, |
| 199 | diff_start, 0); | 227 | &key, |
| 228 | diff_start, 0); | ||
| 200 | break; | 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 | if (found_start < start) { | 241 | if (found_start < start) { |
| 213 | u64 diff_start = start - found_start; | 242 | u64 diff_start = start - found_start; |
| 214 | 243 | ||
| 215 | btrfs_partially_delete_raid_extent(trans, path, &key, | 244 | ret = btrfs_partially_delete_raid_extent(trans, path, |
| 216 | diff_start, 0); | 245 | &key, |
| 246 | diff_start, 0); | ||
| 247 | if (ret) | ||
| 248 | break; | ||
| 217 | 249 | ||
| 218 | start += (key.offset - diff_start); | 250 | start += (key.offset - diff_start); |
| 219 | length -= (key.offset - diff_start); | 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 | if (found_end > end) { | 268 | if (found_end > end) { |
| 237 | u64 diff_end = found_end - end; | 269 | u64 diff_end = found_end - end; |
| 238 | 270 | ||
| 239 | btrfs_partially_delete_raid_extent(trans, path, &key, | 271 | ret = btrfs_partially_delete_raid_extent(trans, path, |
| 240 | key.offset - length, | 272 | &key, |
| 241 | length); | 273 | key.offset - length, |
| 274 | length); | ||
| 242 | ASSERT(key.offset - diff_end == length); | 275 | ASSERT(key.offset - diff_end == length); |
| 243 | break; | 276 | break; |
| 244 | } | 277 | } |
| @@ -2607,7 +2607,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, · 2606 unmodified lines | |||
| 2607 | if (!block->key_ready) | 2607 | if (!block->key_ready) |
| 2608 | btrfs_readahead_tree_block(fs_info, block->bytenr, | 2608 | btrfs_readahead_tree_block(fs_info, block->bytenr, |
| 2609 | block->owner, 0, | 2609 | block->owner, 0, |
| 2610 | block->level); | 2610 | block->level, NULL); |
| 2611 | } | 2611 | } |
| 2612 | 2612 | ||
| 2613 | /* Get first keys */ | 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 | ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch); | 3876 | ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch); |
| 3877 | btrfs_release_path(path); | 3877 | btrfs_release_path(path); |
| 3878 | 3878 | ||
| 3879 | if (num_entries <= max_items) | 3879 | if (ret || num_entries <= max_items) |
| 3880 | break; | 3880 | break; |
| 3881 | 3881 | ||
| 3882 | num_entries -= max_items; | 3882 | num_entries -= max_items; |
| @@ -4174,6 +4174,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info, · 291 unmodified lines | |||
| 4174 | return ret; | 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 | dest_addr = ins.objectid; | 4183 | dest_addr = ins.objectid; |
| 4178 | dest_length = ins.offset; | 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 | return ret; | 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 | made_reservation = true; | 5015 | made_reservation = true; |
| 5004 | 5016 | ||
| 5005 | new_addr = ins.objectid; | 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 | if (bg_needs_free_space) { | 5036 | if (bg_needs_free_space) { |
| 5025 | ret = btrfs_add_block_group_free_space(trans, dest_bg); | 5037 | ret = btrfs_add_block_group_free_space(trans, dest_bg); |
| 5026 | if (ret) | 5038 | if (ret) { |
| 5039 | btrfs_abort_transaction(trans, ret); | ||
| 5027 | goto fail; | 5040 | goto fail; |
| 5041 | } | ||
| 5028 | } | 5042 | } |
| 5029 | 5043 | ||
| 5030 | ret = copy_remapped_data(fs_info, start, new_addr, length); | 5044 | ret = copy_remapped_data(fs_info, start, new_addr, length); |
| 5031 | if (ret) | 5045 | if (ret) { |
| 5046 | btrfs_abort_transaction(trans, ret); | ||
| 5032 | goto fail; | 5047 | goto fail; |
| 5048 | } | ||
| 5033 | 5049 | ||
| 5034 | ret = btrfs_remove_from_free_space_tree(trans, new_addr, length); | 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 | goto fail; | 5053 | goto fail; |
| 5054 | } | ||
| 5037 | 5055 | ||
| 5038 | ret = add_remap_entry(trans, path, src_bg, start, new_addr, length); | 5056 | ret = add_remap_entry(trans, path, src_bg, start, new_addr, length); |
| 5039 | if (ret) { | 5057 | if (ret) { |
| 5040 | btrfs_add_to_free_space_tree(trans, new_addr, length); | 5058 | btrfs_abort_transaction(trans, ret); |
| 5041 | goto fail; | 5059 | goto fail; |
| 5042 | } | 5060 | } |
| 5043 | 5061 | ||
| @@ -24,7 +24,7 @@ isofs_export_iget(struct super_block *sb, · 23 unmodified lines | |||
| 24 | { | 24 | { |
| 25 | struct inode *inode; | 25 | struct inode *inode; |
| 26 | 26 | ||
| 27 | if (block == 0) | 27 | if (block == 0 || block >= ISOFS_SB(sb)->s_nzones) |
| 28 | return ERR_PTR(-ESTALE); | 28 | return ERR_PTR(-ESTALE); |
| 29 | inode = isofs_iget(sb, block, offset); | 29 | inode = isofs_iget(sb, block, offset); |
| 30 | if (IS_ERR(inode)) | 30 | if (IS_ERR(inode)) |
| @@ -10,20 +10,13 @@ · 9 unmodified lines | |||
| 10 | #include <linux/gfp.h> | 10 | #include <linux/gfp.h> |
| 11 | #include "isofs.h" | 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 | static int | 13 | static int |
| 19 | isofs_cmp(struct dentry *dentry, const char *compare, int dlen) | 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 | if (likely(!dentry->d_op)) | 16 | if (likely(!dentry->d_op)) |
| 25 | return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen); | 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 | goto out; | 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 | if (rs->cont_extent) { | 113 | if (rs->cont_extent) { |
| 105 | struct buffer_head *bh; | 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 | * Unlike file_handle, type and len of struct fanotify_fh are u8. | 458 | * Unlike file_handle, type and len of struct fanotify_fh are u8. |
| 459 | * Traditionally, filesystem return handle_type < 0xff, but there | 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 | BUILD_BUG_ON(MAX_HANDLE_SZ > 0xff || FILEID_INVALID > 0xff); | 462 | BUILD_BUG_ON(MAX_HANDLE_SZ > 0xff || FILEID_INVALID > 0xff); |
| 463 | if (type <= 0 || type >= FILEID_INVALID || fh_len != dwords << 2) | 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 | return hlist_entry_safe(node, struct fsnotify_mark, obj_list); | 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 | struct hlist_node *node = NULL; | 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 | return inode; | 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 | u32 new_mask = 0; | 248 | u32 new_mask = 0; |
| 244 | bool want_iref = false; | 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 | WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask); | 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 | return fsnotify_update_iref(conn, want_iref); | 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 | spin_lock(&conn->lock); | 332 | spin_lock(&conn->lock); |
| 300 | update_children = !fsnotify_conn_watches_children(conn); | 333 | update_children = !fsnotify_conn_watches_children(conn); |
| 301 | __fsnotify_recalc_mask(conn); | 334 | fsnotify_recalc_mask_set_iref(conn); |
| 302 | update_children &= fsnotify_conn_watches_children(conn); | 335 | update_children &= fsnotify_conn_watches_children(conn); |
| 303 | spin_unlock(&conn->lock); | 336 | spin_unlock(&conn->lock); |
| 304 | /* | 337 | /* |
| @@ -419,7 +452,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) · 114 unmodified lines | |||
| 419 | /* Update watched objects after detaching mark */ | 452 | /* Update watched objects after detaching mark */ |
| 420 | if (sb) | 453 | if (sb) |
| 421 | fsnotify_update_sb_watchers(sb, conn); | 454 | fsnotify_update_sb_watchers(sb, conn); |
| 422 | objp = __fsnotify_recalc_mask(conn); | 455 | objp = fsnotify_recalc_mask_clear_iref(conn); |
| 423 | type = conn->type; | 456 | type = conn->type; |
| 424 | } | 457 | } |
| 425 | WRITE_ONCE(mark->connector, NULL); | 458 | WRITE_ONCE(mark->connector, NULL); |
| @@ -457,9 +490,6 @@ EXPORT_SYMBOL_GPL(fsnotify_put_mark); · 31 unmodified lines | |||
| 457 | */ | 490 | */ |
| 458 | static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) | 491 | static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) |
| 459 | { | 492 | { |
| 460 | if (!mark) | ||
| 461 | return true; | ||
| 462 | |||
| 463 | if (refcount_inc_not_zero(&mark->refcnt)) { | 493 | if (refcount_inc_not_zero(&mark->refcnt)) { |
| 464 | spin_lock(&mark->lock); | 494 | spin_lock(&mark->lock); |
| 465 | if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) { | 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 | int type; | 530 | int type; |
| 501 | 531 | ||
| 502 | fsnotify_foreach_iter_type(type) { | 532 | fsnotify_foreach_iter_type(type) { |
| 533 | struct fsnotify_mark *mark = iter_info->marks[type]; | ||
| 534 | |||
| 503 | /* This can fail if mark is being removed */ | 535 | /* This can fail if mark is being removed */ |
| 504 | if (!fsnotify_get_mark_safe(iter_info->marks[type])) { | 536 | while (mark && !fsnotify_get_mark_safe(mark)) { |
| 505 | __release(&fsnotify_mark_srcu); | 537 | if (mark->group == iter_info->current_group) { |
| 506 | goto fail; | 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 | * lists, we can drop SRCU lock, and safely resume the list iteration | 549 | * lists, we can drop SRCU lock, and safely resume the list iteration |
| 513 | * once userspace returns. | 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 | struct address_space *mapping; | 125 | struct address_space *mapping; |
| 126 | struct folio *folio; | 126 | struct folio *folio; |
| 127 | u8 *kaddr; | 127 | u8 *kaddr; |
| 128 | int pos, len; | 128 | int pos, len, err; |
| 129 | u8 bit; | 129 | u8 bit; |
| 130 | struct ntfs_inode *ni = NTFS_I(vi); | 130 | struct ntfs_inode *ni = NTFS_I(vi); |
| 131 | struct ntfs_volume *vol = ni->vol; | 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 | /* If we are not in the last page, deal with all subsequent pages. */ | 202 | /* If we are not in the last page, deal with all subsequent pages. */ |
| 203 | while (index < end_index) { | 203 | while (index < end_index) { |
| 204 | if (cnt <= 0) | 204 | if (cnt <= 0) { |
| 205 | err = -EIO; | ||
| 205 | goto rollback; | 206 | goto rollback; |
| 207 | } | ||
| 206 | 208 | ||
| 207 | /* Update @index and get the next folio. */ | 209 | /* Update @index and get the next folio. */ |
| 208 | folio_mark_dirty(folio); | 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 | ntfs_error(vi->i_sb, | 216 | ntfs_error(vi->i_sb, |
| 215 | "Failed to map subsequent page (error %li), aborting.", | 217 | "Failed to map subsequent page (error %li), aborting.", |
| 216 | PTR_ERR(folio)); | 218 | PTR_ERR(folio)); |
| 219 | err = PTR_ERR(folio); | ||
| 217 | goto rollback; | 220 | goto rollback; |
| 218 | } | 221 | } |
| 219 | 222 | ||
| @@ -265,7 +268,7 @@ rollback: · 45 unmodified lines | |||
| 265 | * - @count - @cnt is the number of bits that have been modified | 268 | * - @count - @cnt is the number of bits that have been modified |
| 266 | */ | 269 | */ |
| 267 | if (is_rollback) | 270 | if (is_rollback) |
| 268 | return PTR_ERR(folio); | 271 | return err; |
| 269 | if (count != cnt) | 272 | if (count != cnt) |
| 270 | pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt, | 273 | pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt, |
| 271 | value ? 0 : 1, true); | 274 | value ? 0 : 1, true); |
| @@ -274,14 +277,14 @@ rollback: · 2 unmodified lines | |||
| 274 | if (!pos) { | 277 | if (!pos) { |
| 275 | /* Rollback was successful. */ | 278 | /* Rollback was successful. */ |
| 276 | ntfs_error(vi->i_sb, | 279 | ntfs_error(vi->i_sb, |
| 277 | "Failed to map subsequent page (error %li), aborting.", | 280 | "Failed to map subsequent page (error %i), aborting.", |
| 278 | PTR_ERR(folio)); | 281 | err); |
| 279 | } else { | 282 | } else { |
| 280 | /* Rollback failed. */ | 283 | /* Rollback failed. */ |
| 281 | ntfs_error(vi->i_sb, | 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.", | 285 | "Failed to map subsequent page (error %i) and rollback failed (error %i). Aborting and leaving inconsistent metadata. Unmount and run chkdsk.", |
| 283 | PTR_ERR(folio), pos); | 286 | err, pos); |
| 284 | NVolSetErrors(NTFS_SB(vi->i_sb)); | 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 | if (next->flags & INDEX_ENTRY_NODE) { | 912 | if (next->flags & INDEX_ENTRY_NODE) { |
| 913 | next = ntfs_index_walk_down(next, ictx); | 913 | next = ntfs_index_walk_down(next, ictx); |
| 914 | if (!next) { | 914 | if (IS_ERR(next)) { |
| 915 | err = -EIO; | 915 | err = PTR_ERR(next); |
| 916 | goto out; | 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 | if (next && !(next->flags & INDEX_ENTRY_END)) | 920 | if (next && !(next->flags & INDEX_ENTRY_END)) |
| 921 | goto nextdir; | 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 | nextdir: | 931 | nextdir: |
| 925 | /* Check the consistency of an index entry */ | 932 | /* Check the consistency of an index entry */ |
| 926 | if (ntfs_index_entry_inconsistent(ictx, vol, next, COLLATION_FILE_NAME, | 933 | if (ntfs_index_entry_inconsistent(ictx, vol, next, COLLATION_FILE_NAME, |
| @@ -1969,15 +1969,19 @@ err_out: · 1968 unmodified lines | |||
| 1969 | struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_index_context *ictx) | 1969 | struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_index_context *ictx) |
| 1970 | { | 1970 | { |
| 1971 | struct index_entry *entry; | 1971 | struct index_entry *entry; |
| 1972 | struct index_block *ib; | ||
| 1972 | s64 vcn; | 1973 | s64 vcn; |
| 1973 | 1974 | ||
| 1974 | entry = ie; | 1975 | entry = ie; |
| 1975 | do { | 1976 | do { |
| 1976 | vcn = ntfs_ie_get_vcn(entry); | 1977 | vcn = ntfs_ie_get_vcn(entry); |
| 1977 | if (ictx->is_in_root) { | 1978 | if (ictx->is_in_root) { |
| 1979 | ib = kvzalloc(ictx->block_size, GFP_NOFS); | ||
| 1980 | if (!ib) | ||
| 1981 | return ERR_PTR(-ENOMEM); | ||
| 1978 | /* down from level zero */ | 1982 | /* down from level zero */ |
| 1979 | ictx->ir = NULL; | 1983 | ictx->ir = NULL; |
| 1980 | ictx->ib = kvzalloc(ictx->block_size, GFP_NOFS); | 1984 | ictx->ib = ib; |
| 1981 | ictx->pindex = 1; | 1985 | ictx->pindex = 1; |
| 1982 | ictx->is_in_root = false; | 1986 | ictx->is_in_root = false; |
| 1983 | } else { | 1987 | } else { |
| @@ -1991,8 +1995,8 @@ struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_ind · 7 unmodified lines | |||
| 1991 | ictx->entry = ntfs_ie_get_first(&ictx->ib->index); | 1995 | ictx->entry = ntfs_ie_get_first(&ictx->ib->index); |
| 1992 | entry = ictx->entry; | 1996 | entry = ictx->entry; |
| 1993 | } else | 1997 | } else |
| 1994 | entry = NULL; | 1998 | entry = ERR_PTR(-EIO); |
| 1995 | } while (entry && (entry->flags & INDEX_ENTRY_NODE)); | 1999 | } while (!IS_ERR(entry) && (entry->flags & INDEX_ENTRY_NODE)); |
| 1996 | 2000 | ||
| 1997 | return entry; | 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 | /* walk down if it has a subnode */ | 2102 | /* walk down if it has a subnode */ |
| 2099 | if (flags & INDEX_ENTRY_NODE) { | 2103 | if (flags & INDEX_ENTRY_NODE) { |
| 2100 | if (!ictx->ia_ni) | 2104 | if (!ictx->ia_ni) { |
| 2101 | ictx->ia_ni = ntfs_ia_open(ictx, ictx->idx_ni); | 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 | next = ntfs_index_walk_down(next, ictx); | 2110 | next = ntfs_index_walk_down(next, ictx); |
| 2111 | if (IS_ERR(next)) | ||
| 2112 | return next; | ||
| 2104 | } else { | 2113 | } else { |
| 2105 | 2114 | ||
| 2106 | /* walk up it has no subnode, nor data */ | 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 | ctx = ntfs_attr_get_search_ctx(ni, NULL); | 788 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 789 | if (!ctx) { | 789 | if (!ctx) { |
| 790 | written = -ENOMEM; | 790 | written = -ENOMEM; |
| 791 | mutex_unlock(&ni->mrec_lock); | 791 | goto err_out; |
| 792 | return written; | ||
| 793 | } | 792 | } |
| 794 | 793 | ||
| 795 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 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 | memcpy(kattr + pos, iomap_inline_data(iomap, pos), written); | 809 | memcpy(kattr + pos, iomap_inline_data(iomap, pos), written); |
| 811 | mark_mft_record_dirty(ctx->ntfs_ino); | 810 | mark_mft_record_dirty(ctx->ntfs_ino); |
| 812 | err_out: | 811 | err_out: |
| 813 | ntfs_attr_put_search_ctx(ctx); | 812 | if (ctx) |
| 813 | ntfs_attr_put_search_ctx(ctx); | ||
| 814 | put_page(ipage); | 814 | put_page(ipage); |
| 815 | mutex_unlock(&ni->mrec_lock); | 815 | mutex_unlock(&ni->mrec_lock); |
| 816 | return written; | 816 | return written; |
| @@ -945,7 +945,8 @@ search: · 944 unmodified lines | |||
| 945 | 945 | ||
| 946 | ni_mrec = actx->base_mrec ? actx->base_mrec : actx->mrec; | 946 | ni_mrec = actx->base_mrec ? actx->base_mrec : actx->mrec; |
| 947 | ni_mrec->link_count = cpu_to_le16(le16_to_cpu(ni_mrec->link_count) - 1); | 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 | mark_mft_record_dirty(ni); | 951 | mark_mft_record_dirty(ni); |
| 951 | if (looking_for_dos_name) { | 952 | if (looking_for_dos_name) { |
| @@ -955,6 +956,13 @@ search: · 3 unmodified lines | |||
| 955 | goto search; | 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 | * If hard link count is not equal to zero then we are done. In other | 967 | * If hard link count is not equal to zero then we are done. In other |
| 960 | * case there are no reference to this inode left, so we should free all | 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 | /* Increment hard links count. */ | 1230 | /* Increment hard links count. */ |
| 1223 | ni_mrec->link_count = cpu_to_le16(le16_to_cpu(ni_mrec->link_count) + 1); | 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 | /* Done! */ | 1235 | /* Done! */ |
| 1227 | mark_mft_record_dirty(ni); | 1236 | mark_mft_record_dirty(ni); |
| @@ -505,7 +505,6 @@ int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, · 504 unmodified lines | |||
| 505 | struct reparse_point *reparse; | 505 | struct reparse_point *reparse; |
| 506 | struct wsl_link_reparse_data *data; | 506 | struct wsl_link_reparse_data *data; |
| 507 | 507 | ||
| 508 | utarget = (char *)NULL; | ||
| 509 | len = ntfs_ucstonls(ni->vol, target, target_len, &utarget, 0); | 508 | len = ntfs_ucstonls(ni->vol, target, target_len, &utarget, 0); |
| 510 | if (len <= 0) | 509 | if (len <= 0) |
| 511 | return -EINVAL; | 510 | return -EINVAL; |
| @@ -514,7 +513,7 @@ int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, · 2 unmodified lines | |||
| 514 | reparse = kvzalloc(reparse_len, GFP_NOFS); | 513 | reparse = kvzalloc(reparse_len, GFP_NOFS); |
| 515 | if (!reparse) { | 514 | if (!reparse) { |
| 516 | err = -ENOMEM; | 515 | err = -ENOMEM; |
| 517 | kvfree(utarget); | 516 | kfree(utarget); |
| 518 | } else { | 517 | } else { |
| 519 | data = (struct wsl_link_reparse_data *)reparse->reparse_data; | 518 | data = (struct wsl_link_reparse_data *)reparse->reparse_data; |
| 520 | reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; | 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 | kvfree(reparse); | 527 | kvfree(reparse); |
| 529 | if (!err) | 528 | if (!err) |
| 530 | ni->target = utarget; | 529 | ni->target = utarget; |
| 530 | else | ||
| 531 | kfree(utarget); | ||
| 531 | } | 532 | } |
| 532 | return err; | 533 | return err; |
| 533 | } | 534 | } |
| @@ -15,6 +15,8 @@ · 14 unmodified lines | |||
| 15 | * Copyright (c) 2007-2022 Jean-Pierre Andre | 15 | * Copyright (c) 2007-2022 Jean-Pierre Andre |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/overflow.h> | ||
| 19 | |||
| 18 | #include "ntfs.h" | 20 | #include "ntfs.h" |
| 19 | #include "attrib.h" | 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 | int rlsize; /* Size of runlist buffer. */ | 741 | int rlsize; /* Size of runlist buffer. */ |
| 740 | u16 rlpos; /* Current runlist position in units of struct runlist_elements. */ | 742 | u16 rlpos; /* Current runlist position in units of struct runlist_elements. */ |
| 741 | u8 b; /* Current byte offset in buf. */ | 743 | u8 b; /* Current byte offset in buf. */ |
| 744 | u64 lowest_vcn; /* Raw on-disk lowest_vcn. */ | ||
| 742 | 745 | ||
| 743 | #ifdef DEBUG | 746 | #ifdef DEBUG |
| 744 | /* Make sure attr exists and is non-resident. */ | 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 | return ERR_PTR(-EINVAL); | 750 | return ERR_PTR(-EINVAL); |
| 748 | } | 751 | } |
| 749 | #endif | 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 | /* Start at vcn = lowest_vcn and lcn 0. */ | 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 | lcn = 0; | 761 | lcn = 0; |
| 753 | /* Get start of the mapping pairs array. */ | 762 | /* Get start of the mapping pairs array. */ |
| 754 | buf = (u8 *)attr + | 763 | buf = (u8 *)attr + |
| @@ -823,8 +832,17 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume * · 68 unmodified lines | |||
| 823 | * element. | 832 | * element. |
| 824 | */ | 833 | */ |
| 825 | rl[rlpos].length = deltaxcn; | 834 | rl[rlpos].length = deltaxcn; |
| 826 | /* Increment the current vcn by the current run length. */ | 835 | /* |
| 827 | vcn += deltaxcn; | 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 | * There might be no lcn change at all, as is the case for | 847 | * There might be no lcn change at all, as is the case for |
| 830 | * sparse clusters on NTFS 3.0+, in which case we set the lcn | 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 | struct mid_q_entry *mid); | 89 | struct mid_q_entry *mid); |
| 90 | char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep); | 90 | char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep); |
| 91 | int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); | 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 | int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); | 92 | int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); |
| 94 | bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); | 93 | bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); |
| 95 | int cifs_discard_remaining_data(struct TCP_Server_Info *server); | 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 | return 0; | 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 | * Remove duplicate path delimiters. Windows is supposed to do that | 540 | * Remove duplicate path delimiters. Windows is supposed to do that |
| 572 | * but there are some bugs that prevent rename from working if there are | 541 | * but there are some bugs that prevent rename from working if there are |
| @@ -230,7 +230,7 @@ replay_again: · 229 unmodified lines | |||
| 230 | num_rqst = 0; | 230 | num_rqst = 0; |
| 231 | server = cifs_pick_channel(ses); | 231 | server = cifs_pick_channel(ses); |
| 232 | 232 | ||
| 233 | vars = kzalloc_obj(*vars, GFP_ATOMIC); | 233 | vars = kzalloc_obj(*vars, GFP_KERNEL); |
| 234 | if (vars == NULL) { | 234 | if (vars == NULL) { |
| 235 | rc = -ENOMEM; | 235 | rc = -ENOMEM; |
| 236 | goto out; | 236 | goto out; |
| @@ -111,10 +111,21 @@ smb2_add_credits(struct TCP_Server_Info *server, · 110 unmodified lines | |||
| 111 | cifs_trace_rw_credits_zero_in_flight); | 111 | cifs_trace_rw_credits_zero_in_flight); |
| 112 | } | 112 | } |
| 113 | server->in_flight--; | 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 | if (server->in_flight == 0 && | 122 | if (server->in_flight == 0 && |
| 115 | ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) && | 123 | ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) && |
| 116 | ((optype & CIFS_OP_MASK) != CIFS_SESS_OP)) | 124 | ((optype & CIFS_OP_MASK) != CIFS_SESS_OP)) |
| 117 | rc = change_conf(server); | 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 | * Sometimes server returns 0 credits on oplock break ack - we need to | 130 | * Sometimes server returns 0 credits on oplock break ack - we need to |
| 120 | * rebalance credits in this case. | 131 | * rebalance credits in this case. |
| @@ -540,24 +540,54 @@ out: · 539 unmodified lines | |||
| 540 | 540 | ||
| 541 | static void stop_sessions(void) | 541 | static void stop_sessions(void) |
| 542 | { | 542 | { |
| 543 | struct ksmbd_conn *conn; | 543 | struct ksmbd_conn *conn, *target; |
| 544 | struct ksmbd_transport *t; | 544 | struct ksmbd_transport *t; |
| 545 | bool any; | ||
| 545 | int bkt; | 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 | again: | 553 | again: |
| 554 | target = NULL; | ||
| 555 | any = false; | ||
| 548 | down_read(&conn_list_lock); | 556 | down_read(&conn_list_lock); |
| 549 | hash_for_each(conn_list, bkt, conn, hlist) { | 557 | hash_for_each(conn_list, bkt, conn, hlist) { |
| 550 | t = conn->transport; | 558 | any = true; |
| 551 | ksmbd_conn_set_exiting(conn); | 559 | if (conn->stop_called) |
| 552 | if (t->ops->shutdown) { | 560 | continue; |
| 553 | up_read(&conn_list_lock); | 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 | t->ops->shutdown(t); | 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 | msleep(100); | 591 | msleep(100); |
| 562 | goto again; | 592 | goto again; |
| 563 | } | 593 | } |
| @@ -49,6 +49,7 @@ struct ksmbd_conn { · 48 unmodified lines | |||
| 49 | struct mutex srv_mutex; | 49 | struct mutex srv_mutex; |
| 50 | int status; | 50 | int status; |
| 51 | unsigned int cli_cap; | 51 | unsigned int cli_cap; |
| 52 | bool stop_called; | ||
| 52 | union { | 53 | union { |
| 53 | __be32 inet_addr; | 54 | __be32 inet_addr; |
| 54 | #if IS_ENABLED(CONFIG_IPV6) | 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 | goto free_conv_name; | 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 | next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT); | 3956 | next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT); |
| 3951 | d_info->last_entry_off_align = next_entry_offset - struct_sz; | 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 | /* Verify the descriptor CRC */ | 232 | /* Verify the descriptor CRC */ |
| 233 | if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize || | 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, | 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 | bh->b_data + sizeof(struct tag), | 239 | bh->b_data + sizeof(struct tag), |
| 236 | le16_to_cpu(tag_p->descCRCLength))) | 240 | le16_to_cpu(tag_p->descCRCLength))) |
| 237 | return bh; | 241 | return bh; |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | |||
| 17 | #include <linux/property.h> | 17 | #include <linux/property.h> |
| 18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 19 | 19 | ||
| 20 | struct notifier_block; | ||
| 21 | |||
| 20 | struct acpi_handle_list { | 22 | struct acpi_handle_list { |
| 21 | u32 count; | 23 | u32 count; |
| 22 | acpi_handle *handles; | 24 | acpi_handle *handles; |
| @@ -1386,6 +1386,12 @@ enum acpi_einj_command_status { · 1385 unmodified lines | |||
| 1386 | #define ACPI_EINJ_CXL_MEM_FATAL (1<<17) | 1386 | #define ACPI_EINJ_CXL_MEM_FATAL (1<<17) |
| 1387 | #define ACPI_EINJ_VENDOR_DEFINED (1<<31) | 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 | * ERST - Error Record Serialization Table (ACPI 4.0) | 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 | int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); | 273 | int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); |
| 274 | bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper, | 274 | bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper, |
| 275 | const struct drm_gem_object *obj); | 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 | #endif | 282 | #endif |
| 277 | 283 | ||
| 278 | #endif | 284 | #endif |
| @@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, · 107 unmodified lines | |||
| 108 | extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, | 108 | extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, |
| 109 | unsigned int clearing); | 109 | unsigned int clearing); |
| 110 | 110 | ||
| 111 | extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); | ||
| 111 | extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); | 112 | extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); |
| 112 | extern void unregister_cdrom(struct cdrom_device_info *cdi); | 113 | extern void unregister_cdrom(struct cdrom_device_info *cdi); |
| 113 | 114 | ||
| @@ -322,13 +322,13 @@ struct dma_buf { · 321 unmodified lines | |||
| 322 | * @vmapping_counter: | 322 | * @vmapping_counter: |
| 323 | * | 323 | * |
| 324 | * Used internally to refcnt the vmaps returned by dma_buf_vmap(). | 324 | * Used internally to refcnt the vmaps returned by dma_buf_vmap(). |
| 325 | * Protected by @lock. | 325 | * Protected by @resv. |
| 326 | */ | 326 | */ |
| 327 | unsigned vmapping_counter; | 327 | unsigned vmapping_counter; |
| 328 | 328 | ||
| 329 | /** | 329 | /** |
| 330 | * @vmap_ptr: | 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 | struct iosys_map vmap_ptr; | 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 | int dpll_device_change_ntf(struct dpll_device *dpll); | 287 | int dpll_device_change_ntf(struct dpll_device *dpll); |
| 288 | 288 | ||
| 289 | int __dpll_pin_change_ntf(struct dpll_pin *pin); | ||
| 289 | int dpll_pin_change_ntf(struct dpll_pin *pin); | 290 | int dpll_pin_change_ntf(struct dpll_pin *pin); |
| 290 | 291 | ||
| 291 | int register_dpll_notifier(struct notifier_block *nb); | 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 | unsigned int obj_type); | 915 | unsigned int obj_type); |
| 916 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); | 916 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); |
| 917 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); | 917 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); |
| 918 | struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark); | ||
| 918 | extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); | 919 | extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); |
| 919 | extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); | 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 | int mbox_flush(struct mbox_chan *chan, unsigned long timeout); | 45 | int mbox_flush(struct mbox_chan *chan, unsigned long timeout); |
| 46 | void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */ | 46 | void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */ |
| 47 | bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */ | 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 | void mbox_free_channel(struct mbox_chan *chan); /* may sleep */ | 49 | void mbox_free_channel(struct mbox_chan *chan); /* may sleep */ |
| 49 | 50 | ||
| 50 | #endif /* __MAILBOX_CLIENT_H */ | 51 | #endif /* __MAILBOX_CLIENT_H */ |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | |||
| 3 | #ifndef __MAILBOX_CONTROLLER_H | 3 | #ifndef __MAILBOX_CONTROLLER_H |
| 4 | #define __MAILBOX_CONTROLLER_H | 4 | #define __MAILBOX_CONTROLLER_H |
| 5 | 5 | ||
| 6 | #include <linux/bits.h> | ||
| 6 | #include <linux/completion.h> | 7 | #include <linux/completion.h> |
| 7 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 8 | #include <linux/hrtimer.h> | 9 | #include <linux/hrtimer.h> |
| @@ -11,6 +12,13 @@ · 2 unmodified lines | |||
| 11 | 12 | ||
| 12 | struct mbox_chan; | 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 | * struct mbox_chan_ops - methods to control mailbox channels | 23 | * struct mbox_chan_ops - methods to control mailbox channels |
| 16 | * @send_data: The API asks the MBOX controller driver, in atomic | 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 | * struct mbox_controller - Controller of a class of communication channels | 64 | * struct mbox_controller - Controller of a class of communication channels |
| 57 | * @dev: Device backing this controller | 65 | * @dev: Device backing this controller. Required. |
| 58 | * @ops: Operators that work on each communication chan | 66 | * @ops: Operators that work on each communication chan. Required. |
| 59 | * @chans: Array of channels | 67 | * @chans: Array of channels. Required. |
| 60 | * @num_chans: Number of channels in the 'chans' array. | 68 | * @num_chans: Number of channels in the 'chans' array. Required. |
| 61 | * @txdone_irq: Indicates if the controller can report to API when | 69 | * @txdone_irq: Indicates if the controller can report to API when |
| 62 | * the last transmitted data was read by the remote. | 70 | * the last transmitted data was read by the remote. |
| 63 | * Eg, if it has some TX ACK irq. | 71 | * Eg, if it has some TX ACK irq. |
| @@ -70,6 +78,7 @@ struct mbox_chan_ops { · 6 unmodified lines | |||
| 70 | * @of_xlate: Controller driver specific mapping of channel via DT | 78 | * @of_xlate: Controller driver specific mapping of channel via DT |
| 71 | * @poll_hrt: API private. hrtimer used to poll for TXDONE on all | 79 | * @poll_hrt: API private. hrtimer used to poll for TXDONE on all |
| 72 | * channels. | 80 | * channels. |
| 81 | * @poll_hrt_lock: API private. Lock protecting access to poll_hrt. | ||
| 73 | * @node: API private. To hook into list of controllers. | 82 | * @node: API private. To hook into list of controllers. |
| 74 | */ | 83 | */ |
| 75 | struct mbox_controller { | 84 | struct mbox_controller { |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | |||
| 4 | /* | 4 | /* |
| 5 | * Maple Tree - An RCU-safe adaptive tree for storing ranges | 5 | * Maple Tree - An RCU-safe adaptive tree for storing ranges |
| 6 | * Copyright (c) 2018-2022 Oracle | 6 | * Copyright (c) 2018-2022 Oracle |
| 7 | * Authors: Liam R. Howlett <Liam.Howlett@Oracle.com> | 7 | * Authors: Liam R. Howlett <liam@infradead.org> |
| 8 | * Matthew Wilcox <willy@infradead.org> | 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 | int mmap_action_prepare(struct vm_area_desc *desc); | 4392 | int mmap_action_prepare(struct vm_area_desc *desc); |
| 4393 | int mmap_action_complete(struct vm_area_struct *vma, | 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 | /* Look up the first VMA which exactly match the interval vm_start ... vm_end */ | 4396 | /* Look up the first VMA which exactly match the interval vm_start ... vm_end */ |
| 4397 | static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm, | 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 | * struct mr_table - a multicast routing table | 228 | * struct mr_table - a multicast routing table |
| 229 | * @work: used for table destruction | ||
| 229 | * @list: entry within a list of multicast routing tables | 230 | * @list: entry within a list of multicast routing tables |
| 230 | * @net: net where this table belongs | 231 | * @net: net where this table belongs |
| 231 | * @ops: protocol specific operations | 232 | * @ops: protocol specific operations |
| @@ -243,6 +244,7 @@ struct mr_table_ops { · 11 unmodified lines | |||
| 243 | * @mroute_reg_vif_num: PIM-device vif index | 244 | * @mroute_reg_vif_num: PIM-device vif index |
| 244 | */ | 245 | */ |
| 245 | struct mr_table { | 246 | struct mr_table { |
| 247 | struct rcu_work work; | ||
| 246 | struct list_head list; | 248 | struct list_head list; |
| 247 | possible_net_t net; | 249 | possible_net_t net; |
| 248 | struct mr_table_ops ops; | 250 | struct mr_table_ops ops; |
| @@ -274,6 +276,7 @@ void vif_device_init(struct vif_device *v, · 25 unmodified lines | |||
| 274 | unsigned short flags, | 276 | unsigned short flags, |
| 275 | unsigned short get_iflink_mask); | 277 | unsigned short get_iflink_mask); |
| 276 | 278 | ||
| 279 | void mr_table_free(struct mr_table *mrt); | ||
| 277 | struct mr_table * | 280 | struct mr_table * |
| 278 | mr_table_alloc(struct net *net, u32 id, | 281 | mr_table_alloc(struct net *net, u32 id, |
| 279 | struct mr_table_ops *ops, | 282 | struct mr_table_ops *ops, |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | |||
| 9 | #ifndef __MTD_NAND_QPIC_COMMON_H__ | 9 | #ifndef __MTD_NAND_QPIC_COMMON_H__ |
| 10 | #define __MTD_NAND_QPIC_COMMON_H__ | 10 | #define __MTD_NAND_QPIC_COMMON_H__ |
| 11 | 11 | ||
| 12 | #include <linux/mtd/rawnand.h> | ||
| 13 | |||
| 12 | /* NANDc reg offsets */ | 14 | /* NANDc reg offsets */ |
| 13 | #define NAND_FLASH_CMD 0x00 | 15 | #define NAND_FLASH_CMD 0x00 |
| 14 | #define NAND_ADDR0 0x04 | 16 | #define NAND_ADDR0 0x04 |
| @@ -394,7 +396,7 @@ struct qcom_nand_controller { · 379 unmodified lines | |||
| 394 | 396 | ||
| 395 | const struct qcom_nandc_props *props; | 397 | const struct qcom_nandc_props *props; |
| 396 | 398 | ||
| 397 | struct nand_controller *controller; | 399 | struct nand_controller controller; |
| 398 | struct qpic_spi_nand *qspi; | 400 | struct qpic_spi_nand *qspi; |
| 399 | struct list_head host_list; | 401 | struct list_head host_list; |
| 400 | 402 | ||
| @@ -290,6 +290,12 @@ · 289 unmodified lines | |||
| 290 | SPI_MEM_OP_NO_DUMMY, \ | 290 | SPI_MEM_OP_NO_DUMMY, \ |
| 291 | SPI_MEM_OP_NO_DATA) | 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 | #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ | 299 | #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ |
| 294 | SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ | 300 | SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ |
| 295 | SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ | 301 | SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ |
| @@ -483,6 +489,7 @@ struct spinand_ecc_info { · 187 unmodified lines | |||
| 483 | #define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) | 489 | #define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) |
| 484 | #define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) | 490 | #define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) |
| 485 | #define SPINAND_NO_RAW_ACCESS BIT(4) | 491 | #define SPINAND_NO_RAW_ACCESS BIT(4) |
| 492 | #define SPINAND_ODTR_PACKED_PAGE_READ BIT(5) | ||
| 486 | 493 | ||
| 487 | /** | 494 | /** |
| 488 | * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure | 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 | * @op_variants.read_cache: variants of the read-cache operation | 583 | * @op_variants.read_cache: variants of the read-cache operation |
| 577 | * @op_variants.write_cache: variants of the write-cache operation | 584 | * @op_variants.write_cache: variants of the write-cache operation |
| 578 | * @op_variants.update_cache: variants of the update-cache operation | 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 | * @vendor_ops: vendor specific operations | 587 | * @vendor_ops: vendor specific operations |
| 580 | * @select_target: function used to select a target/die. Required only for | 588 | * @select_target: function used to select a target/die. Required only for |
| 581 | * multi-die chips | 589 | * multi-die chips |
| @@ -585,6 +593,7 @@ enum spinand_bus_interface { · 3 unmodified lines | |||
| 585 | * @user_otp: SPI NAND user OTP info. | 593 | * @user_otp: SPI NAND user OTP info. |
| 586 | * @read_retries: the number of read retry modes supported | 594 | * @read_retries: the number of read retry modes supported |
| 587 | * @set_read_retry: enable/disable read retry for data recovery | 595 | * @set_read_retry: enable/disable read retry for data recovery |
| 596 | * @set_randomizer: enable/disable randomizer support | ||
| 588 | * | 597 | * |
| 589 | * Each SPI NAND manufacturer driver should have a spinand_info table | 598 | * Each SPI NAND manufacturer driver should have a spinand_info table |
| 590 | * describing all the chips supported by the driver. | 599 | * describing all the chips supported by the driver. |
| @@ -600,6 +609,7 @@ struct spinand_info { · 9 unmodified lines | |||
| 600 | const struct spinand_op_variants *read_cache; | 609 | const struct spinand_op_variants *read_cache; |
| 601 | const struct spinand_op_variants *write_cache; | 610 | const struct spinand_op_variants *write_cache; |
| 602 | const struct spinand_op_variants *update_cache; | 611 | const struct spinand_op_variants *update_cache; |
| 612 | const struct spinand_op_variants *cont_read_cache; | ||
| 603 | } op_variants; | 613 | } op_variants; |
| 604 | const struct spinand_op_variants *vendor_ops; | 614 | const struct spinand_op_variants *vendor_ops; |
| 605 | int (*select_target)(struct spinand_device *spinand, | 615 | int (*select_target)(struct spinand_device *spinand, |
| @@ -613,6 +623,8 @@ struct spinand_info { · 7 unmodified lines | |||
| 613 | unsigned int read_retries; | 623 | unsigned int read_retries; |
| 614 | int (*set_read_retry)(struct spinand_device *spinand, | 624 | int (*set_read_retry)(struct spinand_device *spinand, |
| 615 | unsigned int read_retry); | 625 | unsigned int read_retry); |
| 626 | int (*set_randomizer)(struct spinand_device *spinand, | ||
| 627 | bool enable); | ||
| 616 | }; | 628 | }; |
| 617 | 629 | ||
| 618 | #define SPINAND_ID(__method, ...) \ | 630 | #define SPINAND_ID(__method, ...) \ |
| @@ -629,6 +641,14 @@ struct spinand_info { · 10 unmodified lines | |||
| 629 | .update_cache = __update, \ | 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 | #define SPINAND_INFO_VENDOR_OPS(__ops) \ | 652 | #define SPINAND_INFO_VENDOR_OPS(__ops) \ |
| 633 | .vendor_ops = __ops | 653 | .vendor_ops = __ops |
| 634 | 654 | ||
| @@ -669,6 +689,9 @@ struct spinand_info { · 34 unmodified lines | |||
| 669 | .read_retries = __read_retries, \ | 689 | .read_retries = __read_retries, \ |
| 670 | .set_read_retry = __set_read_retry | 690 | .set_read_retry = __set_read_retry |
| 671 | 691 | ||
| 692 | #define SPINAND_RANDOMIZER(__set_randomizer) \ | ||
| 693 | .set_randomizer = __set_randomizer | ||
| 694 | |||
| 672 | #define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \ | 695 | #define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \ |
| 673 | __flags, ...) \ | 696 | __flags, ...) \ |
| 674 | { \ | 697 | { \ |
| @@ -684,8 +707,6 @@ struct spinand_info { · 9 unmodified lines | |||
| 684 | struct spinand_dirmap { | 707 | struct spinand_dirmap { |
| 685 | struct spi_mem_dirmap_desc *wdesc; | 708 | struct spi_mem_dirmap_desc *wdesc; |
| 686 | struct spi_mem_dirmap_desc *rdesc; | 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 | * @read_cache: read cache op template | 723 | * @read_cache: read cache op template |
| 703 | * @write_cache: write cache op template | 724 | * @write_cache: write cache op template |
| 704 | * @update_cache: update cache op template | 725 | * @update_cache: update cache op template |
| 726 | * @cont_read_cache: continuous read cache op template (optional) | ||
| 705 | */ | 727 | */ |
| 706 | struct spinand_mem_ops { | 728 | struct spinand_mem_ops { |
| 707 | struct spi_mem_op reset; | 729 | struct spi_mem_op reset; |
| @@ -716,6 +738,7 @@ struct spinand_mem_ops { · 8 unmodified lines | |||
| 716 | const struct spi_mem_op *read_cache; | 738 | const struct spi_mem_op *read_cache; |
| 717 | const struct spi_mem_op *write_cache; | 739 | const struct spi_mem_op *write_cache; |
| 718 | const struct spi_mem_op *update_cache; | 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 | * @user_otp: SPI NAND user OTP info. | 777 | * @user_otp: SPI NAND user OTP info. |
| 755 | * @read_retries: the number of read retry modes supported | 778 | * @read_retries: the number of read retry modes supported |
| 756 | * @set_read_retry: Enable/disable the read retry feature | 779 | * @set_read_retry: Enable/disable the read retry feature |
| 780 | * @set_randomizer: Enable/disable the randomizer feature | ||
| 757 | */ | 781 | */ |
| 758 | struct spinand_device { | 782 | struct spinand_device { |
| 759 | struct nand_device base; | 783 | struct nand_device base; |
| @@ -787,6 +811,8 @@ struct spinand_device { · 27 unmodified lines | |||
| 787 | bool cont_read_possible; | 811 | bool cont_read_possible; |
| 788 | int (*set_cont_read)(struct spinand_device *spinand, | 812 | int (*set_cont_read)(struct spinand_device *spinand, |
| 789 | bool enable); | 813 | bool enable); |
| 814 | int (*set_randomizer)(struct spinand_device *spinand, | ||
| 815 | bool enable); | ||
| 790 | 816 | ||
| 791 | const struct spinand_fact_otp *fact_otp; | 817 | const struct spinand_fact_otp *fact_otp; |
| 792 | const struct spinand_user_otp *user_otp; | 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 | nanddev_set_of_node(&spinand->base, np); | 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 | int spinand_match_and_init(struct spinand_device *spinand, | 893 | int spinand_match_and_init(struct spinand_device *spinand, |
| 866 | const struct spinand_info *table, | 894 | const struct spinand_info *table, |
| 867 | unsigned int table_size, | 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 | int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid); | 49 | int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid); |
| 50 | int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm, | 50 | int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm, |
| 51 | u8 *host_key, size_t host_key_len); | 51 | u8 *host_key, size_t host_key_len); |
| 52 | int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm, | 52 | int nvme_auth_gen_session_key(struct crypto_kpp *dh_tfm, |
| 53 | const u8 *ctrl_key, size_t ctrl_key_len, | 53 | const u8 *public_key, size_t public_key_len, |
| 54 | u8 *sess_key, size_t sess_key_len); | 54 | u8 *sess_key, size_t sess_key_len, u8 hash_id); |
| 55 | int nvme_auth_generate_psk(u8 hmac_id, const u8 *skey, size_t skey_len, | 55 | int nvme_auth_generate_psk(u8 hmac_id, const u8 *skey, size_t skey_len, |
| 56 | const u8 *c1, const u8 *c2, size_t hash_len, | 56 | const u8 *c1, const u8 *c2, size_t hash_len, |
| 57 | u8 **ret_psk, size_t *ret_len); | 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 | old->prev = LIST_POISON2; | 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 | * __list_splice_init_rcu - join an RCU-protected list into an existing list. | 294 | * __list_splice_init_rcu - join an RCU-protected list into an existing list. |
| 266 | * @list: the RCU-protected list to splice | 295 | * @list: the RCU-protected list to splice |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/alloc_tag.h> | 12 | #include <linux/alloc_tag.h> |
| 13 | #include <linux/atomic.h> | 13 | #include <linux/atomic.h> |
| 14 | #include <linux/compiler.h> | 14 | #include <linux/compiler.h> |
| 15 | #include <linux/irq_work_types.h> | ||
| 15 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
| 16 | #include <linux/workqueue_types.h> | 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 | * @head_offset: Offset of rhash_head in struct to be hashed | 50 | * @head_offset: Offset of rhash_head in struct to be hashed |
| 50 | * @max_size: Maximum size while expanding | 51 | * @max_size: Maximum size while expanding |
| 51 | * @min_size: Minimum size while shrinking | 52 | * @min_size: Minimum size while shrinking |
| 53 | * @insecure_elasticity: Set to true to disable chain length checks | ||
| 52 | * @automatic_shrinking: Enable automatic shrinking of tables | 54 | * @automatic_shrinking: Enable automatic shrinking of tables |
| 53 | * @hashfn: Hash function (default: jhash2 if !(key_len % 4), or jhash) | 55 | * @hashfn: Hash function (default: jhash2 if !(key_len % 4), or jhash) |
| 54 | * @obj_hashfn: Function to hash object | 56 | * @obj_hashfn: Function to hash object |
| @@ -61,6 +63,7 @@ struct rhashtable_params { · 6 unmodified lines | |||
| 61 | u16 head_offset; | 63 | u16 head_offset; |
| 62 | unsigned int max_size; | 64 | unsigned int max_size; |
| 63 | u16 min_size; | 65 | u16 min_size; |
| 66 | bool insecure_elasticity; | ||
| 64 | bool automatic_shrinking; | 67 | bool automatic_shrinking; |
| 65 | rht_hashfn_t hashfn; | 68 | rht_hashfn_t hashfn; |
| 66 | rht_obj_hashfn_t obj_hashfn; | 69 | rht_obj_hashfn_t obj_hashfn; |
| @@ -75,6 +78,7 @@ struct rhashtable_params { · 8 unmodified lines | |||
| 75 | * @p: Configuration parameters | 78 | * @p: Configuration parameters |
| 76 | * @rhlist: True if this is an rhltable | 79 | * @rhlist: True if this is an rhltable |
| 77 | * @run_work: Deferred worker to expand/shrink asynchronously | 80 | * @run_work: Deferred worker to expand/shrink asynchronously |
| 81 | * @run_irq_work: Bounces the @run_work kick through hard IRQ context. | ||
| 78 | * @mutex: Mutex to protect current/future table swapping | 82 | * @mutex: Mutex to protect current/future table swapping |
| 79 | * @lock: Spin lock to protect walker list | 83 | * @lock: Spin lock to protect walker list |
| 80 | * @nelems: Number of elements in table | 84 | * @nelems: Number of elements in table |
| @@ -86,6 +90,7 @@ struct rhashtable { · 5 unmodified lines | |||
| 86 | struct rhashtable_params p; | 90 | struct rhashtable_params p; |
| 87 | bool rhlist; | 91 | bool rhlist; |
| 88 | struct work_struct run_work; | 92 | struct work_struct run_work; |
| 93 | struct irq_work run_irq_work; | ||
| 89 | struct mutex mutex; | 94 | struct mutex mutex; |
| 90 | spinlock_t lock; | 95 | spinlock_t lock; |
| 91 | atomic_t nelems; | 96 | atomic_t nelems; |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
| 22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
| 23 | #include <linux/irq_work.h> | ||
| 23 | #include <linux/jhash.h> | 24 | #include <linux/jhash.h> |
| 24 | #include <linux/list_nulls.h> | 25 | #include <linux/list_nulls.h> |
| 25 | #include <linux/workqueue.h> | 26 | #include <linux/workqueue.h> |
| @@ -821,14 +822,15 @@ slow_path: · 795 unmodified lines | |||
| 821 | goto out; | 822 | goto out; |
| 822 | } | 823 | } |
| 823 | 824 | ||
| 824 | if (elasticity <= 0) | 825 | if (elasticity <= 0 && !params.insecure_elasticity) |
| 825 | goto slow_path; | 826 | goto slow_path; |
| 826 | 827 | ||
| 827 | data = ERR_PTR(-E2BIG); | 828 | data = ERR_PTR(-E2BIG); |
| 828 | if (unlikely(rht_grow_above_max(ht, tbl))) | 829 | if (unlikely(rht_grow_above_max(ht, tbl))) |
| 829 | goto out_unlock; | 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 | goto slow_path; | 834 | goto slow_path; |
| 833 | 835 | ||
| 834 | /* Inserting at head of list makes unlocking free. */ | 836 | /* Inserting at head of list makes unlocking free. */ |
| @@ -846,7 +848,7 @@ slow_path: · 11 unmodified lines | |||
| 846 | rht_assign_unlock(tbl, bkt, obj, flags); | 848 | rht_assign_unlock(tbl, bkt, obj, flags); |
| 847 | 849 | ||
| 848 | if (rht_grow_above_75(ht, tbl)) | 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 | data = NULL; | 853 | data = NULL; |
| 852 | out: | 854 | out: |
| @@ -227,6 +227,8 @@ struct spi_mem_op { · 226 unmodified lines | |||
| 227 | * struct spi_mem_dirmap_info - Direct mapping information | 227 | * struct spi_mem_dirmap_info - Direct mapping information |
| 228 | * @op_tmpl: operation template that should be used by the direct mapping when | 228 | * @op_tmpl: operation template that should be used by the direct mapping when |
| 229 | * the memory device is accessed | 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 | * @offset: absolute offset this direct mapping is pointing to | 232 | * @offset: absolute offset this direct mapping is pointing to |
| 231 | * @length: length in byte of this direct mapping | 233 | * @length: length in byte of this direct mapping |
| 232 | * | 234 | * |
| @@ -237,7 +239,9 @@ struct spi_mem_op { · 4 unmodified lines | |||
| 237 | * direction is directly encoded in the ->op_tmpl.data.dir field. | 239 | * direction is directly encoded in the ->op_tmpl.data.dir field. |
| 238 | */ | 240 | */ |
| 239 | struct spi_mem_dirmap_info { | 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 | u64 offset; | 245 | u64 offset; |
| 242 | u64 length; | 246 | u64 length; |
| 243 | }; | 247 | }; |
| @@ -381,12 +385,18 @@ struct spi_controller_mem_ops { · 137 unmodified lines | |||
| 381 | * @swap16: Supports swapping bytes on a 16 bit boundary when configured in | 385 | * @swap16: Supports swapping bytes on a 16 bit boundary when configured in |
| 382 | * Octal DTR | 386 | * Octal DTR |
| 383 | * @per_op_freq: Supports per operation frequency switching | 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 | struct spi_controller_mem_caps { | 393 | struct spi_controller_mem_caps { |
| 386 | bool dtr; | 394 | bool dtr; |
| 387 | bool ecc; | 395 | bool ecc; |
| 388 | bool swap16; | 396 | bool swap16; |
| 389 | bool per_op_freq; | 397 | bool per_op_freq; |
| 398 | bool secondary_op_tmpl; | ||
| 399 | bool no_cs_assertion; | ||
| 390 | }; | 400 | }; |
| 391 | 401 | ||
| 392 | #define spi_mem_controller_is_capable(ctlr, cap) \ | 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 | #define TP_CONDITION(args...) args | 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 | * enable their tracepoints. By default, this file will create | 206 | * enable their tracepoints. By default, this file will create |
| 207 | * the tracepoints if CONFIG_TRACEPOINTS is defined. If a subsystem | 207 | * the tracepoints if CONFIG_TRACEPOINTS is defined. If a subsystem |
| 208 | * wants to be able to disable its tracepoints from being created | 208 | * wants to be able to disable its tracepoints from being created |
| @@ -243,7 +243,7 @@ typedef struct port { · 242 unmodified lines | |||
| 243 | churn_state_t sm_churn_actor_state; | 243 | churn_state_t sm_churn_actor_state; |
| 244 | churn_state_t sm_churn_partner_state; | 244 | churn_state_t sm_churn_partner_state; |
| 245 | struct slave *slave; /* pointer to the bond slave that this port belongs to */ | 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 | struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ | 247 | struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ |
| 248 | u32 transaction_id; /* continuous number for identification of Marker PDU's; */ | 248 | u32 transaction_id; /* continuous number for identification of Marker PDU's; */ |
| 249 | struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ | 249 | struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ |
| @@ -1204,12 +1204,15 @@ struct nft_stats { · 1203 unmodified lines | |||
| 1204 | struct u64_stats_sync syncp; | 1204 | struct u64_stats_sync syncp; |
| 1205 | }; | 1205 | }; |
| 1206 | 1206 | ||
| 1207 | #define NFT_HOOK_REMOVE (1 << 0) | ||
| 1208 | |||
| 1207 | struct nft_hook { | 1209 | struct nft_hook { |
| 1208 | struct list_head list; | 1210 | struct list_head list; |
| 1209 | struct list_head ops_list; | 1211 | struct list_head ops_list; |
| 1210 | struct rcu_head rcu; | 1212 | struct rcu_head rcu; |
| 1211 | char ifname[IFNAMSIZ]; | 1213 | char ifname[IFNAMSIZ]; |
| 1212 | u8 ifnamelen; | 1214 | u8 ifnamelen; |
| 1215 | u8 flags; | ||
| 1213 | }; | 1216 | }; |
| 1214 | 1217 | ||
| 1215 | struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook, | 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 | u8 put_net:1; | 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 | * struct nft_trans_binding - nf_tables object with binding support in transaction | 1681 | * struct nft_trans_binding - nf_tables object with binding support in transaction |
| 1669 | * @nft_trans: base structure, MUST be first member | 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 | return niov - net_iov_owner(niov)->niovs; | 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 | /* netmem */ | 145 | /* netmem */ |
| 131 | 146 | ||
| 132 | /** | 147 | /** |
| @@ -905,7 +905,8 @@ struct io_uring_buf_reg { · 904 unmodified lines | |||
| 905 | __u32 ring_entries; | 905 | __u32 ring_entries; |
| 906 | __u16 bgid; | 906 | __u16 bgid; |
| 907 | __u16 flags; | 907 | __u16 flags; |
| 908 | __u64 resv[3]; | 908 | __u32 min_left; |
| 909 | __u32 resv[5]; | ||
| 909 | }; | 910 | }; |
| 910 | 911 | ||
| 911 | /* argument for IORING_REGISTER_PBUF_STATUS */ | 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 | this_len = min_t(u32, len, buf_len); | 47 | this_len = min_t(u32, len, buf_len); |
| 48 | buf_len -= this_len; | 48 | buf_len -= this_len; |
| 49 | /* Stop looping for invalid buffer length of 0 */ | 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 | WRITE_ONCE(buf->addr, READ_ONCE(buf->addr) + this_len); | 51 | WRITE_ONCE(buf->addr, READ_ONCE(buf->addr) + this_len); |
| 52 | WRITE_ONCE(buf->len, buf_len); | 52 | WRITE_ONCE(buf->len, buf_len); |
| 53 | return false; | 53 | return false; |
| @@ -637,6 +637,10 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) · 583 unmodified lines | |||
| 637 | if (reg.ring_entries >= 65536) | 637 | if (reg.ring_entries >= 65536) |
| 638 | return -EINVAL; | 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 | bl = io_buffer_get_list(ctx, reg.bgid); | 644 | bl = io_buffer_get_list(ctx, reg.bgid); |
| 641 | if (bl) { | 645 | if (bl) { |
| 642 | /* if mapped buffer ring OR classic exists, don't allow */ | 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 | #endif | 685 | #endif |
| 682 | 686 | ||
| 683 | bl->nr_entries = reg.ring_entries; | ||
| 684 | bl->mask = reg.ring_entries - 1; | 687 | bl->mask = reg.ring_entries - 1; |
| 685 | bl->flags |= IOBL_BUF_RING; | 688 | bl->flags |= IOBL_BUF_RING; |
| 686 | bl->buf_ring = br; | 689 | bl->buf_ring = br; |
| 690 | if (reg.min_left) | ||
| 691 | bl->min_left_sub_one = reg.min_left - 1; | ||
| 687 | if (reg.flags & IOU_PBUF_RING_INC) | 692 | if (reg.flags & IOU_PBUF_RING_INC) |
| 688 | bl->flags |= IOBL_INC; | 693 | bl->flags |= IOBL_INC; |
| 689 | ret = io_buffer_add_list(ctx, bl, reg.bgid); | 694 | ret = io_buffer_add_list(ctx, bl, reg.bgid); |
| @@ -27,12 +27,18 @@ struct io_buffer_list { · 26 unmodified lines | |||
| 27 | __u16 bgid; | 27 | __u16 bgid; |
| 28 | 28 | ||
| 29 | /* below is for ring provided buffers */ | 29 | /* below is for ring provided buffers */ |
| 30 | __u16 nr_entries; | ||
| 31 | __u16 head; | 30 | __u16 head; |
| 32 | __u16 mask; | 31 | __u16 mask; |
| 33 | 32 | ||
| 34 | __u16 flags; | 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 | struct io_mapped_region region; | 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 | /* clean the napi list for new settings */ | 276 | /* clean the napi list for new settings */ |
| 277 | io_napi_free(ctx); | 277 | io_napi_free(ctx); |
| 278 | WRITE_ONCE(ctx->napi_track_mode, napi->op_param); | 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 | WRITE_ONCE(ctx->napi_busy_poll_dt, napi->busy_poll_to * NSEC_PER_USEC); | 281 | WRITE_ONCE(ctx->napi_busy_poll_dt, napi->busy_poll_to * NSEC_PER_USEC); |
| 280 | WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll); | 282 | WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll); |
| 281 | return 0; | 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 | void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx) | 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 | __io_fallback_tw(node, false); | 288 | __io_fallback_tw(node, false); |
| 279 | node = llist_del_all(&ctx->retry_llist); | 289 | node = llist_del_all(&ctx->retry_llist); |
| 280 | __io_fallback_tw(node, false); | 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 | for (i = 0; i < nr_iovs; i++) { | 495 | for (i = 0; i < nr_iovs; i++) { |
| 496 | struct net_iov *niov = &area->nia.niovs[i]; | 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 | area->freelist[i] = i; | 499 | area->freelist[i] = i; |
| 500 | atomic_set(&area->user_refs[i], 0); | 500 | atomic_set(&area->user_refs[i], 0); |
| 501 | niov->type = NET_IOV_IOURING; | ||
| 502 | } | 501 | } |
| 503 | 502 | ||
| 504 | if (ifq->dev) { | 503 | if (ifq->dev) { |
| @@ -3934,33 +3934,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) · 3933 unmodified lines | |||
| 3934 | static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, | 3934 | static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, |
| 3935 | size_t nbytes, enum psi_res res) | 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 | struct psi_trigger *new; | 3938 | struct psi_trigger *new; |
| 3939 | struct cgroup *cgrp; | 3939 | struct cgroup *cgrp; |
| 3940 | struct psi_group *psi; | 3940 | struct psi_group *psi; |
| 3941 | ssize_t ret = 0; | ||
| 3941 | 3942 | ||
| 3942 | cgrp = cgroup_kn_lock_live(of->kn, false); | 3943 | cgrp = cgroup_kn_lock_live(of->kn, false); |
| 3943 | if (!cgrp) | 3944 | if (!cgrp) |
| 3944 | return -ENODEV; | 3945 | return -ENODEV; |
| 3945 | 3946 | ||
| 3946 | cgroup_get(cgrp); | 3947 | ctx = of->priv; |
| 3947 | cgroup_kn_unlock(of->kn); | 3948 | if (!ctx) { |
| 3949 | ret = -ENODEV; | ||
| 3950 | goto out_unlock; | ||
| 3951 | } | ||
| 3948 | 3952 | ||
| 3949 | /* Allow only one trigger per file descriptor */ | 3953 | /* Allow only one trigger per file descriptor */ |
| 3950 | if (ctx->psi.trigger) { | 3954 | if (ctx->psi.trigger) { |
| 3951 | cgroup_put(cgrp); | 3955 | ret = -EBUSY; |
| 3952 | return -EBUSY; | 3956 | goto out_unlock; |
| 3953 | } | 3957 | } |
| 3954 | 3958 | ||
| 3955 | psi = cgroup_psi(cgrp); | 3959 | psi = cgroup_psi(cgrp); |
| 3956 | new = psi_trigger_create(psi, buf, res, of->file, of); | 3960 | new = psi_trigger_create(psi, buf, res, of->file, of); |
| 3957 | if (IS_ERR(new)) { | 3961 | if (IS_ERR(new)) { |
| 3958 | cgroup_put(cgrp); | 3962 | ret = PTR_ERR(new); |
| 3959 | return PTR_ERR(new); | 3963 | goto out_unlock; |
| 3960 | } | 3964 | } |
| 3961 | 3965 | ||
| 3962 | smp_store_release(&ctx->psi.trigger, new); | 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 | return nbytes; | 3973 | return nbytes; |
| 3966 | } | 3974 | } |
| @@ -5716,16 +5724,6 @@ static void offline_css(struct cgroup_subsys_state *css) · 1749 unmodified lines | |||
| 5716 | RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); | 5724 | RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); |
| 5717 | 5725 | ||
| 5718 | wake_up_all(&css->cgroup->offline_waitq); | 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 | static void kill_css(struct cgroup_subsys_state *css) | 6037 | static void kill_css(struct cgroup_subsys_state *css) |
| 6040 | { | 6038 | { |
| 6039 | struct cgroup_subsys *ss = css->ss; | ||
| 6040 | |||
| 6041 | lockdep_assert_held(&cgroup_mutex); | 6041 | lockdep_assert_held(&cgroup_mutex); |
| 6042 | 6042 | ||
| 6043 | if (css->flags & CSS_DYING) | 6043 | if (css->flags & CSS_DYING) |
| @@ -6074,6 +6074,16 @@ static void kill_css(struct cgroup_subsys_state *css) · 30 unmodified lines | |||
| 6074 | * css is confirmed to be seen as killed on all CPUs. | 6074 | * css is confirmed to be seen as killed on all CPUs. |
| 6075 | */ | 6075 | */ |
| 6076 | percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); | 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 | int nr_deadline_tasks; | 168 | int nr_deadline_tasks; |
| 169 | int nr_migrate_dl_tasks; | 169 | int nr_migrate_dl_tasks; |
| 170 | u64 sum_migrate_dl_bw; | 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 | /* Invalid partition error code, not lock protected */ | 177 | /* Invalid partition error code, not lock protected */ |
| 173 | enum prs_errcode prs_err; | 178 | enum prs_errcode prs_err; |
| @@ -288,6 +288,7 @@ struct cpuset top_cpuset = { · 287 unmodified lines | |||
| 288 | .flags = BIT(CS_CPU_EXCLUSIVE) | | 288 | .flags = BIT(CS_CPU_EXCLUSIVE) | |
| 289 | BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE), | 289 | BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE), |
| 290 | .partition_root_state = PRS_ROOT, | 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 | if (!trial) | 580 | if (!trial) |
| 580 | return NULL; | 581 | return NULL; |
| 581 | 582 | ||
| 583 | trial->dl_bw_cpu = -1; | ||
| 584 | |||
| 582 | /* Setup cpumask pointer array */ | 585 | /* Setup cpumask pointer array */ |
| 583 | cpumask_var_t *pmask[4] = { | 586 | cpumask_var_t *pmask[4] = { |
| 584 | &trial->cpus_allowed, | 587 | &trial->cpus_allowed, |
| @@ -2980,6 +2983,7 @@ static void reset_migrate_dl_data(struct cpuset *cs) · 2395 unmodified lines | |||
| 2980 | { | 2983 | { |
| 2981 | cs->nr_migrate_dl_tasks = 0; | 2984 | cs->nr_migrate_dl_tasks = 0; |
| 2982 | cs->sum_migrate_dl_bw = 0; | 2985 | cs->sum_migrate_dl_bw = 0; |
| 2986 | cs->dl_bw_cpu = -1; | ||
| 2983 | } | 2987 | } |
| 2984 | 2988 | ||
| 2985 | /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */ | 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 | reset_migrate_dl_data(cs); | 3060 | reset_migrate_dl_data(cs); |
| 3057 | goto out_unlock; | 3061 | goto out_unlock; |
| 3058 | } | 3062 | } |
| 3063 | |||
| 3064 | cs->dl_bw_cpu = cpu; | ||
| 3059 | } | 3065 | } |
| 3060 | 3066 | ||
| 3061 | out_success: | 3067 | out_success: |
| @@ -3080,12 +3086,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset) · 18 unmodified lines | |||
| 3080 | mutex_lock(&cpuset_mutex); | 3086 | mutex_lock(&cpuset_mutex); |
| 3081 | dec_attach_in_progress_locked(cs); | 3087 | dec_attach_in_progress_locked(cs); |
| 3082 | 3088 | ||
| 3083 | if (cs->nr_migrate_dl_tasks) { | 3089 | if (cs->dl_bw_cpu >= 0) |
| 3084 | int cpu = cpumask_any(cs->effective_cpus); | 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 | reset_migrate_dl_data(cs); | 3093 | reset_migrate_dl_data(cs); |
| 3088 | } | ||
| 3089 | 3094 | ||
| 3090 | mutex_unlock(&cpuset_mutex); | 3095 | mutex_unlock(&cpuset_mutex); |
| 3091 | } | 3096 | } |
| @@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, · 282 unmodified lines | |||
| 283 | ret = PTR_ERR(rpool); | 283 | ret = PTR_ERR(rpool); |
| 284 | goto err; | 284 | goto err; |
| 285 | } else { | 285 | } else { |
| 286 | new = rpool->resources[index].usage + 1; | 286 | new = (s64)rpool->resources[index].usage + 1; |
| 287 | if (new > rpool->resources[index].max) { | 287 | if (new > rpool->resources[index].max) { |
| 288 | ret = -EAGAIN; | 288 | ret = -EAGAIN; |
| 289 | goto err; | 289 | goto err; |
| @@ -1951,9 +1951,11 @@ static void rv_task_fork(struct task_struct *p) · 1950 unmodified lines | |||
| 1951 | 1951 | ||
| 1952 | static bool need_futex_hash_allocate_default(u64 clone_flags) | 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)) | 1954 | /* |
| 1955 | return false; | 1955 | * Allocate a default futex hash for any sibling that will |
| 1956 | return true; | 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 | if (retval) | 2382 | if (retval) |
| 2381 | goto bad_fork_cancel_cgroup; | 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 | if (need_futex_hash_allocate_default(clone_flags)) { | 2385 | if (need_futex_hash_allocate_default(clone_flags)) { |
| 2388 | retval = futex_hash_allocate_default(); | 2386 | retval = futex_hash_allocate_default(); |
| 2389 | if (retval) | 2387 | if (retval) |
| @@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, · 318 unmodified lines | |||
| 319 | return -EINVAL; | 319 | return -EINVAL; |
| 320 | 320 | ||
| 321 | /* Ensure that this does not race against an early wakeup */ | 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 | return -EAGAIN; | 325 | return -EAGAIN; |
| 326 | } | ||
| 324 | 327 | ||
| 325 | /* | 328 | /* |
| 326 | * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit | 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 | * We were woken prior to requeue by a timeout or a signal. | 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); | 730 | if (!plist_node_empty(&q->list)) { |
| 728 | futex_hb_waiters_dec(hb); | 731 | plist_del(&q->list, &hb->chain); |
| 732 | futex_hb_waiters_dec(hb); | ||
| 733 | } | ||
| 729 | 734 | ||
| 730 | /* Handle spurious wakeups gracefully */ | 735 | /* Handle spurious wakeups gracefully */ |
| 731 | ret = -EWOULDBLOCK; | 736 | ret = -EWOULDBLOCK; |
| @@ -762,19 +762,24 @@ int kho_add_subtree(const char *name, void *blob, size_t size) · 761 unmodified lines | |||
| 762 | goto out_pack; | 762 | goto out_pack; |
| 763 | } | 763 | } |
| 764 | 764 | ||
| 765 | err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, | 765 | fdt_err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, |
| 766 | &phys, sizeof(phys)); | 766 | &phys, sizeof(phys)); |
| 767 | if (err < 0) | 767 | if (fdt_err < 0) |
| 768 | goto out_pack; | 768 | goto out_del_node; |
| 769 | 769 | ||
| 770 | err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME, | 770 | fdt_err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME, |
| 771 | &size_u64, sizeof(size_u64)); | 771 | &size_u64, sizeof(size_u64)); |
| 772 | if (err < 0) | 772 | if (fdt_err < 0) |
| 773 | goto out_pack; | 773 | goto out_del_node; |
| 774 | 774 | ||
| 775 | WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob, | 775 | WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob, |
| 776 | size, false)); | 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 | out_pack: | 783 | out_pack: |
| 779 | fdt_pack(root_fdt); | 784 | fdt_pack(root_fdt); |
| 780 | 785 | ||
| @@ -514,11 +514,12 @@ int luo_session_deserialize(void) · 513 unmodified lines | |||
| 514 | { | 514 | { |
| 515 | struct luo_session_header *sh = &luo_session_global.incoming; | 515 | struct luo_session_header *sh = &luo_session_global.incoming; |
| 516 | static bool is_deserialized; | 516 | static bool is_deserialized; |
| 517 | static int err; | 517 | static int saved_err; |
| 518 | int err; | ||
| 518 | 519 | ||
| 519 | /* If has been deserialized, always return the same error code */ | 520 | /* If has been deserialized, always return the same error code */ |
| 520 | if (is_deserialized) | 521 | if (is_deserialized) |
| 521 | return err; | 522 | return saved_err; |
| 522 | 523 | ||
| 523 | is_deserialized = true; | 524 | is_deserialized = true; |
| 524 | if (!sh->active) | 525 | if (!sh->active) |
| @@ -547,7 +548,8 @@ int luo_session_deserialize(void) · 22 unmodified lines | |||
| 547 | pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n", | 548 | pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n", |
| 548 | (int)sizeof(sh->ser[i].name), | 549 | (int)sizeof(sh->ser[i].name), |
| 549 | sh->ser[i].name, session); | 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 | err = luo_session_insert(sh, session); | 555 | err = luo_session_insert(sh, session); |
| @@ -555,7 +557,7 @@ int luo_session_deserialize(void) · 1 unmodified line | |||
| 555 | pr_warn("Failed to insert session [%s] %pe\n", | 557 | pr_warn("Failed to insert session [%s] %pe\n", |
| 556 | session->name, ERR_PTR(err)); | 558 | session->name, ERR_PTR(err)); |
| 557 | luo_session_free(session); | 559 | luo_session_free(session); |
| 558 | return err; | 560 | goto save_err; |
| 559 | } | 561 | } |
| 560 | 562 | ||
| 561 | scoped_guard(mutex, &session->mutex) { | 563 | scoped_guard(mutex, &session->mutex) { |
| @@ -565,7 +567,7 @@ int luo_session_deserialize(void) · 3 unmodified lines | |||
| 565 | if (err) { | 567 | if (err) { |
| 566 | pr_warn("Failed to deserialize files for session [%s] %pe\n", | 568 | pr_warn("Failed to deserialize files for session [%s] %pe\n", |
| 567 | session->name, ERR_PTR(err)); | 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 | sh->ser = NULL; | 576 | sh->ser = NULL; |
| 575 | 577 | ||
| 576 | return 0; | 578 | return 0; |
| 579 | save_err: | ||
| 580 | saved_err = err; | ||
| 581 | return err; | ||
| 577 | } | 582 | } |
| 578 | 583 | ||
| 579 | int luo_session_serialize(void) | 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 | p->se.nr_migrations = 0; | 4458 | p->se.nr_migrations = 0; |
| 4459 | p->se.vruntime = 0; | 4459 | p->se.vruntime = 0; |
| 4460 | p->se.vlag = 0; | 4460 | p->se.vlag = 0; |
| 4461 | p->se.rel_deadline = 0; | ||
| 4461 | INIT_LIST_HEAD(&p->se.group_node); | 4462 | INIT_LIST_HEAD(&p->se.group_node); |
| 4462 | 4463 | ||
| 4463 | /* A delayed task cannot be in clone(). */ | 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 | .key_len = sizeof_field(struct scx_sched, ops.sub_cgroup_id), | 32 | .key_len = sizeof_field(struct scx_sched, ops.sub_cgroup_id), |
| 33 | .key_offset = offsetof(struct scx_sched, ops.sub_cgroup_id), | 33 | .key_offset = offsetof(struct scx_sched, ops.sub_cgroup_id), |
| 34 | .head_offset = offsetof(struct scx_sched, hash_node), | 34 | .head_offset = offsetof(struct scx_sched, hash_node), |
| 35 | .insecure_elasticity = true, /* inserted under scx_sched_lock */ | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | static struct rhashtable scx_sched_hash; | 38 | static struct rhashtable scx_sched_hash; |
| @@ -52,8 +53,6 @@ DEFINE_STATIC_KEY_FALSE(__scx_enabled); · 14 unmodified lines | |||
| 52 | DEFINE_STATIC_PERCPU_RWSEM(scx_fork_rwsem); | 53 | DEFINE_STATIC_PERCPU_RWSEM(scx_fork_rwsem); |
| 53 | static atomic_t scx_enable_state_var = ATOMIC_INIT(SCX_DISABLED); | 54 | static atomic_t scx_enable_state_var = ATOMIC_INIT(SCX_DISABLED); |
| 54 | static DEFINE_RAW_SPINLOCK(scx_bypass_lock); | 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 | static bool scx_init_task_enabled; | 56 | static bool scx_init_task_enabled; |
| 58 | static bool scx_switching_all; | 57 | static bool scx_switching_all; |
| 59 | DEFINE_STATIC_KEY_FALSE(__scx_switched_all); | 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 | __this_cpu_write(scx_locked_rq_state, rq); | 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 | do { \ | 476 | do { \ |
| 474 | if (rq) \ | 477 | struct rq *__prev_locked_rq; \ |
| 475 | update_locked_rq(rq); \ | 478 | \ |
| 479 | if (locked_rq) { \ | ||
| 480 | __prev_locked_rq = scx_locked_rq(); \ | ||
| 481 | update_locked_rq(locked_rq); \ | ||
| 482 | } \ | ||
| 476 | (sch)->ops.op(args); \ | 483 | (sch)->ops.op(args); \ |
| 477 | if (rq) \ | 484 | if (locked_rq) \ |
| 478 | update_locked_rq(NULL); \ | 485 | update_locked_rq(__prev_locked_rq); \ |
| 479 | } while (0) | 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 | __typeof__((sch)->ops.op(args)) __ret; \ | 491 | __typeof__((sch)->ops.op(args)) __ret; \ |
| 484 | \ | 492 | \ |
| 485 | if (rq) \ | 493 | if (locked_rq) { \ |
| 486 | update_locked_rq(rq); \ | 494 | __prev_locked_rq = scx_locked_rq(); \ |
| 495 | update_locked_rq(locked_rq); \ | ||
| 496 | } \ | ||
| 487 | __ret = (sch)->ops.op(args); \ | 497 | __ret = (sch)->ops.op(args); \ |
| 488 | if (rq) \ | 498 | if (locked_rq) \ |
| 489 | update_locked_rq(NULL); \ | 499 | update_locked_rq(__prev_locked_rq); \ |
| 490 | __ret; \ | 500 | __ret; \ |
| 491 | }) | 501 | }) |
| 492 | 502 | ||
| @@ -498,39 +508,39 @@ do { \ · 5 unmodified lines | |||
| 498 | * those subject tasks. | 508 | * those subject tasks. |
| 499 | * | 509 | * |
| 500 | * Every SCX_CALL_OP_TASK*() call site invokes its op with @p's rq lock held - | 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 | 511 | * either via the @locked_rq argument here, or (for ops.select_cpu()) via @p's |
| 502 | * held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu. So if | 512 | * pi_lock held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu. |
| 503 | * kf_tasks[] is set, @p's scheduler-protected fields are stable. | 513 | * So if kf_tasks[] is set, @p's scheduler-protected fields are stable. |
| 504 | * | 514 | * |
| 505 | * kf_tasks[] can not stack, so task-based SCX ops must not nest. The | 515 | * kf_tasks[] can not stack, so task-based SCX ops must not nest. The |
| 506 | * WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants | 516 | * WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants |
| 507 | * while a previous one is still in progress. | 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 | do { \ | 520 | do { \ |
| 511 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ | 521 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ |
| 512 | current->scx.kf_tasks[0] = task; \ | 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 | current->scx.kf_tasks[0] = NULL; \ | 524 | current->scx.kf_tasks[0] = NULL; \ |
| 515 | } while (0) | 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 | __typeof__((sch)->ops.op(task, ##args)) __ret; \ | 529 | __typeof__((sch)->ops.op(task, ##args)) __ret; \ |
| 520 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ | 530 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ |
| 521 | current->scx.kf_tasks[0] = task; \ | 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 | current->scx.kf_tasks[0] = NULL; \ | 533 | current->scx.kf_tasks[0] = NULL; \ |
| 524 | __ret; \ | 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 | __typeof__((sch)->ops.op(task0, task1, ##args)) __ret; \ | 539 | __typeof__((sch)->ops.op(task0, task1, ##args)) __ret; \ |
| 530 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ | 540 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ |
| 531 | current->scx.kf_tasks[0] = task0; \ | 541 | current->scx.kf_tasks[0] = task0; \ |
| 532 | current->scx.kf_tasks[1] = task1; \ | 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 | current->scx.kf_tasks[0] = NULL; \ | 544 | current->scx.kf_tasks[0] = NULL; \ |
| 535 | current->scx.kf_tasks[1] = NULL; \ | 545 | current->scx.kf_tasks[1] = NULL; \ |
| 536 | __ret; \ | 546 | __ret; \ |
| @@ -1388,18 +1398,55 @@ static void call_task_dequeue(struct scx_sched *sch, struct rq *rq, · 851 unmodified lines | |||
| 1388 | p->scx.flags &= ~SCX_TASK_IN_CUSTODY; | 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, | 1401 | static void local_dsq_post_enq(struct scx_sched *sch, struct scx_dispatch_q *dsq, |
| 1392 | u64 enq_flags) | 1402 | struct task_struct *p, u64 enq_flags) |
| 1393 | { | 1403 | { |
| 1394 | struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); | 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 | * If @rq is in balance, the CPU is already vacant and looking for the | 1444 | * If @rq is in balance, the CPU is already vacant and looking for the |
| 1401 | * next task to run. No need to preempt or trigger resched after moving | 1445 | * next task to run. No need to preempt or trigger resched after moving |
| 1402 | * @p into its local DSQ. | 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 | if (rq->scx.flags & SCX_RQ_IN_BALANCE) | 1451 | if (rq->scx.flags & SCX_RQ_IN_BALANCE) |
| 1405 | return; | 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 | if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && | 1454 | if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && |
| 1408 | rq->curr->sched_class == &ext_sched_class) { | 1455 | rq->curr->sched_class == &ext_sched_class) { |
| 1409 | rq->curr->scx.slice = 0; | 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 | resched_curr(rq); | 1457 | resched_curr(rq); |
| 1458 | } | ||
| 1415 | } | 1459 | } |
| 1416 | 1460 | ||
| 1417 | static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq, | 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 | if (!(dsq->id & SCX_DSQ_FLAG_BUILTIN)) | 1538 | if (!(dsq->id & SCX_DSQ_FLAG_BUILTIN)) |
| 1495 | rcu_assign_pointer(dsq->first_task, p); | 1539 | rcu_assign_pointer(dsq->first_task, p); |
| 1496 | } else { | 1540 | } else { |
| 1497 | bool was_empty; | 1541 | /* |
| 1498 | 1542 | * dsq->list can contain parked BPF iterator cursors, so | |
| 1499 | was_empty = list_empty(&dsq->list); | 1543 | * list_empty() here isn't a reliable proxy for "no real |
| 1544 | * task in the DSQ". Test dsq->first_task directly. | ||
| 1545 | */ | ||
| 1500 | list_add_tail(&p->scx.dsq_list.node, &dsq->list); | 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 | rcu_assign_pointer(dsq->first_task, p); | 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 | * concurrently in a non-atomic way. | 1564 | * concurrently in a non-atomic way. |
| 1519 | */ | 1565 | */ |
| 1520 | if (is_local) { | 1566 | if (is_local) { |
| 1521 | local_dsq_post_enq(dsq, p, enq_flags); | 1567 | local_dsq_post_enq(sch, dsq, p, enq_flags); |
| 1522 | } else { | 1568 | } else { |
| 1523 | /* | 1569 | /* |
| 1524 | * Task on global/bypass DSQ: leave custody, task on | 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 | schedule_reenq_local(rq, 0); | 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 | struct scx_dispatch_q *src_dsq, | 2180 | struct scx_dispatch_q *src_dsq, |
| 2134 | struct rq *dst_rq) | 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 | dsq_inc_nr(dst_dsq, p, enq_flags); | 2196 | dsq_inc_nr(dst_dsq, p, enq_flags); |
| 2150 | p->scx.dsq = dst_dsq; | 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 | /* @p is going from a non-local DSQ to a local DSQ */ | 2417 | /* @p is going from a non-local DSQ to a local DSQ */ |
| 2371 | if (src_rq == dst_rq) { | 2418 | if (src_rq == dst_rq) { |
| 2372 | task_unlink_from_dsq(p, src_dsq); | 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 | src_dsq, dst_rq); | 2421 | src_dsq, dst_rq); |
| 2375 | raw_spin_unlock(&src_dsq->lock); | 2422 | raw_spin_unlock(&src_dsq->lock); |
| 2376 | } else { | 2423 | } else { |
| @@ -2423,7 +2470,7 @@ retry: · 46 unmodified lines | |||
| 2423 | 2470 | ||
| 2424 | if (rq == task_rq) { | 2471 | if (rq == task_rq) { |
| 2425 | task_unlink_from_dsq(p, dsq); | 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 | raw_spin_unlock(&dsq->lock); | 2474 | raw_spin_unlock(&dsq->lock); |
| 2428 | return true; | 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 | if (sch_a == sch_b && SCX_HAS_OP(sch_a, core_sched_before) && | 3230 | if (sch_a == sch_b && SCX_HAS_OP(sch_a, core_sched_before) && |
| 3184 | !scx_bypassing(sch_a, task_cpu(a))) | 3231 | !scx_bypassing(sch_a, task_cpu(a))) |
| 3185 | return SCX_CALL_OP_2TASKS_RET(sch_a, core_sched_before, | 3232 | return SCX_CALL_OP_2TASKS_RET(sch_a, core_sched_before, |
| 3186 | NULL, | 3233 | task_rq(a), |
| 3187 | (struct task_struct *)a, | 3234 | (struct task_struct *)a, |
| 3188 | (struct task_struct *)b); | 3235 | (struct task_struct *)b); |
| 3189 | else | 3236 | else |
| @@ -3631,6 +3678,22 @@ static void __scx_disable_and_exit_task(struct scx_sched *sch, · 441 unmodified lines | |||
| 3631 | SCX_CALL_OP_TASK(sch, exit_task, task_rq(p), p, &args); | 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 | static void scx_disable_and_exit_task(struct scx_sched *sch, | 3697 | static void scx_disable_and_exit_task(struct scx_sched *sch, |
| 3635 | struct task_struct *p) | 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 | * If set, @p exited between __scx_init_task() and scx_enable_task() in | 3703 | * If set, @p exited between __scx_init_task() and scx_enable_task() in |
| 3641 | * scx_sub_enable() and is initialized for both the associated sched and | 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) && | 3708 | if (p->scx.flags & SCX_TASK_SUB_INIT) { |
| 3645 | !WARN_ON_ONCE(!scx_enabling_sub_sched)) { | 3709 | if (!WARN_ON_ONCE(!scx_enabling_sub_sched)) |
| 3646 | __scx_disable_and_exit_task(scx_enabling_sub_sched, p); | 3710 | scx_sub_init_cancel_task(scx_enabling_sub_sched, p); |
| 3647 | p->scx.flags &= ~SCX_TASK_SUB_INIT; | 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 | void scx_group_set_weight(struct task_group *tg, unsigned long weight) | 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 | percpu_down_read(&scx_cgroup_ops_rwsem); | 4393 | percpu_down_read(&scx_cgroup_ops_rwsem); |
| 4394 | sch = scx_root; | ||
| 4330 | 4395 | ||
| 4331 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_weight) && | 4396 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_weight) && |
| 4332 | tg->scx.weight != weight) | 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 | void scx_group_set_idle(struct task_group *tg, bool idle) | 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 | percpu_down_read(&scx_cgroup_ops_rwsem); | 4409 | percpu_down_read(&scx_cgroup_ops_rwsem); |
| 4410 | sch = scx_root; | ||
| 4345 | 4411 | ||
| 4346 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle)) | 4412 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle)) |
| 4347 | SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle); | 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 | void scx_group_set_bandwidth(struct task_group *tg, | 4421 | void scx_group_set_bandwidth(struct task_group *tg, |
| 4356 | u64 period_us, u64 quota_us, u64 burst_us) | 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 | percpu_down_read(&scx_cgroup_ops_rwsem); | 4426 | percpu_down_read(&scx_cgroup_ops_rwsem); |
| 4427 | sch = scx_root; | ||
| 4361 | 4428 | ||
| 4362 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_bandwidth) && | 4429 | if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_bandwidth) && |
| 4363 | (tg->scx.bw_period_us != period_us || | 4430 | (tg->scx.bw_period_us != period_us || |
| @@ -4380,21 +4447,6 @@ static struct cgroup *root_cgroup(void) · 16 unmodified lines | |||
| 4380 | return &cgrp_dfl_root.cgrp; | 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 | static void scx_cgroup_lock(void) | 4450 | static void scx_cgroup_lock(void) |
| 4399 | { | 4451 | { |
| 4400 | #ifdef CONFIG_EXT_GROUP_SCHED | 4452 | #ifdef CONFIG_EXT_GROUP_SCHED |
| @@ -4412,12 +4464,30 @@ static void scx_cgroup_unlock(void) · 11 unmodified lines | |||
| 4412 | } | 4464 | } |
| 4413 | #else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */ | 4465 | #else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */ |
| 4414 | static struct cgroup *root_cgroup(void) { return NULL; } | 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 | static void scx_cgroup_lock(void) {} | 4467 | static void scx_cgroup_lock(void) {} |
| 4418 | static void scx_cgroup_unlock(void) {} | 4468 | static void scx_cgroup_unlock(void) {} |
| 4419 | #endif /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */ | 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 | * Omitted operations: | 4492 | * Omitted operations: |
| 4423 | * | 4493 | * |
| @@ -4712,6 +4782,8 @@ static void scx_sched_free_rcu_work(struct work_struct *work) · 288 unmodified lines | |||
| 4712 | irq_work_sync(&sch->disable_irq_work); | 4782 | irq_work_sync(&sch->disable_irq_work); |
| 4713 | kthread_destroy_worker(sch->helper); | 4783 | kthread_destroy_worker(sch->helper); |
| 4714 | timer_shutdown_sync(&sch->bypass_lb_timer); | 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 | #ifdef CONFIG_EXT_SUB_SCHED | 4788 | #ifdef CONFIG_EXT_SUB_SCHED |
| 4717 | kfree(sch->cgrp_path); | 4789 | kfree(sch->cgrp_path); |
| @@ -4938,6 +5010,25 @@ void scx_softlockup(u32 dur_s) · 220 unmodified lines | |||
| 4938 | smp_processor_id(), dur_s); | 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 | * scx_hardlockup - sched_ext hardlockup handler | 5033 | * scx_hardlockup - sched_ext hardlockup handler |
| 4943 | * | 5034 | * |
| @@ -4946,17 +5037,19 @@ void scx_softlockup(u32 dur_s) · 2 unmodified lines | |||
| 4946 | * Try kicking out the current scheduler in an attempt to recover the system to | 5037 | * Try kicking out the current scheduler in an attempt to recover the system to |
| 4947 | * a good state before taking more drastic actions. | 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 | 5040 | * Queues an irq_work; the handle_lockup() call happens in IRQ context (see |
| 4950 | * resolve the reported hardlockup. %false if sched_ext is not enabled or | 5041 | * scx_hardlockup_irq_workfn). |
| 4951 | * someone else already initiated abort. | 5042 | * |
| 5043 | * Returns %true if sched_ext is enabled and the work was queued, %false | ||
| 5044 | * otherwise. | ||
| 4952 | */ | 5045 | */ |
| 4953 | bool scx_hardlockup(int cpu) | 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 | return false; | 5049 | return false; |
| 4957 | 5050 | ||
| 4958 | printk_deferred(KERN_ERR "sched_ext: Hard lockup - CPU %d, disabling BPF scheduler\n", | 5051 | atomic_cmpxchg(&scx_hardlockup_cpu, -1, cpu); |
| 4959 | cpu); | 5052 | irq_work_queue(&scx_hardlockup_irq_work); |
| 4960 | return true; | 5053 | return true; |
| 4961 | } | 5054 | } |
| 4962 | 5055 | ||
| @@ -5000,6 +5093,15 @@ resume: · 37 unmodified lines | |||
| 5000 | if (cpumask_empty(donee_mask)) | 5093 | if (cpumask_empty(donee_mask)) |
| 5001 | break; | 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 | donee = cpumask_any_and_distribute(donee_mask, p->cpus_ptr); | 5105 | donee = cpumask_any_and_distribute(donee_mask, p->cpus_ptr); |
| 5004 | if (donee >= nr_cpu_ids) | 5106 | if (donee >= nr_cpu_ids) |
| 5005 | continue; | 5107 | continue; |
| @@ -5058,8 +5160,8 @@ resume: · 52 unmodified lines | |||
| 5058 | static void bypass_lb_node(struct scx_sched *sch, int node) | 5160 | static void bypass_lb_node(struct scx_sched *sch, int node) |
| 5059 | { | 5161 | { |
| 5060 | const struct cpumask *node_mask = cpumask_of_node(node); | 5162 | const struct cpumask *node_mask = cpumask_of_node(node); |
| 5061 | struct cpumask *donee_mask = scx_bypass_lb_donee_cpumask; | 5163 | struct cpumask *donee_mask = sch->bypass_lb_donee_cpumask; |
| 5062 | struct cpumask *resched_mask = scx_bypass_lb_resched_cpumask; | 5164 | struct cpumask *resched_mask = sch->bypass_lb_resched_cpumask; |
| 5063 | u32 nr_tasks = 0, nr_cpus = 0, nr_balanced = 0; | 5165 | u32 nr_tasks = 0, nr_cpus = 0, nr_balanced = 0; |
| 5064 | u32 nr_target, nr_donor_target; | 5166 | u32 nr_target, nr_donor_target; |
| 5065 | u32 before_min = U32_MAX, before_max = 0; | 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 | if (sch->ops.exit) | 5801 | if (sch->ops.exit) |
| 5700 | SCX_CALL_OP(sch, exit, NULL, sch->exit_info); | 5802 | SCX_CALL_OP(sch, exit, NULL, sch->exit_info); |
| 5803 | if (sch->sub_kset) | ||
| 5804 | kset_unregister(sch->sub_kset); | ||
| 5701 | kobject_del(&sch->kobj); | 5805 | kobject_del(&sch->kobj); |
| 5702 | } | 5806 | } |
| 5703 | #else /* CONFIG_EXT_SUB_SCHED */ | 5807 | #else /* CONFIG_EXT_SUB_SCHED */ |
| @@ -5829,6 +5933,10 @@ static void scx_root_disable(struct scx_sched *sch) · 125 unmodified lines | |||
| 5829 | * could observe an object of the same name still in the hierarchy when | 5933 | * could observe an object of the same name still in the hierarchy when |
| 5830 | * the next scheduler is loaded. | 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 | kobject_del(&sch->kobj); | 5940 | kobject_del(&sch->kobj); |
| 5833 | 5941 | ||
| 5834 | free_kick_syncs(); | 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 | irq_work_queue(&sch->disable_irq_work); | 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 | static void dump_newline(struct seq_buf *s) | 6051 | static void dump_newline(struct seq_buf *s) |
| 5925 | { | 6052 | { |
| 5926 | trace_sched_ext_dump(""); | 6053 | trace_sched_ext_dump(""); |
| @@ -6032,9 +6159,8 @@ static void ops_dump_exit(void) · 105 unmodified lines | |||
| 6032 | scx_dump_data.cpu = -1; | 6159 | scx_dump_data.cpu = -1; |
| 6033 | } | 6160 | } |
| 6034 | 6161 | ||
| 6035 | static void scx_dump_task(struct scx_sched *sch, | 6162 | static void scx_dump_task(struct scx_sched *sch, struct seq_buf *s, struct scx_dump_ctx *dctx, |
| 6036 | struct seq_buf *s, struct scx_dump_ctx *dctx, | 6163 | struct rq *rq, struct task_struct *p, char marker) |
| 6037 | struct task_struct *p, char marker) | ||
| 6038 | { | 6164 | { |
| 6039 | static unsigned long bt[SCX_EXIT_BT_LEN]; | 6165 | static unsigned long bt[SCX_EXIT_BT_LEN]; |
| 6040 | struct scx_sched *task_sch = scx_task_sched(p); | 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 | if (SCX_HAS_OP(sch, dump_task)) { | 6202 | if (SCX_HAS_OP(sch, dump_task)) { |
| 6077 | ops_dump_init(s, " "); | 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 | ops_dump_exit(); | 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 | used = seq_buf_used(&ns); | 6325 | used = seq_buf_used(&ns); |
| 6200 | if (SCX_HAS_OP(sch, dump_cpu)) { | 6326 | if (SCX_HAS_OP(sch, dump_cpu)) { |
| 6201 | ops_dump_init(&ns, " "); | 6327 | ops_dump_init(&ns, " "); |
| 6202 | SCX_CALL_OP(sch, dump_cpu, NULL, | 6328 | SCX_CALL_OP(sch, dump_cpu, rq, &dctx, cpu, idle); |
| 6203 | &dctx, cpu, idle); | ||
| 6204 | ops_dump_exit(); | 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 | if (rq->curr->sched_class == &ext_sched_class && | 6349 | if (rq->curr->sched_class == &ext_sched_class && |
| 6225 | (dump_all_tasks || scx_task_on_sched(sch, rq->curr))) | 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 | list_for_each_entry(p, &rq->scx.runnable_list, scx.runnable_node) | 6353 | list_for_each_entry(p, &rq->scx.runnable_list, scx.runnable_node) |
| 6229 | if (dump_all_tasks || scx_task_on_sched(sch, p)) | 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 | next: | 6356 | next: |
| 6232 | rq_unlock_irqrestore(rq, &rf); | 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 | init_irq_work(&sch->disable_irq_work, scx_disable_irq_workfn); | 6562 | init_irq_work(&sch->disable_irq_work, scx_disable_irq_workfn); |
| 6438 | kthread_init_work(&sch->disable_work, scx_disable_workfn); | 6563 | kthread_init_work(&sch->disable_work, scx_disable_workfn); |
| 6439 | timer_setup(&sch->bypass_lb_timer, scx_bypass_lb_timerfn, 0); | 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 | sch->ops = *ops; | 6574 | sch->ops = *ops; |
| 6441 | rcu_assign_pointer(ops->priv, sch); | 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 | char *buf = kzalloc(PATH_MAX, GFP_KERNEL); | 6580 | char *buf = kzalloc(PATH_MAX, GFP_KERNEL); |
| 6447 | if (!buf) { | 6581 | if (!buf) { |
| 6448 | ret = -ENOMEM; | 6582 | ret = -ENOMEM; |
| 6449 | goto err_stop_helper; | 6583 | goto err_free_lb_resched; |
| 6450 | } | 6584 | } |
| 6451 | cgroup_path(cgrp, buf, PATH_MAX); | 6585 | cgroup_path(cgrp, buf, PATH_MAX); |
| 6452 | sch->cgrp_path = kstrdup(buf, GFP_KERNEL); | 6586 | sch->cgrp_path = kstrdup(buf, GFP_KERNEL); |
| 6453 | kfree(buf); | 6587 | kfree(buf); |
| 6454 | if (!sch->cgrp_path) { | 6588 | if (!sch->cgrp_path) { |
| 6455 | ret = -ENOMEM; | 6589 | ret = -ENOMEM; |
| 6456 | goto err_stop_helper; | 6590 | goto err_free_lb_resched; |
| 6457 | } | 6591 | } |
| 6458 | 6592 | ||
| 6459 | sch->cgrp = cgrp; | 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 | #endif /* CONFIG_EXT_SUB_SCHED */ | 6622 | #endif /* CONFIG_EXT_SUB_SCHED */ |
| 6489 | return sch; | 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 | err_stop_helper: | 6629 | err_stop_helper: |
| 6493 | kthread_destroy_worker(sch->helper); | 6630 | kthread_destroy_worker(sch->helper); |
| 6494 | #endif | ||
| 6495 | err_free_pcpu: | 6631 | err_free_pcpu: |
| 6496 | for_each_possible_cpu(cpu) { | 6632 | for_each_possible_cpu(cpu) { |
| 6497 | if (cpu == bypass_fail_cpu) | 6633 | if (cpu == bypass_fail_cpu) |
| @@ -6510,7 +6646,7 @@ err_free_ei: · 12 unmodified lines | |||
| 6510 | err_free_sch: | 6646 | err_free_sch: |
| 6511 | kfree(sch); | 6647 | kfree(sch); |
| 6512 | err_put_cgrp: | 6648 | err_put_cgrp: |
| 6513 | #if defined(CONFIG_EXT_GROUP_SCHED) || defined(CONFIG_EXT_SUB_SCHED) | 6649 | #ifdef CONFIG_EXT_SUB_SCHED |
| 6514 | cgroup_put(cgrp); | 6650 | cgroup_put(cgrp); |
| 6515 | #endif | 6651 | #endif |
| 6516 | return ERR_PTR(ret); | 6652 | return ERR_PTR(ret); |
| @@ -6601,7 +6737,7 @@ static void scx_root_enable_workfn(struct kthread_work *work) · 84 unmodified lines | |||
| 6601 | if (ret) | 6737 | if (ret) |
| 6602 | goto err_unlock; | 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 | cgroup_get(cgrp); | 6741 | cgroup_get(cgrp); |
| 6606 | #endif | 6742 | #endif |
| 6607 | sch = scx_alloc_and_add_sched(ops, cgrp, NULL); | 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 | rcu_assign_pointer(scx_root, sch); | 6775 | rcu_assign_pointer(scx_root, sch); |
| 6640 | 6776 | ||
| 6641 | ret = scx_link_sched(sch); | 6777 | ret = scx_link_sched(sch); |
| 6642 | if (ret) | 6778 | if (ret) { |
| 6779 | cpus_read_unlock(); | ||
| 6643 | goto err_disable; | 6780 | goto err_disable; |
| 6781 | } | ||
| 6644 | 6782 | ||
| 6645 | scx_idle_enable(ops); | 6783 | scx_idle_enable(ops); |
| 6646 | 6784 | ||
| @@ -6821,7 +6959,7 @@ err_disable: · 174 unmodified lines | |||
| 6821 | * completion. sch's base reference will be put by bpf_scx_unreg(). | 6959 | * completion. sch's base reference will be put by bpf_scx_unreg(). |
| 6822 | */ | 6960 | */ |
| 6823 | scx_error(sch, "scx_root_enable() failed (%d)", ret); | 6961 | scx_error(sch, "scx_root_enable() failed (%d)", ret); |
| 6824 | kthread_flush_work(&sch->disable_work); | 6962 | scx_flush_disable_work(sch); |
| 6825 | cmd->ret = 0; | 6963 | cmd->ret = 0; |
| 6826 | } | 6964 | } |
| 6827 | 6965 | ||
| @@ -7072,23 +7210,30 @@ out_unlock: · 244 unmodified lines | |||
| 7072 | abort: | 7210 | abort: |
| 7073 | put_task_struct(p); | 7211 | put_task_struct(p); |
| 7074 | scx_task_iter_stop(&sti); | 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 | scx_task_iter_start(&sti, sch->cgrp); | 7221 | scx_task_iter_start(&sti, sch->cgrp); |
| 7078 | while ((p = scx_task_iter_next_locked(&sti))) { | 7222 | while ((p = scx_task_iter_next_locked(&sti))) { |
| 7079 | if (p->scx.flags & SCX_TASK_SUB_INIT) { | 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 | p->scx.flags &= ~SCX_TASK_SUB_INIT; | 7225 | p->scx.flags &= ~SCX_TASK_SUB_INIT; |
| 7082 | } | 7226 | } |
| 7083 | } | 7227 | } |
| 7084 | scx_task_iter_stop(&sti); | 7228 | scx_task_iter_stop(&sti); |
| 7229 | scx_enabling_sub_sched = NULL; | ||
| 7085 | err_unlock_and_disable: | 7230 | err_unlock_and_disable: |
| 7086 | /* we'll soon enter disable path, keep bypass on */ | 7231 | /* we'll soon enter disable path, keep bypass on */ |
| 7087 | scx_cgroup_unlock(); | 7232 | scx_cgroup_unlock(); |
| 7088 | percpu_up_write(&scx_fork_rwsem); | 7233 | percpu_up_write(&scx_fork_rwsem); |
| 7089 | err_disable: | 7234 | err_disable: |
| 7090 | mutex_unlock(&scx_enable_mutex); | 7235 | mutex_unlock(&scx_enable_mutex); |
| 7091 | kthread_flush_work(&sch->disable_work); | 7236 | scx_flush_disable_work(sch); |
| 7092 | cmd->ret = 0; | 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 | struct scx_sched *sch = rcu_dereference_protected(ops->priv, true); | 7494 | struct scx_sched *sch = rcu_dereference_protected(ops->priv, true); |
| 7350 | 7495 | ||
| 7351 | scx_disable(sch, SCX_EXIT_UNREG); | 7496 | scx_disable(sch, SCX_EXIT_UNREG); |
| 7352 | kthread_flush_work(&sch->disable_work); | 7497 | scx_flush_disable_work(sch); |
| 7353 | RCU_INIT_POINTER(ops->priv, NULL); | 7498 | RCU_INIT_POINTER(ops->priv, NULL); |
| 7354 | kobject_put(&sch->kobj); | 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 | struct task_struct *p, u64 dsq_id, u64 enq_flags) | 8178 | struct task_struct *p, u64 dsq_id, u64 enq_flags) |
| 8034 | { | 8179 | { |
| 8035 | struct scx_dispatch_q *src_dsq = kit->dsq, *dst_dsq; | 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 | struct rq *this_rq, *src_rq, *locked_rq; | 8182 | struct rq *this_rq, *src_rq, *locked_rq; |
| 8038 | bool dispatched = false; | 8183 | bool dispatched = false; |
| 8039 | bool in_balance; | 8184 | bool in_balance; |
| 8040 | unsigned long flags; | 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 | if (!scx_vet_enq_flags(sch, dsq_id, &enq_flags)) | 8197 | if (!scx_vet_enq_flags(sch, dsq_id, &enq_flags)) |
| 8043 | return false; | 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 | guard(rcu)(); | 8682 | guard(rcu)(); |
| 8528 | sch = scx_prog_sched(aux); | 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 | return false; | 8685 | return false; |
| 8531 | 8686 | ||
| 8532 | p->scx.slice = slice; | 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 | guard(rcu)(); | 8705 | guard(rcu)(); |
| 8551 | sch = scx_prog_sched(aux); | 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 | return false; | 8708 | return false; |
| 8554 | 8709 | ||
| 8555 | p->scx.dsq_vtime = vtime; | 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 | * scx_bpf_dsq_nr_queued - Return the number of queued tasks | 8789 | * scx_bpf_dsq_nr_queued - Return the number of queued tasks |
| 8635 | * @dsq_id: id of the DSQ | 8790 | * @dsq_id: id of the DSQ |
| 8791 | * @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs | ||
| 8636 | * | 8792 | * |
| 8637 | * Return the number of tasks in the DSQ matching @dsq_id. If not found, | 8793 | * Return the number of tasks in the DSQ matching @dsq_id. If not found, |
| 8638 | * -%ENOENT is returned. | 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 | struct scx_sched *sch; | 8798 | struct scx_sched *sch; |
| 8643 | struct scx_dispatch_q *dsq; | 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 | preempt_disable(); | 8802 | preempt_disable(); |
| 8647 | 8803 | ||
| 8648 | sch = rcu_dereference_sched(scx_root); | 8804 | sch = scx_prog_sched(aux); |
| 8649 | if (unlikely(!sch)) { | 8805 | if (unlikely(!sch)) { |
| 8650 | ret = -ENODEV; | 8806 | ret = -ENODEV; |
| 8651 | goto out; | 8807 | goto out; |
| @@ -8677,21 +8833,21 @@ out: · 25 unmodified lines | |||
| 8677 | /** | 8833 | /** |
| 8678 | * scx_bpf_destroy_dsq - Destroy a custom DSQ | 8834 | * scx_bpf_destroy_dsq - Destroy a custom DSQ |
| 8679 | * @dsq_id: DSQ to destroy | 8835 | * @dsq_id: DSQ to destroy |
| 8836 | * @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs | ||
| 8680 | * | 8837 | * |
| 8681 | * Destroy the custom DSQ identified by @dsq_id. Only DSQs created with | 8838 | * Destroy the custom DSQ identified by @dsq_id. Only DSQs created with |
| 8682 | * scx_bpf_create_dsq() can be destroyed. The caller must ensure that the DSQ is | 8839 | * scx_bpf_create_dsq() can be destroyed. The caller must ensure that the DSQ is |
| 8683 | * empty and no further tasks are dispatched to it. Ignored if called on a DSQ | 8840 | * empty and no further tasks are dispatched to it. Ignored if called on a DSQ |
| 8684 | * which doesn't exist. Can be called from any online scx_ops operations. | 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 | struct scx_sched *sch; | 8845 | struct scx_sched *sch; |
| 8689 | 8846 | ||
| 8690 | rcu_read_lock(); | 8847 | guard(rcu)(); |
| 8691 | sch = rcu_dereference(scx_root); | 8848 | sch = scx_prog_sched(aux); |
| 8692 | if (sch) | 8849 | if (sch) |
| 8693 | destroy_dsq(sch, dsq_id); | 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 | BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_IMPLICIT_ARGS | KF_RCU); | 9601 | BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_IMPLICIT_ARGS | KF_RCU); |
| 9446 | BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_IMPLICIT_ARGS | KF_RCU); | 9602 | BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_IMPLICIT_ARGS | KF_RCU); |
| 9447 | BTF_ID_FLAGS(func, scx_bpf_kick_cpu, KF_IMPLICIT_ARGS) | 9603 | BTF_ID_FLAGS(func, scx_bpf_kick_cpu, KF_IMPLICIT_ARGS) |
| 9448 | BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued) | 9604 | BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued, KF_IMPLICIT_ARGS) |
| 9449 | BTF_ID_FLAGS(func, scx_bpf_destroy_dsq) | 9605 | BTF_ID_FLAGS(func, scx_bpf_destroy_dsq, KF_IMPLICIT_ARGS) |
| 9450 | BTF_ID_FLAGS(func, scx_bpf_dsq_peek, KF_IMPLICIT_ARGS | KF_RCU_PROTECTED | KF_RET_NULL) | 9606 | BTF_ID_FLAGS(func, scx_bpf_dsq_peek, KF_IMPLICIT_ARGS | KF_RCU_PROTECTED | KF_RET_NULL) |
| 9451 | BTF_ID_FLAGS(func, scx_bpf_dsq_reenq, KF_IMPLICIT_ARGS) | 9607 | BTF_ID_FLAGS(func, scx_bpf_dsq_reenq, KF_IMPLICIT_ARGS) |
| 9452 | BTF_ID_FLAGS(func, scx_bpf_reenqueue_local___v2, KF_IMPLICIT_ARGS) | 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 | static const struct btf_kfunc_id_set scx_kfunc_set_any = { | 9635 | static const struct btf_kfunc_id_set scx_kfunc_set_any = { |
| 9480 | .owner = THIS_MODULE, | 9636 | .owner = THIS_MODULE, |
| 9481 | .set = &scx_kfunc_ids_any, | 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 | 9686 | * Verifier-time filter for SCX kfuncs. Registered via the .filter field on |
| 9530 | * .filter field on each per-group btf_kfunc_id_set. The BPF core invokes this | 9687 | * each per-group btf_kfunc_id_set. The BPF core invokes this for every kfunc |
| 9531 | * for every kfunc call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or | 9688 | * call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or |
| 9532 | * BPF_PROG_TYPE_SYSCALL), regardless of which set originally introduced the | 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. | 9690 | * kfunc - so the filter must short-circuit on kfuncs it doesn't govern by |
| 9534 | * scx_kfunc_ids_any) by falling through to "allow" when none of the | 9691 | * falling through to "allow" when none of the SCX sets contain the kfunc. |
| 9535 | * context-sensitive sets contain the kfunc. | ||
| 9536 | */ | 9692 | */ |
| 9537 | int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id) | 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 | bool in_enqueue = btf_id_set8_contains(&scx_kfunc_ids_enqueue_dispatch, kfunc_id); | 9697 | bool in_enqueue = btf_id_set8_contains(&scx_kfunc_ids_enqueue_dispatch, kfunc_id); |
| 9542 | bool in_dispatch = btf_id_set8_contains(&scx_kfunc_ids_dispatch, kfunc_id); | 9698 | bool in_dispatch = btf_id_set8_contains(&scx_kfunc_ids_dispatch, kfunc_id); |
| 9543 | bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id); | 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 | u32 moff, flags; | 9702 | u32 moff, flags; |
| 9545 | 9703 | ||
| 9546 | /* Not a context-sensitive kfunc (e.g. from scx_kfunc_ids_any) - allow. */ | 9704 | /* Not an SCX kfunc - allow. */ |
| 9547 | if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch || in_cpu_release)) | 9705 | if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch || |
| 9706 | in_cpu_release || in_idle || in_any)) | ||
| 9548 | return 0; | 9707 | return 0; |
| 9549 | 9708 | ||
| 9550 | /* SYSCALL progs (e.g. BPF test_run()) may call unlocked and select_cpu kfuncs. */ | 9709 | /* SYSCALL progs (e.g. BPF test_run()) may call unlocked and select_cpu kfuncs. */ |
| 9551 | if (prog->type == BPF_PROG_TYPE_SYSCALL) | 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 | if (prog->type != BPF_PROG_TYPE_STRUCT_OPS) | 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 | * add_subprog_and_kfunc() collects all kfunc calls, including dead code | 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 | return 0; | 9724 | return 0; |
| 9566 | 9725 | ||
| 9567 | /* | 9726 | /* |
| 9568 | * Non-SCX struct_ops: only unlocked kfuncs are safe. The other | 9727 | * Non-SCX struct_ops: SCX kfuncs are not permitted. |
| 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. | ||
| 9571 | */ | 9728 | */ |
| 9572 | if (prog->aux->st_ops != &bpf_sched_ext_ops) | 9729 | if (prog->aux->st_ops != &bpf_sched_ext_ops) |
| 9573 | return in_unlocked ? 0 : -EACCES; | 9730 | return -EACCES; |
| 9574 | 9731 | ||
| 9575 | /* SCX struct_ops: check the per-op allow list. */ | 9732 | /* SCX struct_ops: check the per-op allow list. */ |
| 9733 | if (in_any || in_idle) | ||
| 9734 | return 0; | ||
| 9735 | |||
| 9576 | moff = prog->aux->attach_st_ops_member_off; | 9736 | moff = prog->aux->attach_st_ops_member_off; |
| 9577 | flags = scx_kf_allow_flags[SCX_MOFF_IDX(moff)]; | 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 | return ret; | 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 | return 0; | 9819 | return 0; |
| 9666 | } | 9820 | } |
| 9667 | __initcall(scx_init); | 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 | * Accessing p->cpus_ptr / p->nr_cpus_allowed needs either @p's rq | 927 | * Accessing p->cpus_ptr / p->nr_cpus_allowed needs either @p's rq |
| 928 | * lock or @p's pi_lock. Three cases: | 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 | * - other rq-locked SCX op: scx_locked_rq() points at the held rq. | 933 | * - other rq-locked SCX op: scx_locked_rq() points at the held rq. |
| 932 | * - truly unlocked (UNLOCKED ops, SYSCALL, non-SCX struct_ops): | 934 | * - truly unlocked (UNLOCKED ops, SYSCALL, non-SCX struct_ops): |
| 933 | * nothing held, take pi_lock ourselves. | 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 | if (this_rq()->scx.in_select_cpu) { | 940 | if (this_rq()->scx.in_select_cpu) { |
| 941 | if (!scx_kf_arg_task_ok(sch, p)) | ||
| 942 | return -EINVAL; | ||
| 936 | lockdep_assert_held(&p->pi_lock); | 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 | raw_spin_lock_irqsave(&p->pi_lock, irq_flags); | 948 | raw_spin_lock_irqsave(&p->pi_lock, irq_flags); |
| 939 | we_locked = true; | 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 | raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags); | 970 | raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags); |
| 961 | 971 | ||
| 962 | return cpu; | 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 | static const struct btf_kfunc_id_set scx_kfunc_set_idle = { | 1482 | static const struct btf_kfunc_id_set scx_kfunc_set_idle = { |
| 1468 | .owner = THIS_MODULE, | 1483 | .owner = THIS_MODULE, |
| 1469 | .set = &scx_kfunc_ids_idle, | 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 | struct sched_ext_ops; | 13 | struct sched_ext_ops; |
| 14 | 14 | ||
| 15 | extern struct btf_id_set8 scx_kfunc_ids_idle; | ||
| 15 | extern struct btf_id_set8 scx_kfunc_ids_select_cpu; | 16 | extern struct btf_id_set8 scx_kfunc_ids_select_cpu; |
| 16 | 17 | ||
| 17 | void scx_idle_update_selcpu_topology(struct sched_ext_ops *ops); | 18 | void scx_idle_update_selcpu_topology(struct sched_ext_ops *ops); |
| @@ -1075,6 +1075,8 @@ struct scx_sched { · 1074 unmodified lines | |||
| 1075 | struct irq_work disable_irq_work; | 1075 | struct irq_work disable_irq_work; |
| 1076 | struct kthread_work disable_work; | 1076 | struct kthread_work disable_work; |
| 1077 | struct timer_list bypass_lb_timer; | 1077 | struct timer_list bypass_lb_timer; |
| 1078 | cpumask_var_t bypass_lb_donee_cpumask; | ||
| 1079 | cpumask_var_t bypass_lb_resched_cpumask; | ||
| 1078 | struct rcu_work rcu_work; | 1080 | struct rcu_work rcu_work; |
| 1079 | 1081 | ||
| 1080 | /* all ancestors including self */ | 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 | * Similarly, check that the entity didn't gain positive lag when DELAY_ZERO | 847 | * Similarly, check that the entity didn't gain positive lag when DELAY_ZERO |
| 848 | * is set. | 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 | static __always_inline | 858 | static __always_inline |
| 853 | bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se) | 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)); | 861 | u64 avruntime = avg_vruntime(cfs_rq); |
| 856 | bool ret; | 862 | s64 vlag = entity_lag(cfs_rq, se, avruntime); |
| 857 | 863 | ||
| 858 | WARN_ON_ONCE(!se->on_rq); | 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 | if (sched_feat(DELAY_ZERO)) | 869 | if (sched_feat(DELAY_ZERO)) |
| 864 | vlag = min(vlag, 0); | 870 | vlag = min(vlag, 0); |
| 865 | } | 871 | } |
| 866 | ret = (vlag == se->vlag); | ||
| 867 | se->vlag = vlag; | 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 | * Which allows tree pruning through eligibility. | 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 | struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node; | 1109 | struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node; |
| 1105 | struct sched_entity *se = __pick_first_entity(cfs_rq); | 1110 | struct sched_entity *se = __pick_first_entity(cfs_rq); |
| @@ -1170,11 +1175,6 @@ found: · 64 unmodified lines | |||
| 1170 | return best; | 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 | struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) | 1178 | struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) |
| 1179 | { | 1179 | { |
| 1180 | struct rb_node *last = rb_last(&cfs_rq->tasks_timeline.rb_root); | 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 | * 4) do not run the "skip" process, if something else is available | 5749 | * 4) do not run the "skip" process, if something else is available |
| 5750 | */ | 5750 | */ |
| 5751 | static struct sched_entity * | 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 | struct sched_entity *se; | 5754 | struct sched_entity *se; |
| 5755 | 5755 | ||
| 5756 | se = pick_eevdf(cfs_rq); | 5756 | se = pick_eevdf(cfs_rq, protect); |
| 5757 | if (se->sched_delayed) { | 5757 | if (se->sched_delayed) { |
| 5758 | dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); | 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 | enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK; | 9028 | enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK; |
| 9029 | struct task_struct *donor = rq->donor; | 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 | struct cfs_rq *cfs_rq = task_cfs_rq(donor); | 9031 | struct cfs_rq *cfs_rq = task_cfs_rq(donor); |
| 9032 | int cse_is_idle, pse_is_idle; | 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 | pick: | 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) | 9150 | if (!nse) |
| 9145 | goto preempt; | 9151 | goto pick; |
| 9146 | 9152 | ||
| 9147 | if (sched_feat(RUN_TO_PARITY)) | 9153 | if (sched_feat(RUN_TO_PARITY)) |
| 9148 | update_protect_slice(cfs_rq, se); | 9154 | update_protect_slice(cfs_rq, se); |
| @@ -9179,7 +9185,7 @@ again: · 30 unmodified lines | |||
| 9179 | 9185 | ||
| 9180 | throttled |= check_cfs_rq_runtime(cfs_rq); | 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 | if (!se) | 9189 | if (!se) |
| 9184 | goto again; | 9190 | goto again; |
| 9185 | cfs_rq = group_cfs_rq(se); | 9191 | cfs_rq = group_cfs_rq(se); |
| @@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void) · 372 unmodified lines | |||
| 373 | int ret; | 373 | int ret; |
| 374 | 374 | ||
| 375 | ret = register_stat_tracer(&annotated_branch_stats); | 375 | ret = register_stat_tracer(&annotated_branch_stats); |
| 376 | if (!ret) { | 376 | if (ret) { |
| 377 | printk(KERN_WARNING "Warning: could not register " | 377 | printk(KERN_WARNING "Warning: could not register " |
| 378 | "annotated branches stats\n"); | 378 | "annotated branches stats\n"); |
| 379 | return 1; | 379 | return ret; |
| 380 | } | 380 | } |
| 381 | return 0; | 381 | return 0; |
| 382 | } | 382 | } |
| @@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void) · 55 unmodified lines | |||
| 438 | int ret; | 438 | int ret; |
| 439 | 439 | ||
| 440 | ret = register_stat_tracer(&all_branch_stats); | 440 | ret = register_stat_tracer(&all_branch_stats); |
| 441 | if (!ret) { | 441 | if (ret) { |
| 442 | printk(KERN_WARNING "Warning: could not register " | 442 | printk(KERN_WARNING "Warning: could not register " |
| 443 | "all branches stats\n"); | 443 | "all branches stats\n"); |
| 444 | return 1; | 444 | return ret; |
| 445 | } | 445 | } |
| 446 | return 0; | 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 | parg->offset = *size; | 1523 | parg->offset = *size; |
| 1524 | *size += parg->type->size * (parg->count ?: 1); | 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 | if (parg->count) { | 1532 | if (parg->count) { |
| 1527 | len = strlen(parg->type->fmttype) + 6; | 1533 | len = strlen(parg->type->fmttype) + 6; |
| 1528 | parg->fmt = kmalloc(len, GFP_KERNEL); | 1534 | parg->fmt = kmalloc(len, GFP_KERNEL); |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | |||
| 38 | #define MAX_BTF_ARGS_LEN 128 | 38 | #define MAX_BTF_ARGS_LEN 128 |
| 39 | #define MAX_DENTRY_ARGS_LEN 256 | 39 | #define MAX_DENTRY_ARGS_LEN 256 |
| 40 | #define MAX_STRING_SIZE PATH_MAX | 40 | #define MAX_STRING_SIZE PATH_MAX |
| 41 | #define MAX_PROBE_EVENT_SIZE 3072 | ||
| 41 | 42 | ||
| 42 | /* Reserved field names */ | 43 | /* Reserved field names */ |
| 43 | #define FIELD_STRING_IP "__probe_ip" | 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 | C(BAD_TYPE4STR, "This type does not fit for string."),\ | 562 | C(BAD_TYPE4STR, "This type does not fit for string."),\ |
| 562 | C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\ | 563 | C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\ |
| 563 | C(TOO_MANY_ARGS, "Too many arguments are specified"), \ | 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 | #undef C | 568 | #undef C |
| 567 | #define C(a, b) TP_ERR_##a | 569 | #define C(a, b) TP_ERR_##a |
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Maple Tree implementation | 3 | * Maple Tree implementation |
| 4 | * Copyright (c) 2018-2022 Oracle Corporation | 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 | * Matthew Wilcox <willy@infradead.org> | 6 | * Matthew Wilcox <willy@infradead.org> |
| 7 | * Copyright (c) 2023 ByteDance | 7 | * Copyright (c) 2023 ByteDance |
| 8 | * Author: Peng Zhang <zhangpeng.00@bytedance.com> | 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 | mutex_unlock(&ht->mutex); | 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 | if (err) | 452 | if (err) |
| 445 | schedule_work(&ht->run_work); | 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 | static int rhashtable_insert_rehash(struct rhashtable *ht, | 471 | static int rhashtable_insert_rehash(struct rhashtable *ht, |
| 449 | struct bucket_table *tbl) | 472 | struct bucket_table *tbl) |
| 450 | { | 473 | { |
| @@ -477,7 +500,7 @@ static int rhashtable_insert_rehash(struct rhashtable *ht, · 26 unmodified lines | |||
| 477 | if (err == -EEXIST) | 500 | if (err == -EEXIST) |
| 478 | err = 0; | 501 | err = 0; |
| 479 | } else | 502 | } else |
| 480 | schedule_work(&ht->run_work); | 503 | irq_work_queue(&ht->run_irq_work); |
| 481 | 504 | ||
| 482 | return err; | 505 | return err; |
| 483 | 506 | ||
| @@ -488,7 +511,7 @@ fail: · 4 unmodified lines | |||
| 488 | 511 | ||
| 489 | /* Schedule async rehash to retry allocation in process context. */ | 512 | /* Schedule async rehash to retry allocation in process context. */ |
| 490 | if (err == -ENOMEM) | 513 | if (err == -ENOMEM) |
| 491 | schedule_work(&ht->run_work); | 514 | irq_work_queue(&ht->run_irq_work); |
| 492 | 515 | ||
| 493 | return err; | 516 | return err; |
| 494 | } | 517 | } |
| @@ -538,7 +561,7 @@ static void *rhashtable_lookup_one(struct rhashtable *ht, · 43 unmodified lines | |||
| 538 | return NULL; | 561 | return NULL; |
| 539 | } | 562 | } |
| 540 | 563 | ||
| 541 | if (elasticity <= 0) | 564 | if (elasticity <= 0 && !ht->p.insecure_elasticity) |
| 542 | return ERR_PTR(-EAGAIN); | 565 | return ERR_PTR(-EAGAIN); |
| 543 | 566 | ||
| 544 | return ERR_PTR(-ENOENT); | 567 | return ERR_PTR(-ENOENT); |
| @@ -568,7 +591,8 @@ static struct bucket_table *rhashtable_insert_one( · 23 unmodified lines | |||
| 568 | if (unlikely(rht_grow_above_max(ht, tbl))) | 591 | if (unlikely(rht_grow_above_max(ht, tbl))) |
| 569 | return ERR_PTR(-E2BIG); | 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 | return ERR_PTR(-EAGAIN); | 596 | return ERR_PTR(-EAGAIN); |
| 573 | 597 | ||
| 574 | head = rht_ptr(bkt, tbl, hash); | 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 | rht_unlock(tbl, bkt, flags); | 653 | rht_unlock(tbl, bkt, flags); |
| 630 | 654 | ||
| 631 | if (inserted && rht_grow_above_75(ht, tbl)) | 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 | } while (!IS_ERR_OR_NULL(new_tbl)); | 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 | RCU_INIT_POINTER(ht->tbl, tbl); | 1108 | RCU_INIT_POINTER(ht->tbl, tbl); |
| 1085 | 1109 | ||
| 1086 | INIT_WORK(&ht->run_work, rht_deferred_worker); | 1110 | INIT_WORK(&ht->run_work, rht_deferred_worker); |
| 1111 | init_irq_work(&ht->run_irq_work, rht_deferred_irq_work); | ||
| 1087 | 1112 | ||
| 1088 | return 0; | 1113 | return 0; |
| 1089 | } | 1114 | } |
| @@ -1149,6 +1174,7 @@ void rhashtable_free_and_destroy(struct rhashtable *ht, · 59 unmodified lines | |||
| 1149 | struct bucket_table *tbl, *next_tbl; | 1174 | struct bucket_table *tbl, *next_tbl; |
| 1150 | unsigned int i; | 1175 | unsigned int i; |
| 1151 | 1176 | ||
| 1177 | irq_work_sync(&ht->run_irq_work); | ||
| 1152 | cancel_work_sync(&ht->run_work); | 1178 | cancel_work_sync(&ht->run_work); |
| 1153 | 1179 | ||
| 1154 | mutex_lock(&ht->mutex); | 1180 | mutex_lock(&ht->mutex); |
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * test_maple_tree.c: Test the maple tree API | 3 | * test_maple_tree.c: Test the maple tree API |
| 4 | * Copyright (c) 2018-2022 Oracle Corporation | 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 | * Any tests that only require the interface of the tree. | 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 | module_init(maple_tree_seed); | 4022 | module_init(maple_tree_seed); |
| 4023 | module_exit(maple_tree_harvest); | 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 | MODULE_DESCRIPTION("maple tree API test module"); | 4025 | MODULE_DESCRIPTION("maple tree API test module"); |
| 4026 | MODULE_LICENSE("GPL"); | 4026 | MODULE_LICENSE("GPL"); |
| @@ -161,15 +161,6 @@ module_param(monitor_region_end, ulong, 0600); · 160 unmodified lines | |||
| 161 | */ | 161 | */ |
| 162 | static unsigned long addr_unit __read_mostly = 1; | 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 | static struct damos_stat damon_lru_sort_hot_stat; | 164 | static struct damos_stat damon_lru_sort_hot_stat; |
| 174 | DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat, | 165 | DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat, |
| 175 | lru_sort_tried_hot_regions, lru_sorted_hot_regions, | 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 | int err; | 378 | int err; |
| 388 | 379 | ||
| 389 | if (!on) { | 380 | if (!on) |
| 390 | err = damon_stop(&ctx, 1); | 381 | return damon_stop(&ctx, 1); |
| 391 | if (!err) | ||
| 392 | kdamond_pid = -1; | ||
| 393 | return err; | ||
| 394 | } | ||
| 395 | 382 | ||
| 396 | err = damon_lru_sort_apply_parameters(); | 383 | err = damon_lru_sort_apply_parameters(); |
| 397 | if (err) | 384 | if (err) |
| @@ -400,9 +387,6 @@ static int damon_lru_sort_turn(bool on) · 2 unmodified lines | |||
| 400 | err = damon_start(&ctx, 1, true); | 387 | err = damon_start(&ctx, 1, true); |
| 401 | if (err) | 388 | if (err) |
| 402 | return err; | 389 | return err; |
| 403 | kdamond_pid = damon_kdamond_pid(ctx); | ||
| 404 | if (kdamond_pid < 0) | ||
| 405 | return kdamond_pid; | ||
| 406 | return damon_call(ctx, &call_control); | 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 | MODULE_PARM_DESC(addr_unit, | 414 | MODULE_PARM_DESC(addr_unit, |
| 431 | "Scale factor for DAMON_LRU_SORT to ops address conversion (default: 1)"); | 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 | static int damon_lru_sort_enabled_store(const char *val, | 424 | static int damon_lru_sort_enabled_store(const char *val, |
| 434 | const struct kernel_param *kp) | 425 | const struct kernel_param *kp) |
| 435 | { | 426 | { |
| 436 | bool is_enabled = enabled; | ||
| 437 | bool enable; | ||
| 438 | int err; | 427 | int err; |
| 439 | 428 | ||
| 440 | err = kstrtobool(val, &enable); | 429 | err = kstrtobool(val, &enabled); |
| 441 | if (err) | 430 | if (err) |
| 442 | return err; | 431 | return err; |
| 443 | 432 | ||
| 444 | if (is_enabled == enable) | 433 | if (damon_lru_sort_enabled() == enabled) |
| 445 | return 0; | 434 | return 0; |
| 446 | 435 | ||
| 447 | /* Called before init function. The function will handle this. */ | 436 | /* Called before init function. The function will handle this. */ |
| 448 | if (!damon_initialized()) | 437 | if (!damon_initialized()) |
| 449 | goto set_param_out; | 438 | return 0; |
| 450 | 439 | ||
| 451 | err = damon_lru_sort_turn(enable); | 440 | return damon_lru_sort_turn(enabled); |
| 452 | if (err) | 441 | } |
| 453 | return err; | ||
| 454 | 442 | ||
| 455 | set_param_out: | 443 | static int damon_lru_sort_enabled_load(char *buffer, |
| 456 | enabled = enable; | 444 | const struct kernel_param *kp) |
| 457 | return err; | 445 | { |
| 446 | return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N'); | ||
| 458 | } | 447 | } |
| 459 | 448 | ||
| 460 | static const struct kernel_param_ops enabled_param_ops = { | 449 | static const struct kernel_param_ops enabled_param_ops = { |
| 461 | .set = damon_lru_sort_enabled_store, | 450 | .set = damon_lru_sort_enabled_store, |
| 462 | .get = param_get_bool, | 451 | .get = damon_lru_sort_enabled_load, |
| 463 | }; | 452 | }; |
| 464 | 453 | ||
| 465 | module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); | 454 | module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); |
| 466 | MODULE_PARM_DESC(enabled, | 455 | MODULE_PARM_DESC(enabled, |
| 467 | "Enable or disable DAMON_LRU_SORT (default: disabled)"); | 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 | static int __init damon_lru_sort_init(void) | 494 | static int __init damon_lru_sort_init(void) |
| 470 | { | 495 | { |
| 471 | int err; | 496 | int err; |
| @@ -144,15 +144,6 @@ static unsigned long addr_unit __read_mostly = 1; · 143 unmodified lines | |||
| 144 | static bool skip_anon __read_mostly; | 144 | static bool skip_anon __read_mostly; |
| 145 | module_param(skip_anon, bool, 0600); | 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 | static struct damos_stat damon_reclaim_stat; | 147 | static struct damos_stat damon_reclaim_stat; |
| 157 | DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat, | 148 | DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat, |
| 158 | reclaim_tried_regions, reclaimed_regions, quota_exceeds); | 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 | int err; | 280 | int err; |
| 290 | 281 | ||
| 291 | if (!on) { | 282 | if (!on) |
| 292 | err = damon_stop(&ctx, 1); | 283 | return damon_stop(&ctx, 1); |
| 293 | if (!err) | ||
| 294 | kdamond_pid = -1; | ||
| 295 | return err; | ||
| 296 | } | ||
| 297 | 284 | ||
| 298 | err = damon_reclaim_apply_parameters(); | 285 | err = damon_reclaim_apply_parameters(); |
| 299 | if (err) | 286 | if (err) |
| @@ -302,9 +289,6 @@ static int damon_reclaim_turn(bool on) · 2 unmodified lines | |||
| 302 | err = damon_start(&ctx, 1, true); | 289 | err = damon_start(&ctx, 1, true); |
| 303 | if (err) | 290 | if (err) |
| 304 | return err; | 291 | return err; |
| 305 | kdamond_pid = damon_kdamond_pid(ctx); | ||
| 306 | if (kdamond_pid < 0) | ||
| 307 | return kdamond_pid; | ||
| 308 | return damon_call(ctx, &call_control); | 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 | MODULE_PARM_DESC(addr_unit, | 316 | MODULE_PARM_DESC(addr_unit, |
| 333 | "Scale factor for DAMON_RECLAIM to ops address conversion (default: 1)"); | 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 | static int damon_reclaim_enabled_store(const char *val, | 326 | static int damon_reclaim_enabled_store(const char *val, |
| 336 | const struct kernel_param *kp) | 327 | const struct kernel_param *kp) |
| 337 | { | 328 | { |
| 338 | bool is_enabled = enabled; | ||
| 339 | bool enable; | ||
| 340 | int err; | 329 | int err; |
| 341 | 330 | ||
| 342 | err = kstrtobool(val, &enable); | 331 | err = kstrtobool(val, &enabled); |
| 343 | if (err) | 332 | if (err) |
| 344 | return err; | 333 | return err; |
| 345 | 334 | ||
| 346 | if (is_enabled == enable) | 335 | if (damon_reclaim_enabled() == enabled) |
| 347 | return 0; | 336 | return 0; |
| 348 | 337 | ||
| 349 | /* Called before init function. The function will handle this. */ | 338 | /* Called before init function. The function will handle this. */ |
| 350 | if (!damon_initialized()) | 339 | if (!damon_initialized()) |
| 351 | goto set_param_out; | 340 | return 0; |
| 352 | 341 | ||
| 353 | err = damon_reclaim_turn(enable); | 342 | return damon_reclaim_turn(enabled); |
| 354 | if (err) | 343 | } |
| 355 | return err; | ||
| 356 | 344 | ||
| 357 | set_param_out: | 345 | static int damon_reclaim_enabled_load(char *buffer, |
| 358 | enabled = enable; | 346 | const struct kernel_param *kp) |
| 359 | return err; | 347 | { |
| 348 | return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N'); | ||
| 360 | } | 349 | } |
| 361 | 350 | ||
| 362 | static const struct kernel_param_ops enabled_param_ops = { | 351 | static const struct kernel_param_ops enabled_param_ops = { |
| 363 | .set = damon_reclaim_enabled_store, | 352 | .set = damon_reclaim_enabled_store, |
| 364 | .get = param_get_bool, | 353 | .get = damon_reclaim_enabled_load, |
| 365 | }; | 354 | }; |
| 366 | 355 | ||
| 367 | module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); | 356 | module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); |
| 368 | MODULE_PARM_DESC(enabled, | 357 | MODULE_PARM_DESC(enabled, |
| 369 | "Enable or disable DAMON_RECLAIM (default: disabled)"); | 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 | static int __init damon_reclaim_init(void) | 396 | static int __init damon_reclaim_init(void) |
| 372 | { | 397 | { |
| 373 | int err; | 398 | int err; |
| @@ -19,14 +19,17 @@ · 18 unmodified lines | |||
| 19 | static int damon_stat_enabled_store( | 19 | static int damon_stat_enabled_store( |
| 20 | const char *val, const struct kernel_param *kp); | 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 | static const struct kernel_param_ops enabled_param_ops = { | 25 | static const struct kernel_param_ops enabled_param_ops = { |
| 23 | .set = damon_stat_enabled_store, | 26 | .set = damon_stat_enabled_store, |
| 24 | .get = param_get_bool, | 27 | .get = damon_stat_enabled_load, |
| 25 | }; | 28 | }; |
| 26 | 29 | ||
| 27 | static bool enabled __read_mostly = IS_ENABLED( | 30 | static bool enabled __read_mostly = IS_ENABLED( |
| 28 | CONFIG_DAMON_STAT_ENABLED_DEFAULT); | 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 | MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT"); | 33 | MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT"); |
| 31 | 34 | ||
| 32 | static unsigned long estimated_memory_bandwidth __read_mostly; | 35 | static unsigned long estimated_memory_bandwidth __read_mostly; |
| @@ -273,17 +276,23 @@ static void damon_stat_stop(void) · 240 unmodified lines | |||
| 273 | damon_stat_context = NULL; | 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 | static int damon_stat_enabled_store( | 286 | static int damon_stat_enabled_store( |
| 277 | const char *val, const struct kernel_param *kp) | 287 | const char *val, const struct kernel_param *kp) |
| 278 | { | 288 | { |
| 279 | bool is_enabled = enabled; | ||
| 280 | int err; | 289 | int err; |
| 281 | 290 | ||
| 282 | err = kstrtobool(val, &enabled); | 291 | err = kstrtobool(val, &enabled); |
| 283 | if (err) | 292 | if (err) |
| 284 | return err; | 293 | return err; |
| 285 | 294 | ||
| 286 | if (is_enabled == enabled) | 295 | if (damon_stat_enabled() == enabled) |
| 287 | return 0; | 296 | return 0; |
| 288 | 297 | ||
| 289 | if (!damon_initialized()) | 298 | if (!damon_initialized()) |
| @@ -293,16 +302,17 @@ static int damon_stat_enabled_store( · 3 unmodified lines | |||
| 293 | */ | 302 | */ |
| 294 | return 0; | 303 | return 0; |
| 295 | 304 | ||
| 296 | if (enabled) { | 305 | if (enabled) |
| 297 | err = damon_stat_start(); | 306 | return damon_stat_start(); |
| 298 | if (err) | ||
| 299 | enabled = false; | ||
| 300 | return err; | ||
| 301 | } | ||
| 302 | damon_stat_stop(); | 307 | damon_stat_stop(); |
| 303 | return 0; | 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 | static int __init damon_stat_init(void) | 316 | static int __init damon_stat_init(void) |
| 307 | { | 317 | { |
| 308 | int err = 0; | 318 | int err = 0; |
| @@ -533,9 +533,14 @@ static ssize_t memcg_path_show(struct kobject *kobj, · 532 unmodified lines | |||
| 533 | { | 533 | { |
| 534 | struct damon_sysfs_scheme_filter *filter = container_of(kobj, | 534 | struct damon_sysfs_scheme_filter *filter = container_of(kobj, |
| 535 | struct damon_sysfs_scheme_filter, kobj); | 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 | filter->memcg_path ? filter->memcg_path : ""); | 541 | filter->memcg_path ? filter->memcg_path : ""); |
| 542 | mutex_unlock(&damon_sysfs_lock); | ||
| 543 | return len; | ||
| 539 | } | 544 | } |
| 540 | 545 | ||
| 541 | static ssize_t memcg_path_store(struct kobject *kobj, | 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 | return -ENOMEM; | 555 | return -ENOMEM; |
| 551 | 556 | ||
| 552 | strscpy(path, buf, count + 1); | 557 | strscpy(path, buf, count + 1); |
| 558 | if (!mutex_trylock(&damon_sysfs_lock)) { | ||
| 559 | kfree(path); | ||
| 560 | return -EBUSY; | ||
| 561 | } | ||
| 553 | kfree(filter->memcg_path); | 562 | kfree(filter->memcg_path); |
| 554 | filter->memcg_path = path; | 563 | filter->memcg_path = path; |
| 564 | mutex_unlock(&damon_sysfs_lock); | ||
| 555 | return count; | 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 | struct damos_sysfs_quota_goal *goal = container_of(kobj, | 1198 | struct damos_sysfs_quota_goal *goal = container_of(kobj, |
| 1189 | struct damos_sysfs_quota_goal, kobj); | 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 | static ssize_t path_store(struct kobject *kobj, | 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 | return -ENOMEM; | 1218 | return -ENOMEM; |
| 1204 | 1219 | ||
| 1205 | strscpy(path, buf, count + 1); | 1220 | strscpy(path, buf, count + 1); |
| 1221 | if (!mutex_trylock(&damon_sysfs_lock)) { | ||
| 1222 | kfree(path); | ||
| 1223 | return -EBUSY; | ||
| 1224 | } | ||
| 1206 | kfree(goal->path); | 1225 | kfree(goal->path); |
| 1207 | goal->path = path; | 1226 | goal->path = path; |
| 1227 | mutex_unlock(&damon_sysfs_lock); | ||
| 1208 | return count; | 1228 | return count; |
| 1209 | } | 1229 | } |
| 1210 | 1230 | ||
| @@ -204,6 +204,7 @@ void __init hugetlb_cma_reserve(void) · 203 unmodified lines | |||
| 204 | */ | 204 | */ |
| 205 | per_node = DIV_ROUND_UP(hugetlb_cma_size, | 205 | per_node = DIV_ROUND_UP(hugetlb_cma_size, |
| 206 | nodes_weight(hugetlb_bootmem_nodes)); | 206 | nodes_weight(hugetlb_bootmem_nodes)); |
| 207 | per_node = round_up(per_node, PAGE_SIZE << order); | ||
| 207 | pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n", | 208 | pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n", |
| 208 | hugetlb_cma_size / SZ_1M, per_node / SZ_1M); | 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 | * Used in mod_memcg_state() and mod_memcg_lruvec_state() to avoid race with | 805 | * Used in mod_memcg_state() and mod_memcg_lruvec_state() to avoid race with |
| 806 | * reparenting of non-hierarchical state_locals. | 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 | return memcg; | 814 | return memcg; |
| 815 | } | ||
| 812 | 816 | ||
| 813 | rcu_read_lock(); | 817 | rcu_read_lock(); |
| 818 | *rcu_locked = true; | ||
| 814 | 819 | ||
| 815 | while (memcg_is_dying(memcg)) | 820 | while (memcg_is_dying(memcg)) |
| 816 | memcg = parent_mem_cgroup(memcg); | 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 | return memcg; | 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 | return; | 829 | return; |
| 825 | 830 | ||
| 826 | rcu_read_unlock(); | 831 | rcu_read_unlock(); |
| 827 | } | 832 | } |
| 828 | #else | 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 | return memcg; | 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 | #endif | 843 | #endif |
| @@ -865,12 +871,14 @@ static void __mod_memcg_state(struct mem_cgroup *memcg, · 27 unmodified lines | |||
| 865 | void mod_memcg_state(struct mem_cgroup *memcg, enum memcg_stat_item idx, | 871 | void mod_memcg_state(struct mem_cgroup *memcg, enum memcg_stat_item idx, |
| 866 | int val) | 872 | int val) |
| 867 | { | 873 | { |
| 874 | bool rcu_locked = false; | ||
| 875 | |||
| 868 | if (mem_cgroup_disabled()) | 876 | if (mem_cgroup_disabled()) |
| 869 | return; | 877 | return; |
| 870 | 878 | ||
| 871 | memcg = get_non_dying_memcg_start(memcg); | 879 | memcg = get_non_dying_memcg_start(memcg, &rcu_locked); |
| 872 | __mod_memcg_state(memcg, idx, val); | 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 | #ifdef CONFIG_MEMCG_V1 | 884 | #ifdef CONFIG_MEMCG_V1 |
| @@ -933,14 +941,15 @@ static void mod_memcg_lruvec_state(struct lruvec *lruvec, · 56 unmodified lines | |||
| 933 | struct pglist_data *pgdat = lruvec_pgdat(lruvec); | 941 | struct pglist_data *pgdat = lruvec_pgdat(lruvec); |
| 934 | struct mem_cgroup_per_node *pn; | 942 | struct mem_cgroup_per_node *pn; |
| 935 | struct mem_cgroup *memcg; | 943 | struct mem_cgroup *memcg; |
| 944 | bool rcu_locked = false; | ||
| 936 | 945 | ||
| 937 | pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); | 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 | pn = memcg->nodeinfo[pgdat->node_id]; | 948 | pn = memcg->nodeinfo[pgdat->node_id]; |
| 940 | 949 | ||
| 941 | __mod_memcg_lruvec_state(pn, idx, val); | 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 | balance_domain_limits(mdtc, strictlimit); | 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 | wb_start_background_writeback(wb); | 1841 | wb_start_background_writeback(wb); |
| 1840 | 1842 | ||
| 1841 | /* | 1843 | /* |
| @@ -1862,15 +1864,9 @@ free_running: · 20 unmodified lines | |||
| 1862 | * Unconditionally start background writeback if it's not | 1864 | * Unconditionally start background writeback if it's not |
| 1863 | * already in progress. We need to do this because the global | 1865 | * already in progress. We need to do this because the global |
| 1864 | * dirty threshold check above (nr_dirty > gdtc->bg_thresh) | 1866 | * dirty threshold check above (nr_dirty > gdtc->bg_thresh) |
| 1865 | * doesn't account for these cases: | 1867 | * doesn't account for the memcg-based throttling case. memcg |
| 1866 | * | 1868 | * uses its own dirty count and thresholds and can trigger |
| 1867 | * a) strictlimit BDIs: throttling is calculated using per-wb | 1869 | * throttling even when global nr_dirty < gdtc->bg_thresh |
| 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 | ||
| 1874 | * | 1870 | * |
| 1875 | * Writeback needs to be started else the writer stalls in the | 1871 | * Writeback needs to be started else the writer stalls in the |
| 1876 | * throttle loop waiting for dirty pages to be written back | 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 | if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) | 7738 | if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) |
| 7739 | return NULL; | 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 | if (!pcp_allowed_order(order)) | 7745 | if (!pcp_allowed_order(order)) |
| 7741 | return NULL; | 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 | if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) | 5339 | if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) |
| 5340 | return NULL; | 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 | retry: | 5346 | retry: |
| 5343 | if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) | 5347 | if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) |
| 5344 | return NULL; | 5348 | return NULL; |
| @@ -443,8 +443,10 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr) · 442 unmodified lines | |||
| 443 | return ret; | 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 | unsigned long src_addr = state->src_addr; | 450 | unsigned long src_addr = state->src_addr; |
| 449 | void *kaddr; | 451 | void *kaddr; |
| 450 | int err; | 452 | int err; |
| @@ -465,6 +467,14 @@ static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio · 14 unmodified lines | |||
| 465 | if (err) | 467 | if (err) |
| 466 | return err; | 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 | err = mfill_establish_pmd(state); | 478 | err = mfill_establish_pmd(state); |
| 469 | if (err) | 479 | if (err) |
| 470 | return err; | 480 | return err; |
| @@ -1232,7 +1232,7 @@ int __compat_vma_mmap(struct vm_area_desc *desc, · 1231 unmodified lines | |||
| 1232 | /* Update the VMA from the descriptor. */ | 1232 | /* Update the VMA from the descriptor. */ |
| 1233 | compat_set_vma_from_desc(vma, desc); | 1233 | compat_set_vma_from_desc(vma, desc); |
| 1234 | /* Complete any specified mmap actions. */ | 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 | EXPORT_SYMBOL(__compat_vma_mmap); | 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 | static int mmap_action_finish(struct vm_area_struct *vma, | 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 | size_t len; | 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 | /* do_munmap() might take rmap lock, so release if held. */ | 1402 | /* do_munmap() might take rmap lock, so release if held. */ |
| 1402 | maybe_rmap_unlock_action(vma, action); | 1403 | maybe_rmap_unlock_action(vma, action); |
| 1403 | if (!err) | 1404 | /* |
| 1404 | return 0; | 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 | * If an error occurs, unmap the VMA altogether and return an error. We | 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 | * mmap_action_complete - Execute VMA descriptor action. | 1456 | * mmap_action_complete - Execute VMA descriptor action. |
| 1452 | * @vma: The VMA to perform the action upon. | 1457 | * @vma: The VMA to perform the action upon. |
| 1453 | * @action: The action to perform. | 1458 | * @action: The action to perform. |
| 1459 | * @is_compat: Is this being invoked from the compatibility layer? | ||
| 1454 | * | 1460 | * |
| 1455 | * Similar to mmap_action_prepare(). | 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 | int mmap_action_complete(struct vm_area_struct *vma, | 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 | int err = 0; | 1469 | int err = 0; |
| 1463 | 1470 | ||
| @@ -1478,7 +1485,7 @@ int mmap_action_complete(struct vm_area_struct *vma, · 14 unmodified lines | |||
| 1478 | break; | 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 | EXPORT_SYMBOL(mmap_action_complete); | 1490 | EXPORT_SYMBOL(mmap_action_complete); |
| 1484 | #else | 1491 | #else |
| @@ -1500,7 +1507,8 @@ int mmap_action_prepare(struct vm_area_desc *desc) · 15 unmodified lines | |||
| 1500 | EXPORT_SYMBOL(mmap_action_prepare); | 1507 | EXPORT_SYMBOL(mmap_action_prepare); |
| 1501 | 1508 | ||
| 1502 | int mmap_action_complete(struct vm_area_struct *vma, | 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 | int err = 0; | 1513 | int err = 0; |
| 1506 | 1514 | ||
| @@ -1517,7 +1525,7 @@ int mmap_action_complete(struct vm_area_struct *vma, · 10 unmodified lines | |||
| 1517 | break; | 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 | EXPORT_SYMBOL(mmap_action_complete); | 1530 | EXPORT_SYMBOL(mmap_action_complete); |
| 1523 | #endif | 1531 | #endif |
| @@ -2780,7 +2780,8 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, · 2779 unmodified lines | |||
| 2780 | __mmap_complete(&map, vma); | 2780 | __mmap_complete(&map, vma); |
| 2781 | 2781 | ||
| 2782 | if (have_mmap_prepare && allocated_new) { | 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 | if (error) | 2785 | if (error) |
| 2785 | return error; | 2786 | return error; |
| 2786 | } | 2787 | } |
| @@ -4361,7 +4361,7 @@ need_realloc: · 4360 unmodified lines | |||
| 4361 | return NULL; | 4361 | return NULL; |
| 4362 | 4362 | ||
| 4363 | if (p) { | 4363 | if (p) { |
| 4364 | memcpy(n, p, old_size); | 4364 | memcpy(n, p, min(size, old_size)); |
| 4365 | vfree(p); | 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 | for (i = 0; i < owner->area.num_niovs; i++) { | 298 | for (i = 0; i < owner->area.num_niovs; i++) { |
| 299 | niov = &owner->area.niovs[i]; | 299 | niov = &owner->area.niovs[i]; |
| 300 | niov->type = NET_IOV_DMABUF; | 300 | net_iov_init(niov, &owner->area, NET_IOV_DMABUF); |
| 301 | niov->owner = &owner->area; | ||
| 302 | page_pool_set_dma_addr_netmem(net_iov_to_netmem(niov), | 301 | page_pool_set_dma_addr_netmem(net_iov_to_netmem(niov), |
| 303 | net_devmem_get_dma_addr(niov)); | 302 | net_devmem_get_dma_addr(niov)); |
| 304 | if (direction == DMA_TO_DEVICE) | 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 | rcu_read_lock(); | 3211 | rcu_read_lock(); |
| 3212 | tbl = rcu_dereference(neigh_tables[index]); | 3212 | tbl = rcu_dereference(neigh_tables[index]); |
| 3213 | if (!tbl) | 3213 | if (!tbl) { |
| 3214 | goto out_unlock; | 3214 | rcu_read_unlock(); |
| 3215 | goto out_kfree_skb; | ||
| 3216 | } | ||
| 3215 | if (index == NEIGH_ARP_TABLE) { | 3217 | if (index == NEIGH_ARP_TABLE) { |
| 3216 | u32 key = *((u32 *)addr); | 3218 | u32 key = *((u32 *)addr); |
| 3217 | 3219 | ||
| @@ -3227,7 +3229,6 @@ int neigh_xmit(int index, struct net_device *dev, · 9 unmodified lines | |||
| 3227 | goto out_kfree_skb; | 3229 | goto out_kfree_skb; |
| 3228 | } | 3230 | } |
| 3229 | err = READ_ONCE(neigh->output)(neigh, skb); | 3231 | err = READ_ONCE(neigh->output)(neigh, skb); |
| 3230 | out_unlock: | ||
| 3231 | rcu_read_unlock(); | 3232 | rcu_read_unlock(); |
| 3232 | } | 3233 | } |
| 3233 | else if (index == NEIGH_LINK_TABLE) { | 3234 | else if (index == NEIGH_LINK_TABLE) { |
| @@ -3237,11 +3238,10 @@ out_unlock: · 3 unmodified lines | |||
| 3237 | goto out_kfree_skb; | 3238 | goto out_kfree_skb; |
| 3238 | err = dev_queue_xmit(skb); | 3239 | err = dev_queue_xmit(skb); |
| 3239 | } | 3240 | } |
| 3240 | out: | ||
| 3241 | return err; | 3241 | return err; |
| 3242 | out_kfree_skb: | 3242 | out_kfree_skb: |
| 3243 | kfree_skb(skb); | 3243 | kfree_skb(skb); |
| 3244 | goto out; | 3244 | return err; |
| 3245 | } | 3245 | } |
| 3246 | EXPORT_SYMBOL(neigh_xmit); | 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 | return 0; | 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 | int netpoll_setup(struct netpoll *np) | 724 | int netpoll_setup(struct netpoll *np) |
| 708 | { | 725 | { |
| 709 | struct net *net = current->nsproxy->net_ns; | 726 | struct net *net = current->nsproxy->net_ns; |
| @@ -747,7 +764,7 @@ int netpoll_setup(struct netpoll *np) · 37 unmodified lines | |||
| 747 | rtnl_lock(); | 764 | rtnl_lock(); |
| 748 | } | 765 | } |
| 749 | 766 | ||
| 750 | if (!np->local_ip.ip) { | 767 | if (netpoll_local_ip_unset(np)) { |
| 751 | if (!np->ipv6) { | 768 | if (!np->ipv6) { |
| 752 | err = netpoll_take_ipv4(np, ndev); | 769 | err = netpoll_take_ipv4(np, ndev); |
| 753 | if (err) | 770 | if (err) |
| @@ -327,6 +327,11 @@ static void page_pool_uninit(struct page_pool *pool) · 326 unmodified lines | |||
| 327 | if (!pool->system) | 327 | if (!pool->system) |
| 328 | free_percpu(pool->recycle_stats); | 328 | free_percpu(pool->recycle_stats); |
| 329 | #endif | 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 | page_pool_unlist(pool); | 1151 | page_pool_unlist(pool); |
| 1147 | page_pool_uninit(pool); | 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 | kfree(pool); | 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 | return NULL; | 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 | static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, | 154 | static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, |
| 165 | struct mr_table **mrt) | 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 | struct mr_table *mrt, *next; | 283 | struct mr_table *mrt, *next; |
| 294 | 284 | ||
| 295 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { | 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 | ipmr_free_table(mrt, dev_kill_list); | 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 | EXPORT_SYMBOL(ipmr_rule_default); | 306 | EXPORT_SYMBOL(ipmr_rule_default); |
| 317 | #else | 307 | #else |
| 318 | #define ipmr_for_each_table(mrt, net) \ | ||
| 319 | for (mrt = net->ipv4.mrt; mrt; mrt = NULL) | ||
| 320 | |||
| 321 | static struct mr_table *ipmr_mr_table_iter(struct net *net, | 308 | static struct mr_table *ipmr_mr_table_iter(struct net *net, |
| 322 | struct mr_table *mrt) | 309 | struct mr_table *mrt) |
| 323 | { | 310 | { |
| 324 | if (!mrt) | 311 | if (!mrt) |
| 325 | return net->ipv4.mrt; | 312 | return rcu_dereference(net->ipv4.mrt); |
| 326 | return NULL; | 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 | static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, | 326 | static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, |
| 337 | struct mr_table **mrt) | 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 | return 0; | 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 | mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); | 339 | mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); |
| 348 | if (IS_ERR(mrt)) | 340 | if (IS_ERR(mrt)) |
| 349 | return PTR_ERR(mrt); | 341 | return PTR_ERR(mrt); |
| 350 | net->ipv4.mrt = mrt; | 342 | |
| 343 | rcu_assign_pointer(net->ipv4.mrt, mrt); | ||
| 351 | return 0; | 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 | static void __net_exit ipmr_rules_exit_rtnl(struct net *net, | 351 | static void __net_exit ipmr_rules_exit_rtnl(struct net *net, |
| 359 | struct list_head *dev_kill_list) | 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 | static int ipmr_rules_dump(struct net *net, struct notifier_block *nb, | 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 | EXPORT_SYMBOL(ipmr_rule_default); | 375 | EXPORT_SYMBOL(ipmr_rule_default); |
| 382 | #endif | 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 | static inline int ipmr_hash_cmp(struct rhashtable_compare_arg *arg, | 389 | static inline int ipmr_hash_cmp(struct rhashtable_compare_arg *arg, |
| 385 | const void *ptr) | 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 | WARN_ON_ONCE(!mr_can_free_table(net)); | 447 | WARN_ON_ONCE(!mr_can_free_table(net)); |
| 443 | 448 | ||
| 444 | timer_shutdown_sync(&mrt->ipmr_expire_timer); | ||
| 445 | mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC | | 449 | mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC | |
| 446 | MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC, | 450 | MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC, |
| 447 | &ipmr_dev_kill_list); | 451 | &ipmr_dev_kill_list); |
| 448 | rhltable_destroy(&mrt->mfc_hash); | 452 | timer_shutdown_sync(&mrt->ipmr_expire_timer); |
| 449 | kfree(mrt); | 453 | mr_table_free(mrt); |
| 450 | 454 | ||
| 451 | WARN_ON_ONCE(!net_initialized(net) && !list_empty(&ipmr_dev_kill_list)); | 455 | WARN_ON_ONCE(!net_initialized(net) && !list_empty(&ipmr_dev_kill_list)); |
| 452 | list_splice(&ipmr_dev_kill_list, dev_kill_list); | 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 | static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, | 1139 | static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, |
| 1136 | struct sk_buff *skb, struct net_device *dev) | 1140 | struct sk_buff *skb, struct net_device *dev) |
| 1137 | { | 1141 | { |
| 1142 | struct net *net = read_pnet(&mrt->net); | ||
| 1138 | const struct iphdr *iph = ip_hdr(skb); | 1143 | const struct iphdr *iph = ip_hdr(skb); |
| 1139 | struct mfc_cache *c; | 1144 | struct mfc_cache *c = NULL; |
| 1140 | bool found = false; | 1145 | bool found = false; |
| 1141 | int err; | 1146 | int err; |
| 1142 | 1147 | ||
| 1143 | spin_lock_bh(&mfc_unres_lock); | 1148 | spin_lock_bh(&mfc_unres_lock); |
| 1149 | |||
| 1150 | if (!check_net(net)) { | ||
| 1151 | err = -EINVAL; | ||
| 1152 | goto err; | ||
| 1153 | } | ||
| 1154 | |||
| 1144 | list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) { | 1155 | list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) { |
| 1145 | if (c->mfc_mcastgrp == iph->daddr && | 1156 | if (c->mfc_mcastgrp == iph->daddr && |
| 1146 | c->mfc_origin == iph->saddr) { | 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 | /* Create a new entry if allowable */ | 1164 | /* Create a new entry if allowable */ |
| 1154 | c = ipmr_cache_alloc_unres(); | 1165 | c = ipmr_cache_alloc_unres(); |
| 1155 | if (!c) { | 1166 | if (!c) { |
| 1156 | spin_unlock_bh(&mfc_unres_lock); | 1167 | err = -ENOBUFS; |
| 1157 | 1168 | goto err; | |
| 1158 | kfree_skb(skb); | ||
| 1159 | return -ENOBUFS; | ||
| 1160 | } | 1169 | } |
| 1161 | 1170 | ||
| 1162 | /* Fill in the new cache entry */ | 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 | /* Reflect first query at mrouted. */ | 1176 | /* Reflect first query at mrouted. */ |
| 1168 | err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE); | 1177 | err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE); |
| 1169 | 1178 | if (err < 0) | |
| 1170 | if (err < 0) { | 1179 | goto err; |
| 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 | } | ||
| 1180 | 1180 | ||
| 1181 | atomic_inc(&mrt->cache_resolve_queue_len); | 1181 | atomic_inc(&mrt->cache_resolve_queue_len); |
| 1182 | list_add(&c->_c.list, &mrt->mfc_unres_queue); | 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 | /* See if we can append the packet */ | 1190 | /* See if we can append the packet */ |
| 1191 | if (c->_c.mfc_un.unres.unresolved.qlen > 3) { | 1191 | if (c->_c.mfc_un.unres.unresolved.qlen > 3) { |
| 1192 | kfree_skb(skb); | 1192 | c = NULL; |
| 1193 | err = -ENOBUFS; | 1193 | err = -ENOBUFS; |
| 1194 | } else { | 1194 | goto err; |
| 1195 | if (dev) { | 1195 | } |
| 1196 | skb->dev = dev; | 1196 | |
| 1197 | skb->skb_iif = dev->ifindex; | 1197 | if (dev) { |
| 1198 | } | 1198 | skb->dev = dev; |
| 1199 | skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); | 1199 | skb->skb_iif = dev->ifindex; |
| 1200 | err = 0; | ||
| 1201 | } | 1200 | } |
| 1202 | 1201 | ||
| 1202 | skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); | ||
| 1203 | |||
| 1203 | spin_unlock_bh(&mfc_unres_lock); | 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 | return err; | 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 | if (flags & MRT_FLUSH_MFC) { | 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 | spin_lock_bh(&mfc_unres_lock); | 1358 | spin_lock_bh(&mfc_unres_lock); |
| 1351 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { | 1359 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
| 1352 | list_del(&c->list); | 1360 | list_del(&c->list); |
| @@ -28,6 +28,20 @@ void vif_device_init(struct vif_device *v, · 27 unmodified lines | |||
| 28 | v->link = dev->ifindex; | 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 | struct mr_table * | 45 | struct mr_table * |
| 32 | mr_table_alloc(struct net *net, u32 id, | 46 | mr_table_alloc(struct net *net, u32 id, |
| 33 | struct mr_table_ops *ops, | 47 | struct mr_table_ops *ops, |
| @@ -50,6 +64,8 @@ mr_table_alloc(struct net *net, u32 id, · 16 unmodified lines | |||
| 50 | kfree(mrt); | 64 | kfree(mrt); |
| 51 | return ERR_PTR(err); | 65 | return ERR_PTR(err); |
| 52 | } | 66 | } |
| 67 | |||
| 68 | INIT_RCU_WORK(&mrt->work, __mr_free_table); | ||
| 53 | INIT_LIST_HEAD(&mrt->mfc_cache_list); | 69 | INIT_LIST_HEAD(&mrt->mfc_cache_list); |
| 54 | INIT_LIST_HEAD(&mrt->mfc_unres_queue); | 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 | arpptr += dev->addr_len; | 110 | arpptr += dev->addr_len; |
| 111 | memcpy(&src_ipaddr, arpptr, sizeof(u32)); | 111 | memcpy(&src_ipaddr, arpptr, sizeof(u32)); |
| 112 | arpptr += sizeof(u32); | 112 | arpptr += sizeof(u32); |
| 113 | tgt_devaddr = arpptr; | 113 | |
| 114 | arpptr += dev->addr_len; | 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 | memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); | 124 | memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); |
| 116 | 125 | ||
| 117 | if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, | 126 | if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, |
| 118 | arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, | 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 | NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, | 132 | NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, |
| 121 | arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, | 133 | arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, |
| 122 | dev->addr_len))) | 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 | arpptr += pln; | 41 | arpptr += pln; |
| 42 | if (mangle->flags & ARPT_MANGLE_TDEV) { | 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 | if (ARPT_DEV_ADDR_LEN_MAX < hln || | 47 | if (ARPT_DEV_ADDR_LEN_MAX < hln || |
| 44 | (arpptr + hln > skb_tail_pointer(skb))) | 48 | (arpptr + hln > skb_tail_pointer(skb))) |
| 45 | return NF_DROP; | 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 | arpptr += hln; | 52 | arpptr += hln; |
| 49 | if (mangle->flags & ARPT_MANGLE_TIP) { | 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 | if (ARPT_MANGLE_ADDR_LEN_MAX < pln || | 58 | if (ARPT_MANGLE_ADDR_LEN_MAX < pln || |
| 51 | (arpptr + pln > skb_tail_pointer(skb))) | 59 | (arpptr + pln > skb_tail_pointer(skb))) |
| 52 | return NF_DROP; | 60 | return NF_DROP; |
| @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) · 49 unmodified lines | |||
| 50 | u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) | 50 | u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) |
| 51 | { | 51 | { |
| 52 | const struct inet_connection_sock *icsk = inet_csk(sk); | 52 | const struct inet_connection_sock *icsk = inet_csk(sk); |
| 53 | u32 remaining, user_timeout; | 53 | u32 user_timeout; |
| 54 | s32 remaining; | ||
| 54 | s32 elapsed; | 55 | s32 elapsed; |
| 55 | 56 | ||
| 56 | user_timeout = READ_ONCE(icsk->icsk_user_timeout); | 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 | if (unlikely(elapsed < 0)) | 62 | if (unlikely(elapsed < 0)) |
| 62 | elapsed = 0; | 63 | elapsed = 0; |
| 63 | remaining = msecs_to_jiffies(user_timeout) - elapsed; | 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 | return min_t(u32, remaining, when); | 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 | struct net *net = dev_net(skb->dev); | 491 | struct net *net = dev_net(skb->dev); |
| 492 | struct inet6_dev *idev; | 492 | struct inet6_dev *idev; |
| 493 | struct ipv6hdr *oldhdr; | 493 | struct ipv6hdr *oldhdr; |
| 494 | unsigned int chdr_len; | ||
| 494 | unsigned char *buf; | 495 | unsigned char *buf; |
| 495 | int accept_rpl_seg; | 496 | int accept_rpl_seg; |
| 496 | int i, err; | 497 | int i, err; |
| @@ -592,8 +593,10 @@ looped_back: · 95 unmodified lines | |||
| 592 | skb_pull(skb, ((hdr->hdrlen + 1) << 3)); | 593 | skb_pull(skb, ((hdr->hdrlen + 1) << 3)); |
| 593 | skb_postpull_rcsum(skb, oldhdr, | 594 | skb_postpull_rcsum(skb, oldhdr, |
| 594 | sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); | 595 | sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); |
| 595 | if (unlikely(!hdr->segments_left)) { | 596 | chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3); |
| 596 | if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0, | 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 | GFP_ATOMIC)) { | 600 | GFP_ATOMIC)) { |
| 598 | __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); | 601 | __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); |
| 599 | kfree_skb(skb); | 602 | kfree_skb(skb); |
| @@ -603,7 +606,7 @@ looped_back: · 3 unmodified lines | |||
| 603 | 606 | ||
| 604 | oldhdr = ipv6_hdr(skb); | 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 | skb_reset_network_header(skb); | 610 | skb_reset_network_header(skb); |
| 608 | skb_mac_header_rebuild(skb); | 611 | skb_mac_header_rebuild(skb); |
| 609 | skb_set_transport_header(skb, sizeof(struct ipv6hdr)); | 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 | if (!dst) { | 288 | if (!dst) { |
| 289 | ip6_route_input(skb); | 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 | dst = skb_dst(skb); | 295 | dst = skb_dst(skb); |
| 296 | if (unlikely(!dst)) { | ||
| 297 | err = -ENETUNREACH; | ||
| 298 | goto drop; | ||
| 299 | } | ||
| 291 | 300 | ||
| 292 | /* cache only if we don't create a dst reference loop */ | 301 | /* cache only if we don't create a dst reference loop */ |
| 293 | if (!dst->error && lwtst != dst->lwtstate) { | 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 | if (!dst) { | 516 | if (!dst) { |
| 517 | ip6_route_input(skb); | 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 | dst = skb_dst(skb); | 523 | dst = skb_dst(skb); |
| 524 | if (unlikely(!dst)) { | ||
| 525 | err = -ENETUNREACH; | ||
| 526 | goto drop; | ||
| 527 | } | ||
| 519 | 528 | ||
| 520 | /* cache only if we don't create a dst reference loop */ | 529 | /* cache only if we don't create a dst reference loop */ |
| 521 | if (!dst->error && lwtst != dst->lwtstate) { | 530 | if (!dst->error && lwtst != dst->lwtstate) { |
| @@ -1278,6 +1278,7 @@ static void __reset_counters(struct pm_nl_pernet *pernet) · 1277 unmodified lines | |||
| 1278 | WRITE_ONCE(pernet->endp_signal_max, 0); | 1278 | WRITE_ONCE(pernet->endp_signal_max, 0); |
| 1279 | WRITE_ONCE(pernet->endp_subflow_max, 0); | 1279 | WRITE_ONCE(pernet->endp_subflow_max, 0); |
| 1280 | WRITE_ONCE(pernet->endp_laminar_max, 0); | 1280 | WRITE_ONCE(pernet->endp_laminar_max, 0); |
| 1281 | WRITE_ONCE(pernet->endp_fullmesh_max, 0); | ||
| 1281 | pernet->endpoints = 0; | 1282 | pernet->endpoints = 0; |
| 1282 | } | 1283 | } |
| 1283 | 1284 | ||
| @@ -3302,7 +3302,8 @@ bool __mptcp_close(struct sock *sk, long timeout) · 3301 unmodified lines | |||
| 3302 | goto cleanup; | 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 | /* If the msk has read data, or the caller explicitly ask it, | 3307 | /* If the msk has read data, or the caller explicitly ask it, |
| 3307 | * do the MPTCP equivalent of TCP reset, aka MPTCP fastclose | 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 | lock_sock(sk); | 159 | lock_sock(sk); |
| 160 | mptcp_for_each_subflow(msk, subflow) { | 160 | mptcp_for_each_subflow(msk, subflow) { |
| 161 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | 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); | 163 | lock_sock(ssk); |
| 165 | unlock_sock_fast(ssk, slow); | 164 | sock_set_timestamp(ssk, optname, !!val); |
| 165 | release_sock(ssk); | ||
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | release_sock(sk); | 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 | mptcp_for_each_subflow(msk, subflow) { | 236 | mptcp_for_each_subflow(msk, subflow) { |
| 237 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | 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); | 239 | lock_sock(ssk); |
| 241 | unlock_sock_fast(ssk, slow); | 240 | sock_set_timestamping(ssk, optname, timestamping); |
| 241 | release_sock(ssk); | ||
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | release_sock(sk); | 244 | release_sock(sk); |
| @@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, · 465 unmodified lines | |||
| 466 | if (!ih) | 466 | if (!ih) |
| 467 | goto out_unlock; | 467 | goto out_unlock; |
| 468 | 468 | ||
| 469 | if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) | 469 | /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ |
| 470 | ct->proto.sctp.init[!dir] = 0; | 470 | if (old_state == SCTP_CONNTRACK_NONE || |
| 471 | ct->proto.sctp.init[dir] = 1; | 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 | pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); | 477 | pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); |
| 474 | ct->proto.sctp.vtag[!dir] = ih->init_tag; | 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 | return 1; | 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 | /* skip ip address. returns its length. */ | 235 | /* skip ip address. returns its length. */ |
| 185 | static int epaddr_len(const struct nf_conn *ct, const char *dptr, | 236 | static int epaddr_len(const struct nf_conn *ct, const char *dptr, |
| 186 | const char *limit, int *shift) | 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 | return 0; | 244 | return 0; |
| 194 | } | 245 | } |
| 195 | 246 | ||
| 196 | /* Port number */ | 247 | if (!sip_parse_port(dptr, &dptr, limit, NULL)) |
| 197 | if (*dptr == ':') { | 248 | return 0; |
| 198 | dptr++; | ||
| 199 | dptr += digits_len(ct, dptr, limit, shift); | ||
| 200 | } | ||
| 201 | return dptr - aux; | 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 | return epaddr_len(ct, dptr, limit, shift); | 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 | /* Parse a SIP request line of the form: | 324 | /* Parse a SIP request line of the form: |
| 232 | * | 325 | * |
| 233 | * Request-Line = Method SP Request-URI SP SIP-Version CRLF | 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 | const char *start = dptr, *limit = dptr + datalen, *end; | 335 | const char *start = dptr, *limit = dptr + datalen, *end; |
| 243 | unsigned int mlen; | 336 | unsigned int mlen; |
| 244 | unsigned int p; | ||
| 245 | int shift = 0; | 337 | int shift = 0; |
| 246 | 338 | ||
| 247 | /* Skip method and following whitespace */ | 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 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) | 360 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) |
| 269 | return -1; | 361 | return -1; |
| 270 | if (end < limit && *end == ':') { | 362 | if (!sip_parse_port(end, &end, limit, port)) |
| 271 | end++; | 363 | return -1; |
| 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); | ||
| 278 | 364 | ||
| 279 | if (end == dptr) | 365 | if (end == dptr) |
| 280 | return 0; | 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 | union nf_inet_addr *addr, __be16 *port) | 595 | union nf_inet_addr *addr, __be16 *port) |
| 510 | { | 596 | { |
| 511 | const char *c, *limit = dptr + datalen; | 597 | const char *c, *limit = dptr + datalen; |
| 512 | unsigned int p; | ||
| 513 | int ret; | 598 | int ret; |
| 514 | 599 | ||
| 515 | ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, | 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 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) | 606 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) |
| 522 | return -1; | 607 | return -1; |
| 523 | if (*c == ':') { | 608 | if (!sip_parse_port(c, &c, limit, port)) |
| 524 | c++; | 609 | return -1; |
| 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); | ||
| 531 | 610 | ||
| 532 | if (dataoff) | 611 | if (dataoff) |
| 533 | *dataoff = c - dptr; | 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 | return 0; | 688 | return 0; |
| 610 | 689 | ||
| 611 | start += strlen(name); | 690 | start += strlen(name); |
| 612 | *val = simple_strtoul(start, &end, 0); | 691 | *val = sip_strtouint(start, limit - start, (char **)&end); |
| 613 | if (start == end) | 692 | if (start == end) |
| 614 | return -1; | 693 | return -1; |
| 615 | if (matchoff && matchlen) { | 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 | mediaoff = sdpoff; | 1144 | mediaoff = sdpoff; |
| 1066 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { | 1145 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { |
| 1146 | char *end; | ||
| 1147 | |||
| 1067 | if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, | 1148 | if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, |
| 1068 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, | 1149 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, |
| 1069 | &mediaoff, &medialen) <= 0) | 1150 | &mediaoff, &medialen) <= 0) |
| @@ -1079,8 +1160,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, · 9 unmodified lines | |||
| 1079 | mediaoff += t->len; | 1160 | mediaoff += t->len; |
| 1080 | medialen -= t->len; | 1161 | medialen -= t->len; |
| 1081 | 1162 | ||
| 1082 | port = simple_strtoul(*dptr + mediaoff, NULL, 10); | 1163 | port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); |
| 1083 | if (port == 0) | 1164 | if (port == 0 || *dptr + mediaoff == end) |
| 1084 | continue; | 1165 | continue; |
| 1085 | if (port < 1024 || port > 65535) { | 1166 | if (port < 1024 || port > 65535) { |
| 1086 | nf_ct_helper_log(skb, ct, "wrong port %u", port); | 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 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, | 1336 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, |
| 1256 | &matchoff, &matchlen) > 0) | 1337 | &matchoff, &matchlen) > 0) |
| 1257 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); | 1338 | expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); |
| 1258 | 1339 | ||
| 1259 | ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | 1340 | ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
| 1260 | SIP_HDR_CONTACT, NULL, | 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 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, | 1440 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, |
| 1360 | &matchoff, &matchlen) > 0) | 1441 | &matchoff, &matchlen) > 0) |
| 1361 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); | 1442 | expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); |
| 1362 | 1443 | ||
| 1363 | while (1) { | 1444 | while (1) { |
| 1364 | unsigned int c_expires = expires; | 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 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1499 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
| 1419 | unsigned int matchoff, matchlen, matchend; | 1500 | unsigned int matchoff, matchlen, matchend; |
| 1420 | unsigned int code, cseq, i; | 1501 | unsigned int code, cseq, i; |
| 1502 | char *end; | ||
| 1421 | 1503 | ||
| 1422 | if (*datalen < strlen("SIP/2.0 200")) | 1504 | if (*datalen < strlen("SIP/2.0 200")) |
| 1423 | return NF_ACCEPT; | 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 | if (!code) { | 1508 | if (!code) { |
| 1426 | nf_ct_helper_log(skb, ct, "cannot get code"); | 1509 | nf_ct_helper_log(skb, ct, "cannot get code"); |
| 1427 | return NF_DROP; | 1510 | return NF_DROP; |
| @@ -1432,8 +1515,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, · 4 unmodified lines | |||
| 1432 | nf_ct_helper_log(skb, ct, "cannot parse cseq"); | 1515 | nf_ct_helper_log(skb, ct, "cannot parse cseq"); |
| 1433 | return NF_DROP; | 1516 | return NF_DROP; |
| 1434 | } | 1517 | } |
| 1435 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | 1518 | cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); |
| 1436 | if (!cseq && *(*dptr + matchoff) != '0') { | 1519 | if (*dptr + matchoff == end) { |
| 1437 | nf_ct_helper_log(skb, ct, "cannot get cseq"); | 1520 | nf_ct_helper_log(skb, ct, "cannot get cseq"); |
| 1438 | return NF_DROP; | 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 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { | 1566 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { |
| 1484 | const struct sip_handler *handler; | 1567 | const struct sip_handler *handler; |
| 1568 | char *end; | ||
| 1485 | 1569 | ||
| 1486 | handler = &sip_handlers[i]; | 1570 | handler = &sip_handlers[i]; |
| 1487 | if (handler->request == NULL) | 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 | nf_ct_helper_log(skb, ct, "cannot parse cseq"); | 1582 | nf_ct_helper_log(skb, ct, "cannot parse cseq"); |
| 1499 | return NF_DROP; | 1583 | return NF_DROP; |
| 1500 | } | 1584 | } |
| 1501 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | 1585 | cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); |
| 1502 | if (!cseq && *(*dptr + matchoff) != '0') { | 1586 | if (*dptr + matchoff == end) { |
| 1503 | nf_ct_helper_log(skb, ct, "cannot get cseq"); | 1587 | nf_ct_helper_log(skb, ct, "cannot get cseq"); |
| 1504 | return NF_DROP; | 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 | &matchoff, &matchlen) <= 0) | 1659 | &matchoff, &matchlen) <= 0) |
| 1576 | break; | 1660 | break; |
| 1577 | 1661 | ||
| 1578 | clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); | 1662 | clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); |
| 1579 | if (dptr + matchoff == end) | 1663 | if (dptr + matchoff == end) |
| 1580 | break; | 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 | if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, | 246 | if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, |
| 247 | "rport=", &poff, &plen, | 247 | "rport=", &poff, &plen, |
| 248 | &n) > 0 && | 248 | &n) > 0 && |
| 249 | n >= 1024 && n <= 65535 && | ||
| 249 | htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && | 250 | htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && |
| 250 | htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { | 251 | htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { |
| 251 | __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; | 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 | call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu); | 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 | static void nft_netdev_unregister_hooks(struct net *net, | 409 | static void nft_netdev_unregister_hooks(struct net *net, |
| 378 | struct list_head *hook_list, | 410 | struct list_head *hook_list, |
| 379 | bool release_netdev) | 411 | bool release_netdev) |
| @@ -384,10 +416,8 @@ static void nft_netdev_unregister_hooks(struct net *net, · 4 unmodified lines | |||
| 384 | list_for_each_entry_safe(hook, next, hook_list, list) { | 416 | list_for_each_entry_safe(hook, next, hook_list, list) { |
| 385 | list_for_each_entry(ops, &hook->ops_list, list) | 417 | list_for_each_entry(ops, &hook->ops_list, list) |
| 386 | nf_unregister_net_hook(net, ops); | 418 | nf_unregister_net_hook(net, ops); |
| 387 | if (release_netdev) { | 419 | if (release_netdev) |
| 388 | list_del(&hook->list); | 420 | nft_netdev_hook_unlink_free_rcu(hook); |
| 389 | nft_netdev_hook_free_rcu(hook); | ||
| 390 | } | ||
| 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 | return nla_put_string(skb, attr, hook->ifname); | 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 | static int nft_dump_basechain_hook(struct sk_buff *skb, | 2029 | static int nft_dump_basechain_hook(struct sk_buff *skb, |
| 1946 | const struct net *net, int family, | 2030 | const struct net *net, int family, |
| 1947 | const struct nft_base_chain *basechain, | 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 | const struct nf_hook_ops *ops = &basechain->ops; | 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 | struct nlattr *nest, *nest_devs; | 2037 | struct nlattr *nest, *nest_devs; |
| 1953 | int n = 0; | ||
| 1954 | 2038 | ||
| 1955 | nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK); | 2039 | nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK); |
| 1956 | if (nest == NULL) | 2040 | if (nest == NULL) |
| @@ -1965,23 +2049,23 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, · 8 unmodified lines | |||
| 1965 | if (!nest_devs) | 2049 | if (!nest_devs) |
| 1966 | goto nla_put_failure; | 2050 | goto nla_put_failure; |
| 1967 | 2051 | ||
| 1968 | if (!hook_list) | 2052 | if (!hook_list && !trans_hook_list) |
| 1969 | hook_list = &basechain->hook_list; | 2053 | hook_list = &basechain->hook_list; |
| 1970 | 2054 | ||
| 1971 | list_for_each_entry_rcu(hook, hook_list, list, | 2055 | if (hook_list && |
| 1972 | lockdep_commit_lock_is_held(net)) { | 2056 | nft_dump_basechain_hook_list(skb, net, hook_list, &dump_hook_ctx)) { |
| 1973 | if (!first) | 2057 | goto nla_put_failure; |
| 1974 | first = hook; | 2058 | } else if (trans_hook_list && |
| 1975 | 2059 | nft_dump_basechain_trans_hook_list(skb, trans_hook_list, | |
| 1976 | if (nft_nla_put_hook_dev(skb, hook)) | 2060 | &dump_hook_ctx)) { |
| 1977 | goto nla_put_failure; | 2061 | goto nla_put_failure; |
| 1978 | n++; | ||
| 1979 | } | 2062 | } |
| 2063 | |||
| 1980 | nla_nest_end(skb, nest_devs); | 2064 | nla_nest_end(skb, nest_devs); |
| 1981 | 2065 | ||
| 1982 | if (n == 1 && | 2066 | if (dump_hook_ctx.n == 1 && |
| 1983 | !hook_is_prefix(first) && | 2067 | !hook_is_prefix(dump_hook_ctx.first) && |
| 1984 | nla_put_string(skb, NFTA_HOOK_DEV, first->ifname)) | 2068 | nla_put_string(skb, NFTA_HOOK_DEV, dump_hook_ctx.first->ifname)) |
| 1985 | goto nla_put_failure; | 2069 | goto nla_put_failure; |
| 1986 | } | 2070 | } |
| 1987 | nla_nest_end(skb, nest); | 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 | u32 portid, u32 seq, int event, u32 flags, | 2079 | u32 portid, u32 seq, int event, u32 flags, |
| 1996 | int family, const struct nft_table *table, | 2080 | int family, const struct nft_table *table, |
| 1997 | const struct nft_chain *chain, | 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 | struct nlmsghdr *nlh; | 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 | NFTA_CHAIN_PAD)) | 2096 | NFTA_CHAIN_PAD)) |
| 2012 | goto nla_put_failure; | 2097 | goto nla_put_failure; |
| 2013 | 2098 | ||
| 2014 | if (!hook_list && | 2099 | if (!hook_list && !trans_hook_list && |
| 2015 | (event == NFT_MSG_DELCHAIN || | 2100 | (event == NFT_MSG_DELCHAIN || |
| 2016 | event == NFT_MSG_DESTROYCHAIN)) { | 2101 | event == NFT_MSG_DESTROYCHAIN)) { |
| 2017 | nlmsg_end(skb, nlh); | 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 | const struct nft_base_chain *basechain = nft_base_chain(chain); | 2107 | const struct nft_base_chain *basechain = nft_base_chain(chain); |
| 2023 | struct nft_stats __percpu *stats; | 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 | goto nla_put_failure; | 2112 | goto nla_put_failure; |
| 2027 | 2113 | ||
| 2028 | if (nla_put_be32(skb, NFTA_CHAIN_POLICY, | 2114 | if (nla_put_be32(skb, NFTA_CHAIN_POLICY, |
| @@ -2058,7 +2144,8 @@ nla_put_failure: · 29 unmodified lines | |||
| 2058 | } | 2144 | } |
| 2059 | 2145 | ||
| 2060 | static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event, | 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 | struct nftables_pernet *nft_net; | 2150 | struct nftables_pernet *nft_net; |
| 2064 | struct sk_buff *skb; | 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 | err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, | 2166 | err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, |
| 2080 | event, flags, ctx->family, ctx->table, | 2167 | event, flags, ctx->family, ctx->table, |
| 2081 | ctx->chain, hook_list); | 2168 | ctx->chain, hook_list, trans_hook_list); |
| 2082 | if (err < 0) { | 2169 | if (err < 0) { |
| 2083 | kfree_skb(skb); | 2170 | kfree_skb(skb); |
| 2084 | goto err; | 2171 | goto err; |
| @@ -2124,7 +2211,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb, · 39 unmodified lines | |||
| 2124 | NFT_MSG_NEWCHAIN, | 2211 | NFT_MSG_NEWCHAIN, |
| 2125 | NLM_F_MULTI, | 2212 | NLM_F_MULTI, |
| 2126 | table->family, table, | 2213 | table->family, table, |
| 2127 | chain, NULL) < 0) | 2214 | chain, NULL, NULL) < 0) |
| 2128 | goto done; | 2215 | goto done; |
| 2129 | 2216 | ||
| 2130 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | 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 | err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid, | 2266 | err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid, |
| 2180 | info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, | 2267 | info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, |
| 2181 | 0, family, table, chain, NULL); | 2268 | 0, family, table, chain, NULL, NULL); |
| 2182 | if (err < 0) | 2269 | if (err < 0) |
| 2183 | goto err_fill_chain_info; | 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 | if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) { | 2359 | if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) { |
| 2273 | list_for_each_entry_safe(hook, next, | 2360 | list_for_each_entry_safe(hook, next, |
| 2274 | &basechain->hook_list, list) { | 2361 | &basechain->hook_list, list) |
| 2275 | list_del_rcu(&hook->list); | 2362 | nft_netdev_hook_unlink_free_rcu(hook); |
| 2276 | nft_netdev_hook_free_rcu(hook); | ||
| 2277 | } | ||
| 2278 | } | 2363 | } |
| 2279 | module_put(basechain->type->owner); | 2364 | module_put(basechain->type->owner); |
| 2280 | if (rcu_access_pointer(basechain->stats)) { | 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 | list_for_each_entry(hook, hook_list, list) { | 2429 | list_for_each_entry(hook, hook_list, list) { |
| 2345 | if (!strncmp(hook->ifname, this->ifname, | 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 | return hook; | 2435 | return hook; |
| 2436 | } | ||
| 2348 | } | 2437 | } |
| 2349 | 2438 | ||
| 2350 | return NULL; | 2439 | return NULL; |
| @@ -2974,6 +3063,7 @@ err_hooks: · 623 unmodified lines | |||
| 2974 | list_for_each_entry(ops, &h->ops_list, list) | 3063 | list_for_each_entry(ops, &h->ops_list, list) |
| 2975 | nf_unregister_net_hook(ctx->net, ops); | 3064 | nf_unregister_net_hook(ctx->net, ops); |
| 2976 | } | 3065 | } |
| 3066 | /* hook.list is on stack, no need for list_del_rcu() */ | ||
| 2977 | list_del(&h->list); | 3067 | list_del(&h->list); |
| 2978 | nft_netdev_hook_free_rcu(h); | 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 | return nf_tables_addchain(&ctx, family, policy, flags, extack); | 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 | static int nft_delchain_hook(struct nft_ctx *ctx, | 3221 | static int nft_delchain_hook(struct nft_ctx *ctx, |
| 3106 | struct nft_base_chain *basechain, | 3222 | struct nft_base_chain *basechain, |
| 3107 | struct netlink_ext_ack *extack) | 3223 | struct netlink_ext_ack *extack) |
| @@ -3128,7 +3244,10 @@ static int nft_delchain_hook(struct nft_ctx *ctx, · 20 unmodified lines | |||
| 3128 | err = -ENOENT; | 3244 | err = -ENOENT; |
| 3129 | goto err_chain_del_hook; | 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 | trans = nft_trans_alloc_chain(ctx, NFT_MSG_DELCHAIN); | 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 | return 0; | 3267 | return 0; |
| 3149 | 3268 | ||
| 3150 | err_chain_del_hook: | 3269 | err_chain_del_hook: |
| 3151 | list_splice(&chain_del_list, &basechain->hook_list); | 3270 | nft_trans_delhook_abort(&chain_del_list); |
| 3152 | nft_chain_release_hook(&chain_hook); | 3271 | nft_chain_release_hook(&chain_hook); |
| 3153 | 3272 | ||
| 3154 | return err; | 3273 | return err; |
| @@ -8852,10 +8971,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net, · 5697 unmodified lines | |||
| 8852 | list_for_each_entry_safe(hook, next, hook_list, list) { | 8971 | list_for_each_entry_safe(hook, next, hook_list, list) { |
| 8853 | list_for_each_entry(ops, &hook->ops_list, list) | 8972 | list_for_each_entry(ops, &hook->ops_list, list) |
| 8854 | nft_unregister_flowtable_ops(net, flowtable, ops); | 8973 | nft_unregister_flowtable_ops(net, flowtable, ops); |
| 8855 | if (release_netdev) { | 8974 | if (release_netdev) |
| 8856 | list_del(&hook->list); | 8975 | nft_netdev_hook_unlink_free_rcu(hook); |
| 8857 | nft_netdev_hook_free_rcu(hook); | ||
| 8858 | } | ||
| 8859 | } | 8976 | } |
| 8860 | } | 8977 | } |
| 8861 | 8978 | ||
| @@ -8926,8 +9043,7 @@ err_unregister_net_hooks: · 64 unmodified lines | |||
| 8926 | 9043 | ||
| 8927 | nft_unregister_flowtable_ops(net, flowtable, ops); | 9044 | nft_unregister_flowtable_ops(net, flowtable, ops); |
| 8928 | } | 9045 | } |
| 8929 | list_del_rcu(&hook->list); | 9046 | nft_netdev_hook_unlink_free_rcu(hook); |
| 8930 | nft_netdev_hook_free_rcu(hook); | ||
| 8931 | } | 9047 | } |
| 8932 | 9048 | ||
| 8933 | return err; | 9049 | return err; |
| @@ -8937,9 +9053,25 @@ static void nft_hooks_destroy(struct list_head *hook_list) · 3 unmodified lines | |||
| 8937 | { | 9053 | { |
| 8938 | struct nft_hook *hook, *next; | 9054 | struct nft_hook *hook, *next; |
| 8939 | 9055 | ||
| 8940 | list_for_each_entry_safe(hook, next, hook_list, list) { | 9056 | list_for_each_entry_safe(hook, next, hook_list, list) |
| 8941 | list_del_rcu(&hook->list); | 9057 | nft_netdev_hook_unlink_free_rcu(hook); |
| 8942 | nft_netdev_hook_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 | nft_unregister_flowtable_ops(ctx->net, | 9160 | nft_unregister_flowtable_ops(ctx->net, |
| 9029 | flowtable, ops); | 9161 | flowtable, ops); |
| 9030 | } | 9162 | } |
| 9031 | list_del_rcu(&hook->list); | 9163 | nft_netdev_hook_unlink_free_rcu(hook); |
| 9032 | nft_netdev_hook_free_rcu(hook); | ||
| 9033 | } | 9164 | } |
| 9034 | 9165 | ||
| 9035 | return err; | 9166 | return err; |
| @@ -9202,7 +9333,10 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx, · 166 unmodified lines | |||
| 9202 | err = -ENOENT; | 9333 | err = -ENOENT; |
| 9203 | goto err_flowtable_del_hook; | 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 | trans = nft_trans_alloc(ctx, NFT_MSG_DELFLOWTABLE, | 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 | return 0; | 9357 | return 0; |
| 9224 | 9358 | ||
| 9225 | err_flowtable_del_hook: | 9359 | err_flowtable_del_hook: |
| 9226 | list_splice(&flowtable_del_list, &flowtable->hook_list); | 9360 | nft_trans_delhook_abort(&flowtable_del_list); |
| 9227 | nft_flowtable_hook_release(&flowtable_hook); | 9361 | nft_flowtable_hook_release(&flowtable_hook); |
| 9228 | 9362 | ||
| 9229 | return err; | 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 | u32 portid, u32 seq, int event, | 9422 | u32 portid, u32 seq, int event, |
| 9289 | u32 flags, int family, | 9423 | u32 flags, int family, |
| 9290 | struct nft_flowtable *flowtable, | 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 | struct nlattr *nest, *nest_devs; | 9429 | struct nlattr *nest, *nest_devs; |
| 9294 | struct nft_hook *hook; | 9430 | struct nft_hook *hook; |
| 9295 | struct nlmsghdr *nlh; | 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 | NFTA_FLOWTABLE_PAD)) | 9442 | NFTA_FLOWTABLE_PAD)) |
| 9307 | goto nla_put_failure; | 9443 | goto nla_put_failure; |
| 9308 | 9444 | ||
| 9309 | if (!hook_list && | 9445 | if (!hook_list && !trans_hook_list && |
| 9310 | (event == NFT_MSG_DELFLOWTABLE || | 9446 | (event == NFT_MSG_DELFLOWTABLE || |
| 9311 | event == NFT_MSG_DESTROYFLOWTABLE)) { | 9447 | event == NFT_MSG_DESTROYFLOWTABLE)) { |
| 9312 | nlmsg_end(skb, nlh); | 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 | if (!nest_devs) | 9464 | if (!nest_devs) |
| 9329 | goto nla_put_failure; | 9465 | goto nla_put_failure; |
| 9330 | 9466 | ||
| 9331 | if (!hook_list) | 9467 | if (!hook_list && !trans_hook_list) |
| 9332 | hook_list = &flowtable->hook_list; | 9468 | hook_list = &flowtable->hook_list; |
| 9333 | 9469 | ||
| 9334 | list_for_each_entry_rcu(hook, hook_list, list, | 9470 | if (hook_list) { |
| 9335 | lockdep_commit_lock_is_held(net)) { | 9471 | list_for_each_entry_rcu(hook, hook_list, list, |
| 9336 | if (nft_nla_put_hook_dev(skb, hook)) | 9472 | lockdep_commit_lock_is_held(net)) { |
| 9337 | goto nla_put_failure; | 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 | nla_nest_end(skb, nest_devs); | 9482 | nla_nest_end(skb, nest_devs); |
| 9340 | nla_nest_end(skb, nest); | 9483 | nla_nest_end(skb, nest); |
| @@ -9388,7 +9531,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb, · 47 unmodified lines | |||
| 9388 | NFT_MSG_NEWFLOWTABLE, | 9531 | NFT_MSG_NEWFLOWTABLE, |
| 9389 | NLM_F_MULTI | NLM_F_APPEND, | 9532 | NLM_F_MULTI | NLM_F_APPEND, |
| 9390 | table->family, | 9533 | table->family, |
| 9391 | flowtable, NULL) < 0) | 9534 | flowtable, NULL, NULL) < 0) |
| 9392 | goto done; | 9535 | goto done; |
| 9393 | 9536 | ||
| 9394 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | 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 | err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid, | 9631 | err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid, |
| 9489 | info->nlh->nlmsg_seq, | 9632 | info->nlh->nlmsg_seq, |
| 9490 | NFT_MSG_NEWFLOWTABLE, 0, family, | 9633 | NFT_MSG_NEWFLOWTABLE, 0, family, |
| 9491 | flowtable, NULL); | 9634 | flowtable, NULL, NULL); |
| 9492 | if (err < 0) | 9635 | if (err < 0) |
| 9493 | goto err_fill_flowtable_info; | 9636 | goto err_fill_flowtable_info; |
| 9494 | 9637 | ||
| @@ -9501,7 +9644,9 @@ err_fill_flowtable_info: · 6 unmodified lines | |||
| 9501 | 9644 | ||
| 9502 | static void nf_tables_flowtable_notify(struct nft_ctx *ctx, | 9645 | static void nf_tables_flowtable_notify(struct nft_ctx *ctx, |
| 9503 | struct nft_flowtable *flowtable, | 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 | struct nftables_pernet *nft_net = nft_pernet(ctx->net); | 9651 | struct nftables_pernet *nft_net = nft_pernet(ctx->net); |
| 9507 | struct sk_buff *skb; | 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 | err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, | 9667 | err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, |
| 9523 | ctx->seq, event, flags, | 9668 | ctx->seq, event, flags, |
| 9524 | ctx->family, flowtable, hook_list); | 9669 | ctx->family, flowtable, |
| 9670 | hook_list, trans_hook_list); | ||
| 9525 | if (err < 0) { | 9671 | if (err < 0) { |
| 9526 | kfree_skb(skb); | 9672 | kfree_skb(skb); |
| 9527 | goto err; | 9673 | goto err; |
| @@ -9535,13 +9681,8 @@ err: · 7 unmodified lines | |||
| 9535 | 9681 | ||
| 9536 | static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) | 9682 | static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) |
| 9537 | { | 9683 | { |
| 9538 | struct nft_hook *hook, *next; | ||
| 9539 | |||
| 9540 | flowtable->data.type->free(&flowtable->data); | 9684 | flowtable->data.type->free(&flowtable->data); |
| 9541 | list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) { | 9685 | nft_hooks_destroy(&flowtable->hook_list); |
| 9542 | list_del_rcu(&hook->list); | ||
| 9543 | nft_netdev_hook_free_rcu(hook); | ||
| 9544 | } | ||
| 9545 | kfree(flowtable->name); | 9686 | kfree(flowtable->name); |
| 9546 | module_put(flowtable->data.type->owner); | 9687 | module_put(flowtable->data.type->owner); |
| 9547 | kfree(flowtable); | 9688 | kfree(flowtable); |
| @@ -10060,9 +10201,7 @@ static void nft_commit_release(struct nft_trans *trans) · 512 unmodified lines | |||
| 10060 | break; | 10201 | break; |
| 10061 | case NFT_MSG_DELCHAIN: | 10202 | case NFT_MSG_DELCHAIN: |
| 10062 | case NFT_MSG_DESTROYCHAIN: | 10203 | case NFT_MSG_DESTROYCHAIN: |
| 10063 | if (nft_trans_chain_update(trans)) | 10204 | if (!nft_trans_chain_update(trans)) |
| 10064 | nft_hooks_destroy(&nft_trans_chain_hooks(trans)); | ||
| 10065 | else | ||
| 10066 | nf_tables_chain_destroy(nft_trans_chain(trans)); | 10205 | nf_tables_chain_destroy(nft_trans_chain(trans)); |
| 10067 | break; | 10206 | break; |
| 10068 | case NFT_MSG_DELRULE: | 10207 | case NFT_MSG_DELRULE: |
| @@ -10083,9 +10222,7 @@ static void nft_commit_release(struct nft_trans *trans) · 14 unmodified lines | |||
| 10083 | break; | 10222 | break; |
| 10084 | case NFT_MSG_DELFLOWTABLE: | 10223 | case NFT_MSG_DELFLOWTABLE: |
| 10085 | case NFT_MSG_DESTROYFLOWTABLE: | 10224 | case NFT_MSG_DESTROYFLOWTABLE: |
| 10086 | if (nft_trans_flowtable_update(trans)) | 10225 | if (!nft_trans_flowtable_update(trans)) |
| 10087 | nft_hooks_destroy(&nft_trans_flowtable_hooks(trans)); | ||
| 10088 | else | ||
| 10089 | nf_tables_flowtable_destroy(nft_trans_flowtable(trans)); | 10226 | nf_tables_flowtable_destroy(nft_trans_flowtable(trans)); |
| 10090 | break; | 10227 | break; |
| 10091 | } | 10228 | } |
| @@ -10845,31 +10982,28 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) · 753 unmodified lines | |||
| 10845 | if (nft_trans_chain_update(trans)) { | 10982 | if (nft_trans_chain_update(trans)) { |
| 10846 | nft_chain_commit_update(nft_trans_container_chain(trans)); | 10983 | nft_chain_commit_update(nft_trans_container_chain(trans)); |
| 10847 | nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, | 10984 | nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, |
| 10848 | &nft_trans_chain_hooks(trans)); | 10985 | &nft_trans_chain_hooks(trans), NULL); |
| 10849 | list_splice(&nft_trans_chain_hooks(trans), | 10986 | list_splice_rcu(&nft_trans_chain_hooks(trans), |
| 10850 | &nft_trans_basechain(trans)->hook_list); | 10987 | &nft_trans_basechain(trans)->hook_list); |
| 10851 | /* trans destroyed after rcu grace period */ | 10988 | /* trans destroyed after rcu grace period */ |
| 10852 | } else { | 10989 | } else { |
| 10853 | nft_chain_commit_drop_policy(nft_trans_container_chain(trans)); | 10990 | nft_chain_commit_drop_policy(nft_trans_container_chain(trans)); |
| 10854 | nft_clear(net, nft_trans_chain(trans)); | 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 | nft_trans_destroy(trans); | 10993 | nft_trans_destroy(trans); |
| 10857 | } | 10994 | } |
| 10858 | break; | 10995 | break; |
| 10859 | case NFT_MSG_DELCHAIN: | 10996 | case NFT_MSG_DELCHAIN: |
| 10860 | case NFT_MSG_DESTROYCHAIN: | 10997 | case NFT_MSG_DESTROYCHAIN: |
| 10861 | if (nft_trans_chain_update(trans)) { | 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 | &nft_trans_chain_hooks(trans)); | 11000 | &nft_trans_chain_hooks(trans)); |
| 10864 | if (!(table->flags & NFT_TABLE_F_DORMANT)) { | 11001 | nft_netdev_unregister_trans_hook(net, table, |
| 10865 | nft_netdev_unregister_hooks(net, | 11002 | &nft_trans_chain_hooks(trans)); |
| 10866 | &nft_trans_chain_hooks(trans), | ||
| 10867 | true); | ||
| 10868 | } | ||
| 10869 | } else { | 11003 | } else { |
| 10870 | nft_chain_del(nft_trans_chain(trans)); | 11004 | nft_chain_del(nft_trans_chain(trans)); |
| 10871 | nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, | 11005 | nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, |
| 10872 | NULL); | 11006 | NULL, NULL); |
| 10873 | nf_tables_unregister_hook(ctx.net, ctx.table, | 11007 | nf_tables_unregister_hook(ctx.net, ctx.table, |
| 10874 | nft_trans_chain(trans)); | 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 | nf_tables_flowtable_notify(&ctx, | 11109 | nf_tables_flowtable_notify(&ctx, |
| 10976 | nft_trans_flowtable(trans), | 11110 | nft_trans_flowtable(trans), |
| 10977 | &nft_trans_flowtable_hooks(trans), | 11111 | &nft_trans_flowtable_hooks(trans), |
| 11112 | NULL, | ||
| 10978 | NFT_MSG_NEWFLOWTABLE); | 11113 | NFT_MSG_NEWFLOWTABLE); |
| 10979 | list_splice(&nft_trans_flowtable_hooks(trans), | 11114 | list_splice_rcu(&nft_trans_flowtable_hooks(trans), |
| 10980 | &nft_trans_flowtable(trans)->hook_list); | 11115 | &nft_trans_flowtable(trans)->hook_list); |
| 10981 | } else { | 11116 | } else { |
| 10982 | nft_clear(net, nft_trans_flowtable(trans)); | 11117 | nft_clear(net, nft_trans_flowtable(trans)); |
| 10983 | nf_tables_flowtable_notify(&ctx, | 11118 | nf_tables_flowtable_notify(&ctx, |
| 10984 | nft_trans_flowtable(trans), | 11119 | nft_trans_flowtable(trans), |
| 10985 | NULL, | 11120 | NULL, |
| 11121 | NULL, | ||
| 10986 | NFT_MSG_NEWFLOWTABLE); | 11122 | NFT_MSG_NEWFLOWTABLE); |
| 10987 | } | 11123 | } |
| 10988 | nft_trans_destroy(trans); | 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 | if (nft_trans_flowtable_update(trans)) { | 11128 | if (nft_trans_flowtable_update(trans)) { |
| 10993 | nf_tables_flowtable_notify(&ctx, | 11129 | nf_tables_flowtable_notify(&ctx, |
| 10994 | nft_trans_flowtable(trans), | 11130 | nft_trans_flowtable(trans), |
| 11131 | NULL, | ||
| 10995 | &nft_trans_flowtable_hooks(trans), | 11132 | &nft_trans_flowtable_hooks(trans), |
| 10996 | trans->msg_type); | 11133 | trans->msg_type); |
| 10997 | nft_unregister_flowtable_net_hooks(net, | 11134 | nft_flowtable_unregister_trans_hook(net, |
| 10998 | nft_trans_flowtable(trans), | 11135 | nft_trans_flowtable(trans), |
| 10999 | &nft_trans_flowtable_hooks(trans)); | 11136 | &nft_trans_flowtable_hooks(trans)); |
| 11000 | } else { | 11137 | } else { |
| 11001 | list_del_rcu(&nft_trans_flowtable(trans)->list); | 11138 | list_del_rcu(&nft_trans_flowtable(trans)->list); |
| 11002 | nf_tables_flowtable_notify(&ctx, | 11139 | nf_tables_flowtable_notify(&ctx, |
| 11003 | nft_trans_flowtable(trans), | 11140 | nft_trans_flowtable(trans), |
| 11004 | NULL, | 11141 | NULL, |
| 11142 | NULL, | ||
| 11005 | trans->msg_type); | 11143 | trans->msg_type); |
| 11006 | nft_unregister_flowtable_net_hooks(net, | 11144 | nft_unregister_flowtable_net_hooks(net, |
| 11007 | nft_trans_flowtable(trans), | 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 | case NFT_MSG_DELCHAIN: | 11303 | case NFT_MSG_DELCHAIN: |
| 11166 | case NFT_MSG_DESTROYCHAIN: | 11304 | case NFT_MSG_DESTROYCHAIN: |
| 11167 | if (nft_trans_chain_update(trans)) { | 11305 | if (nft_trans_chain_update(trans)) { |
| 11168 | list_splice(&nft_trans_chain_hooks(trans), | 11306 | nft_trans_delhook_abort(&nft_trans_chain_hooks(trans)); |
| 11169 | &nft_trans_basechain(trans)->hook_list); | ||
| 11170 | } else { | 11307 | } else { |
| 11171 | nft_use_inc_restore(&table->use); | 11308 | nft_use_inc_restore(&table->use); |
| 11172 | nft_clear(trans->net, nft_trans_chain(trans)); | 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 | case NFT_MSG_DELFLOWTABLE: | 11417 | case NFT_MSG_DELFLOWTABLE: |
| 11281 | case NFT_MSG_DESTROYFLOWTABLE: | 11418 | case NFT_MSG_DESTROYFLOWTABLE: |
| 11282 | if (nft_trans_flowtable_update(trans)) { | 11419 | if (nft_trans_flowtable_update(trans)) { |
| 11283 | list_splice(&nft_trans_flowtable_hooks(trans), | 11420 | nft_trans_delhook_abort(&nft_trans_flowtable_hooks(trans)); |
| 11284 | &nft_trans_flowtable(trans)->hook_list); | ||
| 11285 | } else { | 11421 | } else { |
| 11286 | nft_use_inc_restore(&table->use); | 11422 | nft_use_inc_restore(&table->use); |
| 11287 | nft_clear(trans->net, nft_trans_flowtable(trans)); | 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 | if (err < 0) | 196 | if (err < 0) |
| 197 | return err; | 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 | nft_data_release(&priv->data, desc.type); | 201 | nft_data_release(&priv->data, desc.type); |
| 201 | return -EINVAL; | 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 | return 0; | 63 | return 0; |
| 64 | 64 | ||
| 65 | for (i = sp->len - 1; i >= 0; i--) { | 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 | if (pos >= info->len) | 67 | if (pos >= info->len) |
| 68 | return 0; | 68 | return 0; |
| 69 | e = &info->pol[pos]; | 69 | e = &info->pol[pos]; |
| @@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock) · 207 unmodified lines | |||
| 208 | sa.spn_family = AF_PHONET; | 208 | sa.spn_family = AF_PHONET; |
| 209 | err = pn_socket_bind(sock, (struct sockaddr_unsized *)&sa, | 209 | err = pn_socket_bind(sock, (struct sockaddr_unsized *)&sa, |
| 210 | sizeof(struct sockaddr_pn)); | 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 | return err; | 219 | return err; |
| 213 | BUG_ON(!pn_port(pn_sk(sock->sk)->sobject)); | ||
| 214 | return 0; /* socket was already bound */ | 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 | .post_doit = psp_device_unlock, | 76 | .post_doit = psp_device_unlock, |
| 77 | .policy = psp_dev_set_nl_policy, | 77 | .policy = psp_dev_set_nl_policy, |
| 78 | .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA, | 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 | .cmd = PSP_CMD_KEY_ROTATE, | 82 | .cmd = PSP_CMD_KEY_ROTATE, |
| @@ -85,7 +85,7 @@ static const struct genl_split_ops psp_nl_ops[] = { · 2 unmodified lines | |||
| 85 | .post_doit = psp_device_unlock, | 85 | .post_doit = psp_device_unlock, |
| 86 | .policy = psp_key_rotate_nl_policy, | 86 | .policy = psp_key_rotate_nl_policy, |
| 87 | .maxattr = PSP_A_DEV_ID, | 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 | .cmd = PSP_CMD_RX_ASSOC, | 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 | psd = psp_dev_get_for_sock(socket->sk); | 306 | psd = psp_dev_get_for_sock(socket->sk); |
| 307 | if (psd) { | 307 | if (psd) { |
| 308 | err = psp_dev_check_access(psd, genl_info_net(info)); | 308 | /* Extra care needed here, psp_dev_get_for_sock() only gives |
| 309 | if (err) { | 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 | psp_dev_put(psd); | 315 | psp_dev_put(psd); |
| 311 | psd = NULL; | 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 | id = info->attrs[PSP_A_ASSOC_DEV_ID]; | 325 | id = info->attrs[PSP_A_ASSOC_DEV_ID]; |
| 321 | if (psd) { | 326 | if (psd) { |
| 322 | mutex_lock(&psd->lock); | ||
| 323 | if (id && psd->id != nla_get_u32(id)) { | 327 | if (id && psd->id != nla_get_u32(id)) { |
| 324 | mutex_unlock(&psd->lock); | 328 | mutex_unlock(&psd->lock); |
| 325 | NL_SET_ERR_MSG_ATTR(info->extack, id, | 329 | NL_SET_ERR_MSG_ATTR(info->extack, id, |
| @@ -813,7 +813,7 @@ skip_hash: · 812 unmodified lines | |||
| 813 | i++, k = (k + 1) % CAKE_SET_WAYS) { | 813 | i++, k = (k + 1) % CAKE_SET_WAYS) { |
| 814 | if (q->tags[outer_hash + k] == flow_hash) { | 814 | if (q->tags[outer_hash + k] == flow_hash) { |
| 815 | if (i) | 815 | if (i) |
| 816 | q->way_hits++; | 816 | WRITE_ONCE(q->way_hits, q->way_hits + 1); |
| 817 | 817 | ||
| 818 | if (!q->flows[outer_hash + k].set) { | 818 | if (!q->flows[outer_hash + k].set) { |
| 819 | /* need to increment host refcnts */ | 819 | /* need to increment host refcnts */ |
| @@ -831,7 +831,7 @@ skip_hash: · 11 unmodified lines | |||
| 831 | for (i = 0; i < CAKE_SET_WAYS; | 831 | for (i = 0; i < CAKE_SET_WAYS; |
| 832 | i++, k = (k + 1) % CAKE_SET_WAYS) { | 832 | i++, k = (k + 1) % CAKE_SET_WAYS) { |
| 833 | if (!q->flows[outer_hash + k].set) { | 833 | if (!q->flows[outer_hash + k].set) { |
| 834 | q->way_misses++; | 834 | WRITE_ONCE(q->way_misses, q->way_misses + 1); |
| 835 | allocate_src = cake_dsrc(flow_mode); | 835 | allocate_src = cake_dsrc(flow_mode); |
| 836 | allocate_dst = cake_ddst(flow_mode); | 836 | allocate_dst = cake_ddst(flow_mode); |
| 837 | goto found; | 837 | goto found; |
| @@ -841,7 +841,7 @@ skip_hash: · 3 unmodified lines | |||
| 841 | /* With no empty queues, default to the original | 841 | /* With no empty queues, default to the original |
| 842 | * queue, accept the collision, update the host tags. | 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 | allocate_src = cake_dsrc(flow_mode); | 845 | allocate_src = cake_dsrc(flow_mode); |
| 846 | allocate_dst = cake_ddst(flow_mode); | 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 | len -= off; | 1379 | len -= off; |
| 1380 | 1380 | ||
| 1381 | if (qd->max_netlen < len) | 1381 | if (qd->max_netlen < len) |
| 1382 | qd->max_netlen = len; | 1382 | WRITE_ONCE(qd->max_netlen, len); |
| 1383 | if (qd->min_netlen > len) | 1383 | if (qd->min_netlen > len) |
| 1384 | qd->min_netlen = len; | 1384 | WRITE_ONCE(qd->min_netlen, len); |
| 1385 | 1385 | ||
| 1386 | len += q->rate_overhead; | 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 | if (qd->max_adjlen < len) | 1403 | if (qd->max_adjlen < len) |
| 1404 | qd->max_adjlen = len; | 1404 | WRITE_ONCE(qd->max_adjlen, len); |
| 1405 | if (qd->min_adjlen > len) | 1405 | if (qd->min_adjlen > len) |
| 1406 | qd->min_adjlen = len; | 1406 | WRITE_ONCE(qd->min_adjlen, len); |
| 1407 | 1407 | ||
| 1408 | return len; | 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 | u16 segs = qdisc_pkt_segs(skb); | 1416 | u16 segs = qdisc_pkt_segs(skb); |
| 1417 | u32 len = qdisc_pkt_len(skb); | 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 | if (segs == 1) | 1421 | if (segs == 1) |
| 1422 | return cake_calc_overhead(q, len, off); | 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 | if (cobalt_queue_full(&flow->cvars, &b->cparams, now)) | 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 | len = qdisc_pkt_len(skb); | 1596 | len = qdisc_pkt_len(skb); |
| 1596 | q->buffer_used -= skb->truesize; | 1597 | q->buffer_used -= skb->truesize; |
| 1597 | b->backlogs[idx] -= len; | 1598 | b->backlogs[idx] -= len; |
| 1598 | b->tin_backlog -= len; | 1599 | WRITE_ONCE(b->tin_backlog, b->tin_backlog - len); |
| 1599 | sch->qstats.backlog -= len; | 1600 | sch->qstats.backlog -= len; |
| 1600 | 1601 | ||
| 1601 | flow->dropped++; | 1602 | flow->dropped++; |
| 1602 | b->tin_dropped++; | 1603 | WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); |
| 1603 | 1604 | ||
| 1604 | if (q->config->rate_flags & CAKE_FLAG_INGRESS) | 1605 | if (q->config->rate_flags & CAKE_FLAG_INGRESS) |
| 1605 | cake_advance_shaper(q, b, skb, now, true); | 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 | if (unlikely(len > b->max_skblen)) | 1798 | if (unlikely(len > b->max_skblen)) |
| 1798 | b->max_skblen = len; | 1799 | WRITE_ONCE(b->max_skblen, len); |
| 1799 | 1800 | ||
| 1800 | if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) { | 1801 | if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) { |
| 1801 | struct sk_buff *segs, *nskb; | 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 | numsegs++; | 1820 | numsegs++; |
| 1820 | slen += segs->len; | 1821 | slen += segs->len; |
| 1821 | q->buffer_used += segs->truesize; | 1822 | q->buffer_used += segs->truesize; |
| 1822 | b->packets++; | 1823 | WRITE_ONCE(b->packets, b->packets + 1); |
| 1823 | } | 1824 | } |
| 1824 | 1825 | ||
| 1825 | /* stats */ | 1826 | /* stats */ |
| 1826 | b->bytes += slen; | ||
| 1827 | b->backlogs[idx] += slen; | 1827 | b->backlogs[idx] += slen; |
| 1828 | b->tin_backlog += slen; | ||
| 1829 | sch->qstats.backlog += slen; | 1828 | sch->qstats.backlog += slen; |
| 1830 | q->avg_window_bytes += slen; | 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 | qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); | 1833 | qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); |
| 1833 | consume_skb(skb); | 1834 | consume_skb(skb); |
| @@ -1843,10 +1844,10 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 9 unmodified lines | |||
| 1843 | ack = cake_ack_filter(q, flow); | 1844 | ack = cake_ack_filter(q, flow); |
| 1844 | 1845 | ||
| 1845 | if (ack) { | 1846 | if (ack) { |
| 1846 | b->ack_drops++; | 1847 | WRITE_ONCE(b->ack_drops, b->ack_drops + 1); |
| 1847 | sch->qstats.drops++; | 1848 | sch->qstats.drops++; |
| 1848 | ack_pkt_len = qdisc_pkt_len(ack); | 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 | q->buffer_used += skb->truesize - ack->truesize; | 1851 | q->buffer_used += skb->truesize - ack->truesize; |
| 1851 | if (q->config->rate_flags & CAKE_FLAG_INGRESS) | 1852 | if (q->config->rate_flags & CAKE_FLAG_INGRESS) |
| 1852 | cake_advance_shaper(q, b, ack, now, true); | 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 | /* stats */ | 1862 | /* stats */ |
| 1862 | b->packets++; | 1863 | WRITE_ONCE(b->packets, b->packets + 1); |
| 1863 | b->bytes += len - ack_pkt_len; | ||
| 1864 | b->backlogs[idx] += len - ack_pkt_len; | 1864 | b->backlogs[idx] += len - ack_pkt_len; |
| 1865 | b->tin_backlog += len - ack_pkt_len; | ||
| 1866 | sch->qstats.backlog += len - ack_pkt_len; | 1865 | sch->qstats.backlog += len - ack_pkt_len; |
| 1867 | q->avg_window_bytes += len - ack_pkt_len; | 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 | if (q->overflow_timeout) | 1871 | if (q->overflow_timeout) |
| @@ -1894,9 +1895,9 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 23 unmodified lines | |||
| 1894 | u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC; | 1895 | u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC; |
| 1895 | 1896 | ||
| 1896 | b = div64_u64(b, window_interval); | 1897 | b = div64_u64(b, window_interval); |
| 1897 | q->avg_peak_bandwidth = | 1898 | WRITE_ONCE(q->avg_peak_bandwidth, |
| 1898 | cake_ewma(q->avg_peak_bandwidth, b, | 1899 | cake_ewma(q->avg_peak_bandwidth, b, |
| 1899 | b > q->avg_peak_bandwidth ? 2 : 8); | 1900 | b > q->avg_peak_bandwidth ? 2 : 8)); |
| 1900 | q->avg_window_bytes = 0; | 1901 | q->avg_window_bytes = 0; |
| 1901 | q->avg_window_begin = now; | 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 | if (!flow->set) { | 1918 | if (!flow->set) { |
| 1918 | list_add_tail(&flow->flowchain, &b->new_flows); | 1919 | list_add_tail(&flow->flowchain, &b->new_flows); |
| 1919 | } else { | 1920 | } else { |
| 1920 | b->decaying_flow_count--; | 1921 | WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1); |
| 1921 | list_move_tail(&flow->flowchain, &b->new_flows); | 1922 | list_move_tail(&flow->flowchain, &b->new_flows); |
| 1922 | } | 1923 | } |
| 1923 | flow->set = CAKE_SET_SPARSE; | 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 | flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode); | 1927 | flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode); |
| 1927 | } else if (flow->set == CAKE_SET_SPARSE_WAIT) { | 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 | * in the bulk rotation. | 1930 | * in the bulk rotation. |
| 1930 | */ | 1931 | */ |
| 1931 | flow->set = CAKE_SET_BULK; | 1932 | flow->set = CAKE_SET_BULK; |
| 1932 | b->sparse_flow_count--; | 1933 | WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); |
| 1933 | b->bulk_flow_count++; | 1934 | WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1); |
| 1934 | 1935 | ||
| 1935 | cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); | 1936 | cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 1936 | cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); | 1937 | cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 1937 | } | 1938 | } |
| 1938 | 1939 | ||
| 1939 | if (q->buffer_used > q->buffer_max_used) | 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 | if (q->buffer_used <= q->buffer_limit) | 1943 | if (q->buffer_used <= q->buffer_limit) |
| 1943 | return NET_XMIT_SUCCESS; | 1944 | return NET_XMIT_SUCCESS; |
| @@ -1977,7 +1978,7 @@ static struct sk_buff *cake_dequeue_one(struct Qdisc *sch) · 33 unmodified lines | |||
| 1977 | skb = dequeue_head(flow); | 1978 | skb = dequeue_head(flow); |
| 1978 | len = qdisc_pkt_len(skb); | 1979 | len = qdisc_pkt_len(skb); |
| 1979 | b->backlogs[q->cur_flow] -= len; | 1980 | b->backlogs[q->cur_flow] -= len; |
| 1980 | b->tin_backlog -= len; | 1981 | WRITE_ONCE(b->tin_backlog, b->tin_backlog - len); |
| 1981 | sch->qstats.backlog -= len; | 1982 | sch->qstats.backlog -= len; |
| 1982 | q->buffer_used -= skb->truesize; | 1983 | q->buffer_used -= skb->truesize; |
| 1983 | sch->q.qlen--; | 1984 | sch->q.qlen--; |
| @@ -2042,7 +2043,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) · 58 unmodified lines | |||
| 2042 | 2043 | ||
| 2043 | cake_configure_rates(sch, new_rate, true); | 2044 | cake_configure_rates(sch, new_rate, true); |
| 2044 | q->last_checked_active = now; | 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 | begin: | 2049 | begin: |
| @@ -2149,8 +2150,8 @@ retry: · 100 unmodified lines | |||
| 2149 | */ | 2150 | */ |
| 2150 | if (flow->set == CAKE_SET_SPARSE) { | 2151 | if (flow->set == CAKE_SET_SPARSE) { |
| 2151 | if (flow->head) { | 2152 | if (flow->head) { |
| 2152 | b->sparse_flow_count--; | 2153 | WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); |
| 2153 | b->bulk_flow_count++; | 2154 | WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1); |
| 2154 | 2155 | ||
| 2155 | cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); | 2156 | cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2156 | cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); | 2157 | cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| @@ -2177,7 +2178,8 @@ retry: · 20 unmodified lines | |||
| 2177 | if (!skb) { | 2178 | if (!skb) { |
| 2178 | /* this queue was actually empty */ | 2179 | /* this queue was actually empty */ |
| 2179 | if (cobalt_queue_empty(&flow->cvars, &b->cparams, now)) | 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 | if (flow->cvars.p_drop || flow->cvars.count || | 2184 | if (flow->cvars.p_drop || flow->cvars.count || |
| 2183 | ktime_before(now, flow->cvars.drop_next)) { | 2185 | ktime_before(now, flow->cvars.drop_next)) { |
| @@ -2187,32 +2189,32 @@ retry: · 3 unmodified lines | |||
| 2187 | list_move_tail(&flow->flowchain, | 2189 | list_move_tail(&flow->flowchain, |
| 2188 | &b->decaying_flows); | 2190 | &b->decaying_flows); |
| 2189 | if (flow->set == CAKE_SET_BULK) { | 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 | cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); | 2194 | cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2193 | cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); | 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 | } else if (flow->set == CAKE_SET_SPARSE || | 2198 | } else if (flow->set == CAKE_SET_SPARSE || |
| 2197 | flow->set == CAKE_SET_SPARSE_WAIT) { | 2199 | flow->set == CAKE_SET_SPARSE_WAIT) { |
| 2198 | b->sparse_flow_count--; | 2200 | WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); |
| 2199 | b->decaying_flow_count++; | 2201 | WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1); |
| 2200 | } | 2202 | } |
| 2201 | flow->set = CAKE_SET_DECAYING; | 2203 | flow->set = CAKE_SET_DECAYING; |
| 2202 | } else { | 2204 | } else { |
| 2203 | /* remove empty queue from the flowchain */ | 2205 | /* remove empty queue from the flowchain */ |
| 2204 | list_del_init(&flow->flowchain); | 2206 | list_del_init(&flow->flowchain); |
| 2205 | if (flow->set == CAKE_SET_SPARSE || | 2207 | if (flow->set == CAKE_SET_SPARSE || |
| 2206 | flow->set == CAKE_SET_SPARSE_WAIT) | 2208 | flow->set == CAKE_SET_SPARSE_WAIT) { |
| 2207 | b->sparse_flow_count--; | 2209 | WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); |
| 2208 | else if (flow->set == CAKE_SET_BULK) { | 2210 | } else if (flow->set == CAKE_SET_BULK) { |
| 2209 | b->bulk_flow_count--; | 2211 | WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1); |
| 2210 | 2212 | ||
| 2211 | cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); | 2213 | cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2212 | cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); | 2214 | cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); |
| 2213 | } else | 2215 | } else { |
| 2214 | b->decaying_flow_count--; | 2216 | WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1); |
| 2215 | 2217 | } | |
| 2216 | flow->set = CAKE_SET_NONE; | 2218 | flow->set = CAKE_SET_NONE; |
| 2217 | } | 2219 | } |
| 2218 | goto begin; | 2220 | goto begin; |
| @@ -2234,7 +2236,7 @@ retry: · 15 unmodified lines | |||
| 2234 | b->tin_deficit -= len; | 2236 | b->tin_deficit -= len; |
| 2235 | } | 2237 | } |
| 2236 | flow->dropped++; | 2238 | flow->dropped++; |
| 2237 | b->tin_dropped++; | 2239 | WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); |
| 2238 | qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); | 2240 | qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); |
| 2239 | qdisc_qstats_drop(sch); | 2241 | qdisc_qstats_drop(sch); |
| 2240 | qdisc_dequeue_drop(sch, skb, reason); | 2242 | qdisc_dequeue_drop(sch, skb, reason); |
| @@ -2242,17 +2244,19 @@ retry: · 1 unmodified line | |||
| 2242 | goto retry; | 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 | qdisc_bstats_update(sch, skb); | 2248 | qdisc_bstats_update(sch, skb); |
| 2247 | WRITE_ONCE(q->last_active, now); | 2249 | WRITE_ONCE(q->last_active, now); |
| 2248 | 2250 | ||
| 2249 | /* collect delay stats */ | 2251 | /* collect delay stats */ |
| 2250 | delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); | 2252 | delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); |
| 2251 | b->avge_delay = cake_ewma(b->avge_delay, delay, 8); | 2253 | WRITE_ONCE(b->avge_delay, cake_ewma(b->avge_delay, delay, 8)); |
| 2252 | b->peak_delay = cake_ewma(b->peak_delay, delay, | 2254 | WRITE_ONCE(b->peak_delay, |
| 2253 | delay > b->peak_delay ? 2 : 8); | 2255 | cake_ewma(b->peak_delay, delay, |
| 2254 | b->base_delay = cake_ewma(b->base_delay, delay, | 2256 | delay > b->peak_delay ? 2 : 8)); |
| 2255 | delay < b->base_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 | len = cake_advance_shaper(q, b, skb, now, false); | 2261 | len = cake_advance_shaper(q, b, skb, now, false); |
| 2258 | flow->deficit -= len; | 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 | u8 rate_shft = 0; | 2333 | u8 rate_shft = 0; |
| 2330 | u64 rate_ns = 0; | 2334 | u64 rate_ns = 0; |
| 2331 | 2335 | ||
| 2332 | b->flow_quantum = 1514; | ||
| 2333 | if (rate) { | 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 | rate_shft = 34; | 2339 | rate_shft = 34; |
| 2336 | rate_ns = ((u64)NSEC_PER_SEC) << rate_shft; | 2340 | rate_ns = ((u64)NSEC_PER_SEC) << rate_shft; |
| 2337 | rate_ns = div64_u64(rate_ns, max(MIN_RATE, rate)); | 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 | rate_ns >>= 1; | 2343 | rate_ns >>= 1; |
| 2340 | rate_shft--; | 2344 | rate_shft--; |
| 2341 | } | 2345 | } |
| 2342 | } /* else unlimited, ie. zero delay */ | 2346 | } else { |
| 2343 | 2347 | /* else unlimited, ie. zero delay */ | |
| 2344 | b->tin_rate_bps = rate; | 2348 | WRITE_ONCE(b->flow_quantum, 1514); |
| 2349 | } | ||
| 2350 | WRITE_ONCE(b->tin_rate_bps, rate); | ||
| 2345 | b->tin_rate_ns = rate_ns; | 2351 | b->tin_rate_ns = rate_ns; |
| 2346 | b->tin_rate_shft = rate_shft; | 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 | byte_target_ns = (byte_target * rate_ns) >> rate_shft; | 2357 | byte_target_ns = (byte_target * rate_ns) >> rate_shft; |
| 2352 | 2358 | ||
| 2353 | b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); | 2359 | WRITE_ONCE(b->cparams.target, |
| 2354 | b->cparams.interval = max(rtt_est_ns + | 2360 | max((byte_target_ns * 3) / 2, target_ns)); |
| 2355 | b->cparams.target - target_ns, | 2361 | WRITE_ONCE(b->cparams.interval, |
| 2356 | b->cparams.target * 2); | 2362 | max(rtt_est_ns + b->cparams.target - target_ns, |
| 2363 | b->cparams.target * 2)); | ||
| 2357 | b->cparams.mtu_time = byte_target_ns; | 2364 | b->cparams.mtu_time = byte_target_ns; |
| 2358 | b->cparams.p_inc = 1 << 24; /* 1/256 */ | 2365 | b->cparams.p_inc = 1 << 24; /* 1/256 */ |
| 2359 | b->cparams.p_dec = 1 << 20; /* 1/4096 */ | 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 | struct cake_sched_data *qd = qdisc_priv(sch); | 2619 | struct cake_sched_data *qd = qdisc_priv(sch); |
| 2613 | struct cake_sched_config *q = qd->config; | 2620 | struct cake_sched_config *q = qd->config; |
| 2621 | u32 buffer_limit; | ||
| 2614 | 2622 | ||
| 2615 | cake_configure_rates(sch, qd->config->rate_bps, false); | 2623 | cake_configure_rates(sch, qd->config->rate_bps, false); |
| 2616 | 2624 | ||
| 2617 | if (q->buffer_config_limit) { | 2625 | if (q->buffer_config_limit) { |
| 2618 | qd->buffer_limit = q->buffer_config_limit; | 2626 | buffer_limit = q->buffer_config_limit; |
| 2619 | } else if (q->rate_bps) { | 2627 | } else if (q->rate_bps) { |
| 2620 | u64 t = q->rate_bps * q->interval; | 2628 | u64 t = q->rate_bps * q->interval; |
| 2621 | 2629 | ||
| 2622 | do_div(t, USEC_PER_SEC / 4); | 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 | } else { | 2632 | } else { |
| 2625 | qd->buffer_limit = ~0; | 2633 | buffer_limit = ~0; |
| 2626 | } | 2634 | } |
| 2627 | 2635 | ||
| 2628 | sch->flags &= ~TCQ_F_CAN_BYPASS; | 2636 | sch->flags &= ~TCQ_F_CAN_BYPASS; |
| 2629 | 2637 | ||
| 2630 | qd->buffer_limit = min(qd->buffer_limit, | 2638 | WRITE_ONCE(qd->buffer_limit, |
| 2631 | max(sch->limit * psched_mtu(qdisc_dev(sch)), | 2639 | min(buffer_limit, |
| 2632 | q->buffer_config_limit)); | 2640 | max(sch->limit * psched_mtu(qdisc_dev(sch)), |
| 2641 | q->buffer_config_limit))); | ||
| 2633 | } | 2642 | } |
| 2634 | 2643 | ||
| 2635 | static int cake_config_change(struct cake_sched_config *q, struct nlattr *opt, | 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 | return ret; | 2783 | return ret; |
| 2775 | 2784 | ||
| 2776 | if (overhead_changed) { | 2785 | if (overhead_changed) { |
| 2777 | qd->max_netlen = 0; | 2786 | WRITE_ONCE(qd->max_netlen, 0); |
| 2778 | qd->max_adjlen = 0; | 2787 | WRITE_ONCE(qd->max_adjlen, 0); |
| 2779 | qd->min_netlen = ~0; | 2788 | WRITE_ONCE(qd->min_netlen, ~0); |
| 2780 | qd->min_adjlen = ~0; | 2789 | WRITE_ONCE(qd->min_adjlen, ~0); |
| 2781 | } | 2790 | } |
| 2782 | 2791 | ||
| 2783 | if (qd->tins) { | 2792 | if (qd->tins) { |
| @@ -2995,15 +3004,15 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) · 211 unmodified lines | |||
| 2995 | goto nla_put_failure; \ | 3004 | goto nla_put_failure; \ |
| 2996 | } while (0) | 3005 | } while (0) |
| 2997 | 3006 | ||
| 2998 | PUT_STAT_U64(CAPACITY_ESTIMATE64, q->avg_peak_bandwidth); | 3007 | PUT_STAT_U64(CAPACITY_ESTIMATE64, READ_ONCE(q->avg_peak_bandwidth)); |
| 2999 | PUT_STAT_U32(MEMORY_LIMIT, q->buffer_limit); | 3008 | PUT_STAT_U32(MEMORY_LIMIT, READ_ONCE(q->buffer_limit)); |
| 3000 | PUT_STAT_U32(MEMORY_USED, q->buffer_max_used); | 3009 | PUT_STAT_U32(MEMORY_USED, READ_ONCE(q->buffer_max_used)); |
| 3001 | PUT_STAT_U32(AVG_NETOFF, ((q->avg_netoff + 0x8000) >> 16)); | 3010 | PUT_STAT_U32(AVG_NETOFF, ((READ_ONCE(q->avg_netoff) + 0x8000) >> 16)); |
| 3002 | PUT_STAT_U32(MAX_NETLEN, q->max_netlen); | 3011 | PUT_STAT_U32(MAX_NETLEN, READ_ONCE(q->max_netlen)); |
| 3003 | PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen); | 3012 | PUT_STAT_U32(MAX_ADJLEN, READ_ONCE(q->max_adjlen)); |
| 3004 | PUT_STAT_U32(MIN_NETLEN, q->min_netlen); | 3013 | PUT_STAT_U32(MIN_NETLEN, READ_ONCE(q->min_netlen)); |
| 3005 | PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen); | 3014 | PUT_STAT_U32(MIN_ADJLEN, READ_ONCE(q->min_adjlen)); |
| 3006 | PUT_STAT_U32(ACTIVE_QUEUES, q->active_queues); | 3015 | PUT_STAT_U32(ACTIVE_QUEUES, READ_ONCE(q->active_queues)); |
| 3007 | 3016 | ||
| 3008 | #undef PUT_STAT_U32 | 3017 | #undef PUT_STAT_U32 |
| 3009 | #undef PUT_STAT_U64 | 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 | if (!ts) | 3038 | if (!ts) |
| 3030 | goto nla_put_failure; | 3039 | goto nla_put_failure; |
| 3031 | 3040 | ||
| 3032 | PUT_TSTAT_U64(THRESHOLD_RATE64, b->tin_rate_bps); | 3041 | PUT_TSTAT_U64(THRESHOLD_RATE64, READ_ONCE(b->tin_rate_bps)); |
| 3033 | PUT_TSTAT_U64(SENT_BYTES64, b->bytes); | 3042 | PUT_TSTAT_U64(SENT_BYTES64, READ_ONCE(b->bytes)); |
| 3034 | PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); | 3043 | PUT_TSTAT_U32(BACKLOG_BYTES, READ_ONCE(b->tin_backlog)); |
| 3035 | 3044 | ||
| 3036 | PUT_TSTAT_U32(TARGET_US, | 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 | PUT_TSTAT_U32(INTERVAL_US, | 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); | 3050 | PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets)); |
| 3042 | PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); | 3051 | PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped)); |
| 3043 | PUT_TSTAT_U32(ECN_MARKED_PACKETS, b->tin_ecn_mark); | 3052 | PUT_TSTAT_U32(ECN_MARKED_PACKETS, READ_ONCE(b->tin_ecn_mark)); |
| 3044 | PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, b->ack_drops); | 3053 | PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, READ_ONCE(b->ack_drops)); |
| 3045 | 3054 | ||
| 3046 | PUT_TSTAT_U32(PEAK_DELAY_US, | 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 | PUT_TSTAT_U32(AVG_DELAY_US, | 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 | PUT_TSTAT_U32(BASE_DELAY_US, | 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); | 3062 | PUT_TSTAT_U32(WAY_INDIRECT_HITS, READ_ONCE(b->way_hits)); |
| 3054 | PUT_TSTAT_U32(WAY_MISSES, b->way_misses); | 3063 | PUT_TSTAT_U32(WAY_MISSES, READ_ONCE(b->way_misses)); |
| 3055 | PUT_TSTAT_U32(WAY_COLLISIONS, b->way_collisions); | 3064 | PUT_TSTAT_U32(WAY_COLLISIONS, READ_ONCE(b->way_collisions)); |
| 3056 | 3065 | ||
| 3057 | PUT_TSTAT_U32(SPARSE_FLOWS, b->sparse_flow_count + | 3066 | PUT_TSTAT_U32(SPARSE_FLOWS, READ_ONCE(b->sparse_flow_count) + |
| 3058 | b->decaying_flow_count); | 3067 | READ_ONCE(b->decaying_flow_count)); |
| 3059 | PUT_TSTAT_U32(BULK_FLOWS, b->bulk_flow_count); | 3068 | PUT_TSTAT_U32(BULK_FLOWS, READ_ONCE(b->bulk_flow_count)); |
| 3060 | PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, b->unresponsive_flow_count); | 3069 | PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, READ_ONCE(b->unresponsive_flow_count)); |
| 3061 | PUT_TSTAT_U32(MAX_SKBLEN, b->max_skblen); | 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 | nla_nest_end(d->skb, ts); | 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 | struct cake_sched_data *qd = qdisc_priv(chld); | 3307 | struct cake_sched_data *qd = qdisc_priv(chld); |
| 3299 | 3308 | ||
| 3300 | if (overhead_changed) { | 3309 | if (overhead_changed) { |
| 3301 | qd->max_netlen = 0; | 3310 | WRITE_ONCE(qd->max_netlen, 0); |
| 3302 | qd->max_adjlen = 0; | 3311 | WRITE_ONCE(qd->max_adjlen, 0); |
| 3303 | qd->min_netlen = ~0; | 3312 | WRITE_ONCE(qd->min_netlen, ~0); |
| 3304 | qd->min_adjlen = ~0; | 3313 | WRITE_ONCE(qd->min_adjlen, ~0); |
| 3305 | } | 3314 | } |
| 3306 | 3315 | ||
| 3307 | if (qd->tins) { | 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 | /* Draw a packet at random from queue and compare flow */ | 230 | /* Draw a packet at random from queue and compare flow */ |
| 231 | if (choke_match_random(q, skb, &idx)) { | 231 | if (choke_match_random(q, skb, &idx)) { |
| 232 | q->stats.matched++; | 232 | WRITE_ONCE(q->stats.matched, q->stats.matched + 1); |
| 233 | choke_drop_by_idx(sch, idx, to_free); | 233 | choke_drop_by_idx(sch, idx, to_free); |
| 234 | goto congestion_drop; | 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 | qdisc_qstats_overlimit(sch); | 241 | qdisc_qstats_overlimit(sch); |
| 242 | if (use_harddrop(q) || !use_ecn(q) || | 242 | if (use_harddrop(q) || !use_ecn(q) || |
| 243 | !INET_ECN_set_ce(skb)) { | 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 | goto congestion_drop; | 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 | } else if (++q->vars.qcount) { | 251 | } else if (++q->vars.qcount) { |
| 250 | if (red_mark_probability(p, &q->vars, q->vars.qavg)) { | 252 | if (red_mark_probability(p, &q->vars, q->vars.qavg)) { |
| 251 | q->vars.qcount = 0; | 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 | qdisc_qstats_overlimit(sch); | 256 | qdisc_qstats_overlimit(sch); |
| 255 | if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { | 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 | goto congestion_drop; | 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 | } else | 266 | } else |
| 263 | q->vars.qR = red_random(p); | 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 | return NET_XMIT_SUCCESS; | 276 | return NET_XMIT_SUCCESS; |
| 273 | } | 277 | } |
| 274 | 278 | ||
| 275 | q->stats.pdrop++; | 279 | WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); |
| 276 | return qdisc_drop(skb, sch, to_free); | 280 | return qdisc_drop(skb, sch, to_free); |
| 277 | 281 | ||
| 278 | congestion_drop: | 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 | struct choke_sched_data *q = qdisc_priv(sch); | 466 | struct choke_sched_data *q = qdisc_priv(sch); |
| 463 | struct tc_choke_xstats st = { | 467 | struct tc_choke_xstats st = { |
| 464 | .early = q->stats.prob_drop + q->stats.forced_drop, | 468 | .early = READ_ONCE(q->stats.prob_drop) + |
| 465 | .marked = q->stats.prob_mark + q->stats.forced_mark, | 469 | READ_ONCE(q->stats.forced_drop), |
| 466 | .pdrop = q->stats.pdrop, | 470 | .marked = READ_ONCE(q->stats.prob_mark) + |
| 467 | .matched = q->stats.matched, | 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 | return gnet_stats_copy_app(d, &st, sizeof(st)); | 476 | return gnet_stats_copy_app(d, &st, sizeof(st)); |
| @@ -509,18 +509,19 @@ nla_put_failure: · 508 unmodified lines | |||
| 509 | static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) | 509 | static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) |
| 510 | { | 510 | { |
| 511 | struct fq_pie_sched_data *q = qdisc_priv(sch); | 511 | struct fq_pie_sched_data *q = qdisc_priv(sch); |
| 512 | struct tc_fq_pie_xstats st = { | 512 | struct tc_fq_pie_xstats st = { 0 }; |
| 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 | }; | ||
| 521 | struct list_head *pos; | 513 | struct list_head *pos; |
| 522 | 514 | ||
| 523 | sch_tree_lock(sch); | 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 | list_for_each(pos, &q->new_flows) | 525 | list_for_each(pos, &q->new_flows) |
| 525 | st.new_flows_len++; | 526 | st.new_flows_len++; |
| 526 | 527 | ||
| @@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q) · 226 unmodified lines | |||
| 227 | if (rnd < clg->a4) { | 227 | if (rnd < clg->a4) { |
| 228 | clg->state = LOST_IN_GAP_PERIOD; | 228 | clg->state = LOST_IN_GAP_PERIOD; |
| 229 | return true; | 229 | return true; |
| 230 | } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { | 230 | } else if (rnd < clg->a1 + clg->a4) { |
| 231 | clg->state = LOST_IN_BURST_PERIOD; | 231 | clg->state = LOST_IN_BURST_PERIOD; |
| 232 | return true; | 232 | return true; |
| 233 | } else if (clg->a1 + clg->a4 < rnd) { | 233 | } else { |
| 234 | clg->state = TX_IN_GAP_PERIOD; | 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 | case LOST_IN_BURST_PERIOD: | 247 | case LOST_IN_BURST_PERIOD: |
| 248 | if (rnd < clg->a3) | 248 | if (rnd < clg->a3) |
| 249 | clg->state = TX_IN_BURST_PERIOD; | 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 | clg->state = TX_IN_GAP_PERIOD; | 251 | clg->state = TX_IN_GAP_PERIOD; |
| 252 | } else if (clg->a2 + clg->a3 < rnd) { | 252 | } else { |
| 253 | clg->state = LOST_IN_BURST_PERIOD; | 253 | clg->state = LOST_IN_BURST_PERIOD; |
| 254 | return true; | 254 | return true; |
| 255 | } | 255 | } |
| @@ -524,7 +524,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 268 unmodified lines | |||
| 524 | 1 << get_random_u32_below(8); | 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 | /* re-link segs, so that qdisc_drop_all() frees them all */ | 528 | /* re-link segs, so that qdisc_drop_all() frees them all */ |
| 529 | skb->next = segs; | 529 | skb->next = segs; |
| 530 | qdisc_drop_all(skb, sch, to_free); | 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 | if (!q->slot_dist) | 660 | if (!q->slot_dist) |
| 661 | next_delay = q->slot_config.min_delay + | 661 | next_delay = q->slot_config.min_delay + |
| 662 | (get_random_u32() * | 662 | mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, |
| 663 | (q->slot_config.max_delay - | 663 | get_random_u32(), 32); |
| 664 | q->slot_config.min_delay) >> 32); | ||
| 665 | else | 664 | else |
| 666 | next_delay = tabledist(q->slot_config.dist_delay, | 665 | next_delay = tabledist(q->slot_config.dist_delay, |
| 667 | (s32)(q->slot_config.dist_jitter), | 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 | return 0; | 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 | static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) | 862 | static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) |
| 831 | { | 863 | { |
| 832 | const struct tc_netem_slot *c = nla_data(attr); | 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 | goto table_free; | 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 | sch_tree_lock(sch); | 1093 | sch_tree_lock(sch); |
| 1044 | /* backup q->clg and q->loss_model */ | 1094 | /* backup q->clg and q->loss_model */ |
| 1045 | old_clg = q->clg; | 1095 | old_clg = q->clg; |
| @@ -1112,11 +1162,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, · 66 unmodified lines | |||
| 1112 | /* capping jitter to the range acceptable by tabledist() */ | 1162 | /* capping jitter to the range acceptable by tabledist() */ |
| 1113 | q->jitter = min_t(s64, abs(q->jitter), INT_MAX); | 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 | q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); | 1166 | q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); |
| 1117 | else | 1167 | prandom_seed_state(&q->prng.prng_state, q->prng.seed); |
| 1118 | q->prng.seed = get_random_u64(); | 1168 | } |
| 1119 | prandom_seed_state(&q->prng.prng_state, q->prng.seed); | ||
| 1120 | 1169 | ||
| 1121 | unlock: | 1170 | unlock: |
| 1122 | sch_tree_unlock(sch); | 1171 | sch_tree_unlock(sch); |
| @@ -1139,6 +1188,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, · 16 unmodified lines | |||
| 1139 | return -EINVAL; | 1188 | return -EINVAL; |
| 1140 | 1189 | ||
| 1141 | q->loss_model = CLG_RANDOM; | 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 | ret = netem_change(sch, opt, extack); | 1194 | ret = netem_change(sch, opt, extack); |
| 1143 | if (ret) | 1195 | if (ret) |
| 1144 | pr_info("netem: change failed\n"); | 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 | queue = skb_get_queue_mapping(skb); | 634 | queue = skb_get_queue_mapping(skb); |
| 635 | 635 | ||
| 636 | child = q->qdiscs[queue]; | 636 | child = q->qdiscs[queue]; |
| 637 | if (unlikely(!child)) | 637 | if (unlikely(child == &noop_qdisc)) |
| 638 | return qdisc_drop(skb, sch, to_free); | 638 | return qdisc_drop(skb, sch, to_free); |
| 639 | 639 | ||
| 640 | if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { | 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 | int len; | 717 | int len; |
| 718 | u8 tc; | 718 | u8 tc; |
| 719 | 719 | ||
| 720 | if (unlikely(!child)) | 720 | if (unlikely(child == &noop_qdisc)) |
| 721 | return NULL; | 721 | return NULL; |
| 722 | 722 | ||
| 723 | if (TXTIME_ASSIST_IS_ENABLED(q->flags)) | 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 | if (!dev_queue) | 2184 | if (!dev_queue) |
| 2185 | return -EINVAL; | 2185 | return -EINVAL; |
| 2186 | 2186 | ||
| 2187 | if (!new) | ||
| 2188 | new = &noop_qdisc; | ||
| 2189 | |||
| 2187 | if (dev->flags & IFF_UP) | 2190 | if (dev->flags & IFF_UP) |
| 2188 | dev_deactivate(dev, false); | 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 | *old = q->qdiscs[cl - 1]; | 2200 | *old = q->qdiscs[cl - 1]; |
| 2198 | if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { | 2201 | if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { |
| 2199 | WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); | 2202 | WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); |
| 2200 | if (new) | 2203 | if (new != &noop_qdisc) |
| 2201 | qdisc_refcount_inc(new); | 2204 | qdisc_refcount_inc(new); |
| 2202 | if (*old) | 2205 | if (*old && *old != &noop_qdisc) |
| 2203 | qdisc_put(*old); | 2206 | qdisc_put(*old); |
| 2204 | } | 2207 | } |
| 2205 | 2208 | ||
| 2206 | q->qdiscs[cl - 1] = new; | 2209 | q->qdiscs[cl - 1] = new; |
| 2207 | if (new) | 2210 | if (new != &noop_qdisc) |
| 2208 | new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; | 2211 | new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; |
| 2209 | 2212 | ||
| 2210 | if (dev->flags & IFF_UP) | 2213 | if (dev->flags & IFF_UP) |
| @@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( · 1555 unmodified lines | |||
| 1556 | /* Tag the variable length parameters. */ | 1556 | /* Tag the variable length parameters. */ |
| 1557 | chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); | 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 | /* Verify the INIT chunk before processing it. */ | 1565 | /* Verify the INIT chunk before processing it. */ |
| 1560 | err_chunk = NULL; | 1566 | err_chunk = NULL; |
| 1561 | if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, | 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 | void tls_strp_dev_exit(void); | 188 | void tls_strp_dev_exit(void); |
| 189 | 189 | ||
| 190 | void tls_strp_done(struct tls_strparser *strp); | 190 | void tls_strp_done(struct tls_strparser *strp); |
| 191 | void __tls_strp_done(struct tls_strparser *strp); | ||
| 191 | void tls_strp_stop(struct tls_strparser *strp); | 192 | void tls_strp_stop(struct tls_strparser *strp); |
| 192 | int tls_strp_init(struct tls_strparser *strp, struct sock *sk); | 193 | int tls_strp_init(struct tls_strparser *strp, struct sock *sk); |
| 193 | void tls_strp_data_ready(struct tls_strparser *strp); | 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 | WARN_ON(!strp->stopped); | 624 | WARN_ON(!strp->stopped); |
| 625 | 625 | ||
| 626 | cancel_work_sync(&strp->work); | 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 | tls_strp_anchor_free(strp); | 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 | void tls_sw_free_resources_rx(struct sock *sk) | 2624 | void tls_sw_free_resources_rx(struct sock *sk) |
| 2625 | { | 2625 | { |
| 2626 | struct tls_context *tls_ctx = tls_get_ctx(sk); | 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 | tls_sw_release_resources_rx(sk); | 2631 | tls_sw_release_resources_rx(sk); |
| 2632 | __tls_strp_done(&ctx->strp); | ||
| 2629 | tls_sw_free_ctx_rx(tls_ctx); | 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 | } else { | 375 | } else { |
| 376 | sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE); | 376 | sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE); |
| 377 | sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE); | 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 | rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE); | 379 | rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE); |
| 380 | rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE); | 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 | chan->max_pkt_size = HVS_MAX_PKT_SIZE; | 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 | const struct cred_security_struct *crsec = selinux_cred(current_cred()); | 2967 | const struct cred_security_struct *crsec = selinux_cred(current_cred()); |
| 2968 | struct superblock_security_struct *sbsec; | 2968 | struct superblock_security_struct *sbsec; |
| 2969 | struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count); | 2969 | struct xattr *xattr; |
| 2970 | u32 newsid, clen; | 2970 | u32 newsid, clen; |
| 2971 | u16 newsclass; | 2971 | u16 newsclass; |
| 2972 | int rc; | 2972 | int rc; |
| @@ -2992,6 +2992,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, · 19 unmodified lines | |||
| 2992 | !(sbsec->flags & SBLABEL_MNT)) | 2992 | !(sbsec->flags & SBLABEL_MNT)) |
| 2993 | return -EOPNOTSUPP; | 2993 | return -EOPNOTSUPP; |
| 2994 | 2994 | ||
| 2995 | xattr = lsm_get_xattr_slot(xattrs, xattr_count); | ||
| 2995 | if (xattr) { | 2996 | if (xattr) { |
| 2996 | rc = security_sid_to_context_force(newsid, | 2997 | rc = security_sid_to_context_force(newsid, |
| 2997 | &context, &clen); | 2998 | &context, &clen); |
| @@ -3208,15 +3209,13 @@ static inline int task_avdcache_search(struct task_security_struct *tsec, · 210 unmodified lines | |||
| 3208 | * @tsec: the task's security state | 3209 | * @tsec: the task's security state |
| 3209 | * @isec: the inode associated with the cache entry | 3210 | * @isec: the inode associated with the cache entry |
| 3210 | * @avd: the AVD to cache | 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 | * with @isec. | 3214 | * with @isec. |
| 3215 | */ | 3215 | */ |
| 3216 | static inline void task_avdcache_update(struct task_security_struct *tsec, | 3216 | static inline void task_avdcache_update(struct task_security_struct *tsec, |
| 3217 | struct inode_security_struct *isec, | 3217 | struct inode_security_struct *isec, |
| 3218 | struct av_decision *avd, | 3218 | struct av_decision *avd) |
| 3219 | u32 audited) | ||
| 3220 | { | 3219 | { |
| 3221 | int spot; | 3220 | int spot; |
| 3222 | 3221 | ||
| @@ -3228,9 +3227,7 @@ static inline void task_avdcache_update(struct task_security_struct *tsec, · 5 unmodified lines | |||
| 3228 | spot = (tsec->avdcache.dir_spot + 1) & (TSEC_AVDC_DIR_SIZE - 1); | 3227 | spot = (tsec->avdcache.dir_spot + 1) & (TSEC_AVDC_DIR_SIZE - 1); |
| 3229 | tsec->avdcache.dir_spot = spot; | 3228 | tsec->avdcache.dir_spot = spot; |
| 3230 | tsec->avdcache.dir[spot].isid = isec->sid; | 3229 | tsec->avdcache.dir[spot].isid = isec->sid; |
| 3231 | tsec->avdcache.dir[spot].audited = audited; | 3230 | tsec->avdcache.dir[spot].avd = *avd; |
| 3232 | tsec->avdcache.dir[spot].allowed = avd->allowed; | ||
| 3233 | tsec->avdcache.dir[spot].permissive = avd->flags & AVD_FLAGS_PERMISSIVE; | ||
| 3234 | tsec->avdcache.permissive_neveraudit = | 3231 | tsec->avdcache.permissive_neveraudit = |
| 3235 | (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT)); | 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 | struct task_security_struct *tsec; | 3248 | struct task_security_struct *tsec; |
| 3252 | struct inode_security_struct *isec; | 3249 | struct inode_security_struct *isec; |
| 3253 | struct avdc_entry *avdc; | 3250 | struct avdc_entry *avdc; |
| 3251 | struct av_decision avd, *avdp = &avd; | ||
| 3254 | int rc, rc2; | 3252 | int rc, rc2; |
| 3255 | u32 audited, denied; | 3253 | u32 audited, denied; |
| 3256 | 3254 | ||
| @@ -3272,23 +3270,21 @@ static int selinux_inode_permission(struct inode *inode, int requested) · 15 unmodified lines | |||
| 3272 | rc = task_avdcache_search(tsec, isec, &avdc); | 3270 | rc = task_avdcache_search(tsec, isec, &avdc); |
| 3273 | if (likely(!rc)) { | 3271 | if (likely(!rc)) { |
| 3274 | /* Cache hit. */ | 3272 | /* Cache hit. */ |
| 3275 | audited = perms & avdc->audited; | 3273 | avdp = &avdc->avd; |
| 3276 | denied = perms & ~avdc->allowed; | 3274 | denied = perms & ~avdp->allowed; |
| 3277 | if (unlikely(denied && enforcing_enabled() && | 3275 | if (unlikely(denied) && enforcing_enabled() && |
| 3278 | !avdc->permissive)) | 3276 | !(avdp->flags & AVD_FLAGS_PERMISSIVE)) |
| 3279 | rc = -EACCES; | 3277 | rc = -EACCES; |
| 3280 | } else { | 3278 | } else { |
| 3281 | struct av_decision avd; | ||
| 3282 | |||
| 3283 | /* Cache miss. */ | 3279 | /* Cache miss. */ |
| 3284 | rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, | 3280 | rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, |
| 3285 | perms, 0, &avd); | 3281 | perms, 0, avdp); |
| 3286 | audited = avc_audit_required(perms, &avd, rc, | 3282 | task_avdcache_update(tsec, isec, avdp); |
| 3287 | (requested & MAY_ACCESS) ? FILE__AUDIT_ACCESS : 0, | ||
| 3288 | &denied); | ||
| 3289 | task_avdcache_update(tsec, isec, &avd, audited); | ||
| 3290 | } | 3283 | } |
| 3291 | 3284 | ||
| 3285 | audited = avc_audit_required(perms, avdp, rc, | ||
| 3286 | (requested & MAY_ACCESS) ? | ||
| 3287 | FILE__AUDIT_ACCESS : 0, &denied); | ||
| 3292 | if (likely(!audited)) | 3288 | if (likely(!audited)) |
| 3293 | return rc; | 3289 | return rc; |
| 3294 | 3290 | ||
| @@ -4920,7 +4916,7 @@ static bool sock_skip_has_perm(u32 sid) · 1625 unmodified lines | |||
| 4920 | 4916 | ||
| 4921 | static int sock_has_perm(struct sock *sk, u32 perms) | 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 | struct common_audit_data ad; | 4920 | struct common_audit_data ad; |
| 4925 | struct lsm_network_audit net; | 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 | static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_type) | 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 | struct common_audit_data ad; | 6227 | struct common_audit_data ad; |
| 6232 | u8 driver; | 6228 | u8 driver; |
| 6233 | u8 xperm; | 6229 | u8 xperm; |
| @@ -32,9 +32,7 @@ · 31 unmodified lines | |||
| 32 | 32 | ||
| 33 | struct avdc_entry { | 33 | struct avdc_entry { |
| 34 | u32 isid; /* inode SID */ | 34 | u32 isid; /* inode SID */ |
| 35 | u32 allowed; /* allowed permission bitmask */ | 35 | struct av_decision avd; /* av decision */ |
| 36 | u32 audited; /* audited permission bitmask */ | ||
| 37 | bool permissive; /* AVC permissive flag */ | ||
| 38 | }; | 36 | }; |
| 39 | 37 | ||
| 40 | struct cred_security_struct { | 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 | psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; | 2156 | psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
| 2157 | csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; | 2157 | csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; |
| 2158 | if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger) | 2158 | if (psubstream && psubstream->runtime) { |
| 2159 | result |= PCM_ENABLE_OUTPUT; | 2159 | guard(mutex)(&psubstream->runtime->oss.params_lock); |
| 2160 | if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger) | 2160 | if (psubstream->runtime->oss.trigger) |
| 2161 | result |= PCM_ENABLE_INPUT; | 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 | return result; | 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 | runtime->oss.period_frames; | 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 | static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) | 2852 | static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) |
| 2836 | { | 2853 | { |
| 2837 | struct snd_pcm_oss_file *pcm_oss_file; | 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 | snd_pcm_oss_capture_ready(csubstream)) | 2881 | snd_pcm_oss_capture_ready(csubstream)) |
| 2865 | mask |= EPOLLIN | EPOLLRDNORM; | 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 | struct snd_pcm_oss_file ofile; | 2886 | struct snd_pcm_oss_file ofile; |
| 2869 | memset(&ofile, 0, sizeof(ofile)); | 2887 | memset(&ofile, 0, sizeof(ofile)); |
| 2870 | ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; | 2888 | ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; |
| 2871 | runtime->oss.trigger = 0; | ||
| 2872 | snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT); | 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 | struct loopback_cable { | 99 | struct loopback_cable { |
| 100 | spinlock_t lock; | 100 | spinlock_t lock; |
| 101 | struct loopback_pcm *streams[2]; | 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 | struct snd_pcm_hardware hw; | 105 | struct snd_pcm_hardware hw; |
| 103 | /* flags */ | 106 | /* flags */ |
| 104 | unsigned int valid; | 107 | unsigned int valid; |
| @@ -366,8 +369,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) · 261 unmodified lines | |||
| 366 | return 0; | 369 | return 0; |
| 367 | if (stream == SNDRV_PCM_STREAM_CAPTURE) | 370 | if (stream == SNDRV_PCM_STREAM_CAPTURE) |
| 368 | return -EIO; | 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 | stop_capture = true; | 375 | stop_capture = true; |
| 376 | } | ||
| 371 | } | 377 | } |
| 372 | 378 | ||
| 373 | setup = get_setup(dpcm_play); | 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 | snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING); | 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 | return 0; | 411 | return 0; |
| 403 | } | 412 | } |
| @@ -1049,23 +1058,29 @@ static void free_cable(struct snd_pcm_substream *substream) · 645 unmodified lines | |||
| 1049 | struct loopback *loopback = substream->private_data; | 1058 | struct loopback *loopback = substream->private_data; |
| 1050 | int dev = get_cable_index(substream); | 1059 | int dev = get_cable_index(substream); |
| 1051 | struct loopback_cable *cable; | 1060 | struct loopback_cable *cable; |
| 1061 | struct loopback_pcm *dpcm; | ||
| 1062 | bool other_alive; | ||
| 1052 | 1063 | ||
| 1053 | cable = loopback->cables[substream->number][dev]; | 1064 | cable = loopback->cables[substream->number][dev]; |
| 1054 | if (!cable) | 1065 | if (!cable) |
| 1055 | return; | 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) | 1068 | scoped_guard(spinlock_irq, &cable->lock) { |
| 1064 | cable->ops->close_cable(dpcm); | 1069 | cable->streams[substream->stream] = NULL; |
| 1065 | /* free the cable */ | 1070 | other_alive = cable->streams[!substream->stream]; |
| 1066 | loopback->cables[substream->number][dev] = NULL; | ||
| 1067 | kfree(cable); | ||
| 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 | static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) | 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 | goto unlock; | 1275 | goto unlock; |
| 1261 | } | 1276 | } |
| 1262 | spin_lock_init(&cable->lock); | 1277 | spin_lock_init(&cable->lock); |
| 1278 | atomic_set(&cable->stop_count, 0); | ||
| 1279 | init_waitqueue_head(&cable->stop_wait); | ||
| 1263 | cable->hw = loopback_pcm_hardware; | 1280 | cable->hw = loopback_pcm_hardware; |
| 1264 | if (loopback->timer_source) | 1281 | if (loopback->timer_source) |
| 1265 | cable->ops = &loopback_snd_timer_ops; | 1282 | cable->ops = &loopback_snd_timer_ops; |
| @@ -7,7 +7,6 @@ snd-hda-codec-cm9825-y := cm9825.o · 6 unmodified lines | |||
| 7 | snd-hda-codec-analog-y := analog.o | 7 | snd-hda-codec-analog-y := analog.o |
| 8 | snd-hda-codec-ca0110-y := ca0110.o | 8 | snd-hda-codec-ca0110-y := ca0110.o |
| 9 | snd-hda-codec-ca0132-y := ca0132.o | 9 | snd-hda-codec-ca0132-y := ca0132.o |
| 10 | snd-hda-codec-cmedia-y := cmedia.o | ||
| 11 | snd-hda-codec-conexant-y := conexant.o | 10 | snd-hda-codec-conexant-y := conexant.o |
| 12 | snd-hda-codec-idt-y := sigmatel.o | 11 | snd-hda-codec-idt-y := sigmatel.o |
| 13 | snd-hda-codec-senarytech-y := senarytech.o | 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 | obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o | 25 | obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o |
| 27 | obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o | 26 | obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o |
| 28 | obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o | 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 | obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o | 28 | obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o |
| 31 | obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o | 29 | obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o |
| 32 | obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o | 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 | static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) | 1175 | static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) |
| 1176 | { | 1176 | { |
| 1177 | struct conexant_spec *spec; | 1177 | struct conexant_spec *spec; |
| 1178 | struct hda_jack_callback *callback; | ||
| 1178 | int err; | 1179 | int err; |
| 1179 | 1180 | ||
| 1180 | codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); | 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 | case 0x14f11f86: | 1191 | case 0x14f11f86: |
| 1191 | case 0x14f11f87: | 1192 | case 0x14f11f87: |
| 1192 | spec->is_cx11880_sn6140 = true; | 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 | break; | 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 | spec->power_hook = alc287_s4_power_gpio3_default; | 3694 | spec->power_hook = alc287_s4_power_gpio3_default; |
| 3695 | spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; | 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 | /* GPIO2: mute led GPIO3: micmute led */ | 3708 | /* GPIO2: mute led GPIO3: micmute led */ |
| 3698 | static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec, | 3709 | static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec, |
| 3699 | const struct hda_fixup *fix, int action) | 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 | [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = { | 6460 | [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = { |
| 6450 | .type = HDA_FIXUP_FUNC, | 6461 | .type = HDA_FIXUP_FUNC, |
| 6451 | .v.func = alc287_fixup_bind_dacs, | 6462 | .v.func = alc287_fixup_tb_vmaster_led, |
| 6452 | .chained = true, | 6463 | .chained = true, |
| 6453 | .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, | 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 | SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), | 6728 | SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), |
| 6718 | SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), | 6729 | SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), |
| 6719 | SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), | 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 | SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC), | 6732 | SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC), |
| 6721 | SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), | 6733 | SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), |
| 6722 | SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED), | 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 | struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); | 181 | struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); |
| 182 | unsigned int reg_val; | 182 | unsigned int reg_val; |
| 183 | int i; | 183 | int i, ret; |
| 184 | 184 | ||
| 185 | cs35l56_hda_wait_dsp_ready(cs35l56); | 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 | reg_val &= CS35L56_ASP_TXn_SRC_MASK; | 192 | reg_val &= CS35L56_ASP_TXn_SRC_MASK; |
| 189 | 193 | ||
| 190 | for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) { | 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 | struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); | 207 | struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); |
| 204 | unsigned int item = ucontrol->value.enumerated.item[0]; | 208 | unsigned int item = ucontrol->value.enumerated.item[0]; |
| 205 | bool changed; | 209 | bool changed; |
| 210 | int ret; | ||
| 206 | 211 | ||
| 207 | if (item >= CS35L56_NUM_INPUT_SRC) | 212 | if (item >= CS35L56_NUM_INPUT_SRC) |
| 208 | return -EINVAL; | 213 | return -EINVAL; |
| 209 | 214 | ||
| 210 | cs35l56_hda_wait_dsp_ready(cs35l56); | 215 | cs35l56_hda_wait_dsp_ready(cs35l56); |
| 211 | 216 | ||
| 212 | regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, | 217 | ret = regmap_update_bits_check(cs35l56->base.regmap, |
| 213 | CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], | 218 | kcontrol->private_value, |
| 214 | &changed); | 219 | CS35L56_INPUT_MASK, |
| 220 | cs35l56_tx_input_values[item], | ||
| 221 | &changed); | ||
| 222 | if (ret) | ||
| 223 | return ret; | ||
| 215 | 224 | ||
| 216 | return changed; | 225 | return changed; |
| 217 | } | 226 | } |
| @@ -967,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev) · 749 unmodified lines | |||
| 967 | static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) | 976 | static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) |
| 968 | { | 977 | { |
| 969 | /* The cirrus,dev-index property has the wrong values */ | 978 | /* The cirrus,dev-index property has the wrong values */ |
| 979 | cs35l56->num_amps = 2; | ||
| 970 | switch (*bus_addr) { | 980 | switch (*bus_addr) { |
| 971 | case 0x30: | 981 | case 0x30: |
| 972 | cs35l56->index = 1; | 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 | char hid_string[8]; | 1026 | char hid_string[8]; |
| 1017 | struct acpi_device *adev; | 1027 | struct acpi_device *adev; |
| 1018 | const char *property, *sub; | 1028 | const char *property, *sub; |
| 1019 | size_t nval; | ||
| 1020 | int i, ret; | 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 | ret = -EINVAL; | 1061 | ret = -EINVAL; |
| 1053 | goto err; | 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 | if (ret) | 1068 | if (ret) |
| 1059 | goto err; | 1069 | goto err; |
| 1060 | 1070 | ||
| 1061 | for (i = 0; i < nval; i++) { | 1071 | for (i = 0; i < cs35l56->num_amps; i++) { |
| 1062 | if (values[i] == id) { | 1072 | if (values[i] == id) { |
| 1063 | cs35l56->index = i; | 1073 | cs35l56->index = i; |
| 1064 | break; | 1074 | break; |
| @@ -1081,7 +1091,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) · 16 unmodified lines | |||
| 1081 | "Read ACPI _SUB failed(%ld): fallback to generic firmware\n", | 1091 | "Read ACPI _SUB failed(%ld): fallback to generic firmware\n", |
| 1082 | PTR_ERR(sub)); | 1092 | PTR_ERR(sub)); |
| 1083 | } else { | 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 | if (ret == -ENOENT) { | 1096 | if (ret == -ENOENT) { |
| 1086 | cs35l56->system_name = sub; | 1097 | cs35l56->system_name = sub; |
| 1087 | } else if (ret >= 0) { | 1098 | } else if (ret >= 0) { |
| @@ -26,6 +26,7 @@ struct cs35l56_hda { · 25 unmodified lines | |||
| 26 | struct work_struct dsp_work; | 26 | struct work_struct dsp_work; |
| 27 | 27 | ||
| 28 | int index; | 28 | int index; |
| 29 | int num_amps; | ||
| 29 | const char *system_name; | 30 | const char *system_name; |
| 30 | const char *amp_name; | 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 | int ret, val; | 132 | int ret, val; |
| 133 | 133 | ||
| 134 | /* | 134 | /* |
| 135 | * In our TAS2781 SPI mode, read/write was masked in last bit of | 135 | * In TAS2781 SPI mode, when accessing non-book-zero or page numbers |
| 136 | * address, it cause regmap_update_bits() not work as expected. | 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 | if (ret < 0) { | 147 | if (ret < 0) { |
| 140 | dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); | 148 | dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); |
| 141 | return ret; | 149 | return ret; |
| @@ -353,13 +353,16 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, · 352 unmodified lines | |||
| 353 | if (hdmi_channel_mapping[ca][1] == 0) { | 353 | if (hdmi_channel_mapping[ca][1] == 0) { |
| 354 | int hdmi_slot = 0; | 354 | int hdmi_slot = 0; |
| 355 | /* fill actual channel mappings in ALSA channel (i) order */ | 355 | /* fill actual channel mappings in ALSA channel (i) order */ |
| 356 | for (i = 0; i < ch_alloc->channels; i++) { | 356 | for (i = 0; i < ch_alloc->channels && hdmi_slot < 8; i++) { |
| 357 | while (!WARN_ON(hdmi_slot >= 8) && | 357 | while (!ch_alloc->speakers[7 - hdmi_slot]) { |
| 358 | !ch_alloc->speakers[7 - hdmi_slot]) | 358 | /* skip zero slots */ |
| 359 | hdmi_slot++; /* skip zero slots */ | 359 | if (++hdmi_slot >= 8) |
| 360 | goto out; | ||
| 361 | } | ||
| 360 | 362 | ||
| 361 | hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; | 363 | hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; |
| 362 | } | 364 | } |
| 365 | out: | ||
| 363 | /* fill the rest of the slots with ALSA channel 0xf */ | 366 | /* fill the rest of the slots with ALSA channel 0xf */ |
| 364 | for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) | 367 | for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) |
| 365 | if (!ch_alloc->speakers[7 - hdmi_slot]) | 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 | acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; | 174 | acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; |
| 175 | 175 | ||
| 176 | dmi_id = dmi_first_match(acp_quirk_table); | 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 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; | 178 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; |
| 179 | 179 | ||
| 180 | ret = acp_legacy_dai_links_create(card); | 180 | ret = acp_legacy_dai_links_create(card); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
| 21 | #include <linux/input.h> | 21 | #include <linux/input.h> |
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | #include <linux/dmi.h> | ||
| 23 | 24 | ||
| 24 | #include "../../codecs/rt5682.h" | 25 | #include "../../codecs/rt5682.h" |
| 25 | #include "../../codecs/rt1019.h" | 26 | #include "../../codecs/rt1019.h" |
| @@ -37,15 +38,21 @@ · 11 unmodified lines | |||
| 37 | #define NAU8821_FREQ_OUT 12288000 | 38 | #define NAU8821_FREQ_OUT 12288000 |
| 38 | #define MAX98388_CODEC_DAI "max98388-aif1" | 39 | #define MAX98388_CODEC_DAI "max98388-aif1" |
| 39 | 40 | ||
| 40 | #define TDM_MODE_ENABLE 1 | ||
| 41 | |||
| 42 | const struct dmi_system_id acp_quirk_table[] = { | 41 | const struct dmi_system_id acp_quirk_table[] = { |
| 43 | { | 42 | { |
| 44 | /* Google skyrim proto-0 */ | 43 | /* Google skyrim proto-0 */ |
| 45 | .matches = { | 44 | .matches = { |
| 46 | DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"), | 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 | struct snd_soc_dai_link *links; | 1408 | struct snd_soc_dai_link *links; |
| 1402 | struct device *dev = card->dev; | 1409 | struct device *dev = card->dev; |
| 1403 | struct acp_card_drvdata *drv_data = card->drvdata; | 1410 | struct acp_card_drvdata *drv_data = card->drvdata; |
| 1411 | const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table); | ||
| 1404 | int i = 0, num_links = 0; | 1412 | int i = 0, num_links = 0; |
| 1405 | 1413 | ||
| 1406 | if (drv_data->hs_cpu_id) | 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 | links[i].codecs = &snd_soc_dummy_dlc; | 1580 | links[i].codecs = &snd_soc_dummy_dlc; |
| 1573 | links[i].num_codecs = 1; | 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 | i++; | 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 | links[i].capture_only = 1; | 1598 | links[i].capture_only = 1; |
| 1588 | links[i].nonatomic = true; | 1599 | links[i].nonatomic = true; |
| 1589 | links[i].no_pcm = 1; | 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 | card->dai_link = links; | 1608 | card->dai_link = links; |
| @@ -26,6 +26,10 @@ · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | #define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata) | 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 | enum be_id { | 33 | enum be_id { |
| 30 | HEADSET_BE_ID = 0, | 34 | HEADSET_BE_ID = 0, |
| 31 | AMP_BE_ID, | 35 | AMP_BE_ID, |
| @@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev) · 109 unmodified lines | |||
| 110 | 110 | ||
| 111 | acp_card_drvdata = card->drvdata; | 111 | acp_card_drvdata = card->drvdata; |
| 112 | dmi_id = dmi_first_match(acp_quirk_table); | 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 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; | 114 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; |
| 115 | 115 | ||
| 116 | acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; | 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 | return status; | 2496 | return status; |
| 2497 | } | 2497 | } |
| 2498 | fc = (struct filter_control *) | 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 | drvdata->anc_fir_values = (long *)fc->value; | 2500 | drvdata->anc_fir_values = (long *)fc->value; |
| 2501 | fc = (struct filter_control *) | 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 | drvdata->anc_iir_values = (long *)fc->value; | 2503 | drvdata->anc_iir_values = (long *)fc->value; |
| 2504 | fc = (struct filter_control *) | 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 | drvdata->sid_fir_values = (long *)fc->value; | 2506 | drvdata->sid_fir_values = (long *)fc->value; |
| 2507 | 2507 | ||
| 2508 | snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); | 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 | usleep_range(AW88395_1000_US, AW88395_1000_US + 10); | 456 | usleep_range(AW88395_1000_US, AW88395_1000_US + 10); |
| 457 | gpiod_set_value_cansleep(aw88395->reset_gpio, 1); | 457 | gpiod_set_value_cansleep(aw88395->reset_gpio, 1); |
| 458 | usleep_range(AW88395_1000_US, AW88395_1000_US + 10); | 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 | i2c_set_clientdata(i2c, aw88395); | 520 | i2c_set_clientdata(i2c, aw88395); |
| 523 | 521 | ||
| 524 | aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); | 522 | aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); |
| 525 | if (IS_ERR(aw88395->reset_gpio)) | 523 | if (IS_ERR(aw88395->reset_gpio)) { |
| 526 | dev_info(&i2c->dev, "reset gpio not defined\n"); | 524 | return dev_err_probe(&i2c->dev, PTR_ERR(aw88395->reset_gpio), |
| 527 | 525 | "failed to get reset gpio\n"); | |
| 526 | } | ||
| 528 | /* hardware reset */ | 527 | /* hardware reset */ |
| 529 | aw88395_hw_reset(aw88395); | 528 | aw88395_hw_reset(aw88395); |
| 530 | 529 | ||
| @@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) · 107 unmodified lines | |||
| 108 | EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED"); | 108 | EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED"); |
| 109 | 109 | ||
| 110 | static const struct reg_default cs35l56_reg_defaults[] = { | 110 | static const struct reg_default cs35l56_reg_defaults[] = { |
| 111 | /* no defaults for OTP_MEM - first read populates cache */ | ||
| 112 | |||
| 113 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, | 111 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, |
| 114 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, | 112 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, |
| 115 | { CS35L56_ASP1_CONTROL2, 0x18180200 }, | 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 | static const struct reg_default cs35l63_reg_defaults[] = { | 138 | static const struct reg_default cs35l63_reg_defaults[] = { |
| 141 | /* no defaults for OTP_MEM - first read populates cache */ | ||
| 142 | |||
| 143 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, | 139 | { CS35L56_ASP1_ENABLES1, 0x00000000 }, |
| 144 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, | 140 | { CS35L56_ASP1_CONTROL1, 0x00000028 }, |
| 145 | { CS35L56_ASP1_CONTROL2, 0x18180200 }, | 141 | { CS35L56_ASP1_CONTROL2, 0x18180200 }, |
| @@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg) · 136 unmodified lines | |||
| 282 | case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ | 278 | case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ |
| 283 | case CS35L56_BLOCK_ENABLES: /* owned by firmware */ | 279 | case CS35L56_BLOCK_ENABLES: /* owned by firmware */ |
| 284 | case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ | 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 | case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: | 284 | case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: |
| 286 | case CS35L56_UPDATE_REGS: | 285 | case CS35L56_UPDATE_REGS: |
| 287 | case CS35L56_REFCLK_INPUT: /* owned by firmware */ | 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 | return ret; | 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 | if (IS_ERR(es8389->mclk)) | 896 | if (IS_ERR(es8389->mclk)) |
| 897 | return dev_err_probe(component->dev, PTR_ERR(es8389->mclk), | 897 | return dev_err_probe(component->dev, PTR_ERR(es8389->mclk), |
| 898 | "ES8389 is unable to get mclk\n"); | 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 | switch (reg) { | 905 | switch (reg) { |
| 906 | case TAS2764_SW_RST: | 906 | case TAS2764_SW_RST: |
| 907 | case TAS2764_TEMP: | ||
| 907 | case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: | 908 | case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: |
| 908 | case TAS2764_INT_CLK_CFG: | 909 | case TAS2764_INT_CLK_CFG: |
| 909 | return true; | 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 | * As per datasheet: divide register by 16 and subtract 93 to get | 625 | * As per datasheet: divide register by 16 and subtract 93 to get |
| 626 | * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding | 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 | * NOTE: The ADC registers are initialised to 0 on reset. This means | 629 | * NOTE: The ADC registers are initialised to 0 on reset. This means |
| 630 | * that the temperature will read -93 *C until the chip is brought out | 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 | * value read back from its registers will be the last value sampled | 633 | * value read back from its registers will be the last value sampled |
| 634 | * before entering software shutdown. | 634 | * before entering software shutdown. |
| 635 | */ | 635 | */ |
| 636 | *result = (reading - (93 * 16)) * (1000 / 16); | 636 | *result = (reading - (93 * 16)) * 1000 / 16; |
| 637 | return 0; | 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 | snd_soc_component_update_bits(component, | 546 | snd_soc_component_update_bits(component, |
| 547 | WCD937X_DIGITAL_CDC_ANA_CLK_CTL, | 547 | WCD937X_DIGITAL_CDC_ANA_CLK_CTL, |
| 548 | BIT(2), BIT(2)); | 548 | BIT(2), BIT(2)); |
| 549 | snd_soc_component_update_bits(component, | ||
| 550 | WCD937X_AUX_AUXPA, | ||
| 551 | BIT(4), BIT(4)); | ||
| 549 | snd_soc_component_update_bits(component, | 552 | snd_soc_component_update_bits(component, |
| 550 | WCD937X_DIGITAL_CDC_DIG_CLK_CTL, | 553 | WCD937X_DIGITAL_CDC_DIG_CLK_CTL, |
| 551 | BIT(2), BIT(2)); | 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 | snd_soc_component_update_bits(component, | 565 | snd_soc_component_update_bits(component, |
| 563 | WCD937X_DIGITAL_CDC_ANA_CLK_CTL, | 566 | WCD937X_DIGITAL_CDC_ANA_CLK_CTL, |
| 564 | BIT(2), 0x00); | 567 | BIT(2), 0x00); |
| 568 | snd_soc_component_update_bits(component, | ||
| 569 | WCD937X_AUX_AUXPA, | ||
| 570 | BIT(4), 0x00); | ||
| 565 | break; | 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 | snd_soc_component_update_bits(component, | 736 | snd_soc_component_update_bits(component, |
| 731 | WCD937X_ANA_RX_SUPPLIES, | 737 | WCD937X_ANA_RX_SUPPLIES, |
| 732 | BIT(1), BIT(1)); | 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 | enable_irq(wcd937x->aux_pdm_wd_int); | 746 | enable_irq(wcd937x->aux_pdm_wd_int); |
| 734 | break; | 747 | break; |
| 735 | case SND_SOC_DAPM_PRE_PMD: | 748 | case SND_SOC_DAPM_PRE_PMD: |
| 736 | disable_irq_nosync(wcd937x->aux_pdm_wd_int); | 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 | break; | 756 | break; |
| 738 | case SND_SOC_DAPM_POST_PMD: | 757 | case SND_SOC_DAPM_POST_PMD: |
| 739 | usleep_range(2000, 2010); | 758 | usleep_range(2000, 2010); |
| @@ -2051,7 +2070,12 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { · 1311 unmodified lines | |||
| 2051 | wcd937x_get_swr_port, wcd937x_set_swr_port), | 2070 | wcd937x_get_swr_port, wcd937x_set_swr_port), |
| 2052 | SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0, | 2071 | SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0, |
| 2053 | wcd937x_get_swr_port, wcd937x_set_swr_port), | 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 | SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, | 2079 | SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0, |
| 2056 | wcd937x_get_swr_port, wcd937x_set_swr_port), | 2080 | wcd937x_get_swr_port, wcd937x_set_swr_port), |
| 2057 | SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0, | 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 | ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000); | 170 | ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000); |
| 171 | if (ret) { | 171 | if (ret) { |
| 172 | dev_err(card->dev, "Error setting codec sysclk: %d\n", ret); | 172 | dev_err(card->dev, "Error setting codec sysclk: %d\n", ret); |
| 173 | clk_disable_unprepare(priv->mclk); | ||
| 173 | return ret; | 174 | return ret; |
| 174 | } | 175 | } |
| 175 | } else { | 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 | link_mask |= BIT(peripherals->array[i]->bus->link_id); | 1412 | link_mask |= BIT(peripherals->array[i]->bus->link_id); |
| 1413 | 1413 | ||
| 1414 | link_num = hweight32(link_mask); | 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 | if (!links) | 1417 | if (!links) |
| 1417 | return NULL; | 1418 | return NULL; |
| 1418 | 1419 | ||
| @@ -93,8 +93,8 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s) · 92 unmodified lines | |||
| 93 | u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val; | 93 | u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val; |
| 94 | 94 | ||
| 95 | sscr_val = SSCR_TRAIL | SSCR_FRF_PSP; | 95 | sscr_val = SSCR_TRAIL | SSCR_FRF_PSP; |
| 96 | ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 5) | | 96 | ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 0xF) | |
| 97 | FIELD_PREP(SSFCR_FIELD_RFT, 5) | | 97 | FIELD_PREP(SSFCR_FIELD_RFT, 0xF) | |
| 98 | SSFCR_RSRE | SSFCR_TSRE; | 98 | SSFCR_RSRE | SSFCR_TSRE; |
| 99 | ssrwt_val = SSRWT_RWOT; | 99 | ssrwt_val = SSRWT_RWOT; |
| 100 | sspsp_val = SSPSP_SFRMP; | 100 | sspsp_val = SSPSP_SFRMP; |
| @@ -106,6 +106,37 @@ static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s) · 5 unmodified lines | |||
| 106 | writel(0, i2s->base + SSINTEN); | 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 | static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, | 140 | static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, |
| 110 | struct snd_pcm_hw_params *params, | 141 | struct snd_pcm_hw_params *params, |
| 111 | struct snd_soc_dai *dai) | 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 | dma_data->maxburst = 32; | 188 | dma_data->maxburst = 32; |
| 158 | dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 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 | break; | 191 | break; |
| 168 | case SND_SOC_DAIFMT_DSP_A: | 192 | case SND_SOC_DAIFMT_DSP_A: |
| 169 | case SND_SOC_DAIFMT_DSP_B: | 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 | break; | 194 | break; |
| 177 | default: | 195 | default: |
| 178 | dev_dbg(i2s->dev, "unexpected format type"); | 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 | static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { | 321 | static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { |
| 304 | .probe = spacemit_i2s_dai_probe, | 322 | .probe = spacemit_i2s_dai_probe, |
| 305 | .remove = spacemit_i2s_dai_remove, | 323 | .remove = spacemit_i2s_dai_remove, |
| 324 | .startup = spacemit_i2s_startup, | ||
| 306 | .hw_params = spacemit_i2s_hw_params, | 325 | .hw_params = spacemit_i2s_hw_params, |
| 307 | .set_sysclk = spacemit_i2s_set_sysclk, | 326 | .set_sysclk = spacemit_i2s_set_sysclk, |
| 308 | .set_fmt = spacemit_i2s_set_fmt, | 327 | .set_fmt = spacemit_i2s_set_fmt, |
| @@ -1,7 +1,6 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | # Tegra platform Support | 2 | # Tegra platform Support |
| 3 | snd-soc-tegra-pcm-y := tegra_pcm.o | 3 | snd-soc-tegra-pcm-y := tegra_pcm.o |
| 4 | snd-soc-tegra-utils-y += tegra_asoc_utils.o | ||
| 5 | snd-soc-tegra20-ac97-y := tegra20_ac97.o | 4 | snd-soc-tegra20-ac97-y := tegra20_ac97.o |
| 6 | snd-soc-tegra20-das-y := tegra20_das.o | 5 | snd-soc-tegra20-das-y := tegra20_das.o |
| 7 | snd-soc-tegra20-i2s-y := tegra20_i2s.o | 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 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 367 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
| 368 | ret = snd_usb_caiaq_input_init(cdev); | 368 | ret = snd_usb_caiaq_input_init(cdev); |
| 369 | if (ret < 0) { | 369 | if (ret < 0 && ret != -ENODEV) { |
| 370 | dev_err(dev, "Unable to set up input system (ret=%d)\n", ret); | 370 | dev_err(dev, "Unable to set up input system (ret=%d)\n", ret); |
| 371 | return ret; | 371 | return ret; |
| 372 | } | 372 | } |
| @@ -423,6 +423,7 @@ static int create_card(struct usb_device *usb_dev, · 50 unmodified lines | |||
| 423 | 423 | ||
| 424 | cdev = caiaqdev(card); | 424 | cdev = caiaqdev(card); |
| 425 | cdev->chip.dev = usb_get_dev(usb_dev); | 425 | cdev->chip.dev = usb_get_dev(usb_dev); |
| 426 | card->private_free = card_free; | ||
| 426 | cdev->chip.card = card; | 427 | cdev->chip.card = card; |
| 427 | cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), | 428 | cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), |
| 428 | le16_to_cpu(usb_dev->descriptor.idProduct)); | 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 | scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)", | 512 | scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)", |
| 512 | cdev->vendor_name, cdev->product_name, usbpath); | 513 | cdev->vendor_name, cdev->product_name, usbpath); |
| 513 | 514 | ||
| 514 | card->private_free = card_free; | ||
| 515 | err = setup_card(cdev); | 515 | err = setup_card(cdev); |
| 516 | if (err < 0) | 516 | if (err < 0) |
| 517 | return err; | 517 | goto err_kill_urb; |
| 518 | 518 | ||
| 519 | return 0; | 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 | default: | 805 | default: |
| 806 | /* no input methods supported on this device */ | 806 | /* no input methods supported on this device */ |
| 807 | ret = -EINVAL; | 807 | ret = -ENODEV; |
| 808 | goto exit_free_idev; | 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 | ua->capture.channels = fmt_capture->bNrChannels; | 975 | ua->capture.channels = fmt_capture->bNrChannels; |
| 976 | ua->playback.channels = fmt_playback->bNrChannels; | 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 | ua->capture.frame_bytes = | 984 | ua->capture.frame_bytes = |
| 978 | fmt_capture->bSubframeSize * ua->capture.channels; | 985 | fmt_capture->bSubframeSize * ua->capture.channels; |
| 979 | ua->playback.frame_bytes = | 986 | ua->playback.frame_bytes = |
| @@ -1190,6 +1190,16 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, · 1189 unmodified lines | |||
| 1190 | cval->res = 1; | 1190 | cval->res = 1; |
| 1191 | } | 1191 | } |
| 1192 | break; | 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 | case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ | 1203 | case USB_ID(0x3302, 0x12db): /* MOONDROP Quark2 */ |
| 1194 | if (!strcmp(kctl->id.name, "PCM Playback Volume")) { | 1204 | if (!strcmp(kctl->id.name, "PCM Playback Volume")) { |
| 1195 | usb_audio_info(chip, | 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 | * The AudioBox USB advertises S24_3LE as the only supported format | 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 | snd_usb_audioformat_set_sync_ep(chip, fp); | 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 | if (err < 0) | 129 | if (err < 0) |
| 130 | return err; | 130 | return err; |
| 131 | 131 | ||
| @@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) · 78 unmodified lines | |||
| 79 | static void snd_usb_init_substream(struct snd_usb_stream *as, | 79 | static void snd_usb_init_substream(struct snd_usb_stream *as, |
| 80 | int stream, | 80 | int stream, |
| 81 | struct audioformat *fp, | 81 | struct audioformat *fp, |
| 82 | struct snd_usb_power_domain *pd) | 82 | struct snd_usb_power_domain **pdptr) |
| 83 | { | 83 | { |
| 84 | struct snd_usb_substream *subs = &as->substream[stream]; | 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 | if (fp->channels > subs->channels_max) | 105 | if (fp->channels > subs->channels_max) |
| 106 | subs->channels_max = fp->channels; | 106 | subs->channels_max = fp->channels; |
| 107 | 107 | ||
| 108 | if (pd) { | 108 | if (pdptr && *pdptr) { |
| 109 | subs->str_pd = pd; | 109 | subs->str_pd = *pdptr; |
| 110 | *pdptr = NULL; /* assigned */ | ||
| 110 | /* Initialize Power Domain to idle status D1 */ | 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 | UAC3_PD_STATE_D1); | 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 | if (len < sizeof(*cs_desc)) | 353 | if (len < sizeof(*cs_desc)) |
| 353 | break; | 354 | break; |
| 354 | cs_len = le16_to_cpu(cs_desc->wLength); | 355 | cs_len = le16_to_cpu(cs_desc->wLength); |
| 356 | if (cs_len < sizeof(*cs_desc)) | ||
| 357 | break; | ||
| 355 | if (len < cs_len) | 358 | if (len < cs_len) |
| 356 | break; | 359 | break; |
| 357 | cs_type = cs_desc->bSegmentType; | 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 | * if not, create a new pcm stream. note, fp is added to the substream | 495 | * if not, create a new pcm stream. note, fp is added to the substream |
| 493 | * fmt_list and will be freed on the chip instance release. do not free | 496 | * fmt_list and will be freed on the chip instance release. do not free |
| 494 | * fp or do remove it from the substream fmt_list to avoid double-free. | 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, | 502 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, |
| 497 | int stream, | 503 | int stream, |
| 498 | struct audioformat *fp, | 504 | struct audioformat *fp, |
| 499 | struct snd_usb_power_domain *pd) | 505 | struct snd_usb_power_domain **pdptr) |
| 500 | 506 | ||
| 501 | { | 507 | { |
| 502 | struct snd_usb_stream *as; | 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 | err = snd_pcm_new_stream(as->pcm, stream, 1); | 535 | err = snd_pcm_new_stream(as->pcm, stream, 1); |
| 530 | if (err < 0) | 536 | if (err < 0) |
| 531 | return err; | 537 | return err; |
| 532 | snd_usb_init_substream(as, stream, fp, pd); | 538 | snd_usb_init_substream(as, stream, fp, pdptr); |
| 533 | return add_chmap(as->pcm, stream, subs); | 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 | else | 564 | else |
| 559 | strscpy(pcm->name, "USB Audio"); | 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 | * Keep using head insertion for M-Audio Audiophile USB (tm) which has a | 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 | return add_chmap(pcm, stream, &as->substream[stream]); | 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 | static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, | 585 | static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, |
| 595 | struct usb_host_interface *alts, | 586 | struct usb_host_interface *alts, |
| 596 | int protocol, int iface_no) | 587 | int protocol, int iface_no) |
| @@ -1003,7 +994,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, · 406 unmodified lines | |||
| 1003 | * and request Cluster Descriptor | 994 | * and request Cluster Descriptor |
| 1004 | */ | 995 | */ |
| 1005 | wLength = le16_to_cpu(hc_header.wLength); | 996 | wLength = le16_to_cpu(hc_header.wLength); |
| 1006 | if (wLength < sizeof(cluster)) | 997 | if (wLength < sizeof(*cluster)) |
| 1007 | return NULL; | 998 | return NULL; |
| 1008 | cluster = kzalloc(wLength, GFP_KERNEL); | 999 | cluster = kzalloc(wLength, GFP_KERNEL); |
| 1009 | if (!cluster) | 1000 | if (!cluster) |
| @@ -1113,8 +1104,7 @@ found_clock: · 103 unmodified lines | |||
| 1113 | } | 1104 | } |
| 1114 | } | 1105 | } |
| 1115 | 1106 | ||
| 1116 | if (pd) | 1107 | *pd_out = pd; |
| 1117 | *pd_out = pd; | ||
| 1118 | 1108 | ||
| 1119 | return fp; | 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 | struct usb_interface_descriptor *altsd; | 1119 | struct usb_interface_descriptor *altsd; |
| 1130 | int i, altno, err, stream; | 1120 | int i, altno, err, stream; |
| 1131 | struct audioformat *fp = NULL; | 1121 | struct audioformat *fp = NULL; |
| 1132 | struct snd_usb_power_domain *pd = NULL; | ||
| 1133 | bool set_iface_first; | 1122 | bool set_iface_first; |
| 1134 | int num, protocol; | 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 | if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) | 1160 | if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) |
| 1172 | continue; | 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 | * Roland audio streaming interfaces are marked with protocols | 1170 | * Roland audio streaming interfaces are marked with protocols |
| 1176 | * 0/1/2, but are UAC 1 compatible. | 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 | *has_non_pcm = true; | 1221 | *has_non_pcm = true; |
| 1227 | if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { | 1222 | if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { |
| 1228 | audioformat_free(fp); | 1223 | audioformat_free(fp); |
| 1229 | kfree(pd); | ||
| 1230 | fp = NULL; | 1224 | fp = NULL; |
| 1231 | pd = NULL; | ||
| 1232 | continue; | 1225 | continue; |
| 1233 | } | 1226 | } |
| 1234 | 1227 | ||
| 1235 | snd_usb_audioformat_set_sync_ep(chip, fp); | 1228 | snd_usb_audioformat_set_sync_ep(chip, fp); |
| 1236 | 1229 | ||
| 1237 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); | 1230 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); |
| 1238 | if (protocol == UAC_VERSION_3) | 1231 | err = snd_usb_add_audio_stream(chip, stream, fp, &pd); |
| 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 | |||
| 1243 | if (err < 0) { | 1232 | if (err < 0) { |
| 1244 | audioformat_free(fp); | 1233 | audioformat_free(fp); |
| 1245 | kfree(pd); | ||
| 1246 | return err; | 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 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | 8 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, |
| 9 | int stream, | 9 | int stream, |
| 10 | struct audioformat *fp); | 10 | struct audioformat *fp, |
| 11 | struct snd_usb_power_domain **pdptr); | ||
| 11 | 12 | ||
| 12 | #endif /* __USBAUDIO_STREAM_H */ | 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 | static struct task_ctx *lookup_task_ctx(struct task_struct *p) | 160 | static struct task_ctx *lookup_task_ctx(struct task_struct *p) |
| 161 | { | 161 | { |
| 162 | struct task_ctx *tctx; | 162 | return bpf_task_storage_get(&task_ctx_stor, p, 0, 0); |
| 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; | ||
| 169 | } | 163 | } |
| 170 | 164 | ||
| 171 | s32 BPF_STRUCT_OPS(qmap_select_cpu, struct task_struct *p, | 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 | s32 cpu; | 169 | s32 cpu; |
| 176 | 170 | ||
| 177 | if (!(tctx = lookup_task_ctx(p))) | 171 | if (!(tctx = lookup_task_ctx(p))) |
| 178 | return -ESRCH; | 172 | return prev_cpu; |
| 179 | 173 | ||
| 180 | if (p->scx.weight < 2 && !(p->flags & PF_KTHREAD)) | 174 | if (p->scx.weight < 2 && !(p->flags & PF_KTHREAD)) |
| 181 | return prev_cpu; | 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 | if (prev) { | 535 | if (prev) { |
| 542 | tctx = bpf_task_storage_get(&task_ctx_stor, prev, 0, 0); | 536 | tctx = bpf_task_storage_get(&task_ctx_stor, prev, 0, 0); |
| 543 | if (!tctx) { | 537 | if (tctx) |
| 544 | scx_bpf_error("task_ctx lookup failed"); | 538 | tctx->core_sched_seq = |
| 545 | return; | 539 | core_sched_tail_seqs[weight_to_idx(prev->scx.weight)]++; |
| 546 | } | ||
| 547 | |||
| 548 | tctx->core_sched_seq = | ||
| 549 | 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 | s64 qdist; | 574 | s64 qdist; |
| 585 | 575 | ||
| 586 | tctx = bpf_task_storage_get(&task_ctx_stor, p, 0, 0); | 576 | tctx = bpf_task_storage_get(&task_ctx_stor, p, 0, 0); |
| 587 | if (!tctx) { | 577 | if (!tctx) |
| 588 | scx_bpf_error("task_ctx lookup failed"); | ||
| 589 | return 0; | 578 | return 0; |
| 590 | } | ||
| 591 | 579 | ||
| 592 | qdist = tctx->core_sched_seq - core_sched_head_seqs[idx]; | 580 | qdist = tctx->core_sched_seq - core_sched_head_seqs[idx]; |
| 593 | 581 | ||
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * maple_tree.c: Userspace testing for maple tree test-suite | 3 | * maple_tree.c: Userspace testing for maple tree test-suite |
| 4 | * Copyright (c) 2018-2022 Oracle Corporation | 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 | * Any tests that require internal knowledge of the tree or threads and other | 7 | * Any tests that require internal knowledge of the tree or threads and other |
| 8 | * difficult to handle in kernel tests. | 8 | * difficult to handle in kernel tests. |
| @@ -18,12 +18,6 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | #ifndef NT_ARM_GCS | 19 | #ifndef NT_ARM_GCS |
| 20 | #define NT_ARM_GCS 0x410 | 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 | #endif | 21 | #endif |
| 28 | 22 | ||
| 29 | /* Shadow Stack/Guarded Control Stack interface */ | 23 | /* Shadow Stack/Guarded Control Stack interface */ |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | #include <asm/hwcap.h> | 17 | #include <asm/hwcap.h> |
| 18 | #include <asm/mman.h> | 18 | #include <asm/mman.h> |
| 19 | #include <asm/ptrace.h> | ||
| 19 | 20 | ||
| 20 | #include <linux/compiler.h> | 21 | #include <linux/compiler.h> |
| 21 | 22 | ||
| @@ -211,8 +211,8 @@ Avoid libraries and frameworks · 210 unmodified lines | |||
| 211 | 211 | ||
| 212 | Test files should be relatively self contained. The libraries should | 212 | Test files should be relatively self contained. The libraries should |
| 213 | only include very core or non-trivial code. | 213 | only include very core or non-trivial code. |
| 214 | It may be tempting to "factor out" the common code, but fight that urge. | 214 | It may be tempting to "factor out" the common code to lib/py/, but fight that |
| 215 | Library code increases the barrier of entry, and complexity in general. | 215 | urge. Library code increases the barrier of entry, and complexity in general. |
| 216 | 216 | ||
| 217 | Avoid mixing test code and boilerplate | 217 | Avoid mixing test code and boilerplate |
| 218 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 218 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -290,6 +290,12 @@ or:: · 71 unmodified lines | |||
| 290 | def test(cfg, mode, protocol): | 290 | def test(cfg, mode, protocol): |
| 291 | pass | 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 | Running tests CI-style | 299 | Running tests CI-style |
| 294 | ====================== | 300 | ====================== |
| 295 | 301 | ||
| @@ -101,15 +101,15 @@ struct test_params { · 100 unmodified lines | |||
| 101 | enum vm_mem_backing_src_type backing_src; | 101 | enum vm_mem_backing_src_type backing_src; |
| 102 | 102 | ||
| 103 | /* The amount of memory to allocate for each vCPU. */ | 103 | /* The amount of memory to allocate for each vCPU. */ |
| 104 | uint64_t vcpu_memory_bytes; | 104 | u64 vcpu_memory_bytes; |
| 105 | 105 | ||
| 106 | /* The number of vCPUs to create in the VM. */ | 106 | /* The number of vCPUs to create in the VM. */ |
| 107 | int nr_vcpus; | 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 | off_t offset = index * sizeof(value); | 113 | off_t offset = index * sizeof(value); |
| 114 | 114 | ||
| 115 | TEST_ASSERT(pread(fd, &value, sizeof(value), offset) == sizeof(value), | 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 | #define PAGEMAP_PRESENT (1ULL << 63) | 123 | #define PAGEMAP_PRESENT (1ULL << 63) |
| 124 | #define PAGEMAP_PFN_MASK ((1ULL << 55) - 1) | 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); | 128 | u64 hva = (u64)addr_gva2hva(vm, gva); |
| 129 | uint64_t entry; | 129 | u64 entry; |
| 130 | uint64_t pfn; | 130 | u64 pfn; |
| 131 | 131 | ||
| 132 | entry = pread_uint64(pagemap_fd, "pagemap", hva / getpagesize()); | 132 | entry = pread_u64(pagemap_fd, "pagemap", hva / getpagesize()); |
| 133 | if (!(entry & PAGEMAP_PRESENT)) | 133 | if (!(entry & PAGEMAP_PRESENT)) |
| 134 | return 0; | 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 | return pfn; | 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 | return !!((bits >> (pfn % 64)) & 1); | 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 | TEST_ASSERT(pwrite(page_idle_fd, &bits, 8, 8 * (pfn / 64)) == 8, | 153 | TEST_ASSERT(pwrite(page_idle_fd, &bits, 8, 8 * (pfn / 64)) == 8, |
| 154 | "Set page_idle bits for PFN 0x%" PRIx64, pfn); | 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 | struct memstress_vcpu_args *vcpu_args) | 174 | struct memstress_vcpu_args *vcpu_args) |
| 175 | { | 175 | { |
| 176 | int vcpu_idx = vcpu_args->vcpu_idx; | 176 | int vcpu_idx = vcpu_args->vcpu_idx; |
| 177 | uint64_t base_gva = vcpu_args->gva; | 177 | gva_t base_gva = vcpu_args->gva; |
| 178 | uint64_t pages = vcpu_args->pages; | 178 | u64 pages = vcpu_args->pages; |
| 179 | uint64_t page; | 179 | u64 page; |
| 180 | uint64_t still_idle = 0; | 180 | u64 still_idle = 0; |
| 181 | uint64_t no_pfn = 0; | 181 | u64 no_pfn = 0; |
| 182 | int page_idle_fd; | 182 | int page_idle_fd; |
| 183 | int pagemap_fd; | 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 | TEST_ASSERT(pagemap_fd > 0, "Failed to open pagemap."); | 193 | TEST_ASSERT(pagemap_fd > 0, "Failed to open pagemap."); |
| 194 | 194 | ||
| 195 | for (page = 0; page < pages; page++) { | 195 | for (page = 0; page < pages; page++) { |
| 196 | uint64_t gva = base_gva + page * memstress_args.guest_page_size; | 196 | gva_t gva = base_gva + page * memstress_args.guest_page_size; |
| 197 | uint64_t pfn = lookup_pfn(pagemap_fd, vm, gva); | 197 | u64 pfn = lookup_pfn(pagemap_fd, vm, gva); |
| 198 | 198 | ||
| 199 | if (!pfn) { | 199 | if (!pfn) { |
| 200 | no_pfn++; | 200 | no_pfn++; |
| @@ -297,10 +297,10 @@ static void lru_gen_mark_memory_idle(struct kvm_vm *vm) · 96 unmodified lines | |||
| 297 | lru_gen_last_gen = new_gen; | 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 | struct ucall uc; | 302 | struct ucall uc; |
| 303 | uint64_t actual_ucall = get_ucall(vcpu, &uc); | 303 | u64 actual_ucall = get_ucall(vcpu, &uc); |
| 304 | 304 | ||
| 305 | TEST_ASSERT(expected_ucall == actual_ucall, | 305 | TEST_ASSERT(expected_ucall == actual_ucall, |
| 306 | "Guest exited unexpectedly (expected ucall %" PRIu64 | 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 | test_pages = params->nr_vcpus * params->vcpu_memory_bytes / | 418 | test_pages = params->nr_vcpus * params->vcpu_memory_bytes / |
| 419 | max(memstress_args.guest_page_size, | 419 | max(memstress_args.guest_page_size, |
| 420 | (uint64_t)getpagesize()); | 420 | (u64)getpagesize()); |
| 421 | 421 | ||
| 422 | memstress_start_vcpu_threads(nr_vcpus, vcpu_thread_main); | 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 | return NULL; | 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 | unsigned int nproc_conf; | 84 | unsigned int nproc_conf; |
| 85 | cpu_set_t online_cpuset; | 85 | cpu_set_t online_cpuset; |
| 86 | 86 | ||
| @@ -98,7 +98,7 @@ static uint32_t test_get_pcpu(void) · 11 unmodified lines | |||
| 98 | static int test_migrate_vcpu(unsigned int vcpu_idx) | 98 | static int test_migrate_vcpu(unsigned int vcpu_idx) |
| 99 | { | 99 | { |
| 100 | int ret; | 100 | int ret; |
| 101 | uint32_t new_pcpu = test_get_pcpu(); | 101 | u32 new_pcpu = test_get_pcpu(); |
| 102 | 102 | ||
| 103 | pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu_idx, new_pcpu); | 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 | KVM_ARM64_SYS_REG(SYS_ID_PFR0_EL1), | 70 | KVM_ARM64_SYS_REG(SYS_ID_PFR0_EL1), |
| 71 | KVM_ARM64_SYS_REG(SYS_ID_PFR1_EL1), | 71 | KVM_ARM64_SYS_REG(SYS_ID_PFR1_EL1), |
| 72 | KVM_ARM64_SYS_REG(SYS_ID_DFR0_EL1), | 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 | int i; | 94 | int i; |
| 95 | 95 | ||
| 96 | for (i = 0; i < ARRAY_SIZE(raz_wi_reg_ids); i++) { | 96 | for (i = 0; i < ARRAY_SIZE(raz_wi_reg_ids); i++) { |
| 97 | uint64_t reg_id = raz_wi_reg_ids[i]; | 97 | u64 reg_id = raz_wi_reg_ids[i]; |
| 98 | uint64_t val; | 98 | u64 val; |
| 99 | 99 | ||
| 100 | val = vcpu_get_reg(vcpu, reg_id); | 100 | val = vcpu_get_reg(vcpu, reg_id); |
| 101 | TEST_ASSERT_EQ(val, 0); | 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 | KVM_ARM64_SYS_REG(SYS_ID_AFR0_EL1), | 115 | KVM_ARM64_SYS_REG(SYS_ID_AFR0_EL1), |
| 116 | KVM_ARM64_SYS_REG(sys_reg(3, 0, 0, 3, 3)), | 116 | KVM_ARM64_SYS_REG(sys_reg(3, 0, 0, 3, 3)), |
| 117 | KVM_ARM64_SYS_REG(SYS_ID_DFR1_EL1), | 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 | int i, r; | 123 | int i, r; |
| 124 | 124 | ||
| 125 | for (i = 0; i < ARRAY_SIZE(raz_invariant_reg_ids); i++) { | 125 | for (i = 0; i < ARRAY_SIZE(raz_invariant_reg_ids); i++) { |
| 126 | uint64_t reg_id = raz_invariant_reg_ids[i]; | 126 | u64 reg_id = raz_invariant_reg_ids[i]; |
| 127 | uint64_t val; | 127 | u64 val; |
| 128 | 128 | ||
| 129 | val = vcpu_get_reg(vcpu, reg_id); | 129 | val = vcpu_get_reg(vcpu, reg_id); |
| 130 | TEST_ASSERT_EQ(val, 0); | 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 | static bool vcpu_aarch64_only(struct kvm_vcpu *vcpu) | 143 | static bool vcpu_aarch64_only(struct kvm_vcpu *vcpu) |
| 144 | { | 144 | { |
| 145 | uint64_t val, el0; | 145 | u64 val, el0; |
| 146 | 146 | ||
| 147 | val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); | 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 | struct test_vcpu_shared_data *shared_data) | 56 | struct test_vcpu_shared_data *shared_data) |
| 57 | { | 57 | { |
| 58 | enum guest_stage stage = shared_data->guest_stage; | 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 | unsigned long xctl = 0; | 60 | unsigned long xctl = 0; |
| 61 | unsigned int timer_irq = 0; | 61 | unsigned int timer_irq = 0; |
| 62 | unsigned int accessor; | 62 | unsigned int accessor; |
| @@ -105,7 +105,7 @@ static void guest_validate_irq(unsigned int intid, · 42 unmodified lines | |||
| 105 | static void guest_irq_handler(struct ex_regs *regs) | 105 | static void guest_irq_handler(struct ex_regs *regs) |
| 106 | { | 106 | { |
| 107 | unsigned int intid = gic_get_and_ack_irq(); | 107 | unsigned int intid = gic_get_and_ack_irq(); |
| 108 | uint32_t cpu = guest_get_vcpuid(); | 108 | u32 cpu = guest_get_vcpuid(); |
| 109 | struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; | 109 | struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; |
| 110 | 110 | ||
| 111 | guest_validate_irq(intid, shared_data); | 111 | guest_validate_irq(intid, shared_data); |
| @@ -116,7 +116,7 @@ static void guest_irq_handler(struct ex_regs *regs) · 4 unmodified lines | |||
| 116 | static void guest_run_stage(struct test_vcpu_shared_data *shared_data, | 116 | static void guest_run_stage(struct test_vcpu_shared_data *shared_data, |
| 117 | enum guest_stage stage) | 117 | enum guest_stage stage) |
| 118 | { | 118 | { |
| 119 | uint32_t irq_iter, config_iter; | 119 | u32 irq_iter, config_iter; |
| 120 | 120 | ||
| 121 | shared_data->guest_stage = stage; | 121 | shared_data->guest_stage = stage; |
| 122 | shared_data->nr_iter = 0; | 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 | static void guest_code(void) | 141 | static void guest_code(void) |
| 142 | { | 142 | { |
| 143 | uint32_t cpu = guest_get_vcpuid(); | 143 | u32 cpu = guest_get_vcpuid(); |
| 144 | struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; | 144 | struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; |
| 145 | 145 | ||
| 146 | local_irq_disable(); | 146 | local_irq_disable(); |
| @@ -23,25 +23,25 @@ · 22 unmodified lines | |||
| 23 | #include "vgic.h" | 23 | #include "vgic.h" |
| 24 | 24 | ||
| 25 | /* Depends on counter width. */ | 25 | /* Depends on counter width. */ |
| 26 | static uint64_t CVAL_MAX; | 26 | static u64 CVAL_MAX; |
| 27 | /* tval is a signed 32-bit int. */ | 27 | /* tval is a signed 32-bit int. */ |
| 28 | static const int32_t TVAL_MAX = INT32_MAX; | 28 | static const s32 TVAL_MAX = INT32_MAX; |
| 29 | static const int32_t TVAL_MIN = INT32_MIN; | 29 | static const s32 TVAL_MIN = INT32_MIN; |
| 30 | 30 | ||
| 31 | /* After how much time we say there is no IRQ. */ | 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 | /* Counter value to use as the starting one for most tests. Set to CVAL_MAX/2 */ | 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 | /* Number of runs. */ | 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 | /* Default wait test time in ms. */ | 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 | /* Default "long" wait test time in ms. */ | 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 | /* Shared with IRQ handler. */ | 46 | /* Shared with IRQ handler. */ |
| 47 | struct test_vcpu_shared_data { | 47 | struct test_vcpu_shared_data { |
| @@ -53,9 +53,9 @@ struct test_args { · 5 unmodified lines | |||
| 53 | /* Virtual or physical timer and counter tests. */ | 53 | /* Virtual or physical timer and counter tests. */ |
| 54 | enum arch_timer timer; | 54 | enum arch_timer timer; |
| 55 | /* Delay used for most timer tests. */ | 55 | /* Delay used for most timer tests. */ |
| 56 | uint64_t wait_ms; | 56 | u64 wait_ms; |
| 57 | /* Delay used in the test_long_timer_delays test. */ | 57 | /* Delay used in the test_long_timer_delays test. */ |
| 58 | uint64_t long_wait_ms; | 58 | u64 long_wait_ms; |
| 59 | /* Number of iterations. */ | 59 | /* Number of iterations. */ |
| 60 | int iterations; | 60 | int iterations; |
| 61 | /* Whether to test the physical timer. */ | 61 | /* Whether to test the physical timer. */ |
| @@ -82,12 +82,12 @@ enum sync_cmd { · 20 unmodified lines | |||
| 82 | NO_USERSPACE_CMD, | 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); | 87 | static void sleep_poll(enum arch_timer timer, u64 usec); |
| 88 | static void sleep_sched_poll(enum arch_timer timer, uint64_t usec); | 88 | static void sleep_sched_poll(enum arch_timer timer, u64 usec); |
| 89 | static void sleep_in_userspace(enum arch_timer timer, uint64_t usec); | 89 | static void sleep_in_userspace(enum arch_timer timer, u64 usec); |
| 90 | static void sleep_migrate(enum arch_timer timer, uint64_t usec); | 90 | static void sleep_migrate(enum arch_timer timer, u64 usec); |
| 91 | 91 | ||
| 92 | sleep_method_t sleep_method[] = { | 92 | sleep_method_t sleep_method[] = { |
| 93 | sleep_poll, | 93 | sleep_poll, |
| @@ -115,14 +115,14 @@ enum timer_view { · 21 unmodified lines | |||
| 115 | TIMER_TVAL, | 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 | int h = atomic_read(&shared_data.handled); | 120 | int h = atomic_read(&shared_data.handled); |
| 121 | 121 | ||
| 122 | __GUEST_ASSERT(h == n, "Handled %d IRQS but expected %d", h, n); | 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 | GUEST_SYNC_ARGS(cmd, 0, 0, 0, 0); | 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 | userspace_cmd(USERSPACE_MIGRATE_SELF); | 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 | GUEST_SYNC_ARGS(USERSPACE_USLEEP, usecs, 0, 0, 0); | 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 | GUEST_SYNC_ARGS(SET_COUNTER_VALUE, counter, timer, 0, 0); | 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 | unsigned int intid = gic_get_and_ack_irq(); | 147 | unsigned int intid = gic_get_and_ack_irq(); |
| 148 | enum arch_timer timer; | 148 | enum arch_timer timer; |
| 149 | uint64_t cnt, cval; | 149 | u64 cnt, cval; |
| 150 | uint32_t ctl; | 150 | u32 ctl; |
| 151 | bool timer_condition, istatus; | 151 | bool timer_condition, istatus; |
| 152 | 152 | ||
| 153 | if (intid == IAR_SPURIOUS) { | 153 | if (intid == IAR_SPURIOUS) { |
| @@ -178,8 +178,8 @@ out: · 24 unmodified lines | |||
| 178 | gic_set_eoi(intid); | 178 | gic_set_eoi(intid); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | static void set_cval_irq(enum arch_timer timer, uint64_t cval_cycles, | 181 | static void set_cval_irq(enum arch_timer timer, u64 cval_cycles, |
| 182 | uint32_t ctl) | 182 | u32 ctl) |
| 183 | { | 183 | { |
| 184 | atomic_set(&shared_data.handled, 0); | 184 | atomic_set(&shared_data.handled, 0); |
| 185 | atomic_set(&shared_data.spurious, 0); | 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 | timer_set_ctl(timer, ctl); | 187 | timer_set_ctl(timer, ctl); |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | static void set_tval_irq(enum arch_timer timer, uint64_t tval_cycles, | 190 | static void set_tval_irq(enum arch_timer timer, u64 tval_cycles, |
| 191 | uint32_t ctl) | 191 | u32 ctl) |
| 192 | { | 192 | { |
| 193 | atomic_set(&shared_data.handled, 0); | 193 | atomic_set(&shared_data.handled, 0); |
| 194 | atomic_set(&shared_data.spurious, 0); | 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 | timer_set_ctl(timer, ctl); | 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 | enum timer_view tv) | 200 | enum timer_view tv) |
| 201 | { | 201 | { |
| 202 | switch (tv) { | 202 | switch (tv) { |
| @@ -275,13 +275,13 @@ static void wait_migrate_poll_for_irq(void) · 72 unmodified lines | |||
| 275 | * Sleep for usec microseconds by polling in the guest or in | 275 | * Sleep for usec microseconds by polling in the guest or in |
| 276 | * userspace (e.g. userspace_cmd=USERSPACE_SCHEDULE). | 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 | enum sync_cmd usp_cmd) | 279 | enum sync_cmd usp_cmd) |
| 280 | { | 280 | { |
| 281 | uint64_t cycles = usec_to_cycles(usec); | 281 | u64 cycles = usec_to_cycles(usec); |
| 282 | /* Whichever timer we are testing with, sleep with the other. */ | 282 | /* Whichever timer we are testing with, sleep with the other. */ |
| 283 | enum arch_timer sleep_timer = 1 - test_timer; | 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 | while ((timer_get_cntct(sleep_timer) - start) < cycles) { | 286 | while ((timer_get_cntct(sleep_timer) - start) < cycles) { |
| 287 | if (usp_cmd == NO_USERSPACE_CMD) | 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 | guest_poll(timer, usec, NO_USERSPACE_CMD); | 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 | guest_poll(timer, usec, USERSPACE_SCHED_YIELD); | 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 | guest_poll(timer, usec, USERSPACE_MIGRATE_SELF); | 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 | userspace_sleep(usec); | 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 | * Reset the timer state to some nice values like the counter not being close | 315 | * Reset the timer state to some nice values like the counter not being close |
| 316 | * to the edge, and the control register masked and disabled. | 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 | set_counter(timer, cnt); | 320 | set_counter(timer, cnt); |
| 321 | timer_set_ctl(timer, CTL_IMASK); | 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 | enum timer_view tv, irq_wait_method_t wm, bool reset_state, | 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 | local_irq_disable(); | 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 | * the "runner", like: tools/testing/selftests/kselftest/runner.sh. | 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 | irq_wait_method_t wm, bool reset_state, | 352 | irq_wait_method_t wm, bool reset_state, |
| 353 | uint64_t reset_cnt) | 353 | u64 reset_cnt) |
| 354 | { | 354 | { |
| 355 | test_timer_xval(timer, cval, TIMER_CVAL, wm, reset_state, reset_cnt); | 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 | irq_wait_method_t wm, bool reset_state, | 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 | reset_cnt); | 363 | reset_cnt); |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | static void test_xval_check_no_irq(enum arch_timer timer, uint64_t xval, | 366 | static void test_xval_check_no_irq(enum arch_timer timer, u64 xval, |
| 367 | uint64_t usec, enum timer_view timer_view, | 367 | u64 usec, enum timer_view timer_view, |
| 368 | sleep_method_t guest_sleep) | 368 | sleep_method_t guest_sleep) |
| 369 | { | 369 | { |
| 370 | local_irq_disable(); | 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 | assert_irqs_handled(0); | 379 | assert_irqs_handled(0); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | static void test_cval_no_irq(enum arch_timer timer, uint64_t cval, | 382 | static void test_cval_no_irq(enum arch_timer timer, u64 cval, |
| 383 | uint64_t usec, sleep_method_t wm) | 383 | u64 usec, sleep_method_t wm) |
| 384 | { | 384 | { |
| 385 | test_xval_check_no_irq(timer, cval, usec, TIMER_CVAL, wm); | 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 | sleep_method_t wm) | 389 | sleep_method_t wm) |
| 390 | { | 390 | { |
| 391 | /* tval will be cast to an int32_t in test_xval_check_no_irq */ | 391 | /* tval will be cast to an s32 in test_xval_check_no_irq */ |
| 392 | test_xval_check_no_irq(timer, (uint64_t) tval, usec, TIMER_TVAL, wm); | 392 | test_xval_check_no_irq(timer, (u64)tval, usec, TIMER_TVAL, wm); |
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | /* Test masking/unmasking a timer using the timer mask (not the IRQ mask). */ | 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 | * timeout for the wait: we use the wfi instruction. | 463 | * timeout for the wait: we use the wfi instruction. |
| 464 | */ | 464 | */ |
| 465 | static void test_reprogramming_timer(enum arch_timer timer, irq_wait_method_t wm, | 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 | local_irq_disable(); | 468 | local_irq_disable(); |
| 469 | reset_timer_state(timer, DEF_CNT); | 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 | static void test_reprogram_timers(enum arch_timer timer) | 488 | static void test_reprogram_timers(enum arch_timer timer) |
| 489 | { | 489 | { |
| 490 | int i; | 490 | int i; |
| 491 | uint64_t base_wait = test_args.wait_ms; | 491 | u64 base_wait = test_args.wait_ms; |
| 492 | 492 | ||
| 493 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { | 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 | static void test_basic_functionality(enum arch_timer timer) | 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); | 507 | s32 tval = (s32)msec_to_cycles(test_args.wait_ms); |
| 508 | uint64_t cval = DEF_CNT + msec_to_cycles(test_args.wait_ms); | 508 | u64 cval = DEF_CNT + msec_to_cycles(test_args.wait_ms); |
| 509 | int i; | 509 | int i; |
| 510 | 510 | ||
| 511 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { | 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 | reset_timer_state(timer, DEF_CNT); | 593 | reset_timer_state(timer, DEF_CNT); |
| 594 | 594 | ||
| 595 | set_cval_irq(timer, | 595 | set_cval_irq(timer, |
| 596 | (uint64_t) TVAL_MAX + | 596 | (u64)TVAL_MAX + |
| 597 | msec_to_cycles(test_args.wait_ms) / 2, CTL_ENABLE); | 597 | msec_to_cycles(test_args.wait_ms) / 2, CTL_ENABLE); |
| 598 | 598 | ||
| 599 | set_counter(timer, TVAL_MAX); | 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 | /* Test timers set for: cval = now + TVAL_MAX + wait_ms / 2 */ | 608 | /* Test timers set for: cval = now + TVAL_MAX + wait_ms / 2 */ |
| 609 | static void test_timers_above_tval_max(enum arch_timer timer) | 609 | static void test_timers_above_tval_max(enum arch_timer timer) |
| 610 | { | 610 | { |
| 611 | uint64_t cval; | 611 | u64 cval; |
| 612 | int i; | 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 | * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and | 638 | * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and |
| 639 | * then waits for an IRQ. | 639 | * then waits for an IRQ. |
| 640 | */ | 640 | */ |
| 641 | static void test_set_cnt_after_xval(enum arch_timer timer, uint64_t cnt_1, | 641 | static void test_set_cnt_after_xval(enum arch_timer timer, u64 cnt_1, |
| 642 | uint64_t xval, uint64_t cnt_2, | 642 | u64 xval, u64 cnt_2, |
| 643 | irq_wait_method_t wm, enum timer_view tv) | 643 | irq_wait_method_t wm, enum timer_view tv) |
| 644 | { | 644 | { |
| 645 | local_irq_disable(); | 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 | * then waits for an IRQ. | 662 | * then waits for an IRQ. |
| 663 | */ | 663 | */ |
| 664 | static void test_set_cnt_after_xval_no_irq(enum arch_timer timer, | 664 | static void test_set_cnt_after_xval_no_irq(enum arch_timer timer, |
| 665 | uint64_t cnt_1, uint64_t xval, | 665 | u64 cnt_1, u64 xval, |
| 666 | uint64_t cnt_2, | 666 | u64 cnt_2, |
| 667 | sleep_method_t guest_sleep, | 667 | sleep_method_t guest_sleep, |
| 668 | enum timer_view tv) | 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 | timer_set_ctl(timer, CTL_IMASK); | 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, | 687 | static void test_set_cnt_after_tval(enum arch_timer timer, u64 cnt_1, |
| 688 | int32_t tval, uint64_t cnt_2, | 688 | s32 tval, u64 cnt_2, |
| 689 | irq_wait_method_t wm) | 689 | irq_wait_method_t wm) |
| 690 | { | 690 | { |
| 691 | test_set_cnt_after_xval(timer, cnt_1, tval, cnt_2, wm, TIMER_TVAL); | 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, | 694 | static void test_set_cnt_after_cval(enum arch_timer timer, u64 cnt_1, |
| 695 | uint64_t cval, uint64_t cnt_2, | 695 | u64 cval, u64 cnt_2, |
| 696 | irq_wait_method_t wm) | 696 | irq_wait_method_t wm) |
| 697 | { | 697 | { |
| 698 | test_set_cnt_after_xval(timer, cnt_1, cval, cnt_2, wm, TIMER_CVAL); | 698 | test_set_cnt_after_xval(timer, cnt_1, cval, cnt_2, wm, TIMER_CVAL); |
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | static void test_set_cnt_after_tval_no_irq(enum arch_timer timer, | 701 | static void test_set_cnt_after_tval_no_irq(enum arch_timer timer, |
| 702 | uint64_t cnt_1, int32_t tval, | 702 | u64 cnt_1, s32 tval, |
| 703 | uint64_t cnt_2, sleep_method_t wm) | 703 | u64 cnt_2, sleep_method_t wm) |
| 704 | { | 704 | { |
| 705 | test_set_cnt_after_xval_no_irq(timer, cnt_1, tval, cnt_2, wm, | 705 | test_set_cnt_after_xval_no_irq(timer, cnt_1, tval, cnt_2, wm, |
| 706 | TIMER_TVAL); | 706 | TIMER_TVAL); |
| 707 | } | 707 | } |
| 708 | 708 | ||
| 709 | static void test_set_cnt_after_cval_no_irq(enum arch_timer timer, | 709 | static void test_set_cnt_after_cval_no_irq(enum arch_timer timer, |
| 710 | uint64_t cnt_1, uint64_t cval, | 710 | u64 cnt_1, u64 cval, |
| 711 | uint64_t cnt_2, sleep_method_t wm) | 711 | u64 cnt_2, sleep_method_t wm) |
| 712 | { | 712 | { |
| 713 | test_set_cnt_after_xval_no_irq(timer, cnt_1, cval, cnt_2, wm, | 713 | test_set_cnt_after_xval_no_irq(timer, cnt_1, cval, cnt_2, wm, |
| 714 | TIMER_CVAL); | 714 | TIMER_CVAL); |
| @@ -718,7 +718,7 @@ static void test_set_cnt_after_cval_no_irq(enum arch_timer timer, · 3 unmodified lines | |||
| 718 | static void test_move_counters_ahead_of_timers(enum arch_timer timer) | 718 | static void test_move_counters_ahead_of_timers(enum arch_timer timer) |
| 719 | { | 719 | { |
| 720 | int i; | 720 | int i; |
| 721 | int32_t tval; | 721 | s32 tval; |
| 722 | 722 | ||
| 723 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { | 723 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { |
| 724 | irq_wait_method_t wm = irq_wait_method[i]; | 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 | test_set_cnt_after_tval(timer, 0, -1, DEF_CNT + 1, wm); | 730 | test_set_cnt_after_tval(timer, 0, -1, DEF_CNT + 1, wm); |
| 731 | test_set_cnt_after_tval(timer, 0, -1, TVAL_MAX, wm); | 731 | test_set_cnt_after_tval(timer, 0, -1, TVAL_MAX, wm); |
| 732 | tval = TVAL_MAX; | 732 | tval = TVAL_MAX; |
| 733 | test_set_cnt_after_tval(timer, 0, tval, (uint64_t) tval + 1, | 733 | test_set_cnt_after_tval(timer, 0, tval, (u64)tval + 1, wm); |
| 734 | 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 | static void test_timers_in_the_past(enum arch_timer timer) | 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); | 756 | s32 tval = -1 * (s32)msec_to_cycles(test_args.wait_ms); |
| 758 | uint64_t cval; | 757 | u64 cval; |
| 759 | int i; | 758 | int i; |
| 760 | 759 | ||
| 761 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { | 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 | static void test_long_timer_delays(enum arch_timer timer) | 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); | 792 | s32 tval = (s32)msec_to_cycles(test_args.long_wait_ms); |
| 794 | uint64_t cval = DEF_CNT + msec_to_cycles(test_args.long_wait_ms); | 793 | u64 cval = DEF_CNT + msec_to_cycles(test_args.long_wait_ms); |
| 795 | int i; | 794 | int i; |
| 796 | 795 | ||
| 797 | for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) { | 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 | static cpu_set_t default_cpuset; | 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(); | 850 | u32 max = get_nprocs(); |
| 852 | uint32_t cur = sched_getcpu(); | 851 | u32 cur = sched_getcpu(); |
| 853 | uint32_t next = cur; | 852 | u32 next = cur; |
| 854 | cpu_set_t cpuset = default_cpuset; | 853 | cpu_set_t cpuset = default_cpuset; |
| 855 | 854 | ||
| 856 | TEST_ASSERT(max > 1, "Need at least two physical cpus"); | 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 | return next; | 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 | enum arch_timer timer) | 865 | enum arch_timer timer) |
| 867 | { | 866 | { |
| 868 | if (timer == PHYSICAL) | 867 | if (timer == PHYSICAL) |
| @@ -874,7 +873,7 @@ static void kvm_set_cntxct(struct kvm_vcpu *vcpu, uint64_t cnt, · 5 unmodified lines | |||
| 874 | static void handle_sync(struct kvm_vcpu *vcpu, struct ucall *uc) | 873 | static void handle_sync(struct kvm_vcpu *vcpu, struct ucall *uc) |
| 875 | { | 874 | { |
| 876 | enum sync_cmd cmd = uc->args[1]; | 875 | enum sync_cmd cmd = uc->args[1]; |
| 877 | uint64_t val = uc->args[2]; | 876 | u64 val = uc->args[2]; |
| 878 | enum arch_timer timer = uc->args[3]; | 877 | enum arch_timer timer = uc->args[3]; |
| 879 | 878 | ||
| 880 | switch (cmd) { | 879 | switch (cmd) { |
| @@ -1018,8 +1017,8 @@ static bool parse_args(int argc, char *argv[]) · 137 unmodified lines | |||
| 1018 | 1017 | ||
| 1019 | static void set_counter_defaults(void) | 1018 | static void set_counter_defaults(void) |
| 1020 | { | 1019 | { |
| 1021 | const uint64_t MIN_ROLLOVER_SECS = 40ULL * 365 * 24 * 3600; | 1020 | const u64 MIN_ROLLOVER_SECS = 40ULL * 365 * 24 * 3600; |
| 1022 | uint64_t freq = read_sysreg(CNTFRQ_EL0); | 1021 | u64 freq = read_sysreg(CNTFRQ_EL0); |
| 1023 | int width = ilog2(MIN_ROLLOVER_SECS * freq); | 1022 | int width = ilog2(MIN_ROLLOVER_SECS * freq); |
| 1024 | 1023 | ||
| 1025 | width = clamp(width, 56, 64); | 1024 | width = clamp(width, 56, 64); |
| @@ -31,14 +31,14 @@ · 30 unmodified lines | |||
| 31 | 31 | ||
| 32 | extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start, hw_bp_ctx; | 32 | extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start, hw_bp_ctx; |
| 33 | extern unsigned char iter_ss_begin, iter_ss_end; | 33 | extern unsigned char iter_ss_begin, iter_ss_end; |
| 34 | static volatile uint64_t sw_bp_addr, hw_bp_addr; | 34 | static volatile u64 sw_bp_addr, hw_bp_addr; |
| 35 | static volatile uint64_t wp_addr, wp_data_addr; | 35 | static volatile u64 wp_addr, wp_data_addr; |
| 36 | static volatile uint64_t svc_addr; | 36 | static volatile u64 svc_addr; |
| 37 | static volatile uint64_t ss_addr[4], ss_idx; | 37 | static volatile u64 ss_addr[4], ss_idx; |
| 38 | #define PC(v) ((uint64_t)&(v)) | 38 | #define PC(v) ((u64)&(v)) |
| 39 | 39 | ||
| 40 | #define GEN_DEBUG_WRITE_REG(reg_name) \ | 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 | switch (num) { \ | 43 | switch (num) { \ |
| 44 | case 0: \ | 44 | case 0: \ |
| @@ -102,8 +102,8 @@ GEN_DEBUG_WRITE_REG(dbgwvr) · 57 unmodified lines | |||
| 102 | 102 | ||
| 103 | static void reset_debug_state(void) | 103 | static void reset_debug_state(void) |
| 104 | { | 104 | { |
| 105 | uint8_t brps, wrps, i; | 105 | u8 brps, wrps, i; |
| 106 | uint64_t dfr0; | 106 | u64 dfr0; |
| 107 | 107 | ||
| 108 | asm volatile("msr daifset, #8"); | 108 | asm volatile("msr daifset, #8"); |
| 109 | 109 | ||
| @@ -140,7 +140,7 @@ static void enable_os_lock(void) · 30 unmodified lines | |||
| 140 | 140 | ||
| 141 | static void enable_monitor_debug_exceptions(void) | 141 | static void enable_monitor_debug_exceptions(void) |
| 142 | { | 142 | { |
| 143 | uint64_t mdscr; | 143 | u64 mdscr; |
| 144 | 144 | ||
| 145 | asm volatile("msr daifclr, #8"); | 145 | asm volatile("msr daifclr, #8"); |
| 146 | 146 | ||
| @@ -149,9 +149,9 @@ static void enable_monitor_debug_exceptions(void) · 2 unmodified lines | |||
| 149 | isb(); | 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 | wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E; | 156 | wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E; |
| 157 | write_dbgwcr(wpn, wcr); | 157 | write_dbgwcr(wpn, wcr); |
| @@ -162,9 +162,9 @@ static void install_wp(uint8_t wpn, uint64_t addr) · 4 unmodified lines | |||
| 162 | enable_monitor_debug_exceptions(); | 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 | bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E; | 169 | bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E; |
| 170 | write_dbgbcr(bpn, bcr); | 170 | write_dbgbcr(bpn, bcr); |
| @@ -174,11 +174,10 @@ static void install_hw_bp(uint8_t bpn, uint64_t addr) · 3 unmodified lines | |||
| 174 | enable_monitor_debug_exceptions(); | 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, | 177 | static void install_wp_ctx(u8 addr_wp, u8 ctx_bp, u64 addr, u64 ctx) |
| 178 | uint64_t ctx) | ||
| 179 | { | 178 | { |
| 180 | uint32_t wcr; | 179 | u32 wcr; |
| 181 | uint64_t ctx_bcr; | 180 | u64 ctx_bcr; |
| 182 | 181 | ||
| 183 | /* Setup a context-aware breakpoint for Linked Context ID Match */ | 182 | /* Setup a context-aware breakpoint for Linked Context ID Match */ |
| 184 | ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | | 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 | /* Setup a linked watchpoint (linked to the context-aware breakpoint) */ | 188 | /* Setup a linked watchpoint (linked to the context-aware breakpoint) */ |
| 190 | wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E | | 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 | write_dbgwcr(addr_wp, wcr); | 191 | write_dbgwcr(addr_wp, wcr); |
| 193 | write_dbgwvr(addr_wp, addr); | 192 | write_dbgwvr(addr_wp, addr); |
| 194 | isb(); | 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 | enable_monitor_debug_exceptions(); | 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, | 198 | void install_hw_bp_ctx(u8 addr_bp, u8 ctx_bp, u64 addr, u64 ctx) |
| 200 | uint64_t ctx) | ||
| 201 | { | 199 | { |
| 202 | uint32_t addr_bcr, ctx_bcr; | 200 | u32 addr_bcr, ctx_bcr; |
| 203 | 201 | ||
| 204 | /* Setup a context-aware breakpoint for Linked Context ID Match */ | 202 | /* Setup a context-aware breakpoint for Linked Context ID Match */ |
| 205 | ctx_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | | 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 | addr_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | | 212 | addr_bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E | |
| 215 | DBGBCR_BT_ADDR_LINK_CTX | | 213 | DBGBCR_BT_ADDR_LINK_CTX | |
| 216 | ((uint32_t)ctx_bp << DBGBCR_LBN_SHIFT); | 214 | ((u32)ctx_bp << DBGBCR_LBN_SHIFT); |
| 217 | write_dbgbcr(addr_bp, addr_bcr); | 215 | write_dbgbcr(addr_bp, addr_bcr); |
| 218 | write_dbgbvr(addr_bp, addr); | 216 | write_dbgbvr(addr_bp, addr); |
| 219 | isb(); | 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 | static void install_ss(void) | 222 | static void install_ss(void) |
| 225 | { | 223 | { |
| 226 | uint64_t mdscr; | 224 | u64 mdscr; |
| 227 | 225 | ||
| 228 | asm volatile("msr daifclr, #8"); | 226 | asm volatile("msr daifclr, #8"); |
| 229 | 227 | ||
| @@ -234,9 +232,9 @@ static void install_ss(void) · 4 unmodified lines | |||
| 234 | 232 | ||
| 235 | static volatile char write_data; | 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 | /* Software-breakpoint */ | 239 | /* Software-breakpoint */ |
| 242 | reset_debug_state(); | 240 | reset_debug_state(); |
| @@ -377,8 +375,8 @@ static void guest_svc_handler(struct ex_regs *regs) · 134 unmodified lines | |||
| 377 | 375 | ||
| 378 | static void guest_code_ss(int test_cnt) | 376 | static void guest_code_ss(int test_cnt) |
| 379 | { | 377 | { |
| 380 | uint64_t i; | 378 | u64 i; |
| 381 | uint64_t bvr, wvr, w_bvr, w_wvr; | 379 | u64 bvr, wvr, w_bvr, w_wvr; |
| 382 | 380 | ||
| 383 | for (i = 0; i < test_cnt; i++) { | 381 | for (i = 0; i < test_cnt; i++) { |
| 384 | /* Bits [1:0] of dbg{b,w}vr are RES0 */ | 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 | GUEST_DONE(); | 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 | return FIELD_GET(ID_AA64DFR0_EL1_DebugVer, id_aa64dfr0); | 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 | struct kvm_vcpu *vcpu; | 424 | struct kvm_vcpu *vcpu; |
| 427 | struct kvm_vm *vm; | 425 | struct kvm_vm *vm; |
| @@ -468,8 +466,8 @@ void test_single_step_from_userspace(int test_cnt) · 40 unmodified lines | |||
| 468 | struct kvm_vm *vm; | 466 | struct kvm_vm *vm; |
| 469 | struct ucall uc; | 467 | struct ucall uc; |
| 470 | struct kvm_run *run; | 468 | struct kvm_run *run; |
| 471 | uint64_t pc, cmd; | 469 | u64 pc, cmd; |
| 472 | uint64_t test_pc = 0; | 470 | u64 test_pc = 0; |
| 473 | bool ss_enable = false; | 471 | bool ss_enable = false; |
| 474 | struct kvm_guest_debug debug = {}; | 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 | "Unexpected pc 0x%lx (expected 0x%lx)", | 504 | "Unexpected pc 0x%lx (expected 0x%lx)", |
| 507 | pc, test_pc); | 505 | pc, test_pc); |
| 508 | 506 | ||
| 509 | if ((pc + 4) == (uint64_t)&iter_ss_end) { | 507 | if ((pc + 4) == (u64)&iter_ss_end) { |
| 510 | test_pc = 0; | 508 | test_pc = 0; |
| 511 | debug.control = KVM_GUESTDBG_ENABLE; | 509 | debug.control = KVM_GUESTDBG_ENABLE; |
| 512 | ss_enable = false; | 510 | ss_enable = false; |
| @@ -519,8 +517,8 @@ void test_single_step_from_userspace(int test_cnt) · 6 unmodified lines | |||
| 519 | * iter_ss_end, the pc for the next KVM_EXIT_DEBUG should | 517 | * iter_ss_end, the pc for the next KVM_EXIT_DEBUG should |
| 520 | * be the current pc + 4. | 518 | * be the current pc + 4. |
| 521 | */ | 519 | */ |
| 522 | if ((pc >= (uint64_t)&iter_ss_begin) && | 520 | if ((pc >= (u64)&iter_ss_begin) && |
| 523 | (pc < (uint64_t)&iter_ss_end)) | 521 | (pc < (u64)&iter_ss_end)) |
| 524 | test_pc = pc + 4; | 522 | test_pc = pc + 4; |
| 525 | else | 523 | else |
| 526 | test_pc = 0; | 524 | test_pc = 0; |
| @@ -533,9 +531,9 @@ void test_single_step_from_userspace(int test_cnt) · 6 unmodified lines | |||
| 533 | * Run debug testing using the various breakpoint#, watchpoint# and | 531 | * Run debug testing using the various breakpoint#, watchpoint# and |
| 534 | * context-aware breakpoint# with the given ID_AA64DFR0_EL1 configuration. | 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 | int b, w, c; | 537 | int b, w, c; |
| 540 | 538 | ||
| 541 | /* Number of breakpoints */ | 539 | /* Number of breakpoints */ |
| @@ -580,7 +578,7 @@ int main(int argc, char *argv[]) · 38 unmodified lines | |||
| 580 | struct kvm_vm *vm; | 578 | struct kvm_vm *vm; |
| 581 | int opt; | 579 | int opt; |
| 582 | int ss_iteration = 10000; | 580 | int ss_iteration = 10000; |
| 583 | uint64_t aa64dfr0; | 581 | u64 aa64dfr0; |
| 584 | 582 | ||
| 585 | vm = vm_create_with_one_vcpu(&vcpu, guest_code); | 583 | vm = vm_create_with_one_vcpu(&vcpu, guest_code); |
| 586 | aa64dfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1)); | 584 | aa64dfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1)); |
| @@ -29,9 +29,9 @@ · 28 unmodified lines | |||
| 29 | #define KVM_REG_ARM_VENDOR_HYP_BMAP_2_RESET_VAL 0 | 29 | #define KVM_REG_ARM_VENDOR_HYP_BMAP_2_RESET_VAL 0 |
| 30 | 30 | ||
| 31 | struct kvm_fw_reg_info { | 31 | struct kvm_fw_reg_info { |
| 32 | uint64_t reg; /* Register definition */ | 32 | u64 reg; /* Register definition */ |
| 33 | uint64_t max_feat_bit; /* Bit that represents the upper limit of the feature-map */ | 33 | u64 max_feat_bit; /* Bit that represents the upper limit of the feature-map */ |
| 34 | uint64_t reset_val; /* Reset value for the register */ | 34 | u64 reset_val; /* Reset value for the register */ |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | #define FW_REG_INFO(r) \ | 37 | #define FW_REG_INFO(r) \ |
| @@ -59,8 +59,8 @@ enum test_stage { · 21 unmodified lines | |||
| 59 | static int stage = TEST_STAGE_REG_IFACE; | 59 | static int stage = TEST_STAGE_REG_IFACE; |
| 60 | 60 | ||
| 61 | struct test_hvc_info { | 61 | struct test_hvc_info { |
| 62 | uint32_t func_id; | 62 | u32 func_id; |
| 63 | uint64_t arg1; | 63 | u64 arg1; |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | #define TEST_HVC_INFO(f, a1) \ | 66 | #define TEST_HVC_INFO(f, a1) \ |
| @@ -152,9 +152,9 @@ static void guest_code(void) · 85 unmodified lines | |||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | struct st_time { | 154 | struct st_time { |
| 155 | uint32_t rev; | 155 | u32 rev; |
| 156 | uint32_t attr; | 156 | u32 attr; |
| 157 | uint64_t st_time; | 157 | u64 st_time; |
| 158 | }; | 158 | }; |
| 159 | 159 | ||
| 160 | #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) | 160 | #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) |
| @@ -162,7 +162,7 @@ struct st_time { · 1 unmodified line | |||
| 162 | 162 | ||
| 163 | static void steal_time_init(struct kvm_vcpu *vcpu) | 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 | unsigned int gpages; | 166 | unsigned int gpages; |
| 167 | 167 | ||
| 168 | gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); | 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 | static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) | 175 | static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) |
| 176 | { | 176 | { |
| 177 | uint64_t val; | 177 | u64 val; |
| 178 | unsigned int i; | 178 | unsigned int i; |
| 179 | int ret; | 179 | int ret; |
| 180 | 180 | ||
| 181 | for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { | 181 | for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { |
| 182 | const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; | 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 | /* First 'read' should be the reset value for the reg */ | 185 | /* First 'read' should be the reset value for the reg */ |
| 186 | val = vcpu_get_reg(vcpu, reg_info->reg); | 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 | static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) | 230 | static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) |
| 231 | { | 231 | { |
| 232 | uint64_t val; | 232 | u64 val; |
| 233 | unsigned int i; | 233 | unsigned int i; |
| 234 | int ret; | 234 | int ret; |
| 235 | 235 | ||
| @@ -13,7 +13,7 @@ static volatile bool sys64, undef; · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | #define __check_sr_read(r) \ | 14 | #define __check_sr_read(r) \ |
| 15 | ({ \ | 15 | ({ \ |
| 16 | uint64_t val; \ | 16 | u64 val; \ |
| 17 | \ | 17 | \ |
| 18 | sys64 = false; \ | 18 | sys64 = false; \ |
| 19 | undef = false; \ | 19 | undef = false; \ |
| @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) · 81 unmodified lines | |||
| 101 | { | 101 | { |
| 102 | struct kvm_vcpu *vcpu; | 102 | struct kvm_vcpu *vcpu; |
| 103 | struct kvm_vm *vm; | 103 | struct kvm_vm *vm; |
| 104 | uint64_t mmfr2; | 104 | u64 mmfr2; |
| 105 | 105 | ||
| 106 | test_disable_default_vgic(); | 106 | test_disable_default_vgic(); |
| 107 | 107 | ||
| @@ -15,7 +15,7 @@ static volatile bool handled; · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | #define __check_sr_read(r) \ | 16 | #define __check_sr_read(r) \ |
| 17 | ({ \ | 17 | ({ \ |
| 18 | uint64_t val; \ | 18 | u64 val; \ |
| 19 | \ | 19 | \ |
| 20 | handled = false; \ | 20 | handled = false; \ |
| 21 | dsb(sy); \ | 21 | dsb(sy); \ |
| @@ -33,7 +33,7 @@ static volatile bool handled; · 11 unmodified lines | |||
| 33 | 33 | ||
| 34 | #define __check_gicv5_gicr_op(r) \ | 34 | #define __check_gicv5_gicr_op(r) \ |
| 35 | ({ \ | 35 | ({ \ |
| 36 | uint64_t val; \ | 36 | u64 val; \ |
| 37 | \ | 37 | \ |
| 38 | handled = false; \ | 38 | handled = false; \ |
| 39 | dsb(sy); \ | 39 | dsb(sy); \ |
| @@ -82,7 +82,7 @@ static volatile bool handled; · 42 unmodified lines | |||
| 82 | 82 | ||
| 83 | static void guest_code_gicv3(void) | 83 | static void guest_code_gicv3(void) |
| 84 | { | 84 | { |
| 85 | uint64_t val; | 85 | u64 val; |
| 86 | 86 | ||
| 87 | /* | 87 | /* |
| 88 | * Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having | 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 | struct kvm_vcpu *vcpu; | 262 | struct kvm_vcpu *vcpu; |
| 263 | struct kvm_vm *vm; | 263 | struct kvm_vm *vm; |
| 264 | bool has_v3, has_v5; | 264 | bool has_v3, has_v5; |
| 265 | uint64_t pfr; | 265 | u64 pfr; |
| 266 | 266 | ||
| 267 | test_disable_default_vgic(); | 267 | test_disable_default_vgic(); |
| 268 | 268 | ||
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | #define TEST_PTE_GVA 0xb0000000 | 23 | #define TEST_PTE_GVA 0xb0000000 |
| 24 | #define TEST_DATA 0x0123456789ABCDEF | 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 | #define CMD_NONE (0) | 28 | #define CMD_NONE (0) |
| 29 | #define CMD_SKIP_TEST (1ULL << 1) | 29 | #define CMD_SKIP_TEST (1ULL << 1) |
| @@ -48,7 +48,7 @@ static struct event_cnt { · 18 unmodified lines | |||
| 48 | 48 | ||
| 49 | struct test_desc { | 49 | struct test_desc { |
| 50 | const char *name; | 50 | const char *name; |
| 51 | uint64_t mem_mark_cmd; | 51 | u64 mem_mark_cmd; |
| 52 | /* Skip the test if any prepare function returns false */ | 52 | /* Skip the test if any prepare function returns false */ |
| 53 | bool (*guest_prepare[PREPARE_FN_NR])(void); | 53 | bool (*guest_prepare[PREPARE_FN_NR])(void); |
| 54 | void (*guest_test)(void); | 54 | void (*guest_test)(void); |
| @@ -59,8 +59,8 @@ struct test_desc { · 4 unmodified lines | |||
| 59 | void (*iabt_handler)(struct ex_regs *regs); | 59 | void (*iabt_handler)(struct ex_regs *regs); |
| 60 | void (*mmio_handler)(struct kvm_vm *vm, struct kvm_run *run); | 60 | void (*mmio_handler)(struct kvm_vm *vm, struct kvm_run *run); |
| 61 | void (*fail_vcpu_run_handler)(int ret); | 61 | void (*fail_vcpu_run_handler)(int ret); |
| 62 | uint32_t pt_memslot_flags; | 62 | u32 pt_memslot_flags; |
| 63 | uint32_t data_memslot_flags; | 63 | u32 data_memslot_flags; |
| 64 | bool skip; | 64 | bool skip; |
| 65 | struct event_cnt expected_events; | 65 | struct event_cnt expected_events; |
| 66 | }; | 66 | }; |
| @@ -70,9 +70,9 @@ struct test_params { · 3 unmodified lines | |||
| 70 | struct test_desc *test_desc; | 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 | dsb(ishst); | 77 | dsb(ishst); |
| 78 | asm volatile("tlbi vaae1is, %0" :: "r" (page)); | 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 | static void guest_write64(void) | 83 | static void guest_write64(void) |
| 84 | { | 84 | { |
| 85 | uint64_t val; | 85 | u64 val; |
| 86 | 86 | ||
| 87 | WRITE_ONCE(*guest_test_memory, TEST_DATA); | 87 | WRITE_ONCE(*guest_test_memory, TEST_DATA); |
| 88 | val = READ_ONCE(*guest_test_memory); | 88 | val = READ_ONCE(*guest_test_memory); |
| @@ -92,8 +92,8 @@ static void guest_write64(void) · 3 unmodified lines | |||
| 92 | /* Check the system for atomic instructions. */ | 92 | /* Check the system for atomic instructions. */ |
| 93 | static bool guest_check_lse(void) | 93 | static bool guest_check_lse(void) |
| 94 | { | 94 | { |
| 95 | uint64_t isar0 = read_sysreg(id_aa64isar0_el1); | 95 | u64 isar0 = read_sysreg(id_aa64isar0_el1); |
| 96 | uint64_t atomic; | 96 | u64 atomic; |
| 97 | 97 | ||
| 98 | atomic = FIELD_GET(ID_AA64ISAR0_EL1_ATOMIC, isar0); | 98 | atomic = FIELD_GET(ID_AA64ISAR0_EL1_ATOMIC, isar0); |
| 99 | return atomic >= 2; | 99 | return atomic >= 2; |
| @@ -101,8 +101,8 @@ static bool guest_check_lse(void) · 1 unmodified line | |||
| 101 | 101 | ||
| 102 | static bool guest_check_dc_zva(void) | 102 | static bool guest_check_dc_zva(void) |
| 103 | { | 103 | { |
| 104 | uint64_t dczid = read_sysreg(dczid_el0); | 104 | u64 dczid = read_sysreg(dczid_el0); |
| 105 | uint64_t dzp = FIELD_GET(DCZID_EL0_DZP, dczid); | 105 | u64 dzp = FIELD_GET(DCZID_EL0_DZP, dczid); |
| 106 | 106 | ||
| 107 | return dzp == 0; | 107 | return dzp == 0; |
| 108 | } | 108 | } |
| @@ -110,7 +110,7 @@ static bool guest_check_dc_zva(void) · 1 unmodified line | |||
| 110 | /* Compare and swap instruction. */ | 110 | /* Compare and swap instruction. */ |
| 111 | static void guest_cas(void) | 111 | static void guest_cas(void) |
| 112 | { | 112 | { |
| 113 | uint64_t val; | 113 | u64 val; |
| 114 | 114 | ||
| 115 | GUEST_ASSERT(guest_check_lse()); | 115 | GUEST_ASSERT(guest_check_lse()); |
| 116 | asm volatile(".arch_extension lse\n" | 116 | asm volatile(".arch_extension lse\n" |
| @@ -122,7 +122,7 @@ static void guest_cas(void) · 5 unmodified lines | |||
| 122 | 122 | ||
| 123 | static void guest_read64(void) | 123 | static void guest_read64(void) |
| 124 | { | 124 | { |
| 125 | uint64_t val; | 125 | u64 val; |
| 126 | 126 | ||
| 127 | val = READ_ONCE(*guest_test_memory); | 127 | val = READ_ONCE(*guest_test_memory); |
| 128 | GUEST_ASSERT_EQ(val, 0); | 128 | GUEST_ASSERT_EQ(val, 0); |
| @@ -131,7 +131,7 @@ static void guest_read64(void) · 2 unmodified lines | |||
| 131 | /* Address translation instruction */ | 131 | /* Address translation instruction */ |
| 132 | static void guest_at(void) | 132 | static void guest_at(void) |
| 133 | { | 133 | { |
| 134 | uint64_t par; | 134 | u64 par; |
| 135 | 135 | ||
| 136 | asm volatile("at s1e1r, %0" :: "r" (guest_test_memory)); | 136 | asm volatile("at s1e1r, %0" :: "r" (guest_test_memory)); |
| 137 | isb(); | 137 | isb(); |
| @@ -148,7 +148,7 @@ static void guest_at(void) · 10 unmodified lines | |||
| 148 | */ | 148 | */ |
| 149 | static void guest_dc_zva(void) | 149 | static void guest_dc_zva(void) |
| 150 | { | 150 | { |
| 151 | uint16_t val; | 151 | u16 val; |
| 152 | 152 | ||
| 153 | asm volatile("dc zva, %0" :: "r" (guest_test_memory)); | 153 | asm volatile("dc zva, %0" :: "r" (guest_test_memory)); |
| 154 | dsb(ish); | 154 | dsb(ish); |
| @@ -164,8 +164,8 @@ static void guest_dc_zva(void) · 9 unmodified lines | |||
| 164 | */ | 164 | */ |
| 165 | static void guest_ld_preidx(void) | 165 | static void guest_ld_preidx(void) |
| 166 | { | 166 | { |
| 167 | uint64_t val; | 167 | u64 val; |
| 168 | uint64_t addr = TEST_GVA - 8; | 168 | u64 addr = TEST_GVA - 8; |
| 169 | 169 | ||
| 170 | /* | 170 | /* |
| 171 | * This ends up accessing "TEST_GVA + 8 - 8", where "TEST_GVA - 8" is | 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 | static void guest_st_preidx(void) | 180 | static void guest_st_preidx(void) |
| 181 | { | 181 | { |
| 182 | uint64_t val = TEST_DATA; | 182 | u64 val = TEST_DATA; |
| 183 | uint64_t addr = TEST_GVA - 8; | 183 | u64 addr = TEST_GVA - 8; |
| 184 | 184 | ||
| 185 | asm volatile("str %0, [%1, #8]!" | 185 | asm volatile("str %0, [%1, #8]!" |
| 186 | : "+r" (val), "+r" (addr)); | 186 | : "+r" (val), "+r" (addr)); |
| @@ -191,8 +191,8 @@ static void guest_st_preidx(void) · 4 unmodified lines | |||
| 191 | 191 | ||
| 192 | static bool guest_set_ha(void) | 192 | static bool guest_set_ha(void) |
| 193 | { | 193 | { |
| 194 | uint64_t mmfr1 = read_sysreg(id_aa64mmfr1_el1); | 194 | u64 mmfr1 = read_sysreg(id_aa64mmfr1_el1); |
| 195 | uint64_t hadbs, tcr; | 195 | u64 hadbs, tcr; |
| 196 | 196 | ||
| 197 | /* Skip if HA is not supported. */ | 197 | /* Skip if HA is not supported. */ |
| 198 | hadbs = FIELD_GET(ID_AA64MMFR1_EL1_HAFDBS, mmfr1); | 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 | static bool guest_clear_pte_af(void) | 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 | flush_tlb_page(TEST_GVA); | 212 | flush_tlb_page(TEST_GVA); |
| 213 | 213 | ||
| 214 | return true; | 214 | return true; |
| @@ -217,7 +217,7 @@ static bool guest_clear_pte_af(void) · 2 unmodified lines | |||
| 217 | static void guest_check_pte_af(void) | 217 | static void guest_check_pte_af(void) |
| 218 | { | 218 | { |
| 219 | dsb(ish); | 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 | static void guest_check_write_in_dirty_log(void) | 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 | static struct uffd_args { | 302 | static struct uffd_args { |
| 303 | char *copy; | 303 | char *copy; |
| 304 | void *hva; | 304 | void *hva; |
| 305 | uint64_t paging_size; | 305 | u64 paging_size; |
| 306 | } pt_args, data_args; | 306 | } pt_args, data_args; |
| 307 | 307 | ||
| 308 | /* Returns true to continue the test, and false if it should be skipped. */ | 308 | /* Returns true to continue the test, and false if it should be skipped. */ |
| 309 | static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg, | 309 | static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg, |
| 310 | struct uffd_args *args) | 310 | struct uffd_args *args) |
| 311 | { | 311 | { |
| 312 | uint64_t addr = msg->arg.pagefault.address; | 312 | u64 addr = msg->arg.pagefault.address; |
| 313 | uint64_t flags = msg->arg.pagefault.flags; | 313 | u64 flags = msg->arg.pagefault.flags; |
| 314 | struct uffdio_copy copy; | 314 | struct uffdio_copy copy; |
| 315 | int ret; | 315 | int ret; |
| 316 | 316 | ||
| 317 | TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING, | 317 | TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING, |
| 318 | "The only expected UFFD mode is MISSING"); | 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 | pr_debug("uffd fault: addr=%p write=%d\n", | 321 | pr_debug("uffd fault: addr=%p write=%d\n", |
| 322 | (void *)addr, !!(flags & UFFD_PAGEFAULT_FLAG_WRITE)); | 322 | (void *)addr, !!(flags & UFFD_PAGEFAULT_FLAG_WRITE)); |
| 323 | 323 | ||
| 324 | copy.src = (uint64_t)args->copy; | 324 | copy.src = (u64)args->copy; |
| 325 | copy.dst = addr; | 325 | copy.dst = addr; |
| 326 | copy.len = args->paging_size; | 326 | copy.len = args->paging_size; |
| 327 | copy.mode = 0; | 327 | copy.mode = 0; |
| @@ -407,7 +407,7 @@ static bool punch_hole_in_backing_store(struct kvm_vm *vm, · 79 unmodified lines | |||
| 407 | struct userspace_mem_region *region) | 407 | struct userspace_mem_region *region) |
| 408 | { | 408 | { |
| 409 | void *hva = (void *)region->region.userspace_addr; | 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 | int ret, fd = region->fd; | 411 | int ret, fd = region->fd; |
| 412 | 412 | ||
| 413 | if (fd != -1) { | 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 | static void mmio_no_handler(struct kvm_vm *vm, struct kvm_run *run) | 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 | memcpy(&data, run->mmio.data, sizeof(data)); | 443 | memcpy(&data, run->mmio.data, sizeof(data)); |
| 444 | pr_debug("addr=%lld len=%d w=%d data=%lx\n", | 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 | static bool check_write_in_dirty_log(struct kvm_vm *vm, | 450 | static bool check_write_in_dirty_log(struct kvm_vm *vm, |
| 451 | struct userspace_mem_region *region, | 451 | struct userspace_mem_region *region, |
| 452 | uint64_t host_pg_nr) | 452 | u64 host_pg_nr) |
| 453 | { | 453 | { |
| 454 | unsigned long *bmap; | 454 | unsigned long *bmap; |
| 455 | bool first_page_dirty; | 455 | bool first_page_dirty; |
| 456 | uint64_t size = region->region.memory_size; | 456 | u64 size = region->region.memory_size; |
| 457 | 457 | ||
| 458 | /* getpage_size() is not always equal to vm->page_size */ | 458 | /* getpage_size() is not always equal to vm->page_size */ |
| 459 | bmap = bitmap_zalloc(size / getpagesize()); | 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 | struct userspace_mem_region *data_region, *pt_region; | 469 | struct userspace_mem_region *data_region, *pt_region; |
| 470 | bool continue_test = true; | 470 | bool continue_test = true; |
| 471 | uint64_t pte_gpa, pte_pg; | 471 | u64 pte_gpa, pte_pg; |
| 472 | 472 | ||
| 473 | data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); | 473 | data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); |
| 474 | pt_region = vm_get_mem_region(vm, MEM_REGION_PT); | 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 | events.fail_vcpu_runs += 1; | 510 | events.fail_vcpu_runs += 1; |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | typedef uint32_t aarch64_insn_t; | 513 | typedef u32 aarch64_insn_t; |
| 514 | extern aarch64_insn_t __exec_test[2]; | 514 | extern aarch64_insn_t __exec_test[2]; |
| 515 | 515 | ||
| 516 | noinline void __return_0x77(void) | 516 | noinline void __return_0x77(void) |
| @@ -525,7 +525,7 @@ noinline void __return_0x77(void) · 8 unmodified lines | |||
| 525 | */ | 525 | */ |
| 526 | static void load_exec_code_for_test(struct kvm_vm *vm) | 526 | static void load_exec_code_for_test(struct kvm_vm *vm) |
| 527 | { | 527 | { |
| 528 | uint64_t *code; | 528 | u64 *code; |
| 529 | struct userspace_mem_region *region; | 529 | struct userspace_mem_region *region; |
| 530 | void *hva; | 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 | static void setup_gva_maps(struct kvm_vm *vm) | 552 | static void setup_gva_maps(struct kvm_vm *vm) |
| 553 | { | 553 | { |
| 554 | struct userspace_mem_region *region; | 554 | struct userspace_mem_region *region; |
| 555 | uint64_t pte_gpa; | 555 | u64 pte_gpa; |
| 556 | 556 | ||
| 557 | region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); | 557 | region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); |
| 558 | /* Map TEST_GVA first. This will install a new PTE. */ | 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 | static void setup_memslots(struct kvm_vm *vm, struct test_params *p) | 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); | 577 | u64 backing_src_pagesz = get_backing_src_pagesz(p->src_type); |
| 578 | uint64_t guest_page_size = vm->page_size; | 578 | u64 guest_page_size = vm->page_size; |
| 579 | uint64_t max_gfn = vm_compute_max_gfn(vm); | 579 | u64 max_gfn = vm_compute_max_gfn(vm); |
| 580 | /* Enough for 2M of code when using 4K guest pages. */ | 580 | /* Enough for 2M of code when using 4K guest pages. */ |
| 581 | uint64_t code_npages = 512; | 581 | u64 code_npages = 512; |
| 582 | uint64_t pt_size, data_size, data_gpa; | 582 | u64 pt_size, data_size, data_gpa; |
| 583 | 583 | ||
| 584 | /* | 584 | /* |
| 585 | * This test requires 1 pgd, 2 pud, 4 pmd, and 6 pte pages when using | 585 | * This test requires 1 pgd, 2 pud, 4 pmd, and 6 pte pages when using |
| @@ -22,8 +22,7 @@ · 21 unmodified lines | |||
| 22 | #define CPU_ON_ENTRY_ADDR 0xfeedf00dul | 22 | #define CPU_ON_ENTRY_ADDR 0xfeedf00dul |
| 23 | #define CPU_ON_CONTEXT_ID 0xdeadc0deul | 23 | #define CPU_ON_CONTEXT_ID 0xdeadc0deul |
| 24 | 24 | ||
| 25 | static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, | 25 | static u64 psci_cpu_on(u64 target_cpu, u64 entry_addr, u64 context_id) |
| 26 | uint64_t context_id) | ||
| 27 | { | 26 | { |
| 28 | struct arm_smccc_res res; | 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 | return res.a0; | 32 | return res.a0; |
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | static uint64_t psci_affinity_info(uint64_t target_affinity, | 35 | static u64 psci_affinity_info(u64 target_affinity, u64 lowest_affinity_level) |
| 37 | uint64_t lowest_affinity_level) | ||
| 38 | { | 36 | { |
| 39 | struct arm_smccc_res res; | 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 | return res.a0; | 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 | struct arm_smccc_res res; | 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 | return res.a0; | 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 | struct arm_smccc_res res; | 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 | return res.a0; | 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 | struct arm_smccc_res res; | 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 | static void assert_vcpu_reset(struct kvm_vcpu *vcpu) | 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 | obs_pc = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc)); | 113 | obs_pc = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc)); |
| 116 | obs_x0 = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.regs[0])); | 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 | obs_x0, CPU_ON_CONTEXT_ID); | 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 | GUEST_ASSERT(!psci_cpu_on(target_cpu, CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID)); | 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 | static void host_test_cpu_on(void) | 140 | static void host_test_cpu_on(void) |
| 143 | { | 141 | { |
| 144 | struct kvm_vcpu *source, *target; | 142 | struct kvm_vcpu *source, *target; |
| 145 | uint64_t target_mpidr; | 143 | u64 target_mpidr; |
| 146 | struct kvm_vm *vm; | 144 | struct kvm_vm *vm; |
| 147 | struct ucall uc; | 145 | struct ucall uc; |
| 148 | 146 | ||
| @@ -166,7 +164,7 @@ static void host_test_cpu_on(void) · 17 unmodified lines | |||
| 166 | 164 | ||
| 167 | static void guest_test_system_suspend(void) | 165 | static void guest_test_system_suspend(void) |
| 168 | { | 166 | { |
| 169 | uint64_t ret; | 167 | u64 ret; |
| 170 | 168 | ||
| 171 | /* assert that SYSTEM_SUSPEND is discoverable */ | 169 | /* assert that SYSTEM_SUSPEND is discoverable */ |
| 172 | GUEST_ASSERT(!psci_features(PSCI_1_0_FN_SYSTEM_SUSPEND)); | 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 | static void guest_test_system_off2(void) | 199 | static void guest_test_system_off2(void) |
| 202 | { | 200 | { |
| 203 | uint64_t ret; | 201 | u64 ret; |
| 204 | 202 | ||
| 205 | /* assert that SYSTEM_OFF2 is discoverable */ | 203 | /* assert that SYSTEM_OFF2 is discoverable */ |
| 206 | GUEST_ASSERT(psci_features(PSCI_1_3_FN_SYSTEM_OFF2) & | 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 | struct kvm_vcpu *source, *target; | 237 | struct kvm_vcpu *source, *target; |
| 240 | struct kvm_mp_state mps; | 238 | struct kvm_mp_state mps; |
| 241 | uint64_t psci_version = 0; | 239 | u64 psci_version = 0; |
| 242 | int nr_shutdowns = 0; | 240 | int nr_shutdowns = 0; |
| 243 | struct kvm_run *run; | 241 | struct kvm_run *run; |
| 244 | struct ucall uc; | 242 | struct ucall uc; |
| @@ -51,18 +51,16 @@ · 50 unmodified lines | |||
| 51 | #define EINJ_OFFSET 0x01234badUL | 51 | #define EINJ_OFFSET 0x01234badUL |
| 52 | #define EINJ_GVA ((START_GVA) + (EINJ_OFFSET)) | 52 | #define EINJ_GVA ((START_GVA) + (EINJ_OFFSET)) |
| 53 | 53 | ||
| 54 | static vm_paddr_t einj_gpa; | 54 | static gpa_t einj_gpa; |
| 55 | static void *einj_hva; | 55 | static void *einj_hva; |
| 56 | static uint64_t einj_hpa; | 56 | static u64 einj_hpa; |
| 57 | static bool far_invalid; | 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; | 61 | u64 pinfo; |
| 62 | int64_t offset = vaddr / getpagesize() * sizeof(pinfo); | 62 | s64 offset = hva / getpagesize() * sizeof(pinfo); |
| 63 | int fd; | 63 | int fd; |
| 64 | uint64_t page_addr; | ||
| 65 | uint64_t paddr; | ||
| 66 | 64 | ||
| 67 | fd = open("/proc/self/pagemap", O_RDONLY); | 65 | fd = open("/proc/self/pagemap", O_RDONLY); |
| 68 | if (fd < 0) | 66 | if (fd < 0) |
| @@ -77,12 +75,11 @@ static uint64_t translate_to_host_paddr(unsigned long vaddr) · 8 unmodified lines | |||
| 77 | if ((pinfo & PAGE_PRESENT) == 0) | 75 | if ((pinfo & PAGE_PRESENT) == 0) |
| 78 | ksft_exit_fail_perror("Page not present"); | 76 | ksft_exit_fail_perror("Page not present"); |
| 79 | 77 | ||
| 80 | page_addr = (pinfo & PAGE_PHYSICAL) << MIN_PAGE_SHIFT; | 78 | return ((pinfo & PAGE_PHYSICAL) << MIN_PAGE_SHIFT) + |
| 81 | paddr = page_addr + (vaddr & (getpagesize() - 1)); | 79 | (hva & (getpagesize() - 1)); |
| 82 | return paddr; | ||
| 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 | char cmd[256] = {0}; | 84 | char cmd[256] = {0}; |
| 88 | FILE *cmdfile = NULL; | 85 | FILE *cmdfile = NULL; |
| @@ -96,7 +93,7 @@ static void write_einj_entry(const char *einj_path, uint64_t val) · 7 unmodified lines | |||
| 96 | ksft_exit_fail_perror("Failed to write EINJ entry"); | 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 | if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) | 98 | if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) |
| 102 | ksft_test_result_skip("EINJ table no available in firmware"); | 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 | write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER); | 104 | write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER); |
| 108 | write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER); | 105 | write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER); |
| 109 | write_einj_entry(EINJ_ADDR, paddr); | 106 | write_einj_entry(EINJ_ADDR, hpa); |
| 110 | write_einj_entry(EINJ_MASK, ~0x0UL); | 107 | write_einj_entry(EINJ_MASK, ~0x0UL); |
| 111 | write_einj_entry(EINJ_NOTRIGGER, 1); | 108 | write_einj_entry(EINJ_NOTRIGGER, 1); |
| 112 | write_einj_entry(EINJ_DOIT, 1); | 109 | write_einj_entry(EINJ_DOIT, 1); |
| @@ -145,10 +142,10 @@ static void setup_sigbus_handler(void) · 32 unmodified lines | |||
| 145 | 142 | ||
| 146 | static void guest_code(void) | 143 | static void guest_code(void) |
| 147 | { | 144 | { |
| 148 | uint64_t guest_data; | 145 | u64 guest_data; |
| 149 | 146 | ||
| 150 | /* Consumes error will cause a SEA. */ | 147 | /* Consumes error will cause a SEA. */ |
| 151 | guest_data = *(uint64_t *)EINJ_GVA; | 148 | guest_data = *(u64 *)EINJ_GVA; |
| 152 | 149 | ||
| 153 | GUEST_FAIL("Poison not protected by SEA: gva=%#lx, guest_data=%#lx\n", | 150 | GUEST_FAIL("Poison not protected by SEA: gva=%#lx, guest_data=%#lx\n", |
| 154 | EINJ_GVA, guest_data); | 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 | size_t backing_page_size; | 250 | size_t backing_page_size; |
| 254 | size_t guest_page_size; | 251 | size_t guest_page_size; |
| 255 | size_t alignment; | 252 | size_t alignment; |
| 256 | uint64_t num_guest_pages; | 253 | u64 num_guest_pages; |
| 257 | vm_paddr_t start_gpa; | 254 | gpa_t start_gpa; |
| 258 | enum vm_mem_backing_src_type src_type = VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB; | 255 | enum vm_mem_backing_src_type src_type = VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB; |
| 259 | struct kvm_vm *vm; | 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 | vm_userspace_mem_region_add( | 275 | vm_userspace_mem_region_add( |
| 279 | /*vm=*/vm, | 276 | /*vm=*/vm, |
| 280 | /*src_type=*/src_type, | 277 | /*src_type=*/src_type, |
| 281 | /*guest_paddr=*/start_gpa, | 278 | /*gpa=*/start_gpa, |
| 282 | /*slot=*/1, | 279 | /*slot=*/1, |
| 283 | /*npages=*/num_guest_pages, | 280 | /*npages=*/num_guest_pages, |
| 284 | /*flags=*/0); | 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 | static void vm_inject_memory_uer(struct kvm_vm *vm) | 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 | einj_gpa = addr_gva2gpa(vm, EINJ_GVA); | 294 | einj_gpa = addr_gva2gpa(vm, EINJ_GVA); |
| 298 | einj_hva = addr_gva2hva(vm, EINJ_GVA); | 295 | einj_hva = addr_gva2hva(vm, EINJ_GVA); |
| 299 | 296 | ||
| 300 | /* Populate certain data before injecting UER. */ | 297 | /* Populate certain data before injecting UER. */ |
| 301 | *(uint64_t *)einj_hva = 0xBAADCAFE; | 298 | *(u64 *)einj_hva = 0xBAADCAFE; |
| 302 | guest_data = *(uint64_t *)einj_hva; | 299 | guest_data = *(u64 *)einj_hva; |
| 303 | ksft_print_msg("Before EINJect: data=%#lx\n", | 300 | ksft_print_msg("Before EINJect: data=%#lx\n", |
| 304 | guest_data); | 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 | ksft_print_msg("EINJ_GVA=%#lx, einj_gpa=%#lx, einj_hva=%p, einj_hpa=%#lx\n", | 305 | ksft_print_msg("EINJ_GVA=%#lx, einj_gpa=%#lx, einj_hva=%p, einj_hpa=%#lx\n", |
| 309 | EINJ_GVA, einj_gpa, einj_hva, einj_hpa); | 306 | EINJ_GVA, einj_gpa, einj_hva, einj_hpa); |
| @@ -30,20 +30,20 @@ struct reg_ftr_bits { · 29 unmodified lines | |||
| 30 | char *name; | 30 | char *name; |
| 31 | bool sign; | 31 | bool sign; |
| 32 | enum ftr_type type; | 32 | enum ftr_type type; |
| 33 | uint8_t shift; | 33 | u8 shift; |
| 34 | uint64_t mask; | 34 | u64 mask; |
| 35 | /* | 35 | /* |
| 36 | * For FTR_EXACT, safe_val is used as the exact safe value. | 36 | * For FTR_EXACT, safe_val is used as the exact safe value. |
| 37 | * For FTR_LOWER_SAFE, safe_val is used as the minimal safe value. | 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 | /* Allowed to be changed by the host after run */ | 41 | /* Allowed to be changed by the host after run */ |
| 42 | bool mutable; | 42 | bool mutable; |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | struct test_feature_reg { | 45 | struct test_feature_reg { |
| 46 | uint32_t reg; | 46 | u32 reg; |
| 47 | const struct reg_ftr_bits *ftr_bits; | 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 | /* Return a safe value to a given ftr_bits an ftr value */ | 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 | TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features"); | 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 | /* Return an invalid value to a given ftr_bits an ftr value */ | 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 | TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features"); | 336 | TEST_ASSERT(ftr_max > 1, "This test doesn't support single bit features"); |
| 337 | 337 | ||
| 338 | if (ftr_bits->sign == FTR_UNSIGNED) { | 338 | if (ftr_bits->sign == FTR_UNSIGNED) { |
| 339 | switch (ftr_bits->type) { | 339 | switch (ftr_bits->type) { |
| 340 | case FTR_EXACT: | 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 | break; | 342 | break; |
| 343 | case FTR_LOWER_SAFE: | 343 | case FTR_LOWER_SAFE: |
| 344 | ftr++; | 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 | } else if (ftr != ftr_max) { | 358 | } else if (ftr != ftr_max) { |
| 359 | switch (ftr_bits->type) { | 359 | switch (ftr_bits->type) { |
| 360 | case FTR_EXACT: | 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 | break; | 362 | break; |
| 363 | case FTR_LOWER_SAFE: | 363 | case FTR_LOWER_SAFE: |
| 364 | ftr++; | 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 | return ftr; | 382 | return ftr; |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg, | 385 | static u64 test_reg_set_success(struct kvm_vcpu *vcpu, u64 reg, |
| 386 | const struct reg_ftr_bits *ftr_bits) | 386 | const struct reg_ftr_bits *ftr_bits) |
| 387 | { | 387 | { |
| 388 | uint8_t shift = ftr_bits->shift; | 388 | u8 shift = ftr_bits->shift; |
| 389 | uint64_t mask = ftr_bits->mask; | 389 | u64 mask = ftr_bits->mask; |
| 390 | uint64_t val, new_val, ftr; | 390 | u64 val, new_val, ftr; |
| 391 | 391 | ||
| 392 | val = vcpu_get_reg(vcpu, reg); | 392 | val = vcpu_get_reg(vcpu, reg); |
| 393 | ftr = (val & mask) >> shift; | 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 | return new_val; | 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 | const struct reg_ftr_bits *ftr_bits) | 409 | const struct reg_ftr_bits *ftr_bits) |
| 410 | { | 410 | { |
| 411 | uint8_t shift = ftr_bits->shift; | 411 | u8 shift = ftr_bits->shift; |
| 412 | uint64_t mask = ftr_bits->mask; | 412 | u64 mask = ftr_bits->mask; |
| 413 | uint64_t val, old_val, ftr; | 413 | u64 val, old_val, ftr; |
| 414 | int r; | 414 | int r; |
| 415 | 415 | ||
| 416 | val = vcpu_get_reg(vcpu, reg); | 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 | TEST_ASSERT_EQ(val, old_val); | 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 | #define encoding_to_range_idx(encoding) \ | 436 | #define encoding_to_range_idx(encoding) \ |
| 437 | KVM_ARM_FEATURE_ID_RANGE_IDX(sys_reg_Op0(encoding), sys_reg_Op1(encoding), \ | 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 | static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only) | 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 | struct reg_mask_range range = { | 445 | struct reg_mask_range range = { |
| 446 | .addr = (__u64)masks, | 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 | for (int i = 0; i < ARRAY_SIZE(test_regs); i++) { | 459 | for (int i = 0; i < ARRAY_SIZE(test_regs); i++) { |
| 460 | const struct reg_ftr_bits *ftr_bits = test_regs[i].ftr_bits; | 460 | const struct reg_ftr_bits *ftr_bits = test_regs[i].ftr_bits; |
| 461 | uint32_t reg_id = test_regs[i].reg; | 461 | u32 reg_id = test_regs[i].reg; |
| 462 | uint64_t reg = KVM_ARM64_SYS_REG(reg_id); | 462 | u64 reg = KVM_ARM64_SYS_REG(reg_id); |
| 463 | int idx; | 463 | int idx; |
| 464 | 464 | ||
| 465 | /* Get the index to masks array for the idreg */ | 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 | #define MPAM_IDREG_TEST 6 | 489 | #define MPAM_IDREG_TEST 6 |
| 490 | static void test_user_set_mpam_reg(struct kvm_vcpu *vcpu) | 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 | struct reg_mask_range range = { | 493 | struct reg_mask_range range = { |
| 494 | .addr = (__u64)masks, | 494 | .addr = (__u64)masks, |
| 495 | }; | 495 | }; |
| 496 | uint64_t val; | 496 | u64 val; |
| 497 | int idx, err; | 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 | #define MTE_IDREG_TEST 1 | 584 | #define MTE_IDREG_TEST 1 |
| 585 | static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) | 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 | struct reg_mask_range range = { | 588 | struct reg_mask_range range = { |
| 589 | .addr = (__u64)masks, | 589 | .addr = (__u64)masks, |
| 590 | }; | 590 | }; |
| 591 | uint64_t val; | 591 | u64 val; |
| 592 | uint64_t mte; | 592 | u64 mte; |
| 593 | uint64_t mte_frac; | 593 | u64 mte_frac; |
| 594 | int idx, err; | 594 | int idx, err; |
| 595 | 595 | ||
| 596 | val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1)); | 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 | ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n"); | 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 | struct test_feature_reg *reg = NULL; | 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 | struct ucall uc; | 674 | struct ucall uc; |
| 675 | 675 | ||
| 676 | while (!done) { | 676 | while (!done) { |
| 677 | uint64_t val; | 677 | u64 val; |
| 678 | 678 | ||
| 679 | vcpu_run(vcpu); | 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 | static void test_clidr(struct kvm_vcpu *vcpu) | 708 | static void test_clidr(struct kvm_vcpu *vcpu) |
| 709 | { | 709 | { |
| 710 | uint64_t clidr; | 710 | u64 clidr; |
| 711 | int level; | 711 | int level; |
| 712 | 712 | ||
| 713 | clidr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CLIDR_EL1)); | 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 | ksft_test_result_pass("%s\n", __func__); | 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 | size_t idx = encoding_to_range_idx(encoding); | 777 | size_t idx = encoding_to_range_idx(encoding); |
| 778 | uint64_t observed; | 778 | u64 observed; |
| 779 | 779 | ||
| 780 | observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding)); | 780 | observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding)); |
| 781 | TEST_ASSERT_EQ(reset_mutable_bits(encoding, test_reg_vals[idx]), | 781 | TEST_ASSERT_EQ(reset_mutable_bits(encoding, test_reg_vals[idx]), |
| @@ -808,7 +808,7 @@ int main(void) · 26 unmodified lines | |||
| 808 | struct kvm_vcpu *vcpu; | 808 | struct kvm_vcpu *vcpu; |
| 809 | struct kvm_vm *vm; | 809 | struct kvm_vm *vm; |
| 810 | bool aarch64_only; | 810 | bool aarch64_only; |
| 811 | uint64_t val, el0; | 811 | u64 val, el0; |
| 812 | int test_cnt, i, j; | 812 | int test_cnt, i, j; |
| 813 | 813 | ||
| 814 | TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES)); | 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 | for (conduit = test_runs_at_el2() ? SMC_INSN : HVC_INSN; \ | 37 | for (conduit = test_runs_at_el2() ? SMC_INSN : HVC_INSN; \ |
| 38 | conduit <= SMC_INSN; conduit++) | 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 | struct arm_smccc_res res; | 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 | GUEST_SYNC(res.a0); | 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 | enum kvm_smccc_filter_action action) | 53 | enum kvm_smccc_filter_action action) |
| 54 | { | 54 | { |
| 55 | struct kvm_smccc_filter filter = { | 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 | KVM_ARM_VM_SMCCC_FILTER, &filter); | 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 | enum kvm_smccc_filter_action action) | 66 | enum kvm_smccc_filter_action action) |
| 67 | { | 67 | { |
| 68 | int ret = __set_smccc_filter(vm, start, nr_functions, action); | 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 | struct kvm_vcpu *vcpu; | 113 | struct kvm_vcpu *vcpu; |
| 114 | struct kvm_vm *vm = setup_vm(&vcpu); | 114 | struct kvm_vm *vm = setup_vm(&vcpu); |
| 115 | uint32_t smc64_fn; | 115 | u32 smc64_fn; |
| 116 | int r; | 116 | int r; |
| 117 | 117 | ||
| 118 | r = __set_smccc_filter(vm, ARM_SMCCC_ARCH_WORKAROUND_1, | 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 | enum smccc_conduit conduit) | 221 | enum smccc_conduit conduit) |
| 222 | { | 222 | { |
| 223 | struct kvm_run *run = vcpu->run; | 223 | struct kvm_run *run = vcpu->run; |
| @@ -19,7 +19,7 @@ · 18 unmodified lines | |||
| 19 | 19 | ||
| 20 | #define NR_VCPUS 4 | 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 | #define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2) | 24 | #define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2) |
| 25 | #define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3) | 25 | #define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3) |
| @@ -27,10 +27,10 @@ · 1 unmodified line | |||
| 27 | struct vm_gic { | 27 | struct vm_gic { |
| 28 | struct kvm_vm *vm; | 28 | struct kvm_vm *vm; |
| 29 | int gic_fd; | 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 | * Helpers to access a redistributor register and verify the ioctl() failed or | 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 | static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset, | 39 | static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset, |
| 40 | int want, const char *msg) | 40 | int want, const char *msg) |
| 41 | { | 41 | { |
| 42 | uint32_t ignored_val; | 42 | u32 ignored_val; |
| 43 | int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, | 43 | int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, |
| 44 | REG_OFFSET(vcpu, offset), &ignored_val); | 44 | REG_OFFSET(vcpu, offset), &ignored_val); |
| 45 | 45 | ||
| 46 | TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want); | 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 | const char *msg) | 50 | const char *msg) |
| 51 | { | 51 | { |
| 52 | uint32_t val; | 52 | u32 val; |
| 53 | 53 | ||
| 54 | kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, | 54 | kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, |
| 55 | REG_OFFSET(vcpu, offset), &val); | 55 | REG_OFFSET(vcpu, offset), &val); |
| @@ -71,8 +71,8 @@ static int run_vcpu(struct kvm_vcpu *vcpu) · 15 unmodified lines | |||
| 71 | return __vcpu_run(vcpu) ? -errno : 0; | 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, | 74 | static struct vm_gic vm_gic_create_with_vcpus(u32 gic_dev_type, |
| 75 | uint32_t nr_vcpus, | 75 | u32 nr_vcpus, |
| 76 | struct kvm_vcpu *vcpus[]) | 76 | struct kvm_vcpu *vcpus[]) |
| 77 | { | 77 | { |
| 78 | struct vm_gic v; | 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 | return v; | 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 | struct vm_gic v; | 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 | struct vgic_region_attr { | 105 | struct vgic_region_attr { |
| 106 | uint64_t attr; | 106 | u64 attr; |
| 107 | uint64_t size; | 107 | u64 size; |
| 108 | uint64_t alignment; | 108 | u64 alignment; |
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | struct vgic_region_attr gic_v3_dist_region = { | 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 | static void subtest_dist_rdist(struct vm_gic *v) | 143 | static void subtest_dist_rdist(struct vm_gic *v) |
| 144 | { | 144 | { |
| 145 | int ret; | 145 | int ret; |
| 146 | uint64_t addr; | 146 | u64 addr; |
| 147 | struct vgic_region_attr rdist; /* CPU interface in GICv2*/ | 147 | struct vgic_region_attr rdist; /* CPU interface in GICv2*/ |
| 148 | struct vgic_region_attr dist; | 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 | /* Test the new REDIST region API */ | 223 | /* Test the new REDIST region API */ |
| 224 | static void subtest_v3_redist_regions(struct vm_gic *v) | 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 | int ret; | 227 | int ret; |
| 228 | 228 | ||
| 229 | ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, | 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 | * VGIC KVM device is created and initialized before the secondary CPUs | 332 | * VGIC KVM device is created and initialized before the secondary CPUs |
| 333 | * get created | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 337 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 338 | struct vm_gic v; | 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 | /* All the VCPUs are created before the VGIC KVM device gets initialized */ | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 358 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 359 | struct vm_gic v; | 359 | struct vm_gic v; |
| @@ -408,7 +408,7 @@ static void test_v3_new_redist_regions(void) · 48 unmodified lines | |||
| 408 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 408 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 409 | void *dummy = NULL; | 409 | void *dummy = NULL; |
| 410 | struct vm_gic v; | 410 | struct vm_gic v; |
| 411 | uint64_t addr; | 411 | u64 addr; |
| 412 | int ret; | 412 | int ret; |
| 413 | 413 | ||
| 414 | v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); | 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 | static void test_v3_typer_accesses(void) | 460 | static void test_v3_typer_accesses(void) |
| 461 | { | 461 | { |
| 462 | struct vm_gic v; | 462 | struct vm_gic v; |
| 463 | uint64_t addr; | 463 | u64 addr; |
| 464 | int ret, i; | 464 | int ret, i; |
| 465 | 465 | ||
| 466 | v.vm = vm_create(NR_VCPUS); | 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 | static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus, | 520 | static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus, |
| 521 | uint32_t vcpuids[]) | 521 | u32 vcpuids[]) |
| 522 | { | 522 | { |
| 523 | struct vm_gic v; | 523 | struct vm_gic v; |
| 524 | int i; | 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 | static void test_v3_last_bit_redist_regions(void) | 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 | struct vm_gic v; | 548 | struct vm_gic v; |
| 549 | uint64_t addr; | 549 | u64 addr; |
| 550 | 550 | ||
| 551 | v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids); | 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 | /* Test last bit with legacy region */ | 578 | /* Test last bit with legacy region */ |
| 579 | static void test_v3_last_bit_single_rdist(void) | 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 | struct vm_gic v; | 582 | struct vm_gic v; |
| 583 | uint64_t addr; | 583 | u64 addr; |
| 584 | 584 | ||
| 585 | v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids); | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 606 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 607 | struct vm_gic v; | 607 | struct vm_gic v; |
| 608 | int ret, i; | 608 | int ret, i; |
| 609 | uint64_t addr; | 609 | u64 addr; |
| 610 | 610 | ||
| 611 | v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus); | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 639 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 640 | struct vm_gic v; | 640 | struct vm_gic v; |
| 641 | uint64_t addr; | 641 | u64 addr; |
| 642 | int its_fd, ret; | 642 | int its_fd, ret; |
| 643 | 643 | ||
| 644 | v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); | 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 | * Returns 0 if it's possible to create GIC device of a given type (V2 or V3). | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 722 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 723 | struct vm_gic v; | 723 | struct vm_gic v; |
| 724 | uint32_t other; | 724 | u32 other; |
| 725 | int ret; | 725 | int ret; |
| 726 | 726 | ||
| 727 | v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus); | 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 | kvm_vm_free(vm); | 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 | test_vcpus_then_vgic(gic_dev_type); | 973 | test_vcpus_then_vgic(gic_dev_type); |
| 974 | test_vgic_then_vcpus(gic_dev_type); | 974 | test_vgic_then_vcpus(gic_dev_type); |
| @@ -24,12 +24,12 @@ · 23 unmodified lines | |||
| 24 | * function. | 24 | * function. |
| 25 | */ | 25 | */ |
| 26 | struct test_args { | 26 | struct test_args { |
| 27 | uint32_t nr_irqs; /* number of KVM supported IRQs. */ | 27 | u32 nr_irqs; /* number of KVM supported IRQs. */ |
| 28 | bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */ | 28 | bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */ |
| 29 | bool level_sensitive; /* 1 is level, 0 is edge */ | 29 | bool level_sensitive; /* 1 is level, 0 is edge */ |
| 30 | int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */ | 30 | int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */ |
| 31 | bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */ | 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 | struct kvm_inject_args { | 65 | struct kvm_inject_args { |
| 66 | kvm_inject_cmd cmd; | 66 | kvm_inject_cmd cmd; |
| 67 | uint32_t first_intid; | 67 | u32 first_intid; |
| 68 | uint32_t num; | 68 | u32 num; |
| 69 | int level; | 69 | int level; |
| 70 | bool expect_failure; | 70 | bool expect_failure; |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | /* Used on the guest side to perform the hypercall. */ | 73 | /* Used on the guest side to perform the hypercall. */ |
| 74 | static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, | 74 | static void kvm_inject_call(kvm_inject_cmd cmd, u32 first_intid, |
| 75 | uint32_t num, int level, bool expect_failure); | 75 | u32 num, int level, bool expect_failure); |
| 76 | 76 | ||
| 77 | /* Used on the host side to get the hypercall info. */ | 77 | /* Used on the host side to get the hypercall info. */ |
| 78 | static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc, | 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 | for_each_supported_inject_fn((args), (t), (f)) | 133 | for_each_supported_inject_fn((args), (t), (f)) |
| 134 | 134 | ||
| 135 | /* Shared between the guest main thread and the IRQ handlers. */ | 135 | /* Shared between the guest main thread and the IRQ handlers. */ |
| 136 | volatile uint64_t irq_handled; | 136 | volatile u64 irq_handled; |
| 137 | volatile uint32_t irqnr_received[MAX_SPI + 1]; | 137 | volatile u32 irqnr_received[MAX_SPI + 1]; |
| 138 | 138 | ||
| 139 | static void reset_stats(void) | 139 | static void reset_stats(void) |
| 140 | { | 140 | { |
| @@ -145,25 +145,25 @@ static void reset_stats(void) · 4 unmodified lines | |||
| 145 | irqnr_received[i] = 0; | 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 | dsb(sy); | 152 | dsb(sy); |
| 153 | return reg; | 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 | write_sysreg_s(val, SYS_ICC_AP1R0_EL1); | 158 | write_sysreg_s(val, SYS_ICC_AP1R0_EL1); |
| 159 | isb(); | 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 | static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive) | 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 | if (intid == IAR_SPURIOUS) | 168 | if (intid == IAR_SPURIOUS) |
| 169 | return; | 169 | return; |
| @@ -189,8 +189,8 @@ static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive) · 19 unmodified lines | |||
| 189 | GUEST_ASSERT(!gic_irq_get_pending(intid)); | 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, | 192 | static void kvm_inject_call(kvm_inject_cmd cmd, u32 first_intid, |
| 193 | uint32_t num, int level, bool expect_failure) | 193 | u32 num, int level, bool expect_failure) |
| 194 | { | 194 | { |
| 195 | struct kvm_inject_args args = { | 195 | struct kvm_inject_args args = { |
| 196 | .cmd = cmd, | 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 | #define GUEST_ASSERT_IAR_EMPTY() \ | 205 | #define GUEST_ASSERT_IAR_EMPTY() \ |
| 206 | do { \ | 206 | do { \ |
| 207 | uint32_t _intid; \ | 207 | u32 _intid; \ |
| 208 | _intid = gic_get_and_ack_irq(); \ | 208 | _intid = gic_get_and_ack_irq(); \ |
| 209 | GUEST_ASSERT(_intid == IAR_SPURIOUS); \ | 209 | GUEST_ASSERT(_intid == IAR_SPURIOUS); \ |
| 210 | } while (0) | 210 | } while (0) |
| @@ -237,13 +237,13 @@ static void reset_priorities(struct test_args *args) · 26 unmodified lines | |||
| 237 | gic_set_priority(i, IRQ_DEFAULT_PRIO_REG); | 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 | kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false); | 242 | kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static void test_inject_fail(struct test_args *args, | 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 | reset_stats(); | 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 | static void guest_inject(struct test_args *args, | 257 | static void guest_inject(struct test_args *args, |
| 258 | uint32_t first_intid, uint32_t num, | 258 | u32 first_intid, u32 num, |
| 259 | kvm_inject_cmd cmd) | 259 | kvm_inject_cmd cmd) |
| 260 | { | 260 | { |
| 261 | uint32_t i; | 261 | u32 i; |
| 262 | 262 | ||
| 263 | reset_stats(); | 263 | reset_stats(); |
| 264 | 264 | ||
| @@ -292,10 +292,10 @@ static void guest_inject(struct test_args *args, · 27 unmodified lines | |||
| 292 | * deactivated yet. | 292 | * deactivated yet. |
| 293 | */ | 293 | */ |
| 294 | static void guest_restore_active(struct test_args *args, | 294 | static void guest_restore_active(struct test_args *args, |
| 295 | uint32_t first_intid, uint32_t num, | 295 | u32 first_intid, u32 num, |
| 296 | kvm_inject_cmd cmd) | 296 | kvm_inject_cmd cmd) |
| 297 | { | 297 | { |
| 298 | uint32_t prio, intid, ap1r; | 298 | u32 prio, intid, ap1r; |
| 299 | int i; | 299 | int i; |
| 300 | 300 | ||
| 301 | /* | 301 | /* |
| @@ -342,9 +342,9 @@ static void guest_restore_active(struct test_args *args, · 40 unmodified lines | |||
| 342 | * This function should only be used in test_inject_preemption (with IRQs | 342 | * This function should only be used in test_inject_preemption (with IRQs |
| 343 | * masked). | 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 | do { | 349 | do { |
| 350 | asm volatile("wfi" : : : "memory"); | 350 | asm volatile("wfi" : : : "memory"); |
| @@ -360,11 +360,11 @@ static uint32_t wait_for_and_activate_irq(void) · 9 unmodified lines | |||
| 360 | * interrupts for the whole test. | 360 | * interrupts for the whole test. |
| 361 | */ | 361 | */ |
| 362 | static void test_inject_preemption(struct test_args *args, | 362 | static void test_inject_preemption(struct test_args *args, |
| 363 | uint32_t first_intid, int num, | 363 | u32 first_intid, int num, |
| 364 | const unsigned long *exclude, | 364 | const unsigned long *exclude, |
| 365 | kvm_inject_cmd cmd) | 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 | int i; | 368 | int i; |
| 369 | 369 | ||
| 370 | /* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs | 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 | local_irq_disable(); | 379 | local_irq_disable(); |
| 380 | 380 | ||
| 381 | for (i = 0; i < num; i++) { | 381 | for (i = 0; i < num; i++) { |
| 382 | uint32_t tmp; | 382 | u32 tmp; |
| 383 | intid = i + first_intid; | 383 | intid = i + first_intid; |
| 384 | 384 | ||
| 385 | if (exclude && test_bit(i, exclude)) | 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 | static void test_injection(struct test_args *args, struct kvm_inject_desc *f) | 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 | if (f->sgi) { | 436 | if (f->sgi) { |
| 437 | guest_inject(args, MIN_SGI, 1, f->cmd); | 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 | static void test_injection_failure(struct test_args *args, | 451 | static void test_injection_failure(struct test_args *args, |
| 452 | struct kvm_inject_desc *f) | 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 | int i; | 455 | int i; |
| 456 | 456 | ||
| 457 | for (i = 0; i < ARRAY_SIZE(bad_intid); i++) | 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 | static void guest_code(struct test_args *args) | 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 | bool level_sensitive = args->level_sensitive; | 494 | bool level_sensitive = args->level_sensitive; |
| 495 | struct kvm_inject_desc *f, *inject_fns; | 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 | GUEST_DONE(); | 529 | GUEST_DONE(); |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level, | 532 | static void kvm_irq_line_check(struct kvm_vm *vm, u32 intid, int level, |
| 533 | struct test_args *test_args, bool expect_failure) | 533 | struct test_args *test_args, bool expect_failure) |
| 534 | { | 534 | { |
| 535 | int ret; | 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, | 551 | void kvm_irq_set_level_info_check(int gic_fd, u32 intid, int level, |
| 552 | bool expect_failure) | 552 | bool expect_failure) |
| 553 | { | 553 | { |
| 554 | if (!expect_failure) { | 554 | if (!expect_failure) { |
| 555 | kvm_irq_set_level_info(gic_fd, intid, level); | 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 | static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm, | 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, | 576 | u32 intid, u32 num, |
| 577 | bool expect_failure) | 577 | u32 kvm_max_routes, |
| 578 | bool expect_failure) | ||
| 578 | { | 579 | { |
| 579 | struct kvm_irq_routing *routing; | 580 | struct kvm_irq_routing *routing; |
| 580 | int ret; | 581 | int ret; |
| 581 | uint64_t i; | 582 | u64 i; |
| 582 | 583 | ||
| 583 | assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES); | 584 | assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES); |
| 584 | 585 | ||
| 585 | routing = kvm_gsi_routing_create(); | 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 | kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI); | 588 | kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI); |
| 588 | 589 | ||
| 589 | if (!expect_failure) { | 590 | if (!expect_failure) { |
| @@ -591,7 +592,7 @@ static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm, · 1 unmodified line | |||
| 591 | } else { | 592 | } else { |
| 592 | ret = _kvm_gsi_routing_write(vm, routing); | 593 | ret = _kvm_gsi_routing_write(vm, routing); |
| 593 | /* The kernel only checks e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS */ | 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 | TEST_ASSERT(ret != 0 && errno == EINVAL, | 596 | TEST_ASSERT(ret != 0 && errno == EINVAL, |
| 596 | "Bad intid %u did not cause KVM_SET_GSI_ROUTING " | 597 | "Bad intid %u did not cause KVM_SET_GSI_ROUTING " |
| 597 | "error: rc: %i errno: %i", intid, ret, errno); | 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 | struct kvm_vcpu *vcpu, | 607 | struct kvm_vcpu *vcpu, |
| 607 | bool expect_failure) | 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 | static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, | 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 | u32 intid, u32 num, u32 kvm_max_routes, |
| 622 | bool expect_failure) | 623 | bool expect_failure) |
| 623 | { | 624 | { |
| 624 | int fd[MAX_SPI]; | 625 | int fd[MAX_SPI]; |
| 625 | uint64_t val; | 626 | u64 val; |
| 626 | int ret, f; | 627 | int ret, f; |
| 627 | uint64_t i; | 628 | u64 i; |
| 628 | 629 | ||
| 629 | /* | 630 | /* |
| 630 | * There is no way to try injecting an SGI or PPI as the interface | 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 | * that no actual interrupt was injected for those cases. | 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 | fd[f] = kvm_new_eventfd(); | 648 | fd[f] = kvm_new_eventfd(); |
| 648 | 649 | ||
| 649 | for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) { | 650 | for (f = 0, i = intid; i < (u64)intid + num; i++, f++) { |
| 650 | assert(i <= (uint64_t)UINT_MAX); | 651 | assert(i <= (u64)UINT_MAX); |
| 651 | kvm_assign_irqfd(vm, i - MIN_SPI, fd[f]); | 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 | val = 1; | 656 | val = 1; |
| 656 | ret = write(fd[f], &val, sizeof(uint64_t)); | 657 | ret = write(fd[f], &val, sizeof(u64)); |
| 657 | TEST_ASSERT(ret == sizeof(uint64_t), | 658 | TEST_ASSERT(ret == sizeof(u64), |
| 658 | __KVM_SYSCALL_ERROR("write()", ret)); | 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 | kvm_close(fd[f]); | 663 | kvm_close(fd[f]); |
| 663 | } | 664 | } |
| 664 | 665 | ||
| 665 | /* handles the valid case: intid=0xffffffff num=1 */ | 666 | /* handles the valid case: intid=0xffffffff num=1 */ |
| 666 | #define for_each_intid(first, num, tmp, i) \ | 667 | #define for_each_intid(first, num, tmp, i) \ |
| 667 | for ((tmp) = (i) = (first); \ | 668 | for ((tmp) = (i) = (first); \ |
| 668 | (tmp) < (uint64_t)(first) + (uint64_t)(num); \ | 669 | (tmp) < (u64)(first) + (u64)(num); \ |
| 669 | (tmp)++, (i)++) | 670 | (tmp)++, (i)++) |
| 670 | 671 | ||
| 671 | static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd, | 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 | struct test_args *test_args) | 674 | struct test_args *test_args) |
| 674 | { | 675 | { |
| 675 | kvm_inject_cmd cmd = inject_args->cmd; | 676 | kvm_inject_cmd cmd = inject_args->cmd; |
| 676 | uint32_t intid = inject_args->first_intid; | 677 | u32 intid = inject_args->first_intid; |
| 677 | uint32_t num = inject_args->num; | 678 | u32 num = inject_args->num; |
| 678 | int level = inject_args->level; | 679 | int level = inject_args->level; |
| 679 | bool expect_failure = inject_args->expect_failure; | 680 | bool expect_failure = inject_args->expect_failure; |
| 680 | struct kvm_vm *vm = vcpu->vm; | 681 | struct kvm_vm *vm = vcpu->vm; |
| 681 | uint64_t tmp; | 682 | u64 tmp; |
| 682 | uint32_t i; | 683 | u32 i; |
| 683 | 684 | ||
| 684 | /* handles the valid case: intid=0xffffffff num=1 */ | 685 | /* handles the valid case: intid=0xffffffff num=1 */ |
| 685 | assert(intid < UINT_MAX - num || num == 1); | 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 | struct kvm_inject_args *args) | 732 | struct kvm_inject_args *args) |
| 732 | { | 733 | { |
| 733 | struct kvm_inject_args *kvm_args_hva; | 734 | struct kvm_inject_args *kvm_args_hva; |
| 734 | vm_vaddr_t kvm_args_gva; | 735 | gva_t kvm_args_gva; |
| 735 | 736 | ||
| 736 | kvm_args_gva = uc->args[1]; | 737 | kvm_args_gva = uc->args[1]; |
| 737 | kvm_args_hva = (struct kvm_inject_args *)addr_gva2hva(vm, kvm_args_gva); | 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 | args->eoi_split); | 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 | struct ucall uc; | 751 | struct ucall uc; |
| 751 | int gic_fd; | 752 | int gic_fd; |
| 752 | struct kvm_vcpu *vcpu; | 753 | struct kvm_vcpu *vcpu; |
| 753 | struct kvm_vm *vm; | 754 | struct kvm_vm *vm; |
| 754 | struct kvm_inject_args inject_args; | 755 | struct kvm_inject_args inject_args; |
| 755 | vm_vaddr_t args_gva; | 756 | gva_t args_gva; |
| 756 | 757 | ||
| 757 | struct test_args args = { | 758 | struct test_args args = { |
| 758 | .nr_irqs = nr_irqs, | 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 | vcpu_init_descriptor_tables(vcpu); | 771 | vcpu_init_descriptor_tables(vcpu); |
| 771 | 772 | ||
| 772 | /* Setup the guest args page (so it gets the args). */ | 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 | memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); | 775 | memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); |
| 775 | vcpu_args_set(vcpu, 1, args_gva); | 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 | gic_set_priority_mask(CPU_PRIO_MASK); | 811 | gic_set_priority_mask(CPU_PRIO_MASK); |
| 811 | 812 | ||
| 812 | if (cpuid == 0) { | 813 | if (cpuid == 0) { |
| 813 | uint32_t intid; | 814 | u32 intid; |
| 814 | 815 | ||
| 815 | local_irq_disable(); | 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 | static void guest_code_group_en(struct test_args *args, int cpuid) | 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 | gic_init(GIC_V3, 2); | 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 | static void guest_code_timer_spi(struct test_args *args, int cpuid) | 898 | static void guest_code_timer_spi(struct test_args *args, int cpuid) |
| 898 | { | 899 | { |
| 899 | uint32_t intid; | 900 | u32 intid; |
| 900 | u64 val; | 901 | u64 val; |
| 901 | 902 | ||
| 902 | gic_init(GIC_V3, 2); | 903 | gic_init(GIC_V3, 2); |
| @@ -986,7 +987,7 @@ static void test_vgic_two_cpus(void *gcode) · 83 unmodified lines | |||
| 986 | struct kvm_vcpu *vcpus[2]; | 987 | struct kvm_vcpu *vcpus[2]; |
| 987 | struct test_args args = {}; | 988 | struct test_args args = {}; |
| 988 | struct kvm_vm *vm; | 989 | struct kvm_vm *vm; |
| 989 | vm_vaddr_t args_gva; | 990 | gva_t args_gva; |
| 990 | int gic_fd, ret; | 991 | int gic_fd, ret; |
| 991 | 992 | ||
| 992 | vm = vm_create_with_vcpus(2, gcode, vcpus); | 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 | vcpu_init_descriptor_tables(vcpus[1]); | 997 | vcpu_init_descriptor_tables(vcpus[1]); |
| 997 | 998 | ||
| 998 | /* Setup the guest args page (so it gets the args). */ | 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 | memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); | 1001 | memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); |
| 1001 | vcpu_args_set(vcpus[0], 2, args_gva, 0); | 1002 | vcpu_args_set(vcpus[0], 2, args_gva, 0); |
| 1002 | vcpu_args_set(vcpus[1], 2, args_gva, 1); | 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 | int main(int argc, char **argv) | 1035 | int main(int argc, char **argv) |
| 1035 | { | 1036 | { |
| 1036 | uint32_t nr_irqs = 64; | 1037 | u32 nr_irqs = 64; |
| 1037 | bool default_args = true; | 1038 | bool default_args = true; |
| 1038 | bool level_sensitive = false; | 1039 | bool level_sensitive = false; |
| 1039 | int opt; | 1040 | int opt; |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | #define GIC_LPI_OFFSET 8192 | 23 | #define GIC_LPI_OFFSET 8192 |
| 24 | 24 | ||
| 25 | static size_t nr_iterations = 1000; | 25 | static size_t nr_iterations = 1000; |
| 26 | static vm_paddr_t gpa_base; | 26 | static gpa_t gpa_base; |
| 27 | 27 | ||
| 28 | static struct kvm_vm *vm; | 28 | static struct kvm_vm *vm; |
| 29 | static struct kvm_vcpu **vcpus; | 29 | static struct kvm_vcpu **vcpus; |
| @@ -35,14 +35,14 @@ static struct test_data { · 5 unmodified lines | |||
| 35 | u32 nr_devices; | 35 | u32 nr_devices; |
| 36 | u32 nr_event_ids; | 36 | u32 nr_event_ids; |
| 37 | 37 | ||
| 38 | vm_paddr_t device_table; | 38 | gpa_t device_table; |
| 39 | vm_paddr_t collection_table; | 39 | gpa_t collection_table; |
| 40 | vm_paddr_t cmdq_base; | 40 | gpa_t cmdq_base; |
| 41 | void *cmdq_base_va; | 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; | 44 | gpa_t lpi_prop_table; |
| 45 | vm_paddr_t lpi_pend_tables; | 45 | gpa_t lpi_pend_tables; |
| 46 | } test_data = { | 46 | } test_data = { |
| 47 | .nr_cpus = 1, | 47 | .nr_cpus = 1, |
| 48 | .nr_devices = 1, | 48 | .nr_devices = 1, |
| @@ -73,7 +73,7 @@ static void guest_setup_its_mappings(void) · 24 unmodified lines | |||
| 73 | /* Round-robin the LPIs to all of the vCPUs in the VM */ | 73 | /* Round-robin the LPIs to all of the vCPUs in the VM */ |
| 74 | coll_id = 0; | 74 | coll_id = 0; |
| 75 | for (device_id = 0; device_id < nr_devices; device_id++) { | 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 | its_send_mapd_cmd(test_data.cmdq_base_va, device_id, | 78 | its_send_mapd_cmd(test_data.cmdq_base_va, device_id, |
| 79 | itt_base, SZ_64K, true); | 79 | itt_base, SZ_64K, true); |
| @@ -188,7 +188,7 @@ static void setup_test_data(void) · 108 unmodified lines | |||
| 188 | size_t pages_per_64k = vm_calc_num_guest_pages(vm->mode, SZ_64K); | 188 | size_t pages_per_64k = vm_calc_num_guest_pages(vm->mode, SZ_64K); |
| 189 | u32 nr_devices = test_data.nr_devices; | 189 | u32 nr_devices = test_data.nr_devices; |
| 190 | u32 nr_cpus = test_data.nr_cpus; | 190 | u32 nr_cpus = test_data.nr_cpus; |
| 191 | vm_paddr_t cmdq_base; | 191 | gpa_t cmdq_base; |
| 192 | 192 | ||
| 193 | test_data.device_table = vm_phy_pages_alloc(vm, pages_per_64k, | 193 | test_data.device_table = vm_phy_pages_alloc(vm, pages_per_64k, |
| 194 | gpa_base, | 194 | gpa_base, |
| @@ -224,7 +224,7 @@ static void setup_gic(void) · 29 unmodified lines | |||
| 224 | 224 | ||
| 225 | static void signal_lpi(u32 device_id, u32 event_id) | 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 | struct kvm_msi msi = { | 229 | struct kvm_msi msi = { |
| 230 | .address_lo = db_addr, | 230 | .address_lo = db_addr, |
| @@ -17,10 +17,10 @@ · 16 unmodified lines | |||
| 17 | struct vm_gic { | 17 | struct vm_gic { |
| 18 | struct kvm_vm *vm; | 18 | struct kvm_vm *vm; |
| 19 | int gic_fd; | 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 | #define GUEST_CMD_IRQ_CDIA 10 | 25 | #define GUEST_CMD_IRQ_CDIA 10 |
| 26 | #define GUEST_CMD_IRQ_DIEOI 11 | 26 | #define GUEST_CMD_IRQ_DIEOI 11 |
| @@ -96,7 +96,7 @@ static void vm_gic_destroy(struct vm_gic *v) · 69 unmodified lines | |||
| 96 | kvm_vm_free(v->vm); | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 101 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 102 | struct ucall uc; | 102 | struct ucall uc; |
| @@ -173,7 +173,7 @@ done: · 70 unmodified lines | |||
| 173 | /* | 173 | /* |
| 174 | * Returns 0 if it's possible to create GIC device of a given type (V5). | 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 | struct kvm_vcpu *vcpus[NR_VCPUS]; | 178 | struct kvm_vcpu *vcpus[NR_VCPUS]; |
| 179 | struct vm_gic v; | 179 | struct vm_gic v; |
| @@ -199,7 +199,7 @@ int test_kvm_device(uint32_t gic_dev_type) · 19 unmodified lines | |||
| 199 | return 0; | 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 | pr_info("Test VGICv5 PPIs\n"); | 204 | pr_info("Test VGICv5 PPIs\n"); |
| 205 | test_vgic_v5_ppis(gic_dev_type); | 205 | test_vgic_v5_ppis(gic_dev_type); |
| @@ -33,20 +33,20 @@ struct vpmu_vm { · 32 unmodified lines | |||
| 33 | static struct vpmu_vm vpmu_vm; | 33 | static struct vpmu_vm vpmu_vm; |
| 34 | 34 | ||
| 35 | struct pmreg_sets { | 35 | struct pmreg_sets { |
| 36 | uint64_t set_reg_id; | 36 | u64 set_reg_id; |
| 37 | uint64_t clr_reg_id; | 37 | u64 clr_reg_id; |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | #define PMREG_SET(set, clr) {.set_reg_id = set, .clr_reg_id = clr} | 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 | return FIELD_GET(ARMV8_PMU_PMCR_N, pmcr); | 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 | if (n) | 51 | if (n) |
| 52 | mask |= GENMASK(n - 1, 0); | 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 | static void pmu_disable_reset(void) | 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 | /* Reset all counters, disabling them */ | 94 | /* Reset all counters, disabling them */ |
| 95 | pmcr &= ~ARMV8_PMU_PMCR_E; | 95 | pmcr &= ~ARMV8_PMU_PMCR_E; |
| @@ -169,7 +169,7 @@ struct pmc_accessor pmc_accessors[] = { · 73 unmodified lines | |||
| 169 | 169 | ||
| 170 | #define GUEST_ASSERT_BITMAP_REG(regname, mask, set_expected) \ | 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 | if (set_expected) \ | 174 | if (set_expected) \ |
| 175 | __GUEST_ASSERT((_tval & mask), \ | 175 | __GUEST_ASSERT((_tval & mask), \ |
| @@ -185,7 +185,7 @@ struct pmc_accessor pmc_accessors[] = { · 9 unmodified lines | |||
| 185 | * Check if @mask bits in {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers | 185 | * Check if @mask bits in {PMCNTEN,PMINTEN,PMOVS}{SET,CLR} registers |
| 186 | * are set or cleared as specified in @set_expected. | 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 | GUEST_ASSERT_BITMAP_REG(pmcntenset_el0, mask, set_expected); | 190 | GUEST_ASSERT_BITMAP_REG(pmcntenset_el0, mask, set_expected); |
| 191 | GUEST_ASSERT_BITMAP_REG(pmcntenclr_el0, mask, set_expected); | 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 | static void test_bitmap_pmu_regs(int pmc_idx, bool set_op) | 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 | bool set_expected = false; | 211 | bool set_expected = false; |
| 212 | 212 | ||
| 213 | if (set_op) { | 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 | static void test_access_pmc_regs(struct pmc_accessor *acc, int pmc_idx) | 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 | /* Disable all PMCs and reset all PMCs to zero. */ | 237 | /* Disable all PMCs and reset all PMCs to zero. */ |
| 238 | pmu_disable_reset(); | 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 | #define INVALID_EC (-1ul) | 289 | #define INVALID_EC (-1ul) |
| 290 | uint64_t expected_ec = INVALID_EC; | 290 | u64 expected_ec = INVALID_EC; |
| 291 | 291 | ||
| 292 | static void guest_sync_handler(struct ex_regs *regs) | 292 | static void guest_sync_handler(struct ex_regs *regs) |
| 293 | { | 293 | { |
| 294 | uint64_t esr, ec; | 294 | u64 esr, ec; |
| 295 | 295 | ||
| 296 | esr = read_sysreg(esr_el1); | 296 | esr = read_sysreg(esr_el1); |
| 297 | ec = ESR_ELx_EC(esr); | 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 | * if reading/writing PMU registers for implemented or unimplemented | 351 | * if reading/writing PMU registers for implemented or unimplemented |
| 352 | * counters works as expected. | 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 | int i, pmc; | 357 | int i, pmc; |
| 358 | 358 | ||
| 359 | __GUEST_ASSERT(expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS, | 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 | static void create_vpmu_vm(void *guest_code) | 402 | static void create_vpmu_vm(void *guest_code) |
| 403 | { | 403 | { |
| 404 | struct kvm_vcpu_init init; | 404 | struct kvm_vcpu_init init; |
| 405 | uint8_t pmuver, ec; | 405 | u8 pmuver, ec; |
| 406 | uint64_t dfr0, irq = 23; | 406 | u64 dfr0, irq = 23; |
| 407 | struct kvm_device_attr irq_attr = { | 407 | struct kvm_device_attr irq_attr = { |
| 408 | .group = KVM_ARM_VCPU_PMU_V3_CTRL, | 408 | .group = KVM_ARM_VCPU_PMU_V3_CTRL, |
| 409 | .attr = KVM_ARM_VCPU_PMU_V3_IRQ, | 409 | .attr = KVM_ARM_VCPU_PMU_V3_IRQ, |
| 410 | .addr = (uint64_t)&irq, | 410 | .addr = (u64)&irq, |
| 411 | }; | 411 | }; |
| 412 | 412 | ||
| 413 | /* The test creates the vpmu_vm multiple times. Ensure a clean state */ | 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 | kvm_vm_free(vpmu_vm.vm); | 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 | struct ucall uc; | 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 | * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n, | 489 | * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n, |
| 490 | * and run the test. | 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 | struct kvm_vcpu *vcpu; | 495 | struct kvm_vcpu *vcpu; |
| 496 | struct kvm_vcpu_init init; | 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 | aarch64_vcpu_setup(vcpu, &init); | 514 | aarch64_vcpu_setup(vcpu, &init); |
| 515 | vcpu_init_descriptor_tables(vcpu); | 515 | vcpu_init_descriptor_tables(vcpu); |
| 516 | vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1), sp); | 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 | run_vcpu(vcpu, pmcr_n); | 519 | run_vcpu(vcpu, pmcr_n); |
| 520 | 520 | ||
| @@ -531,12 +531,12 @@ static struct pmreg_sets validity_check_reg_sets[] = { · 10 unmodified lines | |||
| 531 | * Create a VM, and check if KVM handles the userspace accesses of | 531 | * Create a VM, and check if KVM handles the userspace accesses of |
| 532 | * the PMU register sets in @validity_check_reg_sets[] correctly. | 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 | int i; | 536 | int i; |
| 537 | struct kvm_vcpu *vcpu; | 537 | struct kvm_vcpu *vcpu; |
| 538 | uint64_t set_reg_id, clr_reg_id, reg_val; | 538 | u64 set_reg_id, clr_reg_id, reg_val; |
| 539 | uint64_t valid_counters_mask, max_counters_mask; | 539 | u64 valid_counters_mask, max_counters_mask; |
| 540 | 540 | ||
| 541 | test_create_vpmu_vm_with_nr_counters(pmcr_n, false); | 541 | test_create_vpmu_vm_with_nr_counters(pmcr_n, false); |
| 542 | vcpu = vpmu_vm.vcpu; | 542 | vcpu = vpmu_vm.vcpu; |
| @@ -588,7 +588,7 @@ static void run_pmregs_validity_test(uint64_t pmcr_n) · 45 unmodified lines | |||
| 588 | * the vCPU to @pmcr_n, which is larger than the host value. | 588 | * the vCPU to @pmcr_n, which is larger than the host value. |
| 589 | * The attempt should fail as @pmcr_n is too big to set for the vCPU. | 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 | pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n); | 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 | * Return the default number of implemented PMU event counters excluding | 600 | * Return the default number of implemented PMU event counters excluding |
| 601 | * the cycle counter (i.e. PMCR_EL0.N value) for the guest. | 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 | create_vpmu_vm(guest_code); | 607 | create_vpmu_vm(guest_code); |
| 608 | pmcr = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)); | 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 | int main(void) | 625 | int main(void) |
| 626 | { | 626 | { |
| 627 | uint64_t i, pmcr_n; | 627 | u64 i, pmcr_n; |
| 628 | 628 | ||
| 629 | TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); | 629 | TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); |
| 630 | TEST_REQUIRE(kvm_supports_vgic_v3()); | 630 | TEST_REQUIRE(kvm_supports_vgic_v3()); |
| @@ -14,16 +14,16 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | struct kvm_coalesced_io { | 15 | struct kvm_coalesced_io { |
| 16 | struct kvm_coalesced_mmio_ring *ring; | 16 | struct kvm_coalesced_mmio_ring *ring; |
| 17 | uint32_t ring_size; | 17 | u32 ring_size; |
| 18 | uint64_t mmio_gpa; | 18 | u64 mmio_gpa; |
| 19 | uint64_t *mmio; | 19 | u64 *mmio; |
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * x86-only, but define pio_port for all architectures to minimize the | 22 | * x86-only, but define pio_port for all architectures to minimize the |
| 23 | * amount of #ifdeffery and complexity, without having to sacrifice | 23 | * amount of #ifdeffery and complexity, without having to sacrifice |
| 24 | * verbose error messages. | 24 | * verbose error messages. |
| 25 | */ | 25 | */ |
| 26 | uint8_t pio_port; | 26 | u8 pio_port; |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | static struct kvm_coalesced_io kvm_builtin_io_ring; | 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 | static void vcpu_run_and_verify_io_exit(struct kvm_vcpu *vcpu, | 71 | static void vcpu_run_and_verify_io_exit(struct kvm_vcpu *vcpu, |
| 72 | struct kvm_coalesced_io *io, | 72 | struct kvm_coalesced_io *io, |
| 73 | uint32_t ring_start, | 73 | u32 ring_start, |
| 74 | uint32_t expected_exit) | 74 | u32 expected_exit) |
| 75 | { | 75 | { |
| 76 | const bool want_pio = expected_exit == KVM_EXIT_IO; | 76 | const bool want_pio = expected_exit == KVM_EXIT_IO; |
| 77 | struct kvm_coalesced_mmio_ring *ring = io->ring; | 77 | struct kvm_coalesced_mmio_ring *ring = io->ring; |
| 78 | struct kvm_run *run = vcpu->run; | 78 | struct kvm_run *run = vcpu->run; |
| 79 | uint32_t pio_value; | 79 | u32 pio_value; |
| 80 | 80 | ||
| 81 | WRITE_ONCE(ring->first, ring_start); | 81 | WRITE_ONCE(ring->first, ring_start); |
| 82 | WRITE_ONCE(ring->last, ring_start); | 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 | * data_offset is garbage, e.g. an MMIO gpa. | 88 | * data_offset is garbage, e.g. an MMIO gpa. |
| 89 | */ | 89 | */ |
| 90 | if (run->exit_reason == KVM_EXIT_IO) | 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 | else | 92 | else |
| 93 | pio_value = 0; | 93 | pio_value = 0; |
| 94 | 94 | ||
| 95 | TEST_ASSERT((!want_pio && (run->exit_reason == KVM_EXIT_MMIO && run->mmio.is_write && | 95 | TEST_ASSERT((!want_pio && (run->exit_reason == KVM_EXIT_MMIO && run->mmio.is_write && |
| 96 | run->mmio.phys_addr == io->mmio_gpa && run->mmio.len == 8 && | 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 | (want_pio && (run->exit_reason == KVM_EXIT_IO && run->io.port == io->pio_port && | 98 | (want_pio && (run->exit_reason == KVM_EXIT_IO && run->io.port == io->pio_port && |
| 99 | run->io.direction == KVM_EXIT_IO_OUT && run->io.count == 1 && | 99 | run->io.direction == KVM_EXIT_IO_OUT && run->io.count == 1 && |
| 100 | pio_value == io->pio_port + io->ring_size - 1)), | 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 | want_pio ? (unsigned long long)io->pio_port : io->mmio_gpa, | 105 | want_pio ? (unsigned long long)io->pio_port : io->mmio_gpa, |
| 106 | (want_pio ? io->pio_port : io->mmio_gpa) + io->ring_size - 1, run->exit_reason, | 106 | (want_pio ? io->pio_port : io->mmio_gpa) + io->ring_size - 1, run->exit_reason, |
| 107 | run->exit_reason == KVM_EXIT_MMIO ? "MMIO" : run->exit_reason == KVM_EXIT_IO ? "PIO" : "other", | 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 | run->io.port, run->io.direction, run->io.size, run->io.count, pio_value); | 109 | run->io.port, run->io.direction, run->io.size, run->io.count, pio_value); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu, | 112 | static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu, |
| 113 | struct kvm_coalesced_io *io, | 113 | struct kvm_coalesced_io *io, |
| 114 | uint32_t ring_start, | 114 | u32 ring_start, |
| 115 | uint32_t expected_exit) | 115 | u32 expected_exit) |
| 116 | { | 116 | { |
| 117 | struct kvm_coalesced_mmio_ring *ring = io->ring; | 117 | struct kvm_coalesced_mmio_ring *ring = io->ring; |
| 118 | int i; | 118 | int i; |
| @@ -124,18 +124,18 @@ static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu, · 5 unmodified lines | |||
| 124 | ring->first, ring->last, io->ring_size, ring_start); | 124 | ring->first, ring->last, io->ring_size, ring_start); |
| 125 | 125 | ||
| 126 | for (i = 0; i < io->ring_size - 1; i++) { | 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 | struct kvm_coalesced_mmio *entry = &ring->coalesced_mmio[idx]; | 128 | struct kvm_coalesced_mmio *entry = &ring->coalesced_mmio[idx]; |
| 129 | 129 | ||
| 130 | #ifdef __x86_64__ | 130 | #ifdef __x86_64__ |
| 131 | if (i & 1) | 131 | if (i & 1) |
| 132 | TEST_ASSERT(entry->phys_addr == io->pio_port && | 132 | TEST_ASSERT(entry->phys_addr == io->pio_port && |
| 133 | entry->len == 4 && entry->pio && | 133 | entry->len == 4 && entry->pio && |
| 134 | *(uint32_t *)entry->data == io->pio_port + i, | 134 | *(u32 *)entry->data == io->pio_port + i, |
| 135 | "Wanted 4-byte port I/O 0x%x = 0x%x in entry %u, got %u-byte %s 0x%llx = 0x%x", | 135 | "Wanted 4-byte port I/O 0x%x = 0x%x in entry %u, got %u-byte %s 0x%llx = 0x%x", |
| 136 | io->pio_port, io->pio_port + i, i, | 136 | io->pio_port, io->pio_port + i, i, |
| 137 | entry->len, entry->pio ? "PIO" : "MMIO", | 137 | entry->len, entry->pio ? "PIO" : "MMIO", |
| 138 | entry->phys_addr, *(uint32_t *)entry->data); | 138 | entry->phys_addr, *(u32 *)entry->data); |
| 139 | else | 139 | else |
| 140 | #endif | 140 | #endif |
| 141 | TEST_ASSERT(entry->phys_addr == io->mmio_gpa && | 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 | "Wanted 8-byte MMIO to 0x%lx = %lx in entry %u, got %u-byte %s 0x%llx = 0x%lx", | 143 | "Wanted 8-byte MMIO to 0x%lx = %lx in entry %u, got %u-byte %s 0x%llx = 0x%lx", |
| 144 | io->mmio_gpa, io->mmio_gpa + i, i, | 144 | io->mmio_gpa, io->mmio_gpa + i, i, |
| 145 | entry->len, entry->pio ? "PIO" : "MMIO", | 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 | static void test_coalesced_io(struct kvm_vcpu *vcpu, | 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 | struct kvm_coalesced_mmio_ring *ring = io->ring; | 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 | * the MMIO GPA identity mapped in the guest. | 219 | * the MMIO GPA identity mapped in the guest. |
| 220 | */ | 220 | */ |
| 221 | .mmio_gpa = 4ull * SZ_1G, | 221 | .mmio_gpa = 4ull * SZ_1G, |
| 222 | .mmio = (uint64_t *)(4ull * SZ_1G), | 222 | .mmio = (u64 *)(4ull * SZ_1G), |
| 223 | .pio_port = 0x80, | 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 | sync_global_to_guest(vm, kvm_builtin_io_ring); | 228 | sync_global_to_guest(vm, kvm_builtin_io_ring); |
| 229 | vcpu_args_set(vcpu, 1, &kvm_builtin_io_ring); | 229 | vcpu_args_set(vcpu, 1, &kvm_builtin_io_ring); |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | |||
| 24 | #ifdef __NR_userfaultfd | 24 | #ifdef __NR_userfaultfd |
| 25 | 25 | ||
| 26 | static int nr_vcpus = 1; | 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 | static size_t demand_paging_size; | 29 | static size_t demand_paging_size; |
| 30 | static char *guest_data_prototype; | 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 | struct uffd_msg *msg) | 58 | struct uffd_msg *msg) |
| 59 | { | 59 | { |
| 60 | pid_t tid = syscall(__NR_gettid); | 60 | pid_t tid = syscall(__NR_gettid); |
| 61 | uint64_t addr = msg->arg.pagefault.address; | 61 | u64 addr = msg->arg.pagefault.address; |
| 62 | struct timespec start; | 62 | struct timespec start; |
| 63 | struct timespec ts_diff; | 63 | struct timespec ts_diff; |
| 64 | int r; | 64 | int r; |
| @@ -68,7 +68,7 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, · 3 unmodified lines | |||
| 68 | if (uffd_mode == UFFDIO_REGISTER_MODE_MISSING) { | 68 | if (uffd_mode == UFFDIO_REGISTER_MODE_MISSING) { |
| 69 | struct uffdio_copy copy; | 69 | struct uffdio_copy copy; |
| 70 | 70 | ||
| 71 | copy.src = (uint64_t)guest_data_prototype; | 71 | copy.src = (u64)guest_data_prototype; |
| 72 | copy.dst = addr; | 72 | copy.dst = addr; |
| 73 | copy.len = demand_paging_size; | 73 | copy.len = demand_paging_size; |
| 74 | copy.mode = 0; | 74 | copy.mode = 0; |
| @@ -138,7 +138,7 @@ struct test_params { · 63 unmodified lines | |||
| 138 | bool partition_vcpu_memory_access; | 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 | size_t p; | 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 | struct memstress_vcpu_args *vcpu_args; | 154 | struct memstress_vcpu_args *vcpu_args; |
| 155 | struct test_params *p = arg; | 155 | struct test_params *p = arg; |
| 156 | struct uffd_desc **uffd_descs = NULL; | 156 | struct uffd_desc **uffd_descs = NULL; |
| 157 | uint64_t uffd_region_size; | 157 | u64 uffd_region_size; |
| 158 | struct timespec start; | 158 | struct timespec start; |
| 159 | struct timespec ts_diff; | 159 | struct timespec ts_diff; |
| 160 | double vcpu_paging_rate; | 160 | double vcpu_paging_rate; |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | |||
| 24 | #define TEST_HOST_LOOP_N 2UL | 24 | #define TEST_HOST_LOOP_N 2UL |
| 25 | 25 | ||
| 26 | static int nr_vcpus = 1; | 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 | static bool run_vcpus_while_disabling_dirty_logging; | 28 | static bool run_vcpus_while_disabling_dirty_logging; |
| 29 | 29 | ||
| 30 | /* Host variables */ | 30 | /* Host variables */ |
| @@ -37,7 +37,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) · 6 unmodified lines | |||
| 37 | { | 37 | { |
| 38 | struct kvm_vcpu *vcpu = vcpu_args->vcpu; | 38 | struct kvm_vcpu *vcpu = vcpu_args->vcpu; |
| 39 | int vcpu_idx = vcpu_args->vcpu_idx; | 39 | int vcpu_idx = vcpu_args->vcpu_idx; |
| 40 | uint64_t pages_count = 0; | 40 | u64 pages_count = 0; |
| 41 | struct kvm_run *run; | 41 | struct kvm_run *run; |
| 42 | struct timespec start; | 42 | struct timespec start; |
| 43 | struct timespec ts_diff; | 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 | struct test_params { | 94 | struct test_params { |
| 95 | unsigned long iterations; | 95 | unsigned long iterations; |
| 96 | uint64_t phys_offset; | 96 | u64 phys_offset; |
| 97 | bool partition_vcpu_memory_access; | 97 | bool partition_vcpu_memory_access; |
| 98 | enum vm_mem_backing_src_type backing_src; | 98 | enum vm_mem_backing_src_type backing_src; |
| 99 | int slots; | 99 | int slots; |
| 100 | uint32_t write_percent; | 100 | u32 write_percent; |
| 101 | bool random_access; | 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 | struct test_params *p = arg; | 106 | struct test_params *p = arg; |
| 107 | struct kvm_vm *vm; | 107 | struct kvm_vm *vm; |
| 108 | unsigned long **bitmaps; | 108 | unsigned long **bitmaps; |
| 109 | uint64_t guest_num_pages; | 109 | u64 guest_num_pages; |
| 110 | uint64_t host_num_pages; | 110 | u64 host_num_pages; |
| 111 | uint64_t pages_per_slot; | 111 | u64 pages_per_slot; |
| 112 | struct timespec start; | 112 | struct timespec start; |
| 113 | struct timespec ts_diff; | 113 | struct timespec ts_diff; |
| 114 | struct timespec get_dirty_log_total = (struct timespec){0}; | 114 | struct timespec get_dirty_log_total = (struct timespec){0}; |
| @@ -74,11 +74,11 @@ · 73 unmodified lines | |||
| 74 | * the host. READ/WRITE_ONCE() should also be used with anything | 74 | * the host. READ/WRITE_ONCE() should also be used with anything |
| 75 | * that may change. | 75 | * that may change. |
| 76 | */ | 76 | */ |
| 77 | static uint64_t host_page_size; | 77 | static u64 host_page_size; |
| 78 | static uint64_t guest_page_size; | 78 | static u64 guest_page_size; |
| 79 | static uint64_t guest_num_pages; | 79 | static u64 guest_num_pages; |
| 80 | static uint64_t iteration; | 80 | static u64 iteration; |
| 81 | static uint64_t nr_writes; | 81 | static u64 nr_writes; |
| 82 | static bool vcpu_stop; | 82 | static bool vcpu_stop; |
| 83 | 83 | ||
| 84 | /* | 84 | /* |
| @@ -86,13 +86,13 @@ static bool vcpu_stop; · 1 unmodified line | |||
| 86 | * This will be set to the topmost valid physical address minus | 86 | * This will be set to the topmost valid physical address minus |
| 87 | * the test memory size. | 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 | * Guest virtual memory offset of the testing memory slot. | 92 | * Guest virtual memory offset of the testing memory slot. |
| 93 | * Must not conflict with identity mapped test code. | 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 | * Continuously write to the first 8 bytes of a random pages within | 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 | static void guest_code(void) | 101 | static void guest_code(void) |
| 102 | { | 102 | { |
| 103 | uint64_t addr; | 103 | u64 addr; |
| 104 | 104 | ||
| 105 | #ifdef __s390x__ | 105 | #ifdef __s390x__ |
| 106 | uint64_t i; | 106 | u64 i; |
| 107 | 107 | ||
| 108 | /* | 108 | /* |
| 109 | * On s390x, all pages of a 1M segment are initially marked as dirty | 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 | for (i = 0; i < guest_num_pages; i++) { | 114 | for (i = 0; i < guest_num_pages; i++) { |
| 115 | addr = guest_test_virt_mem + i * guest_page_size; | 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 | nr_writes++; | 117 | nr_writes++; |
| 118 | } | 118 | } |
| 119 | #endif | 119 | #endif |
| @@ -125,7 +125,7 @@ static void guest_code(void) · 5 unmodified lines | |||
| 125 | * guest_page_size; | 125 | * guest_page_size; |
| 126 | addr = align_down(addr, host_page_size); | 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 | nr_writes++; | 129 | nr_writes++; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| @@ -138,11 +138,11 @@ static bool host_quit; · 6 unmodified lines | |||
| 138 | 138 | ||
| 139 | /* Points to the test VM memory region on which we track dirty logs */ | 139 | /* Points to the test VM memory region on which we track dirty logs */ |
| 140 | static void *host_test_mem; | 140 | static void *host_test_mem; |
| 141 | static uint64_t host_num_pages; | 141 | static u64 host_num_pages; |
| 142 | 142 | ||
| 143 | /* For statistics only */ | 143 | /* For statistics only */ |
| 144 | static uint64_t host_dirty_count; | 144 | static u64 host_dirty_count; |
| 145 | static uint64_t host_clear_count; | 145 | static u64 host_clear_count; |
| 146 | 146 | ||
| 147 | /* Whether dirty ring reset is requested, or finished */ | 147 | /* Whether dirty ring reset is requested, or finished */ |
| 148 | static sem_t sem_vcpu_stop; | 148 | static sem_t sem_vcpu_stop; |
| @@ -169,7 +169,7 @@ static bool dirty_ring_vcpu_ring_full; · 20 unmodified lines | |||
| 169 | * dirty gfn we've collected, so that if a mismatch of data found later in the | 169 | * dirty gfn we've collected, so that if a mismatch of data found later in the |
| 170 | * verifying process, we let it pass. | 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 | * In addition to the above, it is possible (especially if this | 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 | * and also don't fail when it is reported in the next iteration, together with | 213 | * and also don't fail when it is reported in the next iteration, together with |
| 214 | * an outdated iteration count. | 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 | enum log_mode_t { | 218 | enum log_mode_t { |
| 219 | /* Only use KVM_GET_DIRTY_LOG for logging */ | 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 | /* Logging mode for current run */ | 236 | /* Logging mode for current run */ |
| 237 | static enum log_mode_t host_log_mode; | 237 | static enum log_mode_t host_log_mode; |
| 238 | static pthread_t vcpu_thread; | 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 | static bool clear_log_supported(void) | 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 | static void dirty_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, | 257 | static void dirty_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, |
| 258 | void *bitmap, uint32_t num_pages, | 258 | void *bitmap, u32 num_pages, |
| 259 | uint32_t *unused) | 259 | u32 *unused) |
| 260 | { | 260 | { |
| 261 | kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); | 261 | kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | static void clear_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, | 264 | static void clear_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, |
| 265 | void *bitmap, uint32_t num_pages, | 265 | void *bitmap, u32 num_pages, |
| 266 | uint32_t *unused) | 266 | u32 *unused) |
| 267 | { | 267 | { |
| 268 | kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); | 268 | kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); |
| 269 | kvm_vm_clear_dirty_log(vcpu->vm, slot, bitmap, 0, num_pages); | 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 | static void dirty_ring_create_vm_done(struct kvm_vm *vm) | 298 | static void dirty_ring_create_vm_done(struct kvm_vm *vm) |
| 299 | { | 299 | { |
| 300 | uint64_t pages; | 300 | u64 pages; |
| 301 | uint32_t limit; | 301 | u32 limit; |
| 302 | 302 | ||
| 303 | /* | 303 | /* |
| 304 | * We rely on vcpu exit due to full dirty ring state. Adjust | 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 | smp_store_release(&gfn->flags, KVM_DIRTY_GFN_F_RESET); | 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, | 336 | static u32 dirty_ring_collect_one(struct kvm_dirty_gfn *dirty_gfns, |
| 337 | int slot, void *bitmap, | 337 | int slot, void *bitmap, |
| 338 | uint32_t num_pages, uint32_t *fetch_index) | 338 | u32 num_pages, u32 *fetch_index) |
| 339 | { | 339 | { |
| 340 | struct kvm_dirty_gfn *cur; | 340 | struct kvm_dirty_gfn *cur; |
| 341 | uint32_t count = 0; | 341 | u32 count = 0; |
| 342 | 342 | ||
| 343 | while (true) { | 343 | while (true) { |
| 344 | cur = &dirty_gfns[*fetch_index % test_dirty_ring_count]; | 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 | static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, | 361 | static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, |
| 362 | void *bitmap, uint32_t num_pages, | 362 | void *bitmap, u32 num_pages, |
| 363 | uint32_t *ring_buf_idx) | 363 | u32 *ring_buf_idx) |
| 364 | { | 364 | { |
| 365 | uint32_t count, cleared; | 365 | u32 count, cleared; |
| 366 | 366 | ||
| 367 | /* Only have one vcpu */ | 367 | /* Only have one vcpu */ |
| 368 | count = dirty_ring_collect_one(vcpu_map_dirty_ring(vcpu), | 368 | count = dirty_ring_collect_one(vcpu_map_dirty_ring(vcpu), |
| @@ -404,8 +404,8 @@ struct log_mode { · 35 unmodified lines | |||
| 404 | void (*create_vm_done)(struct kvm_vm *vm); | 404 | void (*create_vm_done)(struct kvm_vm *vm); |
| 405 | /* Hook to collect the dirty pages into the bitmap provided */ | 405 | /* Hook to collect the dirty pages into the bitmap provided */ |
| 406 | void (*collect_dirty_pages) (struct kvm_vcpu *vcpu, int slot, | 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.