From 5239a89b06d6b199f133bf0ffea421683187f257 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 8 Mar 2023 20:40:43 +0000 Subject: [PATCH 001/182] pstore: Revert pmsg_lock back to a normal mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 76d62f24db07f22ccf9bc18ca793c27d4ebef721. So while priority inversion on the pmsg_lock is an occasional problem that an rt_mutex would help with, in uses where logging is writing to pmsg heavily from multiple threads, the pmsg_lock can be heavily contended. After this change landed, it was reported that cases where the mutex locking overhead was commonly adding on the order of 10s of usecs delay had suddenly jumped to ~msec delay with rtmutex. It seems the slight differences in the locks under this level of contention causes the normal mutexes to utilize the spinning optimizations, while the rtmutexes end up in the sleeping slowpath (which allows additional threads to pile on trying to take the lock). In this case, it devolves to a worse case senerio where the lock acquisition and scheduling overhead dominates, and each thread is waiting on the order of ~ms to do ~us of work. Obviously, having tons of threads all contending on a single lock for logging is non-optimal, so the proper fix is probably reworking pstore pmsg to have per-cpu buffers so we don't have contention. Additionally, Steven Rostedt has provided some furhter optimizations for rtmutexes that improves the rtmutex spinning path, but at least in my testing, I still see the test tripping into the sleeping path on rtmutexes while utilizing the spinning path with mutexes. But in the short term, lets revert the change to the rt_mutex and go back to normal mutexes to avoid a potentially major performance regression. And we can work on optimizations to both rtmutexes and finer-grained locking for pstore pmsg in the future. Cc: Wei Wang Cc: Midas Chien Cc: "Chunhui Li (李春辉)" Cc: Steven Rostedt Cc: Kees Cook Cc: Anton Vorontsov Cc: "Guilherme G. Piccoli" Cc: Tony Luck Cc: kernel-team@android.com Fixes: 76d62f24db07 ("pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion") Reported-by: "Chunhui Li (李春辉)" Signed-off-by: John Stultz Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230308204043.2061631-1-jstultz@google.com --- fs/pstore/pmsg.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c index ab82e5f05346..b31c9c72d90b 100644 --- a/fs/pstore/pmsg.c +++ b/fs/pstore/pmsg.c @@ -7,10 +7,9 @@ #include #include #include -#include #include "internal.h" -static DEFINE_RT_MUTEX(pmsg_lock); +static DEFINE_MUTEX(pmsg_lock); static ssize_t write_pmsg(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -29,9 +28,9 @@ static ssize_t write_pmsg(struct file *file, const char __user *buf, if (!access_ok(buf, count)) return -EFAULT; - rt_mutex_lock(&pmsg_lock); + mutex_lock(&pmsg_lock); ret = psinfo->write_user(&record, buf); - rt_mutex_unlock(&pmsg_lock); + mutex_unlock(&pmsg_lock); return ret ? ret : count; } From f7ca74904dab2f9157fb17463b4fcaf641cc370d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 27 Feb 2023 09:09:11 +0100 Subject: [PATCH 002/182] MIPS: BCM47XX: Add support for Huawei B593u-12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a BCM5358 based home router. One of very few bcm47xx devices with cellular modems (here: LTE). Signed-off-by: Rafał Miłecki Reviewed-by: Florian Fainelli Signed-off-by: Thomas Bogendoerfer --- arch/mips/bcm47xx/board.c | 1 + arch/mips/bcm47xx/leds.c | 8 ++++++++ arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h | 1 + 3 files changed, 10 insertions(+) diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c index 90fb48b046c0..b487f687f62d 100644 --- a/arch/mips/bcm47xx/board.c +++ b/arch/mips/bcm47xx/board.c @@ -193,6 +193,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = { /* boardtype, boardnum, boardrev */ static const struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = { + {{BCM47XX_BOARD_HUAWEI_B593U_12, "Huawei B593u-12"}, "0x053d", "1234", "0x1301"}, {{BCM47XX_BOARD_HUAWEI_E970, "Huawei E970"}, "0x048e", "0x5347", "0x11"}, {{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"}, {{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"}, diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c index 8e257d0896d2..64e37505b9b4 100644 --- a/arch/mips/bcm47xx/leds.c +++ b/arch/mips/bcm47xx/leds.c @@ -222,6 +222,11 @@ bcm47xx_leds_dlink_dir330[] __initconst = { /* Huawei */ +static const struct gpio_led +bcm47xx_leds_huawei_b593u_12[] __initconst = { + BCM47XX_GPIO_LED(5, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + static const struct gpio_led bcm47xx_leds_huawei_e970[] __initconst = { BCM47XX_GPIO_LED(0, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), @@ -672,6 +677,9 @@ void __init bcm47xx_leds_register(void) bcm47xx_set_pdata(bcm47xx_leds_dlink_dir330); break; + case BCM47XX_BOARD_HUAWEI_B593U_12: + bcm47xx_set_pdata(bcm47xx_leds_huawei_b593u_12); + break; case BCM47XX_BOARD_HUAWEI_E970: bcm47xx_set_pdata(bcm47xx_leds_huawei_e970); break; diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h index 3c401f11655e..4bd8c86ec6c3 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h @@ -53,6 +53,7 @@ enum bcm47xx_board { BCM47XX_BOARD_DLINK_DIR130, BCM47XX_BOARD_DLINK_DIR330, + BCM47XX_BOARD_HUAWEI_B593U_12, BCM47XX_BOARD_HUAWEI_E970, BCM47XX_BOARD_LINKSYS_E900V1, From 5bd3990723bdf43333b2c268cc6644cb1961125b Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 21 Feb 2023 13:16:54 +0000 Subject: [PATCH 003/182] MIPS: Loongson64: Prefix ipi register address pointers with __iomem They are truely mmio pointers, so give them proper prefix. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/loongson64/smp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index 660e1de4412a..c268c6dd1ef1 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -27,11 +27,11 @@ DEFINE_PER_CPU(int, cpu_state); #define LS_IPI_IRQ (MIPS_CPU_IRQ_BASE + 6) -static void *ipi_set0_regs[16]; -static void *ipi_clear0_regs[16]; -static void *ipi_status0_regs[16]; -static void *ipi_en0_regs[16]; -static void *ipi_mailbox_buf[16]; +static void __iomem *ipi_set0_regs[16]; +static void __iomem *ipi_clear0_regs[16]; +static void __iomem *ipi_status0_regs[16]; +static void __iomem *ipi_en0_regs[16]; +static void __iomem *ipi_mailbox_buf[16]; static uint32_t core0_c0count[NR_CPUS]; /* read a 32bit value from ipi register */ From ac24cc1835c8e6400230f0bf50e6ba0ab75cb09f Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 21 Feb 2023 13:16:55 +0000 Subject: [PATCH 004/182] MIPS: Loongson64: smp: Use nudge_writes instead of wbflush wbflush here intends to let other cores see the results ASAP, nudge_writes fits this purpose better. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/loongson64/smp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index c268c6dd1ef1..e9d91da7fe24 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -42,13 +42,13 @@ static uint32_t core0_c0count[NR_CPUS]; #define loongson3_ipi_write32(action, addr) \ do { \ writel(action, addr); \ - __wbflush(); \ + nudge_writes(); \ } while (0) /* write a 64bit value to ipi register */ #define loongson3_ipi_write64(action, addr) \ do { \ writeq(action, addr); \ - __wbflush(); \ + nudge_writes(); \ } while (0) static u32 (*ipi_read_clear)(int cpu); @@ -418,7 +418,7 @@ static irqreturn_t loongson3_ipi_interrupt(int irq, void *dev_id) c0count = c0count ? c0count : 1; for (i = 1; i < nr_cpu_ids; i++) core0_c0count[i] = c0count; - __wbflush(); /* Let others see the result ASAP */ + nudge_writes(); /* Let others see the result ASAP */ } return IRQ_HANDLED; From 227003cb5325298a26276f49bebbfaf39d903be4 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 21 Feb 2023 13:16:56 +0000 Subject: [PATCH 005/182] MIPS: Loongson64: smp: Correct nudge_writes usage Previously every write to SMP regisers are followed by nudge_writes, this incures a huge performance penalty because nudge_writes involves SYNC, which will be globalized on chip. Only set off nudge_writes when we really want other cores to see the result ASAP. Also replace read/write functions to relaxed version because we don't need extra barriers to protect against DMA. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/loongson64/smp.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index e9d91da7fe24..90c783981197 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -34,23 +34,6 @@ static void __iomem *ipi_en0_regs[16]; static void __iomem *ipi_mailbox_buf[16]; static uint32_t core0_c0count[NR_CPUS]; -/* read a 32bit value from ipi register */ -#define loongson3_ipi_read32(addr) readl(addr) -/* read a 64bit value from ipi register */ -#define loongson3_ipi_read64(addr) readq(addr) -/* write a 32bit value to ipi register */ -#define loongson3_ipi_write32(action, addr) \ - do { \ - writel(action, addr); \ - nudge_writes(); \ - } while (0) -/* write a 64bit value to ipi register */ -#define loongson3_ipi_write64(action, addr) \ - do { \ - writeq(action, addr); \ - nudge_writes(); \ - } while (0) - static u32 (*ipi_read_clear)(int cpu); static void (*ipi_write_action)(int cpu, u32 action); static void (*ipi_write_enable)(int cpu); @@ -136,26 +119,28 @@ static u32 legacy_ipi_read_clear(int cpu) u32 action; /* Load the ipi register to figure out what we're supposed to do */ - action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]); + action = readl_relaxed(ipi_status0_regs[cpu_logical_map(cpu)]); /* Clear the ipi register to clear the interrupt */ - loongson3_ipi_write32(action, ipi_clear0_regs[cpu_logical_map(cpu)]); + writel_relaxed(action, ipi_clear0_regs[cpu_logical_map(cpu)]); + nudge_writes(); return action; } static void legacy_ipi_write_action(int cpu, u32 action) { - loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]); + writel_relaxed((u32)action, ipi_set0_regs[cpu]); + nudge_writes(); } static void legacy_ipi_write_enable(int cpu) { - loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(cpu)]); + writel_relaxed(0xffffffff, ipi_en0_regs[cpu_logical_map(cpu)]); } static void legacy_ipi_clear_buf(int cpu) { - loongson3_ipi_write64(0, ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); + writeq_relaxed(0, ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); } static void legacy_ipi_write_buf(int cpu, struct task_struct *idle) @@ -171,14 +156,15 @@ static void legacy_ipi_write_buf(int cpu, struct task_struct *idle) pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n", cpu, startargs[0], startargs[1], startargs[2]); - loongson3_ipi_write64(startargs[3], + writeq_relaxed(startargs[3], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18); - loongson3_ipi_write64(startargs[2], + writeq_relaxed(startargs[2], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10); - loongson3_ipi_write64(startargs[1], + writeq_relaxed(startargs[1], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8); - loongson3_ipi_write64(startargs[0], + writeq_relaxed(startargs[0], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); + nudge_writes(); } static void csr_ipi_probe(void) From 162e134aedcacc9ab9d5648349ceb5409f9ec880 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 21 Feb 2023 13:16:57 +0000 Subject: [PATCH 006/182] MIPS: Loongson64: Remove CPU_HAS_WB Q: Do we have really have write buffer A: Yes, on newer Loongson processors there is a "store fill buffer" that will collect *cached* writes, on all Loongson processors AXI crossbar will buffer all writes. Q: Then why do we want to remove CPU_HAS_WB? A: Because CPU_HAS_WB introduces wbflush, which intends to flush all write reuqests to mmio device. We won't be affected by store fill buffer because it won't buffer uncached writes. And a regular memory barrier is sufficient to flush crossbar write buffer. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 1 - arch/mips/loongson64/setup.c | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e2f3ca73f40d..6f275ace27be 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -490,7 +490,6 @@ config MACH_LOONGSON64 select BOARD_SCACHE select CSRC_R4K select CEVT_R4K - select CPU_HAS_WB select FORCE_PCI select ISA select I8259 diff --git a/arch/mips/loongson64/setup.c b/arch/mips/loongson64/setup.c index 3cd11c2b308b..257038e18779 100644 --- a/arch/mips/loongson64/setup.c +++ b/arch/mips/loongson64/setup.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -17,20 +16,6 @@ void *loongson_fdt_blob; -static void wbflush_loongson(void) -{ - asm(".set\tpush\n\t" - ".set\tnoreorder\n\t" - ".set mips3\n\t" - "sync\n\t" - "nop\n\t" - ".set\tpop\n\t" - ".set mips0\n\t"); -} - -void (*__wbflush)(void) = wbflush_loongson; -EXPORT_SYMBOL(__wbflush); - void __init plat_mem_setup(void) { if (loongson_fdt_blob) From 7b76ab837522fd6aa72b25d1c5460995095fedc0 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 21 Feb 2023 13:16:58 +0000 Subject: [PATCH 007/182] MIPS: Loongson64: Opt-out war_io_reorder_wmb It is clearly stated on "Loongson 3A3000/3B3000 processor user manual vol 2" that "All access requests using a non-cached algorithm are executed in a blocking order. That is, before the current read request data is returned to the processor, all subsequent requests are blocked and issued; All subsequent requests are blocked until the write request data has been sent or the issued write request has not received a write reply from the final receiver." Which means uncached read/write is strongly ordered. So we won't need this workaround. This option was introduced when we add initial support for GS464E, it looks like a misinterpretation of another section in the manual saying we need barriers to ensure MMIO order against DMA requests. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index e6d5ccaa309e..cc28d207a061 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -210,7 +210,7 @@ void iounmap(const volatile void __iomem *addr); #define ioremap_wc(offset, size) \ ioremap_prot((offset), (size), boot_cpu_data.writecombine) -#if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_CPU_LOONGSON64) +#if defined(CONFIG_CPU_CAVIUM_OCTEON) #define war_io_reorder_wmb() wmb() #else #define war_io_reorder_wmb() barrier() From e9a440e0923cddc0f9455dab55ae1b8b47a3e660 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Tue, 21 Feb 2023 19:01:42 +0800 Subject: [PATCH 008/182] dt-bindings: mips: loongson: Add Loongson-1 based boards Add two Loongson-1 based boards: LSGZ 1B and Smartloong 1C. Signed-off-by: Keguang Zhang Reviewed-by: Rob Herring Signed-off-by: Thomas Bogendoerfer --- .../devicetree/bindings/mips/loongson/devices.yaml | 12 ++++++++++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 ++ 2 files changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/mips/loongson/devices.yaml b/Documentation/devicetree/bindings/mips/loongson/devices.yaml index f13ce386f42c..099e40e1482d 100644 --- a/Documentation/devicetree/bindings/mips/loongson/devices.yaml +++ b/Documentation/devicetree/bindings/mips/loongson/devices.yaml @@ -37,6 +37,18 @@ properties: items: - const: loongson,loongson64v-4core-virtio + - description: LS1B based boards + items: + - enum: + - loongson,lsgz-1b-dev + - const: loongson,ls1b + + - description: LS1C based boards + items: + - enum: + - loongmasses,smartloong-1c + - const: loongson,ls1c + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index ed64e06ecca4..06d8c326fc3d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -769,6 +769,8 @@ patternProperties: description: Lontium Semiconductor Corporation "^loongson,.*": description: Loongson Technology Corporation Limited + "^loongmasses,.*": + description: Nanjing Loongmasses Ltd. "^lsi,.*": description: LSI Corp. (LSI Logic) "^lwn,.*": From 13a9d0bea9d1cb119c9ce59c95b51cbb954827cc Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:57:55 +0100 Subject: [PATCH 009/182] mips: ralink: rt305x: define RT305X_SYSC_BASE with __iomem So that RT305X_SYSC_BASE can be used later in multiple functions without needing to repeat this __iomem declaration each time Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-ralink/rt305x.h | 3 ++- arch/mips/ralink/rt305x.c | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h index 4d8e8c8d83ce..ef58f7bff957 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -43,7 +43,8 @@ static inline int soc_is_rt5350(void) return ralink_soc == RT305X_SOC_RT5350; } -#define RT305X_SYSC_BASE 0x10000000 +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) +#define RT305X_SYSC_BASE IOMEM(0x10000000) #define SYSC_REG_CHIP_NAME0 0x00 #define SYSC_REG_CHIP_NAME1 0x04 diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index 8b095a9dcb15..135a46517763 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -21,11 +21,10 @@ static unsigned long rt5350_get_mem_size(void) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); unsigned long ret; u32 t; - t = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG); + t = __raw_readl(RT305X_SYSC_BASE + SYSC_REG_SYSTEM_CONFIG); t = (t >> RT5350_SYSCFG0_DRAM_SIZE_SHIFT) & RT5350_SYSCFG0_DRAM_SIZE_MASK; @@ -142,14 +141,13 @@ void __init ralink_of_remap(void) void __init prom_soc_init(struct ralink_soc_info *soc_info) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); unsigned char *name; u32 n0; u32 n1; u32 id; - n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); + n0 = __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME1); if (n0 == RT3052_CHIP_NAME0 && n1 == RT3052_CHIP_NAME1) { unsigned long icache_sets; From 0def2164c94aa504bd2a3575e74a5f7fd86f5587 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:57:56 +0100 Subject: [PATCH 010/182] mips: ralink: rt305x: soc queries and tests as functions Move the SoC register value queries and tests to specific functions, to remove repetition of logic. No functional changes intended Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/rt305x.c | 97 +++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 20 deletions(-) diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index 135a46517763..a24143c739ee 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -139,52 +139,109 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } -void __init prom_soc_init(struct ralink_soc_info *soc_info) +static unsigned int __init rt305x_get_soc_name0(void) { - unsigned char *name; - u32 n0; - u32 n1; - u32 id; + return __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME0); +} - n0 = __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME1); +static unsigned int __init rt305x_get_soc_name1(void) +{ + return __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME1); +} - if (n0 == RT3052_CHIP_NAME0 && n1 == RT3052_CHIP_NAME1) { +static bool __init rt3052_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT3052_CHIP_NAME0 && + rt305x_get_soc_name1() == RT3052_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init rt3350_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT3350_CHIP_NAME0 && + rt305x_get_soc_name1() == RT3350_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init rt3352_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT3352_CHIP_NAME0 && + rt305x_get_soc_name1() == RT3352_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init rt5350_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT5350_CHIP_NAME0 && + rt305x_get_soc_name1() == RT5350_CHIP_NAME1) + return true; + else + return false; +} + +static const char __init *rt305x_get_soc_name(struct ralink_soc_info *soc_info) +{ + if (rt3052_soc_valid()) { unsigned long icache_sets; icache_sets = (read_c0_config1() >> 22) & 7; if (icache_sets == 1) { ralink_soc = RT305X_SOC_RT3050; - name = "RT3050"; soc_info->compatible = "ralink,rt3050-soc"; + return "RT3050"; } else { ralink_soc = RT305X_SOC_RT3052; - name = "RT3052"; soc_info->compatible = "ralink,rt3052-soc"; + return "RT3052"; } - } else if (n0 == RT3350_CHIP_NAME0 && n1 == RT3350_CHIP_NAME1) { + } else if (rt3350_soc_valid()) { ralink_soc = RT305X_SOC_RT3350; - name = "RT3350"; soc_info->compatible = "ralink,rt3350-soc"; - } else if (n0 == RT3352_CHIP_NAME0 && n1 == RT3352_CHIP_NAME1) { + return "RT3350"; + } else if (rt3352_soc_valid()) { ralink_soc = RT305X_SOC_RT3352; - name = "RT3352"; soc_info->compatible = "ralink,rt3352-soc"; - } else if (n0 == RT5350_CHIP_NAME0 && n1 == RT5350_CHIP_NAME1) { + return "RT3352"; + } else if (rt5350_soc_valid()) { ralink_soc = RT305X_SOC_RT5350; - name = "RT5350"; soc_info->compatible = "ralink,rt5350-soc"; + return "RT5350"; } else { - panic("rt305x: unknown SoC, n0:%08x n1:%08x", n0, n1); + panic("rt305x: unknown SoC, n0:%08x n1:%08x", + rt305x_get_soc_name0(), rt305x_get_soc_name1()); } +} - id = __raw_readl(sysc + SYSC_REG_CHIP_ID); +static unsigned int __init rt305x_get_soc_id(void) +{ + return __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_ID); +} + +static unsigned int __init rt305x_get_soc_ver(void) +{ + return (rt305x_get_soc_id() >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK; +} + +static unsigned int __init rt305x_get_soc_rev(void) +{ + return (rt305x_get_soc_id() & CHIP_ID_REV_MASK); +} + +void __init prom_soc_init(struct ralink_soc_info *soc_info) +{ + const char *name = rt305x_get_soc_name(soc_info); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s id:%u rev:%u", name, - (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, - (id & CHIP_ID_REV_MASK)); + rt305x_get_soc_ver(), + rt305x_get_soc_rev()); soc_info->mem_base = RT305X_SDRAM_BASE; if (soc_is_rt5350()) { From bf27860fcabdd61d4bd33ce9488dc68bae5c7107 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:57:57 +0100 Subject: [PATCH 011/182] mips: ralink: rt305x: introduce 'soc_device' initialization RT305x SoCs have their own 'ralink_soc_info' structure with some information about the soc itself. In order to be able to retrieve this information from driver code and avoid architecture dependencies for retrieving these details introduce this 'soc_device'. Set 'data' pointer points to the struct 'ralink_soc_info' to be able to export also current soc information using this mechanism. We need to select 'SOC_BUS' in Kconfig configuration for these SoCs. Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/Kconfig | 1 + arch/mips/ralink/rt305x.c | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 83e61e147b90..0b0459f1f83e 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -32,6 +32,7 @@ choice config SOC_RT305X bool "RT305x" + select SOC_BUS config SOC_RT3883 bool "RT3883" diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index a24143c739ee..d8dcc5cc66cc 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -19,6 +21,8 @@ #include "common.h" +static struct ralink_soc_info *soc_info_ptr; + static unsigned long rt5350_get_mem_size(void) { unsigned long ret; @@ -233,6 +237,46 @@ static unsigned int __init rt305x_get_soc_rev(void) return (rt305x_get_soc_id() & CHIP_ID_REV_MASK); } +static const char __init *rt305x_get_soc_id_name(void) +{ + if (soc_is_rt3050()) + return "rt3050"; + else if (soc_is_rt3052()) + return "rt3052"; + else if (soc_is_rt3350()) + return "rt3350"; + else if (soc_is_rt3352()) + return "rt3352"; + else if (soc_is_rt5350()) + return "rt5350"; + else + return "invalid"; +} + +static int __init rt305x_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = rt305x_get_soc_id_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(rt305x_soc_dev_init); + void __init prom_soc_init(struct ralink_soc_info *soc_info) { const char *name = rt305x_get_soc_name(soc_info); @@ -253,4 +297,6 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_size_min = RT3352_MEM_SIZE_MIN; soc_info->mem_size_max = RT3352_MEM_SIZE_MAX; } + + soc_info_ptr = soc_info; } From 7edb1775846ebc5a7f4d5085ff6d712ed137a460 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:57:58 +0100 Subject: [PATCH 012/182] mips: ralink: rt3883: define RT3883_SYSC_BASE with __iomem So that RT3883_SYSC_BASE can be used later in multiple functions without needing to repeat this __iomem declaration each time Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-ralink/rt3883.h | 4 +++- arch/mips/ralink/rt3883.c | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/mach-ralink/rt3883.h b/arch/mips/include/asm/mach-ralink/rt3883.h index f250de9c055b..ad25d5e8d2dc 100644 --- a/arch/mips/include/asm/mach-ralink/rt3883.h +++ b/arch/mips/include/asm/mach-ralink/rt3883.h @@ -10,8 +10,10 @@ #include +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) + #define RT3883_SDRAM_BASE 0x00000000 -#define RT3883_SYSC_BASE 0x10000000 +#define RT3883_SYSC_BASE IOMEM(0x10000000) #define RT3883_TIMER_BASE 0x10000100 #define RT3883_INTC_BASE 0x10000200 #define RT3883_MEMC_BASE 0x10000300 diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index d9875f146d66..fa215c07558d 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -72,15 +72,14 @@ void __init ralink_of_remap(void) void __init prom_soc_init(struct ralink_soc_info *soc_info) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT3883_SYSC_BASE); const char *name; u32 n0; u32 n1; u32 id; - n0 = __raw_readl(sysc + RT3883_SYSC_REG_CHIPID0_3); - n1 = __raw_readl(sysc + RT3883_SYSC_REG_CHIPID4_7); - id = __raw_readl(sysc + RT3883_SYSC_REG_REVID); + n0 = __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID0_3); + n1 = __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID4_7); + id = __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_REVID); if (n0 == RT3883_CHIP_NAME0 && n1 == RT3883_CHIP_NAME1) { soc_info->compatible = "ralink,rt3883-soc"; From 89f9b3041e7eddfcfa7260d7e0d2846b21f316d1 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:57:59 +0100 Subject: [PATCH 013/182] mips: ralink: rt3883: soc queries and tests as functions Move the SoC register value queries and tests to specific functions, to remove repetition of logic. No functional changes intended Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/rt3883.c | 66 +++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index fa215c07558d..6f8541a4bc8e 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -70,29 +70,61 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } +static unsigned int __init rt3883_get_soc_name0(void) +{ + return __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID0_3); +} + +static unsigned int __init rt3883_get_soc_name1(void) +{ + return __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID4_7); +} + +static bool __init rt3883_soc_valid(void) +{ + if (rt3883_get_soc_name0() == RT3883_CHIP_NAME0 && + rt3883_get_soc_name1() == RT3883_CHIP_NAME1) + return true; + else + return false; +} + +static const char __init *rt3883_get_soc_name(void) +{ + if (rt3883_soc_valid()) + return "RT3883"; + else + return "invalid"; +} + +static unsigned int __init rt3883_get_soc_id(void) +{ + return __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_REVID); +} + +static unsigned int __init rt3883_get_soc_ver(void) +{ + return (rt3883_get_soc_id() >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK; +} + +static unsigned int __init rt3883_get_soc_rev(void) +{ + return (rt3883_get_soc_id() & RT3883_REVID_ECO_ID_MASK); +} + void __init prom_soc_init(struct ralink_soc_info *soc_info) { - const char *name; - u32 n0; - u32 n1; - u32 id; - - n0 = __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID0_3); - n1 = __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID4_7); - id = __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_REVID); - - if (n0 == RT3883_CHIP_NAME0 && n1 == RT3883_CHIP_NAME1) { + if (rt3883_soc_valid()) soc_info->compatible = "ralink,rt3883-soc"; - name = "RT3883"; - } else { - panic("rt3883: unknown SoC, n0:%08x n1:%08x", n0, n1); - } + else + panic("rt3883: unknown SoC, n0:%08x n1:%08x", + rt3883_get_soc_name0(), rt3883_get_soc_name1()); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s ver:%u eco:%u", - name, - (id >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK, - (id & RT3883_REVID_ECO_ID_MASK)); + rt3883_get_soc_name(), + rt3883_get_soc_ver(), + rt3883_get_soc_rev()); soc_info->mem_base = RT3883_SDRAM_BASE; soc_info->mem_size_min = RT3883_MEM_SIZE_MIN; From 2165248f68b5f3e27faac844795e6691e1ee7777 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:00 +0100 Subject: [PATCH 014/182] mips: ralink: rt3883: introduce 'soc_device' initialization RT3883 SoC have its own 'ralink_soc_info' structure with some information about the soc itself. In order to be able to retrieve this information from driver code and avoid architecture dependencies for retrieving these details introduce this 'soc_device'. Set 'data' pointer points to the struct 'ralink_soc_info' to be able to export also current soc information using this mechanism. We need to select 'SOC_BUS' in Kconfig configuration for these SoCs. Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/Kconfig | 1 + arch/mips/ralink/rt3883.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 0b0459f1f83e..e2a43a59fc81 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -37,6 +37,7 @@ choice config SOC_RT3883 bool "RT3883" select HAVE_PCI + select SOC_BUS config SOC_MT7620 bool "MT7620/8" diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index 6f8541a4bc8e..cca887af378f 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -17,6 +19,8 @@ #include "common.h" +static struct ralink_soc_info *soc_info_ptr; + void __init ralink_clk_init(void) { unsigned long cpu_rate, sys_rate; @@ -112,6 +116,30 @@ static unsigned int __init rt3883_get_soc_rev(void) return (rt3883_get_soc_id() & RT3883_REVID_ECO_ID_MASK); } +static int __init rt3883_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = rt3883_get_soc_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(rt3883_soc_dev_init); + void __init prom_soc_init(struct ralink_soc_info *soc_info) { if (rt3883_soc_valid()) @@ -131,4 +159,5 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_size_max = RT3883_MEM_SIZE_MAX; ralink_soc = RT3883_SOC; + soc_info_ptr = soc_info; } From 1e688601d18d3d872ffaad70c599e8c1a1d788a0 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:01 +0100 Subject: [PATCH 015/182] mips: ralink: rt288x: define RT2880_SYSC_BASE with __iomem So that RT2880_SYSC_BASE can be used later in multiple functions without needing to repeat this __iomem declaration each time Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-ralink/rt288x.h | 3 ++- arch/mips/ralink/rt288x.c | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/mach-ralink/rt288x.h b/arch/mips/include/asm/mach-ralink/rt288x.h index 5f213534f0f5..66a999cd1d80 100644 --- a/arch/mips/include/asm/mach-ralink/rt288x.h +++ b/arch/mips/include/asm/mach-ralink/rt288x.h @@ -11,7 +11,8 @@ #ifndef _RT288X_REGS_H_ #define _RT288X_REGS_H_ -#define RT2880_SYSC_BASE 0x00300000 +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) +#define RT2880_SYSC_BASE IOMEM(0x00300000) #define SYSC_REG_CHIP_NAME0 0x00 #define SYSC_REG_CHIP_NAME1 0x04 diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 493335db2fe1..12f339138c4c 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -59,15 +59,14 @@ void __init ralink_of_remap(void) void __init prom_soc_init(struct ralink_soc_info *soc_info) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT2880_SYSC_BASE); const char *name; u32 n0; u32 n1; u32 id; - n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); - id = __raw_readl(sysc + SYSC_REG_CHIP_ID); + n0 = __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME1); + id = __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_ID); if (n0 == RT2880_CHIP_NAME0 && n1 == RT2880_CHIP_NAME1) { soc_info->compatible = "ralink,r2880-soc"; From 5a5aa151bdccea934d4a84086661538b60a09a42 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:02 +0100 Subject: [PATCH 016/182] mips: ralink: rt288x: soc queries and tests as functions Move the SoC register value queries and tests to specific functions, to remove repetition of logic. No functional changes intended Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/rt288x.c | 65 +++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 12f339138c4c..a417b8b89b94 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -57,29 +57,60 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } +static unsigned int __init rt2880_get_soc_name0(void) +{ + return __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME0); +} + +static unsigned int __init rt2880_get_soc_name1(void) +{ + return __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME1); +} + +static bool __init rt2880_soc_valid(void) +{ + if (rt2880_get_soc_name0() == RT2880_CHIP_NAME0 && + rt2880_get_soc_name1() == RT2880_CHIP_NAME1) + return true; + else + return false; +} + +static const char __init *rt2880_get_soc_name(void) +{ + if (rt2880_soc_valid()) + return "RT2880"; + else + return "invalid"; +} + +static unsigned int __init rt2880_get_soc_id(void) +{ + return __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_ID); +} + +static unsigned int __init rt2880_get_soc_ver(void) +{ + return (rt2880_get_soc_id() >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK; +} + +static unsigned int __init rt2880_get_soc_rev(void) +{ + return (rt2880_get_soc_id() & CHIP_ID_REV_MASK); +} void __init prom_soc_init(struct ralink_soc_info *soc_info) { - const char *name; - u32 n0; - u32 n1; - u32 id; - - n0 = __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME1); - id = __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_ID); - - if (n0 == RT2880_CHIP_NAME0 && n1 == RT2880_CHIP_NAME1) { + if (rt2880_soc_valid()) soc_info->compatible = "ralink,r2880-soc"; - name = "RT2880"; - } else { - panic("rt288x: unknown SoC, n0:%08x n1:%08x", n0, n1); - } + else + panic("rt288x: unknown SoC, n0:%08x n1:%08x", + rt2880_get_soc_name0(), rt2880_get_soc_name1()); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s id:%u rev:%u", - name, - (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, - (id & CHIP_ID_REV_MASK)); + rt2880_get_soc_name(), + rt2880_get_soc_ver(), + rt2880_get_soc_rev()); soc_info->mem_base = RT2880_SDRAM_BASE; soc_info->mem_size_min = RT2880_MEM_SIZE_MIN; From 7a26b384c44cfa9ea65799dc375619c96608ecad Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:03 +0100 Subject: [PATCH 017/182] mips: ralink: rt288x: introduce 'soc_device' initialization RT288X SoCs have their own 'ralink_soc_info' structure with some information about the soc itself. In order to be able to retrieve this information from driver code and avoid architecture dependencies for retrieving these details introduce this 'soc_device'. Set 'data' pointer points to the struct 'ralink_soc_info' to be able to export also current soc information using this mechanism. We need to select 'SOC_BUS' in Kconfig configuration for these SoCs. Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/Kconfig | 1 + arch/mips/ralink/rt288x.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index e2a43a59fc81..e8b8fb35d33d 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -29,6 +29,7 @@ choice select MIPS_AUTO_PFN_OFFSET select MIPS_L1_CACHE_SHIFT_4 select HAVE_PCI + select SOC_BUS config SOC_RT305X bool "RT305x" diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index a417b8b89b94..456ba0b2599e 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -17,6 +19,8 @@ #include "common.h" +static struct ralink_soc_info *soc_info_ptr; + void __init ralink_clk_init(void) { unsigned long cpu_rate, wmac_rate = 40000000; @@ -98,6 +102,31 @@ static unsigned int __init rt2880_get_soc_rev(void) { return (rt2880_get_soc_id() & CHIP_ID_REV_MASK); } + +static int __init rt2880_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = rt2880_get_soc_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(rt2880_soc_dev_init); + void __init prom_soc_init(struct ralink_soc_info *soc_info) { if (rt2880_soc_valid()) @@ -117,4 +146,5 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_size_max = RT2880_MEM_SIZE_MAX; ralink_soc = RT2880_SOC; + soc_info_ptr = soc_info; } From 217cf927e7c6ab41dc276442600f1309613ad417 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:04 +0100 Subject: [PATCH 018/182] mips: ralink: mt7620: define MT7620_SYSC_BASE with __iomem So that MT7620_SYSC_BASE can be used later in multiple functions without needing to repeat this __iomem declaration each time Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-ralink/mt7620.h | 3 ++- arch/mips/ralink/mt7620.c | 15 +++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h index d51dfad8f543..3e37705ea9cf 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -11,7 +11,8 @@ #ifndef _MT7620_REGS_H_ #define _MT7620_REGS_H_ -#define MT7620_SYSC_BASE 0x10000000 +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) +#define MT7620_SYSC_BASE IOMEM(0x10000000) #define SYSC_REG_CHIP_NAME0 0x00 #define SYSC_REG_CHIP_NAME1 0x04 diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index ae1fa0391c88..c13b73b6ee3f 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -326,7 +326,6 @@ mt7628_dram_init(struct ralink_soc_info *soc_info) void __init prom_soc_init(struct ralink_soc_info *soc_info) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7620_SYSC_BASE); unsigned char *name = NULL; u32 n0; u32 n1; @@ -336,9 +335,9 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) u32 pmu1; u32 bga; - n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); - rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); + n0 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME1); + rev = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_REV); bga = (rev >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; if (n0 == MT7620_CHIP_NAME0 && n1 == MT7620_CHIP_NAME1) { @@ -352,7 +351,7 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) soc_info->compatible = "ralink,mt7620n-soc"; } } else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) { - u32 efuse = __raw_readl(sysc + SYSC_REG_EFUSE_CFG); + u32 efuse = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_EFUSE_CFG); if (efuse & EFUSE_MT7688) { ralink_soc = MT762X_SOC_MT7688; @@ -372,7 +371,7 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, (rev & CHIP_REV_ECO_MASK)); - cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); + cfg0 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_SYSTEM_CONFIG0); if (is_mt76x8()) { dram_type = cfg0 & DRAM_TYPE_MT7628_MASK; } else { @@ -388,8 +387,8 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) else mt7620_dram_init(soc_info); - pmu0 = __raw_readl(sysc + PMU0_CFG); - pmu1 = __raw_readl(sysc + PMU1_CFG); + pmu0 = __raw_readl(MT7620_SYSC_BASE + PMU0_CFG); + pmu1 = __raw_readl(MT7620_SYSC_BASE + PMU1_CFG); pr_info("Analog PMU set to %s control\n", (pmu0 & PMU_SW_SET) ? ("sw") : ("hw")); From 727ea3c77dd9b94d994708a148b82df76a47fa79 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:05 +0100 Subject: [PATCH 019/182] mips: ralink: mt7620: soc queries and tests as functions Move the SoC register value queries and tests to specific functions, to remove repetition of logic. No functional changes intended Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/mt7620.c | 94 ++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index c13b73b6ee3f..8604d91f3375 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -324,34 +324,76 @@ mt7628_dram_init(struct ralink_soc_info *soc_info) } } -void __init prom_soc_init(struct ralink_soc_info *soc_info) +static unsigned int __init mt7620_get_soc_name0(void) { - unsigned char *name = NULL; - u32 n0; - u32 n1; - u32 rev; - u32 cfg0; - u32 pmu0; - u32 pmu1; - u32 bga; + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME0); +} - n0 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME1); - rev = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_REV); - bga = (rev >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; +static unsigned int __init mt7620_get_soc_name1(void) +{ + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME1); +} + +static bool __init mt7620_soc_valid(void) +{ + if (mt7620_get_soc_name0() == MT7620_CHIP_NAME0 && + mt7620_get_soc_name1() == MT7620_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init mt7628_soc_valid(void) +{ + if (mt7620_get_soc_name0() == MT7620_CHIP_NAME0 && + mt7620_get_soc_name1() == MT7628_CHIP_NAME1) + return true; + else + return false; +} + +static unsigned int __init mt7620_get_rev(void) +{ + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_REV); +} + +static unsigned int __init mt7620_get_bga(void) +{ + return (mt7620_get_rev() >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; +} + +static unsigned int __init mt7620_get_efuse(void) +{ + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_EFUSE_CFG); +} + +static unsigned int __init mt7620_get_soc_ver(void) +{ + return (mt7620_get_rev() >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK; +} + +static unsigned int __init mt7620_get_soc_eco(void) +{ + return (mt7620_get_rev() & CHIP_REV_ECO_MASK); +} + +static const char __init *mt7620_get_soc_name(struct ralink_soc_info *soc_info) +{ + if (mt7620_soc_valid()) { + u32 bga = mt7620_get_bga(); - if (n0 == MT7620_CHIP_NAME0 && n1 == MT7620_CHIP_NAME1) { if (bga) { ralink_soc = MT762X_SOC_MT7620A; - name = "MT7620A"; soc_info->compatible = "ralink,mt7620a-soc"; + return "MT7620A"; } else { ralink_soc = MT762X_SOC_MT7620N; - name = "MT7620N"; soc_info->compatible = "ralink,mt7620n-soc"; + return "MT7620N"; } - } else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) { - u32 efuse = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_EFUSE_CFG); + } else if (mt7628_soc_valid()) { + u32 efuse = mt7620_get_efuse(); + unsigned char *name = NULL; if (efuse & EFUSE_MT7688) { ralink_soc = MT762X_SOC_MT7688; @@ -361,15 +403,23 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) name = "MT7628AN"; } soc_info->compatible = "ralink,mt7628an-soc"; + return name; } else { - panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", n0, n1); + panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", + mt7620_get_soc_name0(), mt7620_get_soc_name1()); } +} + +void __init prom_soc_init(struct ralink_soc_info *soc_info) +{ + const char *name = mt7620_get_soc_name(soc_info); + u32 cfg0; + u32 pmu0; + u32 pmu1; snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "MediaTek %s ver:%u eco:%u", - name, - (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, - (rev & CHIP_REV_ECO_MASK)); + name, mt7620_get_soc_ver(), mt7620_get_soc_eco()); cfg0 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_SYSTEM_CONFIG0); if (is_mt76x8()) { From 83552892b772dfc4639a4f2da075bbb5d605b788 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Mon, 27 Feb 2023 11:58:06 +0100 Subject: [PATCH 020/182] mips: ralink: mt7620: introduce 'soc_device' initialization MT7620 SoCs have their own 'ralink_soc_info' structure with some information about the soc itself. In order to be able to retrieve this information from driver code and avoid architecture dependencies for retrieving these details introduce this 'soc_device'. Set 'data' pointer points to the struct 'ralink_soc_info' to be able to export also current soc information using this mechanism. We need to select 'SOC_BUS' in Kconfig configuration for these SoCs. Signed-off-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/ralink/Kconfig | 1 + arch/mips/ralink/mt7620.c | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index e8b8fb35d33d..08c012a2591f 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -44,6 +44,7 @@ choice bool "MT7620/8" select CPU_MIPSR2_IRQ_VI select HAVE_PCI + select SOC_BUS config SOC_MT7621 bool "MT7621" diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 8604d91f3375..4435f50b8d24 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -49,6 +51,8 @@ /* does the board have sdram or ddram */ static int dram_type; +static struct ralink_soc_info *soc_info_ptr; + static __init u32 mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div) { @@ -410,6 +414,44 @@ static const char __init *mt7620_get_soc_name(struct ralink_soc_info *soc_info) } } +static const char __init *mt7620_get_soc_id_name(void) +{ + if (ralink_soc == MT762X_SOC_MT7620A) + return "mt7620a"; + else if (ralink_soc == MT762X_SOC_MT7620N) + return "mt7620n"; + else if (ralink_soc == MT762X_SOC_MT7688) + return "mt7688"; + else if (ralink_soc == MT762X_SOC_MT7628AN) + return "mt7628n"; + else + return "invalid"; +} + +static int __init mt7620_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = mt7620_get_soc_id_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(mt7620_soc_dev_init); + void __init prom_soc_init(struct ralink_soc_info *soc_info) { const char *name = mt7620_get_soc_name(soc_info); @@ -444,4 +486,6 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) (pmu0 & PMU_SW_SET) ? ("sw") : ("hw")); pr_info("Digital PMU set to %s control\n", (pmu1 & DIG_SW_SEL) ? ("sw") : ("hw")); + + soc_info_ptr = soc_info; } From 9c99b4880d178a3cc6f42634b995d526a86f746b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 08:46:56 -0600 Subject: [PATCH 021/182] mips: Use of_property_read_bool() for boolean properties It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. Convert reading boolean properties to to of_property_read_bool(). Signed-off-by: Rob Herring Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/pci-lantiq.c | 2 +- arch/mips/pci/pci-rt3883.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index d967e4c0cf24..79e29bf42a24 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -118,7 +118,7 @@ static int ltq_pci_startup(struct platform_device *pdev) /* and enable the clocks */ clk_enable(clk_pci); - if (of_find_property(node, "lantiq,external-clock", NULL)) + if (of_property_read_bool(node, "lantiq,external-clock")) clk_enable(clk_external); else clk_disable(clk_external); diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index d59888aaed81..4ac68a534e4f 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -419,7 +419,7 @@ static int rt3883_pci_probe(struct platform_device *pdev) /* find the interrupt controller child node */ for_each_child_of_node(np, child) { - if (of_get_property(child, "interrupt-controller", NULL)) { + if (of_property_read_bool(child, "interrupt-controller")) { rpc->intc_of_node = child; break; } From 1150e181a14666a77dde80252f2b5cbaea69a498 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 15 Mar 2023 14:45:48 +0100 Subject: [PATCH 022/182] MIPS: sibyte: remove no longer needed board_mem_region With the direct use of memblock interface board_mem_region is no longer needed. Signed-off-by: Thomas Bogendoerfer --- arch/mips/sibyte/common/cfe.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c index 1a504294d85f..2503f60271e8 100644 --- a/arch/mips/sibyte/common/cfe.c +++ b/arch/mips/sibyte/common/cfe.c @@ -35,11 +35,6 @@ #endif #endif -#define SIBYTE_MAX_MEM_REGIONS 8 -phys_addr_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS]; -phys_addr_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS]; -unsigned int board_mem_region_count; - int cfe_cons_handle; #ifdef CONFIG_BLK_DEV_INITRD @@ -141,16 +136,6 @@ static __init void prom_meminit(void) size -= 512; memblock_add(addr, size); } - board_mem_region_addrs[board_mem_region_count] = addr; - board_mem_region_sizes[board_mem_region_count] = size; - board_mem_region_count++; - if (board_mem_region_count == - SIBYTE_MAX_MEM_REGIONS) { - /* - * Too many regions. Need to configure more - */ - while(1); - } } } #ifdef CONFIG_BLK_DEV_INITRD From b984d7b56dfcf71648102e227120bdc247562d00 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 15 Mar 2023 14:55:09 +0100 Subject: [PATCH 023/182] MIPS: sibyte: Remove unused config option SIBYTE_BCM1x55 SIBYTE_BCM1x55 is not selected anywhere, so let's get rid of it. Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kbuild.platforms | 1 - arch/mips/sibyte/Kconfig | 13 +------------ arch/mips/sibyte/Makefile | 2 -- arch/mips/sibyte/Platform | 4 ---- arch/mips/sibyte/common/bus_watcher.c | 4 ++-- arch/mips/sibyte/common/cfe.c | 2 +- arch/mips/sibyte/common/sb_tbprof.c | 10 +++++----- arch/mips/sibyte/swarm/setup.c | 6 +++--- 8 files changed, 12 insertions(+), 30 deletions(-) diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 5d04438ee12e..caad195ba5c1 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -29,7 +29,6 @@ platform-$(CONFIG_SGI_IP30) += sgi-ip30/ platform-$(CONFIG_SGI_IP32) += sgi-ip32/ platform-$(CONFIG_SIBYTE_BCM112X) += sibyte/ platform-$(CONFIG_SIBYTE_SB1250) += sibyte/ -platform-$(CONFIG_SIBYTE_BCM1x55) += sibyte/ platform-$(CONFIG_SIBYTE_BCM1x80) += sibyte/ platform-$(CONFIG_SNI_RM) += sni/ platform-$(CONFIG_MACH_TX49XX) += txx9/ diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index 470d46183677..c437bc02dd08 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -58,16 +58,6 @@ config SIBYTE_BCM1x80 select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP -config SIBYTE_BCM1x55 - bool - select CEVT_BCM1480 - select CSRC_BCM1480 - select HAVE_PCI - select IRQ_MIPS_CPU - select SIBYTE_SB1xxx_SOC - select SIBYTE_HAS_ZBUS_PROFILING - select SYS_SUPPORTS_SMP - config SIBYTE_SB1xxx_SOC bool select IRQ_MIPS_CPU @@ -143,8 +133,7 @@ config SIBYTE_CFE_CONSOLE config SIBYTE_BUS_WATCHER bool "Support for Bus Watcher statistics" depends on SIBYTE_SB1xxx_SOC && \ - (SIBYTE_BCM112X || SIBYTE_SB1250 || \ - SIBYTE_BCM1x55 || SIBYTE_BCM1x80) + (SIBYTE_BCM112X || SIBYTE_SB1250 || SIBYTE_BCM1x80) help Handle and keep statistics on the bus error interrupts (COR_ECC, BAD_ECC, IO_BUS). diff --git a/arch/mips/sibyte/Makefile b/arch/mips/sibyte/Makefile index d015c4d79c3e..ca0d57824d56 100644 --- a/arch/mips/sibyte/Makefile +++ b/arch/mips/sibyte/Makefile @@ -6,8 +6,6 @@ obj-$(CONFIG_SIBYTE_BCM112X) += sb1250/ obj-$(CONFIG_SIBYTE_BCM112X) += common/ obj-$(CONFIG_SIBYTE_SB1250) += sb1250/ obj-$(CONFIG_SIBYTE_SB1250) += common/ -obj-$(CONFIG_SIBYTE_BCM1x55) += bcm1480/ -obj-$(CONFIG_SIBYTE_BCM1x55) += common/ obj-$(CONFIG_SIBYTE_BCM1x80) += bcm1480/ obj-$(CONFIG_SIBYTE_BCM1x80) += common/ diff --git a/arch/mips/sibyte/Platform b/arch/mips/sibyte/Platform index 65b2225b76b2..304b4d16dfbf 100644 --- a/arch/mips/sibyte/Platform +++ b/arch/mips/sibyte/Platform @@ -13,10 +13,6 @@ cflags-$(CONFIG_SIBYTE_SB1250) += \ -I$(srctree)/arch/mips/include/asm/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL -cflags-$(CONFIG_SIBYTE_BCM1x55) += \ - -I$(srctree)/arch/mips/include/asm/mach-sibyte \ - -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL - cflags-$(CONFIG_SIBYTE_BCM1x80) += \ -I$(srctree)/arch/mips/include/asm/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL diff --git a/arch/mips/sibyte/common/bus_watcher.c b/arch/mips/sibyte/common/bus_watcher.c index d43291473f76..a296d2c51841 100644 --- a/arch/mips/sibyte/common/bus_watcher.c +++ b/arch/mips/sibyte/common/bus_watcher.c @@ -24,7 +24,7 @@ #include #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #include #endif @@ -71,7 +71,7 @@ void check_bus_watcher(void) #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250) /* Use non-destructive register */ status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG)); -#elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#elif defined(CONFIG_SIBYTE_BCM1x80) /* Use non-destructive register */ /* Same as 1250 except BUS_ERR_STATUS_DEBUG is in a different place. */ status = csr_in32(IOADDR(A_BCM1480_BUS_ERR_STATUS_DEBUG)); diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c index 2503f60271e8..2cb90dbbe843 100644 --- a/arch/mips/sibyte/common/cfe.c +++ b/arch/mips/sibyte/common/cfe.c @@ -295,7 +295,7 @@ void __init prom_init(void) #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250) register_smp_ops(&sb_smp_ops); #endif -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 register_smp_ops(&bcm1480_smp_ops); #endif } diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index bc47681e825a..004a08469a39 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c @@ -23,7 +23,7 @@ #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #include #include #include @@ -35,7 +35,7 @@ #error invalid SiByte UART configuration #endif -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #undef K_INT_TRACE_FREEZE #define K_INT_TRACE_FREEZE K_BCM1480_INT_TRACE_FREEZE #undef K_INT_PERF_CNT @@ -157,7 +157,7 @@ static void arm_tb(void) * a previous interrupt request. This means that bus profiling * requires ALL of the SCD perf counters. */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) | /* keep counters 0,2,3,4,5,6,7 as is */ V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */ @@ -290,7 +290,7 @@ static int sbprof_zbprof_start(struct file *filp) * pass them through. I am exploiting my knowledge that * cp0_status masks out IP[5]. krw */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 __raw_writeq(K_BCM1480_INT_MAP_I3, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + ((K_BCM1480_INT_PERF_CNT & 0x3f) << 3))); @@ -343,7 +343,7 @@ static int sbprof_zbprof_start(struct file *filp) __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7)); /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 __raw_writeq(1ULL << (K_BCM1480_INT_PERF_CNT & 0x3f), IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_TRACE_L))); #else diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 72a31eeeebba..9e7a1e305f61 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -24,7 +24,7 @@ #include #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #include #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #include @@ -34,7 +34,7 @@ #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 extern void bcm1480_setup(void); #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) extern void sb1250_setup(void); @@ -114,7 +114,7 @@ int update_persistent_clock64(struct timespec64 now) void __init plat_mem_setup(void) { -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 bcm1480_setup(); #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) sb1250_setup(); From a0136c28a2d8e03d0cb2f707cd1c837a8e0884e9 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 15 Mar 2023 15:12:02 +0100 Subject: [PATCH 024/182] MIPS: sibyte: Remove Sibyte CARMEL and CRHINE board support Looks like these boards were nether in active use, so let's remove them. Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 18 ----------- arch/mips/include/asm/sibyte/board.h | 6 +--- arch/mips/include/asm/sibyte/carmel.h | 45 --------------------------- arch/mips/include/asm/sibyte/swarm.h | 5 --- arch/mips/sibyte/Kconfig | 9 ------ arch/mips/sibyte/Makefile | 4 --- arch/mips/sibyte/Platform | 4 --- arch/mips/sibyte/swarm/setup.c | 6 ---- 8 files changed, 1 insertion(+), 96 deletions(-) delete mode 100644 arch/mips/include/asm/sibyte/carmel.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6f275ace27be..88afd252bcc3 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -794,24 +794,6 @@ config SGI_IP32 help If you want this kernel to run on SGI O2 workstation, say Y here. -config SIBYTE_CRHINE - bool "Sibyte BCM91120C-CRhine" - select BOOT_ELF32 - select SIBYTE_BCM1120 - select SWAP_IO_SPACE - select SYS_HAS_CPU_SB1 - select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_LITTLE_ENDIAN - -config SIBYTE_CARMEL - bool "Sibyte BCM91120x-Carmel" - select BOOT_ELF32 - select SIBYTE_BCM1120 - select SWAP_IO_SPACE - select SYS_HAS_CPU_SB1 - select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_LITTLE_ENDIAN - config SIBYTE_CRHONE bool "Sibyte BCM91125C-CRhone" select BOOT_ELF32 diff --git a/arch/mips/include/asm/sibyte/board.h b/arch/mips/include/asm/sibyte/board.h index 20fe2f16c97e..03463faa4244 100644 --- a/arch/mips/include/asm/sibyte/board.h +++ b/arch/mips/include/asm/sibyte/board.h @@ -7,7 +7,7 @@ #define _SIBYTE_BOARD_H #if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_CRHONE) || \ - defined(CONFIG_SIBYTE_CRHINE) || defined(CONFIG_SIBYTE_LITTLESUR) + defined(CONFIG_SIBYTE_LITTLESUR) #include #endif @@ -15,10 +15,6 @@ #include #endif -#ifdef CONFIG_SIBYTE_CARMEL -#include -#endif - #ifdef CONFIG_SIBYTE_BIGSUR #include #endif diff --git a/arch/mips/include/asm/sibyte/carmel.h b/arch/mips/include/asm/sibyte/carmel.h deleted file mode 100644 index c6730d7a6392..000000000000 --- a/arch/mips/include/asm/sibyte/carmel.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2002 Broadcom Corporation - */ -#ifndef __ASM_SIBYTE_CARMEL_H -#define __ASM_SIBYTE_CARMEL_H - -#include -#include - -#define SIBYTE_BOARD_NAME "Carmel" - -#define GPIO_PHY_INTERRUPT 2 -#define GPIO_NONMASKABLE_INT 3 -#define GPIO_CF_INSERTED 6 -#define GPIO_MONTEREY_RESET 7 -#define GPIO_QUADUART_INT 8 -#define GPIO_CF_INT 9 -#define GPIO_FPGA_CCLK 10 -#define GPIO_FPGA_DOUT 11 -#define GPIO_FPGA_DIN 12 -#define GPIO_FPGA_PGM 13 -#define GPIO_FPGA_DONE 14 -#define GPIO_FPGA_INIT 15 - -#define LEDS_CS 2 -#define LEDS_PHYS 0x100C0000 -#define MLEDS_CS 3 -#define MLEDS_PHYS 0x100A0000 -#define UART_CS 4 -#define UART_PHYS 0x100D0000 -#define ARAVALI_CS 5 -#define ARAVALI_PHYS 0x11000000 -#define IDE_CS 6 -#define IDE_PHYS 0x100B0000 -#define ARAVALI2_CS 7 -#define ARAVALI2_PHYS 0x100E0000 - -#if defined(CONFIG_SIBYTE_CARMEL) -#define K_GPIO_GB_IDE 9 -#define K_INT_GB_IDE (K_INT_GPIO_0 + K_GPIO_GB_IDE) -#endif - - -#endif /* __ASM_SIBYTE_CARMEL_H */ diff --git a/arch/mips/include/asm/sibyte/swarm.h b/arch/mips/include/asm/sibyte/swarm.h index 947122f487ed..49ea7a645c15 100644 --- a/arch/mips/include/asm/sibyte/swarm.h +++ b/arch/mips/include/asm/sibyte/swarm.h @@ -24,11 +24,6 @@ #define SIBYTE_HAVE_PCMCIA 0 #define SIBYTE_HAVE_IDE 0 #endif -#ifdef CONFIG_SIBYTE_CRHINE -#define SIBYTE_BOARD_NAME "BCM91120C (CRhine)" -#define SIBYTE_HAVE_PCMCIA 0 -#define SIBYTE_HAVE_IDE 0 -#endif /* Generic bus chip selects */ #define LEDS_CS 3 diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index c437bc02dd08..c4596d49edf1 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -10,15 +10,6 @@ config SIBYTE_SB1250 select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP -config SIBYTE_BCM1120 - bool - select CEVT_SB1250 - select CSRC_SB1250 - select IRQ_MIPS_CPU - select SIBYTE_BCM112X - select SIBYTE_HAS_ZBUS_PROFILING - select SIBYTE_SB1xxx_SOC - config SIBYTE_BCM1125 bool select CEVT_SB1250 diff --git a/arch/mips/sibyte/Makefile b/arch/mips/sibyte/Makefile index ca0d57824d56..47078353fe8a 100644 --- a/arch/mips/sibyte/Makefile +++ b/arch/mips/sibyte/Makefile @@ -10,15 +10,11 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += bcm1480/ obj-$(CONFIG_SIBYTE_BCM1x80) += common/ # -# Sibyte BCM91120x (Carmel) board -# Sibyte BCM91120C (CRhine) board # Sibyte BCM91125C (CRhone) board # Sibyte BCM91125E (Rhone) board # Sibyte SWARM board # Sibyte BCM91x80 (BigSur) board # -obj-$(CONFIG_SIBYTE_CARMEL) += swarm/ -obj-$(CONFIG_SIBYTE_CRHINE) += swarm/ obj-$(CONFIG_SIBYTE_CRHONE) += swarm/ obj-$(CONFIG_SIBYTE_RHONE) += swarm/ obj-$(CONFIG_SIBYTE_SENTOSA) += swarm/ diff --git a/arch/mips/sibyte/Platform b/arch/mips/sibyte/Platform index 304b4d16dfbf..937108e41f13 100644 --- a/arch/mips/sibyte/Platform +++ b/arch/mips/sibyte/Platform @@ -18,16 +18,12 @@ cflags-$(CONFIG_SIBYTE_BCM1x80) += \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL # -# Sibyte BCM91120x (Carmel) board -# Sibyte BCM91120C (CRhine) board # Sibyte BCM91125C (CRhone) board # Sibyte BCM91125E (Rhone) board # Sibyte BCM91250A (SWARM) board # Sibyte BCM91250C2 (LittleSur) board # Sibyte BCM91x80 (BigSur) board # -load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000 -load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000 load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000 load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000 load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000 diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 9e7a1e305f61..76683993cdd3 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -146,12 +146,6 @@ void __init plat_mem_setup(void) #ifdef LEDS_PHYS -#ifdef CONFIG_SIBYTE_CARMEL -/* XXXKW need to detect Monterey/LittleSur/etc */ -#undef LEDS_PHYS -#define LEDS_PHYS MLEDS_PHYS -#endif - void setleds(char *str) { void *reg; From 0345234720ca5601b59f20570f71139f5ad4d229 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 15 Mar 2023 15:21:24 +0100 Subject: [PATCH 025/182] MIPS: sibyte: Replace BCM1125H with SB1250 option SIBYTE_BCM1125H is identical to SIBYTE_SB1250, so remove one of them. Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 2 +- arch/mips/sibyte/Kconfig | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 88afd252bcc3..fd7ed68cdb91 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -807,7 +807,7 @@ config SIBYTE_CRHONE config SIBYTE_RHONE bool "Sibyte BCM91125E-Rhone" select BOOT_ELF32 - select SIBYTE_BCM1125H + select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 select SYS_SUPPORTS_BIG_ENDIAN diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index c4596d49edf1..5fb92fe84149 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -20,17 +20,6 @@ config SIBYTE_BCM1125 select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC -config SIBYTE_BCM1125H - bool - select CEVT_SB1250 - select CSRC_SB1250 - select HAVE_PCI - select IRQ_MIPS_CPU - select SIBYTE_BCM112X - select SIBYTE_ENABLE_LDT_IF_PCI - select SIBYTE_HAS_ZBUS_PROFILING - select SIBYTE_SB1xxx_SOC - config SIBYTE_BCM112X bool select CEVT_SB1250 From a45e5fe792349315827b483eb23b307df47c6c6c Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 16 Mar 2023 12:49:52 +0100 Subject: [PATCH 026/182] MIPS: ath79: remove obsolete ATH79_DEV_* configs Commit 85b9686dae30 ("MIPS: ath79: drop platform device registration code") removes all files arch/mips/ath79/dev-*.[ch], adjusts the Makefile, but misses to adjust the Kconfig file. Hence, since then, the configs ATH79_DEV_* are really dead. Commit 3a77e0d75eed ("MIPS: ath79: drop machfiles") already removes all configs that select ATH79_DEV_* config. So at that point, they was not a way to enable them with a kernel build configuration. Remove these obsolete ATH79_DEV_* configs. Signed-off-by: Lukas Bulwahn Signed-off-by: Thomas Bogendoerfer --- arch/mips/ath79/Kconfig | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 7367416642cb..04154128c4de 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -29,20 +29,4 @@ config SOC_QCA955X config PCI_AR724X def_bool n -config ATH79_DEV_GPIO_BUTTONS - def_bool n - -config ATH79_DEV_LEDS_GPIO - def_bool n - -config ATH79_DEV_SPI - def_bool n - -config ATH79_DEV_USB - def_bool n - -config ATH79_DEV_WMAC - depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X) - def_bool n - endif From 2d337b7158f8c38dacf8394028ab87b8a25ed707 Mon Sep 17 00:00:00 2001 From: ZhangPeng Date: Wed, 1 Mar 2023 10:06:27 +0000 Subject: [PATCH 027/182] userfaultfd: move unprivileged_userfaultfd sysctl to its own file The sysctl_unprivileged_userfaultfd is part of userfaultfd, move it to its own file. Signed-off-by: ZhangPeng Signed-off-by: Luis Chamberlain --- fs/userfaultfd.c | 20 +++++++++++++++++++- include/linux/userfaultfd_k.h | 2 -- kernel/sysctl.c | 11 ----------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 44d1ee429eb0..d01f803a6b11 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -32,7 +32,22 @@ #include #include -int sysctl_unprivileged_userfaultfd __read_mostly; +static int sysctl_unprivileged_userfaultfd __read_mostly; + +#ifdef CONFIG_SYSCTL +static struct ctl_table vm_userfaultfd_table[] = { + { + .procname = "unprivileged_userfaultfd", + .data = &sysctl_unprivileged_userfaultfd, + .maxlen = sizeof(sysctl_unprivileged_userfaultfd), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { } +}; +#endif static struct kmem_cache *userfaultfd_ctx_cachep __read_mostly; @@ -2178,6 +2193,9 @@ static int __init userfaultfd_init(void) 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, init_once_userfaultfd_ctx); +#ifdef CONFIG_SYSCTL + register_sysctl_init("vm", vm_userfaultfd_table); +#endif return 0; } __initcall(userfaultfd_init); diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h index 3767f18114ef..fff49fec0258 100644 --- a/include/linux/userfaultfd_k.h +++ b/include/linux/userfaultfd_k.h @@ -36,8 +36,6 @@ #define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK) #define UFFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS) -extern int sysctl_unprivileged_userfaultfd; - extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason); /* diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 1c240d2c99bc..c14552a662ae 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2438,17 +2438,6 @@ static struct ctl_table vm_table[] = { .extra1 = (void *)&mmap_rnd_compat_bits_min, .extra2 = (void *)&mmap_rnd_compat_bits_max, }, -#endif -#ifdef CONFIG_USERFAULTFD - { - .procname = "unprivileged_userfaultfd", - .data = &sysctl_unprivileged_userfaultfd, - .maxlen = sizeof(sysctl_unprivileged_userfaultfd), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, #endif { } }; From 962de54828c5bb100eb8de881b79ed9c8b7468c0 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Thu, 9 Mar 2023 20:20:11 +0800 Subject: [PATCH 028/182] mm: hugetlb: move hugeltb sysctls to its own file This moves all hugetlb sysctls to its own file, also kill an useless hugetlb_treat_movable_handler() defination. Signed-off-by: Kefeng Wang Reviewed-by: Luis Chamberlain Reviewed-by: Mike Kravetz Reviewed-by: Muchun Song Signed-off-by: Luis Chamberlain --- include/linux/hugetlb.h | 8 ------- kernel/sysctl.c | 32 -------------------------- mm/hugetlb.c | 51 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 7c977d234aba..4056b05d81ed 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -124,14 +124,6 @@ void hugepage_put_subpool(struct hugepage_subpool *spool); void hugetlb_dup_vma_private(struct vm_area_struct *vma); void clear_vma_resv_huge_pages(struct vm_area_struct *vma); -int hugetlb_sysctl_handler(struct ctl_table *, int, void *, size_t *, loff_t *); -int hugetlb_overcommit_handler(struct ctl_table *, int, void *, size_t *, - loff_t *); -int hugetlb_treat_movable_handler(struct ctl_table *, int, void *, size_t *, - loff_t *); -int hugetlb_mempolicy_sysctl_handler(struct ctl_table *, int, void *, size_t *, - loff_t *); - int move_hugetlb_page_tables(struct vm_area_struct *vma, struct vm_area_struct *new_vma, unsigned long old_addr, unsigned long new_addr, diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c14552a662ae..ce0297acf97c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2140,38 +2140,6 @@ static struct ctl_table vm_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, -#endif -#ifdef CONFIG_HUGETLB_PAGE - { - .procname = "nr_hugepages", - .data = NULL, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = hugetlb_sysctl_handler, - }, -#ifdef CONFIG_NUMA - { - .procname = "nr_hugepages_mempolicy", - .data = NULL, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &hugetlb_mempolicy_sysctl_handler, - }, -#endif - { - .procname = "hugetlb_shm_group", - .data = &sysctl_hugetlb_shm_group, - .maxlen = sizeof(gid_t), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "nr_overcommit_hugepages", - .data = NULL, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = hugetlb_overcommit_handler, - }, #endif { .procname = "lowmem_reserve_ratio", diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 07abcb6eb203..0ee77c55e44e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4202,6 +4202,12 @@ static void __init hugetlb_sysfs_init(void) hugetlb_register_all_nodes(); } +#ifdef CONFIG_SYSCTL +static void hugetlb_sysctl_init(void); +#else +static inline void hugetlb_sysctl_init(void) { } +#endif + static int __init hugetlb_init(void) { int i; @@ -4257,6 +4263,7 @@ static int __init hugetlb_init(void) hugetlb_sysfs_init(); hugetlb_cgroup_file_init(); + hugetlb_sysctl_init(); #ifdef CONFIG_SMP num_fault_mutexes = roundup_pow_of_two(8 * num_possible_cpus()); @@ -4588,7 +4595,7 @@ out: return ret; } -int hugetlb_sysctl_handler(struct ctl_table *table, int write, +static int hugetlb_sysctl_handler(struct ctl_table *table, int write, void *buffer, size_t *length, loff_t *ppos) { @@ -4597,7 +4604,7 @@ int hugetlb_sysctl_handler(struct ctl_table *table, int write, } #ifdef CONFIG_NUMA -int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write, +static int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write, void *buffer, size_t *length, loff_t *ppos) { return hugetlb_sysctl_handler_common(true, table, write, @@ -4605,7 +4612,7 @@ int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write, } #endif /* CONFIG_NUMA */ -int hugetlb_overcommit_handler(struct ctl_table *table, int write, +static int hugetlb_overcommit_handler(struct ctl_table *table, int write, void *buffer, size_t *length, loff_t *ppos) { struct hstate *h = &default_hstate; @@ -4634,6 +4641,44 @@ out: return ret; } +static struct ctl_table hugetlb_table[] = { + { + .procname = "nr_hugepages", + .data = NULL, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = hugetlb_sysctl_handler, + }, +#ifdef CONFIG_NUMA + { + .procname = "nr_hugepages_mempolicy", + .data = NULL, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = &hugetlb_mempolicy_sysctl_handler, + }, +#endif + { + .procname = "hugetlb_shm_group", + .data = &sysctl_hugetlb_shm_group, + .maxlen = sizeof(gid_t), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "nr_overcommit_hugepages", + .data = NULL, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = hugetlb_overcommit_handler, + }, + { } +}; + +static void hugetlb_sysctl_init(void) +{ + register_sysctl_init("vm", hugetlb_table); +} #endif /* CONFIG_SYSCTL */ void hugetlb_report_meminfo(struct seq_file *m) From 68c37f917ed97e0b0e6a2be9f6be3eba39b8ea4b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Mar 2023 20:00:31 -0800 Subject: [PATCH 029/182] sh: SH2007: drop the bad URL info This URL provided is no longer functional, so drop it. Fixes: 3a598264436e ("sh: SH-2007 board support.") Signed-off-by: Randy Dunlap Cc: John Paul Adrian Glaubitz Cc: Yoshinori Sato Cc: Rich Felker Cc: Geert Uytterhoeven Cc: Hitoshi Mitake Cc: linux-sh@vger.kernel.org Reviewed-by: Geert Uytterhoeven Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230306040037.20350-2-rdunlap@infradead.org Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/boards/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 83bcb6d2daca..fafe15d3ba1d 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -358,7 +358,6 @@ config SH_SH2007 intended for embedded applications. It has an Ethernet interface (SMC9118), direct connected Compact Flash socket, two serial ports and PC-104 bus. - More information at . config SH_APSH4A3A bool "AP-SH4A-3A" From d1155e4132de712a9d3066e2667ceaad39a539c5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Mar 2023 20:00:32 -0800 Subject: [PATCH 030/182] sh: nmi_debug: fix return value of __setup handler __setup() handlers should return 1 to obsolete_checksetup() in init/main.c to indicate that the boot option has been handled. A return of 0 causes the boot option/value to be listed as an Unknown kernel parameter and added to init's (limited) argument or environment strings. Also, error return codes don't mean anything to obsolete_checksetup() -- only non-zero (usually 1) or zero. So return 1 from nmi_debug_setup(). Fixes: 1e1030dccb10 ("sh: nmi_debug support.") Signed-off-by: Randy Dunlap Reported-by: Igor Zhbanov Link: lore.kernel.org/r/64644a2f-4a20-bab3-1e15-3b2cdd0defe3@omprussia.ru Cc: John Paul Adrian Glaubitz Cc: Yoshinori Sato Cc: Rich Felker Cc: linux-sh@vger.kernel.org Cc: stable@vger.kernel.org Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230306040037.20350-3-rdunlap@infradead.org Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/kernel/nmi_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/nmi_debug.c b/arch/sh/kernel/nmi_debug.c index 11777867c6f5..a212b645b4cf 100644 --- a/arch/sh/kernel/nmi_debug.c +++ b/arch/sh/kernel/nmi_debug.c @@ -49,7 +49,7 @@ static int __init nmi_debug_setup(char *str) register_die_notifier(&nmi_debug_nb); if (*str != '=') - return 0; + return 1; for (p = str + 1; *p; p = sep + 1) { sep = strchr(p, ','); @@ -70,6 +70,6 @@ static int __init nmi_debug_setup(char *str) break; } - return 0; + return 1; } __setup("nmi_debug", nmi_debug_setup); From 6cba655543c7959f8a6d2979b9d40a6a66b7ed4f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Mar 2023 20:00:33 -0800 Subject: [PATCH 031/182] sh: init: use OF_EARLY_FLATTREE for early init When CONFIG_OF_EARLY_FLATTREE and CONFIG_SH_DEVICE_TREE are not set, SH3 build fails with a call to early_init_dt_scan(), so in arch/sh/kernel/setup.c and arch/sh/kernel/head_32.S, use CONFIG_OF_EARLY_FLATTREE instead of CONFIG_OF_FLATTREE. Fixes this build error: ../arch/sh/kernel/setup.c: In function 'sh_fdt_init': ../arch/sh/kernel/setup.c:262:26: error: implicit declaration of function 'early_init_dt_scan' [-Werror=implicit-function-declaration] 262 | if (!dt_virt || !early_init_dt_scan(dt_virt)) { Fixes: 03767daa1387 ("sh: fix build regression with CONFIG_OF && !CONFIG_OF_FLATTREE") Fixes: eb6b6930a70f ("sh: fix memory corruption of unflattened device tree") Signed-off-by: Randy Dunlap Suggested-by: Rob Herring Cc: Frank Rowand Cc: devicetree@vger.kernel.org Cc: Rich Felker Cc: Yoshinori Sato Cc: Geert Uytterhoeven Cc: John Paul Adrian Glaubitz Cc: linux-sh@vger.kernel.org Cc: stable@vger.kernel.org Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230306040037.20350-4-rdunlap@infradead.org Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/kernel/head_32.S | 6 +++--- arch/sh/kernel/setup.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 4adbd4ade319..b603b7968b38 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -64,7 +64,7 @@ ENTRY(_stext) ldc r0, r6_bank #endif -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE mov r4, r12 ! Store device tree blob pointer in r12 #endif @@ -315,7 +315,7 @@ ENTRY(_stext) 10: #endif -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE mov.l 8f, r0 ! Make flat device tree available early. jsr @r0 mov r12, r4 @@ -346,7 +346,7 @@ ENTRY(stack_start) 5: .long start_kernel 6: .long cpu_init 7: .long init_thread_union -#if defined(CONFIG_OF_FLATTREE) +#if defined(CONFIG_OF_EARLY_FLATTREE) 8: .long sh_fdt_init #endif diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 1fcb6659822a..af977ec4ca5e 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -244,7 +244,7 @@ void __init __weak plat_early_device_setup(void) { } -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE void __ref sh_fdt_init(phys_addr_t dt_phys) { static int done = 0; @@ -326,7 +326,7 @@ void __init setup_arch(char **cmdline_p) /* Let earlyprintk output early console messages */ sh_early_platform_driver_probe("earlyprintk", 1, 1); -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE #ifdef CONFIG_USE_BUILTIN_DTB unflatten_and_copy_device_tree(); #else From 58a49ad90939386a8682e842c474a0d2c00ec39c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Mar 2023 20:00:34 -0800 Subject: [PATCH 032/182] sh: math-emu: fix macro redefined warning Fix a warning that was reported by the kernel test robot: In file included from ../include/math-emu/soft-fp.h:27, from ../arch/sh/math-emu/math.c:22: ../arch/sh/include/asm/sfp-machine.h:17: warning: "__BYTE_ORDER" redefined 17 | #define __BYTE_ORDER __BIG_ENDIAN In file included from ../arch/sh/math-emu/math.c:21: ../arch/sh/math-emu/sfp-util.h:71: note: this is the location of the previous definition 71 | #define __BYTE_ORDER __LITTLE_ENDIAN Fixes: b929926f01f2 ("sh: define __BIG_ENDIAN for math-emu") Signed-off-by: Randy Dunlap Reported-by: kernel test robot Link: lore.kernel.org/r/202111121827.6v6SXtVv-lkp@intel.com Cc: John Paul Adrian Glaubitz Cc: Yoshinori Sato Cc: Rich Felker Cc: linux-sh@vger.kernel.org Reviewed-by: Geert Uytterhoeven Cc: stable@vger.kernel.org Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230306040037.20350-5-rdunlap@infradead.org Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/math-emu/sfp-util.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/sh/math-emu/sfp-util.h b/arch/sh/math-emu/sfp-util.h index 784f541344f3..bda50762b3d3 100644 --- a/arch/sh/math-emu/sfp-util.h +++ b/arch/sh/math-emu/sfp-util.h @@ -67,7 +67,3 @@ } while (0) #define abort() return 0 - -#define __BYTE_ORDER __LITTLE_ENDIAN - - From 644a9cf0d2a8340121fa8107a5fa6f27782bb080 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Mar 2023 20:00:35 -0800 Subject: [PATCH 033/182] sh: remove sh5/sh64 last fragments A previous patch removed most of the sh5 (sh64) support from the kernel tree. Now remove the last stragglers. Fixes: 37744feebc08 ("sh: remove sh5 support") Signed-off-by: Randy Dunlap Cc: Geert Uytterhoeven Cc: Arnd Bergmann Cc: Rich Felker Cc: Yoshinori Sato Cc: John Paul Adrian Glaubitz Cc: linux-sh@vger.kernel.org Acked-by: John Paul Adrian Glaubitz Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230306040037.20350-6-rdunlap@infradead.org Signed-off-by: John Paul Adrian Glaubitz --- Documentation/kbuild/kbuild.rst | 1 - Documentation/scheduler/sched-arch.rst | 2 -- Documentation/translations/zh_CN/scheduler/sched-arch.rst | 2 -- scripts/checkstack.pl | 7 ------- tools/perf/arch/common.c | 2 -- tools/scripts/Makefile.arch | 5 ----- tools/testing/selftests/mm/Makefile | 2 +- tools/testing/selftests/mm/run_vmtests.sh | 2 +- 8 files changed, 2 insertions(+), 21 deletions(-) diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst index 5202186728b4..e22621f4af0b 100644 --- a/Documentation/kbuild/kbuild.rst +++ b/Documentation/kbuild/kbuild.rst @@ -160,7 +160,6 @@ directory name found in the arch/ directory. But some architectures such as x86 and sparc have aliases. - x86: i386 for 32 bit, x86_64 for 64 bit -- sh: sh for 32 bit, sh64 for 64 bit - sparc: sparc32 for 32 bit, sparc64 for 64 bit CROSS_COMPILE diff --git a/Documentation/scheduler/sched-arch.rst b/Documentation/scheduler/sched-arch.rst index 0eaec669790a..505cd27f9a92 100644 --- a/Documentation/scheduler/sched-arch.rst +++ b/Documentation/scheduler/sched-arch.rst @@ -70,7 +70,5 @@ Possible arch problems I found (and either tried to fix or didn't): ia64 - is safe_halt call racy vs interrupts? (does it sleep?) (See #4a) -sh64 - Is sleeping racy vs interrupts? (See #4a) - sparc - IRQs on at this point(?), change local_irq_save to _disable. - TODO: needs secondary CPUs to disable preempt (See #1) diff --git a/Documentation/translations/zh_CN/scheduler/sched-arch.rst b/Documentation/translations/zh_CN/scheduler/sched-arch.rst index 754a15c6b60f..ce3f39d9b3cb 100644 --- a/Documentation/translations/zh_CN/scheduler/sched-arch.rst +++ b/Documentation/translations/zh_CN/scheduler/sched-arch.rst @@ -70,7 +70,5 @@ arch/x86/kernel/process.c有轮询和睡眠空闲函数的例子。 ia64 - safe_halt的调用与中断相比,是否很荒谬? (它睡眠了吗) (参考 #4a) -sh64 - 睡眠与中断相比,是否很荒谬? (参考 #4a) - sparc - 在这一点上,IRQ是开着的(?),把local_irq_save改为_disable。 - 待办事项: 需要第二个CPU来禁用抢占 (参考 #1) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index d48dfed6d3db..84f5fb7f1cec 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -10,7 +10,6 @@ # Mips port by Juan Quintela # IA64 port via Andreas Dilger # Arm port by Holger Schurig -# sh64 port by Paul Mundt # Random bits by Matt Mackall # M68k port by Geert Uytterhoeven and Andreas Schwab # AArch64, PARISC ports by Kyle McMartin @@ -100,12 +99,6 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) (?:\(\%r15\))?$/ox; - } elsif ($arch =~ /^sh64$/) { - #XXX: we only check for the immediate case presently, - # though we will want to check for the movi/sub - # pair for larger users. -- PFM. - #a00048e0: d4fc40f0 addi.l r15,-240,r15 - $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { # f0019d10: 9d e3 bf 90 save %sp, -112, %sp $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 59dd875fd5e4..cfe63dfab03a 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -51,9 +51,7 @@ const char *const s390_triplets[] = { const char *const sh_triplets[] = { "sh-unknown-linux-gnu-", - "sh64-unknown-linux-gnu-", "sh-linux-gnu-", - "sh64-linux-gnu-", NULL }; diff --git a/tools/scripts/Makefile.arch b/tools/scripts/Makefile.arch index 1c72d07cb9fe..f6a50f06dfc4 100644 --- a/tools/scripts/Makefile.arch +++ b/tools/scripts/Makefile.arch @@ -29,11 +29,6 @@ ifeq ($(ARCH),sparc64) SRCARCH := sparc endif -# Additional ARCH settings for sh -ifeq ($(ARCH),sh64) - SRCARCH := sh -endif - # Additional ARCH settings for loongarch ifeq ($(ARCH),loongarch32) SRCARCH := loongarch diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index c31d952cff68..fc35050b5542 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -90,7 +90,7 @@ endif endif -ifneq (,$(filter $(MACHINE),arm64 ia64 mips64 parisc64 ppc64 riscv64 s390x sh64 sparc64 x86_64)) +ifneq (,$(filter $(MACHINE),arm64 ia64 mips64 parisc64 ppc64 riscv64 s390x sparc64 x86_64)) TEST_GEN_FILES += va_128TBswitch TEST_GEN_FILES += virtual_address_range TEST_GEN_FILES += write_to_hugetlbfs diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index 8984e0bb58c7..a9d6d52596f2 100644 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -132,7 +132,7 @@ else fi # filter 64bit architectures -ARCH64STR="arm64 ia64 mips64 parisc64 ppc64 ppc64le riscv64 s390x sh64 sparc64 x86_64" +ARCH64STR="arm64 ia64 mips64 parisc64 ppc64 ppc64le riscv64 s390x sparc64 x86_64" if [ -z "$ARCH" ]; then ARCH=$(uname -m 2>/dev/null | sed -e 's/aarch64.*/arm64/') fi From c2bd1e18c6f85c0027da2e5e7753b9bfd9f8e6dc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 5 Mar 2023 20:00:37 -0800 Subject: [PATCH 034/182] sh: mcount.S: fix build error when PRINTK is not enabled Fix a build error in mcount.S when CONFIG_PRINTK is not enabled. Fixes this build error: sh2-linux-ld: arch/sh/lib/mcount.o: in function `stack_panic': (.text+0xec): undefined reference to `dump_stack' Fixes: e460ab27b6c3 ("sh: Fix up stack overflow check with ftrace disabled.") Signed-off-by: Randy Dunlap Cc: John Paul Adrian Glaubitz Cc: Yoshinori Sato Cc: Rich Felker Suggested-by: Geert Uytterhoeven Cc: stable@vger.kernel.org Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230306040037.20350-8-rdunlap@infradead.org Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 10290e5c1f43..c449e7c1b20f 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -15,7 +15,7 @@ config SH_STANDARD_BIOS config STACK_DEBUG bool "Check for stack overflows" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && PRINTK help This option will cause messages to be printed if free stack space drops below a certain limit. Saying Y here will add overhead to From d703e5a6ffa73fba8e9023190c53d4458cc09a06 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Fri, 24 Mar 2023 11:08:48 +0100 Subject: [PATCH 035/182] mips: Remove obsolete configs IRQ_MSP_CIC and IRQ_MSP_SLP Commit 1b00767fd8e1 ("MIPS: Remove PMC MSP71xx platform") removes all uses of the config IRQ_MSP_CIC and IRQ_MSP_SLP. Remove these two obsolete configs IRQ_MSP_CIC and IRQ_MSP_SLP. Signed-off-by: Lukas Bulwahn Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index fd7ed68cdb91..b91086b0ae22 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1164,12 +1164,6 @@ config SYS_SUPPORTS_LITTLE_ENDIAN config MIPS_HUGE_TLB_SUPPORT def_bool HUGETLB_PAGE || TRANSPARENT_HUGEPAGE -config IRQ_MSP_SLP - bool - -config IRQ_MSP_CIC - bool - config IRQ_TXX9 bool From ed6a0b6e9fd78e167d0488331d1695c6c84192be Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sun, 19 Mar 2023 11:31:48 -0500 Subject: [PATCH 036/182] MIPS: octeon: Use of_address_to_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace of_get_address() and of_translate_address() calls with single call to of_address_to_resource(). Signed-off-by: Rob Herring Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/octeon-irq.c | 35 ++++++++++++---------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index fd8043f6ff8a..064e2409377a 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -2290,7 +2290,7 @@ static irqreturn_t octeon_irq_cib_handler(int my_irq, void *data) static int __init octeon_irq_init_cib(struct device_node *ciu_node, struct device_node *parent) { - const __be32 *addr; + struct resource res; u32 val; struct octeon_irq_cib_host_data *host_data; int parent_irq; @@ -2309,21 +2309,19 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, return -ENOMEM; raw_spin_lock_init(&host_data->lock); - addr = of_get_address(ciu_node, 0, NULL, NULL); - if (!addr) { + r = of_address_to_resource(ciu_node, 0, &res); + if (r) { pr_err("ERROR: Couldn't acquire reg(0) %pOFn\n", ciu_node); - return -EINVAL; + return r; } - host_data->raw_reg = (u64)phys_to_virt( - of_translate_address(ciu_node, addr)); + host_data->raw_reg = (u64)phys_to_virt(res.start); - addr = of_get_address(ciu_node, 1, NULL, NULL); - if (!addr) { + r = of_address_to_resource(ciu_node, 1, &res); + if (r) { pr_err("ERROR: Couldn't acquire reg(1) %pOFn\n", ciu_node); - return -EINVAL; + return r; } - host_data->en_reg = (u64)phys_to_virt( - of_translate_address(ciu_node, addr)); + host_data->en_reg = (u64)phys_to_virt(res.start); r = of_property_read_u32(ciu_node, "cavium,max-bits", &val); if (r) { @@ -2874,11 +2872,11 @@ static struct irq_chip octeon_irq_chip_ciu3_mbox = { static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, struct device_node *parent) { - int i; + int i, ret; int node; struct irq_domain *domain; struct octeon_ciu3_info *ciu3_info; - const __be32 *zero_addr; + struct resource res; u64 base_addr; union cvmx_ciu3_const consts; @@ -2888,14 +2886,11 @@ static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, if (!ciu3_info) return -ENOMEM; - zero_addr = of_get_address(ciu_node, 0, NULL, NULL); - if (WARN_ON(!zero_addr)) - return -EINVAL; + ret = of_address_to_resource(ciu_node, 0, &res); + if (WARN_ON(ret)) + return ret; - base_addr = of_translate_address(ciu_node, zero_addr); - base_addr = (u64)phys_to_virt(base_addr); - - ciu3_info->ciu3_addr = base_addr; + ciu3_info->ciu3_addr = base_addr = phys_to_virt(res.start); ciu3_info->node = node; consts.u64 = cvmx_read_csr(base_addr + CIU3_CONST); From 6be87d61c427e63c33d9cea8dc2e20cd06700882 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Wed, 22 Feb 2023 13:24:23 +0000 Subject: [PATCH 037/182] MIPS: Always select ARCH_HAS_SETUP_DMA_OPS arch_setup_dma_ops on MIPS sets coherency information in struct device. It's essential for per-device coherency to work. Select it for all non-coherent platforms. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b91086b0ae22..fa72d906916f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -134,7 +134,6 @@ choice config MIPS_GENERIC_KERNEL bool "Generic board-agnostic MIPS kernel" - select ARCH_HAS_SETUP_DMA_OPS select MIPS_GENERIC select BOOT_RAW select BUILTIN_DTB @@ -1069,6 +1068,7 @@ config DMA_NONCOHERENT # by pgprot_writcombine can be mixed, and the latter sometimes provides # significant advantages. # + select ARCH_HAS_SETUP_DMA_OPS select ARCH_HAS_DMA_WRITE_COMBINE select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_SYNC_DMA_FOR_DEVICE From e0b7fd1207a8ec47091439fb62dd87ca6f5b4ad3 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Wed, 22 Feb 2023 13:24:24 +0000 Subject: [PATCH 038/182] MIPS: Always select ARCH_HAS_SYNC_DMA_FOR_CPU for noncoherent platforms As now we are telling the necessity of post DMA flush per CPU type, there is no need to select ARCH_HAS_SYNC_DMA_FOR_CPU on per platform bias, just select it unconditionally and we can sort it at runtime. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index fa72d906916f..2082efdb411b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -115,7 +115,6 @@ config MACH_INGENIC select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_ZBOOT select DMA_NONCOHERENT - select ARCH_HAS_SYNC_DMA_FOR_CPU select IRQ_MIPS_CPU select PINCTRL select GPIOLIB @@ -1071,6 +1070,7 @@ config DMA_NONCOHERENT select ARCH_HAS_SETUP_DMA_OPS select ARCH_HAS_DMA_WRITE_COMBINE select ARCH_HAS_DMA_PREP_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_DMA_SET_UNCACHED select DMA_NONCOHERENT_MMAP @@ -1828,11 +1828,9 @@ config SYS_HAS_CPU_MIPS32_R3_5 config SYS_HAS_CPU_MIPS32_R5 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_MIPS32_R6 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_MIPS64_R1 bool @@ -1842,15 +1840,12 @@ config SYS_HAS_CPU_MIPS64_R2 config SYS_HAS_CPU_MIPS64_R5 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_MIPS64_R6 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_P5600 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_R3000 bool @@ -1875,7 +1870,6 @@ config SYS_HAS_CPU_NEVADA config SYS_HAS_CPU_R10000 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_RM7000 bool @@ -1904,7 +1898,6 @@ config SYS_HAS_CPU_BMIPS4380 config SYS_HAS_CPU_BMIPS5000 bool select SYS_HAS_CPU_BMIPS - select ARCH_HAS_SYNC_DMA_FOR_CPU # # CPU may reorder R->R, R->W, W->R, W->W From 600efe35d54961dd026f04c6ea5b4074b3284c87 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Wed, 22 Feb 2023 13:24:25 +0000 Subject: [PATCH 039/182] MIPS: c-r4k: Always install dma flush functions As nowadays DMA coherence is managed per device, it is possible to have a system that is defaulted to coherent dma but still have noncoherent device that needs to use those flush functions. Just install them unconditionally. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/mm/c-r4k.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index a549fa98c2f4..7d447050a20b 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1867,15 +1867,9 @@ void r4k_cache_init(void) __local_flush_icache_user_range = local_r4k_flush_icache_user_range; #ifdef CONFIG_DMA_NONCOHERENT - if (dma_default_coherent) { - _dma_cache_wback_inv = (void *)cache_noop; - _dma_cache_wback = (void *)cache_noop; - _dma_cache_inv = (void *)cache_noop; - } else { - _dma_cache_wback_inv = r4k_dma_cache_wback_inv; - _dma_cache_wback = r4k_dma_cache_wback_inv; - _dma_cache_inv = r4k_dma_cache_inv; - } + _dma_cache_wback_inv = r4k_dma_cache_wback_inv; + _dma_cache_wback = r4k_dma_cache_wback_inv; + _dma_cache_inv = r4k_dma_cache_inv; #endif /* CONFIG_DMA_NONCOHERENT */ build_clear_page(); From b69edab47f1da8edd8e7bfdf8c70f51a2a5d89fb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 2 Mar 2023 14:49:50 -0800 Subject: [PATCH 040/182] kheaders: Use array declaration instead of char Under CONFIG_FORTIFY_SOURCE, memcpy() will check the size of destination and source buffers. Defining kernel_headers_data as "char" would trip this check. Since these addresses are treated as byte arrays, define them as arrays (as done everywhere else). This was seen with: $ cat /sys/kernel/kheaders.tar.xz >> /dev/null detected buffer overflow in memcpy kernel BUG at lib/string_helpers.c:1027! ... RIP: 0010:fortify_panic+0xf/0x20 [...] Call Trace: ikheaders_read+0x45/0x50 [kheaders] kernfs_fop_read_iter+0x1a4/0x2f0 ... Reported-by: Jakub Kicinski Link: https://lore.kernel.org/bpf/20230302112130.6e402a98@kernel.org/ Acked-by: Joel Fernandes (Google) Reviewed-by: Alexander Lobakin Tested-by: Jakub Kicinski Fixes: 43d8ce9d65a5 ("Provide in-kernel headers to make extending kernel easier") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230302224946.never.243-kees@kernel.org --- kernel/kheaders.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/kheaders.c b/kernel/kheaders.c index 8f69772af77b..42163c9e94e5 100644 --- a/kernel/kheaders.c +++ b/kernel/kheaders.c @@ -26,15 +26,15 @@ asm ( " .popsection \n" ); -extern char kernel_headers_data; -extern char kernel_headers_data_end; +extern char kernel_headers_data[]; +extern char kernel_headers_data_end[]; static ssize_t ikheaders_read(struct file *file, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t len) { - memcpy(buf, &kernel_headers_data + off, len); + memcpy(buf, &kernel_headers_data[off], len); return len; } @@ -48,8 +48,8 @@ static struct bin_attribute kheaders_attr __ro_after_init = { static int __init ikheaders_init(void) { - kheaders_attr.size = (&kernel_headers_data_end - - &kernel_headers_data); + kheaders_attr.size = (kernel_headers_data_end - + kernel_headers_data); return sysfs_create_bin_file(kernel_kobj, &kheaders_attr); } From 101f26c72825c5dba1dfe826e4202a9a04b435c6 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 27 Mar 2023 10:35:22 +0200 Subject: [PATCH 041/182] MIPS: octeon: Fix compile error Commit ed6a0b6e9fd7 ("MIPS: octeon: Use of_address_to_resource()") lost a cast, which causes a compile error. Fixes: ed6a0b6e9fd7 ("MIPS: octeon: Use of_address_to_resource()") Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/octeon-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 064e2409377a..8425a6b38aa2 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -2890,7 +2890,7 @@ static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, if (WARN_ON(ret)) return ret; - ciu3_info->ciu3_addr = base_addr = phys_to_virt(res.start); + ciu3_info->ciu3_addr = base_addr = (u64)phys_to_virt(res.start); ciu3_info->node = node; consts.u64 = cvmx_read_csr(base_addr + CIU3_CONST); From 393a759647061bc29c1d62f83c7d36cacc912a89 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:40 +0100 Subject: [PATCH 042/182] MIPS: Move declaration of bcache ops to cache.c bcache is not tied to CPU's cache interface. Just move those declaration to cache.c so it can be avaialble to CPU with all cache types. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/cache.h | 2 ++ arch/mips/mm/c-r4k.c | 14 -------------- arch/mips/mm/cache.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 29187e12b861..3424a7908c0f 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -16,4 +16,6 @@ #define __read_mostly __section(".data..read_mostly") +extern void cache_noop(void); + #endif /* _ASM_CACHE_H */ diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 7d447050a20b..5599b9c9a737 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -110,20 +110,6 @@ static unsigned long dcache_size __read_mostly; static unsigned long vcache_size __read_mostly; static unsigned long scache_size __read_mostly; -/* - * Dummy cache handling routines for machines without boardcaches - */ -static void cache_noop(void) {} - -static struct bcache_ops no_sc_ops = { - .bc_enable = (void *)cache_noop, - .bc_disable = (void *)cache_noop, - .bc_wback_inv = (void *)cache_noop, - .bc_inv = (void *)cache_noop -}; - -struct bcache_ops *bcops = &no_sc_ops; - #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) #define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 11b3e7ddafd5..7dba4b5c02c3 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,24 @@ EXPORT_SYMBOL_GPL(local_flush_data_cache_page); EXPORT_SYMBOL(flush_data_cache_page); EXPORT_SYMBOL(flush_icache_all); +/* + * Dummy cache handling routine + */ + +void cache_noop(void) {} + +#ifdef CONFIG_BOARD_SCACHE + +static struct bcache_ops no_sc_ops = { + .bc_enable = (void *)cache_noop, + .bc_disable = (void *)cache_noop, + .bc_wback_inv = (void *)cache_noop, + .bc_inv = (void *)cache_noop +}; + +struct bcache_ops *bcops = &no_sc_ops; +#endif + #ifdef CONFIG_DMA_NONCOHERENT /* DMA cache operations. */ From aa45787c0db0a5f7b21bd16b917ff44761a2c6ac Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:41 +0100 Subject: [PATCH 043/182] MIPS: smp-cps: Disable coherence setup for unsupported ISA We don't know how to do coherence setup on ISA before MIPS Release 1. As CPS support only servers simulation purpose on those cores, and simulators are always coherent, just disable initialization code and provide user a warning in case coherence is not setup properly. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/cps-vec.S | 5 +++++ arch/mips/kernel/smp-cps.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 8ef492da827f..64ecfdac6580 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -116,6 +116,8 @@ not_nmi: li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS + /* We don't know how to do coherence setup on earlier ISA */ +#if MIPS_ISA_REV > 0 /* Skip cache & coherence setup if we're already coherent */ lw s7, GCR_CL_COHERENCE_OFS(s1) bnez s7, 1f @@ -129,6 +131,7 @@ not_nmi: li t0, 0xff sw t0, GCR_CL_COHERENCE_OFS(s1) ehb +#endif /* MIPS_ISA_REV > 0 */ /* Set Kseg0 CCA to that in s0 */ 1: mfc0 t0, CP0_CONFIG @@ -515,6 +518,7 @@ LEAF(mips_cps_boot_vpes) nop END(mips_cps_boot_vpes) +#if MIPS_ISA_REV > 0 LEAF(mips_cps_cache_init) /* * Clear the bits used to index the caches. Note that the architecture @@ -588,6 +592,7 @@ dcache_done: jr ra nop END(mips_cps_cache_init) +#endif /* MIPS_ISA_REV > 0 */ #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 4fc288bb85b9..f968a319d87f 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -361,6 +361,8 @@ out: static void cps_init_secondary(void) { + int core = cpu_core(¤t_cpu_data); + /* Disable MT - we only want to run 1 TC per VPE */ if (cpu_has_mipsmt) dmt(); @@ -376,6 +378,9 @@ static void cps_init_secondary(void) BUG_ON(ident != mips_cm_vp_id(smp_processor_id())); } + if (core > 0 && !read_gcr_cl_coherence()) + pr_warn("Core %u is not in coherent domain\n", core); + if (cpu_has_veic) clear_c0_status(ST0_IM); else From e1aa1dfef69320141f5d00eddbf279b41e70d4e7 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:42 +0100 Subject: [PATCH 044/182] MIPS: mips-cm: Check availability of config registers Prevent reading unsupported config register during probing process. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/mips-cm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index b4f7d950c846..3f00788b0871 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -181,11 +181,16 @@ static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); phys_addr_t __mips_cm_phys_base(void) { - u32 config3 = read_c0_config3(); unsigned long cmgcr; /* Check the CMGCRBase register is implemented */ - if (!(config3 & MIPS_CONF3_CMGCR)) + if (!(read_c0_config() & MIPS_CONF_M)) + return 0; + + if (!(read_c0_config2() & MIPS_CONF_M)) + return 0; + + if (!(read_c0_config3() & MIPS_CONF3_CMGCR)) return 0; /* Read the address from CMGCRBase */ From 918d779569dafd81fce4257c552aa4205c918c4a Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:43 +0100 Subject: [PATCH 045/182] MIPS: Octeon: Opt-out 4k_cache feature Octeon has a different cache interface with traditional R4K one, just opt-out this flag for octeon to avoid run R4K cache initialization code accidentally. Also remove ISA level assumption for 4k cache. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/cpu-features.h | 2 +- arch/mips/kernel/cpu-probe.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index c0983130a44c..c613426b0bfc 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -118,7 +118,7 @@ #define cpu_has_3k_cache __isa_lt_and_opt(1, MIPS_CPU_3K_CACHE) #endif #ifndef cpu_has_4k_cache -#define cpu_has_4k_cache __isa_ge_or_opt(1, MIPS_CPU_4K_CACHE) +#define cpu_has_4k_cache __opt(MIPS_CPU_4K_CACHE) #endif #ifndef cpu_has_octeon_cache #define cpu_has_octeon_cache 0 diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 7ddf07f255f3..6d15a398d389 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1602,6 +1602,8 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); + /* Octeon has different cache interface */ + c->options &= ~MIPS_CPU_4K_CACHE; switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_CAVIUM_CN38XX: case PRID_IMP_CAVIUM_CN31XX: From f641519409a73403ee6612b8648b95a688ab85c2 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:44 +0100 Subject: [PATCH 046/182] MIPS: cpu-features: Enable octeon_cache by cpu_type cpu_has_octeon_cache was tied to 0 for generic cpu-features, whith this generic kernel built for octeon CPU won't boot. Just enable this flag by cpu_type. It won't hurt orther platforms because compiler will eliminate the code path on other processors. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/cpu-features.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index c613426b0bfc..51a1737b03d0 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -121,7 +121,24 @@ #define cpu_has_4k_cache __opt(MIPS_CPU_4K_CACHE) #endif #ifndef cpu_has_octeon_cache -#define cpu_has_octeon_cache 0 +#define cpu_has_octeon_cache \ +({ \ + int __res; \ + \ + switch (current_cpu_type()) { \ + case CPU_CAVIUM_OCTEON: \ + case CPU_CAVIUM_OCTEON_PLUS: \ + case CPU_CAVIUM_OCTEON2: \ + case CPU_CAVIUM_OCTEON3: \ + __res = 1; \ + break; \ + \ + default: \ + __res = 0; \ + } \ + \ + __res; \ +}) #endif /* Don't override `cpu_has_fpu' to 1 or the "nofpu" option won't work. */ #ifndef cpu_has_fpu From 6e90049162b92e683641966e4cdc67febe3c8fc5 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:45 +0100 Subject: [PATCH 047/182] MIPS: c-octeon: Provide alternative SMP cache flush function Currently c-octeon relies on octeon's own smp function to flush I-Cache. However this function is not available on generic platform. Just use smp_call_function_many on generic platform. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/mm/c-octeon.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index c7ed589de882..b7393b61cfa7 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -83,8 +83,13 @@ static void octeon_flush_icache_all_cores(struct vm_area_struct *vma) else mask = *cpu_online_mask; cpumask_clear_cpu(cpu, &mask); +#ifdef CONFIG_CAVIUM_OCTEON_SOC for_each_cpu(cpu, &mask) octeon_send_ipi_single(cpu, SMP_ICACHE_FLUSH); +#else + smp_call_function_many(&mask, (smp_call_func_t)octeon_local_flush_icache, + NULL, 1); +#endif preempt_enable(); #endif From b6007ff809682350515936539eb91a2e8a5f799c Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:46 +0100 Subject: [PATCH 048/182] MIPS: Octeon: Allow CVMSEG to be disabled Don't include cvmseg states into thread_status when CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE is not defined or 0. Fix compile for kernel without this feature. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/processor.h | 7 ++++++- arch/mips/kernel/asm-offsets.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 3fde1ff72bd1..ae2cd37a38f0 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -202,11 +202,13 @@ struct octeon_cop2_state { #define COP2_INIT \ .cp2 = {0,}, +#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ + CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 struct octeon_cvmseg_state { unsigned long cvmseg[CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE] [cpu_dcache_line_size() / sizeof(unsigned long)]; }; - +#endif #else #define COP2_INIT #endif @@ -263,7 +265,10 @@ struct thread_struct { unsigned long trap_nr; #ifdef CONFIG_CPU_CAVIUM_OCTEON struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); +#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ + CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); +#endif #endif struct mips_abi *abi; }; diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index c4501897b870..40fd4051bb3d 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -306,7 +306,10 @@ void output_octeon_cop2_state_defines(void) OFFSET(OCTEON_CP2_HSH_IVW, octeon_cop2_state, cop2_hsh_ivw); OFFSET(OCTEON_CP2_SHA3, octeon_cop2_state, cop2_sha3); OFFSET(THREAD_CP2, task_struct, thread.cp2); +#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ + CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 OFFSET(THREAD_CVMSEG, task_struct, thread.cvmseg.cvmseg); +#endif BLANK(); } #endif From 194a835210521282ad31e8f7047556318611f596 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:47 +0100 Subject: [PATCH 049/182] MIPS: Loongson: Move arch cflags to MIPS top level Makefile Arch cflags should be independent to Platform. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 38 ++++++++++++++++++++++++++++++++++ arch/mips/loongson2ef/Platform | 35 ------------------------------- arch/mips/loongson64/Platform | 16 -------------- 3 files changed, 38 insertions(+), 51 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 04e46ec24319..a7a4ee66a9d3 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -181,9 +181,47 @@ endif cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2E) += -march=loongson2e -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2F) += -march=loongson2f -Wa,--trap +# Some -march= flags enable MMI instructions, and GCC complains about that +# support being enabled alongside -msoft-float. Thus explicitly disable MMI. +cflags-$(CONFIG_CPU_LOONGSON2EF) += $(call cc-option,-mno-loongson-mmi) +ifdef CONFIG_CPU_LOONGSON64 +cflags-$(CONFIG_CPU_LOONGSON64) += -Wa,--trap +cflags-$(CONFIG_CC_IS_GCC) += -march=loongson3a +cflags-$(CONFIG_CC_IS_CLANG) += -march=mips64r2 +endif +cflags-$(CONFIG_CPU_LOONGSON64) += $(call cc-option,-mno-loongson-mmi) + cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,) +ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS +cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa,-mfix-loongson2f-nop +cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa,-mfix-loongson2f-jump +endif + +# +# Some versions of binutils, not currently mainline as of 2019/02/04, support +# an -mfix-loongson3-llsc flag which emits a sync prior to each ll instruction +# to work around a CPU bug (see __SYNC_loongson3_war in asm/sync.h for a +# description). +# +# We disable this in order to prevent the assembler meddling with the +# instruction that labels refer to, ie. if we label an ll instruction: +# +# 1: ll v0, 0(a0) +# +# ...then with the assembler fix applied the label may actually point at a sync +# instruction inserted by the assembler, and if we were using the label in an +# exception table the table would no longer contain the address of the ll +# instruction. +# +# Avoid this by explicitly disabling that assembler behaviour. If upstream +# binutils does not merge support for the flag then we can revisit & remove +# this later - for now it ensures vendor toolchains don't cause problems. +# +cflags-$(CONFIG_CPU_LOONGSON64) += $(call as-option,-Wa$(comma)-mno-fix-loongson3-llsc,) # For smartmips configurations, there are hundreds of warnings due to ISA overrides # in assembly and header files. smartmips is only supported for MIPS32r1 onwards diff --git a/arch/mips/loongson2ef/Platform b/arch/mips/loongson2ef/Platform index c6f7a4b95997..d446b705fba4 100644 --- a/arch/mips/loongson2ef/Platform +++ b/arch/mips/loongson2ef/Platform @@ -2,41 +2,6 @@ # Loongson Processors' Support # -cflags-$(CONFIG_CPU_LOONGSON2EF) += -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON2E) += -march=loongson2e -cflags-$(CONFIG_CPU_LOONGSON2F) += -march=loongson2f -# -# Some versions of binutils, not currently mainline as of 2019/02/04, support -# an -mfix-loongson3-llsc flag which emits a sync prior to each ll instruction -# to work around a CPU bug (see __SYNC_loongson3_war in asm/sync.h for a -# description). -# -# We disable this in order to prevent the assembler meddling with the -# instruction that labels refer to, ie. if we label an ll instruction: -# -# 1: ll v0, 0(a0) -# -# ...then with the assembler fix applied the label may actually point at a sync -# instruction inserted by the assembler, and if we were using the label in an -# exception table the table would no longer contain the address of the ll -# instruction. -# -# Avoid this by explicitly disabling that assembler behaviour. If upstream -# binutils does not merge support for the flag then we can revisit & remove -# this later - for now it ensures vendor toolchains don't cause problems. -# -cflags-$(CONFIG_CPU_LOONGSON2EF) += $(call cc-option,-Wa$(comma)-mno-fix-loongson3-llsc,) - -# Enable the workarounds for Loongson2f -ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS -cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa,-mfix-loongson2f-nop -cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa,-mfix-loongson2f-jump -endif - -# Some -march= flags enable MMI instructions, and GCC complains about that -# support being enabled alongside -msoft-float. Thus explicitly disable MMI. -cflags-y += $(call cc-option,-mno-loongson-mmi) - # # Loongson Machines' Support # diff --git a/arch/mips/loongson64/Platform b/arch/mips/loongson64/Platform index 473404cae1c4..49c9889e3d56 100644 --- a/arch/mips/loongson64/Platform +++ b/arch/mips/loongson64/Platform @@ -1,19 +1,3 @@ -# -# Loongson Processors' Support -# - - -cflags-$(CONFIG_CPU_LOONGSON64) += -Wa,--trap - -ifdef CONFIG_CPU_LOONGSON64 -cflags-$(CONFIG_CC_IS_GCC) += -march=loongson3a -cflags-$(CONFIG_CC_IS_CLANG) += -march=mips64r2 -endif - -# Some -march= flags enable MMI instructions, and GCC complains about that -# support being enabled alongside -msoft-float. Thus explicitly disable MMI. -cflags-y += $(call cc-option,-mno-loongson-mmi) - # # Loongson Machines' Support # From 0c6ff92773a9c004c44af47b0609f67dcc97ba82 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:48 +0100 Subject: [PATCH 050/182] MIPS: Loongson: Don't select platform features with CPU ARCH_HAS_PHYS_TO_DMA and GPIOLIB are all platform level features they shouldn't be selected with CPU. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 2 -- arch/mips/loongson2ef/Kconfig | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 2082efdb411b..54a6ba91226e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1341,7 +1341,6 @@ config CPU_LOONGSON2F bool "Loongson 2F" depends on SYS_HAS_CPU_LOONGSON2F select CPU_LOONGSON2EF - select GPIOLIB help The Loongson 2F processor implements the MIPS III instruction set with many extensions. @@ -1763,7 +1762,6 @@ config CPU_LOONGSON2EF select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES - select ARCH_HAS_PHYS_TO_DMA config CPU_LOONGSON32 bool diff --git a/arch/mips/loongson2ef/Kconfig b/arch/mips/loongson2ef/Kconfig index 96dc6eba4310..f93eb6f42238 100644 --- a/arch/mips/loongson2ef/Kconfig +++ b/arch/mips/loongson2ef/Kconfig @@ -7,6 +7,7 @@ choice config LEMOTE_FULOONG2E bool "Lemote Fuloong(2e) mini-PC" select ARCH_SPARSEMEM_ENABLE + select ARCH_HAS_PHYS_TO_DMA select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select CEVT_R4K @@ -36,6 +37,7 @@ config LEMOTE_FULOONG2E config LEMOTE_MACH2F bool "Lemote Loongson 2F family machines" select ARCH_SPARSEMEM_ENABLE + select ARCH_HAS_PHYS_TO_DMA select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select BOARD_SCACHE @@ -46,6 +48,7 @@ config LEMOTE_MACH2F select CSRC_R4K if ! MIPS_EXTERNAL_TIMER select DMA_NONCOHERENT select GENERIC_ISA_DMA_SUPPORT_BROKEN + select GPIOLIB select FORCE_PCI select I8259 select IRQ_MIPS_CPU From 78073b8f1ffe4085309808815746403209bfd6bc Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:49 +0100 Subject: [PATCH 051/182] MIPS: Octeon: Disable CVMSEG by default on other platforms QEMU can't emulate CVMSEG on generic platform for now. Just disable it by default. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index c1899f109e19..450e979ef5d9 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig @@ -14,7 +14,8 @@ config CAVIUM_CN63XXP1 config CAVIUM_OCTEON_CVMSEG_SIZE int "Number of L1 cache lines reserved for CVMSEG memory" range 0 54 - default 1 + default 0 if !CAVIUM_OCTEON_SOC + default 1 if CAVIUM_OCTEON_SOC help CVMSEG LM is a segment that accesses portions of the dcache as a local memory; the larger CVMSEG is, the smaller the cache is. From 03be534e1bac6d92cbcebdddfc4242e1e3588350 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:50 +0100 Subject: [PATCH 052/182] MIPS: Add board config for virt board Aligned with QEMU MIPS virt board. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/configs/generic/board-virt.config | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 arch/mips/configs/generic/board-virt.config diff --git a/arch/mips/configs/generic/board-virt.config b/arch/mips/configs/generic/board-virt.config new file mode 100644 index 000000000000..5594f9e5c3a8 --- /dev/null +++ b/arch/mips/configs/generic/board-virt.config @@ -0,0 +1,38 @@ +CONFIG_COMMON_CLK=y + +CONFIG_GOLDFISH=y +CONFIG_GOLDFISH_PIC=y + +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_HOST_GENERIC=y + +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_SYSCON_REBOOT_MODE=y + +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y + +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y + +CONFIG_MTD=y +CONFIG_MTD_CFI=y + +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_XHCI_HCD=y + +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_NET=y +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y From de34007751aaba992373f2d659001a846aeb8811 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 4 Apr 2023 10:33:51 +0100 Subject: [PATCH 053/182] MIPS: generic: Enable all CPUs supported by virt board in Kconfig Enable extra CPUs that may be supported by virt board, including R4x00 (R4000 in QEMU), Cavium Octeon (Octeon68XX in QEMU), loongson2e, loongson2f. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 54a6ba91226e..a975f140ae82 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -153,12 +153,16 @@ config MIPS_GENERIC_KERNEL select PCI_DRIVERS_GENERIC select SMP_UP if SMP select SWAP_IO_SPACE + select SYS_HAS_CPU_CAVIUM_OCTEON + select SYS_HAS_CPU_LOONGSON2E + select SYS_HAS_CPU_LOONGSON2F select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 select SYS_HAS_CPU_MIPS32_R6 select SYS_HAS_CPU_MIPS64_R1 select SYS_HAS_CPU_MIPS64_R2 select SYS_HAS_CPU_MIPS64_R6 + select SYS_HAS_CPU_R4X00 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN From db9947cea855eb0b0cbf9724a3aa69f7b39b3d73 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 3 Apr 2023 11:41:10 +0200 Subject: [PATCH 054/182] MIPS: mm: Remove unused *cache_page_indexed flush functions The *cache_page_indexed flush functions are no (longer) used. Signed-off-by: Thomas Bogendoerfer --- arch/mips/mm/c-r4k.c | 100 ------------------------------------------- 1 file changed, 100 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 5599b9c9a737..dd31b1007919 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -187,24 +187,6 @@ static void r4k_blast_dcache_user_page_setup(void) #endif -static void (* r4k_blast_dcache_page_indexed)(unsigned long addr); - -static void r4k_blast_dcache_page_indexed_setup(void) -{ - unsigned long dc_lsize = cpu_dcache_line_size(); - - if (dc_lsize == 0) - r4k_blast_dcache_page_indexed = (void *)cache_noop; - else if (dc_lsize == 16) - r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed; - else if (dc_lsize == 32) - r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed; - else if (dc_lsize == 64) - r4k_blast_dcache_page_indexed = blast_dcache64_page_indexed; - else if (dc_lsize == 128) - r4k_blast_dcache_page_indexed = blast_dcache128_page_indexed; -} - void (* r4k_blast_dcache)(void); EXPORT_SYMBOL(r4k_blast_dcache); @@ -266,39 +248,6 @@ static inline void tx49_blast_icache32(void) addr | ws, 32); } -static inline void blast_icache32_r4600_v1_page_indexed(unsigned long page) -{ - unsigned long flags; - - local_irq_save(flags); - blast_icache32_page_indexed(page); - local_irq_restore(flags); -} - -static inline void tx49_blast_icache32_page_indexed(unsigned long page) -{ - unsigned long indexmask = current_cpu_data.icache.waysize - 1; - unsigned long start = INDEX_BASE + (page & indexmask); - unsigned long end = start + PAGE_SIZE; - unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; - unsigned long ws_end = current_cpu_data.icache.ways << - current_cpu_data.icache.waybit; - unsigned long ws, addr; - - CACHE32_UNROLL32_ALIGN2; - /* I'm in even chunk. blast odd chunks */ - for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start + 0x400; addr < end; addr += 0x400 * 2) - cache_unroll(32, kernel_cache, Index_Invalidate_I, - addr | ws, 32); - CACHE32_UNROLL32_ALIGN; - /* I'm in odd chunk. blast even chunks */ - for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start; addr < end; addr += 0x400 * 2) - cache_unroll(32, kernel_cache, Index_Invalidate_I, - addr | ws, 32); -} - static void (* r4k_blast_icache_page)(unsigned long addr); static void r4k_blast_icache_page_setup(void) @@ -341,34 +290,6 @@ static void r4k_blast_icache_user_page_setup(void) #endif -static void (* r4k_blast_icache_page_indexed)(unsigned long addr); - -static void r4k_blast_icache_page_indexed_setup(void) -{ - unsigned long ic_lsize = cpu_icache_line_size(); - - if (ic_lsize == 0) - r4k_blast_icache_page_indexed = (void *)cache_noop; - else if (ic_lsize == 16) - r4k_blast_icache_page_indexed = blast_icache16_page_indexed; - else if (ic_lsize == 32) { - if (IS_ENABLED(CONFIG_WAR_R4600_V1_INDEX_ICACHEOP) && - cpu_is_r4600_v1_x()) - r4k_blast_icache_page_indexed = - blast_icache32_r4600_v1_page_indexed; - else if (IS_ENABLED(CONFIG_WAR_TX49XX_ICACHE_INDEX_INV)) - r4k_blast_icache_page_indexed = - tx49_blast_icache32_page_indexed; - else if (current_cpu_type() == CPU_LOONGSON2EF) - r4k_blast_icache_page_indexed = - loongson2_blast_icache32_page_indexed; - else - r4k_blast_icache_page_indexed = - blast_icache32_page_indexed; - } else if (ic_lsize == 64) - r4k_blast_icache_page_indexed = blast_icache64_page_indexed; -} - void (* r4k_blast_icache)(void); EXPORT_SYMBOL(r4k_blast_icache); @@ -414,24 +335,6 @@ static void r4k_blast_scache_page_setup(void) r4k_blast_scache_page = blast_scache128_page; } -static void (* r4k_blast_scache_page_indexed)(unsigned long addr); - -static void r4k_blast_scache_page_indexed_setup(void) -{ - unsigned long sc_lsize = cpu_scache_line_size(); - - if (scache_size == 0) - r4k_blast_scache_page_indexed = (void *)cache_noop; - else if (sc_lsize == 16) - r4k_blast_scache_page_indexed = blast_scache16_page_indexed; - else if (sc_lsize == 32) - r4k_blast_scache_page_indexed = blast_scache32_page_indexed; - else if (sc_lsize == 64) - r4k_blast_scache_page_indexed = blast_scache64_page_indexed; - else if (sc_lsize == 128) - r4k_blast_scache_page_indexed = blast_scache128_page_indexed; -} - static void (* r4k_blast_scache)(void); static void r4k_blast_scache_setup(void) @@ -1807,13 +1710,10 @@ void r4k_cache_init(void) setup_scache(); r4k_blast_dcache_page_setup(); - r4k_blast_dcache_page_indexed_setup(); r4k_blast_dcache_setup(); r4k_blast_icache_page_setup(); - r4k_blast_icache_page_indexed_setup(); r4k_blast_icache_setup(); r4k_blast_scache_page_setup(); - r4k_blast_scache_page_indexed_setup(); r4k_blast_scache_setup(); r4k_blast_scache_node_setup(); #ifdef CONFIG_EVA From 461ba3e7e663a5c87e7b388b073904149b199593 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 3 Apr 2023 11:41:11 +0200 Subject: [PATCH 055/182] MIPS: Remove no longer used ide.h There are only three drivers left using ide.h, which are all m68k only. Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/ide.h | 13 --- arch/mips/include/asm/mach-generic/ide.h | 138 ----------------------- 2 files changed, 151 deletions(-) delete mode 100644 arch/mips/include/asm/ide.h delete mode 100644 arch/mips/include/asm/mach-generic/ide.h diff --git a/arch/mips/include/asm/ide.h b/arch/mips/include/asm/ide.h deleted file mode 100644 index bb674c3b0303..000000000000 --- a/arch/mips/include/asm/ide.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * This file contains the MIPS architecture specific IDE code. - */ -#ifndef __ASM_IDE_H -#define __ASM_IDE_H - -#include - -#endif /* __ASM_IDE_H */ diff --git a/arch/mips/include/asm/mach-generic/ide.h b/arch/mips/include/asm/mach-generic/ide.h deleted file mode 100644 index 4ae5fbcb15a5..000000000000 --- a/arch/mips/include/asm/mach-generic/ide.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1994-1996 Linus Torvalds & authors - * - * Copied from i386; many of the especially older MIPS or ISA-based platforms - * are basically identical. Using this file probably implies i8259 PIC - * support in a system but the very least interrupt numbers 0 - 15 need to - * be put aside for legacy devices. - */ -#ifndef __ASM_MACH_GENERIC_IDE_H -#define __ASM_MACH_GENERIC_IDE_H - -#ifdef __KERNEL__ - -#include -#include -#include - -/* MIPS port and memory-mapped I/O string operations. */ -static inline void __ide_flush_prologue(void) -{ -#ifdef CONFIG_SMP - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) - preempt_disable(); -#endif -} - -static inline void __ide_flush_epilogue(void) -{ -#ifdef CONFIG_SMP - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) - preempt_enable(); -#endif -} - -static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) -{ - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) { - unsigned long end = addr + size; - - while (addr < end) { - local_flush_data_cache_page((void *)addr); - addr += PAGE_SIZE; - } - } -} - -/* - * insw() and gang might be called with interrupts disabled, so we can't - * send IPIs for flushing due to the potencial of deadlocks, see the comment - * above smp_call_function() in arch/mips/kernel/smp.c. We work around the - * problem by disabling preemption so we know we actually perform the flush - * on the processor that actually has the lines to be flushed which hopefully - * is even better for performance anyway. - */ -static inline void __ide_insw(unsigned long port, void *addr, - unsigned int count) -{ - __ide_flush_prologue(); - insw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_insl(unsigned long port, void *addr, unsigned int count) -{ - __ide_flush_prologue(); - insl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -static inline void __ide_outsw(unsigned long port, const void *addr, - unsigned long count) -{ - __ide_flush_prologue(); - outsw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_outsl(unsigned long port, const void *addr, - unsigned long count) -{ - __ide_flush_prologue(); - outsl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count) -{ - __ide_flush_prologue(); - readsw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count) -{ - __ide_flush_prologue(); - readsl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) -{ - __ide_flush_prologue(); - writesw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) -{ - __ide_flush_prologue(); - writesl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -/* ide_insw calls insw, not __ide_insw. Why? */ -#undef insw -#undef insl -#undef outsw -#undef outsl -#define insw(port, addr, count) __ide_insw(port, addr, count) -#define insl(port, addr, count) __ide_insl(port, addr, count) -#define outsw(port, addr, count) __ide_outsw(port, addr, count) -#define outsl(port, addr, count) __ide_outsl(port, addr, count) - -#endif /* __KERNEL__ */ - -#endif /* __ASM_MACH_GENERIC_IDE_H */ From c86df6c0d4fee0028bb208705bcceae548164fde Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 3 Apr 2023 11:41:12 +0200 Subject: [PATCH 056/182] MIPS: mm: Remove local_cache_flush_page After ide.h is gone, there are no users of local_cache_flush_page() left. Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/cacheflush.h | 1 - arch/mips/mm/c-r3k.c | 5 ----- arch/mips/mm/c-r4k.c | 3 --- arch/mips/mm/cache.c | 2 -- 4 files changed, 11 deletions(-) diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index b3dc9c589442..d8d3f80f9fc0 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -110,7 +110,6 @@ extern void copy_from_user_page(struct vm_area_struct *vma, unsigned long len); extern void (*flush_icache_all)(void); -extern void (*local_flush_data_cache_page)(void * addr); extern void (*flush_data_cache_page)(unsigned long addr); /* Run kernel code uncached, useful for cache probing functions. */ diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index df6755ca1892..5869df848fab 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -261,10 +261,6 @@ static void r3k_flush_cache_page(struct vm_area_struct *vma, r3k_flush_icache_range(kaddr, kaddr + PAGE_SIZE); } -static void local_r3k_flush_data_cache_page(void *addr) -{ -} - static void r3k_flush_data_cache_page(unsigned long addr) { } @@ -302,7 +298,6 @@ void r3k_cache_init(void) __flush_kernel_vmap_range = r3k_flush_kernel_vmap_range; - local_flush_data_cache_page = local_r3k_flush_data_cache_page; flush_data_cache_page = r3k_flush_data_cache_page; _dma_cache_wback_inv = r3k_dma_cache_wback_inv; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index dd31b1007919..4b6554b48923 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1745,7 +1745,6 @@ void r4k_cache_init(void) __flush_kernel_vmap_range = r4k_flush_kernel_vmap_range; flush_icache_all = r4k_flush_icache_all; - local_flush_data_cache_page = local_r4k_flush_data_cache_page; flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; local_flush_icache_range = local_r4k_flush_icache_range; @@ -1788,7 +1787,6 @@ void r4k_cache_init(void) /* I$ fills from D$ just by emptying the write buffers */ flush_cache_page = (void *)b5k_instruction_hazard; flush_cache_range = (void *)b5k_instruction_hazard; - local_flush_data_cache_page = (void *)b5k_instruction_hazard; flush_data_cache_page = (void *)b5k_instruction_hazard; flush_icache_range = (void *)b5k_instruction_hazard; local_flush_icache_range = (void *)b5k_instruction_hazard; @@ -1808,7 +1806,6 @@ void r4k_cache_init(void) flush_cache_range = (void *)cache_noop; flush_icache_all = (void *)cache_noop; flush_data_cache_page = (void *)cache_noop; - local_flush_data_cache_page = (void *)cache_noop; break; } } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 7dba4b5c02c3..d21cf8c6cf6c 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -49,11 +49,9 @@ void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size); EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range); /* MIPS specific cache operations */ -void (*local_flush_data_cache_page)(void * addr); void (*flush_data_cache_page)(unsigned long addr); void (*flush_icache_all)(void); -EXPORT_SYMBOL_GPL(local_flush_data_cache_page); EXPORT_SYMBOL(flush_data_cache_page); EXPORT_SYMBOL(flush_icache_all); From 275aca650e76e203e3efc71835d7195e18d2e718 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 4 Apr 2023 14:18:41 -0700 Subject: [PATCH 057/182] MIPS: Drop unused positional parameter in local_irq_{dis,en}able When building with clang's integrated assembler, it points out that the CONFIG_CPU_HAS_DIEI versions of local_irq_enable and local_irq_disable have a named parameter that is not used in the body of the macro and it thinks that $8 is a positional parameter, rather than a register: arch/mips/include/asm/asmmacro.h:48:2: warning: macro defined with named parameters which are not used in macro body, possible positional parameter found in body which will have no effect .macro local_irq_enable reg=$8 ^ The comment above the function that performs this check in LLVM notes that the warning may trigger in this case, even though it is not problematic. It is easy enough to clean this up by just omitting the named parameter for this version of the macro, as it is entirely unused. Reported-by: Nick Desaulniers Link: https://github.com/ClangBuiltLinux/linux/issues/1415 Link: https://github.com/llvm/llvm-project/commit/81c944cadb7f9e55b3517b7423a820e2577b9279 Signed-off-by: Nathan Chancellor Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/asmmacro.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 1c4438f3f2ab..067a635d3bc8 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -45,12 +45,12 @@ #endif #ifdef CONFIG_CPU_HAS_DIEI - .macro local_irq_enable reg=t0 + .macro local_irq_enable ei irq_enable_hazard .endm - .macro local_irq_disable reg=t0 + .macro local_irq_disable di irq_disable_hazard .endm From 045c340c86f8a9d7cb675e179dc6297caa6ebc01 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Wed, 29 Mar 2023 23:03:28 +0200 Subject: [PATCH 058/182] MIPS: lantiq: remove unused function declaration The removed function declaration is a leftover of the old gphy firmware loader, that has been removed in d5103604f78e1afc29e586785af540c82b573f3a. Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 4790cfa190d6..c2e0acb755cd 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -94,9 +94,6 @@ extern __iomem void *ltq_cgu_membase; #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) -/* allow booting xrx200 phys */ -int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr); - /* request a non-gpio and set the PIO config */ #define PMU_PPE BIT(13) extern void ltq_pmu_enable(unsigned int module); From 7fb6f7b0af6742601e0efe315c78c26e88d30ff1 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 5 Apr 2023 20:51:27 +0200 Subject: [PATCH 059/182] MIPS: Remove deprecated CONFIG_MIPS_CMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 5cac93b35c14 ("MIPS: Deprecate CONFIG_MIPS_CMP") deprecated CONFIG_MIPS_CMP and after 9 years it's time to remove it. Signed-off-by: Thomas Bogendoerfer Reviewed-by: Jiaxun Yang Acked-by: Marc Zyngier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 34 +---- arch/mips/include/asm/rtlx.h | 1 - arch/mips/include/asm/smp-ops.h | 16 --- arch/mips/include/asm/vpe.h | 4 - arch/mips/kernel/Makefile | 3 - arch/mips/kernel/rtlx-cmp.c | 122 ------------------ arch/mips/kernel/smp-cmp.c | 148 ---------------------- arch/mips/kernel/vpe-cmp.c | 180 --------------------------- arch/mips/kernel/vpe.c | 2 +- arch/mips/mti-malta/Makefile | 2 - arch/mips/mti-malta/malta-amon.c | 88 ------------- arch/mips/mti-malta/malta-init.c | 2 - arch/mips/mti-malta/malta-platform.c | 2 - arch/mips/ralink/mt7621.c | 2 - drivers/irqchip/irq-mips-gic.c | 26 ---- 15 files changed, 3 insertions(+), 629 deletions(-) delete mode 100644 arch/mips/kernel/rtlx-cmp.c delete mode 100644 arch/mips/kernel/smp-cmp.c delete mode 100644 arch/mips/kernel/vpe-cmp.c delete mode 100644 arch/mips/mti-malta/malta-amon.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a975f140ae82..61fca312a2c5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -568,7 +568,6 @@ config MIPS_MALTA select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_MICROMIPS select SYS_SUPPORTS_MIPS16 - select SYS_SUPPORTS_MIPS_CMP select SYS_SUPPORTS_MIPS_CPS select SYS_SUPPORTS_MULTITHREADING select SYS_SUPPORTS_RELOCATABLE @@ -2270,15 +2269,10 @@ config MIPS_VPE_LOADER Includes a loader for loading an elf relocatable object onto another VPE and running it. -config MIPS_VPE_LOADER_CMP - bool - default "y" - depends on MIPS_VPE_LOADER && MIPS_CMP - config MIPS_VPE_LOADER_MT bool default "y" - depends on MIPS_VPE_LOADER && !MIPS_CMP + depends on MIPS_VPE_LOADER config MIPS_VPE_LOADER_TOM bool "Load VPE program into memory hidden from linux" @@ -2294,31 +2288,10 @@ config MIPS_VPE_APSP_API bool "Enable support for AP/SP API (RTLX)" depends on MIPS_VPE_LOADER -config MIPS_VPE_APSP_API_CMP - bool - default "y" - depends on MIPS_VPE_APSP_API && MIPS_CMP - config MIPS_VPE_APSP_API_MT bool default "y" - depends on MIPS_VPE_APSP_API && !MIPS_CMP - -config MIPS_CMP - bool "MIPS CMP framework support (DEPRECATED)" - depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 - select SMP - select SYNC_R4K - select SYS_SUPPORTS_SMP - select WEAK_ORDERING - default n - help - Select this if you are using a bootloader which implements the "CMP - framework" protocol (ie. YAMON) and want your kernel to make use of - its ability to start secondary CPUs. - - Unless you have a specific need, you should use CONFIG_MIPS_CPS - instead of this. + depends on MIPS_VPE_APSP_API config MIPS_CPS bool "MIPS Coherent Processing System support" @@ -2774,9 +2747,6 @@ config HOTPLUG_CPU config SMP_UP bool -config SYS_SUPPORTS_MIPS_CMP - bool - config SYS_SUPPORTS_MIPS_CPS bool diff --git a/arch/mips/include/asm/rtlx.h b/arch/mips/include/asm/rtlx.h index c1020654876e..a72785b4bbf4 100644 --- a/arch/mips/include/asm/rtlx.h +++ b/arch/mips/include/asm/rtlx.h @@ -81,7 +81,6 @@ struct rtlx_channel { extern struct rtlx_info { unsigned long id; enum rtlx_state state; - int ap_int_pending; /* Status of 0 or 1 for CONFIG_MIPS_CMP only */ struct rtlx_channel channel[RTLX_CHANNELS]; } *rtlx; diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h index 864aea803984..0145bbfb5efb 100644 --- a/arch/mips/include/asm/smp-ops.h +++ b/arch/mips/include/asm/smp-ops.h @@ -80,22 +80,6 @@ static inline int register_up_smp_ops(void) #endif } -static inline int register_cmp_smp_ops(void) -{ -#ifdef CONFIG_MIPS_CMP - extern const struct plat_smp_ops cmp_smp_ops; - - if (!mips_cm_present()) - return -ENODEV; - - register_smp_ops(&cmp_smp_ops); - - return 0; -#else - return -ENODEV; -#endif -} - static inline int register_vsmp_smp_ops(void) { #ifdef CONFIG_MIPS_MT_SMP diff --git a/arch/mips/include/asm/vpe.h b/arch/mips/include/asm/vpe.h index ef7e07829607..61fd4d0aeda4 100644 --- a/arch/mips/include/asm/vpe.h +++ b/arch/mips/include/asm/vpe.h @@ -29,12 +29,8 @@ static inline int aprp_cpu_index(void) { -#ifdef CONFIG_MIPS_CMP - return setup_max_cpus; -#else extern int tclimit; return tclimit; -#endif } enum vpe_state { diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 5d1addac5e28..853a43ee4b44 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -58,16 +58,13 @@ obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o bmips_5xxx_init.o obj-$(CONFIG_MIPS_MT) += mips-mt.o obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o -obj-$(CONFIG_MIPS_CMP) += smp-cmp.o obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o obj-$(CONFIG_MIPS_CPS_NS16550) += cps-vec-ns16550.o obj-$(CONFIG_MIPS_SPRAM) += spram.o obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o -obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o -obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c deleted file mode 100644 index d26dcc4b46e7..000000000000 --- a/arch/mips/kernel/rtlx-cmp.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static int major; - -static void rtlx_interrupt(void) -{ - int i; - struct rtlx_info *info; - struct rtlx_info **p = vpe_get_shared(aprp_cpu_index()); - - if (p == NULL || *p == NULL) - return; - - info = *p; - - if (info->ap_int_pending == 1 && smp_processor_id() == 0) { - for (i = 0; i < RTLX_CHANNELS; i++) { - wake_up(&channel_wqs[i].lx_queue); - wake_up(&channel_wqs[i].rt_queue); - } - info->ap_int_pending = 0; - } -} - -void _interrupt_sp(void) -{ - smp_send_reschedule(aprp_cpu_index()); -} - -int __init rtlx_module_init(void) -{ - struct device *dev; - int i, err; - - if (!cpu_has_mipsmt) { - pr_warn("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } - - if (num_possible_cpus() - aprp_cpu_index() < 1) { - pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n" - "Pass maxcpus= argument as kernel argument\n"); - - return -ENODEV; - } - - major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops); - if (major < 0) { - pr_err("rtlx_module_init: unable to register device\n"); - return major; - } - - /* initialise the wait queues */ - for (i = 0; i < RTLX_CHANNELS; i++) { - init_waitqueue_head(&channel_wqs[i].rt_queue); - init_waitqueue_head(&channel_wqs[i].lx_queue); - atomic_set(&channel_wqs[i].in_open, 0); - mutex_init(&channel_wqs[i].mutex); - - dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, - "%s%d", RTLX_MODULE_NAME, i); - if (IS_ERR(dev)) { - while (i--) - device_destroy(mt_class, MKDEV(major, i)); - - err = PTR_ERR(dev); - goto out_chrdev; - } - } - - /* set up notifiers */ - rtlx_notify.start = rtlx_starting; - rtlx_notify.stop = rtlx_stopping; - vpe_notify(aprp_cpu_index(), &rtlx_notify); - - if (cpu_has_vint) { - aprp_hook = rtlx_interrupt; - } else { - pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); - err = -ENODEV; - goto out_class; - } - - return 0; - -out_class: - for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); -out_chrdev: - unregister_chrdev(major, RTLX_MODULE_NAME); - - return err; -} - -void __exit rtlx_module_exit(void) -{ - int i; - - for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); - - unregister_chrdev(major, RTLX_MODULE_NAME); - - aprp_hook = NULL; -} diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c deleted file mode 100644 index 76f5824cdb00..000000000000 --- a/arch/mips/kernel/smp-cmp.c +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Copyright (C) 2007 MIPS Technologies, Inc. - * Chris Dearman (chris@mips.com) - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void cmp_init_secondary(void) -{ - struct cpuinfo_mips *c __maybe_unused = ¤t_cpu_data; - - /* Assume GIC is present */ - change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | - STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); - - /* Enable per-cpu interrupts: platform specific */ - -#ifdef CONFIG_MIPS_MT_SMP - if (cpu_has_mipsmt) - cpu_set_vpe_id(c, (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & - TCBIND_CURVPE); -#endif -} - -static void cmp_smp_finish(void) -{ - pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); - - /* CDFIXME: remove this? */ - write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ)); - -#ifdef CONFIG_MIPS_MT_FPAFF - /* If we have an FPU, enroll ourselves in the FPU-full mask */ - if (cpu_has_fpu) - cpumask_set_cpu(smp_processor_id(), &mt_fpu_cpumask); -#endif /* CONFIG_MIPS_MT_FPAFF */ - - local_irq_enable(); -} - -/* - * Setup the PC, SP, and GP of a secondary processor and start it running - * smp_bootstrap is the place to resume from - * __KSTK_TOS(idle) is apparently the stack pointer - * (unsigned long)idle->thread_info the gp - */ -static int cmp_boot_secondary(int cpu, struct task_struct *idle) -{ - struct thread_info *gp = task_thread_info(idle); - unsigned long sp = __KSTK_TOS(idle); - unsigned long pc = (unsigned long)&smp_bootstrap; - unsigned long a0 = 0; - - pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(), - __func__, cpu); - -#if 0 - /* Needed? */ - flush_icache_range((unsigned long)gp, - (unsigned long)(gp + sizeof(struct thread_info))); -#endif - - amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0); - return 0; -} - -/* - * Common setup before any secondaries are started - */ -void __init cmp_smp_setup(void) -{ - int i; - int ncpu = 0; - - pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); - -#ifdef CONFIG_MIPS_MT_FPAFF - /* If we have an FPU, enroll ourselves in the FPU-full mask */ - if (cpu_has_fpu) - cpumask_set_cpu(0, &mt_fpu_cpumask); -#endif /* CONFIG_MIPS_MT_FPAFF */ - - for (i = 1; i < NR_CPUS; i++) { - if (amon_cpu_avail(i)) { - set_cpu_possible(i, true); - __cpu_number_map[i] = ++ncpu; - __cpu_logical_map[ncpu] = i; - } - } - - if (cpu_has_mipsmt) { - unsigned int nvpe = 1; -#ifdef CONFIG_MIPS_MT_SMP - unsigned int mvpconf0 = read_c0_mvpconf0(); - - nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; -#endif - smp_num_siblings = nvpe; - } - pr_info("Detected %i available secondary CPU(s)\n", ncpu); -} - -void __init cmp_prepare_cpus(unsigned int max_cpus) -{ - pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", - smp_processor_id(), __func__, max_cpus); - -#ifdef CONFIG_MIPS_MT - /* - * FIXME: some of these options are per-system, some per-core and - * some per-cpu - */ - mips_mt_set_cpuoptions(); -#endif - -} - -const struct plat_smp_ops cmp_smp_ops = { - .send_ipi_single = mips_smp_send_ipi_single, - .send_ipi_mask = mips_smp_send_ipi_mask, - .init_secondary = cmp_init_secondary, - .smp_finish = cmp_smp_finish, - .boot_secondary = cmp_boot_secondary, - .smp_setup = cmp_smp_setup, - .prepare_cpus = cmp_prepare_cpus, -}; diff --git a/arch/mips/kernel/vpe-cmp.c b/arch/mips/kernel/vpe-cmp.c deleted file mode 100644 index 92140edb3ce3..000000000000 --- a/arch/mips/kernel/vpe-cmp.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - */ -#include -#include -#include -#include -#include - -#include - -static int major; - -void cleanup_tc(struct tc *tc) -{ - -} - -static ssize_t store_kill(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct vpe *vpe = get_vpe(aprp_cpu_index()); - struct vpe_notifications *notifier; - - list_for_each_entry(notifier, &vpe->notify, list) - notifier->stop(aprp_cpu_index()); - - release_progmem(vpe->load_addr); - vpe->state = VPE_STATE_UNUSED; - - return len; -} -static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); - -static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, - char *buf) -{ - struct vpe *vpe = get_vpe(aprp_cpu_index()); - - return sprintf(buf, "%d\n", vpe->ntcs); -} - -static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct vpe *vpe = get_vpe(aprp_cpu_index()); - unsigned long new; - int ret; - - ret = kstrtoul(buf, 0, &new); - if (ret < 0) - return ret; - - /* APRP can only reserve one TC in a VPE and no more. */ - if (new != 1) - return -EINVAL; - - vpe->ntcs = new; - - return len; -} -static DEVICE_ATTR_RW(ntcs); - -static struct attribute *vpe_attrs[] = { - &dev_attr_kill.attr, - &dev_attr_ntcs.attr, - NULL, -}; -ATTRIBUTE_GROUPS(vpe); - -static void vpe_device_release(struct device *cd) -{ -} - -static struct class vpe_class = { - .name = "vpe", - .owner = THIS_MODULE, - .dev_release = vpe_device_release, - .dev_groups = vpe_groups, -}; - -static struct device vpe_device; - -int __init vpe_module_init(void) -{ - struct vpe *v = NULL; - struct tc *t; - int err; - - if (!cpu_has_mipsmt) { - pr_warn("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } - - if (num_possible_cpus() - aprp_cpu_index() < 1) { - pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n" - "Pass maxcpus= argument as kernel argument\n"); - return -ENODEV; - } - - major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops); - if (major < 0) { - pr_warn("VPE loader: unable to register character device\n"); - return major; - } - - err = class_register(&vpe_class); - if (err) { - pr_err("vpe_class registration failed\n"); - goto out_chrdev; - } - - device_initialize(&vpe_device); - vpe_device.class = &vpe_class; - vpe_device.parent = NULL; - dev_set_name(&vpe_device, "vpe_sp"); - vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR); - err = device_add(&vpe_device); - if (err) { - pr_err("Adding vpe_device failed\n"); - goto out_class; - } - - t = alloc_tc(aprp_cpu_index()); - if (!t) { - pr_warn("VPE: unable to allocate TC\n"); - err = -ENOMEM; - goto out_dev; - } - - /* VPE */ - v = alloc_vpe(aprp_cpu_index()); - if (v == NULL) { - pr_warn("VPE: unable to allocate VPE\n"); - kfree(t); - err = -ENOMEM; - goto out_dev; - } - - v->ntcs = 1; - - /* add the tc to the list of this vpe's tc's. */ - list_add(&t->tc, &v->tc); - - /* TC */ - t->pvpe = v; /* set the parent vpe */ - - return 0; - -out_dev: - device_del(&vpe_device); - -out_class: - put_device(&vpe_device); - class_unregister(&vpe_class); - -out_chrdev: - unregister_chrdev(major, VPE_MODULE_NAME); - - return err; -} - -void __exit vpe_module_exit(void) -{ - struct vpe *v, *n; - - device_unregister(&vpe_device); - class_unregister(&vpe_class); - unregister_chrdev(major, VPE_MODULE_NAME); - - /* No locking needed here */ - list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) - if (v->state != VPE_STATE_UNUSED) - release_vpe(v); -} diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 13294972707b..343d2597ed76 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -795,7 +795,7 @@ static int vpe_open(struct inode *inode, struct file *filp) static int vpe_release(struct inode *inode, struct file *filp) { -#if defined(CONFIG_MIPS_VPE_LOADER_MT) || defined(CONFIG_MIPS_VPE_LOADER_CMP) +#ifdef CONFIG_MIPS_VPE_LOADER_MT struct vpe *v; Elf_Ehdr *hdr; int ret = 0; diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index 13bbd12bfa65..bb2c706e11b0 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile @@ -14,6 +14,4 @@ obj-y += malta-platform.o obj-y += malta-setup.o obj-y += malta-time.o -obj-$(CONFIG_MIPS_CMP) += malta-amon.o - CFLAGS_malta-dtshim.o = -I$(src)/../../../scripts/dtc/libfdt diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c deleted file mode 100644 index 84ac523b0ce0..000000000000 --- a/arch/mips/mti-malta/malta-amon.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2007 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - * - * Arbitrary Monitor Interface - */ -#include -#include - -#include -#include -#include -#include - -int amon_cpu_avail(int cpu) -{ - struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); - - if (cpu < 0 || cpu >= NCPULAUNCH) { - pr_debug("avail: cpu%d is out of range\n", cpu); - return 0; - } - - launch += cpu; - if (!(launch->flags & LAUNCH_FREADY)) { - pr_debug("avail: cpu%d is not ready\n", cpu); - return 0; - } - if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) { - pr_debug("avail: too late.. cpu%d is already gone\n", cpu); - return 0; - } - - return 1; -} - -int amon_cpu_start(int cpu, - unsigned long pc, unsigned long sp, - unsigned long gp, unsigned long a0) -{ - volatile struct cpulaunch *launch = - (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); - - if (!amon_cpu_avail(cpu)) - return -1; - if (cpu == smp_processor_id()) { - pr_debug("launch: I am cpu%d!\n", cpu); - return -1; - } - launch += cpu; - - pr_debug("launch: starting cpu%d\n", cpu); - - launch->pc = pc; - launch->gp = gp; - launch->sp = sp; - launch->a0 = a0; - - smp_wmb(); /* Target must see parameters before go */ - launch->flags |= LAUNCH_FGO; - smp_wmb(); /* Target must see go before we poll */ - - while ((launch->flags & LAUNCH_FGONE) == 0) - ; - smp_rmb(); /* Target will be updating flags soon */ - pr_debug("launch: cpu%d gone!\n", cpu); - - return 0; -} - -#ifdef CONFIG_MIPS_VPE_LOADER_CMP -int vpe_run(struct vpe *v) -{ - struct vpe_notifications *n; - - if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0) - return -1; - - list_for_each_entry(n, &v->notify, list) - n->start(VPE_MODULE_MINOR); - - return 0; -} -#endif diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index b03cac5fdc02..000d6d50520a 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -289,8 +289,6 @@ mips_pci_controller: if (!register_cps_smp_ops()) return; - if (!register_cmp_smp_ops()) - return; if (!register_vsmp_smp_ops()) return; register_up_smp_ops(); diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c index 4ffbcc58c6f6..6961a23aefe9 100644 --- a/arch/mips/mti-malta/malta-platform.c +++ b/arch/mips/mti-malta/malta-platform.c @@ -43,7 +43,6 @@ static struct plat_serial8250_port uart8250_data[] = { SMC_PORT(0x3F8, 4), SMC_PORT(0x2F8, 3), -#ifndef CONFIG_MIPS_CMP { .mapbase = 0x1f000900, /* The CBUS UART */ .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2, @@ -53,7 +52,6 @@ static struct plat_serial8250_port uart8250_data[] = { .flags = CBUS_UART_FLAGS, .regshift = 3, }, -#endif { }, }; diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index bbf5811afbf2..c3fbab50b95c 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -217,8 +217,6 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) if (!register_cps_smp_ops()) return; - if (!register_cmp_smp_ops()) - return; if (!register_vsmp_smp_ops()) return; } diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 1a6a7a672ad7..046c355e120b 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -54,7 +54,6 @@ static DEFINE_SPINLOCK(gic_lock); static struct irq_domain *gic_irq_domain; static int gic_shared_intrs; static unsigned int gic_cpu_pin; -static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; #ifdef CONFIG_GENERIC_IRQ_IPI @@ -499,9 +498,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, */ switch (intr) { case GIC_LOCAL_INT_TIMER: - /* CONFIG_MIPS_CMP workaround (see __gic_init) */ - map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin; - fallthrough; case GIC_LOCAL_INT_PERFCTR: case GIC_LOCAL_INT_FDC: /* @@ -795,34 +791,12 @@ static int __init gic_of_init(struct device_node *node, if (cpu_has_veic) { /* Always use vector 1 in EIC mode */ gic_cpu_pin = 0; - timer_cpu_pin = gic_cpu_pin; set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, __gic_irq_dispatch); } else { gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, gic_irq_dispatch); - /* - * With the CMP implementation of SMP (deprecated), other CPUs - * are started by the bootloader and put into a timer based - * waiting poll loop. We must not re-route those CPU's local - * timer interrupts as the wait instruction will never finish, - * so just handle whatever CPU interrupt it is routed to by - * default. - * - * This workaround should be removed when CMP support is - * dropped. - */ - if (IS_ENABLED(CONFIG_MIPS_CMP) && - gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { - timer_cpu_pin = read_gic_vl_timer_map() & GIC_MAP_PIN_MAP; - irq_set_chained_handler(MIPS_CPU_IRQ_BASE + - GIC_CPU_PIN_OFFSET + - timer_cpu_pin, - gic_irq_dispatch); - } else { - timer_cpu_pin = gic_cpu_pin; - } } gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + From ee1809ed7bc456a72dc8410b475b73021a3a68d5 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 11 Apr 2023 12:14:26 +0100 Subject: [PATCH 060/182] MIPS: fw: Allow firmware to pass a empty env fw_getenv will use env entry to determine style of env, however it is legal for firmware to just pass a empty list. Check if first entry exist before running strchr to avoid null pointer dereference. Cc: stable@vger.kernel.org Link: https://github.com/clbr/n64bootloader/issues/5 Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/fw/lib/cmdline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/fw/lib/cmdline.c b/arch/mips/fw/lib/cmdline.c index f24cbb4a39b5..892765b742bb 100644 --- a/arch/mips/fw/lib/cmdline.c +++ b/arch/mips/fw/lib/cmdline.c @@ -53,7 +53,7 @@ char *fw_getenv(char *envname) { char *result = NULL; - if (_fw_envp != NULL) { + if (_fw_envp != NULL && fw_envp(0) != NULL) { /* * Return a pointer to the given environment variable. * YAMON uses "name", "value" pairs, while U-Boot uses From f5748b8c79d1eea924c50487bdb33351f58ef7bb Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 11 Apr 2023 15:17:47 +0800 Subject: [PATCH 061/182] MIPS: Use def_bool y for ARCH_SUPPORTS_UPROBES Like all the other archs, use def_bool y for ARCH_SUPPORTS_UPROBES, then no need to select ARCH_SUPPORTS_UPROBES. Signed-off-by: Tiezhu Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 61fca312a2c5..47944eb5d7e3 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -16,7 +16,6 @@ config MIPS select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_KEEP_MEMBLOCK - select ARCH_SUPPORTS_UPROBES select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if 64BIT select ARCH_USE_MEMTEST @@ -1059,7 +1058,7 @@ config FW_CFE bool config ARCH_SUPPORTS_UPROBES - bool + def_bool y config DMA_NONCOHERENT bool From afa624ff96e8e79136a46ddaf6debb030546d7c6 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 11 Apr 2023 15:17:48 +0800 Subject: [PATCH 062/182] MIPS: Remove set_swbp() in uprobes.c set_swbp() in arch/mips/kernel/uprobes.c is same with the weak version in kernel/events/uprobes.c, remove it. Signed-off-by: Tiezhu Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/uprobes.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index 6c063aa188e6..6b630ed4438d 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -207,24 +207,6 @@ unsigned long arch_uretprobe_hijack_return_addr( return ra; } -/** - * set_swbp - store breakpoint at a given address. - * @auprobe: arch specific probepoint information. - * @mm: the probed process address space. - * @vaddr: the virtual address to insert the opcode. - * - * For mm @mm, store the breakpoint instruction at @vaddr. - * Return 0 (success) or a negative errno. - * - * This version overrides the weak version in kernel/events/uprobes.c. - * It is required to handle MIPS16 and microMIPS. - */ -int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, - unsigned long vaddr) -{ - return uprobe_write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); -} - void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, void *src, unsigned long len) { From f0e7c06f2be9673d008e866bff1a97e1823637e9 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 11 Apr 2023 12:12:20 +0100 Subject: [PATCH 063/182] MIPS: loongson2ef: Add missing break in cs5536_isa Fixes build error: arch/mips/loongson2ef/common/cs5536/cs5536_isa.c:217:2: error: unannotated fall-through between switch labels [-Werror,-Wimplicit-fallthrough] default: ^ arch/mips/loongson2ef/common/cs5536/cs5536_isa.c:217:2: note: insert 'break;' to avoid fall-through default: ^ break; Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/loongson2ef/common/cs5536/cs5536_isa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c b/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c index 5ad38f86ee62..d60dd9992377 100644 --- a/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c +++ b/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c @@ -213,7 +213,7 @@ void pci_isa_write_reg(int reg, u32 value) lo |= 0x00000063; _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); } - + break; default: /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */ break; From 6ca176fa3a23652513a9d593a6742fb896c7c49f Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 11 Apr 2023 12:12:24 +0100 Subject: [PATCH 064/182] MIPS: octeon_switch: Remove duplicated labels EXPORT macro already have labels defined by itself. Remove duplicated labels outside to silent assembler warnings. Signed-off-by: Jiaxun Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/octeon_switch.S | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S index 896080b445c2..9b7c8ab6f08c 100644 --- a/arch/mips/kernel/octeon_switch.S +++ b/arch/mips/kernel/octeon_switch.S @@ -428,7 +428,6 @@ done_restore: jr ra nop .space 30 * 4, 0 -octeon_mult_save_end: EXPORT(octeon_mult_save_end) END(octeon_mult_save) @@ -448,7 +447,6 @@ octeon_mult_save_end: sd k0, PT_MPL+8(sp) /* PT_MPL+8 has MPL1 */ jr ra sd k1, PT_MPL+16(sp) /* PT_MPL+16 has MPL2 */ -octeon_mult_save2_end: EXPORT(octeon_mult_save2_end) END(octeon_mult_save2) @@ -480,7 +478,6 @@ octeon_mult_save2_end: sd $10, PT_MPL+(4*8)(sp) /* store MPL4 */ jr ra sd $11, PT_MPL+(5*8)(sp) /* store MPL5 */ -octeon_mult_save3_end: EXPORT(octeon_mult_save3_end) END(octeon_mult_save3) .set pop @@ -498,7 +495,6 @@ octeon_mult_save3_end: jr ra nop .space 30 * 4, 0 -octeon_mult_restore_end: EXPORT(octeon_mult_restore_end) END(octeon_mult_restore) @@ -517,7 +513,6 @@ octeon_mult_restore_end: mtp1 v0 /* P1 */ jr ra mtp0 v1 /* P0 */ -octeon_mult_restore2_end: EXPORT(octeon_mult_restore2_end) END(octeon_mult_restore2) @@ -548,7 +543,6 @@ octeon_mult_restore2_end: .word 0x714b000b /* mtp2 $10, $11 restore P2 and P5 */ -octeon_mult_restore3_end: EXPORT(octeon_mult_restore3_end) END(octeon_mult_restore3) .set pop From 20470a68a049de3b118e31ab01474c622934c500 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 12 Apr 2023 15:21:38 +0200 Subject: [PATCH 065/182] Revert "MIPS: generic: Enable all CPUs supported by virt board in Kconfig" This reverts commit de34007751aaba992373f2d659001a846aeb8811. There are too many build errors, which needs to be sorted out first. Signed-off-by: Thomas Bogendoerfer --- arch/mips/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 47944eb5d7e3..7629e671381b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -152,16 +152,12 @@ config MIPS_GENERIC_KERNEL select PCI_DRIVERS_GENERIC select SMP_UP if SMP select SWAP_IO_SPACE - select SYS_HAS_CPU_CAVIUM_OCTEON - select SYS_HAS_CPU_LOONGSON2E - select SYS_HAS_CPU_LOONGSON2F select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 select SYS_HAS_CPU_MIPS32_R6 select SYS_HAS_CPU_MIPS64_R1 select SYS_HAS_CPU_MIPS64_R2 select SYS_HAS_CPU_MIPS64_R6 - select SYS_HAS_CPU_R4X00 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN From 67ff32289acad9ed338cd9f2351b44939e55163e Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:16 -0800 Subject: [PATCH 066/182] proc_sysctl: update docs for __register_sysctl_table() Update the docs for __register_sysctl_table() to make it clear no child entries can be passed. When the child is true these are non-leaf entries on the ctl table and sysctl treats these as directories. The point to __register_sysctl_table() is to deal only with directories not part of the ctl table where thay may riside, to be simple and avoid recursion. While at it, hint towards using long on extra1 and extra2 later. Cc: stable@vger.kernel.org # v5.17 Cc: Christian Brauner Cc: Kefeng Wang Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 5851eb5bc726..1df0beb50dbe 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1287,7 +1287,7 @@ out: * __register_sysctl_table - register a leaf sysctl table * @set: Sysctl tree to register on * @path: The path to the directory the sysctl table is in. - * @table: the top-level table structure + * @table: the top-level table structure without any child * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. @@ -1308,9 +1308,12 @@ out: * proc_handler - the text handler routine (described below) * * extra1, extra2 - extra pointers usable by the proc handler routines + * XXX: we should eventually modify these to use long min / max [0] + * [0] https://lkml.kernel.org/87zgpte9o4.fsf@email.froward.int.ebiederm.org * * Leaf nodes in the sysctl tree will be represented by a single file - * under /proc; non-leaf nodes will be represented by directories. + * under /proc; non-leaf nodes (where child is not NULL) are not allowed, + * sysctl_check_table() verifies this. * * There must be a proc_handler routine for any terminal nodes. * Several default handlers are available to cover common cases - @@ -1352,7 +1355,7 @@ struct ctl_table_header *__register_sysctl_table( spin_lock(&sysctl_lock); dir = &set->dir; - /* Reference moved down the diretory tree get_subdir */ + /* Reference moved down the directory tree get_subdir */ dir->header.nreg++; spin_unlock(&sysctl_lock); @@ -1369,6 +1372,11 @@ struct ctl_table_header *__register_sysctl_table( if (namelen == 0) continue; + /* + * namelen ensures if name is "foo/bar/yay" only foo is + * registered first. We traverse as if using mkdir -p and + * return a ctl_dir for the last directory entry. + */ dir = get_subdir(dir, name, namelen); if (IS_ERR(dir)) goto fail; From b2f56e5574eac0cf9e3dc382bef010298cb1f1e9 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:17 -0800 Subject: [PATCH 067/182] proc_sysctl: move helper which creates required subdirectories Move the code which creates the subdirectories for a ctl table into a helper routine so to make it easier to review. Document the goal. This creates no functional changes. Reviewed-by: John Johansen Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 56 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 1df0beb50dbe..6b9b2694d430 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1283,6 +1283,35 @@ out: return err; } +/* Find the directory for the ctl_table. If one is not found create it. */ +static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) +{ + const char *name, *nextname; + + for (name = path; name; name = nextname) { + int namelen; + nextname = strchr(name, '/'); + if (nextname) { + namelen = nextname - name; + nextname++; + } else { + namelen = strlen(name); + } + if (namelen == 0) + continue; + + /* + * namelen ensures if name is "foo/bar/yay" only foo is + * registered first. We traverse as if using mkdir -p and + * return a ctl_dir for the last directory entry. + */ + dir = get_subdir(dir, name, namelen); + if (IS_ERR(dir)) + break; + } + return dir; +} + /** * __register_sysctl_table - register a leaf sysctl table * @set: Sysctl tree to register on @@ -1334,7 +1363,6 @@ struct ctl_table_header *__register_sysctl_table( { struct ctl_table_root *root = set->dir.header.root; struct ctl_table_header *header; - const char *name, *nextname; struct ctl_dir *dir; struct ctl_table *entry; struct ctl_node *node; @@ -1359,29 +1387,9 @@ struct ctl_table_header *__register_sysctl_table( dir->header.nreg++; spin_unlock(&sysctl_lock); - /* Find the directory for the ctl_table */ - for (name = path; name; name = nextname) { - int namelen; - nextname = strchr(name, '/'); - if (nextname) { - namelen = nextname - name; - nextname++; - } else { - namelen = strlen(name); - } - if (namelen == 0) - continue; - - /* - * namelen ensures if name is "foo/bar/yay" only foo is - * registered first. We traverse as if using mkdir -p and - * return a ctl_dir for the last directory entry. - */ - dir = get_subdir(dir, name, namelen); - if (IS_ERR(dir)) - goto fail; - } - + dir = sysctl_mkdir_p(dir, path); + if (IS_ERR(dir)) + goto fail; spin_lock(&sysctl_lock); if (insert_header(dir, header)) goto fail_put_dir_locked; From 228b09de936395ddd740df3522ea35ae934830d8 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:18 -0800 Subject: [PATCH 068/182] sysctl: clarify register_sysctl_init() base directory order Relatively new docs which I added which hinted the base directories needed to be created before is wrong, remove that incorrect comment. This has been hinted before by Eric twice already [0] [1], I had just not verified that until now. Now that I've verified that updates the docs to relax the context described. [0] https://lkml.kernel.org/r/875ys0azt8.fsf@email.froward.int.ebiederm.org [1] https://lkml.kernel.org/r/87ftbiud6s.fsf@x220.int.ebiederm.org Cc: stable@vger.kernel.org # v5.17 Cc: Christian Brauner Cc: Kefeng Wang Suggested-by: Eric W. Biederman Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 6b9b2694d430..15d5e02f1ec0 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1440,10 +1440,7 @@ EXPORT_SYMBOL(register_sysctl); * register_sysctl() failing on init are extremely low, and so for both reasons * this function does not return any error as it is used by initialization code. * - * Context: Can only be called after your respective sysctl base path has been - * registered. So for instance, most base directories are registered early on - * init before init levels are processed through proc_sys_init() and - * sysctl_init_bases(). + * Context: if your base directory does not exist it will be created for you. */ void __init __register_sysctl_init(const char *path, struct ctl_table *table, const char *table_name) From 96200952abeb35c4407851bfcdcbc144cc0d027d Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:19 -0800 Subject: [PATCH 069/182] apparmor: simplify sysctls with register_sysctl_init() Using register_sysctl_paths() is really only needed if you have subdirectories with entries. We can use the simple register_sysctl() instead. Acked-by: John Johansen Reviewed-by: Georgia Garcia Signed-off-by: Luis Chamberlain --- security/apparmor/lsm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d6cc4812ca53..47c7ec7e5a80 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1764,11 +1764,6 @@ static int apparmor_dointvec(struct ctl_table *table, int write, return proc_dointvec(table, write, buffer, lenp, ppos); } -static struct ctl_path apparmor_sysctl_path[] = { - { .procname = "kernel", }, - { } -}; - static struct ctl_table apparmor_sysctl_table[] = { { .procname = "unprivileged_userns_apparmor_policy", @@ -1790,8 +1785,7 @@ static struct ctl_table apparmor_sysctl_table[] = { static int __init apparmor_init_sysctl(void) { - return register_sysctl_paths(apparmor_sysctl_path, - apparmor_sysctl_table) ? 0 : -ENOMEM; + return register_sysctl("kernel", apparmor_sysctl_table) ? 0 : -ENOMEM; } #else static inline int apparmor_init_sysctl(void) From 5df5bdc3c4733a47a818576c13a7bfd0f0715124 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:20 -0800 Subject: [PATCH 070/182] loadpin: simplify sysctls use with register_sysctl() register_sysctl_paths() is not required, we can just use register_sysctl() with the required path specified. Reviewed-by: John Johansen Acked-by: Kees Cook Signed-off-by: Luis Chamberlain --- security/loadpin/loadpin.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index d73a281adf86..c971464b4ad5 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -52,12 +52,6 @@ static bool deny_reading_verity_digests; #endif #ifdef CONFIG_SYSCTL -static struct ctl_path loadpin_sysctl_path[] = { - { .procname = "kernel", }, - { .procname = "loadpin", }, - { } -}; - static struct ctl_table loadpin_sysctl_table[] = { { .procname = "enforce", @@ -262,7 +256,7 @@ static int __init loadpin_init(void) enforce ? "" : "not "); parse_exclude(); #ifdef CONFIG_SYSCTL - if (!register_sysctl_paths(loadpin_sysctl_path, loadpin_sysctl_table)) + if (!register_sysctl("kernel/loadpin", loadpin_sysctl_table)) pr_notice("sysctl registration failed!\n"); #endif security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); From 98cfeb8d540aa009cd5cb973def265b6c44afa00 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:21 -0800 Subject: [PATCH 071/182] yama: simplfy sysctls with register_sysctl() register_sysctl_paths() is only need if you have directories with entries, simplify this by using register_sysctl(). Acked-by: Kees Cook Signed-off-by: Luis Chamberlain --- security/yama/yama_lsm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 06e226166aab..90dd012b0db5 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -447,12 +447,6 @@ static int yama_dointvec_minmax(struct ctl_table *table, int write, static int max_scope = YAMA_SCOPE_NO_ATTACH; -static struct ctl_path yama_sysctl_path[] = { - { .procname = "kernel", }, - { .procname = "yama", }, - { } -}; - static struct ctl_table yama_sysctl_table[] = { { .procname = "ptrace_scope", @@ -467,7 +461,7 @@ static struct ctl_table yama_sysctl_table[] = { }; static void __init yama_init_sysctl(void) { - if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) + if (!register_sysctl("kernel/yama", yama_sysctl_table)) panic("Yama: sysctl registration failed.\n"); } #else From 02a6b455fb35d29620ceaa0ed053ae9846f875ca Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:22 -0800 Subject: [PATCH 072/182] seccomp: simplify sysctls with register_sysctl_init() register_sysctl_paths() is only needed if you have childs (directories) with entries. Just use register_sysctl_init() as it also does the kmemleak check for you. Acked-by: Kees Cook Signed-off-by: Luis Chamberlain --- kernel/seccomp.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index cebf26445f9e..d3e584065c7f 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -2368,12 +2368,6 @@ static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write, return ret; } -static struct ctl_path seccomp_sysctl_path[] = { - { .procname = "kernel", }, - { .procname = "seccomp", }, - { } -}; - static struct ctl_table seccomp_sysctl_table[] = { { .procname = "actions_avail", @@ -2392,14 +2386,7 @@ static struct ctl_table seccomp_sysctl_table[] = { static int __init seccomp_sysctl_init(void) { - struct ctl_table_header *hdr; - - hdr = register_sysctl_paths(seccomp_sysctl_path, seccomp_sysctl_table); - if (!hdr) - pr_warn("sysctl registration failed\n"); - else - kmemleak_not_leak(hdr); - + register_sysctl_init("kernel/seccomp", seccomp_sysctl_table); return 0; } From adf11ea8725bd7874b4aec6990c5807abcd5a00d Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:28:25 -0800 Subject: [PATCH 073/182] csky: simplify alignment sysctl registration Using register_sysctl_paths() is only required if we are using leafs with entries but all we are doing is creates leafs with just one leaf and then entries and register_sysctl_init() works well with that already. The 555 permission is already retained by the new_dir() proc sysctl directory creator. Signed-off-by: Luis Chamberlain --- arch/csky/abiv1/alignment.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/arch/csky/abiv1/alignment.c b/arch/csky/abiv1/alignment.c index 2df115d0e210..b60259daed1b 100644 --- a/arch/csky/abiv1/alignment.c +++ b/arch/csky/abiv1/alignment.c @@ -332,22 +332,9 @@ static struct ctl_table alignment_tbl[5] = { {} }; -static struct ctl_table sysctl_table[2] = { - { - .procname = "csky_alignment", - .mode = 0555, - .child = alignment_tbl}, - {} -}; - -static struct ctl_path sysctl_path[2] = { - {.procname = "csky"}, - {} -}; - static int __init csky_alignment_init(void) { - register_sysctl_paths(sysctl_path, sysctl_table); + register_sysctl_init("csky/csky_alignment", alignment_tbl); return 0; } From ca674057f36bcc42eea3832b8de5d0582615a472 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:46:06 -0800 Subject: [PATCH 074/182] scsi: simplify sysctl registration with register_sysctl() register_sysctl_table() is a deprecated compatibility wrapper. register_sysctl() can do the directory creation for you so just use that. Signed-off-by: Luis Chamberlain --- drivers/scsi/scsi_sysctl.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c index 7259704a7f52..7f0914ea168f 100644 --- a/drivers/scsi/scsi_sysctl.c +++ b/drivers/scsi/scsi_sysctl.c @@ -21,25 +21,11 @@ static struct ctl_table scsi_table[] = { { } }; -static struct ctl_table scsi_dir_table[] = { - { .procname = "scsi", - .mode = 0555, - .child = scsi_table }, - { } -}; - -static struct ctl_table scsi_root_table[] = { - { .procname = "dev", - .mode = 0555, - .child = scsi_dir_table }, - { } -}; - static struct ctl_table_header *scsi_table_header; int __init scsi_init_sysctl(void) { - scsi_table_header = register_sysctl_table(scsi_root_table); + scsi_table_header = register_sysctl("dev/scsi", scsi_table); if (!scsi_table_header) return -ENOMEM; return 0; From 525f23fe58b59b3a78a7044916aed9fe26918296 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:46:08 -0800 Subject: [PATCH 075/182] hv: simplify sysctl registration register_sysctl_table() is a deprecated compatibility wrapper. register_sysctl() can do the directory creation for you so just use that. Signed-off-by: Luis Chamberlain Reviewed-by: Michael Kelley Reviewed-by: Wei Liu --- drivers/hv/vmbus_drv.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index d24dd65b33d4..229353f1e9c2 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1460,15 +1460,6 @@ static struct ctl_table hv_ctl_table[] = { {} }; -static struct ctl_table hv_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = hv_ctl_table - }, - {} -}; - /* * vmbus_bus_init -Main vmbus driver initialization routine. * @@ -1547,7 +1538,7 @@ static int vmbus_bus_init(void) * message recording won't be available in isolated * guests should the following registration fail. */ - hv_ctl_table_hdr = register_sysctl_table(hv_root_table); + hv_ctl_table_hdr = register_sysctl("kernel", hv_ctl_table); if (!hv_ctl_table_hdr) pr_err("Hyper-V: sysctl table register error"); From 9adcf9d3d5c9ed6bb9d493b59594501f79ae3bed Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:46:09 -0800 Subject: [PATCH 076/182] md: simplify sysctl registration register_sysctl_table() is a deprecated compatibility wrapper. register_sysctl() can do the directory creation for you so just use that. Signed-off-by: Luis Chamberlain Acked-by: Song Liu --- drivers/md/md.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 39e49e5d7182..0dc01f834b62 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -322,26 +322,6 @@ static struct ctl_table raid_table[] = { { } }; -static struct ctl_table raid_dir_table[] = { - { - .procname = "raid", - .maxlen = 0, - .mode = S_IRUGO|S_IXUGO, - .child = raid_table, - }, - { } -}; - -static struct ctl_table raid_root_table[] = { - { - .procname = "dev", - .maxlen = 0, - .mode = 0555, - .child = raid_dir_table, - }, - { } -}; - static int start_readonly; /* @@ -9649,7 +9629,7 @@ static int __init md_init(void) mdp_major = ret; register_reboot_notifier(&md_notifier); - raid_table_header = register_sysctl_table(raid_root_table); + raid_table_header = register_sysctl("dev/raid", raid_table); md_geninit(); return 0; From 9f17a75b2d10ddd786b3b2c4fd732356de4f483e Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Thu, 2 Mar 2023 12:46:12 -0800 Subject: [PATCH 077/182] xen: simplify sysctl registration for balloon register_sysctl_table() is a deprecated compatibility wrapper. register_sysctl_init() can do the directory creation for you so just use that. Signed-off-by: Luis Chamberlain Reviewed-by: Juergen Gross --- drivers/xen/balloon.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 617a7f4f07a8..586a1673459e 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -97,24 +97,6 @@ static struct ctl_table balloon_table[] = { { } }; -static struct ctl_table balloon_root[] = { - { - .procname = "balloon", - .mode = 0555, - .child = balloon_table, - }, - { } -}; - -static struct ctl_table xen_root[] = { - { - .procname = "xen", - .mode = 0555, - .child = balloon_root, - }, - { } -}; - #else #define xen_hotplug_unpopulated 0 #endif @@ -747,7 +729,7 @@ static int __init balloon_init(void) #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG set_online_page_callback(&xen_online_page); register_memory_notifier(&xen_memory_nb); - register_sysctl_table(xen_root); + register_sysctl_init("xen/balloon", balloon_table); #endif balloon_add_regions(); From 1dc8689e4cc651e21566e10206a84c4006e81fb1 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 13:00:16 -0800 Subject: [PATCH 078/182] proc_sysctl: enhance documentation Expand documentation to clarify: o that paths don't need to exist for the new API callers o clarify that we *require* callers to keep the memory of the table around during the lifetime of the sysctls o annotate routines we are trying to deprecate and later remove Cc: stable@vger.kernel.org # v5.17 Cc: Christian Brauner Cc: Kefeng Wang Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 15d5e02f1ec0..7ad07435828f 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1316,7 +1316,10 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) * __register_sysctl_table - register a leaf sysctl table * @set: Sysctl tree to register on * @path: The path to the directory the sysctl table is in. - * @table: the top-level table structure without any child + * @table: the top-level table structure without any child. This table + * should not be free'd after registration. So it should not be + * used on stack. It can either be a global or dynamically allocated + * by the caller and free'd later after sysctl unregistration. * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. @@ -1410,8 +1413,15 @@ fail: /** * register_sysctl - register a sysctl table - * @path: The path to the directory the sysctl table is in. - * @table: the table structure + * @path: The path to the directory the sysctl table is in. If the path + * doesn't exist we will create it for you. + * @table: the table structure. The calller must ensure the life of the @table + * will be kept during the lifetime use of the syctl. It must not be freed + * until unregister_sysctl_table() is called with the given returned table + * with this registration. If your code is non modular then you don't need + * to call unregister_sysctl_table() and can instead use something like + * register_sysctl_init() which does not care for the result of the syctl + * registration. * * Register a sysctl table. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. @@ -1427,8 +1437,11 @@ EXPORT_SYMBOL(register_sysctl); /** * __register_sysctl_init() - register sysctl table to path - * @path: path name for sysctl base - * @table: This is the sysctl table that needs to be registered to the path + * @path: path name for sysctl base. If that path doesn't exist we will create + * it for you. + * @table: This is the sysctl table that needs to be registered to the path. + * The caller must ensure the life of the @table will be kept during the + * lifetime use of the sysctl. * @table_name: The name of sysctl table, only used for log printing when * registration fails * @@ -1570,6 +1583,7 @@ out: * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. + * We are slowly deprecating this call so avoid its use. * * See __register_sysctl_table for more details. */ @@ -1641,6 +1655,7 @@ err_register_leaves: * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. + * We are slowly deprecating this caller so avoid future uses of it. * * See __register_sysctl_paths for more details. */ From 37b768ce3d23f79cef906aaf7427dd345b57f477 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 00:37:19 -0800 Subject: [PATCH 079/182] lockd: simplify two-level sysctl registration for nlm_sysctls There is no need to declare two tables to just create directories, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Reviewed-by: Jeff Layton Signed-off-by: Luis Chamberlain --- fs/lockd/svc.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 9a47303b2cba..bb94949bc223 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -510,24 +510,6 @@ static struct ctl_table nlm_sysctls[] = { { } }; -static struct ctl_table nlm_sysctl_dir[] = { - { - .procname = "nfs", - .mode = 0555, - .child = nlm_sysctls, - }, - { } -}; - -static struct ctl_table nlm_sysctl_root[] = { - { - .procname = "fs", - .mode = 0555, - .child = nlm_sysctl_dir, - }, - { } -}; - #endif /* CONFIG_SYSCTL */ /* @@ -644,7 +626,7 @@ static int __init init_nlm(void) #ifdef CONFIG_SYSCTL err = -ENOMEM; - nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); + nlm_sysctl_table = register_sysctl("fs/nfs", nlm_sysctls); if (nlm_sysctl_table == NULL) goto err_sysctl; #endif From d2235a705b48a1a86e2b8ea15091d83f7f80503c Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 00:39:18 -0800 Subject: [PATCH 080/182] nfs: simplify two-level sysctl registration for nfs4_cb_sysctls There is no need to declare two tables to just create directories, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Reviewed-by: Jeff Layton Signed-off-by: Luis Chamberlain --- fs/nfs/nfs4sysctl.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c index c394e4447100..e776200e9a11 100644 --- a/fs/nfs/nfs4sysctl.c +++ b/fs/nfs/nfs4sysctl.c @@ -37,27 +37,10 @@ static struct ctl_table nfs4_cb_sysctls[] = { { } }; -static struct ctl_table nfs4_cb_sysctl_dir[] = { - { - .procname = "nfs", - .mode = 0555, - .child = nfs4_cb_sysctls, - }, - { } -}; - -static struct ctl_table nfs4_cb_sysctl_root[] = { - { - .procname = "fs", - .mode = 0555, - .child = nfs4_cb_sysctl_dir, - }, - { } -}; - int nfs4_register_sysctl(void) { - nfs4_callback_sysctl_table = register_sysctl_table(nfs4_cb_sysctl_root); + nfs4_callback_sysctl_table = register_sysctl("fs/nfs", + nfs4_cb_sysctls); if (nfs4_callback_sysctl_table == NULL) return -ENOMEM; return 0; From a2189b77676b256b6606612fd68ed493f7080929 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 00:40:35 -0800 Subject: [PATCH 081/182] nfs: simplify two-level sysctl registration for nfs_cb_sysctls There is no need to declare two tables to just create directories, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Reviewed-by: Jeff Layton Signed-off-by: Luis Chamberlain --- fs/nfs/sysctl.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 7aea195ddb35..f39e2089bc4c 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c @@ -32,27 +32,9 @@ static struct ctl_table nfs_cb_sysctls[] = { { } }; -static struct ctl_table nfs_cb_sysctl_dir[] = { - { - .procname = "nfs", - .mode = 0555, - .child = nfs_cb_sysctls, - }, - { } -}; - -static struct ctl_table nfs_cb_sysctl_root[] = { - { - .procname = "fs", - .mode = 0555, - .child = nfs_cb_sysctl_dir, - }, - { } -}; - int nfs_register_sysctl(void) { - nfs_callback_sysctl_table = register_sysctl_table(nfs_cb_sysctl_root); + nfs_callback_sysctl_table = register_sysctl("fs/nfs", nfs_cb_sysctls); if (nfs_callback_sysctl_table == NULL) return -ENOMEM; return 0; From f5d2b92c85d420d0020163b9ad153962d8f9fcc7 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 00:42:26 -0800 Subject: [PATCH 082/182] xfs: simplify two-level sysctl registration for xfs_table There is no need to declare two tables to just create directories, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Reviewed-by: Dave Chinner Signed-off-by: Luis Chamberlain --- fs/xfs/xfs_sysctl.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/fs/xfs/xfs_sysctl.c b/fs/xfs/xfs_sysctl.c index 546a6cd96729..fade33735393 100644 --- a/fs/xfs/xfs_sysctl.c +++ b/fs/xfs/xfs_sysctl.c @@ -210,28 +210,10 @@ static struct ctl_table xfs_table[] = { {} }; -static struct ctl_table xfs_dir_table[] = { - { - .procname = "xfs", - .mode = 0555, - .child = xfs_table - }, - {} -}; - -static struct ctl_table xfs_root_table[] = { - { - .procname = "fs", - .mode = 0555, - .child = xfs_dir_table - }, - {} -}; - int xfs_sysctl_register(void) { - xfs_table_header = register_sysctl_table(xfs_root_table); + xfs_table_header = register_sysctl("fs/xfs", xfs_table); if (!xfs_table_header) return -ENOMEM; return 0; From 3d379b8d0de0492e86b93a1b8cd07403825fe23d Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 13:46:23 -0800 Subject: [PATCH 083/182] fs/cachefiles: simplify one-level sysctl registration for cachefiles_sysctls There is no need to declare an extra tables to just create directory, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Signed-off-by: Luis Chamberlain --- fs/cachefiles/error_inject.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/fs/cachefiles/error_inject.c b/fs/cachefiles/error_inject.c index 58f8aec964e4..18de8a876b02 100644 --- a/fs/cachefiles/error_inject.c +++ b/fs/cachefiles/error_inject.c @@ -22,18 +22,9 @@ static struct ctl_table cachefiles_sysctls[] = { {} }; -static struct ctl_table cachefiles_sysctls_root[] = { - { - .procname = "cachefiles", - .mode = 0555, - .child = cachefiles_sysctls, - }, - {} -}; - int __init cachefiles_register_error_injection(void) { - cachefiles_sysctl = register_sysctl_table(cachefiles_sysctls_root); + cachefiles_sysctl = register_sysctl("cachefiles", cachefiles_sysctls); if (!cachefiles_sysctl) return -ENOMEM; return 0; From 1119aaa823e6cc35f2e8c8793cfa58d923a15c1b Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 13:48:17 -0800 Subject: [PATCH 084/182] coda: simplify one-level sysctl registration for coda_table There is no need to declare an extra tables to just create directory, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Acked-by: Jan Harkes Signed-off-by: Luis Chamberlain --- fs/coda/sysctl.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index fda3b702b1c5..a247c14aaab7 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c @@ -39,19 +39,10 @@ static struct ctl_table coda_table[] = { {} }; -static struct ctl_table fs_table[] = { - { - .procname = "coda", - .mode = 0555, - .child = coda_table - }, - {} -}; - void coda_sysctl_init(void) { if ( !fs_table_header ) - fs_table_header = register_sysctl_table(fs_table); + fs_table_header = register_sysctl("coda", coda_table); } void coda_sysctl_clean(void) From 02148ff371b276d664780de6d1f52d52074c3e25 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 13:49:40 -0800 Subject: [PATCH 085/182] ntfs: simplfy one-level sysctl registration for ntfs_sysctls There is no need to declare an extra tables to just create directory, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Signed-off-by: Luis Chamberlain --- fs/ntfs/sysctl.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/fs/ntfs/sysctl.c b/fs/ntfs/sysctl.c index a030d00af90c..174fe536a1c0 100644 --- a/fs/ntfs/sysctl.c +++ b/fs/ntfs/sysctl.c @@ -31,16 +31,6 @@ static struct ctl_table ntfs_sysctls[] = { {} }; -/* Define the parent directory /proc/sys/fs. */ -static struct ctl_table sysctls_root[] = { - { - .procname = "fs", - .mode = 0555, - .child = ntfs_sysctls - }, - {} -}; - /* Storage for the sysctls header. */ static struct ctl_table_header *sysctls_root_table; @@ -54,7 +44,7 @@ int ntfs_sysctl(int add) { if (add) { BUG_ON(sysctls_root_table); - sysctls_root_table = register_sysctl_table(sysctls_root); + sysctls_root_table = register_sysctl("fs", ntfs_sysctls); if (!sysctls_root_table) return -ENOMEM; } else { From 3d51cd8ea3c832c50c22e46354ac89e0964ea2d8 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 01:24:10 -0800 Subject: [PATCH 086/182] utsname: simplify one-level sysctl registration for uts_kern_table There is no need to declare an extra tables to just create directory, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Reviewed-by: Christian Brauner Signed-off-by: Luis Chamberlain --- kernel/utsname_sysctl.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c index f50398cb790d..019e3a1566cf 100644 --- a/kernel/utsname_sysctl.c +++ b/kernel/utsname_sysctl.c @@ -123,15 +123,6 @@ static struct ctl_table uts_kern_table[] = { {} }; -static struct ctl_table uts_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = uts_kern_table, - }, - {} -}; - #ifdef CONFIG_PROC_SYSCTL /* * Notify userspace about a change in a certain entry of uts_kern_table, @@ -147,7 +138,7 @@ void uts_proc_notify(enum uts_proc proc) static int __init utsname_sysctl_init(void) { - register_sysctl_table(uts_root_table); + register_sysctl("kernel", uts_kern_table); return 0; } From 03860ef038e6435c5ea2bda24dc5698e0da60ebc Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 01:10:11 -0800 Subject: [PATCH 087/182] ia64: simplify one-level sysctl registration for kdump_ctl_table There is no need to declare an extra tables to just create directory, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Signed-off-by: Luis Chamberlain --- arch/ia64/kernel/crash.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c index 76730f34685c..88b3ce3e66cd 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c @@ -234,15 +234,6 @@ static struct ctl_table kdump_ctl_table[] = { }, { } }; - -static struct ctl_table sys_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = kdump_ctl_table, - }, - { } -}; #endif static int @@ -257,7 +248,7 @@ machine_crash_setup(void) if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) return ret; #ifdef CONFIG_SYSCTL - register_sysctl_table(sys_table); + register_sysctl("kernel", kdump_ctl_table); #endif return 0; } From ca14ccf310ee9d575c3bacbf1d61d9640d0025b6 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 10 Mar 2023 00:50:50 -0800 Subject: [PATCH 088/182] arm: simplify two-level sysctl registration for ctl_isa_vars There is no need to declare two tables to just create directories, this can be easily be done with a prefix path with register_sysctl(). Simplify this registration. Signed-off-by: Luis Chamberlain --- arch/arm/kernel/isa.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c index d8a509c5d5bd..20218876bef2 100644 --- a/arch/arm/kernel/isa.c +++ b/arch/arm/kernel/isa.c @@ -40,27 +40,11 @@ static struct ctl_table ctl_isa_vars[4] = { static struct ctl_table_header *isa_sysctl_header; -static struct ctl_table ctl_isa[2] = { - { - .procname = "isa", - .mode = 0555, - .child = ctl_isa_vars, - }, {} -}; - -static struct ctl_table ctl_bus[2] = { - { - .procname = "bus", - .mode = 0555, - .child = ctl_isa, - }, {} -}; - void __init register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift) { isa_membase = membase; isa_portbase = portbase; isa_portshift = portshift; - isa_sysctl_header = register_sysctl_table(ctl_bus); + isa_sysctl_header = register_sysctl("bus/isa", ctl_isa_vars); } From 8cbc82f3ec0d58961cf9c1e5d99e56741f4bf134 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Mon, 20 Mar 2023 15:40:10 +0800 Subject: [PATCH 089/182] mm: memory-failure: Move memory failure sysctls to its own file The sysctl_memory_failure_early_kill and memory_failure_recovery are only used in memory-failure.c, move them to its own file. Acked-by: Naoya Horiguchi Signed-off-by: Kefeng Wang [mcgrof: fix by adding empty ctl entry, this caused a crash] Signed-off-by: Luis Chamberlain --- include/linux/mm.h | 2 -- kernel/sysctl.c | 20 -------------------- mm/memory-failure.c | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 1f79667824eb..98da268b834a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3442,8 +3442,6 @@ int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index, extern int memory_failure(unsigned long pfn, int flags); extern void memory_failure_queue_kick(int cpu); extern int unpoison_memory(unsigned long pfn); -extern int sysctl_memory_failure_early_kill; -extern int sysctl_memory_failure_recovery; extern void shake_page(struct page *p); extern atomic_long_t num_poisoned_pages __read_mostly; extern int soft_offline_page(unsigned long pfn, int flags); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ce0297acf97c..0a8a3c9c82e4 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2350,26 +2350,6 @@ static struct ctl_table vm_table[] = { .proc_handler = proc_dointvec, .extra1 = SYSCTL_ZERO, }, -#endif -#ifdef CONFIG_MEMORY_FAILURE - { - .procname = "memory_failure_early_kill", - .data = &sysctl_memory_failure_early_kill, - .maxlen = sizeof(sysctl_memory_failure_early_kill), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, - { - .procname = "memory_failure_recovery", - .data = &sysctl_memory_failure_recovery, - .maxlen = sizeof(sysctl_memory_failure_recovery), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, #endif { .procname = "user_reserve_kbytes", diff --git a/mm/memory-failure.c b/mm/memory-failure.c index fae9baf3be16..10e60b6b2447 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -62,13 +62,14 @@ #include #include #include +#include #include "swap.h" #include "internal.h" #include "ras/ras_event.h" -int sysctl_memory_failure_early_kill __read_mostly = 0; +static int sysctl_memory_failure_early_kill __read_mostly; -int sysctl_memory_failure_recovery __read_mostly = 1; +static int sysctl_memory_failure_recovery __read_mostly = 1; atomic_long_t num_poisoned_pages __read_mostly = ATOMIC_LONG_INIT(0); @@ -122,6 +123,37 @@ const struct attribute_group memory_failure_attr_group = { .attrs = memory_failure_attr, }; +#ifdef CONFIG_SYSCTL +static struct ctl_table memory_failure_table[] = { + { + .procname = "memory_failure_early_kill", + .data = &sysctl_memory_failure_early_kill, + .maxlen = sizeof(sysctl_memory_failure_early_kill), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { + .procname = "memory_failure_recovery", + .data = &sysctl_memory_failure_recovery, + .maxlen = sizeof(sysctl_memory_failure_recovery), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { } +}; + +static int __init memory_failure_sysctl_init(void) +{ + register_sysctl_init("vm", memory_failure_table); + return 0; +} +late_initcall(memory_failure_sysctl_init); +#endif /* CONFIG_SYSCTL */ + /* * Return values: * 1: the page is dissolved (if needed) and taken off from buddy, From 48fe8ab8d5a39c7bc49cb41d0ad92c75f48a9550 Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Tue, 28 Mar 2023 14:46:28 +0800 Subject: [PATCH 090/182] mm: compaction: move compaction sysctl to its own file This moves all compaction sysctls to its own file. Move sysctl to where the functionality truly belongs to improve readability, reduce merge conflicts, and facilitate maintenance. I use x86_defconfig and linux-next-20230327 branch $ make defconfig;make all -jn CONFIG_COMPACTION=y add/remove: 1/0 grow/shrink: 1/1 up/down: 350/-256 (94) Function old new delta vm_compaction - 320 +320 kcompactd_init 180 210 +30 vm_table 2112 1856 -256 Total: Before=21119987, After=21120081, chg +0.00% Despite the addition of 94 bytes the patch still seems a worthwile cleanup. Link: https://lore.kernel.org/lkml/067f7347-ba10-5405-920c-0f5f985c84f4@suse.cz/ Signed-off-by: Minghao Chi Acked-by: Vlastimil Babka Signed-off-by: Luis Chamberlain --- include/linux/compaction.h | 7 ---- kernel/sysctl.c | 59 -------------------------- mm/compaction.c | 84 ++++++++++++++++++++++++++++++++------ 3 files changed, 72 insertions(+), 78 deletions(-) diff --git a/include/linux/compaction.h b/include/linux/compaction.h index 52a9ff65faee..a6e512cfb670 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h @@ -81,13 +81,6 @@ static inline unsigned long compact_gap(unsigned int order) } #ifdef CONFIG_COMPACTION -extern unsigned int sysctl_compaction_proactiveness; -extern int sysctl_compaction_handler(struct ctl_table *table, int write, - void *buffer, size_t *length, loff_t *ppos); -extern int compaction_proactiveness_sysctl_handler(struct ctl_table *table, - int write, void *buffer, size_t *length, loff_t *ppos); -extern int sysctl_extfrag_threshold; -extern int sysctl_compact_unevictable_allowed; extern unsigned int extfrag_for_order(struct zone *zone, unsigned int order); extern int fragmentation_index(struct zone *zone, unsigned int order); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 0a8a3c9c82e4..bfe53e835524 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -746,27 +745,6 @@ int proc_dointvec(struct ctl_table *table, int write, void *buffer, return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL); } -#ifdef CONFIG_COMPACTION -static int proc_dointvec_minmax_warn_RT_change(struct ctl_table *table, - int write, void *buffer, size_t *lenp, loff_t *ppos) -{ - int ret, old; - - if (!IS_ENABLED(CONFIG_PREEMPT_RT) || !write) - return proc_dointvec_minmax(table, write, buffer, lenp, ppos); - - old = *(int *)table->data; - ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (ret) - return ret; - if (old != *(int *)table->data) - pr_warn_once("sysctl attribute %s changed by %s[%d]\n", - table->procname, current->comm, - task_pid_nr(current)); - return ret; -} -#endif - /** * proc_douintvec - read a vector of unsigned integers * @table: the sysctl table @@ -2157,43 +2135,6 @@ static struct ctl_table vm_table[] = { .extra1 = SYSCTL_ONE, .extra2 = SYSCTL_FOUR, }, -#ifdef CONFIG_COMPACTION - { - .procname = "compact_memory", - .data = NULL, - .maxlen = sizeof(int), - .mode = 0200, - .proc_handler = sysctl_compaction_handler, - }, - { - .procname = "compaction_proactiveness", - .data = &sysctl_compaction_proactiveness, - .maxlen = sizeof(sysctl_compaction_proactiveness), - .mode = 0644, - .proc_handler = compaction_proactiveness_sysctl_handler, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE_HUNDRED, - }, - { - .procname = "extfrag_threshold", - .data = &sysctl_extfrag_threshold, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE_THOUSAND, - }, - { - .procname = "compact_unevictable_allowed", - .data = &sysctl_compact_unevictable_allowed, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax_warn_RT_change, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, - -#endif /* CONFIG_COMPACTION */ { .procname = "min_free_kbytes", .data = &min_free_kbytes, diff --git a/mm/compaction.c b/mm/compaction.c index 5a9501e0ae01..f2ddfb1140e2 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1716,7 +1716,14 @@ typedef enum { * Allow userspace to control policy on scanning the unevictable LRU for * compactable pages. */ -int sysctl_compact_unevictable_allowed __read_mostly = CONFIG_COMPACT_UNEVICTABLE_DEFAULT; +static int sysctl_compact_unevictable_allowed __read_mostly = CONFIG_COMPACT_UNEVICTABLE_DEFAULT; +/* + * Tunable for proactive compaction. It determines how + * aggressively the kernel should compact memory in the + * background. It takes values in the range [0, 100]. + */ +static unsigned int __read_mostly sysctl_compaction_proactiveness = 20; +static int sysctl_extfrag_threshold = 500; static inline void update_fast_start_pfn(struct compact_control *cc, unsigned long pfn) @@ -2572,8 +2579,6 @@ static enum compact_result compact_zone_order(struct zone *zone, int order, return ret; } -int sysctl_extfrag_threshold = 500; - /** * try_to_compact_pages - Direct compact to satisfy a high-order allocation * @gfp_mask: The GFP mask of the current allocation @@ -2730,14 +2735,7 @@ static void compact_nodes(void) compact_node(nid); } -/* - * Tunable for proactive compaction. It determines how - * aggressively the kernel should compact memory in the - * background. It takes values in the range [0, 100]. - */ -unsigned int __read_mostly sysctl_compaction_proactiveness = 20; - -int compaction_proactiveness_sysctl_handler(struct ctl_table *table, int write, +static int compaction_proactiveness_sysctl_handler(struct ctl_table *table, int write, void *buffer, size_t *length, loff_t *ppos) { int rc, nid; @@ -2767,7 +2765,7 @@ int compaction_proactiveness_sysctl_handler(struct ctl_table *table, int write, * This is the entry point for compacting all nodes via * /proc/sys/vm/compact_memory */ -int sysctl_compaction_handler(struct ctl_table *table, int write, +static int sysctl_compaction_handler(struct ctl_table *table, int write, void *buffer, size_t *length, loff_t *ppos) { if (write) @@ -3063,6 +3061,65 @@ static int kcompactd_cpu_online(unsigned int cpu) return 0; } +static int proc_dointvec_minmax_warn_RT_change(struct ctl_table *table, + int write, void *buffer, size_t *lenp, loff_t *ppos) +{ + int ret, old; + + if (!IS_ENABLED(CONFIG_PREEMPT_RT) || !write) + return proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + old = *(int *)table->data; + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + if (ret) + return ret; + if (old != *(int *)table->data) + pr_warn_once("sysctl attribute %s changed by %s[%d]\n", + table->procname, current->comm, + task_pid_nr(current)); + return ret; +} + +#ifdef CONFIG_SYSCTL +static struct ctl_table vm_compaction[] = { + { + .procname = "compact_memory", + .data = NULL, + .maxlen = sizeof(int), + .mode = 0200, + .proc_handler = sysctl_compaction_handler, + }, + { + .procname = "compaction_proactiveness", + .data = &sysctl_compaction_proactiveness, + .maxlen = sizeof(sysctl_compaction_proactiveness), + .mode = 0644, + .proc_handler = compaction_proactiveness_sysctl_handler, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE_HUNDRED, + }, + { + .procname = "extfrag_threshold", + .data = &sysctl_extfrag_threshold, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE_THOUSAND, + }, + { + .procname = "compact_unevictable_allowed", + .data = &sysctl_compact_unevictable_allowed, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax_warn_RT_change, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { } +}; +#endif + static int __init kcompactd_init(void) { int nid; @@ -3078,6 +3135,9 @@ static int __init kcompactd_init(void) for_each_node_state(nid, N_MEMORY) kcompactd_run(nid); +#ifdef CONFIG_SYSCTL + register_sysctl_init("vm", vm_compaction); +#endif return 0; } subsys_initcall(kcompactd_init) From b3f312c4815d7acf6c7f88f921544626c31bd24a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Mar 2023 10:02:41 +0200 Subject: [PATCH 091/182] mm: compaction: remove incorrect #ifdef checks Without CONFIG_SYSCTL, the compiler warns about a few unused functions: mm/compaction.c:3076:12: error: 'proc_dointvec_minmax_warn_RT_change' defined but not used [-Werror=unused-function] mm/compaction.c:2780:12: error: 'sysctl_compaction_handler' defined but not used [-Werror=unused-function] mm/compaction.c:2750:12: error: 'compaction_proactiveness_sysctl_handler' defined but not used [-Werror=unused-function] The #ifdef is actually not necessary here, as the alternative register_sysctl_init() stub function does not use its argument, which lets the compiler drop the rest implicitly, while avoiding the warning. Fixes: c521126610c3 ("mm: compaction: move compaction sysctl to its own file") Signed-off-by: Arnd Bergmann Signed-off-by: Luis Chamberlain --- mm/compaction.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index f2ddfb1140e2..9ff71239b1fc 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -3080,7 +3080,6 @@ static int proc_dointvec_minmax_warn_RT_change(struct ctl_table *table, return ret; } -#ifdef CONFIG_SYSCTL static struct ctl_table vm_compaction[] = { { .procname = "compact_memory", @@ -3118,7 +3117,6 @@ static struct ctl_table vm_compaction[] = { }, { } }; -#endif static int __init kcompactd_init(void) { @@ -3135,9 +3133,7 @@ static int __init kcompactd_init(void) for_each_node_state(nid, N_MEMORY) kcompactd_run(nid); -#ifdef CONFIG_SYSCTL register_sysctl_init("vm", vm_compaction); -#endif return 0; } subsys_initcall(kcompactd_init) From e3184de9d46c2eebdb776face2e2662c6733331d Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Fri, 31 Mar 2023 16:45:02 +0800 Subject: [PATCH 092/182] fs: fix sysctls.c built 'obj-$(CONFIG_SYSCTL) += sysctls.o' must be moved after "obj-y :=", or it won't be built as it is overwrited. Note that there is nothing that is going to break by linking sysctl.o later, we were just being way to cautious and patches have been updated to reflect these considerations and sent for stable as well with the whole "base" stuff needing to be linked prior to child sysctl tables that use that directory. All of the kernel sysctl APIs always share the same directory, and races against using it should end up re-using the same single created directory. And so something we can do eventually is do away with all the base stuff. For now it's fine, it's not creating an issue. It is just a bit pedantic and careful. Fixes: ab171b952c6e ("fs: move namespace sysctls and declare fs base directory") Cc: stable@vger.kernel.org # v5.17 Cc: Christian Brauner Cc: Kefeng Wang Signed-off-by: Kefeng Wang [mcgrof: enhanced commit log for stable criteria and clarify base stuff ] Signed-off-by: Luis Chamberlain --- fs/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/Makefile b/fs/Makefile index 05f89b5c962f..8d4736fcc766 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -6,7 +6,6 @@ # Rewritten to use lists instead of if-statements. # -obj-$(CONFIG_SYSCTL) += sysctls.o obj-y := open.o read_write.o file_table.o super.o \ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ @@ -50,7 +49,7 @@ obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_COREDUMP) += coredump.o -obj-$(CONFIG_SYSCTL) += drop_caches.o +obj-$(CONFIG_SYSCTL) += drop_caches.o sysctls.o obj-$(CONFIG_FHANDLE) += fhandle.o obj-y += iomap/ From a4fea9b78ebea6df9a61f34cfc2f7ed0bbc8a9fc Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 20 Mar 2023 00:47:36 -0700 Subject: [PATCH 093/182] drivers/clocksource/hyper-v: non ACPI support in hyperv clock Add a placeholder function for the hv_setup_stimer0_irq API to accommodate systems without ACPI support. Since this function is not utilized on x86/x64 systems and non-ACPI support is only intended for x86/x64 systems, a placeholder function is sufficient for now and can be improved upon if necessary in the future. Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/1679298460-11855-2-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- drivers/clocksource/hyperv_timer.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index c0cef92b12b8..f32948c8a96f 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -49,7 +49,7 @@ static bool direct_mode_enabled; static int stimer0_irq = -1; static int stimer0_message_sint; -static DEFINE_PER_CPU(long, stimer0_evt); +static __maybe_unused DEFINE_PER_CPU(long, stimer0_evt); /* * Common code for stimer0 interrupts coming via Direct Mode or @@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(hv_stimer0_isr); * stimer0 interrupt handler for architectures that support * per-cpu interrupts, which also implies Direct Mode. */ -static irqreturn_t hv_stimer0_percpu_isr(int irq, void *dev_id) +static irqreturn_t __maybe_unused hv_stimer0_percpu_isr(int irq, void *dev_id) { hv_stimer0_isr(); return IRQ_HANDLED; @@ -196,6 +196,7 @@ void __weak hv_remove_stimer0_handler(void) { }; +#ifdef CONFIG_ACPI /* Called only on architectures with per-cpu IRQs (i.e., not x86/x64) */ static int hv_setup_stimer0_irq(void) { @@ -230,6 +231,16 @@ static void hv_remove_stimer0_irq(void) stimer0_irq = -1; } } +#else +static int hv_setup_stimer0_irq(void) +{ + return 0; +} + +static void hv_remove_stimer0_irq(void) +{ +} +#endif /* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */ int hv_stimer_alloc(bool have_percpu_irqs) From 1f6277bf716cc5ba0e3fa0c3e0af1adb4160fb5d Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 20 Mar 2023 00:47:37 -0700 Subject: [PATCH 094/182] ACPI: bus: Add stub acpi_sleep_state_supported() in non-ACPI cases acpi_sleep_state_supported() is defined only when CONFIG_ACPI=y. The function is in acpi_bus.h, and acpi_bus.h can only be used in CONFIG_ACPI=y cases. Add the stub function to linux/acpi.h to make compilation successful for !CONFIG_ACPI cases. Signed-off-by: Saurabh Sengar Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/1679298460-11855-3-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- include/linux/acpi.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index efff750f326d..d331f76b0c19 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1075,6 +1075,11 @@ static inline u32 acpi_osc_ctx_get_cxl_control(struct acpi_osc_context *context) return 0; } +static inline bool acpi_sleep_state_supported(u8 sleep_state) +{ + return false; +} + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC From 9c8434238041e18d53fd6911826973b37656a8d1 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 20 Mar 2023 00:47:38 -0700 Subject: [PATCH 095/182] Drivers: hv: vmbus: Convert acpi_device to more generic platform_device VMBus driver code currently has direct dependency on ACPI and struct acpi_device. As a staging step toward optionally configuring based on Devicetree instead of ACPI, use a more generic platform device to reduce the dependency on ACPI where possible, though the dependency on ACPI is not completely removed. Also rename the function vmbus_acpi_remove() to the more generic vmbus_mmio_remove(). Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/1679298460-11855-4-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- drivers/hv/vmbus_drv.c | 58 +++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index d24dd65b33d4..73497157a23a 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ struct vmbus_dynid { struct hv_vmbus_device_id id; }; -static struct acpi_device *hv_acpi_dev; +static struct device *hv_dev; static int hyperv_cpuhp_online; @@ -143,7 +144,7 @@ static DEFINE_MUTEX(hyperv_mmio_lock); static int vmbus_exists(void) { - if (hv_acpi_dev == NULL) + if (hv_dev == NULL) return -ENODEV; return 0; @@ -932,7 +933,7 @@ static int vmbus_dma_configure(struct device *child_device) * On x86/x64 coherence is assumed and these calls have no effect. */ hv_setup_dma_ops(child_device, - device_get_dma_attr(&hv_acpi_dev->dev) == DEV_DMA_COHERENT); + device_get_dma_attr(hv_dev) == DEV_DMA_COHERENT); return 0; } @@ -2090,7 +2091,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) &child_device_obj->channel->offermsg.offer.if_instance); child_device_obj->device.bus = &hv_bus; - child_device_obj->device.parent = &hv_acpi_dev->dev; + child_device_obj->device.parent = hv_dev; child_device_obj->device.release = vmbus_device_release; child_device_obj->device.dma_parms = &child_device_obj->dma_parms; @@ -2262,7 +2263,7 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) return AE_OK; } -static void vmbus_acpi_remove(struct acpi_device *device) +static void vmbus_mmio_remove(void) { struct resource *cur_res; struct resource *next_res; @@ -2441,13 +2442,14 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) } EXPORT_SYMBOL_GPL(vmbus_free_mmio); -static int vmbus_acpi_add(struct acpi_device *device) +static int vmbus_acpi_add(struct platform_device *pdev) { acpi_status result; int ret_val = -ENODEV; struct acpi_device *ancestor; + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); - hv_acpi_dev = device; + hv_dev = &device->dev; /* * Older versions of Hyper-V for ARM64 fail to include the _CCA @@ -2489,10 +2491,21 @@ static int vmbus_acpi_add(struct acpi_device *device) acpi_walk_err: if (ret_val) - vmbus_acpi_remove(device); + vmbus_mmio_remove(); return ret_val; } +static int vmbus_platform_driver_probe(struct platform_device *pdev) +{ + return vmbus_acpi_add(pdev); +} + +static int vmbus_platform_driver_remove(struct platform_device *pdev) +{ + vmbus_mmio_remove(); + return 0; +} + #ifdef CONFIG_PM_SLEEP static int vmbus_bus_suspend(struct device *dev) { @@ -2658,15 +2671,15 @@ static const struct dev_pm_ops vmbus_bus_pm = { .restore_noirq = vmbus_bus_resume }; -static struct acpi_driver vmbus_acpi_driver = { - .name = "vmbus", - .ids = vmbus_acpi_device_ids, - .ops = { - .add = vmbus_acpi_add, - .remove = vmbus_acpi_remove, - }, - .drv.pm = &vmbus_bus_pm, - .drv.probe_type = PROBE_FORCE_SYNCHRONOUS, +static struct platform_driver vmbus_platform_driver = { + .probe = vmbus_platform_driver_probe, + .remove = vmbus_platform_driver_remove, + .driver = { + .name = "vmbus", + .acpi_match_table = ACPI_PTR(vmbus_acpi_device_ids), + .pm = &vmbus_bus_pm, + .probe_type = PROBE_FORCE_SYNCHRONOUS, + } }; static void hv_kexec_handler(void) @@ -2750,12 +2763,11 @@ static int __init hv_acpi_init(void) /* * Get ACPI resources first. */ - ret = acpi_bus_register_driver(&vmbus_acpi_driver); - + ret = platform_driver_register(&vmbus_platform_driver); if (ret) return ret; - if (!hv_acpi_dev) { + if (!hv_dev) { ret = -ENODEV; goto cleanup; } @@ -2785,8 +2797,8 @@ static int __init hv_acpi_init(void) return 0; cleanup: - acpi_bus_unregister_driver(&vmbus_acpi_driver); - hv_acpi_dev = NULL; + platform_driver_unregister(&vmbus_platform_driver); + hv_dev = NULL; return ret; } @@ -2839,7 +2851,7 @@ static void __exit vmbus_exit(void) cpuhp_remove_state(hyperv_cpuhp_online); hv_synic_free(); - acpi_bus_unregister_driver(&vmbus_acpi_driver); + platform_driver_unregister(&vmbus_platform_driver); } From 61f7a325927e6f15de09aef96eea54801b227864 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 20 Mar 2023 00:47:39 -0700 Subject: [PATCH 096/182] dt-bindings: bus: Add Hyper-V VMBus Add dt-bindings for Hyper-V VMBus. Signed-off-by: Saurabh Sengar Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1679298460-11855-5-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- .../bindings/bus/microsoft,vmbus.yaml | 54 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml diff --git a/Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml b/Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml new file mode 100644 index 000000000000..a8d40c766dcd --- /dev/null +++ b/Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bus/microsoft,vmbus.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microsoft Hyper-V VMBus + +maintainers: + - Saurabh Sengar + +description: + VMBus is a software bus that implement the protocols for communication + between the root or host OS and guest OSs (virtual machines). + +properties: + compatible: + const: microsoft,vmbus + + ranges: true + + '#address-cells': + const: 2 + + '#size-cells': + const: 1 + +required: + - compatible + - ranges + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <1>; + bus { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges; + + vmbus@ff0000000 { + compatible = "microsoft,vmbus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0x0f 0xf0000000 0x0f 0xf0000000 0x10000000>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 0e64787aace8..90ea0a7fb733 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9520,6 +9520,7 @@ S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git F: Documentation/ABI/stable/sysfs-bus-vmbus F: Documentation/ABI/testing/debugfs-hyperv +F: Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml F: Documentation/virt/hyperv F: Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst F: arch/arm64/hyperv From f83705a51275ed29117d46e1d68e8b16dcb40507 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 20 Mar 2023 00:47:40 -0700 Subject: [PATCH 097/182] Driver: VMBus: Add Devicetree support Update the driver to support Devicetree boot as well along with ACPI. At present the Devicetree parsing only provides the mmio region info and is not the exact copy of ACPI parsing. This is sufficient to cater all the current Devicetree usecases for VMBus. Currently Devicetree is supported only for x86 systems. Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/1679298460-11855-6-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- drivers/hv/Kconfig | 5 ++-- drivers/hv/vmbus_drv.c | 66 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 0747a8f1fcee..47132b30b7ee 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -4,11 +4,12 @@ menu "Microsoft Hyper-V guest support" config HYPERV tristate "Microsoft Hyper-V client drivers" - depends on ACPI && ((X86 && X86_LOCAL_APIC && HYPERVISOR_GUEST) \ - || (ARM64 && !CPU_BIG_ENDIAN)) + depends on (X86 && X86_LOCAL_APIC && HYPERVISOR_GUEST) \ + || (ACPI && ARM64 && !CPU_BIG_ENDIAN) select PARAVIRT select X86_HV_CALLBACK_VECTOR if X86 select VMAP_PFN + select OF_EARLY_FLATTREE if OF help Select this option to run Linux as a Hyper-V client operating system. diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 73497157a23a..20b4be426e0c 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2152,7 +2153,7 @@ void vmbus_device_unregister(struct hv_device *device_obj) device_unregister(&device_obj->device); } - +#ifdef CONFIG_ACPI /* * VMBUS is an acpi enumerated device. Get the information we * need from DSDT. @@ -2262,6 +2263,7 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) return AE_OK; } +#endif static void vmbus_mmio_remove(void) { @@ -2282,7 +2284,7 @@ static void vmbus_mmio_remove(void) } } -static void vmbus_reserve_fb(void) +static void __maybe_unused vmbus_reserve_fb(void) { resource_size_t start = 0, size; struct pci_dev *pdev; @@ -2442,6 +2444,7 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) } EXPORT_SYMBOL_GPL(vmbus_free_mmio); +#ifdef CONFIG_ACPI static int vmbus_acpi_add(struct platform_device *pdev) { acpi_status result; @@ -2494,10 +2497,54 @@ acpi_walk_err: vmbus_mmio_remove(); return ret_val; } +#else +static int vmbus_acpi_add(struct platform_device *pdev) +{ + return 0; +} +#endif + +static int vmbus_device_add(struct platform_device *pdev) +{ + struct resource **cur_res = &hyperv_mmio; + struct of_range range; + struct of_range_parser parser; + struct device_node *np = pdev->dev.of_node; + int ret; + + hv_dev = &pdev->dev; + + ret = of_range_parser_init(&parser, np); + if (ret) + return ret; + + for_each_of_range(&parser, &range) { + struct resource *res; + + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (!res) { + vmbus_mmio_remove(); + return -ENOMEM; + } + + res->name = "hyperv mmio"; + res->flags = range.flags; + res->start = range.cpu_addr; + res->end = range.cpu_addr + range.size; + + *cur_res = res; + cur_res = &res->sibling; + } + + return ret; +} static int vmbus_platform_driver_probe(struct platform_device *pdev) { - return vmbus_acpi_add(pdev); + if (acpi_disabled) + return vmbus_device_add(pdev); + else + return vmbus_acpi_add(pdev); } static int vmbus_platform_driver_remove(struct platform_device *pdev) @@ -2643,7 +2690,17 @@ static int vmbus_bus_resume(struct device *dev) #define vmbus_bus_resume NULL #endif /* CONFIG_PM_SLEEP */ -static const struct acpi_device_id vmbus_acpi_device_ids[] = { +static const __maybe_unused struct of_device_id vmbus_of_match[] = { + { + .compatible = "microsoft,vmbus", + }, + { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, vmbus_of_match); + +static const __maybe_unused struct acpi_device_id vmbus_acpi_device_ids[] = { {"VMBUS", 0}, {"VMBus", 0}, {"", 0}, @@ -2677,6 +2734,7 @@ static struct platform_driver vmbus_platform_driver = { .driver = { .name = "vmbus", .acpi_match_table = ACPI_PTR(vmbus_acpi_device_ids), + .of_match_table = of_match_ptr(vmbus_of_match), .pm = &vmbus_bus_pm, .probe_type = PROBE_FORCE_SYNCHRONOUS, } From 0459ff4873739986dccafbb417cfc69e71bdacf4 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 26 Mar 2023 06:52:02 -0700 Subject: [PATCH 098/182] swiotlb: Remove bounce buffer remapping for Hyper-V With changes to how Hyper-V guest VMs flip memory between private (encrypted) and shared (decrypted), creating a second kernel virtual mapping for shared memory is no longer necessary. Everything needed for the transition to shared is handled by set_memory_decrypted(). As such, remove swiotlb_unencrypted_base and the associated code. Signed-off-by: Michael Kelley Acked-by: Christoph Hellwig Acked-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/1679838727-87310-8-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/kernel/cpu/mshyperv.c | 7 +----- include/linux/swiotlb.h | 2 -- kernel/dma/swiotlb.c | 45 +--------------------------------- 3 files changed, 2 insertions(+), 52 deletions(-) diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 315fc358e584..ac630ecde795 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -408,12 +407,8 @@ static void __init ms_hyperv_init_platform(void) pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); - if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) { + if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) static_branch_enable(&isolation_type_snp); -#ifdef CONFIG_SWIOTLB - swiotlb_unencrypted_base = ms_hyperv.shared_gpa_boundary; -#endif - } } if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index bcef10e20ea4..2ef25e6fa1b4 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -180,6 +180,4 @@ static inline bool is_swiotlb_for_alloc(struct device *dev) } #endif /* CONFIG_DMA_RESTRICTED_POOL */ -extern phys_addr_t swiotlb_unencrypted_base; - #endif /* __LINUX_SWIOTLB_H */ diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index dac42a2ad588..0fb16bdbbcae 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -73,8 +73,6 @@ static bool swiotlb_force_disable; struct io_tlb_mem io_tlb_default_mem; -phys_addr_t swiotlb_unencrypted_base; - static unsigned long default_nslabs = IO_TLB_DEFAULT_SIZE >> IO_TLB_SHIFT; static unsigned long default_nareas; @@ -201,34 +199,6 @@ static inline unsigned long nr_slots(u64 val) return DIV_ROUND_UP(val, IO_TLB_SIZE); } -/* - * Remap swioltb memory in the unencrypted physical address space - * when swiotlb_unencrypted_base is set. (e.g. for Hyper-V AMD SEV-SNP - * Isolation VMs). - */ -#ifdef CONFIG_HAS_IOMEM -static void *swiotlb_mem_remap(struct io_tlb_mem *mem, unsigned long bytes) -{ - void *vaddr = NULL; - - if (swiotlb_unencrypted_base) { - phys_addr_t paddr = mem->start + swiotlb_unencrypted_base; - - vaddr = memremap(paddr, bytes, MEMREMAP_WB); - if (!vaddr) - pr_err("Failed to map the unencrypted memory %pa size %lx.\n", - &paddr, bytes); - } - - return vaddr; -} -#else -static void *swiotlb_mem_remap(struct io_tlb_mem *mem, unsigned long bytes) -{ - return NULL; -} -#endif - /* * Early SWIOTLB allocation may be too early to allow an architecture to * perform the desired operations. This function allows the architecture to @@ -238,18 +208,12 @@ static void *swiotlb_mem_remap(struct io_tlb_mem *mem, unsigned long bytes) void __init swiotlb_update_mem_attributes(void) { struct io_tlb_mem *mem = &io_tlb_default_mem; - void *vaddr; unsigned long bytes; if (!mem->nslabs || mem->late_alloc) return; - vaddr = phys_to_virt(mem->start); bytes = PAGE_ALIGN(mem->nslabs << IO_TLB_SHIFT); - set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT); - - mem->vaddr = swiotlb_mem_remap(mem, bytes); - if (!mem->vaddr) - mem->vaddr = vaddr; + set_memory_decrypted((unsigned long)mem->vaddr, bytes >> PAGE_SHIFT); } static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, @@ -280,13 +244,6 @@ static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, mem->slots[i].alloc_size = 0; } - /* - * If swiotlb_unencrypted_base is set, the bounce buffer memory will - * be remapped and cleared in swiotlb_update_mem_attributes. - */ - if (swiotlb_unencrypted_base) - return; - memset(vaddr, 0, bytes); mem->vaddr = vaddr; return; From a5ddb74588213c31ce993a8e9a09d1ffdc11a142 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 26 Mar 2023 06:52:03 -0700 Subject: [PATCH 099/182] Drivers: hv: vmbus: Remove second mapping of VMBus monitor pages With changes to how Hyper-V guest VMs flip memory between private (encrypted) and shared (decrypted), creating a second kernel virtual mapping for shared memory is no longer necessary. Everything needed for the transition to shared is handled by set_memory_decrypted(). As such, remove the code to create and manage the second mapping for VMBus monitor pages. Because set_memory_decrypted() and set_memory_encrypted() are no-ops in normal VMs, it's not even necessary to test for being in a Confidential VM (a.k.a., "Isolation VM"). Signed-off-by: Michael Kelley Reviewed-by: Tianyu Lan Link: https://lore.kernel.org/r/1679838727-87310-9-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- drivers/hv/connection.c | 113 ++++++++++---------------------------- drivers/hv/hyperv_vmbus.h | 2 - 2 files changed, 28 insertions(+), 87 deletions(-) diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index da51b50787df..5978e9dbc286 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -104,8 +104,14 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; } - msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0]; - msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1]; + /* + * shared_gpa_boundary is zero in non-SNP VMs, so it's safe to always + * bitwise OR it + */ + msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]) | + ms_hyperv.shared_gpa_boundary; + msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]) | + ms_hyperv.shared_gpa_boundary; msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU); @@ -219,72 +225,27 @@ int vmbus_connect(void) * Setup the monitor notification facility. The 1st page for * parent->child and the 2nd page for child->parent */ - vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_zeroed_page(); - vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_zeroed_page(); + vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_page(); + vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_page(); if ((vmbus_connection.monitor_pages[0] == NULL) || (vmbus_connection.monitor_pages[1] == NULL)) { ret = -ENOMEM; goto cleanup; } - vmbus_connection.monitor_pages_original[0] - = vmbus_connection.monitor_pages[0]; - vmbus_connection.monitor_pages_original[1] - = vmbus_connection.monitor_pages[1]; - vmbus_connection.monitor_pages_pa[0] - = virt_to_phys(vmbus_connection.monitor_pages[0]); - vmbus_connection.monitor_pages_pa[1] - = virt_to_phys(vmbus_connection.monitor_pages[1]); + ret = set_memory_decrypted((unsigned long) + vmbus_connection.monitor_pages[0], 1); + ret |= set_memory_decrypted((unsigned long) + vmbus_connection.monitor_pages[1], 1); + if (ret) + goto cleanup; - if (hv_is_isolation_supported()) { - ret = set_memory_decrypted((unsigned long) - vmbus_connection.monitor_pages[0], - 1); - ret |= set_memory_decrypted((unsigned long) - vmbus_connection.monitor_pages[1], - 1); - if (ret) - goto cleanup; - - /* - * Isolation VM with AMD SNP needs to access monitor page via - * address space above shared gpa boundary. - */ - if (hv_isolation_type_snp()) { - vmbus_connection.monitor_pages_pa[0] += - ms_hyperv.shared_gpa_boundary; - vmbus_connection.monitor_pages_pa[1] += - ms_hyperv.shared_gpa_boundary; - - vmbus_connection.monitor_pages[0] - = memremap(vmbus_connection.monitor_pages_pa[0], - HV_HYP_PAGE_SIZE, - MEMREMAP_WB); - if (!vmbus_connection.monitor_pages[0]) { - ret = -ENOMEM; - goto cleanup; - } - - vmbus_connection.monitor_pages[1] - = memremap(vmbus_connection.monitor_pages_pa[1], - HV_HYP_PAGE_SIZE, - MEMREMAP_WB); - if (!vmbus_connection.monitor_pages[1]) { - ret = -ENOMEM; - goto cleanup; - } - } - - /* - * Set memory host visibility hvcall smears memory - * and so zero monitor pages here. - */ - memset(vmbus_connection.monitor_pages[0], 0x00, - HV_HYP_PAGE_SIZE); - memset(vmbus_connection.monitor_pages[1], 0x00, - HV_HYP_PAGE_SIZE); - - } + /* + * Set_memory_decrypted() will change the memory contents if + * decryption occurs, so zero monitor pages here. + */ + memset(vmbus_connection.monitor_pages[0], 0x00, HV_HYP_PAGE_SIZE); + memset(vmbus_connection.monitor_pages[1], 0x00, HV_HYP_PAGE_SIZE); msginfo = kzalloc(sizeof(*msginfo) + sizeof(struct vmbus_channel_initiate_contact), @@ -376,31 +337,13 @@ void vmbus_disconnect(void) vmbus_connection.int_page = NULL; } - if (hv_is_isolation_supported()) { - /* - * memunmap() checks input address is ioremap address or not - * inside. It doesn't unmap any thing in the non-SNP CVM and - * so not check CVM type here. - */ - memunmap(vmbus_connection.monitor_pages[0]); - memunmap(vmbus_connection.monitor_pages[1]); + set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[0], 1); + set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[1], 1); - set_memory_encrypted((unsigned long) - vmbus_connection.monitor_pages_original[0], - 1); - set_memory_encrypted((unsigned long) - vmbus_connection.monitor_pages_original[1], - 1); - } - - hv_free_hyperv_page((unsigned long) - vmbus_connection.monitor_pages_original[0]); - hv_free_hyperv_page((unsigned long) - vmbus_connection.monitor_pages_original[1]); - vmbus_connection.monitor_pages_original[0] = - vmbus_connection.monitor_pages[0] = NULL; - vmbus_connection.monitor_pages_original[1] = - vmbus_connection.monitor_pages[1] = NULL; + hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]); + hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]); + vmbus_connection.monitor_pages[0] = NULL; + vmbus_connection.monitor_pages[1] = NULL; } /* diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index dc673edf053c..167ac5115a78 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -241,8 +241,6 @@ struct vmbus_connection { * is child->parent notification */ struct hv_monitor_page *monitor_pages[2]; - void *monitor_pages_original[2]; - phys_addr_t monitor_pages_pa[2]; struct list_head chn_msg_list; spinlock_t channelmsg_lock; From bb862397f48fc79a1ea31b83a0bd8f1f913b4ab6 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 26 Mar 2023 06:52:04 -0700 Subject: [PATCH 100/182] Drivers: hv: vmbus: Remove second way of mapping ring buffers With changes to how Hyper-V guest VMs flip memory between private (encrypted) and shared (decrypted), it's no longer necessary to have separate code paths for mapping VMBus ring buffers for for normal VMs and for Confidential VMs. As such, remove the code path that uses vmap_pfn(), and set the protection flags argument to vmap() to account for the difference between normal and Confidential VMs. Signed-off-by: Michael Kelley Reviewed-by: Tianyu Lan Link: https://lore.kernel.org/r/1679838727-87310-10-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- drivers/hv/ring_buffer.c | 62 +++++++++++++--------------------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 2111e97c3b63..3c9b02471760 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -186,8 +186,6 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, struct page *pages, u32 page_cnt, u32 max_pkt_size) { struct page **pages_wraparound; - unsigned long *pfns_wraparound; - u64 pfn; int i; BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); @@ -196,50 +194,30 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, * First page holds struct hv_ring_buffer, do wraparound mapping for * the rest. */ - if (hv_isolation_type_snp()) { - pfn = page_to_pfn(pages) + - PFN_DOWN(ms_hyperv.shared_gpa_boundary); + pages_wraparound = kcalloc(page_cnt * 2 - 1, + sizeof(struct page *), + GFP_KERNEL); + if (!pages_wraparound) + return -ENOMEM; - pfns_wraparound = kcalloc(page_cnt * 2 - 1, - sizeof(unsigned long), GFP_KERNEL); - if (!pfns_wraparound) - return -ENOMEM; + pages_wraparound[0] = pages; + for (i = 0; i < 2 * (page_cnt - 1); i++) + pages_wraparound[i + 1] = + &pages[i % (page_cnt - 1) + 1]; - pfns_wraparound[0] = pfn; - for (i = 0; i < 2 * (page_cnt - 1); i++) - pfns_wraparound[i + 1] = pfn + i % (page_cnt - 1) + 1; + ring_info->ring_buffer = (struct hv_ring_buffer *) + vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, + pgprot_decrypted(PAGE_KERNEL)); - ring_info->ring_buffer = (struct hv_ring_buffer *) - vmap_pfn(pfns_wraparound, page_cnt * 2 - 1, - pgprot_decrypted(PAGE_KERNEL)); - kfree(pfns_wraparound); - - if (!ring_info->ring_buffer) - return -ENOMEM; - - /* Zero ring buffer after setting memory host visibility. */ - memset(ring_info->ring_buffer, 0x00, PAGE_SIZE * page_cnt); - } else { - pages_wraparound = kcalloc(page_cnt * 2 - 1, - sizeof(struct page *), - GFP_KERNEL); - if (!pages_wraparound) - return -ENOMEM; - - pages_wraparound[0] = pages; - for (i = 0; i < 2 * (page_cnt - 1); i++) - pages_wraparound[i + 1] = - &pages[i % (page_cnt - 1) + 1]; - - ring_info->ring_buffer = (struct hv_ring_buffer *) - vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, - PAGE_KERNEL); - - kfree(pages_wraparound); - if (!ring_info->ring_buffer) - return -ENOMEM; - } + kfree(pages_wraparound); + if (!ring_info->ring_buffer) + return -ENOMEM; + /* + * Ensure the header page is zero'ed since + * encryption status may have changed. + */ + memset(ring_info->ring_buffer, 0, HV_HYP_PAGE_SIZE); ring_info->ring_buffer->read_index = ring_info->ring_buffer->write_index = 0; From 25727aaed6514b88f98a18862c6f2d65a0b0ec3b Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 26 Mar 2023 06:52:05 -0700 Subject: [PATCH 101/182] hv_netvsc: Remove second mapping of send and recv buffers With changes to how Hyper-V guest VMs flip memory between private (encrypted) and shared (decrypted), creating a second kernel virtual mapping for shared memory is no longer necessary. Everything needed for the transition to shared is handled by set_memory_decrypted(). As such, remove the code to create and manage the second mapping for the pre-allocated send and recv buffers. This mapping is the last user of hv_map_memory()/hv_unmap_memory(), so delete these functions as well. Finally, hv_map_memory() is the last user of vmap_pfn() in Hyper-V guest code, so remove the Kconfig selection of VMAP_PFN. Signed-off-by: Michael Kelley Reviewed-by: Tianyu Lan Link: https://lore.kernel.org/r/1679838727-87310-11-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/ivm.c | 28 ------------------- drivers/hv/Kconfig | 1 - drivers/hv/hv_common.c | 11 -------- drivers/net/hyperv/hyperv_net.h | 2 -- drivers/net/hyperv/netvsc.c | 48 ++------------------------------- include/asm-generic/mshyperv.h | 2 -- 6 files changed, 2 insertions(+), 90 deletions(-) diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index f6a020cb1a24..127d5b7b63de 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -376,34 +376,6 @@ void __init hv_vtom_init(void) #endif /* CONFIG_AMD_MEM_ENCRYPT */ -/* - * hv_map_memory - map memory to extra space in the AMD SEV-SNP Isolation VM. - */ -void *hv_map_memory(void *addr, unsigned long size) -{ - unsigned long *pfns = kcalloc(size / PAGE_SIZE, - sizeof(unsigned long), GFP_KERNEL); - void *vaddr; - int i; - - if (!pfns) - return NULL; - - for (i = 0; i < size / PAGE_SIZE; i++) - pfns[i] = vmalloc_to_pfn(addr + i * PAGE_SIZE) + - (ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT); - - vaddr = vmap_pfn(pfns, size / PAGE_SIZE, pgprot_decrypted(PAGE_KERNEL)); - kfree(pfns); - - return vaddr; -} - -void hv_unmap_memory(void *addr) -{ - vunmap(addr); -} - enum hv_isolation_type hv_get_isolation_type(void) { if (!(ms_hyperv.priv_high & HV_ISOLATION)) diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 47132b30b7ee..94982f08b661 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -8,7 +8,6 @@ config HYPERV || (ACPI && ARM64 && !CPU_BIG_ENDIAN) select PARAVIRT select X86_HV_CALLBACK_VECTOR if X86 - select VMAP_PFN select OF_EARLY_FLATTREE if OF help Select this option to run Linux as a Hyper-V client operating diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 52a6f89ccdbd..6d40b6c7b23b 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -311,14 +311,3 @@ u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_s return HV_STATUS_INVALID_PARAMETER; } EXPORT_SYMBOL_GPL(hv_ghcb_hypercall); - -void __weak *hv_map_memory(void *addr, unsigned long size) -{ - return NULL; -} -EXPORT_SYMBOL_GPL(hv_map_memory); - -void __weak hv_unmap_memory(void *addr) -{ -} -EXPORT_SYMBOL_GPL(hv_unmap_memory); diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index dd5919ec408b..33d51e363913 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -1139,7 +1139,6 @@ struct netvsc_device { /* Receive buffer allocated by us but manages by NetVSP */ void *recv_buf; - void *recv_original_buf; u32 recv_buf_size; /* allocated bytes */ struct vmbus_gpadl recv_buf_gpadl_handle; u32 recv_section_cnt; @@ -1148,7 +1147,6 @@ struct netvsc_device { /* Send buffer allocated by us */ void *send_buf; - void *send_original_buf; u32 send_buf_size; struct vmbus_gpadl send_buf_gpadl_handle; u32 send_section_cnt; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index da737d959e81..82e9796c8f5e 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -154,17 +154,8 @@ static void free_netvsc_device(struct rcu_head *head) int i; kfree(nvdev->extension); - - if (nvdev->recv_original_buf) - vfree(nvdev->recv_original_buf); - else - vfree(nvdev->recv_buf); - - if (nvdev->send_original_buf) - vfree(nvdev->send_original_buf); - else - vfree(nvdev->send_buf); - + vfree(nvdev->recv_buf); + vfree(nvdev->send_buf); bitmap_free(nvdev->send_section_map); for (i = 0; i < VRSS_CHANNEL_MAX; i++) { @@ -347,7 +338,6 @@ static int netvsc_init_buf(struct hv_device *device, struct nvsp_message *init_packet; unsigned int buf_size; int i, ret = 0; - void *vaddr; /* Get receive buffer area. */ buf_size = device_info->recv_sections * device_info->recv_section_size; @@ -383,17 +373,6 @@ static int netvsc_init_buf(struct hv_device *device, goto cleanup; } - if (hv_isolation_type_snp()) { - vaddr = hv_map_memory(net_device->recv_buf, buf_size); - if (!vaddr) { - ret = -ENOMEM; - goto cleanup; - } - - net_device->recv_original_buf = net_device->recv_buf; - net_device->recv_buf = vaddr; - } - /* Notify the NetVsp of the gpadl handle */ init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); @@ -497,17 +476,6 @@ static int netvsc_init_buf(struct hv_device *device, goto cleanup; } - if (hv_isolation_type_snp()) { - vaddr = hv_map_memory(net_device->send_buf, buf_size); - if (!vaddr) { - ret = -ENOMEM; - goto cleanup; - } - - net_device->send_original_buf = net_device->send_buf; - net_device->send_buf = vaddr; - } - /* Notify the NetVsp of the gpadl handle */ init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); @@ -762,12 +730,6 @@ void netvsc_device_remove(struct hv_device *device) netvsc_teardown_send_gpadl(device, net_device, ndev); } - if (net_device->recv_original_buf) - hv_unmap_memory(net_device->recv_buf); - - if (net_device->send_original_buf) - hv_unmap_memory(net_device->send_buf); - /* Release all resources */ free_netvsc_device_rcu(net_device); } @@ -1844,12 +1806,6 @@ cleanup: netif_napi_del(&net_device->chan_table[0].napi); cleanup2: - if (net_device->recv_original_buf) - hv_unmap_memory(net_device->recv_buf); - - if (net_device->send_original_buf) - hv_unmap_memory(net_device->send_buf); - free_netvsc_device(&net_device->rcu); return ERR_PTR(ret); diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index 90d7f68ed39d..afcd9ae9588c 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -271,8 +271,6 @@ u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); void hyperv_cleanup(void); bool hv_query_ext_cap(u64 cap_query); void hv_setup_dma_ops(struct device *dev, bool coherent); -void *hv_map_memory(void *addr, unsigned long size); -void hv_unmap_memory(void *addr); #else /* CONFIG_HYPERV */ static inline bool hv_is_hyperv_initialized(void) { return false; } static inline bool hv_is_hibernation_supported(void) { return false; } From 6afd9dc1a4b158456c072580f0851b4dbaaa02f1 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 26 Mar 2023 06:52:06 -0700 Subject: [PATCH 102/182] Drivers: hv: Don't remap addresses that are above shared_gpa_boundary With the vTOM bit now treated as a protection flag and not part of the physical address, avoid remapping physical addresses with vTOM set since technically such addresses aren't valid. Use ioremap_cache() instead of memremap() to ensure that the mapping provides decrypted access, which will correctly set the vTOM bit as a protection flag. While this change is not required for correctness with the current implementation of memremap(), for general code hygiene it's better to not depend on the mapping functions doing something reasonable with a physical address that is out-of-range. While here, fix typos in two error messages. Signed-off-by: Michael Kelley Reviewed-by: Tianyu Lan Link: https://lore.kernel.org/r/1679838727-87310-12-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/hv_init.c | 7 +++++-- drivers/hv/hv.c | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index edbc67ec1f3e..a5f9474f08e1 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -63,7 +63,10 @@ static int hyperv_init_ghcb(void) * memory boundary and map it here. */ rdmsrl(MSR_AMD64_SEV_ES_GHCB, ghcb_gpa); - ghcb_va = memremap(ghcb_gpa, HV_HYP_PAGE_SIZE, MEMREMAP_WB); + + /* Mask out vTOM bit. ioremap_cache() maps decrypted */ + ghcb_gpa &= ~ms_hyperv.shared_gpa_boundary; + ghcb_va = (void *)ioremap_cache(ghcb_gpa, HV_HYP_PAGE_SIZE); if (!ghcb_va) return -ENOMEM; @@ -217,7 +220,7 @@ static int hv_cpu_die(unsigned int cpu) if (hv_ghcb_pg) { ghcb_va = (void **)this_cpu_ptr(hv_ghcb_pg); if (*ghcb_va) - memunmap(*ghcb_va); + iounmap(*ghcb_va); *ghcb_va = NULL; } diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 8b0dd8e5244d..008234894d28 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -217,11 +217,13 @@ void hv_synic_enable_regs(unsigned int cpu) simp.simp_enabled = 1; if (hv_isolation_type_snp() || hv_root_partition) { + /* Mask out vTOM bit. ioremap_cache() maps decrypted */ + u64 base = (simp.base_simp_gpa << HV_HYP_PAGE_SHIFT) & + ~ms_hyperv.shared_gpa_boundary; hv_cpu->synic_message_page - = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT, - HV_HYP_PAGE_SIZE, MEMREMAP_WB); + = (void *)ioremap_cache(base, HV_HYP_PAGE_SIZE); if (!hv_cpu->synic_message_page) - pr_err("Fail to map syinc message page.\n"); + pr_err("Fail to map synic message page.\n"); } else { simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) >> HV_HYP_PAGE_SHIFT; @@ -234,12 +236,13 @@ void hv_synic_enable_regs(unsigned int cpu) siefp.siefp_enabled = 1; if (hv_isolation_type_snp() || hv_root_partition) { - hv_cpu->synic_event_page = - memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT, - HV_HYP_PAGE_SIZE, MEMREMAP_WB); - + /* Mask out vTOM bit. ioremap_cache() maps decrypted */ + u64 base = (siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT) & + ~ms_hyperv.shared_gpa_boundary; + hv_cpu->synic_event_page + = (void *)ioremap_cache(base, HV_HYP_PAGE_SIZE); if (!hv_cpu->synic_event_page) - pr_err("Fail to map syinc event page.\n"); + pr_err("Fail to map synic event page.\n"); } else { siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) >> HV_HYP_PAGE_SHIFT; @@ -316,7 +319,7 @@ void hv_synic_disable_regs(unsigned int cpu) */ simp.simp_enabled = 0; if (hv_isolation_type_snp() || hv_root_partition) { - memunmap(hv_cpu->synic_message_page); + iounmap(hv_cpu->synic_message_page); hv_cpu->synic_message_page = NULL; } else { simp.base_simp_gpa = 0; @@ -328,7 +331,7 @@ void hv_synic_disable_regs(unsigned int cpu) siefp.siefp_enabled = 0; if (hv_isolation_type_snp() || hv_root_partition) { - memunmap(hv_cpu->synic_event_page); + iounmap(hv_cpu->synic_event_page); hv_cpu->synic_event_page = NULL; } else { siefp.base_siefp_gpa = 0; From 2c6ba4216844ca7918289b49ed5f3f7138ee2402 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 26 Mar 2023 06:52:07 -0700 Subject: [PATCH 103/182] PCI: hv: Enable PCI pass-thru devices in Confidential VMs For PCI pass-thru devices in a Confidential VM, Hyper-V requires that PCI config space be accessed via hypercalls. In normal VMs, config space accesses are trapped to the Hyper-V host and emulated. But in a confidential VM, the host can't access guest memory to decode the instruction for emulation, so an explicit hypercall must be used. Add functions to make the new MMIO read and MMIO write hypercalls. Update the PCI config space access functions to use the hypercalls when such use is indicated by Hyper-V flags. Also, set the flag to allow the Hyper-V PCI driver to be loaded and used in a Confidential VM (a.k.a., "Isolation VM"). The driver has previously been hardened against a malicious Hyper-V host[1]. [1] https://lore.kernel.org/all/20220511223207.3386-2-parri.andrea@gmail.com/ Co-developed-by: Dexuan Cui Signed-off-by: Dexuan Cui Signed-off-by: Michael Kelley Reviewed-by: Boqun Feng Reviewed-by: Haiyang Zhang Link: https://lore.kernel.org/r/1679838727-87310-13-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/include/asm/hyperv-tlfs.h | 3 + drivers/hv/channel_mgmt.c | 2 +- drivers/pci/controller/pci-hyperv.c | 232 ++++++++++++++++++++-------- include/asm-generic/hyperv-tlfs.h | 22 +++ 4 files changed, 194 insertions(+), 65 deletions(-) diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index 0b73a809e9e1..b4fb75bd1013 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -122,6 +122,9 @@ /* Recommend using enlightened VMCS */ #define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED BIT(14) +/* Use hypercalls for MMIO config space access */ +#define HV_X64_USE_MMIO_HYPERCALLS BIT(21) + /* * CPU management features identification. * These are HYPERV_CPUID_CPU_MANAGEMENT_FEATURES.EAX bits. diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index cc23b90cae02..007f26d5f1a4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -67,7 +67,7 @@ const struct vmbus_device vmbus_devs[] = { { .dev_type = HV_PCIE, HV_PCIE_GUID, .perf_device = false, - .allowed_in_isolated = false, + .allowed_in_isolated = true, }, /* Synthetic Frame Buffer */ diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index f33370b75628..337f3b4a04fc 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -514,6 +514,7 @@ struct hv_pcibus_device { /* Highest slot of child device with resources allocated */ int wslot_res_allocated; + bool use_calls; /* Use hypercalls to access mmio cfg space */ /* hypercall arg, must not cross page boundary */ struct hv_retarget_device_interrupt retarget_msi_interrupt_params; @@ -1041,6 +1042,70 @@ static int wslot_to_devfn(u32 wslot) return PCI_DEVFN(slot_no.bits.dev, slot_no.bits.func); } +static void hv_pci_read_mmio(struct device *dev, phys_addr_t gpa, int size, u32 *val) +{ + struct hv_mmio_read_input *in; + struct hv_mmio_read_output *out; + u64 ret; + + /* + * Must be called with interrupts disabled so it is safe + * to use the per-cpu input argument page. Use it for + * both input and output. + */ + in = *this_cpu_ptr(hyperv_pcpu_input_arg); + out = *this_cpu_ptr(hyperv_pcpu_input_arg) + sizeof(*in); + in->gpa = gpa; + in->size = size; + + ret = hv_do_hypercall(HVCALL_MMIO_READ, in, out); + if (hv_result_success(ret)) { + switch (size) { + case 1: + *val = *(u8 *)(out->data); + break; + case 2: + *val = *(u16 *)(out->data); + break; + default: + *val = *(u32 *)(out->data); + break; + } + } else + dev_err(dev, "MMIO read hypercall error %llx addr %llx size %d\n", + ret, gpa, size); +} + +static void hv_pci_write_mmio(struct device *dev, phys_addr_t gpa, int size, u32 val) +{ + struct hv_mmio_write_input *in; + u64 ret; + + /* + * Must be called with interrupts disabled so it is safe + * to use the per-cpu input argument memory. + */ + in = *this_cpu_ptr(hyperv_pcpu_input_arg); + in->gpa = gpa; + in->size = size; + switch (size) { + case 1: + *(u8 *)(in->data) = val; + break; + case 2: + *(u16 *)(in->data) = val; + break; + default: + *(u32 *)(in->data) = val; + break; + } + + ret = hv_do_hypercall(HVCALL_MMIO_WRITE, in, NULL); + if (!hv_result_success(ret)) + dev_err(dev, "MMIO write hypercall error %llx addr %llx size %d\n", + ret, gpa, size); +} + /* * PCI Configuration Space for these root PCI buses is implemented as a pair * of pages in memory-mapped I/O space. Writing to the first page chooses @@ -1059,8 +1124,10 @@ static int wslot_to_devfn(u32 wslot) static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, int size, u32 *val) { + struct hv_pcibus_device *hbus = hpdev->hbus; + struct device *dev = &hbus->hdev->device; + int offset = where + CFG_PAGE_OFFSET; unsigned long flags; - void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where; /* * If the attempt is to read the IDs or the ROM BAR, simulate that. @@ -1088,56 +1155,79 @@ static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, */ *val = 0; } else if (where + size <= CFG_PAGE_SIZE) { - spin_lock_irqsave(&hpdev->hbus->config_lock, flags); - /* Choose the function to be read. (See comment above) */ - writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); - /* Make sure the function was chosen before we start reading. */ - mb(); - /* Read from that function's config space. */ - switch (size) { - case 1: - *val = readb(addr); - break; - case 2: - *val = readw(addr); - break; - default: - *val = readl(addr); - break; + + spin_lock_irqsave(&hbus->config_lock, flags); + if (hbus->use_calls) { + phys_addr_t addr = hbus->mem_config->start + offset; + + hv_pci_write_mmio(dev, hbus->mem_config->start, 4, + hpdev->desc.win_slot.slot); + hv_pci_read_mmio(dev, addr, size, val); + } else { + void __iomem *addr = hbus->cfg_addr + offset; + + /* Choose the function to be read. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hbus->cfg_addr); + /* Make sure the function was chosen before reading. */ + mb(); + /* Read from that function's config space. */ + switch (size) { + case 1: + *val = readb(addr); + break; + case 2: + *val = readw(addr); + break; + default: + *val = readl(addr); + break; + } + /* + * Make sure the read was done before we release the + * spinlock allowing consecutive reads/writes. + */ + mb(); } - /* - * Make sure the read was done before we release the spinlock - * allowing consecutive reads/writes. - */ - mb(); - spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + spin_unlock_irqrestore(&hbus->config_lock, flags); } else { - dev_err(&hpdev->hbus->hdev->device, - "Attempt to read beyond a function's config space.\n"); + dev_err(dev, "Attempt to read beyond a function's config space.\n"); } } static u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev) { + struct hv_pcibus_device *hbus = hpdev->hbus; + struct device *dev = &hbus->hdev->device; + u32 val; u16 ret; unsigned long flags; - void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + - PCI_VENDOR_ID; - spin_lock_irqsave(&hpdev->hbus->config_lock, flags); + spin_lock_irqsave(&hbus->config_lock, flags); - /* Choose the function to be read. (See comment above) */ - writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); - /* Make sure the function was chosen before we start reading. */ - mb(); - /* Read from that function's config space. */ - ret = readw(addr); - /* - * mb() is not required here, because the spin_unlock_irqrestore() - * is a barrier. - */ + if (hbus->use_calls) { + phys_addr_t addr = hbus->mem_config->start + + CFG_PAGE_OFFSET + PCI_VENDOR_ID; - spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + hv_pci_write_mmio(dev, hbus->mem_config->start, 4, + hpdev->desc.win_slot.slot); + hv_pci_read_mmio(dev, addr, 2, &val); + ret = val; /* Truncates to 16 bits */ + } else { + void __iomem *addr = hbus->cfg_addr + CFG_PAGE_OFFSET + + PCI_VENDOR_ID; + /* Choose the function to be read. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hbus->cfg_addr); + /* Make sure the function was chosen before we start reading. */ + mb(); + /* Read from that function's config space. */ + ret = readw(addr); + /* + * mb() is not required here, because the + * spin_unlock_irqrestore() is a barrier. + */ + } + + spin_unlock_irqrestore(&hbus->config_lock, flags); return ret; } @@ -1152,39 +1242,51 @@ static u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev) static void _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where, int size, u32 val) { + struct hv_pcibus_device *hbus = hpdev->hbus; + struct device *dev = &hbus->hdev->device; + int offset = where + CFG_PAGE_OFFSET; unsigned long flags; - void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where; if (where >= PCI_SUBSYSTEM_VENDOR_ID && where + size <= PCI_CAPABILITY_LIST) { /* SSIDs and ROM BARs are read-only */ } else if (where >= PCI_COMMAND && where + size <= CFG_PAGE_SIZE) { - spin_lock_irqsave(&hpdev->hbus->config_lock, flags); - /* Choose the function to be written. (See comment above) */ - writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); - /* Make sure the function was chosen before we start writing. */ - wmb(); - /* Write to that function's config space. */ - switch (size) { - case 1: - writeb(val, addr); - break; - case 2: - writew(val, addr); - break; - default: - writel(val, addr); - break; + spin_lock_irqsave(&hbus->config_lock, flags); + + if (hbus->use_calls) { + phys_addr_t addr = hbus->mem_config->start + offset; + + hv_pci_write_mmio(dev, hbus->mem_config->start, 4, + hpdev->desc.win_slot.slot); + hv_pci_write_mmio(dev, addr, size, val); + } else { + void __iomem *addr = hbus->cfg_addr + offset; + + /* Choose the function to write. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hbus->cfg_addr); + /* Make sure the function was chosen before writing. */ + wmb(); + /* Write to that function's config space. */ + switch (size) { + case 1: + writeb(val, addr); + break; + case 2: + writew(val, addr); + break; + default: + writel(val, addr); + break; + } + /* + * Make sure the write was done before we release the + * spinlock allowing consecutive reads/writes. + */ + mb(); } - /* - * Make sure the write was done before we release the spinlock - * allowing consecutive reads/writes. - */ - mb(); - spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + spin_unlock_irqrestore(&hbus->config_lock, flags); } else { - dev_err(&hpdev->hbus->hdev->device, - "Attempt to write beyond a function's config space.\n"); + dev_err(dev, "Attempt to write beyond a function's config space.\n"); } } @@ -3563,6 +3665,7 @@ static int hv_pci_probe(struct hv_device *hdev, hbus->bridge->domain_nr = dom; #ifdef CONFIG_X86 hbus->sysdata.domain = dom; + hbus->use_calls = !!(ms_hyperv.hints & HV_X64_USE_MMIO_HYPERCALLS); #elif defined(CONFIG_ARM64) /* * Set the PCI bus parent to be the corresponding VMbus @@ -3572,6 +3675,7 @@ static int hv_pci_probe(struct hv_device *hdev, * information to devices created on the bus. */ hbus->sysdata.parent = hdev->device.parent; + hbus->use_calls = false; #endif hbus->hdev = hdev; diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h index b870983596b9..ea406e901469 100644 --- a/include/asm-generic/hyperv-tlfs.h +++ b/include/asm-generic/hyperv-tlfs.h @@ -168,6 +168,8 @@ union hv_reference_tsc_msr { #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 #define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db +#define HVCALL_MMIO_READ 0x0106 +#define HVCALL_MMIO_WRITE 0x0107 /* Extended hypercalls */ #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001 @@ -796,4 +798,24 @@ struct hv_memory_hint { union hv_gpa_page_range ranges[]; } __packed; +/* Data structures for HVCALL_MMIO_READ and HVCALL_MMIO_WRITE */ +#define HV_HYPERCALL_MMIO_MAX_DATA_LENGTH 64 + +struct hv_mmio_read_input { + u64 gpa; + u32 size; + u32 reserved; +} __packed; + +struct hv_mmio_read_output { + u8 data[HV_HYPERCALL_MMIO_MAX_DATA_LENGTH]; +} __packed; + +struct hv_mmio_write_input { + u64 gpa; + u32 size; + u32 reserved; + u8 data[HV_HYPERCALL_MMIO_MAX_DATA_LENGTH]; +} __packed; + #endif From c0e96acf884a1ce91c9bdd692c6a425b83c90285 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sat, 8 Apr 2023 14:03:39 -0700 Subject: [PATCH 104/182] clocksource: hyper-v: make sure Invariant-TSC is used if it is available If Hyper-V TSC page is unavailable and Invariant-TSC is available, currently hyperv_cs_msr (rather than Invariant-TSC) is used by default. Use Invariant-TSC by default by downgrading hyperv_cs_msr.rating in hv_init_tsc_clocksource(), if Invariant-TSC is available. Signed-off-by: Dexuan Cui Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20230408210339.15085-1-decui@microsoft.com Signed-off-by: Wei Liu --- drivers/clocksource/hyperv_timer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index f32948c8a96f..bcd9042a0c9f 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -517,9 +517,6 @@ static bool __init hv_init_tsc_clocksource(void) { union hv_reference_tsc_msr tsc_msr; - if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) - return false; - /* * If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly * handles frequency and offset changes due to live migration, @@ -536,6 +533,9 @@ static bool __init hv_init_tsc_clocksource(void) hyperv_cs_msr.rating = 250; } + if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) + return false; + hv_read_reference_counter = read_hv_clock_tsc; /* From 9a6b1a170ca8627d401fa76112e4920ba8c6314c Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sat, 8 Apr 2023 14:34:41 -0700 Subject: [PATCH 105/182] Drivers: hv: vmbus: Remove the per-CPU post_msg_page The post_msg_page was introduced in 2014 in commit b29ef3546aec ("Drivers: hv: vmbus: Cleanup hv_post_message()") Commit 68bb7bfb7985 ("X86/Hyper-V: Enable IPI enlightenments") introduced the hyperv_pcpu_input_arg in 2018, which can be used in hv_post_message(). Remove post_msg_page to simplify the code a little bit. Signed-off-by: Dexuan Cui Reviewed-by: Jinank Jain Link: https://lore.kernel.org/r/20230408213441.15472-1-decui@microsoft.com Signed-off-by: Wei Liu --- drivers/hv/hv.c | 20 +++++--------------- drivers/hv/hyperv_vmbus.h | 4 ---- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 008234894d28..4e1407d59ba0 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -84,14 +84,15 @@ int hv_post_message(union hv_connection_id connection_id, void *payload, size_t payload_size) { struct hv_input_post_message *aligned_msg; - struct hv_per_cpu_context *hv_cpu; + unsigned long flags; u64 status; if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) return -EMSGSIZE; - hv_cpu = get_cpu_ptr(hv_context.cpu_context); - aligned_msg = hv_cpu->post_msg_page; + local_irq_save(flags); + + aligned_msg = *this_cpu_ptr(hyperv_pcpu_input_arg); aligned_msg->connectionid = connection_id; aligned_msg->reserved = 0; aligned_msg->message_type = message_type; @@ -106,11 +107,7 @@ int hv_post_message(union hv_connection_id connection_id, status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); - /* Preemption must remain disabled until after the hypercall - * so some other thread can't get scheduled onto this cpu and - * corrupt the per-cpu post_msg_page - */ - put_cpu_ptr(hv_cpu); + local_irq_restore(flags); return hv_result(status); } @@ -162,12 +159,6 @@ int hv_synic_alloc(void) goto err; } } - - hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); - if (hv_cpu->post_msg_page == NULL) { - pr_err("Unable to allocate post msg page\n"); - goto err; - } } return 0; @@ -190,7 +181,6 @@ void hv_synic_free(void) free_page((unsigned long)hv_cpu->synic_event_page); free_page((unsigned long)hv_cpu->synic_message_page); - free_page((unsigned long)hv_cpu->post_msg_page); } kfree(hv_context.hv_numa_map); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 167ac5115a78..55f2086841ae 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -122,10 +122,6 @@ enum { struct hv_per_cpu_context { void *synic_message_page; void *synic_event_page; - /* - * buffer to post messages to the host. - */ - void *post_msg_page; /* * Starting with win8, we can take channel interrupts on any CPU; From d7b6ba9611aefc4bef207b16db8ff06b726efe35 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Mon, 27 Mar 2023 06:16:06 -0700 Subject: [PATCH 106/182] x86/hyperv: Add callback filter to cpumask_to_vpset() When copying CPUs from a Linux cpumask to a Hyper-V VPset, cpumask_to_vpset() currently has a "_noself" variant that doesn't copy the current CPU to the VPset. Generalize this variant by replacing it with a "_skip" variant having a callback function that is invoked for each CPU to decide if that CPU should be copied. Update the one caller of cpumask_to_vpset_noself() to use the new "_skip" variant instead. No functional change. Signed-off-by: Michael Kelley Link: https://lore.kernel.org/r/1679922967-26582-2-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/hv_apic.c | 12 ++++++++---- include/asm-generic/mshyperv.h | 22 ++++++++++++++-------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index fb8b2c088681..1fbda2f94184 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -96,6 +96,11 @@ static void hv_apic_eoi_write(u32 reg, u32 val) wrmsr(HV_X64_MSR_EOI, val, 0); } +static bool cpu_is_self(int cpu) +{ + return cpu == smp_processor_id(); +} + /* * IPI implementation on Hyper-V. */ @@ -128,10 +133,9 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, */ if (!cpumask_equal(mask, cpu_present_mask) || exclude_self) { ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K; - if (exclude_self) - nr_bank = cpumask_to_vpset_noself(&(ipi_arg->vp_set), mask); - else - nr_bank = cpumask_to_vpset(&(ipi_arg->vp_set), mask); + + nr_bank = cpumask_to_vpset_skip(&(ipi_arg->vp_set), mask, + exclude_self ? cpu_is_self : NULL); /* * 'nr_bank <= 0' means some CPUs in cpumask can't be diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index afcd9ae9588c..402a8c1c202d 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -210,10 +210,9 @@ static inline int hv_cpu_number_to_vp_number(int cpu_number) static inline int __cpumask_to_vpset(struct hv_vpset *vpset, const struct cpumask *cpus, - bool exclude_self) + bool (*func)(int cpu)) { int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; - int this_cpu = smp_processor_id(); int max_vcpu_bank = hv_max_vp_index / HV_VCPUS_PER_SPARSE_BANK; /* vpset.valid_bank_mask can represent up to HV_MAX_SPARSE_VCPU_BANKS banks */ @@ -232,7 +231,7 @@ static inline int __cpumask_to_vpset(struct hv_vpset *vpset, * Some banks may end up being empty but this is acceptable. */ for_each_cpu(cpu, cpus) { - if (exclude_self && cpu == this_cpu) + if (func && func(cpu)) continue; vcpu = hv_cpu_number_to_vp_number(cpu); if (vcpu == VP_INVAL) @@ -248,17 +247,24 @@ static inline int __cpumask_to_vpset(struct hv_vpset *vpset, return nr_bank; } +/* + * Convert a Linux cpumask into a Hyper-V VPset. In the _skip variant, + * 'func' is called for each CPU present in cpumask. If 'func' returns + * true, that CPU is skipped -- i.e., that CPU from cpumask is *not* + * added to the Hyper-V VPset. If 'func' is NULL, no CPUs are + * skipped. + */ static inline int cpumask_to_vpset(struct hv_vpset *vpset, const struct cpumask *cpus) { - return __cpumask_to_vpset(vpset, cpus, false); + return __cpumask_to_vpset(vpset, cpus, NULL); } -static inline int cpumask_to_vpset_noself(struct hv_vpset *vpset, - const struct cpumask *cpus) +static inline int cpumask_to_vpset_skip(struct hv_vpset *vpset, + const struct cpumask *cpus, + bool (*func)(int cpu)) { - WARN_ON_ONCE(preemptible()); - return __cpumask_to_vpset(vpset, cpus, true); + return __cpumask_to_vpset(vpset, cpus, func); } void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); From 493cc07385cf1c6678a6159d410854b8e99aa945 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Mon, 27 Mar 2023 06:16:07 -0700 Subject: [PATCH 107/182] x86/hyperv: Exclude lazy TLB mode CPUs from enlightened TLB flushes In the case where page tables are not freed, native_flush_tlb_multi() does not do a remote TLB flush on CPUs in lazy TLB mode because the CPU will flush itself at the next context switch. By comparison, the Hyper-V enlightened TLB flush does not exclude CPUs in lazy TLB mode and so performs unnecessary flushes. If we're not freeing page tables, add logic to test for lazy TLB mode when adding CPUs to the input argument to the Hyper-V TLB flush hypercall. Exclude lazy TLB mode CPUs so the behavior matches native_flush_tlb_multi() and the unnecessary flushes are avoided. Handle both the <=64 vCPU case and the _ex case for >64 vCPUs. Signed-off-by: Michael Kelley Link: https://lore.kernel.org/r/1679922967-26582-3-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/mmu.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c index 0ad2378fe6ad..8460bd35e10c 100644 --- a/arch/x86/hyperv/mmu.c +++ b/arch/x86/hyperv/mmu.c @@ -52,6 +52,11 @@ static inline int fill_gva_list(u64 gva_list[], int offset, return gva_n - offset; } +static bool cpu_is_lazy(int cpu) +{ + return per_cpu(cpu_tlbstate_shared.is_lazy, cpu); +} + static void hyperv_flush_tlb_multi(const struct cpumask *cpus, const struct flush_tlb_info *info) { @@ -60,6 +65,7 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, struct hv_tlb_flush *flush; u64 status; unsigned long flags; + bool do_lazy = !info->freed_tables; trace_hyperv_mmu_flush_tlb_multi(cpus, info); @@ -112,6 +118,8 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, goto do_ex_hypercall; for_each_cpu(cpu, cpus) { + if (do_lazy && cpu_is_lazy(cpu)) + continue; vcpu = hv_cpu_number_to_vp_number(cpu); if (vcpu == VP_INVAL) { local_irq_restore(flags); @@ -198,7 +206,8 @@ static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus, flush->hv_vp_set.valid_bank_mask = 0; flush->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K; - nr_bank = cpumask_to_vpset(&(flush->hv_vp_set), cpus); + nr_bank = cpumask_to_vpset_skip(&flush->hv_vp_set, cpus, + info->freed_tables ? NULL : cpu_is_lazy); if (nr_bank < 0) return HV_STATUS_INVALID_PARAMETER; From d21a19e1c2f55504c4b3e9f9c82b4554bfa90d7b Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 10 Apr 2023 22:55:28 -0700 Subject: [PATCH 108/182] x86/init: Make get/set_rtc_noop() public Make get/set_rtc_noop() to be public so that they can be used in other modules as well. Co-developed-by: Tianyu Lan Signed-off-by: Tianyu Lan Signed-off-by: Saurabh Sengar Reviewed-by: Wei Liu Reviewed-by: Michael Kelley Acked-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/1681192532-15460-2-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/include/asm/x86_init.h | 2 ++ arch/x86/kernel/x86_init.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index acc20ae4079d..88085f369ff6 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -330,5 +330,7 @@ extern void x86_init_uint_noop(unsigned int unused); extern bool bool_x86_init_noop(void); extern void x86_op_int_noop(int cpu); extern bool x86_pnpbios_disabled(void); +extern int set_rtc_noop(const struct timespec64 *now); +extern void get_rtc_noop(struct timespec64 *now); #endif diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index ecdeb0974a87..d82f4fa2f1bf 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -33,8 +33,8 @@ static int __init iommu_init_noop(void) { return 0; } static void iommu_shutdown_noop(void) { } bool __init bool_x86_init_noop(void) { return false; } void x86_op_int_noop(int cpu) { } -static int set_rtc_noop(const struct timespec64 *now) { return -EINVAL; } -static void get_rtc_noop(struct timespec64 *now) { } +int set_rtc_noop(const struct timespec64 *now) { return -EINVAL; } +void get_rtc_noop(struct timespec64 *now) { } static __initconst const struct of_device_id of_cmos_match[] = { { .compatible = "motorola,mc146818" }, From c26e0527aaf84a34b4774d80c9a9baa65f4d77f2 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 10 Apr 2023 22:55:29 -0700 Subject: [PATCH 109/182] x86/hyperv: Add VTL specific structs and hypercalls Add structs and hypercalls required to enable VTL support on x86. Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Reviewed-by: Stanislav Kinsburskii Link: https://lore.kernel.org/r/1681192532-15460-3-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/include/asm/hyperv-tlfs.h | 75 ++++++++++++++++++++++++++++++ include/asm-generic/hyperv-tlfs.h | 4 ++ 2 files changed, 79 insertions(+) diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index b4fb75bd1013..cea95dcd27c2 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -716,6 +716,81 @@ union hv_msi_entry { } __packed; }; +struct hv_x64_segment_register { + u64 base; + u32 limit; + u16 selector; + union { + struct { + u16 segment_type : 4; + u16 non_system_segment : 1; + u16 descriptor_privilege_level : 2; + u16 present : 1; + u16 reserved : 4; + u16 available : 1; + u16 _long : 1; + u16 _default : 1; + u16 granularity : 1; + } __packed; + u16 attributes; + }; +} __packed; + +struct hv_x64_table_register { + u16 pad[3]; + u16 limit; + u64 base; +} __packed; + +struct hv_init_vp_context { + u64 rip; + u64 rsp; + u64 rflags; + + struct hv_x64_segment_register cs; + struct hv_x64_segment_register ds; + struct hv_x64_segment_register es; + struct hv_x64_segment_register fs; + struct hv_x64_segment_register gs; + struct hv_x64_segment_register ss; + struct hv_x64_segment_register tr; + struct hv_x64_segment_register ldtr; + + struct hv_x64_table_register idtr; + struct hv_x64_table_register gdtr; + + u64 efer; + u64 cr0; + u64 cr3; + u64 cr4; + u64 msr_cr_pat; +} __packed; + +union hv_input_vtl { + u8 as_uint8; + struct { + u8 target_vtl: 4; + u8 use_target_vtl: 1; + u8 reserved_z: 3; + }; +} __packed; + +struct hv_enable_vp_vtl { + u64 partition_id; + u32 vp_index; + union hv_input_vtl target_vtl; + u8 mbz0; + u16 mbz1; + struct hv_init_vp_context vp_context; +} __packed; + +struct hv_get_vp_from_apic_id_in { + u64 partition_id; + union hv_input_vtl target_vtl; + u8 res[7]; + u32 apic_ids[]; +} __packed; + #include #endif diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h index ea406e901469..f4e4cc4f965f 100644 --- a/include/asm-generic/hyperv-tlfs.h +++ b/include/asm-generic/hyperv-tlfs.h @@ -146,6 +146,7 @@ union hv_reference_tsc_msr { /* Declare the various hypercall operations. */ #define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002 #define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003 +#define HVCALL_ENABLE_VP_VTL 0x000f #define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 #define HVCALL_SEND_IPI 0x000b #define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013 @@ -165,6 +166,8 @@ union hv_reference_tsc_msr { #define HVCALL_MAP_DEVICE_INTERRUPT 0x007c #define HVCALL_UNMAP_DEVICE_INTERRUPT 0x007d #define HVCALL_RETARGET_INTERRUPT 0x007e +#define HVCALL_START_VP 0x0099 +#define HVCALL_GET_VP_ID_FROM_APIC_ID 0x009a #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 #define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db @@ -220,6 +223,7 @@ enum HV_GENERIC_SET_FORMAT { #define HV_STATUS_INVALID_PORT_ID 17 #define HV_STATUS_INVALID_CONNECTION_ID 18 #define HV_STATUS_INSUFFICIENT_BUFFERS 19 +#define HV_STATUS_VTL_ALREADY_ENABLED 134 /* * The Hyper-V TimeRefCount register and the TSC From 0a7a00580a4fad9a6cd28c2d825e0e5ae917e59e Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 10 Apr 2023 22:55:30 -0700 Subject: [PATCH 110/182] x86/hyperv: Make hv_get_nmi_reason public Move hv_get_nmi_reason to .h file so it can be used in other modules as well. Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/1681192532-15460-4-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/include/asm/mshyperv.h | 5 +++++ arch/x86/kernel/cpu/mshyperv.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index e3cef98a0142..67f8386c1775 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -29,6 +29,11 @@ typedef int (*hyperv_fill_flush_list_func)( void hyperv_vector_handler(struct pt_regs *regs); +static inline unsigned char hv_get_nmi_reason(void) +{ + return 0; +} + #if IS_ENABLED(CONFIG_HYPERV) extern int hyperv_init_cpuhp; diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index ac630ecde795..c8a0e70cc484 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -248,11 +248,6 @@ static uint32_t __init ms_hyperv_platform(void) return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS; } -static unsigned char hv_get_nmi_reason(void) -{ - return 0; -} - #ifdef CONFIG_X86_LOCAL_APIC /* * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes From d01b9a9f2d0131e1e249177a70e6b80d146d16d2 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 10 Apr 2023 22:55:31 -0700 Subject: [PATCH 111/182] Drivers: hv: Kconfig: Add HYPERV_VTL_MODE Add HYPERV_VTL_MODE Kconfig flag for VTL mode. Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/1681192532-15460-5-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- drivers/hv/Kconfig | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 94982f08b661..00242107d62e 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -13,6 +13,30 @@ config HYPERV Select this option to run Linux as a Hyper-V client operating system. +config HYPERV_VTL_MODE + bool "Enable Linux to boot in VTL context" + depends on X86_64 && HYPERV + default n + help + Virtual Secure Mode (VSM) is a set of hypervisor capabilities and + enlightenments offered to host and guest partitions which enables + the creation and management of new security boundaries within + operating system software. + + VSM achieves and maintains isolation through Virtual Trust Levels + (VTLs). Virtual Trust Levels are hierarchical, with higher levels + being more privileged than lower levels. VTL0 is the least privileged + level, and currently only other level supported is VTL2. + + Select this option to build a Linux kernel to run at a VTL other than + the normal VTL0, which currently is only VTL2. This option + initializes the x86 platform for VTL2, and adds the ability to boot + secondary CPUs directly into 64-bit context as required for VTLs other + than 0. A kernel built with this option must run at VTL2, and will + not run as a normal guest. + + If unsure, say N + config HYPERV_TIMER def_bool HYPERV && X86 From 3be1bc2fe9d2e4fc1375efa2567d2f58cd2a2a7c Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 10 Apr 2023 22:55:32 -0700 Subject: [PATCH 112/182] x86/hyperv: VTL support for Hyper-V Virtual Trust Levels (VTL) helps enable Hyper-V Virtual Secure Mode (VSM) feature. VSM is a set of hypervisor capabilities and enlightenments offered to host and guest partitions which enable the creation and management of new security boundaries within operating system software. VSM achieves and maintains isolation through VTLs. Add early initialization for Virtual Trust Levels (VTL). This includes initializing the x86 platform for VTL and enabling boot support for secondary CPUs to start in targeted VTL context. For now, only enable the code for targeted VTL level as 2. When starting an AP at a VTL other than VTL0, the AP must start directly in 64-bit mode, bypassing the usual 16-bit -> 32-bit -> 64-bit mode transition sequence that occurs after waking up an AP with SIPI whose vector points to the 16-bit AP startup trampoline code. Signed-off-by: Saurabh Sengar Reviewed-by: Michael Kelley Reviewed-by: Stanislav Kinsburskii Link: https://lore.kernel.org/r/1681192532-15460-6-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/hyperv/Makefile | 1 + arch/x86/hyperv/hv_vtl.c | 227 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/mshyperv.h | 10 ++ arch/x86/kernel/cpu/mshyperv.c | 1 + 4 files changed, 239 insertions(+) create mode 100644 arch/x86/hyperv/hv_vtl.c diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile index 5d2de10809ae..3a1548054b48 100644 --- a/arch/x86/hyperv/Makefile +++ b/arch/x86/hyperv/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o +obj-$(CONFIG_HYPERV_VTL_MODE) += hv_vtl.o ifdef CONFIG_X86_64 obj-$(CONFIG_PARAVIRT_SPINLOCKS) += hv_spinlock.o diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c new file mode 100644 index 000000000000..1ba5d3b99b16 --- /dev/null +++ b/arch/x86/hyperv/hv_vtl.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Microsoft Corporation. + * + * Author: + * Saurabh Sengar + */ + +#include +#include +#include +#include +#include +#include + +extern struct boot_params boot_params; +static struct real_mode_header hv_vtl_real_mode_header; + +void __init hv_vtl_init_platform(void) +{ + pr_info("Linux runs in Hyper-V Virtual Trust Level\n"); + + x86_init.irqs.pre_vector_init = x86_init_noop; + x86_init.timers.timer_init = x86_init_noop; + + x86_platform.get_wallclock = get_rtc_noop; + x86_platform.set_wallclock = set_rtc_noop; + x86_platform.get_nmi_reason = hv_get_nmi_reason; + + x86_platform.legacy.i8042 = X86_LEGACY_I8042_PLATFORM_ABSENT; + x86_platform.legacy.rtc = 0; + x86_platform.legacy.warm_reset = 0; + x86_platform.legacy.reserve_bios_regions = 0; + x86_platform.legacy.devices.pnpbios = 0; +} + +static inline u64 hv_vtl_system_desc_base(struct ldttss_desc *desc) +{ + return ((u64)desc->base3 << 32) | ((u64)desc->base2 << 24) | + (desc->base1 << 16) | desc->base0; +} + +static inline u32 hv_vtl_system_desc_limit(struct ldttss_desc *desc) +{ + return ((u32)desc->limit1 << 16) | (u32)desc->limit0; +} + +typedef void (*secondary_startup_64_fn)(void*, void*); +static void hv_vtl_ap_entry(void) +{ + ((secondary_startup_64_fn)secondary_startup_64)(&boot_params, &boot_params); +} + +static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored) +{ + u64 status; + int ret = 0; + struct hv_enable_vp_vtl *input; + unsigned long irq_flags; + + struct desc_ptr gdt_ptr; + struct desc_ptr idt_ptr; + + struct ldttss_desc *tss; + struct ldttss_desc *ldt; + struct desc_struct *gdt; + + u64 rsp = current->thread.sp; + u64 rip = (u64)&hv_vtl_ap_entry; + + native_store_gdt(&gdt_ptr); + store_idt(&idt_ptr); + + gdt = (struct desc_struct *)((void *)(gdt_ptr.address)); + tss = (struct ldttss_desc *)(gdt + GDT_ENTRY_TSS); + ldt = (struct ldttss_desc *)(gdt + GDT_ENTRY_LDT); + + local_irq_save(irq_flags); + + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(input, 0, sizeof(*input)); + + input->partition_id = HV_PARTITION_ID_SELF; + input->vp_index = target_vp_index; + input->target_vtl.target_vtl = HV_VTL_MGMT; + + /* + * The x86_64 Linux kernel follows the 16-bit -> 32-bit -> 64-bit + * mode transition sequence after waking up an AP with SIPI whose + * vector points to the 16-bit AP startup trampoline code. Here in + * VTL2, we can't perform that sequence as the AP has to start in + * the 64-bit mode. + * + * To make this happen, we tell the hypervisor to load a valid 64-bit + * context (most of which is just magic numbers from the CPU manual) + * so that AP jumps right to the 64-bit entry of the kernel, and the + * control registers are loaded with values that let the AP fetch the + * code and data and carry on with work it gets assigned. + */ + + input->vp_context.rip = rip; + input->vp_context.rsp = rsp; + input->vp_context.rflags = 0x0000000000000002; + input->vp_context.efer = __rdmsr(MSR_EFER); + input->vp_context.cr0 = native_read_cr0(); + input->vp_context.cr3 = __native_read_cr3(); + input->vp_context.cr4 = native_read_cr4(); + input->vp_context.msr_cr_pat = __rdmsr(MSR_IA32_CR_PAT); + input->vp_context.idtr.limit = idt_ptr.size; + input->vp_context.idtr.base = idt_ptr.address; + input->vp_context.gdtr.limit = gdt_ptr.size; + input->vp_context.gdtr.base = gdt_ptr.address; + + /* Non-system desc (64bit), long, code, present */ + input->vp_context.cs.selector = __KERNEL_CS; + input->vp_context.cs.base = 0; + input->vp_context.cs.limit = 0xffffffff; + input->vp_context.cs.attributes = 0xa09b; + /* Non-system desc (64bit), data, present, granularity, default */ + input->vp_context.ss.selector = __KERNEL_DS; + input->vp_context.ss.base = 0; + input->vp_context.ss.limit = 0xffffffff; + input->vp_context.ss.attributes = 0xc093; + + /* System desc (128bit), present, LDT */ + input->vp_context.ldtr.selector = GDT_ENTRY_LDT * 8; + input->vp_context.ldtr.base = hv_vtl_system_desc_base(ldt); + input->vp_context.ldtr.limit = hv_vtl_system_desc_limit(ldt); + input->vp_context.ldtr.attributes = 0x82; + + /* System desc (128bit), present, TSS, 0x8b - busy, 0x89 -- default */ + input->vp_context.tr.selector = GDT_ENTRY_TSS * 8; + input->vp_context.tr.base = hv_vtl_system_desc_base(tss); + input->vp_context.tr.limit = hv_vtl_system_desc_limit(tss); + input->vp_context.tr.attributes = 0x8b; + + status = hv_do_hypercall(HVCALL_ENABLE_VP_VTL, input, NULL); + + if (!hv_result_success(status) && + hv_result(status) != HV_STATUS_VTL_ALREADY_ENABLED) { + pr_err("HVCALL_ENABLE_VP_VTL failed for VP : %d ! [Err: %#llx\n]", + target_vp_index, status); + ret = -EINVAL; + goto free_lock; + } + + status = hv_do_hypercall(HVCALL_START_VP, input, NULL); + + if (!hv_result_success(status)) { + pr_err("HVCALL_START_VP failed for VP : %d ! [Err: %#llx]\n", + target_vp_index, status); + ret = -EINVAL; + } + +free_lock: + local_irq_restore(irq_flags); + + return ret; +} + +static int hv_vtl_apicid_to_vp_id(u32 apic_id) +{ + u64 control; + u64 status; + unsigned long irq_flags; + struct hv_get_vp_from_apic_id_in *input; + u32 *output, ret; + + local_irq_save(irq_flags); + + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(input, 0, sizeof(*input)); + input->partition_id = HV_PARTITION_ID_SELF; + input->apic_ids[0] = apic_id; + + output = (u32 *)input; + + control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_ID_FROM_APIC_ID; + status = hv_do_hypercall(control, input, output); + ret = output[0]; + + local_irq_restore(irq_flags); + + if (!hv_result_success(status)) { + pr_err("failed to get vp id from apic id %d, status %#llx\n", + apic_id, status); + return -EINVAL; + } + + return ret; +} + +static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip) +{ + int vp_id; + + pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid); + vp_id = hv_vtl_apicid_to_vp_id(apicid); + + if (vp_id < 0) { + pr_err("Couldn't find CPU with APIC ID %d\n", apicid); + return -EINVAL; + } + if (vp_id > ms_hyperv.max_vp_index) { + pr_err("Invalid CPU id %d for APIC ID %d\n", vp_id, apicid); + return -EINVAL; + } + + return hv_vtl_bringup_vcpu(vp_id, start_eip); +} + +static int __init hv_vtl_early_init(void) +{ + /* + * `boot_cpu_has` returns the runtime feature support, + * and here is the earliest it can be used. + */ + if (cpu_feature_enabled(X86_FEATURE_XSAVE)) + panic("XSAVE has to be disabled as it is not supported by this module.\n" + "Please add 'noxsave' to the kernel command line.\n"); + + real_mode_header = &hv_vtl_real_mode_header; + apic->wakeup_secondary_cpu_64 = hv_vtl_wakeup_secondary_cpu; + + return 0; +} +early_initcall(hv_vtl_early_init); diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 67f8386c1775..b445e252aa83 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -19,6 +19,10 @@ */ #define HV_IOAPIC_BASE_ADDRESS 0xfec00000 +#define HV_VTL_NORMAL 0x0 +#define HV_VTL_SECURE 0x1 +#define HV_VTL_MGMT 0x2 + union hv_ghcb; DECLARE_STATIC_KEY_FALSE(isolation_type_snp); @@ -276,6 +280,12 @@ static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; } #endif /* CONFIG_HYPERV */ +#ifdef CONFIG_HYPERV_VTL_MODE +void __init hv_vtl_init_platform(void); +#else +static inline void __init hv_vtl_init_platform(void) {} +#endif + #include #endif diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index c8a0e70cc484..c7969e806c64 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -514,6 +514,7 @@ static void __init ms_hyperv_init_platform(void) /* Register Hyper-V specific clocksource */ hv_init_clocksource(); + hv_vtl_init_platform(); #endif /* * TSC should be marked as unstable only after Hyper-V From 63f148c44f3919047301a023b10b0e3ce65a7389 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Wed, 19 Apr 2023 09:09:33 +0200 Subject: [PATCH 113/182] sh: pci: Remove unused variable in SH-7786 PCI Express code Addresses the following warning when building sdk7786_defconfig: arch/sh/drivers/pci/pcie-sh7786.c:34:22: warning: 'dma_pfn_offset' defined but not used [-Wunused-variable] 34 | static unsigned long dma_pfn_offset; | ^~~~~~~~~~~~~~ Fixes: e0d072782c73 ("dma-mapping: introduce DMA range map, supplanting dma_pfn_offset") Reviewed-by: Geert Uytterhoeven Signed-off-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230419070934.422997-1-glaubitz@physik.fu-berlin.de --- arch/sh/drivers/pci/pcie-sh7786.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index b0c2a5238d04..39bb5038e1c6 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -31,7 +31,6 @@ struct sh7786_pcie_port { static struct sh7786_pcie_port *sh7786_pcie_ports; static unsigned int nr_ports; -static unsigned long dma_pfn_offset; size_t memsize; u64 memstart; From 80f746e2bd0e1da3fdb49a53570e54a1a225faac Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Wed, 19 Apr 2023 13:48:52 +0200 Subject: [PATCH 114/182] sh: sq: Fix incorrect element size for allocating bitmap buffer The Store Queue code allocates a bitmap buffer with the size of multiple of sizeof(long) in sq_api_init(). While the buffer size is calculated correctly, the code uses the wrong element size to allocate the buffer which results in the allocated bitmap buffer being too small. Fix this by allocating the buffer with kcalloc() with element size sizeof(long) instead of kzalloc() whose elements size defaults to sizeof(char). Fixes: d7c30c682a27 ("sh: Store Queue API rework.") Reviewed-by: Geert Uytterhoeven Signed-off-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/20230419114854.528677-1-glaubitz@physik.fu-berlin.de --- arch/sh/kernel/cpu/sh4/sq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 27f2e3da5aa2..6e0bb3f47fa5 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -382,7 +382,7 @@ static int __init sq_api_init(void) if (unlikely(!sq_cache)) return ret; - sq_bitmap = kzalloc(size, GFP_KERNEL); + sq_bitmap = kcalloc(size, sizeof(long), GFP_KERNEL); if (unlikely(!sq_bitmap)) goto out; From 9c318a1d9b5000c77527011f158a75c5483510f5 Mon Sep 17 00:00:00 2001 From: Long Li Date: Thu, 20 Apr 2023 15:49:06 -0700 Subject: [PATCH 115/182] Drivers: hv: move panic report code from vmbus to hv early init code The panic reporting code was added in commit 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic") It was added to the vmbus driver. The panic reporting has no dependence on vmbus, and can be enabled at an earlier boot time when Hyper-V is initialized. This patch moves the panic reporting code out of vmbus. There is no functionality changes. During moving, also refactored some cleanup functions into hv_kmsg_dump_unregister(). Signed-off-by: Long Li Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/1682030946-6372-1-git-send-email-longli@linuxonhyperv.com Signed-off-by: Wei Liu --- drivers/hv/hv.c | 36 ------- drivers/hv/hv_common.c | 231 +++++++++++++++++++++++++++++++++++++++++ drivers/hv/vmbus_drv.c | 199 ----------------------------------- 3 files changed, 231 insertions(+), 235 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 4e1407d59ba0..de6708dbe0df 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -38,42 +38,6 @@ int hv_init(void) return 0; } -/* - * Functions for allocating and freeing memory with size and - * alignment HV_HYP_PAGE_SIZE. These functions are needed because - * the guest page size may not be the same as the Hyper-V page - * size. We depend upon kmalloc() aligning power-of-two size - * allocations to the allocation size boundary, so that the - * allocated memory appears to Hyper-V as a page of the size - * it expects. - */ - -void *hv_alloc_hyperv_page(void) -{ - BUILD_BUG_ON(PAGE_SIZE < HV_HYP_PAGE_SIZE); - - if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - return (void *)__get_free_page(GFP_KERNEL); - else - return kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); -} - -void *hv_alloc_hyperv_zeroed_page(void) -{ - if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); - else - return kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); -} - -void hv_free_hyperv_page(unsigned long addr) -{ - if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - free_page(addr); - else - kfree((void *)addr); -} - /* * hv_post_message - Post a message using the hypervisor message IPC. * diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 6d40b6c7b23b..64f9ceca887b 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -17,8 +17,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -54,6 +57,10 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg); void * __percpu *hyperv_pcpu_output_arg; EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg); +static void hv_kmsg_dump_unregister(void); + +static struct ctl_table_header *hv_ctl_table_hdr; + /* * Hyper-V specific initialization and shutdown code that is * common across all architectures. Called from architecture @@ -62,6 +69,12 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg); void __init hv_common_free(void) { + unregister_sysctl_table(hv_ctl_table_hdr); + hv_ctl_table_hdr = NULL; + + if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) + hv_kmsg_dump_unregister(); + kfree(hv_vp_index); hv_vp_index = NULL; @@ -72,10 +85,203 @@ void __init hv_common_free(void) hyperv_pcpu_input_arg = NULL; } +/* + * Functions for allocating and freeing memory with size and + * alignment HV_HYP_PAGE_SIZE. These functions are needed because + * the guest page size may not be the same as the Hyper-V page + * size. We depend upon kmalloc() aligning power-of-two size + * allocations to the allocation size boundary, so that the + * allocated memory appears to Hyper-V as a page of the size + * it expects. + */ + +void *hv_alloc_hyperv_page(void) +{ + BUILD_BUG_ON(PAGE_SIZE < HV_HYP_PAGE_SIZE); + + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + return (void *)__get_free_page(GFP_KERNEL); + else + return kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page); + +void *hv_alloc_hyperv_zeroed_page(void) +{ + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + else + return kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page); + +void hv_free_hyperv_page(unsigned long addr) +{ + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + free_page(addr); + else + kfree((void *)addr); +} +EXPORT_SYMBOL_GPL(hv_free_hyperv_page); + +static void *hv_panic_page; + +/* + * Boolean to control whether to report panic messages over Hyper-V. + * + * It can be set via /proc/sys/kernel/hyperv_record_panic_msg + */ +static int sysctl_record_panic_msg = 1; + +/* + * sysctl option to allow the user to control whether kmsg data should be + * reported to Hyper-V on panic. + */ +static struct ctl_table hv_ctl_table[] = { + { + .procname = "hyperv_record_panic_msg", + .data = &sysctl_record_panic_msg, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE + }, + {} +}; + +static int hv_die_panic_notify_crash(struct notifier_block *self, + unsigned long val, void *args); + +static struct notifier_block hyperv_die_report_block = { + .notifier_call = hv_die_panic_notify_crash, +}; + +static struct notifier_block hyperv_panic_report_block = { + .notifier_call = hv_die_panic_notify_crash, +}; + +/* + * The following callback works both as die and panic notifier; its + * goal is to provide panic information to the hypervisor unless the + * kmsg dumper is used [see hv_kmsg_dump()], which provides more + * information but isn't always available. + * + * Notice that both the panic/die report notifiers are registered only + * if we have the capability HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE set. + */ +static int hv_die_panic_notify_crash(struct notifier_block *self, + unsigned long val, void *args) +{ + struct pt_regs *regs; + bool is_die; + + /* Don't notify Hyper-V unless we have a die oops event or panic. */ + if (self == &hyperv_panic_report_block) { + is_die = false; + regs = current_pt_regs(); + } else { /* die event */ + if (val != DIE_OOPS) + return NOTIFY_DONE; + + is_die = true; + regs = ((struct die_args *)args)->regs; + } + + /* + * Hyper-V should be notified only once about a panic/die. If we will + * be calling hv_kmsg_dump() later with kmsg data, don't do the + * notification here. + */ + if (!sysctl_record_panic_msg || !hv_panic_page) + hyperv_report_panic(regs, val, is_die); + + return NOTIFY_DONE; +} + +/* + * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg + * buffer and call into Hyper-V to transfer the data. + */ +static void hv_kmsg_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) +{ + struct kmsg_dump_iter iter; + size_t bytes_written; + + /* We are only interested in panics. */ + if (reason != KMSG_DUMP_PANIC || !sysctl_record_panic_msg) + return; + + /* + * Write dump contents to the page. No need to synchronize; panic should + * be single-threaded. + */ + kmsg_dump_rewind(&iter); + kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE, + &bytes_written); + if (!bytes_written) + return; + /* + * P3 to contain the physical address of the panic page & P4 to + * contain the size of the panic data in that page. Rest of the + * registers are no-op when the NOTIFY_MSG flag is set. + */ + hv_set_register(HV_REGISTER_CRASH_P0, 0); + hv_set_register(HV_REGISTER_CRASH_P1, 0); + hv_set_register(HV_REGISTER_CRASH_P2, 0); + hv_set_register(HV_REGISTER_CRASH_P3, virt_to_phys(hv_panic_page)); + hv_set_register(HV_REGISTER_CRASH_P4, bytes_written); + + /* + * Let Hyper-V know there is crash data available along with + * the panic message. + */ + hv_set_register(HV_REGISTER_CRASH_CTL, + (HV_CRASH_CTL_CRASH_NOTIFY | + HV_CRASH_CTL_CRASH_NOTIFY_MSG)); +} + +static struct kmsg_dumper hv_kmsg_dumper = { + .dump = hv_kmsg_dump, +}; + +static void hv_kmsg_dump_unregister(void) +{ + kmsg_dump_unregister(&hv_kmsg_dumper); + unregister_die_notifier(&hyperv_die_report_block); + atomic_notifier_chain_unregister(&panic_notifier_list, + &hyperv_panic_report_block); + + hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_panic_page = NULL; +} + +static void hv_kmsg_dump_register(void) +{ + int ret; + + hv_panic_page = hv_alloc_hyperv_zeroed_page(); + if (!hv_panic_page) { + pr_err("Hyper-V: panic message page memory allocation failed\n"); + return; + } + + ret = kmsg_dump_register(&hv_kmsg_dumper); + if (ret) { + pr_err("Hyper-V: kmsg dump register error 0x%x\n", ret); + hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_panic_page = NULL; + } +} + int __init hv_common_init(void) { int i; + if (hv_is_isolation_supported()) + sysctl_record_panic_msg = 0; + /* * Hyper-V expects to get crash register data or kmsg when * crash enlightment is available and system crashes. Set @@ -84,8 +290,33 @@ int __init hv_common_init(void) * kernel. */ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + u64 hyperv_crash_ctl; + crash_kexec_post_notifiers = true; pr_info("Hyper-V: enabling crash_kexec_post_notifiers\n"); + + /* + * Panic message recording (sysctl_record_panic_msg) + * is enabled by default in non-isolated guests and + * disabled by default in isolated guests; the panic + * message recording won't be available in isolated + * guests should the following registration fail. + */ + hv_ctl_table_hdr = register_sysctl("kernel", hv_ctl_table); + if (!hv_ctl_table_hdr) + pr_err("Hyper-V: sysctl table register error"); + + /* + * Register for panic kmsg callback only if the right + * capability is supported by the hypervisor. + */ + hyperv_crash_ctl = hv_get_register(HV_REGISTER_CRASH_CTL); + if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) + hv_kmsg_dump_register(); + + register_die_notifier(&hyperv_die_report_block); + atomic_notifier_chain_register(&panic_notifier_list, + &hyperv_panic_report_block); } /* diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 19a0069dc4a9..309c78ce1d30 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -50,26 +49,12 @@ static struct device *hv_dev; static int hyperv_cpuhp_online; -static void *hv_panic_page; - static long __percpu *vmbus_evt; /* Values parsed from ACPI DSDT */ int vmbus_irq; int vmbus_interrupt; -/* - * Boolean to control whether to report panic messages over Hyper-V. - * - * It can be set via /proc/sys/kernel/hyperv_record_panic_msg - */ -static int sysctl_record_panic_msg = 1; - -static int hyperv_report_reg(void) -{ - return !sysctl_record_panic_msg || !hv_panic_page; -} - /* * The panic notifier below is responsible solely for unloading the * vmbus connection, which is necessary in a panic event. @@ -90,54 +75,6 @@ static struct notifier_block hyperv_panic_vmbus_unload_block = { .priority = INT_MIN + 1, /* almost the latest one to execute */ }; -static int hv_die_panic_notify_crash(struct notifier_block *self, - unsigned long val, void *args); - -static struct notifier_block hyperv_die_report_block = { - .notifier_call = hv_die_panic_notify_crash, -}; -static struct notifier_block hyperv_panic_report_block = { - .notifier_call = hv_die_panic_notify_crash, -}; - -/* - * The following callback works both as die and panic notifier; its - * goal is to provide panic information to the hypervisor unless the - * kmsg dumper is used [see hv_kmsg_dump()], which provides more - * information but isn't always available. - * - * Notice that both the panic/die report notifiers are registered only - * if we have the capability HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE set. - */ -static int hv_die_panic_notify_crash(struct notifier_block *self, - unsigned long val, void *args) -{ - struct pt_regs *regs; - bool is_die; - - /* Don't notify Hyper-V unless we have a die oops event or panic. */ - if (self == &hyperv_panic_report_block) { - is_die = false; - regs = current_pt_regs(); - } else { /* die event */ - if (val != DIE_OOPS) - return NOTIFY_DONE; - - is_die = true; - regs = ((struct die_args *)args)->regs; - } - - /* - * Hyper-V should be notified only once about a panic/die. If we will - * be calling hv_kmsg_dump() later with kmsg data, don't do the - * notification here. - */ - if (hyperv_report_reg()) - hyperv_report_panic(regs, val, is_die); - - return NOTIFY_DONE; -} - static const char *fb_mmio_name = "fb_range"; static struct resource *fb_mmio; static struct resource *hyperv_mmio; @@ -1379,98 +1316,6 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg - * buffer and call into Hyper-V to transfer the data. - */ -static void hv_kmsg_dump(struct kmsg_dumper *dumper, - enum kmsg_dump_reason reason) -{ - struct kmsg_dump_iter iter; - size_t bytes_written; - - /* We are only interested in panics. */ - if ((reason != KMSG_DUMP_PANIC) || (!sysctl_record_panic_msg)) - return; - - /* - * Write dump contents to the page. No need to synchronize; panic should - * be single-threaded. - */ - kmsg_dump_rewind(&iter); - kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE, - &bytes_written); - if (!bytes_written) - return; - /* - * P3 to contain the physical address of the panic page & P4 to - * contain the size of the panic data in that page. Rest of the - * registers are no-op when the NOTIFY_MSG flag is set. - */ - hv_set_register(HV_REGISTER_CRASH_P0, 0); - hv_set_register(HV_REGISTER_CRASH_P1, 0); - hv_set_register(HV_REGISTER_CRASH_P2, 0); - hv_set_register(HV_REGISTER_CRASH_P3, virt_to_phys(hv_panic_page)); - hv_set_register(HV_REGISTER_CRASH_P4, bytes_written); - - /* - * Let Hyper-V know there is crash data available along with - * the panic message. - */ - hv_set_register(HV_REGISTER_CRASH_CTL, - (HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG)); -} - -static struct kmsg_dumper hv_kmsg_dumper = { - .dump = hv_kmsg_dump, -}; - -static void hv_kmsg_dump_register(void) -{ - int ret; - - hv_panic_page = hv_alloc_hyperv_zeroed_page(); - if (!hv_panic_page) { - pr_err("Hyper-V: panic message page memory allocation failed\n"); - return; - } - - ret = kmsg_dump_register(&hv_kmsg_dumper); - if (ret) { - pr_err("Hyper-V: kmsg dump register error 0x%x\n", ret); - hv_free_hyperv_page((unsigned long)hv_panic_page); - hv_panic_page = NULL; - } -} - -static struct ctl_table_header *hv_ctl_table_hdr; - -/* - * sysctl option to allow the user to control whether kmsg data should be - * reported to Hyper-V on panic. - */ -static struct ctl_table hv_ctl_table[] = { - { - .procname = "hyperv_record_panic_msg", - .data = &sysctl_record_panic_msg, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE - }, - {} -}; - -static struct ctl_table hv_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = hv_ctl_table - }, - {} -}; - /* * vmbus_bus_init -Main vmbus driver initialization routine. * @@ -1534,38 +1379,6 @@ static int vmbus_bus_init(void) if (ret) goto err_connect; - if (hv_is_isolation_supported()) - sysctl_record_panic_msg = 0; - - /* - * Only register if the crash MSRs are available - */ - if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { - u64 hyperv_crash_ctl; - /* - * Panic message recording (sysctl_record_panic_msg) - * is enabled by default in non-isolated guests and - * disabled by default in isolated guests; the panic - * message recording won't be available in isolated - * guests should the following registration fail. - */ - hv_ctl_table_hdr = register_sysctl_table(hv_root_table); - if (!hv_ctl_table_hdr) - pr_err("Hyper-V: sysctl table register error"); - - /* - * Register for panic kmsg callback only if the right - * capability is supported by the hypervisor. - */ - hyperv_crash_ctl = hv_get_register(HV_REGISTER_CRASH_CTL); - if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) - hv_kmsg_dump_register(); - - register_die_notifier(&hyperv_die_report_block); - atomic_notifier_chain_register(&panic_notifier_list, - &hyperv_panic_report_block); - } - /* * Always register the vmbus unload panic notifier because we * need to shut the VMbus channel connection on panic. @@ -1590,8 +1403,6 @@ err_alloc: } err_setup: bus_unregister(&hv_bus); - unregister_sysctl_table(hv_ctl_table_hdr); - hv_ctl_table_hdr = NULL; return ret; } @@ -2887,13 +2698,6 @@ static void __exit vmbus_exit(void) vmbus_free_channels(); kfree(vmbus_connection.channels); - if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { - kmsg_dump_unregister(&hv_kmsg_dumper); - unregister_die_notifier(&hyperv_die_report_block); - atomic_notifier_chain_unregister(&panic_notifier_list, - &hyperv_panic_report_block); - } - /* * The vmbus panic notifier is always registered, hence we should * also unconditionally unregister it here as well. @@ -2901,9 +2705,6 @@ static void __exit vmbus_exit(void) atomic_notifier_chain_unregister(&panic_notifier_list, &hyperv_panic_vmbus_unload_block); - free_page((unsigned long)hv_panic_page); - unregister_sysctl_table(hv_ctl_table_hdr); - hv_ctl_table_hdr = NULL; bus_unregister(&hv_bus); cpuhp_remove_state(hyperv_cpuhp_online); From c384c2401eed99a2e1f84191e573f15b898babe6 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Mon, 17 Apr 2023 14:03:43 +0300 Subject: [PATCH 116/182] vdpa/mlx5: Avoid losing link state updates Current code ignores link state updates if VIRTIO_NET_F_STATUS was not negotiated. However, link state updates could be received before feature negotiation was completed , therefore causing link state events to be lost, possibly leaving the link state down. Modify the code so link state notifier is registered after DRIVER_OK was negotiated and carry the registration only if VIRTIO_NET_F_STATUS was negotiated. Unregister the notifier when the device is reset. Fixes: 033779a708f0 ("vdpa/mlx5: make MTU/STATUS presence conditional on feature bits") Acked-by: Jason Wang Signed-off-by: Eli Cohen Message-Id: <20230417110343.138319-1-elic@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 203 +++++++++++++++++------------- 1 file changed, 114 insertions(+), 89 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 195963b82b63..97a16f7eb894 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2298,6 +2298,113 @@ static void update_cvq_info(struct mlx5_vdpa_dev *mvdev) } } +static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) +{ + u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; + int err; + + MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); + MLX5_SET(query_vport_state_in, in, op_mod, opmod); + MLX5_SET(query_vport_state_in, in, vport_number, vport); + if (vport) + MLX5_SET(query_vport_state_in, in, other_vport, 1); + + err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); + if (err) + return 0; + + return MLX5_GET(query_vport_state_out, out, state); +} + +static bool get_link_state(struct mlx5_vdpa_dev *mvdev) +{ + if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == + VPORT_STATE_UP) + return true; + + return false; +} + +static void update_carrier(struct work_struct *work) +{ + struct mlx5_vdpa_wq_ent *wqent; + struct mlx5_vdpa_dev *mvdev; + struct mlx5_vdpa_net *ndev; + + wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); + mvdev = wqent->mvdev; + ndev = to_mlx5_vdpa_ndev(mvdev); + if (get_link_state(mvdev)) + ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); + else + ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); + + if (ndev->config_cb.callback) + ndev->config_cb.callback(ndev->config_cb.private); + + kfree(wqent); +} + +static int queue_link_work(struct mlx5_vdpa_net *ndev) +{ + struct mlx5_vdpa_wq_ent *wqent; + + wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); + if (!wqent) + return -ENOMEM; + + wqent->mvdev = &ndev->mvdev; + INIT_WORK(&wqent->work, update_carrier); + queue_work(ndev->mvdev.wq, &wqent->work); + return 0; +} + +static int event_handler(struct notifier_block *nb, unsigned long event, void *param) +{ + struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); + struct mlx5_eqe *eqe = param; + int ret = NOTIFY_DONE; + + if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { + switch (eqe->sub_type) { + case MLX5_PORT_CHANGE_SUBTYPE_DOWN: + case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: + if (queue_link_work(ndev)) + return NOTIFY_DONE; + + ret = NOTIFY_OK; + break; + default: + return NOTIFY_DONE; + } + return ret; + } + return ret; +} + +static void register_link_notifier(struct mlx5_vdpa_net *ndev) +{ + if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) + return; + + ndev->nb.notifier_call = event_handler; + mlx5_notifier_register(ndev->mvdev.mdev, &ndev->nb); + ndev->nb_registered = true; + queue_link_work(ndev); +} + +static void unregister_link_notifier(struct mlx5_vdpa_net *ndev) +{ + if (!ndev->nb_registered) + return; + + ndev->nb_registered = false; + mlx5_notifier_unregister(ndev->mvdev.mdev, &ndev->nb); + if (ndev->mvdev.wq) + flush_workqueue(ndev->mvdev.wq); +} + static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); @@ -2567,10 +2674,11 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); goto err_setup; } + register_link_notifier(ndev); err = setup_driver(mvdev); if (err) { mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); - goto err_setup; + goto err_driver; } } else { mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); @@ -2582,6 +2690,8 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) up_write(&ndev->reslock); return; +err_driver: + unregister_link_notifier(ndev); err_setup: mlx5_vdpa_destroy_mr(&ndev->mvdev); ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; @@ -2607,6 +2717,7 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev) mlx5_vdpa_info(mvdev, "performing device reset\n"); down_write(&ndev->reslock); + unregister_link_notifier(ndev); teardown_driver(ndev); clear_vqs_ready(ndev); mlx5_vdpa_destroy_mr(&ndev->mvdev); @@ -2861,9 +2972,7 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev) mlx5_vdpa_info(mvdev, "suspending device\n"); down_write(&ndev->reslock); - ndev->nb_registered = false; - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); - flush_workqueue(ndev->mvdev.wq); + unregister_link_notifier(ndev); for (i = 0; i < ndev->cur_num_vqs; i++) { mvq = &ndev->vqs[i]; suspend_vq(ndev, mvq); @@ -3000,84 +3109,6 @@ struct mlx5_vdpa_mgmtdev { struct mlx5_vdpa_net *ndev; }; -static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) -{ - u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; - int err; - - MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); - MLX5_SET(query_vport_state_in, in, op_mod, opmod); - MLX5_SET(query_vport_state_in, in, vport_number, vport); - if (vport) - MLX5_SET(query_vport_state_in, in, other_vport, 1); - - err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); - if (err) - return 0; - - return MLX5_GET(query_vport_state_out, out, state); -} - -static bool get_link_state(struct mlx5_vdpa_dev *mvdev) -{ - if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == - VPORT_STATE_UP) - return true; - - return false; -} - -static void update_carrier(struct work_struct *work) -{ - struct mlx5_vdpa_wq_ent *wqent; - struct mlx5_vdpa_dev *mvdev; - struct mlx5_vdpa_net *ndev; - - wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); - mvdev = wqent->mvdev; - ndev = to_mlx5_vdpa_ndev(mvdev); - if (get_link_state(mvdev)) - ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); - else - ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); - - if (ndev->nb_registered && ndev->config_cb.callback) - ndev->config_cb.callback(ndev->config_cb.private); - - kfree(wqent); -} - -static int event_handler(struct notifier_block *nb, unsigned long event, void *param) -{ - struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); - struct mlx5_eqe *eqe = param; - int ret = NOTIFY_DONE; - struct mlx5_vdpa_wq_ent *wqent; - - if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { - if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) - return NOTIFY_DONE; - switch (eqe->sub_type) { - case MLX5_PORT_CHANGE_SUBTYPE_DOWN: - case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: - wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); - if (!wqent) - return NOTIFY_DONE; - - wqent->mvdev = &ndev->mvdev; - INIT_WORK(&wqent->work, update_carrier); - queue_work(ndev->mvdev.wq, &wqent->work); - ret = NOTIFY_OK; - break; - default: - return NOTIFY_DONE; - } - return ret; - } - return ret; -} - static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) { int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); @@ -3258,9 +3289,6 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, goto err_res2; } - ndev->nb.notifier_call = event_handler; - mlx5_notifier_register(mdev, &ndev->nb); - ndev->nb_registered = true; mvdev->vdev.mdev = &mgtdev->mgtdev; err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); if (err) @@ -3294,10 +3322,7 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device * mlx5_vdpa_remove_debugfs(ndev->debugfs); ndev->debugfs = NULL; - if (ndev->nb_registered) { - ndev->nb_registered = false; - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); - } + unregister_link_notifier(ndev); wq = mvdev->wq; mvdev->wq = NULL; destroy_workqueue(wq); From e4be66e5f36b8cd2a052ba9e2ba063e6c37f5453 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 27 Feb 2023 13:41:27 -0800 Subject: [PATCH 117/182] vhost: use struct_size and size_add to compute flex array sizes The vhost_get_avail_size and vhost_get_used_size functions compute the size of structures with flexible array members with an additional 2 bytes if the VIRTIO_RING_F_EVENT_IDX feature flag is set. Convert these functions to use struct_size() and size_add() instead of coding the calculation by hand. This ensures that the calculations will saturate at SIZE_MAX rather than overflowing. Signed-off-by: Jacob Keller Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: virtualization@lists.linux-foundation.org Cc: kvm@vger.kernel.org Message-Id: <20230227214127.3678392-1-jacob.e.keller@intel.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index f11bdbe4c2c5..43fa626d4e44 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -436,8 +436,7 @@ static size_t vhost_get_avail_size(struct vhost_virtqueue *vq, size_t event __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; - return sizeof(*vq->avail) + - sizeof(*vq->avail->ring) * num + event; + return size_add(struct_size(vq->avail, ring, num), event); } static size_t vhost_get_used_size(struct vhost_virtqueue *vq, @@ -446,8 +445,7 @@ static size_t vhost_get_used_size(struct vhost_virtqueue *vq, size_t event __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; - return sizeof(*vq->used) + - sizeof(*vq->used->ring) * num + event; + return size_add(struct_size(vq->used, ring, num), event); } static size_t vhost_get_desc_size(struct vhost_virtqueue *vq, From 48cd6bc5b22d68b8bbc8601f3c7ddeed99541a0b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 18 Feb 2023 09:10:31 +0100 Subject: [PATCH 118/182] virtio: Reorder fields in 'struct virtqueue' Group some variables based on their sizes to reduce hole and avoid padding. On x86_64, this shrinks the size of 'struct virtqueue' from 72 to 68 bytes. It saves a few bytes of memory. Signed-off-by: Christophe JAILLET Message-Id: <8f3d2e49270a2158717e15008e7ed7228196ba02.1676707807.git.christophe.jaillet@wanadoo.fr> Signed-off-by: Michael S. Tsirkin Acked-by: Peter Lafreniere Reviewed-by: Stefano Garzarella --- include/linux/virtio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 2b472514c49b..d6e161aa532e 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -34,8 +34,8 @@ struct virtqueue { unsigned int index; unsigned int num_free; unsigned int num_max; - void *priv; bool reset; + void *priv; }; int virtqueue_add_outbuf(struct virtqueue *vq, From 9b2b3de63c07123c0ec9b912d7b8e77b150e520b Mon Sep 17 00:00:00 2001 From: Rong Tao Date: Thu, 9 Mar 2023 14:13:20 +0800 Subject: [PATCH 119/182] tools/virtio: virtio_test: Fix indentation Replace eight spaces with Tab. Signed-off-by: Rong Tao Message-Id: Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 120062f94590..280c6f8ee297 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -134,7 +134,7 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features) dev->buf_size = 1024; dev->buf = malloc(dev->buf_size); assert(dev->buf); - dev->control = open("/dev/vhost-test", O_RDWR); + dev->control = open("/dev/vhost-test", O_RDWR); assert(dev->control >= 0); r = ioctl(dev->control, VHOST_SET_OWNER, NULL); assert(r >= 0); From 6b27cd84a7917b995f66c052fd3453fdbd6e3d70 Mon Sep 17 00:00:00 2001 From: Rong Tao Date: Thu, 9 Mar 2023 16:42:50 +0800 Subject: [PATCH 120/182] tools/virtio: virtio_test -h,--help should return directly When we get help information, we should return directly, and we should not execute test cases. Move the exit() directly into the help() function and remove it from case '?'. Signed-off-by: Rong Tao Message-Id: Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 280c6f8ee297..028f54e6854a 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -327,7 +327,7 @@ const struct option longopts[] = { } }; -static void help(void) +static void help(int status) { fprintf(stderr, "Usage: virtio_test [--help]" " [--no-indirect]" @@ -337,6 +337,8 @@ static void help(void) " [--batch=random/N]" " [--reset=N]" "\n"); + + exit(status); } int main(int argc, char **argv) @@ -354,14 +356,12 @@ int main(int argc, char **argv) case -1: goto done; case '?': - help(); - exit(2); + help(2); case 'e': features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX); break; case 'h': - help(); - goto done; + help(0); case 'i': features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC); break; From 1adbd6b2fc0c09645c4c30c5eb47beaa3e6ea4b4 Mon Sep 17 00:00:00 2001 From: Feng Liu Date: Fri, 10 Mar 2023 07:34:27 +0200 Subject: [PATCH 121/182] virtio_ring: Avoid using inline for small functions According to kernel coding style [1], defining inline functions is not necessary and beneficial for simple functions. Hence clean up the code by removing the inline keyword. It is verified with GCC 12.2.0, the generated code with/without inline is same. Additionally tested with pktgen and iperf, and verified the result, the pps test results are the same in the cases of with/without inline. Iperf and pps of pktgen for virtio-net didn't change before and after the change. [1] https://www.kernel.org/doc/html/v6.2-rc3/process/coding-style.html#the-inline-disease Signed-off-by: Feng Liu Reviewed-by: Jiri Pirko Reviewed-by: Parav Pandit Reviewed-by: Gavin Li Reviewed-by: Bodong Wang Reviewed-by: David Edmondson Message-Id: <20230310053428.3376-3-feliu@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_ring.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 41144b5246a8..a26fab91c59f 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -233,8 +233,8 @@ static void vring_free(struct virtqueue *_vq); #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) -static inline bool virtqueue_use_indirect(struct vring_virtqueue *vq, - unsigned int total_sg) +static bool virtqueue_use_indirect(struct vring_virtqueue *vq, + unsigned int total_sg) { /* * If the host supports indirect descriptor tables, and we have multiple @@ -349,7 +349,7 @@ static void vring_free_queue(struct virtio_device *vdev, size_t size, * making all of the arch DMA ops work on the vring device itself * is a mess. */ -static inline struct device *vring_dma_dev(const struct vring_virtqueue *vq) +static struct device *vring_dma_dev(const struct vring_virtqueue *vq) { return vq->dma_dev; } @@ -784,7 +784,7 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head, } } -static inline bool more_used_split(const struct vring_virtqueue *vq) +static bool more_used_split(const struct vring_virtqueue *vq) { return vq->last_used_idx != virtio16_to_cpu(vq->vq.vdev, vq->split.vring.used->idx); @@ -1172,12 +1172,12 @@ err: /* * Packed ring specific functions - *_packed(). */ -static inline bool packed_used_wrap_counter(u16 last_used_idx) +static bool packed_used_wrap_counter(u16 last_used_idx) { return !!(last_used_idx & (1 << VRING_PACKED_EVENT_F_WRAP_CTR)); } -static inline u16 packed_last_used(u16 last_used_idx) +static u16 packed_last_used(u16 last_used_idx) { return last_used_idx & ~(-(1 << VRING_PACKED_EVENT_F_WRAP_CTR)); } @@ -1612,7 +1612,7 @@ static inline bool is_used_desc_packed(const struct vring_virtqueue *vq, return avail == used && used == used_wrap_counter; } -static inline bool more_used_packed(const struct vring_virtqueue *vq) +static bool more_used_packed(const struct vring_virtqueue *vq) { u16 last_used; u16 last_used_idx; From 4b6ec919b84830949313c805c586fb34f141ce0c Mon Sep 17 00:00:00 2001 From: Feng Liu Date: Fri, 10 Mar 2023 07:34:28 +0200 Subject: [PATCH 122/182] virtio_ring: Use const to annotate read-only pointer params Add const to make the read-only pointer parameters clear, similar to many existing functions. To implement this change, the commit also introduces the use of `container_of_const` to implement `to_vvq`, which ensures the const-ness of read-only parameters and avoids accidental modification of their members. Signed-off-by: Feng Liu Reviewed-by: Jiri Pirko Reviewed-by: Parav Pandit Reviewed-by: Gavin Li Reviewed-by: Bodong Wang Message-Id: <20230310053428.3376-4-feliu@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_ring.c | 36 ++++++++++++++++++------------------ include/linux/virtio.h | 14 +++++++------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index a26fab91c59f..4c3bb0ddeb9b 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -231,9 +231,9 @@ static void vring_free(struct virtqueue *_vq); * Helpers. */ -#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) +#define to_vvq(_vq) container_of_const(_vq, struct vring_virtqueue, vq) -static bool virtqueue_use_indirect(struct vring_virtqueue *vq, +static bool virtqueue_use_indirect(const struct vring_virtqueue *vq, unsigned int total_sg) { /* @@ -269,7 +269,7 @@ static bool virtqueue_use_indirect(struct vring_virtqueue *vq, * unconditionally on data path. */ -static bool vring_use_dma_api(struct virtio_device *vdev) +static bool vring_use_dma_api(const struct virtio_device *vdev) { if (!virtio_has_dma_quirk(vdev)) return true; @@ -289,7 +289,7 @@ static bool vring_use_dma_api(struct virtio_device *vdev) return false; } -size_t virtio_max_dma_size(struct virtio_device *vdev) +size_t virtio_max_dma_size(const struct virtio_device *vdev) { size_t max_segment_size = SIZE_MAX; @@ -423,7 +423,7 @@ static void virtqueue_init(struct vring_virtqueue *vq, u32 num) */ static void vring_unmap_one_split_indirect(const struct vring_virtqueue *vq, - struct vring_desc *desc) + const struct vring_desc *desc) { u16 flags; @@ -1183,7 +1183,7 @@ static u16 packed_last_used(u16 last_used_idx) } static void vring_unmap_extra_packed(const struct vring_virtqueue *vq, - struct vring_desc_extra *extra) + const struct vring_desc_extra *extra) { u16 flags; @@ -1206,7 +1206,7 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq, } static void vring_unmap_desc_packed(const struct vring_virtqueue *vq, - struct vring_packed_desc *desc) + const struct vring_packed_desc *desc) { u16 flags; @@ -2786,10 +2786,10 @@ EXPORT_SYMBOL_GPL(vring_transport_features); * Returns the size of the vring. This is mainly used for boasting to * userspace. Unlike other operations, this need not be serialized. */ -unsigned int virtqueue_get_vring_size(struct virtqueue *_vq) +unsigned int virtqueue_get_vring_size(const struct virtqueue *_vq) { - struct vring_virtqueue *vq = to_vvq(_vq); + const struct vring_virtqueue *vq = to_vvq(_vq); return vq->packed_ring ? vq->packed.vring.num : vq->split.vring.num; } @@ -2819,9 +2819,9 @@ void __virtqueue_unbreak(struct virtqueue *_vq) } EXPORT_SYMBOL_GPL(__virtqueue_unbreak); -bool virtqueue_is_broken(struct virtqueue *_vq) +bool virtqueue_is_broken(const struct virtqueue *_vq) { - struct vring_virtqueue *vq = to_vvq(_vq); + const struct vring_virtqueue *vq = to_vvq(_vq); return READ_ONCE(vq->broken); } @@ -2868,9 +2868,9 @@ void __virtio_unbreak_device(struct virtio_device *dev) } EXPORT_SYMBOL_GPL(__virtio_unbreak_device); -dma_addr_t virtqueue_get_desc_addr(struct virtqueue *_vq) +dma_addr_t virtqueue_get_desc_addr(const struct virtqueue *_vq) { - struct vring_virtqueue *vq = to_vvq(_vq); + const struct vring_virtqueue *vq = to_vvq(_vq); BUG_ON(!vq->we_own_ring); @@ -2881,9 +2881,9 @@ dma_addr_t virtqueue_get_desc_addr(struct virtqueue *_vq) } EXPORT_SYMBOL_GPL(virtqueue_get_desc_addr); -dma_addr_t virtqueue_get_avail_addr(struct virtqueue *_vq) +dma_addr_t virtqueue_get_avail_addr(const struct virtqueue *_vq) { - struct vring_virtqueue *vq = to_vvq(_vq); + const struct vring_virtqueue *vq = to_vvq(_vq); BUG_ON(!vq->we_own_ring); @@ -2895,9 +2895,9 @@ dma_addr_t virtqueue_get_avail_addr(struct virtqueue *_vq) } EXPORT_SYMBOL_GPL(virtqueue_get_avail_addr); -dma_addr_t virtqueue_get_used_addr(struct virtqueue *_vq) +dma_addr_t virtqueue_get_used_addr(const struct virtqueue *_vq) { - struct vring_virtqueue *vq = to_vvq(_vq); + const struct vring_virtqueue *vq = to_vvq(_vq); BUG_ON(!vq->we_own_ring); @@ -2910,7 +2910,7 @@ dma_addr_t virtqueue_get_used_addr(struct virtqueue *_vq) EXPORT_SYMBOL_GPL(virtqueue_get_used_addr); /* Only available for split ring */ -const struct vring *virtqueue_get_vring(struct virtqueue *vq) +const struct vring *virtqueue_get_vring(const struct virtqueue *vq) { return &to_vvq(vq)->split.vring; } diff --git a/include/linux/virtio.h b/include/linux/virtio.h index d6e161aa532e..b93238db94e3 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -84,14 +84,14 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *vq); void *virtqueue_detach_unused_buf(struct virtqueue *vq); -unsigned int virtqueue_get_vring_size(struct virtqueue *vq); +unsigned int virtqueue_get_vring_size(const struct virtqueue *vq); -bool virtqueue_is_broken(struct virtqueue *vq); +bool virtqueue_is_broken(const struct virtqueue *vq); -const struct vring *virtqueue_get_vring(struct virtqueue *vq); -dma_addr_t virtqueue_get_desc_addr(struct virtqueue *vq); -dma_addr_t virtqueue_get_avail_addr(struct virtqueue *vq); -dma_addr_t virtqueue_get_used_addr(struct virtqueue *vq); +const struct vring *virtqueue_get_vring(const struct virtqueue *vq); +dma_addr_t virtqueue_get_desc_addr(const struct virtqueue *vq); +dma_addr_t virtqueue_get_avail_addr(const struct virtqueue *vq); +dma_addr_t virtqueue_get_used_addr(const struct virtqueue *vq); int virtqueue_resize(struct virtqueue *vq, u32 num, void (*recycle)(struct virtqueue *vq, void *buf)); @@ -147,7 +147,7 @@ int virtio_device_restore(struct virtio_device *dev); #endif void virtio_reset_device(struct virtio_device *dev); -size_t virtio_max_dma_size(struct virtio_device *vdev); +size_t virtio_max_dma_size(const struct virtio_device *vdev); #define virtio_device_for_each_vq(vdev, vq) \ list_for_each_entry(vq, &vdev->vqs, list) From 9a10cb4de33f4c914bd2e33ac05cff3ddb6a67b0 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Mar 2023 21:06:20 -0500 Subject: [PATCH 123/182] vhost-scsi: Delay releasing our refcount on the tpg We currently hold the vhost_scsi_mutex the entire time we are running vhost_scsi_clear_endpoint. One of the reasons for this is that it prevents userspace from being able to free the se_tpg from under us after we have called target_undepend_item. However, it forces management operations for for other devices to have to wait on a flakey device's: vhost_scsi_clear_endpoint -> vhost_scsi_flush() call which can which can take a long time. This moves the target_undepend_item call and the tpg unsetup code to after we have stopped new IO from starting up and after we have waited on running IO. We can then release our refcount on the tpg and session knowing our device is no longer accessing them. We can then drop the vhost_scsi_mutex use during thee flush call in later patches in this set, when we have removed other reasons for holding it. Signed-off-by: Mike Christie Message-Id: <20230321020624.13323-4-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 61 +++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 32d0be968103..502d6803df0b 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1691,11 +1691,10 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, if (!tpg) continue; - mutex_lock(&tpg->tv_tpg_mutex); tv_tport = tpg->tport; if (!tv_tport) { ret = -ENODEV; - goto err_tpg; + goto err_dev; } if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) { @@ -1704,35 +1703,51 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, tv_tport->tport_name, tpg->tport_tpgt, t->vhost_wwpn, t->vhost_tpgt); ret = -EINVAL; - goto err_tpg; + goto err_dev; } + match = true; + } + if (!match) + goto free_vs_tpg; + + /* Prevent new cmds from starting and accessing the tpgs/sessions */ + for (i = 0; i < vs->dev.nvqs; i++) { + vq = &vs->vqs[i].vq; + mutex_lock(&vq->mutex); + vhost_vq_set_backend(vq, NULL); + mutex_unlock(&vq->mutex); + } + /* Make sure cmds are not running before tearing them down. */ + vhost_scsi_flush(vs); + + for (i = 0; i < vs->dev.nvqs; i++) { + vq = &vs->vqs[i].vq; + vhost_scsi_destroy_vq_cmds(vq); + } + + /* + * We can now release our hold on the tpg and sessions and userspace + * can free them after this point. + */ + for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) { + target = i; + tpg = vs->vs_tpg[target]; + if (!tpg) + continue; + + mutex_lock(&tpg->tv_tpg_mutex); + tpg->tv_tpg_vhost_count--; tpg->vhost_scsi = NULL; vs->vs_tpg[target] = NULL; - match = true; + mutex_unlock(&tpg->tv_tpg_mutex); - /* - * Release se_tpg->tpg_group.cg_item configfs dependency now - * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur. - */ + se_tpg = &tpg->se_tpg; target_undepend_item(&se_tpg->tpg_group.cg_item); } - if (match) { - for (i = 0; i < vs->dev.nvqs; i++) { - vq = &vs->vqs[i].vq; - mutex_lock(&vq->mutex); - vhost_vq_set_backend(vq, NULL); - mutex_unlock(&vq->mutex); - } - /* Make sure cmds are not running before tearing them down. */ - vhost_scsi_flush(vs); - for (i = 0; i < vs->dev.nvqs; i++) { - vq = &vs->vqs[i].vq; - vhost_scsi_destroy_vq_cmds(vq); - } - } +free_vs_tpg: /* * Act as synchronize_rcu to make sure access to * old vs->vs_tpg is finished. @@ -1745,8 +1760,6 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, mutex_unlock(&vhost_scsi_mutex); return 0; -err_tpg: - mutex_unlock(&tpg->tv_tpg_mutex); err_dev: mutex_unlock(&vs->dev.mutex); mutex_unlock(&vhost_scsi_mutex); From eb1b291466376ad4d2f0a42392a2cd9f0e4983e5 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Mar 2023 21:06:21 -0500 Subject: [PATCH 124/182] vhost-scsi: Drop device mutex use in vhost_scsi_do_plug We don't need the device mutex in vhost_scsi_do_plug because: 1. we have the vhost_scsi_mutex so the tpg->vhost_scsi pointer will not change on us and the vhost_scsi can't be freed from under us if it was set. 2. vhost_scsi_clear_endpoint will stop the virtqueues and flush them while holding the vhost_scsi_mutex so we know once vhost_scsi_clear_endpoint has completed that vhost_scsi_do_plug can't send new events and any queued ones have completed. So this patch drops the device mutex use in vhost_scsi_do_plug. Signed-off-by: Mike Christie Message-Id: <20230321020624.13323-5-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 502d6803df0b..c945136ecf18 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -2003,8 +2003,6 @@ vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg, if (!vs) return; - mutex_lock(&vs->dev.mutex); - if (plug) reason = VIRTIO_SCSI_EVT_RESET_RESCAN; else @@ -2016,7 +2014,6 @@ vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg, vhost_scsi_send_evt(vs, tpg, lun, VIRTIO_SCSI_T_TRANSPORT_RESET, reason); mutex_unlock(&vq->mutex); - mutex_unlock(&vs->dev.mutex); } static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun) From ced9eb376ab716ec5b06bef8c3e05608b8eb6700 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Mar 2023 21:06:22 -0500 Subject: [PATCH 125/182] vhost-scsi: Check for a cleared backend before queueing an event We currenly hold the vhost_scsi_mutex while clearing the endpoint and while performing vhost_scsi_do_plug, so tpg->vhost_scsi can't be freed from uder us, and to make sure anything queued is handled by the full call in vhost_scsi_clear_endpoint. This patch removes the need for the vhost_scsi_mutex for the latter case. In the next patches, we won't hold the vhost_scsi_mutex while flushing so this patch adds a check for the clearing of the virtqueue from vhost_scsi_clear_endpoint. We then know that once vhost_scsi_clear_endpoint has cleared the backend that no new events will be queued, and the flush after the vhost_vq_set_backend(vq, NULL) call will see everything that's been queued to that point. So the flush will then handle all events without the need for the vhost_scsi_mutex. Signed-off-by: Mike Christie Message-Id: <20230321020624.13323-6-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index c945136ecf18..ba8097fcea43 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -2010,9 +2010,17 @@ vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg, vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq; mutex_lock(&vq->mutex); + /* + * We can't queue events if the backend has been cleared, because + * we could end up queueing an event after the flush. + */ + if (!vhost_vq_get_backend(vq)) + goto unlock; + if (vhost_has_feature(vq, VIRTIO_SCSI_F_HOTPLUG)) vhost_scsi_send_evt(vs, tpg, lun, VIRTIO_SCSI_T_TRANSPORT_RESET, reason); +unlock: mutex_unlock(&vq->mutex); } From f5ed6f9e82ee62bf805551522dfa2d6c8030bb47 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Mar 2023 21:06:23 -0500 Subject: [PATCH 126/182] vhost-scsi: Drop vhost_scsi_mutex use in port callouts We are using the vhost_scsi_mutex to make sure vhost_scsi_port_link and vhost_scsi_port_unlink see if vhost_scsi_clear_endpoint has cleared tpg->vhost_scsi and it can't be freed while they are using. However, we currently set the tpg->vhost_scsi pointer while holding tv_tpg_mutex. So, we can just hold that while calling vhost_scsi_hotplug/hotunplug. We then don't need to hold the vhost_scsi_mutex while vhost_scsi_clear_endpoint is holding it and doing a flush which could cause the LUN map/unmap to have to wait on another device's flush. Signed-off-by: Mike Christie Message-Id: <20230321020624.13323-7-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index ba8097fcea43..d4372a4aff49 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -2040,15 +2040,10 @@ static int vhost_scsi_port_link(struct se_portal_group *se_tpg, struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); - mutex_lock(&vhost_scsi_mutex); - mutex_lock(&tpg->tv_tpg_mutex); tpg->tv_tpg_port_count++; - mutex_unlock(&tpg->tv_tpg_mutex); - vhost_scsi_hotplug(tpg, lun); - - mutex_unlock(&vhost_scsi_mutex); + mutex_unlock(&tpg->tv_tpg_mutex); return 0; } @@ -2059,15 +2054,10 @@ static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg, struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); - mutex_lock(&vhost_scsi_mutex); - mutex_lock(&tpg->tv_tpg_mutex); tpg->tv_tpg_port_count--; - mutex_unlock(&tpg->tv_tpg_mutex); - vhost_scsi_hotunplug(tpg, lun); - - mutex_unlock(&vhost_scsi_mutex); + mutex_unlock(&tpg->tv_tpg_mutex); } static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store( From bea273c7a8712a055cd504a2bb7d76d8d713ba6e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Mar 2023 21:06:24 -0500 Subject: [PATCH 127/182] vhost-scsi: Reduce vhost_scsi_mutex use We on longer need to hold the vhost_scsi_mutex the entire time we set/clear the endpoint. The tv_tpg_mutex handles tpg accesses not related to the tpg list, the port link/unlink functions use the tv_tpg_mutex while accessing the tpg->vhost_scsi pointer, vhost_scsi_do_plug will no longer queue events after the virtqueue's backend has been cleared and flushed, and we don't drop our refcount to the tpg until after we have stopped cmds and wait for outstanding cmds to complete. This moves the vhost_scsi_mutex use to it's documented use of being used to access the tpg list. We then don't need to hold it while a flush is being performed causing other device's vhost_scsi_set_endpoint and vhost_scsi_make_tpg/vhost_scsi_drop_tpg calls to have to wait on a flakey device. Signed-off-by: Mike Christie Message-Id: <20230321020624.13323-8-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index d4372a4aff49..3b0b556c57ef 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -229,7 +229,10 @@ struct vhost_scsi_ctx { struct iov_iter out_iter; }; -/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */ +/* + * Global mutex to protect vhost_scsi TPG list for vhost IOCTLs and LIO + * configfs management operations. + */ static DEFINE_MUTEX(vhost_scsi_mutex); static LIST_HEAD(vhost_scsi_list); @@ -1526,7 +1529,7 @@ out: * vhost_scsi_tpg with an active struct vhost_scsi_nexus * * The lock nesting rule is: - * vhost_scsi_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex + * vs->dev.mutex -> vhost_scsi_mutex -> tpg->tv_tpg_mutex -> vq->mutex */ static int vhost_scsi_set_endpoint(struct vhost_scsi *vs, @@ -1540,7 +1543,6 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, int index, ret, i, len; bool match = false; - mutex_lock(&vhost_scsi_mutex); mutex_lock(&vs->dev.mutex); /* Verify that ring has been setup correctly. */ @@ -1561,6 +1563,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, if (vs->vs_tpg) memcpy(vs_tpg, vs->vs_tpg, len); + mutex_lock(&vhost_scsi_mutex); list_for_each_entry(tpg, &vhost_scsi_list, tv_tpg_list) { mutex_lock(&tpg->tv_tpg_mutex); if (!tpg->tpg_nexus) { @@ -1576,6 +1579,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) { if (vs->vs_tpg && vs->vs_tpg[tpg->tport_tpgt]) { mutex_unlock(&tpg->tv_tpg_mutex); + mutex_unlock(&vhost_scsi_mutex); ret = -EEXIST; goto undepend; } @@ -1590,6 +1594,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, if (ret) { pr_warn("target_depend_item() failed: %d\n", ret); mutex_unlock(&tpg->tv_tpg_mutex); + mutex_unlock(&vhost_scsi_mutex); goto undepend; } tpg->tv_tpg_vhost_count++; @@ -1599,6 +1604,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, } mutex_unlock(&tpg->tv_tpg_mutex); } + mutex_unlock(&vhost_scsi_mutex); if (match) { memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn, @@ -1654,7 +1660,6 @@ undepend: kfree(vs_tpg); out: mutex_unlock(&vs->dev.mutex); - mutex_unlock(&vhost_scsi_mutex); return ret; } @@ -1670,7 +1675,6 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, int index, ret, i; u8 target; - mutex_lock(&vhost_scsi_mutex); mutex_lock(&vs->dev.mutex); /* Verify that ring has been setup correctly. */ for (index = 0; index < vs->dev.nvqs; ++index) { @@ -1757,12 +1761,10 @@ free_vs_tpg: vs->vs_tpg = NULL; WARN_ON(vs->vs_events_nr); mutex_unlock(&vs->dev.mutex); - mutex_unlock(&vhost_scsi_mutex); return 0; err_dev: mutex_unlock(&vs->dev.mutex); - mutex_unlock(&vhost_scsi_mutex); return ret; } From a084983dcd4e75616fe4102c690d2fc922ac32b5 Mon Sep 17 00:00:00 2001 From: Feng Liu Date: Wed, 15 Mar 2023 20:54:56 +0200 Subject: [PATCH 128/182] virtio_ring: Allow non power of 2 sizes for packed virtqueue According to the Virtio Specification, the Queue Size parameter of a virtqueue corresponds to the maximum number of descriptors in that queue, and it does not have to be a power of 2 for packed virtqueues. However, the virtio_pci_modern driver enforced a power of 2 check for virtqueue sizes, which is unnecessary and restrictive for packed virtuqueue. Split virtqueue still needs to check the virtqueue size is power_of_2 which has been done in vring_alloc_queue_split of the virtio_ring layer. To validate this change, we tested various virtqueue sizes for packed rings, including 128, 256, 512, 100, 200, 500, and 1000, with CONFIG_PAGE_POISONING enabled, and all tests passed successfully. Signed-off-by: Feng Liu Reviewed-by: Jiri Pirko Message-Id: <20230315185458.11638-2-feliu@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_modern.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index 9e496e288cfa..6e713904d8e8 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -310,11 +310,6 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, if (!num || vp_modern_get_queue_enable(mdev, index)) return ERR_PTR(-ENOENT); - if (!is_power_of_2(num)) { - dev_warn(&vp_dev->pci_dev->dev, "bad queue size %u", num); - return ERR_PTR(-EINVAL); - } - info->msix_vector = msix_vec; /* create the vring */ From 791a1cb7b8591ece6a5075dfed803da379e7ecd3 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 21 Mar 2023 13:28:08 +0200 Subject: [PATCH 129/182] vdpa/mlx5: Make VIRTIO_NET_F_MRG_RXBUF off by default Following patch adds driver support for VIRTIO_NET_F_MRG_RXBUF. Current firmware versions show degradation in packet rate when using MRG_RXBUF. Users who favor memory saving over packet rate could enable this feature but we want to keep it off by default. One can still enable it when creating the vdpa device using vdpa tool by providing features that include it. For example: $ vdpa dev add name vdpa0 mgmtdev pci/0000:86:00.2 device_features 0x300cb982b Acked-by: Jason Wang Signed-off-by: Eli Cohen Message-Id: <20230321112809.221432-2-elic@nvidia.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Si-Wei Liu --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 97a16f7eb894..b5245956665b 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -3158,6 +3158,8 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, return -EINVAL; } device_features &= add_config->device_features; + } else { + device_features &= ~BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); } if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) && device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) { From e9d67e59f151eae964f749af74dbe4bd3b01b0d2 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 21 Mar 2023 13:28:09 +0200 Subject: [PATCH 130/182] vdpa/mlx5: Extend driver support for new features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the possible list for features that can be supported by firmware. Note that different versions of firmware may or may not support these features. The driver is made aware of them by querying the firmware. While doing this, improve the code so we use enum names instead of hard coded numerical values. The new features supported by the driver are the following: VIRTIO_NET_F_MRG_RXBUF VIRTIO_NET_F_HOST_ECN VIRTIO_NET_F_GUEST_ECN VIRTIO_NET_F_GUEST_TSO6 VIRTIO_NET_F_GUEST_TSO4 Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eli Cohen Message-Id: <20230321112809.221432-3-elic@nvidia.com> Signed-off-by: Michael S. Tsirkin Acked-by: Eugenio Pérez Martin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 56 ++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index b5245956665b..e29e32b306ad 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -778,12 +778,28 @@ static bool vq_is_tx(u16 idx) return idx % 2; } -static u16 get_features_12_3(u64 features) +enum { + MLX5_VIRTIO_NET_F_MRG_RXBUF = 2, + MLX5_VIRTIO_NET_F_HOST_ECN = 4, + MLX5_VIRTIO_NET_F_GUEST_ECN = 6, + MLX5_VIRTIO_NET_F_GUEST_TSO6 = 7, + MLX5_VIRTIO_NET_F_GUEST_TSO4 = 8, + MLX5_VIRTIO_NET_F_GUEST_CSUM = 9, + MLX5_VIRTIO_NET_F_CSUM = 10, + MLX5_VIRTIO_NET_F_HOST_TSO6 = 11, + MLX5_VIRTIO_NET_F_HOST_TSO4 = 12, +}; + +static u16 get_features(u64 features) { - return (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << 9) | - (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << 8) | - (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << 7) | - (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_CSUM)) << 6); + return (!!(features & BIT_ULL(VIRTIO_NET_F_MRG_RXBUF)) << MLX5_VIRTIO_NET_F_MRG_RXBUF) | + (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_ECN)) << MLX5_VIRTIO_NET_F_HOST_ECN) | + (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_ECN)) << MLX5_VIRTIO_NET_F_GUEST_ECN) | + (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO6)) << MLX5_VIRTIO_NET_F_GUEST_TSO6) | + (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO4)) << MLX5_VIRTIO_NET_F_GUEST_TSO4) | + (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << MLX5_VIRTIO_NET_F_CSUM) | + (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << MLX5_VIRTIO_NET_F_HOST_TSO6) | + (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << MLX5_VIRTIO_NET_F_HOST_TSO4); } static bool counters_supported(const struct mlx5_vdpa_dev *mvdev) @@ -797,6 +813,7 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in); u32 out[MLX5_ST_SZ_DW(create_virtio_net_q_out)] = {}; void *obj_context; + u16 mlx_features; void *cmd_hdr; void *vq_ctx; void *in; @@ -812,6 +829,7 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque goto err_alloc; } + mlx_features = get_features(ndev->mvdev.actual_features); cmd_hdr = MLX5_ADDR_OF(create_virtio_net_q_in, in, general_obj_in_cmd_hdr); MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); @@ -822,7 +840,9 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, - get_features_12_3(ndev->mvdev.actual_features)); + mlx_features >> 3); + MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, + mlx_features & 7); vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context); MLX5_SET(virtio_q, vq_ctx, virtio_q_type, get_queue_type(ndev)); @@ -2171,23 +2191,27 @@ static u32 mlx5_vdpa_get_vq_group(struct vdpa_device *vdev, u16 idx) return MLX5_VDPA_DATAVQ_GROUP; } -enum { MLX5_VIRTIO_NET_F_GUEST_CSUM = 1 << 9, - MLX5_VIRTIO_NET_F_CSUM = 1 << 10, - MLX5_VIRTIO_NET_F_HOST_TSO6 = 1 << 11, - MLX5_VIRTIO_NET_F_HOST_TSO4 = 1 << 12, -}; - static u64 mlx_to_vritio_features(u16 dev_features) { u64 result = 0; - if (dev_features & MLX5_VIRTIO_NET_F_GUEST_CSUM) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_MRG_RXBUF)) + result |= BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_ECN)) + result |= BIT_ULL(VIRTIO_NET_F_HOST_ECN); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_ECN)) + result |= BIT_ULL(VIRTIO_NET_F_GUEST_ECN); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO6)) + result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO6); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO4)) + result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO4); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_CSUM)) result |= BIT_ULL(VIRTIO_NET_F_GUEST_CSUM); - if (dev_features & MLX5_VIRTIO_NET_F_CSUM) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_CSUM)) result |= BIT_ULL(VIRTIO_NET_F_CSUM); - if (dev_features & MLX5_VIRTIO_NET_F_HOST_TSO6) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO6)) result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO6); - if (dev_features & MLX5_VIRTIO_NET_F_HOST_TSO4) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO4)) result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO4); return result; From aaf0594829c3a6f16bdf5d30904a7db4548dae15 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:33 +0800 Subject: [PATCH 131/182] lib/group_cpus: Export group_cpus_evenly() Export group_cpus_evenly() so that some modules can make use of it to group CPUs evenly according to NUMA and CPU locality. Signed-off-by: Xie Yongji Acked-by: Jason Wang Message-Id: <20230323053043.35-2-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin --- lib/group_cpus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/group_cpus.c b/lib/group_cpus.c index 9c837a35fef7..aa3f6815bb12 100644 --- a/lib/group_cpus.c +++ b/lib/group_cpus.c @@ -426,3 +426,4 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps) return masks; } #endif /* CONFIG_SMP */ +EXPORT_SYMBOL_GPL(group_cpus_evenly); From 1d24692732fb299c94b0dcc032b48ac8fa85c854 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:34 +0800 Subject: [PATCH 132/182] vdpa: Add set/get_vq_affinity callbacks in vdpa_config_ops This introduces set/get_vq_affinity callbacks in vdpa_config_ops to support virtqueue affinity management for vdpa device drivers. Signed-off-by: Xie Yongji Acked-by: Jason Wang Message-Id: <20230323053043.35-3-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_vdpa.c | 28 ++++++++++++++++++++++++++++ include/linux/vdpa.h | 13 +++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index d7f5af62ddaa..f72696b4c1c2 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -337,6 +337,32 @@ static const char *virtio_vdpa_bus_name(struct virtio_device *vdev) return dev_name(&vdpa->dev); } +static int virtio_vdpa_set_vq_affinity(struct virtqueue *vq, + const struct cpumask *cpu_mask) +{ + struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vq->vdev); + struct vdpa_device *vdpa = vd_dev->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + unsigned int index = vq->index; + + if (ops->set_vq_affinity) + return ops->set_vq_affinity(vdpa, index, cpu_mask); + + return 0; +} + +static const struct cpumask * +virtio_vdpa_get_vq_affinity(struct virtio_device *vdev, int index) +{ + struct vdpa_device *vdpa = vd_get_vdpa(vdev); + const struct vdpa_config_ops *ops = vdpa->config; + + if (ops->get_vq_affinity) + return ops->get_vq_affinity(vdpa, index); + + return NULL; +} + static const struct virtio_config_ops virtio_vdpa_config_ops = { .get = virtio_vdpa_get, .set = virtio_vdpa_set, @@ -349,6 +375,8 @@ static const struct virtio_config_ops virtio_vdpa_config_ops = { .get_features = virtio_vdpa_get_features, .finalize_features = virtio_vdpa_finalize_features, .bus_name = virtio_vdpa_bus_name, + .set_vq_affinity = virtio_vdpa_set_vq_affinity, + .get_vq_affinity = virtio_vdpa_get_vq_affinity, }; static void virtio_vdpa_release_dev(struct device *_d) diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index 43f59ef10cc9..2313db735773 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -250,6 +250,15 @@ struct vdpa_map_file { * @vdev: vdpa device * Returns the iova range supported by * the device. + * @set_vq_affinity: Set the affinity of virtqueue (optional) + * @vdev: vdpa device + * @idx: virtqueue index + * @cpu_mask: the affinity mask + * Returns integer: success (0) or error (< 0) + * @get_vq_affinity: Get the affinity of virtqueue (optional) + * @vdev: vdpa device + * @idx: virtqueue index + * Returns the affinity mask * @set_group_asid: Set address space identifier for a * virtqueue group (optional) * @vdev: vdpa device @@ -340,6 +349,10 @@ struct vdpa_config_ops { const void *buf, unsigned int len); u32 (*get_generation)(struct vdpa_device *vdev); struct vdpa_iova_range (*get_iova_range)(struct vdpa_device *vdev); + int (*set_vq_affinity)(struct vdpa_device *vdev, u16 idx, + const struct cpumask *cpu_mask); + const struct cpumask *(*get_vq_affinity)(struct vdpa_device *vdev, + u16 idx); /* DMA ops */ int (*set_map)(struct vdpa_device *vdev, unsigned int asid, From 3dad56823b5332ffdbe1867b2d7b50fbacea124a Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:35 +0800 Subject: [PATCH 133/182] virtio-vdpa: Support interrupt affinity spreading mechanism To support interrupt affinity spreading mechanism, this makes use of group_cpus_evenly() to create an irq callback affinity mask for each virtqueue of vdpa device. Then we will unify set_vq_affinity callback to pass the affinity to the vdpa device driver. Signed-off-by: Xie Yongji Message-Id: <20230323053043.35-4-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/virtio/virtio_vdpa.c | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index f72696b4c1c2..f3826f42b704 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -272,6 +273,66 @@ static void virtio_vdpa_del_vqs(struct virtio_device *vdev) virtio_vdpa_del_vq(vq); } +static void default_calc_sets(struct irq_affinity *affd, unsigned int affvecs) +{ + affd->nr_sets = 1; + affd->set_size[0] = affvecs; +} + +static struct cpumask * +create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd) +{ + unsigned int affvecs = 0, curvec, usedvecs, i; + struct cpumask *masks = NULL; + + if (nvecs > affd->pre_vectors + affd->post_vectors) + affvecs = nvecs - affd->pre_vectors - affd->post_vectors; + + if (!affd->calc_sets) + affd->calc_sets = default_calc_sets; + + affd->calc_sets(affd, affvecs); + + if (!affvecs) + return NULL; + + masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL); + if (!masks) + return NULL; + + /* Fill out vectors at the beginning that don't need affinity */ + for (curvec = 0; curvec < affd->pre_vectors; curvec++) + cpumask_setall(&masks[curvec]); + + for (i = 0, usedvecs = 0; i < affd->nr_sets; i++) { + unsigned int this_vecs = affd->set_size[i]; + int j; + struct cpumask *result = group_cpus_evenly(this_vecs); + + if (!result) { + kfree(masks); + return NULL; + } + + for (j = 0; j < this_vecs; j++) + cpumask_copy(&masks[curvec + j], &result[j]); + kfree(result); + + curvec += this_vecs; + usedvecs += this_vecs; + } + + /* Fill out vectors at the end that don't need affinity */ + if (usedvecs >= affvecs) + curvec = affd->pre_vectors + affvecs; + else + curvec = affd->pre_vectors + usedvecs; + for (; curvec < nvecs; curvec++) + cpumask_setall(&masks[curvec]); + + return masks; +} + static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], @@ -282,9 +343,15 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev); struct vdpa_device *vdpa = vd_get_vdpa(vdev); const struct vdpa_config_ops *ops = vdpa->config; + struct irq_affinity default_affd = { 0 }; + struct cpumask *masks; struct vdpa_callback cb; int i, err, queue_idx = 0; + masks = create_affinity_masks(nvqs, desc ? desc : &default_affd); + if (!masks) + return -ENOMEM; + for (i = 0; i < nvqs; ++i) { if (!names[i]) { vqs[i] = NULL; @@ -298,6 +365,7 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, err = PTR_ERR(vqs[i]); goto err_setup_vq; } + ops->set_vq_affinity(vdpa, i, &masks[i]); } cb.callback = virtio_vdpa_config_cb; From 78885597b9ccf68d4ce554aec98db01ee3c2d3fc Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:36 +0800 Subject: [PATCH 134/182] vduse: Refactor allocation for vduse virtqueues Allocate memory for vduse virtqueues one by one instead of doing one allocation for all of them. This is a preparation for adding sysfs interface for virtqueues. Signed-off-by: Xie Yongji Acked-by: Jason Wang Message-Id: <20230323053043.35-5-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_user/vduse_dev.c | 98 ++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 0c3b48616a9f..98359d87a06f 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -76,7 +76,7 @@ struct vduse_umem { struct vduse_dev { struct vduse_vdpa *vdev; struct device *dev; - struct vduse_virtqueue *vqs; + struct vduse_virtqueue **vqs; struct vduse_iova_domain *domain; char *name; struct mutex lock; @@ -434,7 +434,7 @@ static void vduse_dev_reset(struct vduse_dev *dev) flush_work(&dev->inject); for (i = 0; i < dev->vq_num; i++) { - struct vduse_virtqueue *vq = &dev->vqs[i]; + struct vduse_virtqueue *vq = dev->vqs[i]; vq->ready = false; vq->desc_addr = 0; @@ -466,7 +466,7 @@ static int vduse_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 idx, u64 device_area) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; vq->desc_addr = desc_area; vq->driver_addr = driver_area; @@ -500,7 +500,7 @@ static void vduse_vq_kick_work(struct work_struct *work) static void vduse_vdpa_kick_vq(struct vdpa_device *vdpa, u16 idx) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; if (!eventfd_signal_allowed()) { schedule_work(&vq->kick); @@ -513,7 +513,7 @@ static void vduse_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 idx, struct vdpa_callback *cb) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; spin_lock(&vq->irq_lock); vq->cb.callback = cb->callback; @@ -524,7 +524,7 @@ static void vduse_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 idx, static void vduse_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; vq->num = num; } @@ -533,7 +533,7 @@ static void vduse_vdpa_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; vq->ready = ready; } @@ -541,7 +541,7 @@ static void vduse_vdpa_set_vq_ready(struct vdpa_device *vdpa, static bool vduse_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 idx) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; return vq->ready; } @@ -550,7 +550,7 @@ static int vduse_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 idx, const struct vdpa_vq_state *state) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; if (dev->driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) { vq->state.packed.last_avail_counter = @@ -569,7 +569,7 @@ static int vduse_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 idx, struct vdpa_vq_state *state) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; if (dev->driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) return vduse_dev_get_vq_state_packed(dev, vq, &state->packed); @@ -624,8 +624,8 @@ static u16 vduse_vdpa_get_vq_num_max(struct vdpa_device *vdpa) int i; for (i = 0; i < dev->vq_num; i++) - if (num_max < dev->vqs[i].num_max) - num_max = dev->vqs[i].num_max; + if (num_max < dev->vqs[i]->num_max) + num_max = dev->vqs[i]->num_max; return num_max; } @@ -863,7 +863,7 @@ static int vduse_kickfd_setup(struct vduse_dev *dev, return -EINVAL; index = array_index_nospec(eventfd->index, dev->vq_num); - vq = &dev->vqs[index]; + vq = dev->vqs[index]; if (eventfd->fd >= 0) { ctx = eventfd_ctx_fdget(eventfd->fd); if (IS_ERR(ctx)) @@ -889,7 +889,7 @@ static bool vduse_dev_is_ready(struct vduse_dev *dev) int i; for (i = 0; i < dev->vq_num; i++) - if (!dev->vqs[i].num_max) + if (!dev->vqs[i]->num_max) return false; return true; @@ -1130,7 +1130,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; index = array_index_nospec(config.index, dev->vq_num); - dev->vqs[index].num_max = config.max_size; + dev->vqs[index]->num_max = config.max_size; ret = 0; break; } @@ -1148,7 +1148,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; index = array_index_nospec(vq_info.index, dev->vq_num); - vq = &dev->vqs[index]; + vq = dev->vqs[index]; vq_info.desc_addr = vq->desc_addr; vq_info.driver_addr = vq->driver_addr; vq_info.device_addr = vq->device_addr; @@ -1198,7 +1198,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; index = array_index_nospec(index, dev->vq_num); - ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index].inject); + ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index]->inject); break; } case VDUSE_IOTLB_REG_UMEM: { @@ -1339,6 +1339,49 @@ static const struct file_operations vduse_dev_fops = { .llseek = noop_llseek, }; +static void vduse_dev_deinit_vqs(struct vduse_dev *dev) +{ + int i; + + if (!dev->vqs) + return; + + for (i = 0; i < dev->vq_num; i++) + kfree(dev->vqs[i]); + kfree(dev->vqs); +} + +static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num) +{ + int i; + + dev->vq_align = vq_align; + dev->vq_num = vq_num; + dev->vqs = kcalloc(dev->vq_num, sizeof(*dev->vqs), GFP_KERNEL); + if (!dev->vqs) + return -ENOMEM; + + for (i = 0; i < vq_num; i++) { + dev->vqs[i] = kzalloc(sizeof(*dev->vqs[i]), GFP_KERNEL); + if (!dev->vqs[i]) + goto err; + + dev->vqs[i]->index = i; + INIT_WORK(&dev->vqs[i]->inject, vduse_vq_irq_inject); + INIT_WORK(&dev->vqs[i]->kick, vduse_vq_kick_work); + spin_lock_init(&dev->vqs[i]->kick_lock); + spin_lock_init(&dev->vqs[i]->irq_lock); + } + + return 0; +err: + while (i--) + kfree(dev->vqs[i]); + kfree(dev->vqs); + dev->vqs = NULL; + return -ENOMEM; +} + static struct vduse_dev *vduse_dev_create(void) { struct vduse_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1396,7 +1439,7 @@ static int vduse_destroy_dev(char *name) device_destroy(vduse_class, MKDEV(MAJOR(vduse_major), dev->minor)); idr_remove(&vduse_idr, dev->minor); kvfree(dev->config); - kfree(dev->vqs); + vduse_dev_deinit_vqs(dev); vduse_domain_destroy(dev->domain); kfree(dev->name); vduse_dev_destroy(dev); @@ -1486,7 +1529,7 @@ ATTRIBUTE_GROUPS(vduse_dev); static int vduse_create_dev(struct vduse_dev_config *config, void *config_buf, u64 api_version) { - int i, ret; + int ret; struct vduse_dev *dev; ret = -EEXIST; @@ -1513,19 +1556,10 @@ static int vduse_create_dev(struct vduse_dev_config *config, dev->config = config_buf; dev->config_size = config->config_size; - dev->vq_align = config->vq_align; - dev->vq_num = config->vq_num; - dev->vqs = kcalloc(dev->vq_num, sizeof(*dev->vqs), GFP_KERNEL); - if (!dev->vqs) - goto err_vqs; - for (i = 0; i < dev->vq_num; i++) { - dev->vqs[i].index = i; - INIT_WORK(&dev->vqs[i].inject, vduse_vq_irq_inject); - INIT_WORK(&dev->vqs[i].kick, vduse_vq_kick_work); - spin_lock_init(&dev->vqs[i].kick_lock); - spin_lock_init(&dev->vqs[i].irq_lock); - } + ret = vduse_dev_init_vqs(dev, config->vq_align, config->vq_num); + if (ret) + goto err_vqs; ret = idr_alloc(&vduse_idr, dev, 1, VDUSE_DEV_MAX, GFP_KERNEL); if (ret < 0) @@ -1546,7 +1580,7 @@ static int vduse_create_dev(struct vduse_dev_config *config, err_dev: idr_remove(&vduse_idr, dev->minor); err_idr: - kfree(dev->vqs); + vduse_dev_deinit_vqs(dev); err_vqs: vduse_domain_destroy(dev->domain); err_domain: From 28f6288eb63d5979fa6758e64f52e4d55cf184a8 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:37 +0800 Subject: [PATCH 135/182] vduse: Support set_vq_affinity callback Since virtio-vdpa bus driver already support interrupt affinity spreading mechanism, let's implement the set_vq_affinity callback to bring it to vduse device. After we get the virtqueue's affinity, we can spread IRQs between CPUs in the affinity mask, in a round-robin manner, to run the irq callback. Signed-off-by: Xie Yongji Message-Id: <20230323053043.35-6-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vdpa/vdpa_user/vduse_dev.c | 61 ++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 98359d87a06f..45aa8703c4b5 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -41,6 +41,8 @@ #define VDUSE_IOVA_SIZE (128 * 1024 * 1024) #define VDUSE_MSG_DEFAULT_TIMEOUT 30 +#define IRQ_UNBOUND -1 + struct vduse_virtqueue { u16 index; u16 num_max; @@ -57,6 +59,8 @@ struct vduse_virtqueue { struct vdpa_callback cb; struct work_struct inject; struct work_struct kick; + int irq_effective_cpu; + struct cpumask irq_affinity; }; struct vduse_dev; @@ -128,6 +132,7 @@ static struct class *vduse_class; static struct cdev vduse_ctrl_cdev; static struct cdev vduse_cdev; static struct workqueue_struct *vduse_irq_wq; +static struct workqueue_struct *vduse_irq_bound_wq; static u32 allowed_device_id[] = { VIRTIO_ID_BLOCK, @@ -708,6 +713,15 @@ static u32 vduse_vdpa_get_generation(struct vdpa_device *vdpa) return dev->generation; } +static int vduse_vdpa_set_vq_affinity(struct vdpa_device *vdpa, u16 idx, + const struct cpumask *cpu_mask) +{ + struct vduse_dev *dev = vdpa_to_vduse(vdpa); + + cpumask_copy(&dev->vqs[idx]->irq_affinity, cpu_mask); + return 0; +} + static int vduse_vdpa_set_map(struct vdpa_device *vdpa, unsigned int asid, struct vhost_iotlb *iotlb) @@ -758,6 +772,7 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = { .get_config = vduse_vdpa_get_config, .set_config = vduse_vdpa_set_config, .get_generation = vduse_vdpa_get_generation, + .set_vq_affinity = vduse_vdpa_set_vq_affinity, .reset = vduse_vdpa_reset, .set_map = vduse_vdpa_set_map, .free = vduse_vdpa_free, @@ -917,7 +932,8 @@ static void vduse_vq_irq_inject(struct work_struct *work) } static int vduse_dev_queue_irq_work(struct vduse_dev *dev, - struct work_struct *irq_work) + struct work_struct *irq_work, + int irq_effective_cpu) { int ret = -EINVAL; @@ -926,7 +942,11 @@ static int vduse_dev_queue_irq_work(struct vduse_dev *dev, goto unlock; ret = 0; - queue_work(vduse_irq_wq, irq_work); + if (irq_effective_cpu == IRQ_UNBOUND) + queue_work(vduse_irq_wq, irq_work); + else + queue_work_on(irq_effective_cpu, + vduse_irq_bound_wq, irq_work); unlock: up_read(&dev->rwsem); @@ -1029,6 +1049,22 @@ unlock: return ret; } +static void vduse_vq_update_effective_cpu(struct vduse_virtqueue *vq) +{ + int curr_cpu = vq->irq_effective_cpu; + + while (true) { + curr_cpu = cpumask_next(curr_cpu, &vq->irq_affinity); + if (cpu_online(curr_cpu)) + break; + + if (curr_cpu >= nr_cpu_ids) + curr_cpu = IRQ_UNBOUND; + } + + vq->irq_effective_cpu = curr_cpu; +} + static long vduse_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1111,7 +1147,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; } case VDUSE_DEV_INJECT_CONFIG_IRQ: - ret = vduse_dev_queue_irq_work(dev, &dev->inject); + ret = vduse_dev_queue_irq_work(dev, &dev->inject, IRQ_UNBOUND); break; case VDUSE_VQ_SETUP: { struct vduse_vq_config config; @@ -1198,7 +1234,10 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; index = array_index_nospec(index, dev->vq_num); - ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index]->inject); + + vduse_vq_update_effective_cpu(dev->vqs[index]); + ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index]->inject, + dev->vqs[index]->irq_effective_cpu); break; } case VDUSE_IOTLB_REG_UMEM: { @@ -1367,10 +1406,12 @@ static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num) goto err; dev->vqs[i]->index = i; + dev->vqs[i]->irq_effective_cpu = IRQ_UNBOUND; INIT_WORK(&dev->vqs[i]->inject, vduse_vq_irq_inject); INIT_WORK(&dev->vqs[i]->kick, vduse_vq_kick_work); spin_lock_init(&dev->vqs[i]->kick_lock); spin_lock_init(&dev->vqs[i]->irq_lock); + cpumask_setall(&dev->vqs[i]->irq_affinity); } return 0; @@ -1858,12 +1899,15 @@ static int vduse_init(void) if (ret) goto err_cdev; + ret = -ENOMEM; vduse_irq_wq = alloc_workqueue("vduse-irq", WQ_HIGHPRI | WQ_SYSFS | WQ_UNBOUND, 0); - if (!vduse_irq_wq) { - ret = -ENOMEM; + if (!vduse_irq_wq) goto err_wq; - } + + vduse_irq_bound_wq = alloc_workqueue("vduse-irq-bound", WQ_HIGHPRI, 0); + if (!vduse_irq_bound_wq) + goto err_bound_wq; ret = vduse_domain_init(); if (ret) @@ -1877,6 +1921,8 @@ static int vduse_init(void) err_mgmtdev: vduse_domain_exit(); err_domain: + destroy_workqueue(vduse_irq_bound_wq); +err_bound_wq: destroy_workqueue(vduse_irq_wq); err_wq: cdev_del(&vduse_cdev); @@ -1896,6 +1942,7 @@ static void vduse_exit(void) { vduse_mgmtdev_exit(); vduse_domain_exit(); + destroy_workqueue(vduse_irq_bound_wq); destroy_workqueue(vduse_irq_wq); cdev_del(&vduse_cdev); device_destroy(vduse_class, vduse_major); From bfae1648ec2159da0a14d71a7d75b810f728a1e6 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:38 +0800 Subject: [PATCH 136/182] vduse: Support get_vq_affinity callback This implements get_vq_affinity callback so that the virtio-blk driver can build the blk-mq queues based on the irq callback affinity. Signed-off-by: Xie Yongji Message-Id: <20230323053043.35-7-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vdpa/vdpa_user/vduse_dev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 45aa8703c4b5..cefabd0dab9c 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -722,6 +722,14 @@ static int vduse_vdpa_set_vq_affinity(struct vdpa_device *vdpa, u16 idx, return 0; } +static const struct cpumask * +vduse_vdpa_get_vq_affinity(struct vdpa_device *vdpa, u16 idx) +{ + struct vduse_dev *dev = vdpa_to_vduse(vdpa); + + return &dev->vqs[idx]->irq_affinity; +} + static int vduse_vdpa_set_map(struct vdpa_device *vdpa, unsigned int asid, struct vhost_iotlb *iotlb) @@ -773,6 +781,7 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = { .set_config = vduse_vdpa_set_config, .get_generation = vduse_vdpa_get_generation, .set_vq_affinity = vduse_vdpa_set_vq_affinity, + .get_vq_affinity = vduse_vdpa_get_vq_affinity, .reset = vduse_vdpa_reset, .set_map = vduse_vdpa_set_map, .free = vduse_vdpa_free, From 66640f4a6fcc1861d1b1f9b36b65a218064f263f Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:39 +0800 Subject: [PATCH 137/182] vduse: Add sysfs interface for irq callback affinity Add sysfs interface for each vduse virtqueue to get/set the affinity for irq callback. This might be useful for performance tuning when the irq callback affinity mask contains more than one CPU. Signed-off-by: Xie Yongji Message-Id: <20230323053043.35-8-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vdpa/vdpa_user/vduse_dev.c | 124 ++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 11 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index cefabd0dab9c..77da3685568a 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -61,6 +61,7 @@ struct vduse_virtqueue { struct work_struct kick; int irq_effective_cpu; struct cpumask irq_affinity; + struct kobject kobj; }; struct vduse_dev; @@ -1387,6 +1388,96 @@ static const struct file_operations vduse_dev_fops = { .llseek = noop_llseek, }; +static ssize_t irq_cb_affinity_show(struct vduse_virtqueue *vq, char *buf) +{ + return sprintf(buf, "%*pb\n", cpumask_pr_args(&vq->irq_affinity)); +} + +static ssize_t irq_cb_affinity_store(struct vduse_virtqueue *vq, + const char *buf, size_t count) +{ + cpumask_var_t new_value; + int ret; + + if (!zalloc_cpumask_var(&new_value, GFP_KERNEL)) + return -ENOMEM; + + ret = cpumask_parse(buf, new_value); + if (ret) + goto free_mask; + + ret = -EINVAL; + if (!cpumask_intersects(new_value, cpu_online_mask)) + goto free_mask; + + cpumask_copy(&vq->irq_affinity, new_value); + ret = count; +free_mask: + free_cpumask_var(new_value); + return ret; +} + +struct vq_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct vduse_virtqueue *vq, char *buf); + ssize_t (*store)(struct vduse_virtqueue *vq, const char *buf, + size_t count); +}; + +static struct vq_sysfs_entry irq_cb_affinity_attr = __ATTR_RW(irq_cb_affinity); + +static struct attribute *vq_attrs[] = { + &irq_cb_affinity_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(vq); + +static ssize_t vq_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct vduse_virtqueue *vq = container_of(kobj, + struct vduse_virtqueue, kobj); + struct vq_sysfs_entry *entry = container_of(attr, + struct vq_sysfs_entry, attr); + + if (!entry->show) + return -EIO; + + return entry->show(vq, buf); +} + +static ssize_t vq_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct vduse_virtqueue *vq = container_of(kobj, + struct vduse_virtqueue, kobj); + struct vq_sysfs_entry *entry = container_of(attr, + struct vq_sysfs_entry, attr); + + if (!entry->store) + return -EIO; + + return entry->store(vq, buf, count); +} + +static const struct sysfs_ops vq_sysfs_ops = { + .show = vq_attr_show, + .store = vq_attr_store, +}; + +static void vq_release(struct kobject *kobj) +{ + struct vduse_virtqueue *vq = container_of(kobj, + struct vduse_virtqueue, kobj); + kfree(vq); +} + +static const struct kobj_type vq_type = { + .release = vq_release, + .sysfs_ops = &vq_sysfs_ops, + .default_groups = vq_groups, +}; + static void vduse_dev_deinit_vqs(struct vduse_dev *dev) { int i; @@ -1395,13 +1486,13 @@ static void vduse_dev_deinit_vqs(struct vduse_dev *dev) return; for (i = 0; i < dev->vq_num; i++) - kfree(dev->vqs[i]); + kobject_put(&dev->vqs[i]->kobj); kfree(dev->vqs); } static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num) { - int i; + int ret, i; dev->vq_align = vq_align; dev->vq_num = vq_num; @@ -1411,8 +1502,10 @@ static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num) for (i = 0; i < vq_num; i++) { dev->vqs[i] = kzalloc(sizeof(*dev->vqs[i]), GFP_KERNEL); - if (!dev->vqs[i]) + if (!dev->vqs[i]) { + ret = -ENOMEM; goto err; + } dev->vqs[i]->index = i; dev->vqs[i]->irq_effective_cpu = IRQ_UNBOUND; @@ -1421,15 +1514,23 @@ static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num) spin_lock_init(&dev->vqs[i]->kick_lock); spin_lock_init(&dev->vqs[i]->irq_lock); cpumask_setall(&dev->vqs[i]->irq_affinity); + + kobject_init(&dev->vqs[i]->kobj, &vq_type); + ret = kobject_add(&dev->vqs[i]->kobj, + &dev->dev->kobj, "vq%d", i); + if (ret) { + kfree(dev->vqs[i]); + goto err; + } } return 0; err: while (i--) - kfree(dev->vqs[i]); + kobject_put(&dev->vqs[i]->kobj); kfree(dev->vqs); dev->vqs = NULL; - return -ENOMEM; + return ret; } static struct vduse_dev *vduse_dev_create(void) @@ -1607,10 +1708,6 @@ static int vduse_create_dev(struct vduse_dev_config *config, dev->config = config_buf; dev->config_size = config->config_size; - ret = vduse_dev_init_vqs(dev, config->vq_align, config->vq_num); - if (ret) - goto err_vqs; - ret = idr_alloc(&vduse_idr, dev, 1, VDUSE_DEV_MAX, GFP_KERNEL); if (ret < 0) goto err_idr; @@ -1624,14 +1721,19 @@ static int vduse_create_dev(struct vduse_dev_config *config, ret = PTR_ERR(dev->dev); goto err_dev; } + + ret = vduse_dev_init_vqs(dev, config->vq_align, config->vq_num); + if (ret) + goto err_vqs; + __module_get(THIS_MODULE); return 0; +err_vqs: + device_destroy(vduse_class, MKDEV(MAJOR(vduse_major), dev->minor)); err_dev: idr_remove(&vduse_idr, dev->minor); err_idr: - vduse_dev_deinit_vqs(dev); -err_vqs: vduse_domain_destroy(dev->domain); err_domain: kfree(dev->name); From 5e68470f4e80a4120e9ecec408f6ab4ad386bd4a Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:40 +0800 Subject: [PATCH 138/182] vdpa: Add eventfd for the vdpa callback Add eventfd for the vdpa callback so that user can signal it directly instead of triggering the callback. It will be used for vhost-vdpa case. Signed-off-by: Xie Yongji Message-Id: <20230323053043.35-9-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vhost/vdpa.c | 2 ++ drivers/virtio/virtio_vdpa.c | 1 + include/linux/vdpa.h | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 7be9d9d8f01c..9cd878e25cff 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -599,9 +599,11 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, if (vq->call_ctx.ctx) { cb.callback = vhost_vdpa_virtqueue_cb; cb.private = vq; + cb.trigger = vq->call_ctx.ctx; } else { cb.callback = NULL; cb.private = NULL; + cb.trigger = NULL; } ops->set_vq_cb(vdpa, idx, &cb); vhost_vdpa_setup_vq_irq(v, idx); diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index f3826f42b704..2a095f37f26b 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -196,6 +196,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, /* Setup virtqueue callback */ cb.callback = callback ? virtio_vdpa_virtqueue_cb : NULL; cb.private = info; + cb.trigger = NULL; ops->set_vq_cb(vdpa, index, &cb); ops->set_vq_num(vdpa, index, virtqueue_get_vring_size(vq)); diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index 2313db735773..f2064fa2d2da 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -13,10 +13,16 @@ * struct vdpa_calllback - vDPA callback definition. * @callback: interrupt callback function * @private: the data passed to the callback function + * @trigger: the eventfd for the callback (Optional). + * When it is set, the vDPA driver must guarantee that + * signaling it is functional equivalent to triggering + * the callback. Then vDPA parent can signal it directly + * instead of triggering the callback. */ struct vdpa_callback { irqreturn_t (*callback)(void *data); void *private; + struct eventfd_ctx *trigger; }; /** From e38632dd71818d99bcebeb55f27dc764a9f7d547 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:41 +0800 Subject: [PATCH 139/182] vduse: Signal vq trigger eventfd directly if possible Now the vdpa callback will associate an trigger eventfd in some cases. For performance reasons, VDUSE can signal it directly during irq injection. Signed-off-by: Xie Yongji Acked-by: Jason Wang Message-Id: <20230323053043.35-10-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_user/vduse_dev.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 77da3685568a..8c06f6ab960b 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -459,6 +459,7 @@ static void vduse_dev_reset(struct vduse_dev *dev) spin_lock(&vq->irq_lock); vq->cb.callback = NULL; vq->cb.private = NULL; + vq->cb.trigger = NULL; spin_unlock(&vq->irq_lock); flush_work(&vq->inject); flush_work(&vq->kick); @@ -524,6 +525,7 @@ static void vduse_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 idx, spin_lock(&vq->irq_lock); vq->cb.callback = cb->callback; vq->cb.private = cb->private; + vq->cb.trigger = cb->trigger; spin_unlock(&vq->irq_lock); } @@ -941,6 +943,23 @@ static void vduse_vq_irq_inject(struct work_struct *work) spin_unlock_irq(&vq->irq_lock); } +static bool vduse_vq_signal_irqfd(struct vduse_virtqueue *vq) +{ + bool signal = false; + + if (!vq->cb.trigger) + return false; + + spin_lock_irq(&vq->irq_lock); + if (vq->ready && vq->cb.trigger) { + eventfd_signal(vq->cb.trigger, 1); + signal = true; + } + spin_unlock_irq(&vq->irq_lock); + + return signal; +} + static int vduse_dev_queue_irq_work(struct vduse_dev *dev, struct work_struct *irq_work, int irq_effective_cpu) @@ -1243,11 +1262,14 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, if (index >= dev->vq_num) break; + ret = 0; index = array_index_nospec(index, dev->vq_num); - - vduse_vq_update_effective_cpu(dev->vqs[index]); - ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index]->inject, - dev->vqs[index]->irq_effective_cpu); + if (!vduse_vq_signal_irqfd(dev->vqs[index])) { + vduse_vq_update_effective_cpu(dev->vqs[index]); + ret = vduse_dev_queue_irq_work(dev, + &dev->vqs[index]->inject, + dev->vqs[index]->irq_effective_cpu); + } break; } case VDUSE_IOTLB_REG_UMEM: { From d4438d23eeeef8bb1b3a8abe418abffd60bb544a Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:42 +0800 Subject: [PATCH 140/182] vduse: Delay iova domain creation Delay creating iova domain until the vduse device is registered to vdpa bus. This is a preparation for adding sysfs interface to support specifying bounce buffer size for the iova domain. Signed-off-by: Xie Yongji Acked-by: Jason Wang Message-Id: <20230323053043.35-11-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_user/vduse_dev.c | 75 +++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 8c06f6ab960b..ccca84d51a28 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -111,6 +111,8 @@ struct vduse_dev { u32 vq_align; struct vduse_umem *umem; struct mutex mem_lock; + unsigned int bounce_size; + struct mutex domain_lock; }; struct vduse_dev_msg { @@ -425,7 +427,7 @@ static void vduse_dev_reset(struct vduse_dev *dev) struct vduse_iova_domain *domain = dev->domain; /* The coherent mappings are handled in vduse_dev_free_coherent() */ - if (domain->bounce_map) + if (domain && domain->bounce_map) vduse_domain_reset_bounce_map(domain); down_write(&dev->rwsem); @@ -993,6 +995,9 @@ static int vduse_dev_dereg_umem(struct vduse_dev *dev, goto unlock; ret = -EINVAL; + if (!dev->domain) + goto unlock; + if (dev->umem->iova != iova || size != dev->domain->bounce_size) goto unlock; @@ -1019,7 +1024,7 @@ static int vduse_dev_reg_umem(struct vduse_dev *dev, unsigned long npages, lock_limit; int ret; - if (!dev->domain->bounce_map || + if (!dev->domain || !dev->domain->bounce_map || size != dev->domain->bounce_size || iova != 0 || uaddr & ~PAGE_MASK) return -EINVAL; @@ -1109,7 +1114,6 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, struct vduse_iotlb_entry entry; struct vhost_iotlb_map *map; struct vdpa_map_file *map_file; - struct vduse_iova_domain *domain = dev->domain; struct file *f = NULL; ret = -EFAULT; @@ -1120,8 +1124,13 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, if (entry.start > entry.last) break; - spin_lock(&domain->iotlb_lock); - map = vhost_iotlb_itree_first(domain->iotlb, + mutex_lock(&dev->domain_lock); + if (!dev->domain) { + mutex_unlock(&dev->domain_lock); + break; + } + spin_lock(&dev->domain->iotlb_lock); + map = vhost_iotlb_itree_first(dev->domain->iotlb, entry.start, entry.last); if (map) { map_file = (struct vdpa_map_file *)map->opaque; @@ -1131,7 +1140,8 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, entry.last = map->last; entry.perm = map->perm; } - spin_unlock(&domain->iotlb_lock); + spin_unlock(&dev->domain->iotlb_lock); + mutex_unlock(&dev->domain_lock); ret = -EINVAL; if (!f) break; @@ -1284,8 +1294,10 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, sizeof(umem.reserved))) break; + mutex_lock(&dev->domain_lock); ret = vduse_dev_reg_umem(dev, umem.iova, umem.uaddr, umem.size); + mutex_unlock(&dev->domain_lock); break; } case VDUSE_IOTLB_DEREG_UMEM: { @@ -1299,15 +1311,15 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, if (!is_mem_zero((const char *)umem.reserved, sizeof(umem.reserved))) break; - + mutex_lock(&dev->domain_lock); ret = vduse_dev_dereg_umem(dev, umem.iova, umem.size); + mutex_unlock(&dev->domain_lock); break; } case VDUSE_IOTLB_GET_INFO: { struct vduse_iova_info info; struct vhost_iotlb_map *map; - struct vduse_iova_domain *domain = dev->domain; ret = -EFAULT; if (copy_from_user(&info, argp, sizeof(info))) @@ -1321,18 +1333,24 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, sizeof(info.reserved))) break; - spin_lock(&domain->iotlb_lock); - map = vhost_iotlb_itree_first(domain->iotlb, + mutex_lock(&dev->domain_lock); + if (!dev->domain) { + mutex_unlock(&dev->domain_lock); + break; + } + spin_lock(&dev->domain->iotlb_lock); + map = vhost_iotlb_itree_first(dev->domain->iotlb, info.start, info.last); if (map) { info.start = map->start; info.last = map->last; info.capability = 0; - if (domain->bounce_map && map->start == 0 && - map->last == domain->bounce_size - 1) + if (dev->domain->bounce_map && map->start == 0 && + map->last == dev->domain->bounce_size - 1) info.capability |= VDUSE_IOVA_CAP_UMEM; } - spin_unlock(&domain->iotlb_lock); + spin_unlock(&dev->domain->iotlb_lock); + mutex_unlock(&dev->domain_lock); if (!map) break; @@ -1355,7 +1373,10 @@ static int vduse_dev_release(struct inode *inode, struct file *file) { struct vduse_dev *dev = file->private_data; - vduse_dev_dereg_umem(dev, 0, dev->domain->bounce_size); + mutex_lock(&dev->domain_lock); + if (dev->domain) + vduse_dev_dereg_umem(dev, 0, dev->domain->bounce_size); + mutex_unlock(&dev->domain_lock); spin_lock(&dev->msg_lock); /* Make sure the inflight messages can processed after reconncection */ list_splice_init(&dev->recv_list, &dev->send_list); @@ -1564,6 +1585,7 @@ static struct vduse_dev *vduse_dev_create(void) mutex_init(&dev->lock); mutex_init(&dev->mem_lock); + mutex_init(&dev->domain_lock); spin_lock_init(&dev->msg_lock); INIT_LIST_HEAD(&dev->send_list); INIT_LIST_HEAD(&dev->recv_list); @@ -1613,7 +1635,8 @@ static int vduse_destroy_dev(char *name) idr_remove(&vduse_idr, dev->minor); kvfree(dev->config); vduse_dev_deinit_vqs(dev); - vduse_domain_destroy(dev->domain); + if (dev->domain) + vduse_domain_destroy(dev->domain); kfree(dev->name); vduse_dev_destroy(dev); module_put(THIS_MODULE); @@ -1722,11 +1745,7 @@ static int vduse_create_dev(struct vduse_dev_config *config, if (!dev->name) goto err_str; - dev->domain = vduse_domain_create(VDUSE_IOVA_SIZE - 1, - VDUSE_BOUNCE_SIZE); - if (!dev->domain) - goto err_domain; - + dev->bounce_size = VDUSE_BOUNCE_SIZE; dev->config = config_buf; dev->config_size = config->config_size; @@ -1756,8 +1775,6 @@ err_vqs: err_dev: idr_remove(&vduse_idr, dev->minor); err_idr: - vduse_domain_destroy(dev->domain); -err_domain: kfree(dev->name); err_str: vduse_dev_destroy(dev); @@ -1924,9 +1941,23 @@ static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, if (ret) return ret; + mutex_lock(&dev->domain_lock); + if (!dev->domain) + dev->domain = vduse_domain_create(VDUSE_IOVA_SIZE - 1, + dev->bounce_size); + mutex_unlock(&dev->domain_lock); + if (!dev->domain) { + put_device(&dev->vdev->vdpa.dev); + return -ENOMEM; + } + ret = _vdpa_register_device(&dev->vdev->vdpa, dev->vq_num); if (ret) { put_device(&dev->vdev->vdpa.dev); + mutex_lock(&dev->domain_lock); + vduse_domain_destroy(dev->domain); + dev->domain = NULL; + mutex_unlock(&dev->domain_lock); return ret; } From b774f93d87e198481680873b22c2a443e10c3f93 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 23 Mar 2023 13:30:43 +0800 Subject: [PATCH 141/182] vduse: Support specifying bounce buffer size via sysfs As discussed in [1], this adds sysfs interface to support specifying bounce buffer size in virtio-vdpa case. It would be a performance tuning parameter for high throughput workloads. [1] https://lore.kernel.org/netdev/e8f25a35-9d45-69f9-795d-bdbbb90337a3@redhat.com/ Signed-off-by: Xie Yongji Acked-by: Jason Wang Message-Id: <20230323053043.35-12-xieyongji@bytedance.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_user/vduse_dev.c | 45 +++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index ccca84d51a28..34eebdf030af 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -37,8 +37,11 @@ #define DRV_LICENSE "GPL v2" #define VDUSE_DEV_MAX (1U << MINORBITS) +#define VDUSE_MAX_BOUNCE_SIZE (1024 * 1024 * 1024) +#define VDUSE_MIN_BOUNCE_SIZE (1024 * 1024) #define VDUSE_BOUNCE_SIZE (64 * 1024 * 1024) -#define VDUSE_IOVA_SIZE (128 * 1024 * 1024) +/* 128 MB reserved for virtqueue creation */ +#define VDUSE_IOVA_SIZE (VDUSE_MAX_BOUNCE_SIZE + 128 * 1024 * 1024) #define VDUSE_MSG_DEFAULT_TIMEOUT 30 #define IRQ_UNBOUND -1 @@ -1715,8 +1718,48 @@ static ssize_t msg_timeout_store(struct device *device, static DEVICE_ATTR_RW(msg_timeout); +static ssize_t bounce_size_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct vduse_dev *dev = dev_get_drvdata(device); + + return sysfs_emit(buf, "%u\n", dev->bounce_size); +} + +static ssize_t bounce_size_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vduse_dev *dev = dev_get_drvdata(device); + unsigned int bounce_size; + int ret; + + ret = -EPERM; + mutex_lock(&dev->domain_lock); + if (dev->domain) + goto unlock; + + ret = kstrtouint(buf, 10, &bounce_size); + if (ret < 0) + goto unlock; + + ret = -EINVAL; + if (bounce_size > VDUSE_MAX_BOUNCE_SIZE || + bounce_size < VDUSE_MIN_BOUNCE_SIZE) + goto unlock; + + dev->bounce_size = bounce_size & PAGE_MASK; + ret = count; +unlock: + mutex_unlock(&dev->domain_lock); + return ret; +} + +static DEVICE_ATTR_RW(bounce_size); + static struct attribute *vduse_dev_attrs[] = { &dev_attr_msg_timeout.attr, + &dev_attr_bounce_size.attr, NULL }; From 905233af513c0c6971cae0f25280f23be1f6cbe4 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 31 Mar 2023 10:02:08 +0200 Subject: [PATCH 142/182] vringh: fix typos in the vringh_init_* documentation Replace `userpace` with `userspace`. Cc: Simon Horman Signed-off-by: Stefano Garzarella Message-Id: <20230331080208.17002-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Xuan Zhuo Acked-by: Jason Wang --- drivers/vhost/vringh.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index a1e27da54481..694462ba3242 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -636,9 +636,9 @@ static inline int xfer_to_user(const struct vringh *vrh, * @features: the feature bits for this ring. * @num: the number of elements. * @weak_barriers: true if we only need memory barriers, not I/O. - * @desc: the userpace descriptor pointer. - * @avail: the userpace avail pointer. - * @used: the userpace used pointer. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. * * Returns an error if num is invalid: you should check pointers * yourself! @@ -911,9 +911,9 @@ static inline int kern_xfer(const struct vringh *vrh, void *dst, * @features: the feature bits for this ring. * @num: the number of elements. * @weak_barriers: true if we only need memory barriers, not I/O. - * @desc: the userpace descriptor pointer. - * @avail: the userpace avail pointer. - * @used: the userpace used pointer. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. * * Returns an error if num is invalid. */ @@ -1306,9 +1306,9 @@ static inline int putused_iotlb(const struct vringh *vrh, * @features: the feature bits for this ring. * @num: the number of elements. * @weak_barriers: true if we only need memory barriers, not I/O. - * @desc: the userpace descriptor pointer. - * @avail: the userpace avail pointer. - * @used: the userpace used pointer. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. * * Returns an error if num is invalid. */ From c618c84d4ccc6268c3da7609c7388b6cb305c639 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:13:18 +0200 Subject: [PATCH 143/182] vdpa: add bind_mm/unbind_mm callbacks These new optional callbacks is used to bind/unbind the device to a specific address space so the vDPA framework can use VA when these callbacks are implemented. Suggested-by: Jason Wang Acked-by: Jason Wang Signed-off-by: Stefano Garzarella Message-Id: <20230404131326.44403-2-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- include/linux/vdpa.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index f2064fa2d2da..2f1af73b3a1a 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -305,6 +305,14 @@ struct vdpa_map_file { * @vdev: vdpa device * @idx: virtqueue index * Returns pointer to structure device or error (NULL) + * @bind_mm: Bind the device to a specific address space + * so the vDPA framework can use VA when this + * callback is implemented. (optional) + * @vdev: vdpa device + * @mm: address space to bind + * @unbind_mm: Unbind the device from the address space + * bound using the bind_mm callback. (optional) + * @vdev: vdpa device * @free: Free resources that belongs to vDPA (optional) * @vdev: vdpa device */ @@ -370,6 +378,8 @@ struct vdpa_config_ops { int (*set_group_asid)(struct vdpa_device *vdev, unsigned int group, unsigned int asid); struct device *(*get_vq_dma_dev)(struct vdpa_device *vdev, u16 idx); + int (*bind_mm)(struct vdpa_device *vdev, struct mm_struct *mm); + void (*unbind_mm)(struct vdpa_device *vdev); /* Free device resources */ void (*free)(struct vdpa_device *vdev); From 9067de4725a299bc1baf11de9f5040fdd0bd05c3 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:13:19 +0200 Subject: [PATCH 144/182] vhost-vdpa: use bind_mm/unbind_mm device callbacks When the user call VHOST_SET_OWNER ioctl and the vDPA device has `use_va` set to true, let's call the bind_mm callback. In this way we can bind the device to the user address space and directly use the user VA. The unbind_mm callback is called during the release after stopping the device. Signed-off-by: Stefano Garzarella Message-Id: <20230404131326.44403-3-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vdpa.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 9cd878e25cff..cd266fa80c4e 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -219,6 +219,28 @@ static int vhost_vdpa_reset(struct vhost_vdpa *v) return vdpa_reset(vdpa); } +static long vhost_vdpa_bind_mm(struct vhost_vdpa *v) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + + if (!vdpa->use_va || !ops->bind_mm) + return 0; + + return ops->bind_mm(vdpa, v->vdev.mm); +} + +static void vhost_vdpa_unbind_mm(struct vhost_vdpa *v) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + + if (!vdpa->use_va || !ops->unbind_mm) + return; + + ops->unbind_mm(vdpa); +} + static long vhost_vdpa_get_device_id(struct vhost_vdpa *v, u8 __user *argp) { struct vdpa_device *vdpa = v->vdpa; @@ -718,6 +740,17 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep, break; } + if (r) + goto out; + + switch (cmd) { + case VHOST_SET_OWNER: + r = vhost_vdpa_bind_mm(v); + if (r) + vhost_dev_reset_owner(d, NULL); + break; + } +out: mutex_unlock(&d->mutex); return r; } @@ -1289,6 +1322,7 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) vhost_vdpa_clean_irq(v); vhost_vdpa_reset(v); vhost_dev_stop(&v->vdev); + vhost_vdpa_unbind_mm(v); vhost_vdpa_config_put(v); vhost_vdpa_cleanup(v); mutex_unlock(&d->mutex); From c0371782500c5314741da9ccbfbf0375a0d379fc Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:13:20 +0200 Subject: [PATCH 145/182] vringh: replace kmap_atomic() with kmap_local_page() kmap_atomic() is deprecated in favor of kmap_local_page() since commit f3ba3c710ac5 ("mm/highmem: Provide kmap_local*"). With kmap_local_page() the mappings are per thread, CPU local, can take page-faults, and can be called from any context (including interrupts). Furthermore, the tasks can be preempted and, when they are scheduled to run again, the kernel virtual addresses are restored and still valid. kmap_atomic() is implemented like a kmap_local_page() which also disables page-faults and preemption (the latter only for !PREEMPT_RT kernels, otherwise it only disables migration). The code within the mappings/un-mappings in getu16_iotlb() and putu16_iotlb() don't depend on the above-mentioned side effects of kmap_atomic(), so that mere replacements of the old API with the new one is all that is required (i.e., there is no need to explicitly add calls to pagefault_disable() and/or preempt_disable()). This commit reuses a "boiler plate" commit message from Fabio, who has already did this change in several places. Cc: "Fabio M. De Francesco" Reviewed-by: Fabio M. De Francesco Acked-by: Jason Wang Signed-off-by: Stefano Garzarella Message-Id: <20230404131326.44403-4-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vringh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index 694462ba3242..a98adc469f19 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -1220,10 +1220,10 @@ static inline int getu16_iotlb(const struct vringh *vrh, if (ret < 0) return ret; - kaddr = kmap_atomic(iov.bv_page); + kaddr = kmap_local_page(iov.bv_page); from = kaddr + iov.bv_offset; *val = vringh16_to_cpu(vrh, READ_ONCE(*(__virtio16 *)from)); - kunmap_atomic(kaddr); + kunmap_local(kaddr); return 0; } @@ -1241,10 +1241,10 @@ static inline int putu16_iotlb(const struct vringh *vrh, if (ret < 0) return ret; - kaddr = kmap_atomic(iov.bv_page); + kaddr = kmap_local_page(iov.bv_page); to = kaddr + iov.bv_offset; WRITE_ONCE(*(__virtio16 *)to, cpu_to_vringh16(vrh, val)); - kunmap_atomic(kaddr); + kunmap_local(kaddr); return 0; } From f609d6cbb36ab1c9c7434f67d555c57a2f7d3dde Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:13:21 +0200 Subject: [PATCH 146/182] vringh: define the stride used for translation Define a macro to be reused in the different parts of the code. Useful for the next patches where we add more arrays to manage also translations with user VA. Suggested-by: Eugenio Perez Martin Signed-off-by: Stefano Garzarella Message-Id: <20230404131326.44403-5-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vringh.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index a98adc469f19..3d5f6bb4ac31 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -1141,13 +1141,15 @@ static int iotlb_translate(const struct vringh *vrh, return ret; } +#define IOTLB_IOV_STRIDE 16 + static inline int copy_from_iotlb(const struct vringh *vrh, void *dst, void *src, size_t len) { u64 total_translated = 0; while (total_translated < len) { - struct bio_vec iov[16]; + struct bio_vec iov[IOTLB_IOV_STRIDE]; struct iov_iter iter; u64 translated; int ret; @@ -1180,7 +1182,7 @@ static inline int copy_to_iotlb(const struct vringh *vrh, void *dst, u64 total_translated = 0; while (total_translated < len) { - struct bio_vec iov[16]; + struct bio_vec iov[IOTLB_IOV_STRIDE]; struct iov_iter iter; u64 translated; int ret; From 42823a871fd4e17b34034f43b36ae57bd2ed8a67 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:17:16 +0200 Subject: [PATCH 147/182] vringh: support VA with iotlb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vDPA supports the possibility to use user VA in the iotlb messages. So, let's add support for user VA in vringh to use it in the vDPA simulators. Acked-by: Eugenio Pérez Signed-off-by: Stefano Garzarella Message-Id: <20230404131716.45855-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vringh.c | 171 +++++++++++++++++++++++++++++++++-------- include/linux/vringh.h | 9 +++ 2 files changed, 148 insertions(+), 32 deletions(-) diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index 3d5f6bb4ac31..955d938eb663 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -1094,10 +1094,17 @@ EXPORT_SYMBOL(vringh_need_notify_kern); #if IS_REACHABLE(CONFIG_VHOST_IOTLB) +struct iotlb_vec { + union { + struct iovec *iovec; + struct bio_vec *bvec; + } iov; + size_t count; +}; + static int iotlb_translate(const struct vringh *vrh, u64 addr, u64 len, u64 *translated, - struct bio_vec iov[], - int iov_size, u32 perm) + struct iotlb_vec *ivec, u32 perm) { struct vhost_iotlb_map *map; struct vhost_iotlb *iotlb = vrh->iotlb; @@ -1107,9 +1114,11 @@ static int iotlb_translate(const struct vringh *vrh, spin_lock(vrh->iotlb_lock); while (len > s) { - u64 size, pa, pfn; + uintptr_t io_addr; + size_t io_len; + u64 size; - if (unlikely(ret >= iov_size)) { + if (unlikely(ret >= ivec->count)) { ret = -ENOBUFS; break; } @@ -1124,10 +1133,22 @@ static int iotlb_translate(const struct vringh *vrh, } size = map->size - addr + map->start; - pa = map->addr + addr - map->start; - pfn = pa >> PAGE_SHIFT; - bvec_set_page(&iov[ret], pfn_to_page(pfn), min(len - s, size), - pa & (PAGE_SIZE - 1)); + io_len = min(len - s, size); + io_addr = map->addr - map->start + addr; + + if (vrh->use_va) { + struct iovec *iovec = ivec->iov.iovec; + + iovec[ret].iov_len = io_len; + iovec[ret].iov_base = (void __user *)io_addr; + } else { + u64 pfn = io_addr >> PAGE_SHIFT; + struct bio_vec *bvec = ivec->iov.bvec; + + bvec_set_page(&bvec[ret], pfn_to_page(pfn), io_len, + io_addr & (PAGE_SIZE - 1)); + } + s += size; addr += size; ++ret; @@ -1146,23 +1167,36 @@ static int iotlb_translate(const struct vringh *vrh, static inline int copy_from_iotlb(const struct vringh *vrh, void *dst, void *src, size_t len) { + struct iotlb_vec ivec; + union { + struct iovec iovec[IOTLB_IOV_STRIDE]; + struct bio_vec bvec[IOTLB_IOV_STRIDE]; + } iov; u64 total_translated = 0; + ivec.iov.iovec = iov.iovec; + ivec.count = IOTLB_IOV_STRIDE; + while (total_translated < len) { - struct bio_vec iov[IOTLB_IOV_STRIDE]; struct iov_iter iter; u64 translated; int ret; ret = iotlb_translate(vrh, (u64)(uintptr_t)src, len - total_translated, &translated, - iov, ARRAY_SIZE(iov), VHOST_MAP_RO); + &ivec, VHOST_MAP_RO); if (ret == -ENOBUFS) - ret = ARRAY_SIZE(iov); + ret = IOTLB_IOV_STRIDE; else if (ret < 0) return ret; - iov_iter_bvec(&iter, ITER_SOURCE, iov, ret, translated); + if (vrh->use_va) { + iov_iter_init(&iter, ITER_SOURCE, ivec.iov.iovec, ret, + translated); + } else { + iov_iter_bvec(&iter, ITER_SOURCE, ivec.iov.bvec, ret, + translated); + } ret = copy_from_iter(dst, translated, &iter); if (ret < 0) @@ -1179,23 +1213,36 @@ static inline int copy_from_iotlb(const struct vringh *vrh, void *dst, static inline int copy_to_iotlb(const struct vringh *vrh, void *dst, void *src, size_t len) { + struct iotlb_vec ivec; + union { + struct iovec iovec[IOTLB_IOV_STRIDE]; + struct bio_vec bvec[IOTLB_IOV_STRIDE]; + } iov; u64 total_translated = 0; + ivec.iov.iovec = iov.iovec; + ivec.count = IOTLB_IOV_STRIDE; + while (total_translated < len) { - struct bio_vec iov[IOTLB_IOV_STRIDE]; struct iov_iter iter; u64 translated; int ret; ret = iotlb_translate(vrh, (u64)(uintptr_t)dst, len - total_translated, &translated, - iov, ARRAY_SIZE(iov), VHOST_MAP_WO); + &ivec, VHOST_MAP_WO); if (ret == -ENOBUFS) - ret = ARRAY_SIZE(iov); + ret = IOTLB_IOV_STRIDE; else if (ret < 0) return ret; - iov_iter_bvec(&iter, ITER_DEST, iov, ret, translated); + if (vrh->use_va) { + iov_iter_init(&iter, ITER_DEST, ivec.iov.iovec, ret, + translated); + } else { + iov_iter_bvec(&iter, ITER_DEST, ivec.iov.bvec, ret, + translated); + } ret = copy_to_iter(src, translated, &iter); if (ret < 0) @@ -1212,20 +1259,36 @@ static inline int copy_to_iotlb(const struct vringh *vrh, void *dst, static inline int getu16_iotlb(const struct vringh *vrh, u16 *val, const __virtio16 *p) { - struct bio_vec iov; - void *kaddr, *from; + struct iotlb_vec ivec; + union { + struct iovec iovec[1]; + struct bio_vec bvec[1]; + } iov; + __virtio16 tmp; int ret; + ivec.iov.iovec = iov.iovec; + ivec.count = 1; + /* Atomic read is needed for getu16 */ - ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), NULL, - &iov, 1, VHOST_MAP_RO); + ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), + NULL, &ivec, VHOST_MAP_RO); if (ret < 0) return ret; - kaddr = kmap_local_page(iov.bv_page); - from = kaddr + iov.bv_offset; - *val = vringh16_to_cpu(vrh, READ_ONCE(*(__virtio16 *)from)); - kunmap_local(kaddr); + if (vrh->use_va) { + ret = __get_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base); + if (ret) + return ret; + } else { + void *kaddr = kmap_local_page(ivec.iov.bvec[0].bv_page); + void *from = kaddr + ivec.iov.bvec[0].bv_offset; + + tmp = READ_ONCE(*(__virtio16 *)from); + kunmap_local(kaddr); + } + + *val = vringh16_to_cpu(vrh, tmp); return 0; } @@ -1233,20 +1296,36 @@ static inline int getu16_iotlb(const struct vringh *vrh, static inline int putu16_iotlb(const struct vringh *vrh, __virtio16 *p, u16 val) { - struct bio_vec iov; - void *kaddr, *to; + struct iotlb_vec ivec; + union { + struct iovec iovec; + struct bio_vec bvec; + } iov; + __virtio16 tmp; int ret; + ivec.iov.iovec = &iov.iovec; + ivec.count = 1; + /* Atomic write is needed for putu16 */ - ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), NULL, - &iov, 1, VHOST_MAP_WO); + ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), + NULL, &ivec, VHOST_MAP_RO); if (ret < 0) return ret; - kaddr = kmap_local_page(iov.bv_page); - to = kaddr + iov.bv_offset; - WRITE_ONCE(*(__virtio16 *)to, cpu_to_vringh16(vrh, val)); - kunmap_local(kaddr); + tmp = cpu_to_vringh16(vrh, val); + + if (vrh->use_va) { + ret = __put_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base); + if (ret) + return ret; + } else { + void *kaddr = kmap_local_page(ivec.iov.bvec[0].bv_page); + void *to = kaddr + ivec.iov.bvec[0].bv_offset; + + WRITE_ONCE(*(__virtio16 *)to, tmp); + kunmap_local(kaddr); + } return 0; } @@ -1320,11 +1399,39 @@ int vringh_init_iotlb(struct vringh *vrh, u64 features, struct vring_avail *avail, struct vring_used *used) { + vrh->use_va = false; + return vringh_init_kern(vrh, features, num, weak_barriers, desc, avail, used); } EXPORT_SYMBOL(vringh_init_iotlb); +/** + * vringh_init_iotlb_va - initialize a vringh for a ring with IOTLB containing + * user VA. + * @vrh: the vringh to initialize. + * @features: the feature bits for this ring. + * @num: the number of elements. + * @weak_barriers: true if we only need memory barriers, not I/O. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. + * + * Returns an error if num is invalid. + */ +int vringh_init_iotlb_va(struct vringh *vrh, u64 features, + unsigned int num, bool weak_barriers, + struct vring_desc *desc, + struct vring_avail *avail, + struct vring_used *used) +{ + vrh->use_va = true; + + return vringh_init_kern(vrh, features, num, weak_barriers, + desc, avail, used); +} +EXPORT_SYMBOL(vringh_init_iotlb_va); + /** * vringh_set_iotlb - initialize a vringh for a ring with IOTLB. * @vrh: the vring diff --git a/include/linux/vringh.h b/include/linux/vringh.h index 1991a02c6431..b4edfadf5479 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -32,6 +32,9 @@ struct vringh { /* Can we get away with weak barriers? */ bool weak_barriers; + /* Use user's VA */ + bool use_va; + /* Last available index we saw (ie. where we're up to). */ u16 last_avail_idx; @@ -284,6 +287,12 @@ int vringh_init_iotlb(struct vringh *vrh, u64 features, struct vring_avail *avail, struct vring_used *used); +int vringh_init_iotlb_va(struct vringh *vrh, u64 features, + unsigned int num, bool weak_barriers, + struct vring_desc *desc, + struct vring_avail *avail, + struct vring_used *used); + int vringh_getdesc_iotlb(struct vringh *vrh, struct vringh_kiov *riov, struct vringh_kiov *wiov, From e2a4f808a78646badefcd13a6e995d369898f443 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:17:21 +0200 Subject: [PATCH 148/182] vdpa_sim: make devices agnostic for work management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's move work management inside the vdpa_sim core. This way we can easily change how we manage the works, without having to change the devices each time. Acked-by: Eugenio Pérez Martin Acked-by: Jason Wang Signed-off-by: Stefano Garzarella Message-Id: <20230404131721.45886-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 17 +++++++++++++++-- drivers/vdpa/vdpa_sim/vdpa_sim.h | 3 ++- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 6 ++---- drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 6 ++---- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index eea23c630f7c..2df5227e0b62 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -127,6 +127,13 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim) static const struct vdpa_config_ops vdpasim_config_ops; static const struct vdpa_config_ops vdpasim_batch_config_ops; +static void vdpasim_work_fn(struct work_struct *work) +{ + struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); + + vdpasim->dev_attr.work_fn(vdpasim); +} + struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, const struct vdpa_dev_set_config *config) { @@ -163,7 +170,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, vdpasim = vdpa_to_sim(vdpa); vdpasim->dev_attr = *dev_attr; - INIT_WORK(&vdpasim->work, dev_attr->work_fn); + INIT_WORK(&vdpasim->work, vdpasim_work_fn); spin_lock_init(&vdpasim->lock); spin_lock_init(&vdpasim->iommu_lock); @@ -214,6 +221,12 @@ err_alloc: } EXPORT_SYMBOL_GPL(vdpasim_create); +void vdpasim_schedule_work(struct vdpasim *vdpasim) +{ + schedule_work(&vdpasim->work); +} +EXPORT_SYMBOL_GPL(vdpasim_schedule_work); + static int vdpasim_set_vq_address(struct vdpa_device *vdpa, u16 idx, u64 desc_area, u64 driver_area, u64 device_area) @@ -248,7 +261,7 @@ static void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx) } if (vq->ready) - schedule_work(&vdpasim->work); + vdpasim_schedule_work(vdpasim); } static void vdpasim_set_vq_cb(struct vdpa_device *vdpa, u16 idx, diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index 144858636c10..acee20faaf6a 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -45,7 +45,7 @@ struct vdpasim_dev_attr { u32 ngroups; u32 nas; - work_func_t work_fn; + void (*work_fn)(struct vdpasim *vdpasim); void (*get_config)(struct vdpasim *vdpasim, void *config); void (*set_config)(struct vdpasim *vdpasim, const void *config); int (*get_stats)(struct vdpasim *vdpasim, u16 idx, @@ -78,6 +78,7 @@ struct vdpasim { struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *attr, const struct vdpa_dev_set_config *config); +void vdpasim_schedule_work(struct vdpasim *vdpasim); /* TODO: cross-endian support */ static inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index 5117959bed8a..eb4897c8541e 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -286,9 +285,8 @@ err: return handled; } -static void vdpasim_blk_work(struct work_struct *work) +static void vdpasim_blk_work(struct vdpasim *vdpasim) { - struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); bool reschedule = false; int i; @@ -326,7 +324,7 @@ out: spin_unlock(&vdpasim->lock); if (reschedule) - schedule_work(&vdpasim->work); + vdpasim_schedule_work(vdpasim); } static void vdpasim_blk_get_config(struct vdpasim *vdpasim, void *config) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index dfe2ce341803..30ac41c5827e 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -192,9 +191,8 @@ static void vdpasim_handle_cvq(struct vdpasim *vdpasim) u64_stats_update_end(&net->cq_stats.syncp); } -static void vdpasim_net_work(struct work_struct *work) +static void vdpasim_net_work(struct vdpasim *vdpasim) { - struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); struct vdpasim_virtqueue *txq = &vdpasim->vqs[1]; struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0]; struct vdpasim_net *net = sim_to_net(vdpasim); @@ -260,7 +258,7 @@ static void vdpasim_net_work(struct work_struct *work) vdpasim_net_complete(rxq, write); if (tx_pkts > 4) { - schedule_work(&vdpasim->work); + vdpasim_schedule_work(vdpasim); goto out; } } From 76acfa7bc54f1e3b9dde396e0a3534493419fd6f Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:17:25 +0200 Subject: [PATCH 149/182] vdpa_sim: use kthread worker Let's use our own kthread to run device jobs. This allows us more flexibility, especially we can attach the kthread to the user address space when vDPA uses user's VA. Acked-by: Jason Wang Signed-off-by: Stefano Garzarella Message-Id: <20230404131725.45908-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 19 +++++++++++++------ drivers/vdpa/vdpa_sim/vdpa_sim.h | 3 ++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 2df5227e0b62..bd9f9054de94 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -127,7 +127,7 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim) static const struct vdpa_config_ops vdpasim_config_ops; static const struct vdpa_config_ops vdpasim_batch_config_ops; -static void vdpasim_work_fn(struct work_struct *work) +static void vdpasim_work_fn(struct kthread_work *work) { struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); @@ -170,11 +170,17 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, vdpasim = vdpa_to_sim(vdpa); vdpasim->dev_attr = *dev_attr; - INIT_WORK(&vdpasim->work, vdpasim_work_fn); + dev = &vdpasim->vdpa.dev; + + kthread_init_work(&vdpasim->work, vdpasim_work_fn); + vdpasim->worker = kthread_create_worker(0, "vDPA sim worker: %s", + dev_attr->name); + if (IS_ERR(vdpasim->worker)) + goto err_iommu; + spin_lock_init(&vdpasim->lock); spin_lock_init(&vdpasim->iommu_lock); - dev = &vdpasim->vdpa.dev; dev->dma_mask = &dev->coherent_dma_mask; if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) goto err_iommu; @@ -223,7 +229,7 @@ EXPORT_SYMBOL_GPL(vdpasim_create); void vdpasim_schedule_work(struct vdpasim *vdpasim) { - schedule_work(&vdpasim->work); + kthread_queue_work(vdpasim->worker, &vdpasim->work); } EXPORT_SYMBOL_GPL(vdpasim_schedule_work); @@ -623,7 +629,8 @@ static void vdpasim_free(struct vdpa_device *vdpa) struct vdpasim *vdpasim = vdpa_to_sim(vdpa); int i; - cancel_work_sync(&vdpasim->work); + kthread_cancel_work_sync(&vdpasim->work); + kthread_destroy_worker(vdpasim->worker); for (i = 0; i < vdpasim->dev_attr.nvqs; i++) { vringh_kiov_cleanup(&vdpasim->vqs[i].out_iov); diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index acee20faaf6a..ce83f9130a5d 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -57,7 +57,8 @@ struct vdpasim_dev_attr { struct vdpasim { struct vdpa_device vdpa; struct vdpasim_virtqueue *vqs; - struct work_struct work; + struct kthread_worker *worker; + struct kthread_work work; struct vdpasim_dev_attr dev_attr; /* spinlock to synchronize virtqueue state */ spinlock_t lock; From d7621c28fca1c16f9e94245479792024a5676c50 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:17:29 +0200 Subject: [PATCH 150/182] vdpa_sim: replace the spinlock with a mutex to protect the state The spinlock we use to protect the state of the simulator is sometimes held for a long time (for example, when devices handle requests). This also prevents us from calling functions that might sleep (such as kthread_flush_work() in the next patch), and thus having to release and retake the lock. For these reasons, let's replace the spinlock with a mutex that gives us more flexibility. Suggested-by: Jason Wang Acked-by: Jason Wang Signed-off-by: Stefano Garzarella Message-Id: <20230404131730.45920-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 34 ++++++++++++++-------------- drivers/vdpa/vdpa_sim/vdpa_sim.h | 4 ++-- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 4 ++-- drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 4 ++-- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index bd9f9054de94..2b2e439a66f7 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -178,7 +178,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, if (IS_ERR(vdpasim->worker)) goto err_iommu; - spin_lock_init(&vdpasim->lock); + mutex_init(&vdpasim->mutex); spin_lock_init(&vdpasim->iommu_lock); dev->dma_mask = &dev->coherent_dma_mask; @@ -286,13 +286,13 @@ static void vdpasim_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready) struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; bool old_ready; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); old_ready = vq->ready; vq->ready = ready; if (vq->ready && !old_ready) { vdpasim_queue_ready(vdpasim, idx); } - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); } static bool vdpasim_get_vq_ready(struct vdpa_device *vdpa, u16 idx) @@ -310,9 +310,9 @@ static int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx, struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; struct vringh *vrh = &vq->vring; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vrh->last_avail_idx = state->split.avail_index; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -409,9 +409,9 @@ static u8 vdpasim_get_status(struct vdpa_device *vdpa) struct vdpasim *vdpasim = vdpa_to_sim(vdpa); u8 status; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); status = vdpasim->status; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return status; } @@ -420,19 +420,19 @@ static void vdpasim_set_status(struct vdpa_device *vdpa, u8 status) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->status = status; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); } static int vdpasim_reset(struct vdpa_device *vdpa) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->status = 0; vdpasim_do_reset(vdpasim); - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -441,9 +441,9 @@ static int vdpasim_suspend(struct vdpa_device *vdpa) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->running = false; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -453,7 +453,7 @@ static int vdpasim_resume(struct vdpa_device *vdpa) struct vdpasim *vdpasim = vdpa_to_sim(vdpa); int i; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->running = true; if (vdpasim->pending_kick) { @@ -464,7 +464,7 @@ static int vdpasim_resume(struct vdpa_device *vdpa) vdpasim->pending_kick = false; } - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -536,14 +536,14 @@ static int vdpasim_set_group_asid(struct vdpa_device *vdpa, unsigned int group, iommu = &vdpasim->iommu[asid]; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); for (i = 0; i < vdpasim->dev_attr.nvqs; i++) if (vdpasim_get_vq_group(vdpa, i) == group) vringh_set_iotlb(&vdpasim->vqs[i].vring, iommu, &vdpasim->iommu_lock); - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index ce83f9130a5d..4774292fba8c 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -60,8 +60,8 @@ struct vdpasim { struct kthread_worker *worker; struct kthread_work work; struct vdpasim_dev_attr dev_attr; - /* spinlock to synchronize virtqueue state */ - spinlock_t lock; + /* mutex to synchronize virtqueue state */ + struct mutex mutex; /* virtio config according to device type */ void *config; struct vhost_iotlb *iommu; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index eb4897c8541e..568119e1553f 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -290,7 +290,7 @@ static void vdpasim_blk_work(struct vdpasim *vdpasim) bool reschedule = false; int i; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) goto out; @@ -321,7 +321,7 @@ static void vdpasim_blk_work(struct vdpasim *vdpasim) } } out: - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); if (reschedule) vdpasim_schedule_work(vdpasim); diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index 30ac41c5827e..55920502f76b 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -201,7 +201,7 @@ static void vdpasim_net_work(struct vdpasim *vdpasim) u64 rx_drops = 0, rx_overruns = 0, rx_errors = 0, tx_errors = 0; int err; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); if (!vdpasim->running) goto out; @@ -264,7 +264,7 @@ static void vdpasim_net_work(struct vdpasim *vdpasim) } out: - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); u64_stats_update_begin(&net->tx_stats.syncp); net->tx_stats.pkts += tx_pkts; From 4bb94d2de2fa90aa8d4e1ce940b1b2f7708cf141 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 4 Apr 2023 15:17:34 +0200 Subject: [PATCH 151/182] vdpa_sim: add support for user VA The new "use_va" module parameter (default: true) is used in vdpa_alloc_device() to inform the vDPA framework that the device supports VA. vringh is initialized to use VA only when "use_va" is true and the user's mm has been bound. So, only when the bus supports user VA (e.g. vhost-vdpa). vdpasim_mm_work_fn work is used to serialize the binding to a new address space when the .bind_mm callback is invoked, and unbinding when the .unbind_mm callback is invoked. Call mmget_not_zero()/kthread_use_mm() inside the worker function to pin the address space only as long as needed, following the documentation of mmget() in include/linux/sched/mm.h: * Never use this function to pin this address space for an * unbounded/indefinite amount of time. Acked-by: Jason Wang Signed-off-by: Stefano Garzarella Message-Id: <20230404131734.45943-1-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 95 +++++++++++++++++++++++++++++--- drivers/vdpa/vdpa_sim/vdpa_sim.h | 1 + 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 2b2e439a66f7..2c706bb18897 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -35,10 +35,44 @@ module_param(max_iotlb_entries, int, 0444); MODULE_PARM_DESC(max_iotlb_entries, "Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)"); +static bool use_va = true; +module_param(use_va, bool, 0444); +MODULE_PARM_DESC(use_va, "Enable/disable the device's ability to use VA"); + #define VDPASIM_QUEUE_ALIGN PAGE_SIZE #define VDPASIM_QUEUE_MAX 256 #define VDPASIM_VENDOR_ID 0 +struct vdpasim_mm_work { + struct kthread_work work; + struct vdpasim *vdpasim; + struct mm_struct *mm_to_bind; + int ret; +}; + +static void vdpasim_mm_work_fn(struct kthread_work *work) +{ + struct vdpasim_mm_work *mm_work = + container_of(work, struct vdpasim_mm_work, work); + struct vdpasim *vdpasim = mm_work->vdpasim; + + mm_work->ret = 0; + + //TODO: should we attach the cgroup of the mm owner? + vdpasim->mm_bound = mm_work->mm_to_bind; +} + +static void vdpasim_worker_change_mm_sync(struct vdpasim *vdpasim, + struct vdpasim_mm_work *mm_work) +{ + struct kthread_work *work = &mm_work->work; + + kthread_init_work(work, vdpasim_mm_work_fn); + kthread_queue_work(vdpasim->worker, work); + + kthread_flush_work(work); +} + static struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa) { return container_of(vdpa, struct vdpasim, vdpa); @@ -59,13 +93,20 @@ static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx) { struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; uint16_t last_avail_idx = vq->vring.last_avail_idx; + struct vring_desc *desc = (struct vring_desc *) + (uintptr_t)vq->desc_addr; + struct vring_avail *avail = (struct vring_avail *) + (uintptr_t)vq->driver_addr; + struct vring_used *used = (struct vring_used *) + (uintptr_t)vq->device_addr; - vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, true, - (struct vring_desc *)(uintptr_t)vq->desc_addr, - (struct vring_avail *) - (uintptr_t)vq->driver_addr, - (struct vring_used *) - (uintptr_t)vq->device_addr); + if (use_va && vdpasim->mm_bound) { + vringh_init_iotlb_va(&vq->vring, vdpasim->features, vq->num, + true, desc, avail, used); + } else { + vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, + true, desc, avail, used); + } vq->vring.last_avail_idx = last_avail_idx; @@ -130,8 +171,20 @@ static const struct vdpa_config_ops vdpasim_batch_config_ops; static void vdpasim_work_fn(struct kthread_work *work) { struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); + struct mm_struct *mm = vdpasim->mm_bound; + + if (use_va && mm) { + if (!mmget_not_zero(mm)) + return; + kthread_use_mm(mm); + } vdpasim->dev_attr.work_fn(vdpasim); + + if (use_va && mm) { + kthread_unuse_mm(mm); + mmput(mm); + } } struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, @@ -162,7 +215,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, vdpa = __vdpa_alloc_device(NULL, ops, dev_attr->ngroups, dev_attr->nas, dev_attr->alloc_size, - dev_attr->name, false); + dev_attr->name, use_va); if (IS_ERR(vdpa)) { ret = PTR_ERR(vdpa); goto err_alloc; @@ -582,6 +635,30 @@ err: return ret; } +static int vdpasim_bind_mm(struct vdpa_device *vdpa, struct mm_struct *mm) +{ + struct vdpasim *vdpasim = vdpa_to_sim(vdpa); + struct vdpasim_mm_work mm_work; + + mm_work.vdpasim = vdpasim; + mm_work.mm_to_bind = mm; + + vdpasim_worker_change_mm_sync(vdpasim, &mm_work); + + return mm_work.ret; +} + +static void vdpasim_unbind_mm(struct vdpa_device *vdpa) +{ + struct vdpasim *vdpasim = vdpa_to_sim(vdpa); + struct vdpasim_mm_work mm_work; + + mm_work.vdpasim = vdpasim; + mm_work.mm_to_bind = NULL; + + vdpasim_worker_change_mm_sync(vdpasim, &mm_work); +} + static int vdpasim_dma_map(struct vdpa_device *vdpa, unsigned int asid, u64 iova, u64 size, u64 pa, u32 perm, void *opaque) @@ -678,6 +755,8 @@ static const struct vdpa_config_ops vdpasim_config_ops = { .set_group_asid = vdpasim_set_group_asid, .dma_map = vdpasim_dma_map, .dma_unmap = vdpasim_dma_unmap, + .bind_mm = vdpasim_bind_mm, + .unbind_mm = vdpasim_unbind_mm, .free = vdpasim_free, }; @@ -712,6 +791,8 @@ static const struct vdpa_config_ops vdpasim_batch_config_ops = { .get_iova_range = vdpasim_get_iova_range, .set_group_asid = vdpasim_set_group_asid, .set_map = vdpasim_set_map, + .bind_mm = vdpasim_bind_mm, + .unbind_mm = vdpasim_unbind_mm, .free = vdpasim_free, }; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index 4774292fba8c..3a42887d05d9 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -59,6 +59,7 @@ struct vdpasim { struct vdpasim_virtqueue *vqs; struct kthread_worker *worker; struct kthread_work work; + struct mm_struct *mm_bound; struct vdpasim_dev_attr dev_attr; /* mutex to synchronize virtqueue state */ struct mutex mutex; From 6c0b057cec5eade4c3afec3908821176931a9997 Mon Sep 17 00:00:00 2001 From: Albert Huang Date: Wed, 29 Mar 2023 18:23:00 +0800 Subject: [PATCH 152/182] virtio_ring: don't update event idx on get_buf In virtio_net, if we disable napi_tx, when we trigger a tx interrupt, the vq->event_triggered will be set to true. It is then never reset until we explicitly call virtqueue_enable_cb_delayed or virtqueue_enable_cb_prepare. If we disable the napi_tx, virtqueue_enable_cb* will only be called when the tx ring is getting relatively empty. Since event_triggered is true, VRING_AVAIL_F_NO_INTERRUPT or VRING_PACKED_EVENT_FLAG_DISABLE will not be set. As a result we update vring_used_event(&vq->split.vring) or vq->packed.vring.driver->off_wrap every time we call virtqueue_get_buf_ctx. This causes more interrupts. To summarize: 1) event_triggered was set to true in vring_interrupt() 2) after this nothing will happen in virtqueue_disable_cb() so VRING_AVAIL_F_NO_INTERRUPT is not set in avail_flags_shadow 3) virtqueue_get_buf_ctx_split() will still think the cb is enabled and then it will publish a new event index To fix: update VRING_AVAIL_F_NO_INTERRUPT or VRING_PACKED_EVENT_FLAG_DISABLE in the vq when we call virtqueue_disable_cb even when event_triggered is true. Tested with iperf: iperf3 tcp stream: vm1 -----------------> vm2 vm2 just receives tcp data stream from vm1, and sends acks to vm1, there are many tx interrupts in vm2. with the patch applied there are just a few tx interrupts. v2->v3: -update the interrupt disable flag even with the event_triggered is set, -instead of checking whether event_triggered is set in -virtqueue_get_buf_ctx_{packed/split}, will cause the drivers which have -not called virtqueue_{enable/disable}_cb to miss notifications. v3->v4: -remove change for -"if (vq->packed.event_flags_shadow != VRING_PACKED_EVENT_FLAG_DISABLE)" -in virtqueue_disable_cb_packed Fixes: 8d622d21d248 ("virtio: fix up virtio_disable_cb") Signed-off-by: Albert Huang Signed-off-by: Michael S. Tsirkin Signed-off-by: Jason Wang Message-Id: <20230329102300.61000-1-huangjie.albert@bytedance.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_ring.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 4c3bb0ddeb9b..34e3849629da 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -854,6 +854,14 @@ static void virtqueue_disable_cb_split(struct virtqueue *_vq) if (!(vq->split.avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; + + /* + * If device triggered an event already it won't trigger one again: + * no need to disable. + */ + if (vq->event_triggered) + return; + if (vq->event) /* TODO: this is a hack. Figure out a cleaner value to write. */ vring_used_event(&vq->split.vring) = 0x0; @@ -1699,6 +1707,14 @@ static void virtqueue_disable_cb_packed(struct virtqueue *_vq) if (vq->packed.event_flags_shadow != VRING_PACKED_EVENT_FLAG_DISABLE) { vq->packed.event_flags_shadow = VRING_PACKED_EVENT_FLAG_DISABLE; + + /* + * If device triggered an event already it won't trigger one again: + * no need to disable. + */ + if (vq->event_triggered) + return; + vq->packed.vring.driver->flags = cpu_to_le16(vq->packed.event_flags_shadow); } @@ -2330,12 +2346,6 @@ void virtqueue_disable_cb(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); - /* If device triggered an event already it won't trigger one again: - * no need to disable. - */ - if (vq->event_triggered) - return; - if (vq->packed_ring) virtqueue_disable_cb_packed(_vq); else From 9be5d2d424a19a0c6d643a1baecba3d58e725012 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 31 Mar 2023 10:56:55 +0200 Subject: [PATCH 153/182] vdpa: address kdoc warnings This patch addresses the following minor kdoc problems. * Incorrect spelling of 'callback' and 'notification' * Unrecognised kdoc format for 'struct vdpa_map_file' * Missing documentation of 'get_vendor_vq_stats' member of 'struct vdpa_config_ops' * Missing documentation of 'max_supported_vqs' and 'supported_features' members of 'struct vdpa_mgmt_dev' Most of these problems were flagged by: $ ./scripts/kernel-doc -Werror -none include/linux/vdpa.h include/linux/vdpa.h:20: warning: expecting prototype for struct vdpa_calllback. Prototype was for struct vdpa_callback instead include/linux/vdpa.h:117: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Corresponding file area for device memory mapping include/linux/vdpa.h:357: warning: Function parameter or member 'get_vendor_vq_stats' not described in 'vdpa_config_ops' include/linux/vdpa.h:518: warning: Function parameter or member 'supported_features' not described in 'vdpa_mgmt_dev' include/linux/vdpa.h:518: warning: Function parameter or member 'max_supported_vqs' not described in 'vdpa_mgmt_dev' The misspelling of 'notification' was flagged by: $ ./scripts/checkpatch.pl --codespell --showfile --strict -f include/linux/vdpa.h include/linux/vdpa.h:171: CHECK: 'notifcation' may be misspelled - perhaps 'notification'? ... Signed-off-by: Simon Horman Message-Id: <20230331-vhost-fixes-v1-1-1f046e735b9e@kernel.org> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- include/linux/vdpa.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index 2f1af73b3a1a..c0d3f5433af7 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -10,7 +10,7 @@ #include /** - * struct vdpa_calllback - vDPA callback definition. + * struct vdpa_callback - vDPA callback definition. * @callback: interrupt callback function * @private: the data passed to the callback function * @trigger: the eventfd for the callback (Optional). @@ -120,7 +120,7 @@ struct vdpa_dev_set_config { }; /** - * Corresponding file area for device memory mapping + * struct vdpa_map_file - file area for device memory mapping * @file: vma->vm_file for the mapping * @offset: mapping offset in the vm_file */ @@ -171,10 +171,16 @@ struct vdpa_map_file { * @vdev: vdpa device * @idx: virtqueue index * @state: pointer to returned state (last_avail_idx) + * @get_vendor_vq_stats: Get the vendor statistics of a device. + * @vdev: vdpa device + * @idx: virtqueue index + * @msg: socket buffer holding stats message + * @extack: extack for reporting error messages + * Returns integer: success (0) or error (< 0) * @get_vq_notification: Get the notification area for a virtqueue (optional) * @vdev: vdpa device * @idx: virtqueue index - * Returns the notifcation area + * Returns the notification area * @get_vq_irq: Get the irq number of a virtqueue (optional, * but must implemented if require vq irq offloading) * @vdev: vdpa device @@ -535,6 +541,8 @@ struct vdpa_mgmtdev_ops { * @config_attr_mask: bit mask of attributes of type enum vdpa_attr that * management device support during dev_add callback * @list: list entry + * @supported_features: features supported by device + * @max_supported_vqs: maximum number of virtqueues supported by device */ struct vdpa_mgmt_dev { struct device *device; From b2ffaa672edaf1a681537a9f47bc14ab6c9e8845 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 31 Mar 2023 10:56:56 +0200 Subject: [PATCH 154/182] vringh: address kdoc warnings Address some minor kdoc warnings in vring.h. * Place kdoc for 'struct vringh_config_ops' immediately before the structure * Add missing documentation of members of 'vringh_iov' and 'vringh_kiov' Warnings flagged by: $ ./scripts/kernel-doc -none include/linux/vringh.h include/linux/vringh.h:68: error: Cannot parse struct or union! include/linux/vringh.h:92: warning: Function parameter or member 'iov' not described in 'vringh_iov' include/linux/vringh.h:92: warning: Function parameter or member 'consumed' not described in 'vringh_iov' include/linux/vringh.h:92: warning: Function parameter or member 'i' not described in 'vringh_iov' include/linux/vringh.h:92: warning: Function parameter or member 'used' not described in 'vringh_iov' include/linux/vringh.h:92: warning: Function parameter or member 'max_num' not described in 'vringh_iov' include/linux/vringh.h:104: warning: Function parameter or member 'iov' not described in 'vringh_kiov' include/linux/vringh.h:104: warning: Function parameter or member 'consumed' not described in 'vringh_kiov' include/linux/vringh.h:104: warning: Function parameter or member 'i' not described in 'vringh_kiov' include/linux/vringh.h:104: warning: Function parameter or member 'used' not described in 'vringh_kiov' include/linux/vringh.h:104: warning: Function parameter or member 'max_num' not described in 'vringh_kiov' Signed-off-by: Simon Horman Message-Id: <20230331-vhost-fixes-v1-2-1f046e735b9e@kernel.org> Signed-off-by: Michael S. Tsirkin --- include/linux/vringh.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/linux/vringh.h b/include/linux/vringh.h index b4edfadf5479..c3a8117dabe8 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -57,6 +57,9 @@ struct vringh { void (*notify)(struct vringh *); }; +struct virtio_device; +typedef void vrh_callback_t(struct virtio_device *, struct vringh *); + /** * struct vringh_config_ops - ops for creating a host vring from a virtio driver * @find_vrhs: find the host vrings and instantiate them @@ -68,8 +71,6 @@ struct vringh { * Returns 0 on success or error status * @del_vrhs: free the host vrings found by find_vrhs(). */ -struct virtio_device; -typedef void vrh_callback_t(struct virtio_device *, struct vringh *); struct vringh_config_ops { int (*find_vrhs)(struct virtio_device *vdev, unsigned nhvrs, struct vringh *vrhs[], vrh_callback_t *callbacks[]); @@ -84,6 +85,12 @@ struct vringh_range { /** * struct vringh_iov - iovec mangler. + * @iov: array of iovecs to operate on + * @consumed: number of bytes consumed within iov[i] + * @i: index of current iovec + * @used: number of iovecs present in @iov + * @max_num: maximum number of iovecs. + * corresponds to allocated memory of @iov * * Mangles iovec in place, and restores it. * Remaining data is iov + i, of used - i elements. @@ -96,6 +103,12 @@ struct vringh_iov { /** * struct vringh_kiov - kvec mangler. + * @iov: array of iovecs to operate on + * @consumed: number of bytes consumed within iov[i] + * @i: index of current iovec + * @used: number of iovecs present in @iov + * @max_num: maximum number of iovecs. + * corresponds to allocated memory of @iov * * Mangles kvec in place, and restores it. * Remaining data is iov + i, of used - i elements. From 4a536d881a661c7ff7d241c537ee511106d88163 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 31 Mar 2023 10:56:57 +0200 Subject: [PATCH 155/182] MAINTAINERS: add vringh.h to Virtio Core and Net Drivers vringh.h doesn't seem to belong to any section in MAINTAINERS. Add it to Virtio Core and Net Drivers, which seems to be the most appropriate section to me. Signed-off-by: Simon Horman Message-Id: <20230331-vhost-fixes-v1-3-1f046e735b9e@kernel.org> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0e64787aace8..a8df70387877 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22077,6 +22077,7 @@ F: drivers/vdpa/ F: drivers/virtio/ F: include/linux/vdpa.h F: include/linux/virtio*.h +F: include/linux/vringh.h F: include/uapi/linux/virtio_*.h F: tools/virtio/ From 3f3a1675b731e532d479e65570f2904878fbd9f0 Mon Sep 17 00:00:00 2001 From: Alvaro Karsz Date: Thu, 13 Apr 2023 10:33:36 +0300 Subject: [PATCH 156/182] vdpa/snet: support getting and setting VQ state This patch adds the get_vq_state and set_vq_state vDPA callbacks. In order to get the VQ state, the state needs to be read from the DPU. In order to allow that, the old messaging mechanism is replaced with a new, flexible control mechanism. This mechanism allows to read data from the DPU. The mechanism can be used if the negotiated config version is 2 or higher. If the new mechanism is used when the config version is 1, it will call snet_send_ctrl_msg_old, which is config 1 compatible. Signed-off-by: Alvaro Karsz Message-Id: <20230413073337.31367-2-alvaro.karsz@solid-run.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vdpa/solidrun/Makefile | 1 + drivers/vdpa/solidrun/snet_ctrl.c | 324 +++++++++++++++++++++++++++++ drivers/vdpa/solidrun/snet_hwmon.c | 2 +- drivers/vdpa/solidrun/snet_main.c | 112 ++++------ drivers/vdpa/solidrun/snet_vdpa.h | 19 +- 5 files changed, 387 insertions(+), 71 deletions(-) create mode 100644 drivers/vdpa/solidrun/snet_ctrl.c diff --git a/drivers/vdpa/solidrun/Makefile b/drivers/vdpa/solidrun/Makefile index c0aa3415bf7b..9116252cd5fa 100644 --- a/drivers/vdpa/solidrun/Makefile +++ b/drivers/vdpa/solidrun/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SNET_VDPA) += snet_vdpa.o snet_vdpa-$(CONFIG_SNET_VDPA) += snet_main.o +snet_vdpa-$(CONFIG_SNET_VDPA) += snet_ctrl.o ifdef CONFIG_HWMON snet_vdpa-$(CONFIG_SNET_VDPA) += snet_hwmon.o endif diff --git a/drivers/vdpa/solidrun/snet_ctrl.c b/drivers/vdpa/solidrun/snet_ctrl.c new file mode 100644 index 000000000000..10cde502f1a9 --- /dev/null +++ b/drivers/vdpa/solidrun/snet_ctrl.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SolidRun DPU driver for control plane + * + * Copyright (C) 2022-2023 SolidRun + * + * Author: Alvaro Karsz + * + */ + +#include + +#include "snet_vdpa.h" + +enum snet_ctrl_opcodes { + SNET_CTRL_OP_DESTROY = 1, + SNET_CTRL_OP_READ_VQ_STATE, +}; + +#define SNET_CTRL_TIMEOUT 2000000 + +#define SNET_CTRL_DATA_SIZE_MASK 0x0000FFFF +#define SNET_CTRL_IN_PROCESS_MASK 0x00010000 +#define SNET_CTRL_CHUNK_RDY_MASK 0x00020000 +#define SNET_CTRL_ERROR_MASK 0x0FFC0000 + +#define SNET_VAL_TO_ERR(val) (-(((val) & SNET_CTRL_ERROR_MASK) >> 18)) +#define SNET_EMPTY_CTRL(val) (((val) & SNET_CTRL_ERROR_MASK) || \ + !((val) & SNET_CTRL_IN_PROCESS_MASK)) +#define SNET_DATA_READY(val) ((val) & (SNET_CTRL_ERROR_MASK | SNET_CTRL_CHUNK_RDY_MASK)) + +/* Control register used to read data from the DPU */ +struct snet_ctrl_reg_ctrl { + /* Chunk size in 4B words */ + u16 data_size; + /* We are in the middle of a command */ + u16 in_process:1; + /* A data chunk is ready and can be consumed */ + u16 chunk_ready:1; + /* Error code */ + u16 error:10; + /* Saved for future usage */ + u16 rsvd:4; +}; + +/* Opcode register */ +struct snet_ctrl_reg_op { + u16 opcode; + /* Only if VQ index is relevant for the command */ + u16 vq_idx; +}; + +struct snet_ctrl_regs { + struct snet_ctrl_reg_op op; + struct snet_ctrl_reg_ctrl ctrl; + u32 rsvd; + u32 data[]; +}; + +static struct snet_ctrl_regs __iomem *snet_get_ctrl(struct snet *snet) +{ + return snet->bar + snet->psnet->cfg.ctrl_off; +} + +static int snet_wait_for_empty_ctrl(struct snet_ctrl_regs __iomem *regs) +{ + u32 val; + + return readx_poll_timeout(ioread32, ®s->ctrl, val, SNET_EMPTY_CTRL(val), 10, + SNET_CTRL_TIMEOUT); +} + +static int snet_wait_for_empty_op(struct snet_ctrl_regs __iomem *regs) +{ + u32 val; + + return readx_poll_timeout(ioread32, ®s->op, val, !val, 10, SNET_CTRL_TIMEOUT); +} + +static int snet_wait_for_data(struct snet_ctrl_regs __iomem *regs) +{ + u32 val; + + return readx_poll_timeout(ioread32, ®s->ctrl, val, SNET_DATA_READY(val), 10, + SNET_CTRL_TIMEOUT); +} + +static u32 snet_read32_word(struct snet_ctrl_regs __iomem *ctrl_regs, u16 word_idx) +{ + return ioread32(&ctrl_regs->data[word_idx]); +} + +static u32 snet_read_ctrl(struct snet_ctrl_regs __iomem *ctrl_regs) +{ + return ioread32(&ctrl_regs->ctrl); +} + +static void snet_write_ctrl(struct snet_ctrl_regs __iomem *ctrl_regs, u32 val) +{ + iowrite32(val, &ctrl_regs->ctrl); +} + +static void snet_write_op(struct snet_ctrl_regs __iomem *ctrl_regs, u32 val) +{ + iowrite32(val, &ctrl_regs->op); +} + +static int snet_wait_for_dpu_completion(struct snet_ctrl_regs __iomem *ctrl_regs) +{ + /* Wait until the DPU finishes completely. + * It will clear the opcode register. + */ + return snet_wait_for_empty_op(ctrl_regs); +} + +/* Reading ctrl from the DPU: + * buf_size must be 4B aligned + * + * Steps: + * + * (1) Verify that the DPU is not in the middle of another operation by + * reading the in_process and error bits in the control register. + * (2) Write the request opcode and the VQ idx in the opcode register + * and write the buffer size in the control register. + * (3) Start readind chunks of data, chunk_ready bit indicates that a + * data chunk is available, we signal that we read the data by clearing the bit. + * (4) Detect that the transfer is completed when the in_process bit + * in the control register is cleared or when the an error appears. + */ +static int snet_ctrl_read_from_dpu(struct snet *snet, u16 opcode, u16 vq_idx, void *buffer, + u32 buf_size) +{ + struct pci_dev *pdev = snet->pdev; + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + u32 *bfr_ptr = (u32 *)buffer; + u32 val; + u16 buf_words; + int ret; + u16 words, i, tot_words = 0; + + /* Supported for config 2+ */ + if (!SNET_CFG_VER(snet, 2)) + return -EOPNOTSUPP; + + if (!IS_ALIGNED(buf_size, 4)) + return -EINVAL; + + mutex_lock(&snet->ctrl_lock); + + buf_words = buf_size / 4; + + /* Make sure control register is empty */ + ret = snet_wait_for_empty_ctrl(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for previous control data to be consumed\n"); + goto exit; + } + + /* We need to write the buffer size in the control register, and the opcode + vq index in + * the opcode register. + * We use a spinlock to serialize the writes. + */ + spin_lock(&snet->ctrl_spinlock); + + snet_write_ctrl(regs, buf_words); + snet_write_op(regs, opcode | (vq_idx << 16)); + + spin_unlock(&snet->ctrl_spinlock); + + while (buf_words != tot_words) { + ret = snet_wait_for_data(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for control data\n"); + goto exit; + } + + val = snet_read_ctrl(regs); + + /* Error? */ + if (val & SNET_CTRL_ERROR_MASK) { + ret = SNET_VAL_TO_ERR(val); + SNET_WARN(pdev, "Error while reading control data from DPU, err %d\n", ret); + goto exit; + } + + words = min_t(u16, val & SNET_CTRL_DATA_SIZE_MASK, buf_words - tot_words); + + for (i = 0; i < words; i++) { + *bfr_ptr = snet_read32_word(regs, i); + bfr_ptr++; + } + + tot_words += words; + + /* Is the job completed? */ + if (!(val & SNET_CTRL_IN_PROCESS_MASK)) + break; + + /* Clear the chunk ready bit and continue */ + val &= ~SNET_CTRL_CHUNK_RDY_MASK; + snet_write_ctrl(regs, val); + } + + ret = snet_wait_for_dpu_completion(regs); + if (ret) + SNET_WARN(pdev, "Timeout waiting for the DPU to complete a control command\n"); + +exit: + mutex_unlock(&snet->ctrl_lock); + return ret; +} + +/* Send a control message to the DPU using the old mechanism + * used with config version 1. + */ +static int snet_send_ctrl_msg_old(struct snet *snet, u32 opcode) +{ + struct pci_dev *pdev = snet->pdev; + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + int ret; + + mutex_lock(&snet->ctrl_lock); + + /* Old mechanism uses just 1 register, the opcode register. + * Make sure that the opcode register is empty, and that the DPU isn't + * processing an old message. + */ + ret = snet_wait_for_empty_op(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for previous control message to be ACKed\n"); + goto exit; + } + + /* Write the message */ + snet_write_op(regs, opcode); + + /* DPU ACKs the message by clearing the opcode register */ + ret = snet_wait_for_empty_op(regs); + if (ret) + SNET_WARN(pdev, "Timeout waiting for a control message to be ACKed\n"); + +exit: + mutex_unlock(&snet->ctrl_lock); + return ret; +} + +/* Send a control message to the DPU. + * A control message is a message without payload. + */ +static int snet_send_ctrl_msg(struct snet *snet, u16 opcode, u16 vq_idx) +{ + struct pci_dev *pdev = snet->pdev; + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + u32 val; + int ret; + + /* If config version is not 2+, use the old mechanism */ + if (!SNET_CFG_VER(snet, 2)) + return snet_send_ctrl_msg_old(snet, opcode); + + mutex_lock(&snet->ctrl_lock); + + /* Make sure control register is empty */ + ret = snet_wait_for_empty_ctrl(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for previous control data to be consumed\n"); + goto exit; + } + + /* We need to clear the control register and write the opcode + vq index in the opcode + * register. + * We use a spinlock to serialize the writes. + */ + spin_lock(&snet->ctrl_spinlock); + + snet_write_ctrl(regs, 0); + snet_write_op(regs, opcode | (vq_idx << 16)); + + spin_unlock(&snet->ctrl_spinlock); + + /* The DPU ACKs control messages by setting the chunk ready bit + * without data. + */ + ret = snet_wait_for_data(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for control message to be ACKed\n"); + goto exit; + } + + /* Check for errors */ + val = snet_read_ctrl(regs); + ret = SNET_VAL_TO_ERR(val); + + /* Clear the chunk ready bit */ + val &= ~SNET_CTRL_CHUNK_RDY_MASK; + snet_write_ctrl(regs, val); + + ret = snet_wait_for_dpu_completion(regs); + if (ret) + SNET_WARN(pdev, "Timeout waiting for DPU to complete a control command, err %d\n", + ret); + +exit: + mutex_unlock(&snet->ctrl_lock); + return ret; +} + +void snet_ctrl_clear(struct snet *snet) +{ + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + + snet_write_op(regs, 0); +} + +int snet_destroy_dev(struct snet *snet) +{ + return snet_send_ctrl_msg(snet, SNET_CTRL_OP_DESTROY, 0); +} + +int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state) +{ + return snet_ctrl_read_from_dpu(snet, SNET_CTRL_OP_READ_VQ_STATE, idx, state, + sizeof(*state)); +} diff --git a/drivers/vdpa/solidrun/snet_hwmon.c b/drivers/vdpa/solidrun/snet_hwmon.c index e695e36ff753..42c87387a0f1 100644 --- a/drivers/vdpa/solidrun/snet_hwmon.c +++ b/drivers/vdpa/solidrun/snet_hwmon.c @@ -2,7 +2,7 @@ /* * SolidRun DPU driver for control plane * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index 68de727398ed..86769f436b4d 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -2,7 +2,7 @@ /* * SolidRun DPU driver for control plane * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * @@ -16,14 +16,12 @@ /* SNET signature */ #define SNET_SIGNATURE 0xD0D06363 /* Max. config version that we can work with */ -#define SNET_CFG_VERSION 0x1 +#define SNET_CFG_VERSION 0x2 /* Queue align */ #define SNET_QUEUE_ALIGNMENT PAGE_SIZE /* Kick value to notify that new data is available */ #define SNET_KICK_VAL 0x1 #define SNET_CONFIG_OFF 0x0 -/* ACK timeout for a message */ -#define SNET_ACK_TIMEOUT 2000000 /* How long we are willing to wait for a SNET device */ #define SNET_DETECT_TIMEOUT 5000000 /* How long should we wait for the DPU to read our config */ @@ -32,56 +30,11 @@ #define SNET_GENERAL_CFG_LEN 36 #define SNET_GENERAL_CFG_VQ_LEN 40 -enum snet_msg { - SNET_MSG_DESTROY = 1, -}; - static struct snet *vdpa_to_snet(struct vdpa_device *vdpa) { return container_of(vdpa, struct snet, vdpa); } -static int snet_wait_for_msg_ack(struct snet *snet) -{ - struct pci_dev *pdev = snet->pdev; - int ret; - u32 val; - - /* The DPU will clear the messages offset once messages - * are processed. - */ - ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.msg_off, - val, !val, 10, SNET_ACK_TIMEOUT); - if (ret) - SNET_WARN(pdev, "Timeout waiting for message ACK\n"); - - return ret; -} - -/* Sends a message to the DPU. - * If blocking is set, the function will return once the - * message was processed by the DPU (or timeout). - */ -static int snet_send_msg(struct snet *snet, u32 msg, bool blocking) -{ - int ret = 0; - - /* Make sure the DPU acked last message before issuing a new one */ - ret = snet_wait_for_msg_ack(snet); - if (ret) - return ret; - - /* Write the message */ - snet_write32(snet, snet->psnet->cfg.msg_off, msg); - - if (blocking) - ret = snet_wait_for_msg_ack(snet); - else /* If non-blocking, flush the write by issuing a read */ - snet_read32(snet, snet->psnet->cfg.msg_off); - - return ret; -} - static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data) { struct snet *snet = data; @@ -181,33 +134,48 @@ static bool snet_get_vq_ready(struct vdpa_device *vdev, u16 idx) return snet->vqs[idx]->ready; } -static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state) +static bool snet_vq_state_is_initial(struct snet *snet, const struct vdpa_vq_state *state) { - struct snet *snet = vdpa_to_snet(vdev); - /* Setting the VQ state is not supported. - * If the asked state is the same as the initial one - * we can ignore it. - */ if (SNET_HAS_FEATURE(snet, VIRTIO_F_RING_PACKED)) { const struct vdpa_vq_state_packed *p = &state->packed; if (p->last_avail_counter == 1 && p->last_used_counter == 1 && p->last_avail_idx == 0 && p->last_used_idx == 0) - return 0; + return true; } else { const struct vdpa_vq_state_split *s = &state->split; if (s->avail_index == 0) - return 0; + return true; } + return false; +} + +static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state) +{ + struct snet *snet = vdpa_to_snet(vdev); + + /* We can set any state for config version 2+ */ + if (SNET_CFG_VER(snet, 2)) { + memcpy(&snet->vqs[idx]->vq_state, state, sizeof(*state)); + return 0; + } + + /* Older config - we can't set the VQ state. + * Return 0 only if this is the initial state we use in the DPU. + */ + if (snet_vq_state_is_initial(snet, state)) + return 0; + return -EOPNOTSUPP; } static int snet_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state) { - /* Not supported */ - return -EOPNOTSUPP; + struct snet *snet = vdpa_to_snet(vdev); + + return snet_read_vq_state(snet, idx, state); } static int snet_get_vq_irq(struct vdpa_device *vdev, u16 idx) @@ -232,9 +200,9 @@ static int snet_reset_dev(struct snet *snet) if (!snet->status) return 0; - /* If DPU started, send a destroy message */ + /* If DPU started, destroy it */ if (snet->status & VIRTIO_CONFIG_S_DRIVER_OK) - ret = snet_send_msg(snet, SNET_MSG_DESTROY, true); + ret = snet_destroy_dev(snet); /* Clear VQs */ for (i = 0; i < snet->cfg->vq_num; i++) { @@ -258,7 +226,7 @@ static int snet_reset_dev(struct snet *snet) snet->dpu_ready = false; if (ret) - SNET_WARN(pdev, "Incomplete reset to SNET[%u] device\n", snet->sid); + SNET_WARN(pdev, "Incomplete reset to SNET[%u] device, err: %d\n", snet->sid, ret); else SNET_DBG(pdev, "Reset SNET[%u] device\n", snet->sid); @@ -356,7 +324,7 @@ static int snet_write_conf(struct snet *snet) * | DESC AREA | * | DEVICE AREA | * | DRIVER AREA | - * | RESERVED | + * | VQ STATE (CFG 2+) | RSVD | * * Magic number should be written last, this is the DPU indication that the data is ready */ @@ -391,12 +359,15 @@ static int snet_write_conf(struct snet *snet) off += 8; snet_write64(snet, off, snet->vqs[i]->driver_area); off += 8; + /* Write VQ state if config version is 2+ */ + if (SNET_CFG_VER(snet, 2)) + snet_write32(snet, off, *(u32 *)&snet->vqs[i]->vq_state); + off += 4; + /* Ignore reserved */ - off += 8; + off += 4; } - /* Clear snet messages address for this device */ - snet_write32(snet, snet->psnet->cfg.msg_off, 0); /* Write magic number - data is ready */ snet_write32(snet, snet->psnet->cfg.host_cfg_off, SNET_SIGNATURE); @@ -697,7 +668,7 @@ static int psnet_read_cfg(struct pci_dev *pdev, struct psnet *psnet) off += 4; cfg->hwmon_off = psnet_read32(psnet, off); off += 4; - cfg->msg_off = psnet_read32(psnet, off); + cfg->ctrl_off = psnet_read32(psnet, off); off += 4; cfg->flags = psnet_read32(psnet, off); off += 4; @@ -997,6 +968,10 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev) goto free_irqs; } + /* Init control mutex and spinlock */ + mutex_init(&snet->ctrl_lock); + spin_lock_init(&snet->ctrl_spinlock); + /* Save pci device pointer */ snet->pdev = pdev; snet->psnet = psnet; @@ -1013,6 +988,9 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev) /* Create a VirtIO config pointer */ snet->cfg->virtio_cfg = snet->bar + snet->psnet->cfg.virtio_cfg_off; + /* Clear control registers */ + snet_ctrl_clear(snet); + pci_set_master(pdev); pci_set_drvdata(pdev, snet); diff --git a/drivers/vdpa/solidrun/snet_vdpa.h b/drivers/vdpa/solidrun/snet_vdpa.h index b7f34169053f..09ff676e7a2d 100644 --- a/drivers/vdpa/solidrun/snet_vdpa.h +++ b/drivers/vdpa/solidrun/snet_vdpa.h @@ -2,7 +2,7 @@ /* * SolidRun DPU driver for control plane * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * @@ -20,10 +20,15 @@ #define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f)) +/* Check if negotiated config version is at least @ver */ +#define SNET_CFG_VER(snet, ver) ((snet)->psnet->negotiated_cfg_ver >= (ver)) + /* VQ struct */ struct snet_vq { /* VQ callback */ struct vdpa_callback cb; + /* VQ state received from bus */ + struct vdpa_vq_state vq_state; /* desc base address */ u64 desc_area; /* device base address */ @@ -51,6 +56,10 @@ struct snet { struct vdpa_device vdpa; /* Config callback */ struct vdpa_callback cb; + /* To lock the control mechanism */ + struct mutex ctrl_lock; + /* Spinlock to protect critical parts in the control mechanism */ + spinlock_t ctrl_spinlock; /* array of virqueues */ struct snet_vq **vqs; /* Used features */ @@ -117,8 +126,8 @@ struct snet_cfg { u32 kick_off; /* Offset in PCI BAR for HW monitoring */ u32 hwmon_off; - /* Offset in PCI BAR for SNET messages */ - u32 msg_off; + /* Offset in PCI BAR for Control mechanism */ + u32 ctrl_off; /* Config general flags - enum snet_cfg_flags */ u32 flags; /* Reserved for future usage */ @@ -191,4 +200,8 @@ static inline void snet_write64(struct snet *snet, u32 off, u64 val) void psnet_create_hwmon(struct pci_dev *pdev); #endif +void snet_ctrl_clear(struct snet *snet); +int snet_destroy_dev(struct snet *snet); +int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state); + #endif //_SNET_VDPA_H_ From 3616bf377a5a8ef4f124dfde5f3522c4da335561 Mon Sep 17 00:00:00 2001 From: Alvaro Karsz Date: Thu, 13 Apr 2023 10:33:37 +0300 Subject: [PATCH 157/182] vdpa/snet: support the suspend vDPA callback When suspend is called, the driver sends a suspend command to the DPU through the control mechanism. Signed-off-by: Alvaro Karsz Message-Id: <20230413073337.31367-3-alvaro.karsz@solid-run.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vdpa/solidrun/snet_ctrl.c | 6 ++++++ drivers/vdpa/solidrun/snet_main.c | 15 +++++++++++++++ drivers/vdpa/solidrun/snet_vdpa.h | 1 + 3 files changed, 22 insertions(+) diff --git a/drivers/vdpa/solidrun/snet_ctrl.c b/drivers/vdpa/solidrun/snet_ctrl.c index 10cde502f1a9..3858738643b4 100644 --- a/drivers/vdpa/solidrun/snet_ctrl.c +++ b/drivers/vdpa/solidrun/snet_ctrl.c @@ -15,6 +15,7 @@ enum snet_ctrl_opcodes { SNET_CTRL_OP_DESTROY = 1, SNET_CTRL_OP_READ_VQ_STATE, + SNET_CTRL_OP_SUSPEND, }; #define SNET_CTRL_TIMEOUT 2000000 @@ -322,3 +323,8 @@ int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state) return snet_ctrl_read_from_dpu(snet, SNET_CTRL_OP_READ_VQ_STATE, idx, state, sizeof(*state)); } + +int snet_suspend_dev(struct snet *snet) +{ + return snet_send_ctrl_msg(snet, SNET_CTRL_OP_SUSPEND, 0); +} diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index 86769f436b4d..7359599e09e4 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -483,6 +483,20 @@ static void snet_set_config(struct vdpa_device *vdev, unsigned int offset, iowrite8(*buf_ptr++, cfg_ptr + i); } +static int snet_suspend(struct vdpa_device *vdev) +{ + struct snet *snet = vdpa_to_snet(vdev); + int ret; + + ret = snet_suspend_dev(snet); + if (ret) + SNET_ERR(snet->pdev, "SNET[%u] suspend failed, err: %d\n", snet->sid, ret); + else + SNET_DBG(snet->pdev, "Suspend SNET[%u] device\n", snet->sid); + + return ret; +} + static const struct vdpa_config_ops snet_config_ops = { .set_vq_address = snet_set_vq_address, .set_vq_num = snet_set_vq_num, @@ -508,6 +522,7 @@ static const struct vdpa_config_ops snet_config_ops = { .set_status = snet_set_status, .get_config = snet_get_config, .set_config = snet_set_config, + .suspend = snet_suspend, }; static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet) diff --git a/drivers/vdpa/solidrun/snet_vdpa.h b/drivers/vdpa/solidrun/snet_vdpa.h index 09ff676e7a2d..3c78d4e7d485 100644 --- a/drivers/vdpa/solidrun/snet_vdpa.h +++ b/drivers/vdpa/solidrun/snet_vdpa.h @@ -203,5 +203,6 @@ void psnet_create_hwmon(struct pci_dev *pdev); void snet_ctrl_clear(struct snet *snet); int snet_destroy_dev(struct snet *snet); int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state); +int snet_suspend_dev(struct snet *snet); #endif //_SNET_VDPA_H_ From af8ececda185078c096852edb4e1d7a2349e6856 Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Thu, 13 Apr 2023 11:18:54 +0300 Subject: [PATCH 158/182] virtio: add VIRTIO_F_NOTIFICATION_DATA feature support According to VirtIO spec v1.2, VIRTIO_F_NOTIFICATION_DATA feature indicates that the driver passes extra data along with the queue notifications. In a split queue case, the extra data is 16-bit available index. In a packed queue case, the extra data is 1-bit wrap counter and 15-bit available index. Add support for this feature for MMIO, channel I/O and modern PCI transports. Signed-off-by: Viktor Prutyanov Acked-by: Jason Wang Reviewed-by: Xuan Zhuo Message-Id: <20230413081855.36643-2-alvaro.karsz@solid-run.com> Signed-off-by: Michael S. Tsirkin --- drivers/s390/virtio/virtio_ccw.c | 22 +++++++++++++++++++--- drivers/virtio/virtio_mmio.c | 18 +++++++++++++++++- drivers/virtio/virtio_pci_modern.c | 17 ++++++++++++++++- drivers/virtio/virtio_ring.c | 19 +++++++++++++++++++ include/linux/virtio_ring.h | 2 ++ include/uapi/linux/virtio_config.h | 6 ++++++ 6 files changed, 79 insertions(+), 5 deletions(-) diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 954fc31b4bc7..02922768b129 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -391,7 +391,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area)); } -static bool virtio_ccw_kvm_notify(struct virtqueue *vq) +static inline bool virtio_ccw_do_kvm_notify(struct virtqueue *vq, u32 data) { struct virtio_ccw_vq_info *info = vq->priv; struct virtio_ccw_device *vcdev; @@ -402,12 +402,22 @@ static bool virtio_ccw_kvm_notify(struct virtqueue *vq) BUILD_BUG_ON(sizeof(struct subchannel_id) != sizeof(unsigned int)); info->cookie = kvm_hypercall3(KVM_S390_VIRTIO_CCW_NOTIFY, *((unsigned int *)&schid), - vq->index, info->cookie); + data, info->cookie); if (info->cookie < 0) return false; return true; } +static bool virtio_ccw_kvm_notify(struct virtqueue *vq) +{ + return virtio_ccw_do_kvm_notify(vq, vq->index); +} + +static bool virtio_ccw_kvm_notify_with_data(struct virtqueue *vq) +{ + return virtio_ccw_do_kvm_notify(vq, vring_notification_data(vq)); +} + static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, struct ccw1 *ccw, int index) { @@ -495,6 +505,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, struct ccw1 *ccw) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); + bool (*notify)(struct virtqueue *vq); int err; struct virtqueue *vq = NULL; struct virtio_ccw_vq_info *info; @@ -502,6 +513,11 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, unsigned long flags; bool may_reduce; + if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA)) + notify = virtio_ccw_kvm_notify_with_data; + else + notify = virtio_ccw_kvm_notify; + /* Allocate queue. */ info = kzalloc(sizeof(struct virtio_ccw_vq_info), GFP_KERNEL); if (!info) { @@ -524,7 +540,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, may_reduce = vcdev->revision > 0; vq = vring_create_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev, true, may_reduce, ctx, - virtio_ccw_kvm_notify, callback, name); + notify, callback, name); if (!vq) { /* For now, we fail if we can't get the requested size. */ diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 3ff746e3f24a..dd4424c14233 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -285,6 +285,16 @@ static bool vm_notify(struct virtqueue *vq) return true; } +static bool vm_notify_with_data(struct virtqueue *vq) +{ + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev); + u32 data = vring_notification_data(vq); + + writel(data, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY); + + return true; +} + /* Notify all virtqueues on an interrupt. */ static irqreturn_t vm_interrupt(int irq, void *opaque) { @@ -363,12 +373,18 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in const char *name, bool ctx) { struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); + bool (*notify)(struct virtqueue *vq); struct virtio_mmio_vq_info *info; struct virtqueue *vq; unsigned long flags; unsigned int num; int err; + if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA)) + notify = vm_notify_with_data; + else + notify = vm_notify; + if (!name) return NULL; @@ -397,7 +413,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in /* Create the vring */ vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev, - true, true, ctx, vm_notify, callback, name); + true, true, ctx, notify, callback, name); if (!vq) { err = -ENOMEM; goto error_new_virtqueue; diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index 6e713904d8e8..d6bb68ba84e5 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -288,6 +288,15 @@ static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) return vp_modern_config_vector(&vp_dev->mdev, vector); } +static bool vp_notify_with_data(struct virtqueue *vq) +{ + u32 data = vring_notification_data(vq); + + iowrite32(data, (void __iomem *)vq->priv); + + return true; +} + static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, struct virtio_pci_vq_info *info, unsigned int index, @@ -298,10 +307,16 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, { struct virtio_pci_modern_device *mdev = &vp_dev->mdev; + bool (*notify)(struct virtqueue *vq); struct virtqueue *vq; u16 num; int err; + if (__virtio_test_bit(&vp_dev->vdev, VIRTIO_F_NOTIFICATION_DATA)) + notify = vp_notify_with_data; + else + notify = vp_notify; + if (index >= vp_modern_get_num_queues(mdev)) return ERR_PTR(-EINVAL); @@ -316,7 +331,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, vq = vring_create_virtqueue(index, num, SMP_CACHE_BYTES, &vp_dev->vdev, true, true, ctx, - vp_notify, callback, name); + notify, callback, name); if (!vq) return ERR_PTR(-ENOMEM); diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 34e3849629da..c5310eaf8b46 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -2762,6 +2762,23 @@ void vring_del_virtqueue(struct virtqueue *_vq) } EXPORT_SYMBOL_GPL(vring_del_virtqueue); +u32 vring_notification_data(struct virtqueue *_vq) +{ + struct vring_virtqueue *vq = to_vvq(_vq); + u16 next; + + if (vq->packed_ring) + next = (vq->packed.next_avail_idx & + ~(-(1 << VRING_PACKED_EVENT_F_WRAP_CTR))) | + vq->packed.avail_wrap_counter << + VRING_PACKED_EVENT_F_WRAP_CTR; + else + next = vq->split.avail_idx_shadow; + + return next << 16 | _vq->index; +} +EXPORT_SYMBOL_GPL(vring_notification_data); + /* Manipulates transport-specific feature bits. */ void vring_transport_features(struct virtio_device *vdev) { @@ -2781,6 +2798,8 @@ void vring_transport_features(struct virtio_device *vdev) break; case VIRTIO_F_ORDER_PLATFORM: break; + case VIRTIO_F_NOTIFICATION_DATA: + break; default: /* We don't understand this bit. */ __virtio_clear_bit(vdev, i); diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index 8b95b69ef694..2550c9170f4f 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -117,4 +117,6 @@ void vring_del_virtqueue(struct virtqueue *vq); void vring_transport_features(struct virtio_device *vdev); irqreturn_t vring_interrupt(int irq, void *_vq); + +u32 vring_notification_data(struct virtqueue *_vq); #endif /* _LINUX_VIRTIO_RING_H */ diff --git a/include/uapi/linux/virtio_config.h b/include/uapi/linux/virtio_config.h index 3c05162bc988..2c712c654165 100644 --- a/include/uapi/linux/virtio_config.h +++ b/include/uapi/linux/virtio_config.h @@ -99,6 +99,12 @@ */ #define VIRTIO_F_SR_IOV 37 +/* + * This feature indicates that the driver passes extra data (besides + * identifying the virtqueue) in its device notifications. + */ +#define VIRTIO_F_NOTIFICATION_DATA 38 + /* * This feature indicates that the driver can reset a queue individually. */ From 2c4e4a22a3b090e06191f8544d21e0e1d72ce518 Mon Sep 17 00:00:00 2001 From: Alvaro Karsz Date: Thu, 13 Apr 2023 11:18:55 +0300 Subject: [PATCH 159/182] virtio-vdpa: add VIRTIO_F_NOTIFICATION_DATA feature support Add VIRTIO_F_NOTIFICATION_DATA support for vDPA transport. If this feature is negotiated, the driver passes extra data when kicking a virtqueue. A device that offers this feature needs to implement the kick_vq_with_data callback. kick_vq_with_data receives the vDPA device and data. data includes: 16 bits vqn and 16 bits next available index for split virtqueues. 16 bits vqs, 15 least significant bits of next available index and 1 bit next_wrap for packed virtqueues. This patch follows a patch [1] by Viktor Prutyanov which adds support for the MMIO, channel I/O and modern PCI transports. Signed-off-by: Alvaro Karsz Message-Id: <20230413081855.36643-3-alvaro.karsz@solid-run.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/virtio/virtio_vdpa.c | 23 +++++++++++++++++++++-- include/linux/vdpa.h | 9 +++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index 2a095f37f26b..eb6aee8c06b2 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -113,6 +113,17 @@ static bool virtio_vdpa_notify(struct virtqueue *vq) return true; } +static bool virtio_vdpa_notify_with_data(struct virtqueue *vq) +{ + struct vdpa_device *vdpa = vd_get_vdpa(vq->vdev); + const struct vdpa_config_ops *ops = vdpa->config; + u32 data = vring_notification_data(vq); + + ops->kick_vq_with_data(vdpa, data); + + return true; +} + static irqreturn_t virtio_vdpa_config_cb(void *private) { struct virtio_vdpa_device *vd_dev = private; @@ -139,6 +150,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, struct device *dma_dev; const struct vdpa_config_ops *ops = vdpa->config; struct virtio_vdpa_vq_info *info; + bool (*notify)(struct virtqueue *vq) = virtio_vdpa_notify; struct vdpa_callback cb; struct virtqueue *vq; u64 desc_addr, driver_addr, device_addr; @@ -155,6 +167,14 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, if (index >= vdpa->nvqs) return ERR_PTR(-ENOENT); + /* We cannot accept VIRTIO_F_NOTIFICATION_DATA without kick_vq_with_data */ + if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA)) { + if (ops->kick_vq_with_data) + notify = virtio_vdpa_notify_with_data; + else + __virtio_clear_bit(vdev, VIRTIO_F_NOTIFICATION_DATA); + } + /* Queue shouldn't already be set up. */ if (ops->get_vq_ready(vdpa, index)) return ERR_PTR(-ENOENT); @@ -184,8 +204,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, dma_dev = vdpa_get_dma_dev(vdpa); vq = vring_create_virtqueue_dma(index, max_num, align, vdev, true, may_reduce_num, ctx, - virtio_vdpa_notify, callback, - name, dma_dev); + notify, callback, name, dma_dev); if (!vq) { err = -ENOMEM; goto error_new_virtqueue; diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index c0d3f5433af7..db1b0eaef4eb 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -149,6 +149,14 @@ struct vdpa_map_file { * @kick_vq: Kick the virtqueue * @vdev: vdpa device * @idx: virtqueue index + * @kick_vq_with_data: Kick the virtqueue and supply extra data + * (only if VIRTIO_F_NOTIFICATION_DATA is negotiated) + * @vdev: vdpa device + * @data for split virtqueue: + * 16 bits vqn and 16 bits next available index. + * @data for packed virtqueue: + * 16 bits vqn, 15 least significant bits of + * next available index and 1 bit next_wrap. * @set_vq_cb: Set the interrupt callback function for * a virtqueue * @vdev: vdpa device @@ -329,6 +337,7 @@ struct vdpa_config_ops { u64 device_area); void (*set_vq_num)(struct vdpa_device *vdev, u16 idx, u32 num); void (*kick_vq)(struct vdpa_device *vdev, u16 idx); + void (*kick_vq_with_data)(struct vdpa_device *vdev, u32 data); void (*set_vq_cb)(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb); void (*set_vq_ready)(struct vdpa_device *vdev, u16 idx, bool ready); From 51b6e6c1c8e382c50fe88a04e25d326ceff74f89 Mon Sep 17 00:00:00 2001 From: Alvaro Karsz Date: Mon, 17 Apr 2023 11:38:53 +0300 Subject: [PATCH 160/182] vdpa/snet: implement kick_vq_with_data callback Implement the kick_vq_with_data vDPA callback. On kick, we pass the next available data to the DPU by writing it in the kick offset. Signed-off-by: Alvaro Karsz Message-Id: <20230417083853.375076-1-alvaro.karsz@solid-run.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/solidrun/snet_main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index 7359599e09e4..da14d437af33 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -112,6 +112,18 @@ static void snet_kick_vq(struct vdpa_device *vdev, u16 idx) iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr); } +static void snet_kick_vq_with_data(struct vdpa_device *vdev, u32 data) +{ + struct snet *snet = vdpa_to_snet(vdev); + u16 idx = data & 0xFFFF; + + /* not ready - ignore */ + if (unlikely(!snet->vqs[idx]->ready)) + return; + + iowrite32((data & 0xFFFF0000) | SNET_KICK_VAL, snet->vqs[idx]->kick_ptr); +} + static void snet_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb) { struct snet *snet = vdpa_to_snet(vdev); @@ -501,6 +513,7 @@ static const struct vdpa_config_ops snet_config_ops = { .set_vq_address = snet_set_vq_address, .set_vq_num = snet_set_vq_num, .kick_vq = snet_kick_vq, + .kick_vq_with_data = snet_kick_vq_with_data, .set_vq_cb = snet_set_vq_cb, .set_vq_ready = snet_set_vq_ready, .get_vq_ready = snet_get_vq_ready, From 5b250fac7c76b670dd1b28b67f1a91a1907bc117 Mon Sep 17 00:00:00 2001 From: Alvaro Karsz Date: Sun, 9 Apr 2023 15:02:42 +0300 Subject: [PATCH 161/182] vdpa/snet: use likely/unlikely macros in hot functions - kick callback: most likely that the VQ is ready. - interrupt handlers: most likely that the callback is not NULL. Signed-off-by: Alvaro Karsz Message-Id: <20230409120242.3460074-1-alvaro.karsz@solid-run.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/solidrun/snet_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index da14d437af33..cdcd84ce4f5a 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -39,7 +39,7 @@ static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data) { struct snet *snet = data; /* Call callback if any */ - if (snet->cb.callback) + if (likely(snet->cb.callback)) return snet->cb.callback(snet->cb.private); return IRQ_HANDLED; @@ -49,7 +49,7 @@ static irqreturn_t snet_vq_irq_hndlr(int irq, void *data) { struct snet_vq *vq = data; /* Call callback if any */ - if (vq->cb.callback) + if (likely(vq->cb.callback)) return vq->cb.callback(vq->cb.private); return IRQ_HANDLED; @@ -106,7 +106,7 @@ static void snet_kick_vq(struct vdpa_device *vdev, u16 idx) { struct snet *snet = vdpa_to_snet(vdev); /* not ready - ignore */ - if (!snet->vqs[idx]->ready) + if (unlikely(!snet->vqs[idx]->ready)) return; iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr); From 112f23cd72a2975e11986d73575e2c3651ea4c7e Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 7 Apr 2023 15:36:57 +0200 Subject: [PATCH 162/182] vdpa_sim: move buffer allocation in the devices Currently, the vdpa_sim core does not use the buffer, but only allocates it. The buffer is used by devices differently, and some future devices may not use it. So let's move all its management inside the devices. Add a new `free` device callback called to clean up the resources allocated by the device. Signed-off-by: Stefano Garzarella Message-Id: <20230407133658.66339-2-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 7 ++--- drivers/vdpa/vdpa_sim/vdpa_sim.h | 3 +-- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 40 +++++++++++++++++++++++----- drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 28 ++++++++++++++----- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 2c706bb18897..d343af4fa60e 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -261,10 +261,6 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, for (i = 0; i < vdpasim->dev_attr.nas; i++) vhost_iotlb_init(&vdpasim->iommu[i], max_iotlb_entries, 0); - vdpasim->buffer = kvmalloc(dev_attr->buffer_size, GFP_KERNEL); - if (!vdpasim->buffer) - goto err_iommu; - for (i = 0; i < dev_attr->nvqs; i++) vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0], &vdpasim->iommu_lock); @@ -714,7 +710,8 @@ static void vdpasim_free(struct vdpa_device *vdpa) vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov); } - kvfree(vdpasim->buffer); + vdpasim->dev_attr.free(vdpasim); + for (i = 0; i < vdpasim->dev_attr.nas; i++) vhost_iotlb_reset(&vdpasim->iommu[i]); kfree(vdpasim->iommu); diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index 3a42887d05d9..bb137e479763 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -39,7 +39,6 @@ struct vdpasim_dev_attr { u64 supported_features; size_t alloc_size; size_t config_size; - size_t buffer_size; int nvqs; u32 id; u32 ngroups; @@ -51,6 +50,7 @@ struct vdpasim_dev_attr { int (*get_stats)(struct vdpasim *vdpasim, u16 idx, struct sk_buff *msg, struct netlink_ext_ack *extack); + void (*free)(struct vdpasim *vdpasim); }; /* State of each vdpasim device */ @@ -67,7 +67,6 @@ struct vdpasim { void *config; struct vhost_iotlb *iommu; bool *iommu_pt; - void *buffer; u32 status; u32 generation; u64 features; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index 568119e1553f..c996e750dc02 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -43,6 +43,16 @@ #define VDPASIM_BLK_AS_NUM 1 #define VDPASIM_BLK_GROUP_NUM 1 +struct vdpasim_blk { + struct vdpasim vdpasim; + void *buffer; +}; + +static struct vdpasim_blk *sim_to_blk(struct vdpasim *vdpasim) +{ + return container_of(vdpasim, struct vdpasim_blk, vdpasim); +} + static char vdpasim_blk_id[VIRTIO_BLK_ID_BYTES] = "vdpa_blk_sim"; static bool vdpasim_blk_check_range(struct vdpasim *vdpasim, u64 start_sector, @@ -78,6 +88,7 @@ static bool vdpasim_blk_check_range(struct vdpasim *vdpasim, u64 start_sector, static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, struct vdpasim_virtqueue *vq) { + struct vdpasim_blk *blk = sim_to_blk(vdpasim); size_t pushed = 0, to_pull, to_push; struct virtio_blk_outhdr hdr; bool handled = false; @@ -144,8 +155,7 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, } bytes = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov, - vdpasim->buffer + offset, - to_push); + blk->buffer + offset, to_push); if (bytes < 0) { dev_dbg(&vdpasim->vdpa.dev, "vringh_iov_push_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n", @@ -166,8 +176,7 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, } bytes = vringh_iov_pull_iotlb(&vq->vring, &vq->out_iov, - vdpasim->buffer + offset, - to_pull); + blk->buffer + offset, to_pull); if (bytes < 0) { dev_dbg(&vdpasim->vdpa.dev, "vringh_iov_pull_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n", @@ -247,7 +256,7 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, } if (type == VIRTIO_BLK_T_WRITE_ZEROES) { - memset(vdpasim->buffer + offset, 0, + memset(blk->buffer + offset, 0, num_sectors << SECTOR_SHIFT); } @@ -353,6 +362,13 @@ static void vdpasim_blk_get_config(struct vdpasim *vdpasim, void *config) } +static void vdpasim_blk_free(struct vdpasim *vdpasim) +{ + struct vdpasim_blk *blk = sim_to_blk(vdpasim); + + kvfree(blk->buffer); +} + static void vdpasim_blk_mgmtdev_release(struct device *dev) { } @@ -366,6 +382,7 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, const struct vdpa_dev_set_config *config) { struct vdpasim_dev_attr dev_attr = {}; + struct vdpasim_blk *blk; struct vdpasim *simdev; int ret; @@ -376,16 +393,25 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, dev_attr.nvqs = VDPASIM_BLK_VQ_NUM; dev_attr.ngroups = VDPASIM_BLK_GROUP_NUM; dev_attr.nas = VDPASIM_BLK_AS_NUM; - dev_attr.alloc_size = sizeof(struct vdpasim); + dev_attr.alloc_size = sizeof(struct vdpasim_blk); dev_attr.config_size = sizeof(struct virtio_blk_config); dev_attr.get_config = vdpasim_blk_get_config; dev_attr.work_fn = vdpasim_blk_work; - dev_attr.buffer_size = VDPASIM_BLK_CAPACITY << SECTOR_SHIFT; + dev_attr.free = vdpasim_blk_free; simdev = vdpasim_create(&dev_attr, config); if (IS_ERR(simdev)) return PTR_ERR(simdev); + blk = sim_to_blk(simdev); + + blk->buffer = kvmalloc(VDPASIM_BLK_CAPACITY << SECTOR_SHIFT, + GFP_KERNEL); + if (!blk->buffer) { + ret = -ENOMEM; + goto put_dev; + } + ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_BLK_VQ_NUM); if (ret) goto put_dev; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index 55920502f76b..cfe962911804 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -58,6 +58,7 @@ struct vdpasim_net{ struct vdpasim_dataq_stats tx_stats; struct vdpasim_dataq_stats rx_stats; struct vdpasim_cq_stats cq_stats; + void *buffer; }; static struct vdpasim_net *sim_to_net(struct vdpasim *vdpasim) @@ -87,14 +88,15 @@ static bool receive_filter(struct vdpasim *vdpasim, size_t len) size_t hdr_len = modern ? sizeof(struct virtio_net_hdr_v1) : sizeof(struct virtio_net_hdr); struct virtio_net_config *vio_config = vdpasim->config; + struct vdpasim_net *net = sim_to_net(vdpasim); if (len < ETH_ALEN + hdr_len) return false; - if (is_broadcast_ether_addr(vdpasim->buffer + hdr_len) || - is_multicast_ether_addr(vdpasim->buffer + hdr_len)) + if (is_broadcast_ether_addr(net->buffer + hdr_len) || + is_multicast_ether_addr(net->buffer + hdr_len)) return true; - if (!strncmp(vdpasim->buffer + hdr_len, vio_config->mac, ETH_ALEN)) + if (!strncmp(net->buffer + hdr_len, vio_config->mac, ETH_ALEN)) return true; return false; @@ -225,8 +227,7 @@ static void vdpasim_net_work(struct vdpasim *vdpasim) ++tx_pkts; read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov, - vdpasim->buffer, - PAGE_SIZE); + net->buffer, PAGE_SIZE); tx_bytes += read; @@ -245,7 +246,7 @@ static void vdpasim_net_work(struct vdpasim *vdpasim) } write = vringh_iov_push_iotlb(&rxq->vring, &rxq->in_iov, - vdpasim->buffer, read); + net->buffer, read); if (write <= 0) { ++rx_errors; break; @@ -427,6 +428,13 @@ static void vdpasim_net_setup_config(struct vdpasim *vdpasim, vio_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); } +static void vdpasim_net_free(struct vdpasim *vdpasim) +{ + struct vdpasim_net *net = sim_to_net(vdpasim); + + kvfree(net->buffer); +} + static void vdpasim_net_mgmtdev_release(struct device *dev) { } @@ -456,7 +464,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, dev_attr.get_config = vdpasim_net_get_config; dev_attr.work_fn = vdpasim_net_work; dev_attr.get_stats = vdpasim_net_get_stats; - dev_attr.buffer_size = PAGE_SIZE; + dev_attr.free = vdpasim_net_free; simdev = vdpasim_create(&dev_attr, config); if (IS_ERR(simdev)) @@ -470,6 +478,12 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, u64_stats_init(&net->rx_stats.syncp); u64_stats_init(&net->cq_stats.syncp); + net->buffer = kvmalloc(PAGE_SIZE, GFP_KERNEL); + if (!net->buffer) { + ret = -ENOMEM; + goto reg_err; + } + /* * Initialization must be completed before this call, since it can * connect the device to the vDPA bus, so requests can arrive after From abebb16254b362664452e14d9711ddb54855ddcf Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 7 Apr 2023 15:36:58 +0200 Subject: [PATCH 163/182] vdpa_sim_blk: support shared backend The vdpa_sim_blk simulator uses a ramdisk as the backend. To test live migration, we need two devices that share the backend to have the data synchronized with each other. Add a new module parameter to make the buffer shared between all devices. The shared_buffer_mutex is used just to ensure that each operation is atomic, but it is up to the user to use the devices knowing that the underlying ramdisk is shared. For example, when we do a migration, the VMM (e.g., QEMU) will guarantee to write to the destination device, only after completing operations with the source device. Signed-off-by: Stefano Garzarella Message-Id: <20230407133658.66339-3-sgarzare@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 55 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index c996e750dc02..00d7d72713be 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -46,6 +46,7 @@ struct vdpasim_blk { struct vdpasim vdpasim; void *buffer; + bool shared_backend; }; static struct vdpasim_blk *sim_to_blk(struct vdpasim *vdpasim) @@ -55,6 +56,26 @@ static struct vdpasim_blk *sim_to_blk(struct vdpasim *vdpasim) static char vdpasim_blk_id[VIRTIO_BLK_ID_BYTES] = "vdpa_blk_sim"; +static bool shared_backend; +module_param(shared_backend, bool, 0444); +MODULE_PARM_DESC(shared_backend, "Enable the shared backend between virtio-blk devices"); + +static void *shared_buffer; +/* mutex to synchronize shared_buffer access */ +static DEFINE_MUTEX(shared_buffer_mutex); + +static void vdpasim_blk_buffer_lock(struct vdpasim_blk *blk) +{ + if (blk->shared_backend) + mutex_lock(&shared_buffer_mutex); +} + +static void vdpasim_blk_buffer_unlock(struct vdpasim_blk *blk) +{ + if (blk->shared_backend) + mutex_unlock(&shared_buffer_mutex); +} + static bool vdpasim_blk_check_range(struct vdpasim *vdpasim, u64 start_sector, u64 num_sectors, u64 max_sectors) { @@ -154,8 +175,10 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, break; } + vdpasim_blk_buffer_lock(blk); bytes = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov, blk->buffer + offset, to_push); + vdpasim_blk_buffer_unlock(blk); if (bytes < 0) { dev_dbg(&vdpasim->vdpa.dev, "vringh_iov_push_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n", @@ -175,8 +198,10 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, break; } + vdpasim_blk_buffer_lock(blk); bytes = vringh_iov_pull_iotlb(&vq->vring, &vq->out_iov, blk->buffer + offset, to_pull); + vdpasim_blk_buffer_unlock(blk); if (bytes < 0) { dev_dbg(&vdpasim->vdpa.dev, "vringh_iov_pull_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n", @@ -256,8 +281,10 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, } if (type == VIRTIO_BLK_T_WRITE_ZEROES) { + vdpasim_blk_buffer_lock(blk); memset(blk->buffer + offset, 0, num_sectors << SECTOR_SHIFT); + vdpasim_blk_buffer_unlock(blk); } break; @@ -366,7 +393,8 @@ static void vdpasim_blk_free(struct vdpasim *vdpasim) { struct vdpasim_blk *blk = sim_to_blk(vdpasim); - kvfree(blk->buffer); + if (!blk->shared_backend) + kvfree(blk->buffer); } static void vdpasim_blk_mgmtdev_release(struct device *dev) @@ -404,12 +432,17 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, return PTR_ERR(simdev); blk = sim_to_blk(simdev); + blk->shared_backend = shared_backend; - blk->buffer = kvmalloc(VDPASIM_BLK_CAPACITY << SECTOR_SHIFT, - GFP_KERNEL); - if (!blk->buffer) { - ret = -ENOMEM; - goto put_dev; + if (blk->shared_backend) { + blk->buffer = shared_buffer; + } else { + blk->buffer = kvmalloc(VDPASIM_BLK_CAPACITY << SECTOR_SHIFT, + GFP_KERNEL); + if (!blk->buffer) { + ret = -ENOMEM; + goto put_dev; + } } ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_BLK_VQ_NUM); @@ -461,6 +494,15 @@ static int __init vdpasim_blk_init(void) if (ret) goto parent_err; + if (shared_backend) { + shared_buffer = kvmalloc(VDPASIM_BLK_CAPACITY << SECTOR_SHIFT, + GFP_KERNEL); + if (!shared_buffer) { + ret = -ENOMEM; + goto parent_err; + } + } + return 0; parent_err: @@ -470,6 +512,7 @@ parent_err: static void __exit vdpasim_blk_exit(void) { + kvfree(shared_buffer); vdpa_mgmtdev_unregister(&mgmt_dev); device_unregister(&vdpasim_blk_mgmtdev); } From 38fc29ea754711e9a8c4e9ca2678ab41353a4662 Mon Sep 17 00:00:00 2001 From: Shunsuke Mie Date: Mon, 17 Apr 2023 11:20:36 +0900 Subject: [PATCH 164/182] virtio_ring: add a struct device forward declaration The virtio_ring header file uses the struct device without a forward declaration. Signed-off-by: Shunsuke Mie Message-Id: <20230417022037.917668-1-mie@igel.co.jp> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_ring.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index 2550c9170f4f..9b33df741b63 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -58,6 +58,7 @@ do { \ struct virtio_device; struct virtqueue; +struct device; /* * Creates a virtqueue and allocates the descriptor ring. If From e9c4962c5d69b8a238bb8bd51e8fdce39be13e5b Mon Sep 17 00:00:00 2001 From: Shunsuke Mie Date: Mon, 17 Apr 2023 11:20:37 +0900 Subject: [PATCH 165/182] tools/virtio: fix build caused by virtio_ring changes Fix the build dependency for virtio_test. The virtio_ring that is used from the test requires container_of_const(). Change to use container_of.h kernel header directly and adapt related codes. Signed-off-by: Shunsuke Mie Message-Id: <20230417022037.917668-2-mie@igel.co.jp> Signed-off-by: Michael S. Tsirkin --- tools/include/linux/types.h | 5 +++++ tools/virtio/linux/compiler.h | 2 ++ tools/virtio/linux/kernel.h | 5 +---- tools/virtio/linux/uaccess.h | 11 ++--------- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 051fdeaf2670..8519386acd23 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h @@ -49,7 +49,12 @@ typedef __s8 s8; #endif #define __force +/* This is defined in linux/compiler_types.h and is left for backward + * compatibility. + */ +#ifndef __user #define __user +#endif #define __must_check #define __cold diff --git a/tools/virtio/linux/compiler.h b/tools/virtio/linux/compiler.h index 2c51bccb97bb..1f3a15b954b9 100644 --- a/tools/virtio/linux/compiler.h +++ b/tools/virtio/linux/compiler.h @@ -2,6 +2,8 @@ #ifndef LINUX_COMPILER_H #define LINUX_COMPILER_H +#include "../../../include/linux/compiler_types.h" + #define WRITE_ONCE(var, val) \ (*((volatile typeof(val) *)(&(var))) = (val)) diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h index 8b877167933d..6702008f7f5c 100644 --- a/tools/virtio/linux/kernel.h +++ b/tools/virtio/linux/kernel.h @@ -10,6 +10,7 @@ #include #include +#include "../../../include/linux/container_of.h" #include #include #include @@ -107,10 +108,6 @@ static inline void free_page(unsigned long addr) free((void *)addr); } -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - # ifndef likely # define likely(x) (__builtin_expect(!!(x), 1)) # endif diff --git a/tools/virtio/linux/uaccess.h b/tools/virtio/linux/uaccess.h index 991dfb263998..f13828e0c409 100644 --- a/tools/virtio/linux/uaccess.h +++ b/tools/virtio/linux/uaccess.h @@ -6,15 +6,10 @@ extern void *__user_addr_min, *__user_addr_max; -static inline void __chk_user_ptr(const volatile void *p, size_t size) -{ - assert(p >= __user_addr_min && p + size <= __user_addr_max); -} - #define put_user(x, ptr) \ ({ \ typeof(ptr) __pu_ptr = (ptr); \ - __chk_user_ptr(__pu_ptr, sizeof(*__pu_ptr)); \ + __chk_user_ptr(__pu_ptr); \ WRITE_ONCE(*(__pu_ptr), x); \ 0; \ }) @@ -22,7 +17,7 @@ static inline void __chk_user_ptr(const volatile void *p, size_t size) #define get_user(x, ptr) \ ({ \ typeof(ptr) __pu_ptr = (ptr); \ - __chk_user_ptr(__pu_ptr, sizeof(*__pu_ptr)); \ + __chk_user_ptr(__pu_ptr); \ x = READ_ONCE(*(__pu_ptr)); \ 0; \ }) @@ -37,7 +32,6 @@ static void volatile_memcpy(volatile char *to, const volatile char *from, static inline int copy_from_user(void *to, const void __user volatile *from, unsigned long n) { - __chk_user_ptr(from, n); volatile_memcpy(to, from, n); return 0; } @@ -45,7 +39,6 @@ static inline int copy_from_user(void *to, const void __user volatile *from, static inline int copy_to_user(void __user volatile *to, const void *from, unsigned long n) { - __chk_user_ptr(to, n); volatile_memcpy(to, from, n); return 0; } From 11841c52fa525c9be17c0731cc897d93c3c0f4fe Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Thu, 13 Apr 2023 15:16:10 +0800 Subject: [PATCH 166/182] MAINTAINERS: make me a reviewer of VIRTIO CORE AND NET DRIVERS First of all, I personally love open source, linux and virtio. I have also participated in community work such as virtio for a long time. I think I am familiar enough with virtio/virtio-net and is adequate as a reviewer. Every time there is some patch/bug, I wish I can get pinged and I will feedback on that. For me personally, being a reviewer is an honor and a responsibility, and it also makes it easier for me to participate in virtio-related work. And I will spend more time reviewing virtio patch. Better advance virtio development I had some contributions to virtio/virtio-net and some support for it. * per-queue reset * virtio-net xdp * some bug fix * ...... I make a humble request to grant the reviewer role for the virtio core and net drivers. Signed-off-by: Xuan Zhuo Message-Id: <20230413071610.43659-1-xuanzhuo@linux.alibaba.com> Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a8df70387877..4bdf08b2ab55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22064,6 +22064,7 @@ F: include/uapi/linux/virtio_console.h VIRTIO CORE AND NET DRIVERS M: "Michael S. Tsirkin" M: Jason Wang +R: Xuan Zhuo L: virtualization@lists.linux-foundation.org S: Maintained F: Documentation/ABI/testing/sysfs-bus-vdpa From c82729e06644f4e087f5ff0f91b8fb15e03b8890 Mon Sep 17 00:00:00 2001 From: Cindy Lu Date: Thu, 20 Apr 2023 23:17:34 +0800 Subject: [PATCH 167/182] vhost_vdpa: fix unmap process in no-batch mode While using the vdpa device with vIOMMU enabled in the guest VM, when the vdpa device bind to vfio-pci and run testpmd then system will fail to unmap. The test process is Load guest VM --> attach to virtio driver--> bind to vfio-pci driver So the mapping process is 1)batched mode map to normal MR 2)batched mode unmapped the normal MR 3)unmapped all the memory 4)mapped to iommu MR This error happened in step 3). The iotlb was freed in step 2) and the function vhost_vdpa_process_iotlb_msg will return fail Which causes failure. To fix this, we will not remove the AS while the iotlb->nmaps is 0. This will free in the vhost_vdpa_clean Cc: stable@vger.kernel.org Fixes: aaca8373c4b1 ("vhost-vdpa: support ASID based IOTLB API") Signed-off-by: Cindy Lu Message-Id: <20230420151734.860168-1-lulu@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vdpa.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index cd266fa80c4e..5133004452a1 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -886,11 +886,7 @@ static void vhost_vdpa_unmap(struct vhost_vdpa *v, if (!v->in_batch) ops->set_map(vdpa, asid, iotlb); } - /* If we are in the middle of batch processing, delay the free - * of AS until BATCH_END. - */ - if (!v->in_batch && !iotlb->nmaps) - vhost_vdpa_remove_as(v, asid); + } static int vhost_vdpa_va_map(struct vhost_vdpa *v, @@ -1147,8 +1143,6 @@ static int vhost_vdpa_process_iotlb_msg(struct vhost_dev *dev, u32 asid, if (v->in_batch && ops->set_map) ops->set_map(vdpa, asid, iotlb); v->in_batch = false; - if (!iotlb->nmaps) - vhost_vdpa_remove_as(v, asid); break; default: r = -EINVAL; From 2d60eca501bc70fc73d30a1b151a137c3b990183 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 20 Apr 2023 21:19:03 +0200 Subject: [PATCH 168/182] sh: sq: Use the bitmap API when applicable Using the bitmap API is less verbose than hand writing it. It also improves the semantic. Signed-off-by: Christophe JAILLET Reviewed-by: Geert Uytterhoeven Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/a51e9f32c19a007f4922943282cb12c89064440d.1681671848.git.christophe.jaillet@wanadoo.fr Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/kernel/cpu/sh4/sq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 6e0bb3f47fa5..d289e99dc118 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -372,7 +372,6 @@ static struct subsys_interface sq_interface = { static int __init sq_api_init(void) { unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT; - unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG; int ret = -ENOMEM; printk(KERN_NOTICE "sq: Registering store queue API.\n"); @@ -382,7 +381,7 @@ static int __init sq_api_init(void) if (unlikely(!sq_cache)) return ret; - sq_bitmap = kcalloc(size, sizeof(long), GFP_KERNEL); + sq_bitmap = bitmap_zalloc(nr_pages, GFP_KERNEL); if (unlikely(!sq_bitmap)) goto out; @@ -393,7 +392,7 @@ static int __init sq_api_init(void) return 0; out: - kfree(sq_bitmap); + bitmap_free(sq_bitmap); kmem_cache_destroy(sq_cache); return ret; @@ -402,7 +401,7 @@ out: static void __exit sq_api_exit(void) { subsys_interface_unregister(&sq_interface); - kfree(sq_bitmap); + bitmap_free(sq_bitmap); kmem_cache_destroy(sq_cache); } From a494aef23dfc732945cb42e22246a5c31174e4a5 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Thu, 20 Apr 2023 18:30:25 -0700 Subject: [PATCH 169/182] PCI: hv: Replace retarget_msi_interrupt_params with hyperv_pcpu_input_arg 4 commits are involved here: A (2016): commit 0de8ce3ee8e3 ("PCI: hv: Allocate physically contiguous hypercall params buffer") B (2017): commit be66b6736591 ("PCI: hv: Use page allocation for hbus structure") C (2019): commit 877b911a5ba0 ("PCI: hv: Avoid a kmemleak false positive caused by the hbus buffer") D (2018): commit 68bb7bfb7985 ("X86/Hyper-V: Enable IPI enlightenments") Patch D introduced the per-CPU hypercall input page "hyperv_pcpu_input_arg" in 2018. With patch D, we no longer need the per-Hyper-V-PCI-bus hypercall input page "hbus->retarget_msi_interrupt_params" that was added in patch A, and the issue addressed by patch B is no longer an issue, and we can also get rid of patch C. The change here is required for PCI device assignment to work for Confidential VMs (CVMs) running without a paravisor, because otherwise we would have to call set_memory_decrypted() for "hbus->retarget_msi_interrupt_params" before calling the hypercall HVCALL_RETARGET_INTERRUPT. Signed-off-by: Dexuan Cui Reviewed-by: Michael Kelley Acked-by: Lorenzo Pieralisi Link: https://lore.kernel.org/r/20230421013025.17152-1-decui@microsoft.com Signed-off-by: Wei Liu --- drivers/pci/controller/pci-hyperv.c | 48 +++++------------------------ 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 337f3b4a04fc..bc32662c6bb7 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -508,20 +508,11 @@ struct hv_pcibus_device { struct msi_domain_info msi_info; struct irq_domain *irq_domain; - spinlock_t retarget_msi_interrupt_lock; - struct workqueue_struct *wq; /* Highest slot of child device with resources allocated */ int wslot_res_allocated; bool use_calls; /* Use hypercalls to access mmio cfg space */ - - /* hypercall arg, must not cross page boundary */ - struct hv_retarget_device_interrupt retarget_msi_interrupt_params; - - /* - * Don't put anything here: retarget_msi_interrupt_params must be last - */ }; /* @@ -645,9 +636,9 @@ static void hv_arch_irq_unmask(struct irq_data *data) hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata); int_desc = data->chip_data; - spin_lock_irqsave(&hbus->retarget_msi_interrupt_lock, flags); + local_irq_save(flags); - params = &hbus->retarget_msi_interrupt_params; + params = *this_cpu_ptr(hyperv_pcpu_input_arg); memset(params, 0, sizeof(*params)); params->partition_id = HV_PARTITION_ID_SELF; params->int_entry.source = HV_INTERRUPT_SOURCE_MSI; @@ -680,7 +671,7 @@ static void hv_arch_irq_unmask(struct irq_data *data) if (!alloc_cpumask_var(&tmp, GFP_ATOMIC)) { res = 1; - goto exit_unlock; + goto out; } cpumask_and(tmp, dest, cpu_online_mask); @@ -689,7 +680,7 @@ static void hv_arch_irq_unmask(struct irq_data *data) if (nr_bank <= 0) { res = 1; - goto exit_unlock; + goto out; } /* @@ -708,8 +699,8 @@ static void hv_arch_irq_unmask(struct irq_data *data) res = hv_do_hypercall(HVCALL_RETARGET_INTERRUPT | (var_size << 17), params, NULL); -exit_unlock: - spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags); +out: + local_irq_restore(flags); /* * During hibernation, when a CPU is offlined, the kernel tries @@ -3598,35 +3589,11 @@ static int hv_pci_probe(struct hv_device *hdev, bool enter_d0_retry = true; int ret; - /* - * hv_pcibus_device contains the hypercall arguments for retargeting in - * hv_irq_unmask(). Those must not cross a page boundary. - */ - BUILD_BUG_ON(sizeof(*hbus) > HV_HYP_PAGE_SIZE); - bridge = devm_pci_alloc_host_bridge(&hdev->device, 0); if (!bridge) return -ENOMEM; - /* - * With the recent 59bb47985c1d ("mm, sl[aou]b: guarantee natural - * alignment for kmalloc(power-of-two)"), kzalloc() is able to allocate - * a 4KB buffer that is guaranteed to be 4KB-aligned. Here the size and - * alignment of hbus is important because hbus's field - * retarget_msi_interrupt_params must not cross a 4KB page boundary. - * - * Here we prefer kzalloc to get_zeroed_page(), because a buffer - * allocated by the latter is not tracked and scanned by kmemleak, and - * hence kmemleak reports the pointer contained in the hbus buffer - * (i.e. the hpdev struct, which is created in new_pcichild_device() and - * is tracked by hbus->children) as memory leak (false positive). - * - * If the kernel doesn't have 59bb47985c1d, get_zeroed_page() *must* be - * used to allocate the hbus buffer and we can avoid the kmemleak false - * positive by using kmemleak_alloc() and kmemleak_free() to ask - * kmemleak to track and scan the hbus buffer. - */ - hbus = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); + hbus = kzalloc(sizeof(*hbus), GFP_KERNEL); if (!hbus) return -ENOMEM; @@ -3683,7 +3650,6 @@ static int hv_pci_probe(struct hv_device *hdev, INIT_LIST_HEAD(&hbus->dr_list); spin_lock_init(&hbus->config_lock); spin_lock_init(&hbus->device_list_lock); - spin_lock_init(&hbus->retarget_msi_interrupt_lock); hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0, hbus->bridge->domain_nr); if (!hbus->wq) { From 95b5baf81001a80a8dd8b35306694db163bcb423 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Apr 2023 09:11:26 -0700 Subject: [PATCH 170/182] MIPS: Mark check_bugs() as __init After commit ac7c3e4ff401 ("compiler: enable CONFIG_OPTIMIZE_INLINING forcibly"), a compiler may choose not to inline a function marked with just 'inline'. If check_bugs() is not inlined into start_kernel(), which occurs when building with clang after commit 9ea7e6b62c2b ("init: Mark [arch_call_]rest_init() __noreturn"), modpost complains with: WARNING: modpost: vmlinux.o: section mismatch in reference: check_bugs (section: .text) -> check_bugs32 (section: .init.text) check_bugs() is only called from start_kernel(), which itself is marked __init, so there would not be any issues at run time. Make it obvious to modpost that this call chain is safe by marking check_bugs() as __init, which fixes the warning. Reported-by: Naresh Kamboju Link: https://lore.kernel.org/CA+G9fYt+4e57Gdy6cix=LeNK6XqWoui8du=mZWu=cf8vPYocKw@mail.gmail.com/ Signed-off-by: Nathan Chancellor Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/bugs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/bugs.h b/arch/mips/include/asm/bugs.h index d72dc6e1cf3c..047e14227c45 100644 --- a/arch/mips/include/asm/bugs.h +++ b/arch/mips/include/asm/bugs.h @@ -30,7 +30,7 @@ static inline void check_bugs_early(void) check_bugs64_early(); } -static inline void check_bugs(void) +static inline void __init check_bugs(void) { unsigned int cpu = smp_processor_id(); From f4670a1b30f886e843258ca4a69c442811a90302 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Apr 2023 09:11:27 -0700 Subject: [PATCH 171/182] MIPS: Sink body of check_bugs_early() into its only call site If check_bugs_early() is not inlined, which a compiler is free to do after commit ac7c3e4ff401 ("compiler: enable CONFIG_OPTIMIZE_INLINING forcibly"), modpost would warn that check_bugs_early(), a non-init function, refers to check_bugs64_early(), which is marked __init. This would not result in any run time issues, as check_bugs_early() is only called from setup_arch(), which is marked __init. To avoid this potential warning, just sink the body of check_bugs_early() into its single call site in setup_arch(). Signed-off-by: Nathan Chancellor Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/bugs.h | 6 ------ arch/mips/kernel/setup.c | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/mips/include/asm/bugs.h b/arch/mips/include/asm/bugs.h index 047e14227c45..653f78f3a685 100644 --- a/arch/mips/include/asm/bugs.h +++ b/arch/mips/include/asm/bugs.h @@ -24,12 +24,6 @@ extern void check_bugs64_early(void); extern void check_bugs32(void); extern void check_bugs64(void); -static inline void check_bugs_early(void) -{ - if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64)) - check_bugs64_early(); -} - static inline void __init check_bugs(void) { unsigned int cpu = smp_processor_id(); diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f1c88f8a1dc5..febdc5564638 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -786,7 +786,8 @@ void __init setup_arch(char **cmdline_p) setup_early_printk(); #endif cpu_report(); - check_bugs_early(); + if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64)) + check_bugs64_early(); #if defined(CONFIG_VT) #if defined(CONFIG_VGA_CONSOLE) From fae65ef3a148079103ae935107c62f7830ab52c5 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 28 Mar 2023 10:45:49 +0200 Subject: [PATCH 172/182] xen/pciback: don't call pcistub_device_put() under lock pcistub_device_put() shouldn't be called under spinlock, as it can sleep. For this reason pcistub_device_get_pci_dev() needs to be modified: instead of always calling pcistub_device_get() just do the call of pcistub_device_get() only if it is really needed. This removes the need to call pcistub_device_put(). Reported-by: Dan Carpenter Link: https://lore.kernel.org/lkml/Y+JUIl64UDmdkboh@kadam/ Signed-off-by: Juergen Gross Reviewed-by: Oleksandr Tyshchenko Link: https://lore.kernel.org/r/20230328084549.20695-1-jgross@suse.com Signed-off-by: Juergen Gross --- drivers/xen/xen-pciback/pci_stub.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index bba527620507..e34b623e4b41 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -194,8 +194,6 @@ static struct pci_dev *pcistub_device_get_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *pci_dev = NULL; unsigned long flags; - pcistub_device_get(psdev); - spin_lock_irqsave(&psdev->lock, flags); if (!psdev->pdev) { psdev->pdev = pdev; @@ -203,8 +201,8 @@ static struct pci_dev *pcistub_device_get_pci_dev(struct xen_pcibk_device *pdev, } spin_unlock_irqrestore(&psdev->lock, flags); - if (!pci_dev) - pcistub_device_put(psdev); + if (pci_dev) + pcistub_device_get(psdev); return pci_dev; } From b2c042cc802fe96d431821bf1cf2f0f04a3eda7d Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 28 Mar 2023 10:46:02 +0200 Subject: [PATCH 173/182] xen/scsiback: don't call scsiback_free_translation_entry() under lock scsiback_free_translation_entry() shouldn't be called under spinlock, as it can sleep. This requires to split removing a translation entry from the v2p list from actually calling kref_put() for the entry. Reported-by: Dan Carpenter Link: https://lore.kernel.org/lkml/Y+JUIl64UDmdkboh@kadam/ Signed-off-by: Juergen Gross Reviewed-by: Oleksandr Tyshchenko Link: https://lore.kernel.org/r/20230328084602.20729-1-jgross@suse.com Signed-off-by: Juergen Gross --- drivers/xen/xen-scsiback.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 954188b0b858..294f29cdc7aa 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1010,12 +1010,6 @@ out_free: return err; } -static void __scsiback_del_translation_entry(struct v2p_entry *entry) -{ - list_del(&entry->l); - kref_put(&entry->kref, scsiback_free_translation_entry); -} - /* Delete the translation entry specified */ @@ -1024,18 +1018,20 @@ static int scsiback_del_translation_entry(struct vscsibk_info *info, { struct v2p_entry *entry; unsigned long flags; - int ret = 0; spin_lock_irqsave(&info->v2p_lock, flags); /* Find out the translation entry specified */ entry = scsiback_chk_translation_entry(info, v); if (entry) - __scsiback_del_translation_entry(entry); - else - ret = -ENOENT; + list_del(&entry->l); spin_unlock_irqrestore(&info->v2p_lock, flags); - return ret; + + if (!entry) + return -ENOENT; + + kref_put(&entry->kref, scsiback_free_translation_entry); + return 0; } static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, @@ -1239,14 +1235,19 @@ static void scsiback_release_translation_entry(struct vscsibk_info *info) { struct v2p_entry *entry, *tmp; struct list_head *head = &(info->v2p_entry_lists); + struct list_head tmp_list; unsigned long flags; spin_lock_irqsave(&info->v2p_lock, flags); - list_for_each_entry_safe(entry, tmp, head, l) - __scsiback_del_translation_entry(entry); + list_cut_before(&tmp_list, head, head); spin_unlock_irqrestore(&info->v2p_lock, flags); + + list_for_each_entry_safe(entry, tmp, &tmp_list, l) { + list_del(&entry->l); + kref_put(&entry->kref, scsiback_free_translation_entry); + } } static void scsiback_remove(struct xenbus_device *dev) From c66bb48edd58c3a22072b4f68312c225dc1b0009 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 3 Apr 2023 11:27:11 +0200 Subject: [PATCH 174/182] xen/pvcalls: don't call bind_evtchn_to_irqhandler() under lock bind_evtchn_to_irqhandler() shouldn't be called under spinlock, as it can sleep. This requires to move the calls of create_active() out of the locked regions. This is no problem, as the worst which could happen would be a spurious call of the interrupt handler, causing a spurious wake_up(). Reported-by: Dan Carpenter Link: https://lore.kernel.org/lkml/Y+JUIl64UDmdkboh@kadam/ Signed-off-by: Juergen Gross Reviewed-by: Oleksandr Tyshchenko Reviewed-by: Stefano Stabellini Link: https://lore.kernel.org/r/20230403092711.15285-1-jgross@suse.com Signed-off-by: Juergen Gross --- drivers/xen/pvcalls-front.c | 60 ++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index d5d589bda243..b72ee9379d77 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -227,22 +227,30 @@ again: static void free_active_ring(struct sock_mapping *map); -static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, - struct sock_mapping *map) +static void pvcalls_front_destroy_active(struct pvcalls_bedata *bedata, + struct sock_mapping *map) { int i; unbind_from_irqhandler(map->active.irq, map); - spin_lock(&bedata->socket_lock); - if (!list_empty(&map->list)) - list_del_init(&map->list); - spin_unlock(&bedata->socket_lock); + if (bedata) { + spin_lock(&bedata->socket_lock); + if (!list_empty(&map->list)) + list_del_init(&map->list); + spin_unlock(&bedata->socket_lock); + } for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) gnttab_end_foreign_access(map->active.ring->ref[i], NULL); gnttab_end_foreign_access(map->active.ref, NULL); free_active_ring(map); +} + +static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, + struct sock_mapping *map) +{ + pvcalls_front_destroy_active(bedata, map); kfree(map); } @@ -433,19 +441,18 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, pvcalls_exit_sock(sock); return ret; } + ret = create_active(map, &evtchn); + if (ret < 0) { + free_active_ring(map); + pvcalls_exit_sock(sock); + return ret; + } spin_lock(&bedata->socket_lock); ret = get_request(bedata, &req_id); if (ret < 0) { spin_unlock(&bedata->socket_lock); - free_active_ring(map); - pvcalls_exit_sock(sock); - return ret; - } - ret = create_active(map, &evtchn); - if (ret < 0) { - spin_unlock(&bedata->socket_lock); - free_active_ring(map); + pvcalls_front_destroy_active(NULL, map); pvcalls_exit_sock(sock); return ret; } @@ -821,28 +828,27 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) pvcalls_exit_sock(sock); return ret; } - spin_lock(&bedata->socket_lock); - ret = get_request(bedata, &req_id); - if (ret < 0) { - clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, - (void *)&map->passive.flags); - spin_unlock(&bedata->socket_lock); - free_active_ring(map2); - kfree(map2); - pvcalls_exit_sock(sock); - return ret; - } - ret = create_active(map2, &evtchn); if (ret < 0) { free_active_ring(map2); kfree(map2); clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); - spin_unlock(&bedata->socket_lock); pvcalls_exit_sock(sock); return ret; } + + spin_lock(&bedata->socket_lock); + ret = get_request(bedata, &req_id); + if (ret < 0) { + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); + pvcalls_front_free_map(bedata, map2); + pvcalls_exit_sock(sock); + return ret; + } + list_add_tail(&map2->list, &bedata->socket_mappings); req = RING_GET_REQUEST(&bedata->ring, req_id); From 1492c6b1874ac5ed57d8ffef89e2b5c59f804aa8 Mon Sep 17 00:00:00 2001 From: Henry Willard Date: Wed, 12 Apr 2023 15:29:53 -0600 Subject: [PATCH 175/182] MIPS: Don't clear _PAGE_SPECIAL in _PAGE_CHG_MASK In the special case where p = mmap(NULL, ALLOC_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); is followed by rc = mprotect(p, ALLOC_SIZE, PROT_NONE); the _PAGE_SPECIAL bit in the page tables will be cleared by mistake and the later unmapped operations will incorrectly modify the struct page for the the zero page. This sequence occurs in the madvise05 test of the Linux Test Project suite of tests. This was discovered while testing an older version of the kernel (5.4.17) on a MIPS device. Unfortunately, support for this device is not available in newer kernels, so I can't test this with the latest Linux kernel code. It looks like the problem exists in newer kernels, but I can't verify it. Except for the LTP test, this sequence of calls is probably not common. Passing it along in the hope it will be useful to someone. Signed-off-by: Henry Willard Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/pgtable-bits.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index 2362842ee2b5..1c576679aa87 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -280,6 +280,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) #define __WRITEABLE (_PAGE_SILENT_WRITE | _PAGE_WRITE | _PAGE_MODIFIED) #define _PAGE_CHG_MASK (_PAGE_ACCESSED | _PAGE_MODIFIED | \ - _PAGE_SOFT_DIRTY | _PFN_MASK | _CACHE_MASK) + _PAGE_SOFT_DIRTY | _PFN_MASK | \ + _CACHE_MASK | _PAGE_SPECIAL) #endif /* _ASM_PGTABLE_BITS_H */ From 46e614cc91f7bd6f7872e434e6bcfda44454aac3 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Sun, 23 Apr 2023 09:38:03 +0800 Subject: [PATCH 176/182] MIPS: uprobes: Restore thread.trap_nr thread.trap_nr is saved in arch_uprobe_pre_xol(), it should be restored in arch_uprobe_{post,abort}_xol() accordingly, actually it was only done in the post function, just do it in the abort function too, this change is similar with x86 and powerpc. Signed-off-by: Tiezhu Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/uprobes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index 6b630ed4438d..401b148f8917 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -191,6 +191,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *aup, { struct uprobe_task *utask = current->utask; + current->thread.trap_nr = utask->autask.saved_trap_nr; instruction_pointer_set(regs, utask->vaddr); } From 8bc6666f13fe1971cb870e5e0c3082435e3caa9c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Mar 2023 11:18:07 +0100 Subject: [PATCH 177/182] sh: Use generic GCC library routines The C implementations of __ashldi3(), __ashrdi3__(), and __lshrdi3() in arch/sh/lib/ are identical to the generic C implementations in lib/. Reduce duplication by switching SH to the generic versions. Update the include path in arch/sh/boot/compressed accordingly. Signed-off-by: Geert Uytterhoeven Acked-by: Palmer Dabbelt Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/74dbe68dc8e2ffb6180092f73723fe21ab692c7a.1679566500.git.geert+renesas@glider.be Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/Kconfig | 3 +++ arch/sh/boot/compressed/ashldi3.c | 4 ++-- arch/sh/lib/Makefile | 4 +--- arch/sh/lib/ashldi3.c | 30 ----------------------------- arch/sh/lib/ashrdi3.c | 32 ------------------------------- arch/sh/lib/lshrdi3.c | 30 ----------------------------- 6 files changed, 6 insertions(+), 97 deletions(-) delete mode 100644 arch/sh/lib/ashldi3.c delete mode 100644 arch/sh/lib/ashrdi3.c delete mode 100644 arch/sh/lib/lshrdi3.c diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 0665ac0add0b..d08579ac6f0b 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -21,6 +21,9 @@ config SUPERH select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST select GENERIC_IDLE_POLL_SETUP select GENERIC_IRQ_SHOW + select GENERIC_LIB_ASHLDI3 + select GENERIC_LIB_ASHRDI3 + select GENERIC_LIB_LSHRDI3 select GENERIC_PCI_IOMAP if PCI select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD diff --git a/arch/sh/boot/compressed/ashldi3.c b/arch/sh/boot/compressed/ashldi3.c index 7cebd646df83..7c1212170230 100644 --- a/arch/sh/boot/compressed/ashldi3.c +++ b/arch/sh/boot/compressed/ashldi3.c @@ -1,2 +1,2 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include "../../lib/ashldi3.c" +// SPDX-License-Identifier: GPL-2.0-or-later +#include "../../../../lib/ashldi3.c" diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index eb473d373ca4..d20a0768b31f 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile @@ -7,9 +7,7 @@ lib-y = delay.o memmove.o memchr.o \ checksum.o strlen.o div64.o div64-generic.o # Extracted from libgcc -obj-y += movmem.o ashldi3.o ashrdi3.o lshrdi3.o \ - ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o \ - udiv_qrnnd.o +obj-y += movmem.o ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o udiv_qrnnd.o udivsi3-y := udivsi3_i4i-Os.o diff --git a/arch/sh/lib/ashldi3.c b/arch/sh/lib/ashldi3.c deleted file mode 100644 index e5afe0935847..000000000000 --- a/arch/sh/lib/ashldi3.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -long long __ashldi3(long long u, word_type b) -{ - DWunion uu, w; - word_type bm; - - if (b == 0) - return u; - - uu.ll = u; - bm = 32 - b; - - if (bm <= 0) { - w.s.low = 0; - w.s.high = (unsigned int) uu.s.low << -bm; - } else { - const unsigned int carries = (unsigned int) uu.s.low >> bm; - - w.s.low = (unsigned int) uu.s.low << b; - w.s.high = ((unsigned int) uu.s.high << b) | carries; - } - - return w.ll; -} - -EXPORT_SYMBOL(__ashldi3); diff --git a/arch/sh/lib/ashrdi3.c b/arch/sh/lib/ashrdi3.c deleted file mode 100644 index ae263fbf2538..000000000000 --- a/arch/sh/lib/ashrdi3.c +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -long long __ashrdi3(long long u, word_type b) -{ - DWunion uu, w; - word_type bm; - - if (b == 0) - return u; - - uu.ll = u; - bm = 32 - b; - - if (bm <= 0) { - /* w.s.high = 1..1 or 0..0 */ - w.s.high = - uu.s.high >> 31; - w.s.low = uu.s.high >> -bm; - } else { - const unsigned int carries = (unsigned int) uu.s.high << bm; - - w.s.high = uu.s.high >> b; - w.s.low = ((unsigned int) uu.s.low >> b) | carries; - } - - return w.ll; -} - -EXPORT_SYMBOL(__ashrdi3); diff --git a/arch/sh/lib/lshrdi3.c b/arch/sh/lib/lshrdi3.c deleted file mode 100644 index 33eaa1edbc3c..000000000000 --- a/arch/sh/lib/lshrdi3.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -long long __lshrdi3(long long u, word_type b) -{ - DWunion uu, w; - word_type bm; - - if (b == 0) - return u; - - uu.ll = u; - bm = 32 - b; - - if (bm <= 0) { - w.s.high = 0; - w.s.low = (unsigned int) uu.s.high >> -bm; - } else { - const unsigned int carries = (unsigned int) uu.s.high << bm; - - w.s.high = (unsigned int) uu.s.high >> b; - w.s.low = ((unsigned int) uu.s.low >> b) | carries; - } - - return w.ll; -} - -EXPORT_SYMBOL(__lshrdi3); From e5c23bec0f121b4160dc8ca61e751e734652bd05 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Mar 2023 11:22:59 +0100 Subject: [PATCH 178/182] sh: Replace by As arch/sh/include/uapi/asm/types.h doesn't exist, sh doesn't provide any sh-specific uapi definitions, and it can just include , like most other architectures. Signed-off-by: Geert Uytterhoeven Reviewed-by: John Paul Adrian Glaubitz Link: https://lore.kernel.org/r/26932016c83c2ad350db59f5daf96117a38bbbd8.1679566927.git.geert@linux-m68k.org Signed-off-by: John Paul Adrian Glaubitz --- arch/sh/include/asm/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/include/asm/types.h b/arch/sh/include/asm/types.h index 68eb24ad2013..9b3fc923ee28 100644 --- a/arch/sh/include/asm/types.h +++ b/arch/sh/include/asm/types.h @@ -2,7 +2,7 @@ #ifndef __ASM_SH_TYPES_H #define __ASM_SH_TYPES_H -#include +#include /* * These aren't exported outside the kernel to avoid name space clashes From 6935321eccf32555e6f7e6d29f4cccf84a5c1e3a Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 12 Dec 2022 09:41:34 +0100 Subject: [PATCH 179/182] xen/blkback: fix white space code style issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juergen Gross Acked-by: Roger Pau Monné Signed-off-by: Juergen Gross --- drivers/block/xen-blkback/blkback.c | 2 +- drivers/block/xen-blkback/common.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index a5cf7f1e871c..6e2163aaf362 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -891,7 +891,7 @@ next: out: for (i = last_map; i < num; i++) { /* Don't zap current batch's valid persistent grants. */ - if(i >= map_until) + if (i >= map_until) pages[i]->persistent_gnt = NULL; pages[i]->handle = BLKBACK_INVALID_HANDLE; } diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index a28473470e66..9a13a6b420a6 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -296,7 +296,7 @@ struct xen_blkif_ring { struct work_struct free_work; /* Thread shutdown wait queue. */ wait_queue_head_t shutdown_wq; - struct xen_blkif *blkif; + struct xen_blkif *blkif; }; struct xen_blkif { @@ -315,7 +315,7 @@ struct xen_blkif { atomic_t drain; struct work_struct free_work; - unsigned int nr_ring_pages; + unsigned int nr_ring_pages; bool multi_ref; /* All rings for this device. */ struct xen_blkif_ring *rings; @@ -329,7 +329,7 @@ struct seg_buf { }; struct grant_page { - struct page *page; + struct page *page; struct persistent_gnt *persistent_gnt; grant_handle_t handle; grant_ref_t gref; From 656f3c1d7966ea65f9b51d17db3008ce5dbb4090 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 12 Dec 2022 09:43:28 +0100 Subject: [PATCH 180/182] xen/blkback: remove stale prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no function xen_blkif_purge_persistent(), so remove its prototype from common.h. Signed-off-by: Juergen Gross Acked-by: Roger Pau Monné Signed-off-by: Juergen Gross --- drivers/block/xen-blkback/common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 9a13a6b420a6..fab8a8dee0da 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -384,7 +384,6 @@ void xen_blkif_xenbus_fini(void); irqreturn_t xen_blkif_be_int(int irq, void *dev_id); int xen_blkif_schedule(void *arg); -int xen_blkif_purge_persistent(void *arg); void xen_blkbk_free_caches(struct xen_blkif_ring *ring); int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, From e7b4c07d4b42676691f3c815f05c1bbf071dc718 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 12 Dec 2022 10:37:42 +0100 Subject: [PATCH 181/182] xen/blkback: simplify free_persistent_gnts() interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface of free_persistent_gnts() can be simplified, as there is only a single caller of free_persistent_gnts() and the 2nd and 3rd parameters are easily obtainable via the ring pointer, which is passed as the first parameter anyway. Signed-off-by: Juergen Gross Acked-by: Roger Pau Monné Signed-off-by: Juergen Gross --- drivers/block/xen-blkback/blkback.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 6e2163aaf362..243712b59a05 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -239,9 +239,9 @@ static void put_persistent_gnt(struct xen_blkif_ring *ring, atomic_dec(&ring->persistent_gnt_in_use); } -static void free_persistent_gnts(struct xen_blkif_ring *ring, struct rb_root *root, - unsigned int num) +static void free_persistent_gnts(struct xen_blkif_ring *ring) { + struct rb_root *root = &ring->persistent_gnts; struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct persistent_gnt *persistent_gnt; @@ -249,6 +249,9 @@ static void free_persistent_gnts(struct xen_blkif_ring *ring, struct rb_root *ro int segs_to_unmap = 0; struct gntab_unmap_queue_data unmap_data; + if (RB_EMPTY_ROOT(root)) + return; + unmap_data.pages = pages; unmap_data.unmap_ops = unmap; unmap_data.kunmap_ops = NULL; @@ -277,9 +280,11 @@ static void free_persistent_gnts(struct xen_blkif_ring *ring, struct rb_root *ro rb_erase(&persistent_gnt->node, root); kfree(persistent_gnt); - num--; + ring->persistent_gnt_c--; } - BUG_ON(num != 0); + + BUG_ON(!RB_EMPTY_ROOT(&ring->persistent_gnts)); + BUG_ON(ring->persistent_gnt_c != 0); } void xen_blkbk_unmap_purged_grants(struct work_struct *work) @@ -631,12 +636,7 @@ purge_gnt_list: void xen_blkbk_free_caches(struct xen_blkif_ring *ring) { /* Free all persistent grant pages */ - if (!RB_EMPTY_ROOT(&ring->persistent_gnts)) - free_persistent_gnts(ring, &ring->persistent_gnts, - ring->persistent_gnt_c); - - BUG_ON(!RB_EMPTY_ROOT(&ring->persistent_gnts)); - ring->persistent_gnt_c = 0; + free_persistent_gnts(ring); /* Since we are shutting down remove all pages from the buffer */ gnttab_page_cache_shrink(&ring->free_pages, 0 /* All */); From cbfac7707ba16619006a4fd60faac46303fd2f3e Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 16 Dec 2022 14:49:18 +0100 Subject: [PATCH 182/182] xen/blkback: move blkif_get_x86_*_req() into blkback.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to have the functions blkif_get_x86_32_req() and blkif_get_x86_64_req() in a header file, as they are used in one place only. So move them into the using source file and drop the inline qualifier. While at it fix some style issues, and simplify the code by variable reusing and using min() instead of open coding it. Instead of using barrier() use READ_ONCE() for avoiding multiple reads of nr_segments. Signed-off-by: Juergen Gross Acked-by: Roger Pau Monné Signed-off-by: Juergen Gross --- drivers/block/xen-blkback/blkback.c | 104 ++++++++++++++++++++++++++++ drivers/block/xen-blkback/common.h | 96 ------------------------- 2 files changed, 104 insertions(+), 96 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 243712b59a05..c362f4ad80ab 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1072,7 +1072,111 @@ static void end_block_io_op(struct bio *bio) bio_put(bio); } +static void blkif_get_x86_32_req(struct blkif_request *dst, + const struct blkif_x86_32_request *src) +{ + unsigned int i, n; + dst->operation = READ_ONCE(src->operation); + + switch (dst->operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = READ_ONCE(src->u.rw.nr_segments); + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; + dst->u.rw.sector_number = src->u.rw.sector_number; + n = min_t(unsigned int, BLKIF_MAX_SEGMENTS_PER_REQUEST, + dst->u.rw.nr_segments); + for (i = 0; i < n; i++) + dst->u.rw.seg[i] = src->u.rw.seg[i]; + break; + + case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; + dst->u.discard.id = src->u.discard.id; + dst->u.discard.sector_number = src->u.discard.sector_number; + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + + case BLKIF_OP_INDIRECT: + dst->u.indirect.indirect_op = src->u.indirect.indirect_op; + dst->u.indirect.nr_segments = + READ_ONCE(src->u.indirect.nr_segments); + dst->u.indirect.handle = src->u.indirect.handle; + dst->u.indirect.id = src->u.indirect.id; + dst->u.indirect.sector_number = src->u.indirect.sector_number; + n = min(MAX_INDIRECT_PAGES, + INDIRECT_PAGES(dst->u.indirect.nr_segments)); + for (i = 0; i < n; i++) + dst->u.indirect.indirect_grefs[i] = + src->u.indirect.indirect_grefs[i]; + break; + + default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; + break; + } +} + +static void blkif_get_x86_64_req(struct blkif_request *dst, + const struct blkif_x86_64_request *src) +{ + unsigned int i, n; + + dst->operation = READ_ONCE(src->operation); + + switch (dst->operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = READ_ONCE(src->u.rw.nr_segments); + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; + dst->u.rw.sector_number = src->u.rw.sector_number; + n = min_t(unsigned int, BLKIF_MAX_SEGMENTS_PER_REQUEST, + dst->u.rw.nr_segments); + for (i = 0; i < n; i++) + dst->u.rw.seg[i] = src->u.rw.seg[i]; + break; + + case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; + dst->u.discard.id = src->u.discard.id; + dst->u.discard.sector_number = src->u.discard.sector_number; + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + + case BLKIF_OP_INDIRECT: + dst->u.indirect.indirect_op = src->u.indirect.indirect_op; + dst->u.indirect.nr_segments = + READ_ONCE(src->u.indirect.nr_segments); + dst->u.indirect.handle = src->u.indirect.handle; + dst->u.indirect.id = src->u.indirect.id; + dst->u.indirect.sector_number = src->u.indirect.sector_number; + n = min(MAX_INDIRECT_PAGES, + INDIRECT_PAGES(dst->u.indirect.nr_segments)); + for (i = 0; i < n; i++) + dst->u.indirect.indirect_grefs[i] = + src->u.indirect.indirect_grefs[i]; + break; + + default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; + break; + } +} /* * Function to copy the from the ring buffer the 'struct blkif_request' diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index fab8a8dee0da..40f67bfc052d 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -394,100 +394,4 @@ int xen_blkbk_barrier(struct xenbus_transaction xbt, struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be); void xen_blkbk_unmap_purged_grants(struct work_struct *work); -static inline void blkif_get_x86_32_req(struct blkif_request *dst, - struct blkif_x86_32_request *src) -{ - int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j; - dst->operation = READ_ONCE(src->operation); - switch (dst->operation) { - case BLKIF_OP_READ: - case BLKIF_OP_WRITE: - case BLKIF_OP_WRITE_BARRIER: - case BLKIF_OP_FLUSH_DISKCACHE: - dst->u.rw.nr_segments = src->u.rw.nr_segments; - dst->u.rw.handle = src->u.rw.handle; - dst->u.rw.id = src->u.rw.id; - dst->u.rw.sector_number = src->u.rw.sector_number; - barrier(); - if (n > dst->u.rw.nr_segments) - n = dst->u.rw.nr_segments; - for (i = 0; i < n; i++) - dst->u.rw.seg[i] = src->u.rw.seg[i]; - break; - case BLKIF_OP_DISCARD: - dst->u.discard.flag = src->u.discard.flag; - dst->u.discard.id = src->u.discard.id; - dst->u.discard.sector_number = src->u.discard.sector_number; - dst->u.discard.nr_sectors = src->u.discard.nr_sectors; - break; - case BLKIF_OP_INDIRECT: - dst->u.indirect.indirect_op = src->u.indirect.indirect_op; - dst->u.indirect.nr_segments = src->u.indirect.nr_segments; - dst->u.indirect.handle = src->u.indirect.handle; - dst->u.indirect.id = src->u.indirect.id; - dst->u.indirect.sector_number = src->u.indirect.sector_number; - barrier(); - j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments)); - for (i = 0; i < j; i++) - dst->u.indirect.indirect_grefs[i] = - src->u.indirect.indirect_grefs[i]; - break; - default: - /* - * Don't know how to translate this op. Only get the - * ID so failure can be reported to the frontend. - */ - dst->u.other.id = src->u.other.id; - break; - } -} - -static inline void blkif_get_x86_64_req(struct blkif_request *dst, - struct blkif_x86_64_request *src) -{ - int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j; - dst->operation = READ_ONCE(src->operation); - switch (dst->operation) { - case BLKIF_OP_READ: - case BLKIF_OP_WRITE: - case BLKIF_OP_WRITE_BARRIER: - case BLKIF_OP_FLUSH_DISKCACHE: - dst->u.rw.nr_segments = src->u.rw.nr_segments; - dst->u.rw.handle = src->u.rw.handle; - dst->u.rw.id = src->u.rw.id; - dst->u.rw.sector_number = src->u.rw.sector_number; - barrier(); - if (n > dst->u.rw.nr_segments) - n = dst->u.rw.nr_segments; - for (i = 0; i < n; i++) - dst->u.rw.seg[i] = src->u.rw.seg[i]; - break; - case BLKIF_OP_DISCARD: - dst->u.discard.flag = src->u.discard.flag; - dst->u.discard.id = src->u.discard.id; - dst->u.discard.sector_number = src->u.discard.sector_number; - dst->u.discard.nr_sectors = src->u.discard.nr_sectors; - break; - case BLKIF_OP_INDIRECT: - dst->u.indirect.indirect_op = src->u.indirect.indirect_op; - dst->u.indirect.nr_segments = src->u.indirect.nr_segments; - dst->u.indirect.handle = src->u.indirect.handle; - dst->u.indirect.id = src->u.indirect.id; - dst->u.indirect.sector_number = src->u.indirect.sector_number; - barrier(); - j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments)); - for (i = 0; i < j; i++) - dst->u.indirect.indirect_grefs[i] = - src->u.indirect.indirect_grefs[i]; - break; - default: - /* - * Don't know how to translate this op. Only get the - * ID so failure can be reported to the frontend. - */ - dst->u.other.id = src->u.other.id; - break; - } -} - #endif /* __XEN_BLKIF__BACKEND__COMMON_H__ */