diff options
| author | Niklas Cassel <cassel@kernel.org> | 2026-09-16 15:00:32 +0200 |
|---|---|---|
| committer | Niklas Cassel <cassel@kernel.org> | 2026-09-16 16:18:00 +0200 |
| commit | 8d836581f9b1f57ceaa2b47654754ef1260b410b (patch) | |
| tree | 1dbd4d0dfb99c2e238356cbe947e5b0be3e3a571 /arch/mips/dec/prom | |
| download | linux-stable-8d836581f9b1f57ceaa2b47654754ef1260b410b.tar.gz linux-stable-8d836581f9b1f57ceaa2b47654754ef1260b410b.zip | |
ata: libata-scsi: fix ata_dsm_trim_pages() kernel-docgrafted
make htmldocs fails with:
Documentation/driver-api/libata:604: ./drivers/ata/libata-scsi.c:2301:
ERROR: Unexpected indentation. [docutils]
The Return: section of ata_dsm_trim_pages() ends its first sentence with
a colon and continues with an indented bullet list. reStructuredText
requires a blank line before an indented block, so docutils chokes on
the list.
Simply adding the missing blank line does not work either: Return: is a
kernel-doc "special section", which is terminated by the first blank
line, so the bullet list would end up in the Description section,
detached from the sentence introducing it.
Spell the two bounds out as prose instead, so that the Return: section
stays self-contained. Documentation-only change.
Fixes: e64e6b5dc867 ("ata: libata-scsi: scale DSM TRIM payload by MAX PAGES PER DSM COMMAND")
Reported-by: Thomas Huth <thuth@redhat.com>
Closes: https://lore.kernel.org/linux-ide/b0a0b8e8-cc4f-4c7b-8bc5-fee0712d405a@redhat.com/
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Link: https://lore.kernel.org/r/20260916130031.29990-2-cassel@kernel.org
Signed-off-by: Niklas Cassel <cassel@kernel.org>
Diffstat (limited to 'arch/mips/dec/prom')
| -rw-r--r-- | arch/mips/dec/prom/Makefile | 9 | ||||
| -rw-r--r-- | arch/mips/dec/prom/cmdline.c | 40 | ||||
| -rw-r--r-- | arch/mips/dec/prom/console.c | 44 | ||||
| -rw-r--r-- | arch/mips/dec/prom/dectypes.h | 15 | ||||
| -rw-r--r-- | arch/mips/dec/prom/identify.c | 187 | ||||
| -rw-r--r-- | arch/mips/dec/prom/init.c | 141 | ||||
| -rw-r--r-- | arch/mips/dec/prom/locore.S | 30 | ||||
| -rw-r--r-- | arch/mips/dec/prom/memory.c | 117 |
8 files changed, 583 insertions, 0 deletions
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile new file mode 100644 index 000000000..2bad87551 --- /dev/null +++ b/arch/mips/dec/prom/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the DECstation prom monitor library routines +# under Linux. +# + +lib-y += init.o memory.o cmdline.o identify.o console.o + +lib-$(CONFIG_CPU_R3000) += locore.o diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c new file mode 100644 index 000000000..3ed63280a --- /dev/null +++ b/arch/mips/dec/prom/cmdline.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cmdline.c: read the command line passed to us by the PROM. + * + * Copyright (C) 1998 Harald Koerfgen + * Copyright (C) 2002, 2004 Maciej W. Rozycki + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <asm/bootinfo.h> +#include <asm/dec/prom.h> + +#undef PROM_DEBUG + +void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic) +{ + char *arg; + int start_arg, i; + + /* + * collect args and prepare cmd_line + */ + if (!prom_is_rex(magic)) + start_arg = 1; + else + start_arg = 2; + for (i = start_arg; i < argc; i++) { + arg = (void *)(long)(argv[i]); + strcat(arcs_cmdline, arg); + if (i < (argc - 1)) + strcat(arcs_cmdline, " "); + } + +#ifdef PROM_DEBUG + printk("arcs_cmdline: %s\n", &(arcs_cmdline[0])); +#endif +} diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c new file mode 100644 index 000000000..b4f0dba3f --- /dev/null +++ b/arch/mips/dec/prom/console.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DECstation PROM-based early console support. + * + * Copyright (C) 2004, 2007, 2026 Maciej W. Rozycki + */ +#include <linux/bug.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> + +#include <asm/dec/prom.h> + +static void __init prom_console_write(struct console *con, const char *s, + unsigned int c) +{ + static char buf[81] __initdata = { 0 }; + unsigned int chunk = sizeof(buf) - 1; + + BUG_ON((long)buf != (int)(long)buf); + + while (c > 0) { + if (chunk > c) + chunk = c; + memcpy(buf, s, chunk); + buf[chunk] = '\0'; + prom_printf("%s", buf); + s += chunk; + c -= chunk; + } +} + +static struct console promcons __initdata = { + .name = "prom", + .write = prom_console_write, + .flags = CON_BOOT | CON_PRINTBUFFER, + .index = -1, +}; + +void __init register_prom_console(void) +{ + register_console(&promcons); +} diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h new file mode 100644 index 000000000..9fcbcc7cd --- /dev/null +++ b/arch/mips/dec/prom/dectypes.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef DECTYPES +#define DECTYPES + +#define DS2100_3100 1 /* DS2100/3100 Pmax */ +#define DS5000_200 2 /* DS5000/200 3max */ +#define DS5000_1XX 3 /* DS5000/1xx kmin */ +#define DS5000_2X0 4 /* DS5000/2x0 3max+ */ +#define DS5800 5 /* DS5800 Isis */ +#define DS5400 6 /* DS5400 MIPSfair */ +#define DS5000_XX 7 /* DS5000/xx maxine */ +#define DS5500 11 /* DS5500 MIPSfair-2 */ +#define DS5100 12 /* DS5100 MIPSmate */ + +#endif diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c new file mode 100644 index 000000000..80cd14cd1 --- /dev/null +++ b/arch/mips/dec/prom/identify.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * identify.c: machine identification code. + * + * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine + * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mc146818rtc.h> +#include <linux/export.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <asm/bootinfo.h> + +#include <asm/dec/ioasic.h> +#include <asm/dec/ioasic_addrs.h> +#include <asm/dec/kn01.h> +#include <asm/dec/kn02.h> +#include <asm/dec/kn02ba.h> +#include <asm/dec/kn02ca.h> +#include <asm/dec/kn03.h> +#include <asm/dec/kn230.h> +#include <asm/dec/prom.h> +#include <asm/dec/system.h> + +#include "dectypes.h" + +static const char *dec_system_strings[] = { + [MACH_DSUNKNOWN] "unknown DECstation", + [MACH_DS23100] "DECstation 2100/3100", + [MACH_DS5100] "DECsystem 5100", + [MACH_DS5000_200] "DECstation 5000/200", + [MACH_DS5000_1XX] "DECstation 5000/1xx", + [MACH_DS5000_XX] "Personal DECstation 5000/xx", + [MACH_DS5000_2X0] "DECstation 5000/2x0", + [MACH_DS5400] "DECsystem 5400", + [MACH_DS5500] "DECsystem 5500", + [MACH_DS5800] "DECsystem 5800", + [MACH_DS5900] "DECsystem 5900", +}; + +const char *get_system_type(void) +{ +#define STR_BUF_LEN 64 + static char system[STR_BUF_LEN]; + static int called = 0; + + if (called == 0) { + called = 1; + snprintf(system, STR_BUF_LEN, "Digital %s", + dec_system_strings[mips_machtype]); + } + + return system; +} + + +/* + * Setup essential system-specific memory addresses. We need them + * early. Semantically the functions belong to prom/init.c, but they + * are compact enough we want them inlined. --macro + */ +volatile u8 *dec_rtc_base; + +EXPORT_SYMBOL(dec_rtc_base); + +static inline void prom_init_kn01(void) +{ + dec_kn_slot_base = KN01_SLOT_BASE; + dec_kn_slot_size = KN01_SLOT_SIZE; + + dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN01_RTC); +} + +static inline void prom_init_kn230(void) +{ + dec_kn_slot_base = KN01_SLOT_BASE; + dec_kn_slot_size = KN01_SLOT_SIZE; + + dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN01_RTC); +} + +static inline void prom_init_kn02(void) +{ + dec_kn_slot_base = KN02_SLOT_BASE; + dec_kn_slot_size = KN02_SLOT_SIZE; + dec_tc_bus = 1; + + dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC); +} + +static inline void prom_init_kn02xa(void) +{ + dec_kn_slot_base = KN02XA_SLOT_BASE; + dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; + + ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); + dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); +} + +static inline void prom_init_kn03(void) +{ + dec_kn_slot_base = KN03_SLOT_BASE; + dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; + + ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); + dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); +} + + +void __init prom_identify_arch(u32 magic) +{ + unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype; + u32 dec_sysid; + + if (!prom_is_rex(magic)) { + dec_sysid = simple_strtoul(prom_getenv("systype"), + (char **)0, 0); + } else { + dec_sysid = rex_getsysid(); + if (dec_sysid == 0) { + printk("Zero sysid returned from PROM! " + "Assuming a PMAX-like machine.\n"); + dec_sysid = 1; + } + } + + dec_cpunum = (dec_sysid & 0xff000000) >> 24; + dec_systype = (dec_sysid & 0xff0000) >> 16; + dec_firmrev = (dec_sysid & 0xff00) >> 8; + dec_etc = dec_sysid & 0xff; + + /* + * FIXME: This may not be an exhaustive list of DECStations/Servers! + * Put all model-specific initialisation calls here. + */ + switch (dec_systype) { + case DS2100_3100: + mips_machtype = MACH_DS23100; + prom_init_kn01(); + break; + case DS5100: /* DS5100 MIPSMATE */ + mips_machtype = MACH_DS5100; + prom_init_kn230(); + break; + case DS5000_200: /* DS5000 3max */ + mips_machtype = MACH_DS5000_200; + prom_init_kn02(); + break; + case DS5000_1XX: /* DS5000/100 3min */ + mips_machtype = MACH_DS5000_1XX; + prom_init_kn02xa(); + break; + case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */ + mips_machtype = MACH_DS5000_2X0; + prom_init_kn03(); + if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP)) + mips_machtype = MACH_DS5900; + break; + case DS5000_XX: /* Personal DS5000/xx maxine */ + mips_machtype = MACH_DS5000_XX; + prom_init_kn02xa(); + break; + case DS5800: /* DS5800 Isis */ + mips_machtype = MACH_DS5800; + break; + case DS5400: /* DS5400 MIPSfair */ + mips_machtype = MACH_DS5400; + break; + case DS5500: /* DS5500 MIPSfair-2 */ + mips_machtype = MACH_DS5500; + break; + default: + mips_machtype = MACH_DSUNKNOWN; + break; + } + + if (mips_machtype == MACH_DSUNKNOWN) + printk("This is an %s, id is %x\n", + dec_system_strings[mips_machtype], dec_systype); + else + printk("This is a %s\n", dec_system_strings[mips_machtype]); +} diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c new file mode 100644 index 000000000..e46c7acce --- /dev/null +++ b/arch/mips/dec/prom/init.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * init.c: PROM library initialisation code. + * + * Copyright (C) 1998 Harald Koerfgen + * Copyright (C) 2002, 2004, 2026 Maciej W. Rozycki + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/smp.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/cpu-type.h> +#include <asm/processor.h> + +#include <asm/dec/prom.h> + + +#ifdef CONFIG_64BIT +unsigned long o32_stk[O32_STK_SIZE] __initdata = { 0 }; +#endif + +int (*__rex_bootinit)(void); +int (*__rex_bootread)(void); +int (*__rex_getbitmap)(memmap *); +unsigned long *(*__rex_slot_address)(int); +void *(*__rex_gettcinfo)(void); +int (*__rex_getsysid)(void); +void (*__rex_clear_cache)(void); + +int (*__prom_getchar)(void); +char *(*__prom_getenv)(char *); +int (*__prom_printf)(char *, ...); + +int (*__pmax_open)(char*, int); +int (*__pmax_lseek)(int, long, int); +int (*__pmax_read)(int, void *, int); +int (*__pmax_close)(int); + + +/* + * Detect which PROM the DECSTATION has, and set the callback vectors + * appropriately. + */ +static void __init which_prom(s32 magic, s32 *prom_vec) +{ + /* + * No sign of the REX PROM's magic number means we assume a non-REX + * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx) + */ + if (prom_is_rex(magic)) { + /* + * Set up prom abstraction structure with REX entry points. + */ + __rex_bootinit = + (void *)(long)*(prom_vec + REX_PROM_BOOTINIT); + __rex_bootread = + (void *)(long)*(prom_vec + REX_PROM_BOOTREAD); + __rex_getbitmap = + (void *)(long)*(prom_vec + REX_PROM_GETBITMAP); + __prom_getchar = + (void *)(long)*(prom_vec + REX_PROM_GETCHAR); + __prom_getenv = + (void *)(long)*(prom_vec + REX_PROM_GETENV); + __rex_getsysid = + (void *)(long)*(prom_vec + REX_PROM_GETSYSID); + __rex_gettcinfo = + (void *)(long)*(prom_vec + REX_PROM_GETTCINFO); + __prom_printf = + (void *)(long)*(prom_vec + REX_PROM_PRINTF); + __rex_slot_address = + (void *)(long)*(prom_vec + REX_PROM_SLOTADDR); + __rex_clear_cache = + (void *)(long)*(prom_vec + REX_PROM_CLEARCACHE); + } else { + /* + * Set up prom abstraction structure with non-REX entry points. + */ + __prom_getchar = (void *)PMAX_PROM_GETCHAR; + __prom_getenv = (void *)PMAX_PROM_GETENV; + __prom_printf = (void *)PMAX_PROM_PRINTF; + __pmax_open = (void *)PMAX_PROM_OPEN; + __pmax_lseek = (void *)PMAX_PROM_LSEEK; + __pmax_read = (void *)PMAX_PROM_READ; + __pmax_close = (void *)PMAX_PROM_CLOSE; + } +} + +void __init prom_init(void) +{ + extern void dec_machine_halt(void); + static const char cpu_msg[] __initconst = + "Sorry, this kernel is compiled for a wrong CPU type!\n"; + s32 argc = fw_arg0; + s32 *argv = (void *)fw_arg1; + u32 magic = fw_arg2; + s32 *prom_vec = (void *)fw_arg3; + + /* + * Determine which PROM we have + * (and therefore which machine we're on!) + */ + which_prom(magic, prom_vec); + + if (prom_is_rex(magic)) + rex_clear_cache(); + + /* Register the early console. */ + register_prom_console(); + + /* Were we compiled with the right CPU option? */ +#if defined(CONFIG_CPU_R3000) + if ((current_cpu_type() == CPU_R4000SC) || + (current_cpu_type() == CPU_R4400SC)) { + static const char r4k_msg[] __initconst = + "Please recompile with \"CONFIG_CPU_R4X00 = y\".\n"; + printk(cpu_msg); + printk(r4k_msg); + dec_machine_halt(); + } +#endif + +#if defined(CONFIG_CPU_R4X00) + if ((current_cpu_type() == CPU_R3000) || + (current_cpu_type() == CPU_R3000A)) { + static const char r3k_msg[] __initconst = + "Please recompile with \"CONFIG_CPU_R3000 = y\".\n"; + printk(cpu_msg); + printk(r3k_msg); + dec_machine_halt(); + } +#endif + + prom_meminit(magic); + prom_identify_arch(magic); + prom_init_cmdline(argc, argv, magic); +} diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S new file mode 100644 index 000000000..0eb8fab62 --- /dev/null +++ b/arch/mips/dec/prom/locore.S @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * locore.S + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> + + .text + +/* + * Simple general exception handling routine. This one is used for the + * Memory sizing routine for pmax machines. HK + */ + +NESTED(genexcept_early, 0, sp) + .set noat + .set noreorder + + mfc0 k0, CP0_STATUS + la k1, mem_err + + sw k0, 0(k1) + + mfc0 k0, CP0_EPC + nop + addiu k0, 4 # skip the causing instruction + jr k0 + rfe +END(genexcept_early) diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c new file mode 100644 index 000000000..44490c30d --- /dev/null +++ b/arch/mips/dec/prom/memory.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * memory.c: memory initialisation code. + * + * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine + * Copyright (C) 2000, 2002 Maciej W. Rozycki + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/memblock.h> +#include <linux/types.h> + +#include <asm/addrspace.h> +#include <asm/dec/machtype.h> +#include <asm/dec/prom.h> +#include <asm/page.h> +#include <asm/sections.h> + + +volatile unsigned long mem_err; /* So we know an error occurred */ + +/* + * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen + * off the end of real memory. Only suitable for the 2100/3100's (PMAX). + */ + +#define CHUNK_SIZE 0x400000 + +static __init void pmax_setup_memory_region(void) +{ + volatile unsigned char *memory_page, dummy; + char old_handler[0x80]; + extern char genexcept_early; + + /* Install exception handler */ + memcpy(&old_handler, (void *)(CKSEG0 + 0x80), 0x80); + memcpy((void *)(CKSEG0 + 0x80), &genexcept_early, 0x80); + + /* read unmapped and uncached (KSEG1) + * DECstations have at least 4MB RAM + * Assume less than 480MB of RAM, as this is max for 5000/2xx + * FIXME this should be replaced by the first free page! + */ + for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE; + mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000; + memory_page += CHUNK_SIZE) { + dummy = *memory_page; + } + memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80); + + memblock_add(0, (unsigned long)memory_page - CKSEG1 - CHUNK_SIZE); +} + +/* + * Use the REX prom calls to get hold of the memory bitmap, and thence + * determine memory size. + */ +static __init void rex_setup_memory_region(void) +{ + int i, bitmap_size; + unsigned long mem_start = 0, mem_size = 0; + memmap *bm; + + /* some free 64k */ + bm = (memmap *)CKSEG0ADDR(0x28000); + + bitmap_size = rex_getbitmap(bm); + + for (i = 0; i < bitmap_size; i++) { + /* FIXME: very simplistically only add full sets of pages */ + if (bm->bitmap[i] == 0xff) + mem_size += (8 * bm->pagesize); + else if (!mem_size) + mem_start += (8 * bm->pagesize); + else { + memblock_add(mem_start, mem_size); + mem_start += mem_size + (8 * bm->pagesize); + mem_size = 0; + } + } + if (mem_size) + memblock_add(mem_start, mem_size); +} + +void __init prom_meminit(u32 magic) +{ + if (!prom_is_rex(magic)) + pmax_setup_memory_region(); + else + rex_setup_memory_region(); +} + +void __init prom_free_prom_memory(void) +{ + unsigned long end; + + /* + * Free everything below the kernel itself but leave + * the first page reserved for the exception handlers. + */ + +#if IS_ENABLED(CONFIG_DECLANCE) + /* + * Leave 128 KB reserved for Lance memory for + * IOASIC DECstations. + * + * XXX: save this address for use in dec_lance.c? + */ + if (IOASIC) + end = __pa(&_text) - 0x00020000; + else +#endif + end = __pa(&_text); + + free_init_pages("unused PROM memory", PAGE_SIZE, end); +} |
