From 1e7aaefa7791f40be6e4300817bd63600caba456 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Mon, 6 Jun 2011 19:38:24 +0800 Subject: [PATCH] i386: Allow UP kernel to use LAPIC timer and I/O APIC --- sys/bus/pci/pci_pci.c | 8 +---- sys/platform/pc32/acpica5/acpi_machdep.c | 45 +++++------------------- sys/platform/pc32/apic/apic_vector.s | 3 ++ sys/platform/pc32/apic/ioapic_abi.c | 1 + sys/platform/pc32/apic/ioapic_abi.h | 4 --- sys/platform/pc32/apic/ioapic_ipl.h | 4 --- sys/platform/pc32/apic/lapic.c | 22 +++++++++--- sys/platform/pc32/apic/lapic.h | 23 ++++++------ sys/platform/pc32/conf/files | 18 +++++----- sys/platform/pc32/i386/ipl.s | 10 +++--- sys/platform/pc32/i386/machdep.c | 3 +- sys/platform/pc32/i386/nexus.c | 31 ++++++++-------- sys/platform/pc32/icu/icu.c | 6 ---- sys/platform/pc32/icu/icu_abi.c | 3 -- sys/platform/pc32/icu/icu_var.h | 2 -- sys/platform/pc32/include/intr_machdep.h | 16 ++++----- sys/platform/pc32/isa/clock.c | 24 +++---------- 17 files changed, 83 insertions(+), 140 deletions(-) diff --git a/sys/bus/pci/pci_pci.c b/sys/bus/pci/pci_pci.c index 81659cc6fb..4847f3a340 100644 --- a/sys/bus/pci/pci_pci.c +++ b/sys/bus/pci/pci_pci.c @@ -126,13 +126,7 @@ pcib_probe(device_t dev) if ((pci_get_class(dev) == PCIC_BRIDGE) && (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { device_set_desc(dev, "PCI-PCI bridge"); -#if defined(__i386__) -#ifdef SMP - /* PCIBIOS PCI-PCI bridge is -2000 */ - if (ioapic_enable) - return (-1000); -#endif -#elif defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) /* PCIBIOS PCI-PCI bridge is -2000 */ if (ioapic_enable) return (-1000); diff --git a/sys/platform/pc32/acpica5/acpi_machdep.c b/sys/platform/pc32/acpica5/acpi_machdep.c index 176bff963b..cd6e060482 100644 --- a/sys/platform/pc32/acpica5/acpi_machdep.c +++ b/sys/platform/pc32/acpica5/acpi_machdep.c @@ -56,15 +56,6 @@ static device_t acpi_dev; uint32_t acpi_reset_video = 1; TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video); -/* - * -1 == unset. Use acpi_GetDefaultIntrModel() - */ -#ifdef SMP /* APIC-IO */ -static int intr_model = -1; -#else -static int intr_model = ACPI_INTR_PIC; -#endif - static struct apm_softc apm_softc; static d_open_t apmopen; @@ -331,29 +322,11 @@ acpi_capm_init(struct acpi_softc *sc) kprintf("Warning: ACPI is disabling APM's device. You can't run both\n"); } -/* - * Lazy initialize intr_model - */ -static int -acpi_GetDefaultIntrModel(void) -{ - if (intr_model == -1) { -#ifdef SMP - if (ioapic_enable) - intr_model = ACPI_INTR_APIC; - else - intr_model = ACPI_INTR_PIC; -#else - intr_model = ACPI_INTR_PIC; -#endif - } - return intr_model; -} - int acpi_machdep_init(device_t dev) { struct acpi_softc *sc; + int intr_model; acpi_dev = dev; sc = device_get_softc(acpi_dev); @@ -368,8 +341,13 @@ acpi_machdep_init(device_t dev) acpi_install_wakeup_handler(sc); - if (acpi_GetDefaultIntrModel() != ACPI_INTR_PIC) - acpi_SetIntrModel(acpi_GetDefaultIntrModel()); + if (ioapic_enable) + intr_model = ACPI_INTR_APIC; + else + intr_model = ACPI_INTR_PIC; + + if (intr_model != ACPI_INTR_PIC) + acpi_SetIntrModel(intr_model); SYSCTL_ADD_UINT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, @@ -378,10 +356,3 @@ acpi_machdep_init(device_t dev) return (0); } - -void -acpi_SetDefaultIntrModel(int model) -{ - - intr_model = model; -} diff --git a/sys/platform/pc32/apic/apic_vector.s b/sys/platform/pc32/apic/apic_vector.s index 07c42a81da..1f4f29709e 100644 --- a/sys/platform/pc32/apic/apic_vector.s +++ b/sys/platform/pc32/apic/apic_vector.s @@ -183,6 +183,7 @@ Xspuriousint: iret +#ifdef SMP /* * Handle TLB shootdowns. @@ -323,6 +324,8 @@ Xipiq: MEXITCOUNT jmp doreti_syscall_ret +#endif /* SMP */ + .text SUPERALIGN_TEXT .globl Xtimer diff --git a/sys/platform/pc32/apic/ioapic_abi.c b/sys/platform/pc32/apic/ioapic_abi.c index 9f32fbef6a..1f3bf2d2f5 100644 --- a/sys/platform/pc32/apic/ioapic_abi.c +++ b/sys/platform/pc32/apic/ioapic_abi.c @@ -60,6 +60,7 @@ #include #include #include +#include extern inthand_t IDTVEC(ioapic_intr0), diff --git a/sys/platform/pc32/apic/ioapic_abi.h b/sys/platform/pc32/apic/ioapic_abi.h index ea6916245e..c8ba181d4b 100644 --- a/sys/platform/pc32/apic/ioapic_abi.h +++ b/sys/platform/pc32/apic/ioapic_abi.h @@ -66,8 +66,6 @@ struct apic_intmapinfo { extern struct apic_intmapinfo int_to_apicintpin[]; -#ifdef SMP /* APIC_IO */ - extern struct machintr_abi MachIntrABI_IOAPIC; int ioapic_abi_extint_irqmap(int); @@ -77,6 +75,4 @@ void ioapic_abi_fixup_irqmap(void); int ioapic_abi_find_gsi(int, enum intr_trigger, enum intr_polarity); int ioapic_abi_find_irq(int, enum intr_trigger, enum intr_polarity); -#endif /* SMP */ - #endif /* !_ARCH_APIC_IOAPIC_ABI_H_ */ diff --git a/sys/platform/pc32/apic/ioapic_ipl.h b/sys/platform/pc32/apic/ioapic_ipl.h index 01ce1cab7f..fcdd88faec 100644 --- a/sys/platform/pc32/apic/ioapic_ipl.h +++ b/sys/platform/pc32/apic/ioapic_ipl.h @@ -29,12 +29,8 @@ #ifndef _ARCH_APIC_IOAPIC_IPL_H_ #define _ARCH_APIC_IOAPIC_IPL_H_ -#ifdef SMP /* APIC-IO */ - #define IOAPIC_HWI_VECTORS 192 -#endif - #ifdef LOCORE /* diff --git a/sys/platform/pc32/apic/lapic.c b/sys/platform/pc32/apic/lapic.c index 2af9ca8c21..fe607439a0 100644 --- a/sys/platform/pc32/apic/lapic.c +++ b/sys/platform/pc32/apic/lapic.c @@ -113,6 +113,11 @@ lapic_init(boolean_t bsp) setidt(XSPURIOUSINT_OFFSET, Xspuriousint, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* Install a timer vector */ + setidt(XTIMER_OFFSET, Xtimer, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + +#ifdef SMP /* Install an inter-CPU IPI for TLB invalidation */ setidt(XINVLTLB_OFFSET, Xinvltlb, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -121,13 +126,10 @@ lapic_init(boolean_t bsp) setidt(XIPIQ_OFFSET, Xipiq, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - /* Install a timer vector */ - setidt(XTIMER_OFFSET, Xtimer, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - /* Install an inter-CPU IPI for CPU stop/restart */ setidt(XCPUSTOP_OFFSET, Xcpustop, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#endif } /* @@ -409,14 +411,22 @@ lapic_timer_restart_handler(void *dummy __unused) static void lapic_timer_intr_pmfixup(struct cputimer_intr *cti __unused) { +#ifdef SMP lwkt_send_ipiq_mask(smp_active_mask, lapic_timer_fixup_handler, NULL); +#else + lapic_timer_fixup_handler(NULL); +#endif } static void lapic_timer_intr_restart(struct cputimer_intr *cti __unused) { +#ifdef SMP lwkt_send_ipiq_mask(smp_active_mask, lapic_timer_restart_handler, NULL); +#else + lapic_timer_restart_handler(NULL); +#endif } @@ -431,6 +441,8 @@ apic_dump(char* str) lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr); } +#ifdef SMP + /* * Inter Processor Interrupt functions. */ @@ -557,6 +569,8 @@ selected_apic_ipi(cpumask_t target, int vector, int delivery_mode) crit_exit(); } +#endif /* SMP */ + /* * Timer code, in development... * - suggested by rgrimes@gndrsh.aac.dev.com diff --git a/sys/platform/pc32/apic/lapic.h b/sys/platform/pc32/apic/lapic.h index 759caa22d0..385e3a1bb3 100644 --- a/sys/platform/pc32/apic/lapic.h +++ b/sys/platform/pc32/apic/lapic.h @@ -51,8 +51,6 @@ struct lapic_enumerator { #define LAPIC_ENUM_PRIO_MPTABLE 20 #define LAPIC_ENUM_PRIO_MADT 40 -#ifdef SMP - extern volatile lapic_t *lapic; extern int cpu_id_to_apic_id[]; extern int apic_id_to_cpu_id[]; @@ -60,10 +58,6 @@ extern int lapic_enable; void apic_dump(char*); void lapic_init(boolean_t); -int apic_ipi(int, int, int); -void selected_apic_ipi(cpumask_t, int, int); -void single_apic_ipi(int, int, int); -int single_apic_ipi_passive(int, int, int); void lapic_set_cpuid(int, int); int lapic_config(void); void lapic_enumerator_register(struct lapic_enumerator *); @@ -72,6 +66,17 @@ int get_apic_timer_frequency(void); int read_apic_timer(void); void u_sleep(int); +void lapic_map(vm_offset_t /* XXX should be vm_paddr_t */); +int lapic_unused_apic_id(int); +void lapic_fixup_noioapic(void); + +#ifdef SMP + +int apic_ipi(int, int, int); +void selected_apic_ipi(cpumask_t, int, int); +void single_apic_ipi(int, int, int); +int single_apic_ipi_passive(int, int, int); + /* * Send an IPI INTerrupt containing 'vector' to all CPUs EXCEPT myself */ @@ -83,10 +88,6 @@ all_but_self_ipi(int vector) return apic_ipi(APIC_DEST_ALLESELF, vector, APIC_DELMODE_FIXED); } -#endif - -void lapic_map(vm_offset_t /* XXX should be vm_paddr_t */); -int lapic_unused_apic_id(int); -void lapic_fixup_noioapic(void); +#endif /* SMP */ #endif /* _ARCH_APIC_LAPIC_H_ */ diff --git a/sys/platform/pc32/conf/files b/sys/platform/pc32/conf/files index a948f1522f..60c864b34d 100644 --- a/sys/platform/pc32/conf/files +++ b/sys/platform/pc32/conf/files @@ -193,19 +193,17 @@ platform/pc32/icu/icu_abi.c standard platform/pc32/icu/icu_ipl.s standard platform/pc32/icu/icu_vector.s standard platform/pc32/icu/elcr.c standard -platform/pc32/apic/lapic.c optional smp -platform/pc32/apic/ioapic.c optional smp -platform/pc32/apic/ioapic_abi.c optional smp -platform/pc32/apic/ioapic_ipl.s optional smp -platform/pc32/apic/apic_vector.s optional smp +platform/pc32/apic/lapic.c standard +platform/pc32/apic/ioapic.c standard +platform/pc32/apic/ioapic_abi.c standard +platform/pc32/apic/ioapic_ipl.s standard +platform/pc32/apic/apic_vector.s standard platform/pc32/i386/est.c optional cpu_enable_est # temporarily not in build until we get the 'apic' option working on UP -#arch/i386/i386/io_apic.c optional smp -#arch/i386/i386/local_apic.c optional smp platform/pc32/i386/mpboot.s optional smp platform/pc32/i386/mp_clock.c optional smp platform/pc32/i386/mp_machdep.c optional smp -platform/pc32/i386/mptable.c optional smp +platform/pc32/i386/mptable.c standard platform/pc32/i386/nexus.c standard platform/pc32/i386/p4tcc.c optional cpu_enable_tcc platform/pc32/i386/perfmon.c optional perfmon @@ -227,7 +225,7 @@ platform/pc32/i386/vm_machdep.c standard platform/pc32/i386/cpufreq_machdep.c standard platform/pc32/acpica5/acpi_sdt.c standard platform/pc32/acpica5/acpi_fadt.c standard -platform/pc32/acpica5/acpi_madt.c optional smp +platform/pc32/acpica5/acpi_madt.c standard platform/pc32/isa/asc.c optional asc platform/pc32/isa/clock.c standard nowerror dev/video/ctx/ctx.c optional ctx @@ -255,7 +253,7 @@ bus/pci/i386/legacy.c optional pci bus/pci/i386/pci_bus.c optional pci bus/pci/i386/pci_cfgreg.c optional pci bus/pci/i386/pci_pir.c optional pci -bus/pci/i386/mptable_pci.c optional pci smp +bus/pci/i386/mptable_pci.c optional pci platform/pc32/isa/pmtimer.c optional pmtimer acpi # XXX drhodus platform/pc32/isa/prof_machdep.c optional profiling-routine diff --git a/sys/platform/pc32/i386/ipl.s b/sys/platform/pc32/i386/ipl.s index b01dfa5c14..6c6d06dbb6 100644 --- a/sys/platform/pc32/i386/ipl.s +++ b/sys/platform/pc32/i386/ipl.s @@ -119,9 +119,9 @@ doreti_next: #ifdef SMP testl $RQF_IPIQ,PCPU(reqflags) jnz doreti_ipiq +#endif testl $RQF_TIMER,PCPU(reqflags) jnz doreti_timer -#endif /* * check for an unmasked int (6 groups) */ @@ -318,6 +318,7 @@ doreti_ipiq: decl PCPU(intr_nesting_level) movl %esi,%eax /* restore cpl for loop */ jmp doreti_next +#endif doreti_timer: movl %eax,%esi /* save cpl (can't use stack) */ @@ -332,8 +333,6 @@ doreti_timer: movl %esi,%eax /* restore cpl for loop */ jmp doreti_next -#endif - /* * SPLZ() a C callable procedure to dispatch any unmasked pending * interrupts regardless of critical section nesting. ASTs @@ -358,9 +357,10 @@ splz_next: #ifdef SMP testl $RQF_IPIQ,PCPU(reqflags) jnz splz_ipiq +#endif testl $RQF_TIMER,PCPU(reqflags) jnz splz_timer -#endif + /* * check for an unmasked int (6 groups) */ @@ -460,6 +460,7 @@ splz_ipiq: call lwkt_process_ipiq popl %eax jmp splz_next +#endif splz_timer: andl $~RQF_TIMER,PCPU(reqflags) @@ -468,7 +469,6 @@ splz_timer: call lapic_timer_process popl %eax jmp splz_next -#endif /* * dofastunpend(%ecx:intr) diff --git a/sys/platform/pc32/i386/machdep.c b/sys/platform/pc32/i386/machdep.c index 8d3046b22a..78711181d4 100644 --- a/sys/platform/pc32/i386/machdep.c +++ b/sys/platform/pc32/i386/machdep.c @@ -1948,11 +1948,10 @@ init386(int first) * Default MachIntrABI to ICU */ MachIntrABI = MachIntrABI_ICU; -#ifdef SMP + TUNABLE_INT_FETCH("hw.apic_io_enable", &ioapic_enable); /* for compat */ TUNABLE_INT_FETCH("hw.ioapic_enable", &ioapic_enable); TUNABLE_INT_FETCH("hw.lapic_enable", &lapic_enable); -#endif /* * start with one cpu. Note: with one cpu, ncpus2_shift, ncpus2_mask, diff --git a/sys/platform/pc32/i386/nexus.c b/sys/platform/pc32/i386/nexus.c index c83b9dd4e0..d2a83f0282 100644 --- a/sys/platform/pc32/i386/nexus.c +++ b/sys/platform/pc32/i386/nexus.c @@ -164,23 +164,20 @@ nexus_probe(device_t dev) irq_rman.rm_type = RMAN_ARRAY; irq_rman.rm_descr = "Interrupt request lines"; -#if SMP -if (ioapic_enable) { - irq_rman.rm_end = APIC_INTMAPSIZE - 1; - if (rman_init(&irq_rman) - || rman_manage_region(&irq_rman, - irq_rman.rm_start, irq_rman.rm_end)) - panic("nexus_probe irq_rman"); -} else { -#endif - irq_rman.rm_end = 15; - if (rman_init(&irq_rman) - || rman_manage_region(&irq_rman, irq_rman.rm_start, 1) - || rman_manage_region(&irq_rman, 3, irq_rman.rm_end)) - panic("nexus_probe irq_rman"); -#if SMP -} -#endif + if (ioapic_enable) { + irq_rman.rm_end = APIC_INTMAPSIZE - 1; + if (rman_init(&irq_rman) + || rman_manage_region(&irq_rman, + irq_rman.rm_start, irq_rman.rm_end)) + panic("nexus_probe irq_rman"); + } else { + irq_rman.rm_end = 15; + if (rman_init(&irq_rman) + || rman_manage_region(&irq_rman, irq_rman.rm_start, 1) + || rman_manage_region(&irq_rman, 3, irq_rman.rm_end)) + panic("nexus_probe irq_rman"); + } + /* * ISA DMA on PCI systems is implemented in the ISA part of each * PCI->ISA bridge and the channels can be duplicated if there are diff --git a/sys/platform/pc32/icu/icu.c b/sys/platform/pc32/icu/icu.c index e9bf35e444..58932d31f3 100644 --- a/sys/platform/pc32/icu/icu.c +++ b/sys/platform/pc32/icu/icu.c @@ -70,10 +70,8 @@ icu_init(void) int auto_eoi = 0; /* 8086 mode */ #endif -#ifdef SMP if (ioapic_enable) auto_eoi = 2; /* auto EOI, 8086 mode */ -#endif /* * Program master @@ -183,8 +181,6 @@ icu_ioapic_extint(int irq, int vec) return 0; } -#ifdef SMP - void icu_reinit_noioapic(void) { @@ -209,5 +205,3 @@ icu_reinit_noioapic(void) MachIntrABI.cleanup(); crit_exit(); } - -#endif diff --git a/sys/platform/pc32/icu/icu_abi.c b/sys/platform/pc32/icu/icu_abi.c index e25760b1f0..09680b5a8e 100644 --- a/sys/platform/pc32/icu/icu_abi.c +++ b/sys/platform/pc32/icu/icu_abi.c @@ -167,8 +167,6 @@ static void icu_finalize(void) { KKASSERT(MachIntrABI.type == MACHINTR_ICU); - -#ifdef SMP KKASSERT(!ioapic_enable); /* @@ -184,7 +182,6 @@ icu_finalize(void) outb(0x22, 0x70); outb(0x23, 0x01); } -#endif /* SMP */ } static int diff --git a/sys/platform/pc32/icu/icu_var.h b/sys/platform/pc32/icu/icu_var.h index 47e046c729..7d04411bbb 100644 --- a/sys/platform/pc32/icu/icu_var.h +++ b/sys/platform/pc32/icu/icu_var.h @@ -40,9 +40,7 @@ void icu_definit(void); void icu_reinit(void); -#ifdef SMP void icu_reinit_noioapic(void); -#endif intrmask_t icu_irq_pending(void); diff --git a/sys/platform/pc32/include/intr_machdep.h b/sys/platform/pc32/include/intr_machdep.h index c350242e97..1a13b77c34 100644 --- a/sys/platform/pc32/include/intr_machdep.h +++ b/sys/platform/pc32/include/intr_machdep.h @@ -53,8 +53,6 @@ #define IDT_OFFSET_SYSCALL 0x80 #define IDT_OFFSET_IPI 0xe0 -#if defined(SMP) - /* * Local APIC TPR priority vector levels: * @@ -131,8 +129,6 @@ /* NOTE: this vector MUST be xxxx1111 */ #define XSPURIOUSINT_OFFSET (IDT_OFFSET_IPIG2 + 15) -#endif /* SMP */ - #ifndef LOCORE /* @@ -142,14 +138,16 @@ typedef void inthand_t(u_int cs, u_int ef, u_int esp, u_int ss); #define IDTVEC(name) __CONCAT(X,name) -#if defined(SMP) inthand_t - Xinvltlb, /* TLB shootdowns */ - Xcpustop, /* CPU stops & waits for another CPU to restart it */ Xspuriousint, /* handle APIC "spurious INTs" */ - Xtimer, /* handle LAPIC timer INT */ + Xtimer; /* handle LAPIC timer INT */ + +#ifdef SMP +inthand_t + Xcpustop, /* CPU stops & waits for another CPU to restart it */ + Xinvltlb, /* TLB shootdowns */ Xipiq; /* handle lwkt_send_ipiq() requests */ -#endif /* SMP */ +#endif #endif /* LOCORE */ diff --git a/sys/platform/pc32/isa/clock.c b/sys/platform/pc32/isa/clock.c index 6fde329556..a44c9d0aaa 100644 --- a/sys/platform/pc32/isa/clock.c +++ b/sys/platform/pc32/isa/clock.c @@ -82,10 +82,8 @@ #include #include -#ifdef SMP #include #include -#endif #include #include #include @@ -1001,8 +999,6 @@ resettodr(void) crit_exit(); } -#ifdef SMP - static int i8254_ioapic_trial(int irq, struct cputimer_intr *cti) { @@ -1034,8 +1030,6 @@ i8254_ioapic_trial(int irq, struct cputimer_intr *cti) return 0; } -#endif /* SMP */ - /* * Start both clocks running. DragonFly note: the stat clock is no longer * used. Instead, 8254 based systimers are used for all major clock @@ -1044,10 +1038,8 @@ i8254_ioapic_trial(int irq, struct cputimer_intr *cti) static void i8254_intr_initclock(struct cputimer_intr *cti, boolean_t selected) { -#ifdef SMP /* APIC-IO */ void *clkdesc = NULL; int irq = 0, mixed_mode = 0, error; -#endif callout_init(&sysbeepstop_ch); @@ -1063,7 +1055,6 @@ i8254_intr_initclock(struct cputimer_intr *cti, boolean_t selected) rtc_statusb = RTCSB_24HR; /* Finish initializing 8253 timer 0. */ -#ifdef SMP if (ioapic_enable) { irq = ioapic_abi_find_irq(0, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH); @@ -1096,21 +1087,17 @@ mixed_mode_setup: INTR_NOENTROPY); machintr_intren(irq); } else { -#endif - register_int(0, clkintr, NULL, "clk", NULL, - INTR_EXCL | INTR_CLOCK | - INTR_NOPOLL | INTR_MPSAFE | - INTR_NOENTROPY); - machintr_intren(0); -#ifdef SMP + register_int(0, clkintr, NULL, "clk", NULL, + INTR_EXCL | INTR_CLOCK | + INTR_NOPOLL | INTR_MPSAFE | + INTR_NOENTROPY); + machintr_intren(0); } -#endif /* Initialize RTC. */ writertc(RTC_STATUSA, rtc_statusa); writertc(RTC_STATUSB, RTCSB_24HR); -#ifdef SMP if (ioapic_enable) { error = i8254_ioapic_trial(irq, cti); if (error) { @@ -1133,7 +1120,6 @@ mixed_mode_setup: } } } -#endif return; nointr: -- 2.41.0