The patch titled genirq: i386 irq: Remove the msi assumption that irq == vector has been added to the -mm tree. Its filename is genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector.patch See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this ------------------------------------------------------ Subject: genirq: i386 irq: Remove the msi assumption that irq == vector From: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> This patch removes the change in behavior of the irq allocation code when CONFIG_PCI_MSI is defined. Removing all instances of the assumption that irq == vector. create_irq is rewritten to first allocate a free irq and then to assign that irq a vector. assign_irq_vector is made static and the AUTO_ASSIGN case which allocates an vector not bound to an irq is removed. The ioapic vector methods are removed, and everything now works with irqs. The definition of NR_IRQS no longer depends on CONFIG_PCI_MSI Signed-off-by: Eric W. Biederman <ebiederm@xxxxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> Cc: Rajesh Shah <rajesh.shah@xxxxxxxxx> Cc: Andi Kleen <ak@xxxxxx> Cc: "Protasevich, Natalie" <Natalie.Protasevich@xxxxxxxxxx> Cc: "Luck, Tony" <tony.luck@xxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- arch/i386/kernel/acpi/boot.c | 7 arch/i386/kernel/io_apic.c | 171 ++--------- arch/i386/pci/irq.c | 4 include/asm-i386/hw_irq.h | 1 include/asm-i386/io_apic.h | 42 -- include/asm-i386/mach-default/irq_vectors_limits.h | 5 include/asm-x86_64/io_apic.h | 2 7 files changed, 47 insertions(+), 185 deletions(-) diff -puN arch/i386/kernel/acpi/boot.c~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector arch/i386/kernel/acpi/boot.c --- a/arch/i386/kernel/acpi/boot.c~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/arch/i386/kernel/acpi/boot.c @@ -461,12 +461,7 @@ void __init acpi_pic_sci_set_trigger(uns int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { -#ifdef CONFIG_X86_IO_APIC - if (use_pci_vector() && !platform_legacy_irq(gsi)) - *irq = IO_APIC_VECTOR(gsi); - else -#endif - *irq = gsi_irq_sharing(gsi); + *irq = gsi_irq_sharing(gsi); return 0; } diff -puN arch/i386/kernel/io_apic.c~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/arch/i386/kernel/io_apic.c @@ -89,14 +89,6 @@ static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; -int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; -#ifdef CONFIG_PCI_MSI -#define vector_to_irq(vector) \ - (platform_legacy_irq(vector) ? vector : vector_irq[vector]) -#else -#define vector_to_irq(vector) (vector) -#endif - /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super @@ -262,7 +254,7 @@ static void set_ioapic_affinity_irq(unsi break; entry = irq_2_pin + entry->next; } - set_irq_info(irq, cpumask); + set_native_irq_info(irq, cpumask); spin_unlock_irqrestore(&ioapic_lock, flags); } @@ -1163,18 +1155,14 @@ static inline int IO_APIC_irq_trigger(in /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; -int assign_irq_vector(int irq) +static int __assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - unsigned long flags; int vector; - BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); - - spin_lock_irqsave(&vector_lock, flags); + BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); - if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { - spin_unlock_irqrestore(&vector_lock, flags); + if (IO_APIC_VECTOR(irq) > 0) { return IO_APIC_VECTOR(irq); } next: @@ -1192,15 +1180,22 @@ next: } vector = current_vector; - vector_irq[vector] = irq; - if (irq != AUTO_ASSIGN) - IO_APIC_VECTOR(irq) = vector; + IO_APIC_VECTOR(irq) = vector; + return vector; +} + +static int assign_irq_vector(int irq) +{ + unsigned long flags; + int vector; + + spin_lock_irqsave(&vector_lock, flags); + vector = __assign_irq_vector(irq); spin_unlock_irqrestore(&vector_lock, flags); return vector; } - static struct irq_chip ioapic_chip; #define IOAPIC_AUTO -1 @@ -1209,18 +1204,14 @@ static struct irq_chip ioapic_chip; static void ioapic_register_intr(int irq, int vector, unsigned long trigger) { - unsigned idx; - - idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; - if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || trigger == IOAPIC_LEVEL) - set_irq_chip_and_handler(idx, &ioapic_chip, + set_irq_chip_and_handler(irq, &ioapic_chip, handle_fasteoi_irq); else - set_irq_chip_and_handler(idx, &ioapic_chip, + set_irq_chip_and_handler(irq, &ioapic_chip, handle_edge_irq); - set_intr_gate(vector, interrupt[idx]); + set_intr_gate(vector, interrupt[irq]); } static void __init setup_IO_APIC_irqs(void) @@ -1473,17 +1464,12 @@ void __init print_IO_APIC(void) ); } } - if (use_pci_vector()) - printk(KERN_INFO "Using vector-based indexing\n"); printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; if (entry->pin < 0) continue; - if (use_pci_vector() && !platform_legacy_irq(i)) - printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); - else - printk(KERN_DEBUG "IRQ%d ", i); + printk(KERN_DEBUG "IRQ%d ", i); for (;;) { printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) @@ -1950,7 +1936,7 @@ static unsigned int startup_ioapic_irq(u static void ack_ioapic_irq(unsigned int irq) { - move_irq(irq); + move_native_irq(irq); ack_APIC_irq(); } @@ -1959,7 +1945,7 @@ static void ack_ioapic_quirk_irq(unsigne unsigned long v; int i; - move_irq(irq); + move_native_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1994,63 +1980,8 @@ static void ack_ioapic_quirk_irq(unsigne } } -static unsigned int startup_ioapic_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - - return startup_ioapic_irq(irq); -} - -static void ack_ioapic_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - - move_native_irq(vector); - ack_ioapic_irq(irq); -} - -static void ack_ioapic_quirk_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - - move_native_irq(vector); - ack_ioapic_quirk_irq(irq); -} - -static void mask_IO_APIC_vector (unsigned int vector) -{ - int irq = vector_to_irq(vector); - - mask_IO_APIC_irq(irq); -} - -static void unmask_IO_APIC_vector (unsigned int vector) +static int ioapic_retrigger_irq(unsigned int irq) { - int irq = vector_to_irq(vector); - - unmask_IO_APIC_irq(irq); -} - -/* - * Oh just glorious. If CONFIG_PCI_MSI we've done - * #define set_ioapic_affinity set_ioapic_affinity_vector - */ -#if defined (CONFIG_SMP) && defined(CONFIG_X86_IO_APIC) && \ - defined(CONFIG_PCI_MSI) -static void set_ioapic_affinity_vector (unsigned int vector, - cpumask_t cpu_mask) -{ - int irq = vector_to_irq(vector); - - set_native_irq_info(vector, cpu_mask); - set_ioapic_affinity_irq(irq, cpu_mask); -} -#endif - -static int ioapic_retrigger_vector(unsigned int vector) -{ - int irq = vector_to_irq(vector); - send_IPI_self(IO_APIC_VECTOR(irq)); return 1; @@ -2058,15 +1989,15 @@ static int ioapic_retrigger_vector(unsig static struct irq_chip ioapic_chip __read_mostly = { .name = "IO-APIC", - .startup = startup_ioapic_vector, - .mask = mask_IO_APIC_vector, - .unmask = unmask_IO_APIC_vector, - .ack = ack_ioapic_vector, - .eoi = ack_ioapic_quirk_vector, + .startup = startup_ioapic_irq, + .mask = mask_IO_APIC_irq, + .unmask = unmask_IO_APIC_irq, + .ack = ack_ioapic_irq, + .eoi = ack_ioapic_quirk_irq, #ifdef CONFIG_SMP - .set_affinity = set_ioapic_affinity, + .set_affinity = set_ioapic_affinity_irq, #endif - .retrigger = ioapic_retrigger_vector, + .retrigger = ioapic_retrigger_irq, }; @@ -2087,11 +2018,6 @@ static inline void init_IO_APIC_traps(vo */ for (irq = 0; irq < NR_IRQS ; irq++) { int tmp = irq; - if (use_pci_vector()) { - if (!platform_legacy_irq(tmp)) - if ((tmp = vector_to_irq(tmp)) == -1) - continue; - } if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { /* * Hmm.. We don't have an entry for this, @@ -2505,28 +2431,26 @@ device_initcall(ioapic_init_sysfs); */ int create_irq(void) { - /* Hack of the day: irq == vector. - * - * Ultimately this will be be more general, - * and not depend on the irq to vector identity mapping. - * But this version is needed until msi.c can cope with - * the more general form. - */ - int irq, vector; + /* Allocate an unused irq */ + int irq, new, vector; unsigned long flags; - vector = assign_irq_vector(AUTO_ASSIGN); - irq = vector; - - if (vector >= 0) { - struct irq_desc *desc; - spin_lock_irqsave(&vector_lock, flags); - vector_irq[vector] = irq; - irq_vector[irq] = vector; - spin_unlock_irqrestore(&vector_lock, flags); + irq = -ENOSPC; + spin_lock_irqsave(&vector_lock, flags); + for (new = (NR_IRQS - 1); new >= 0; new--) { + if (platform_legacy_irq(new)) + continue; + if (irq_vector[new] != 0) + continue; + vector = __assign_irq_vector(new); + if (likely(vector > 0)) + irq = new; + break; + } + spin_unlock_irqrestore(&vector_lock, flags); + if (irq >= 0) { set_intr_gate(vector, interrupt[irq]); - dynamic_irq_init(irq); } return irq; @@ -2535,13 +2459,10 @@ int create_irq(void) void destroy_irq(unsigned int irq) { unsigned long flags; - unsigned int vector; dynamic_irq_cleanup(irq); spin_lock_irqsave(&vector_lock, flags); - vector = irq_vector[irq]; - vector_irq[vector] = -1; irq_vector[irq] = 0; spin_unlock_irqrestore(&vector_lock, flags); } @@ -2769,7 +2690,7 @@ int io_apic_set_pci_routing (int ioapic, spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); - set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); + set_native_irq_info(irq, TARGET_CPUS); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; diff -puN arch/i386/pci/irq.c~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector arch/i386/pci/irq.c --- a/arch/i386/pci/irq.c~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/arch/i386/pci/irq.c @@ -982,10 +982,6 @@ static void __init pcibios_fixup_irqs(vo pci_name(bridge), 'A' + pin, irq); } if (irq >= 0) { - if (use_pci_vector() && - !platform_legacy_irq(irq)) - irq = IO_APIC_VECTOR(irq); - printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", pci_name(dev), 'A' + pin, irq); dev->irq = irq; diff -puN include/asm-i386/hw_irq.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector include/asm-i386/hw_irq.h --- a/include/asm-i386/hw_irq.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/include/asm-i386/hw_irq.h @@ -26,7 +26,6 @@ extern u8 irq_vector[NR_IRQ_VECTORS]; #define IO_APIC_VECTOR(irq) (irq_vector[irq]) -#define AUTO_ASSIGN -1 extern void (*interrupt[NR_IRQS])(void); diff -puN include/asm-i386/io_apic.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector include/asm-i386/io_apic.h --- a/include/asm-i386/io_apic.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/include/asm-i386/io_apic.h @@ -12,46 +12,6 @@ #ifdef CONFIG_X86_IO_APIC -#ifdef CONFIG_PCI_MSI -static inline int use_pci_vector(void) {return 1;} -static inline void disable_edge_ioapic_vector(unsigned int vector) { } -static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } -static inline void end_edge_ioapic_vector (unsigned int vector) { } -#define startup_level_ioapic startup_level_ioapic_vector -#define shutdown_level_ioapic mask_IO_APIC_vector -#define enable_level_ioapic unmask_IO_APIC_vector -#define disable_level_ioapic mask_IO_APIC_vector -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector -#define end_level_ioapic end_level_ioapic_vector -#define set_ioapic_affinity set_ioapic_affinity_vector - -#define startup_edge_ioapic startup_edge_ioapic_vector -#define shutdown_edge_ioapic disable_edge_ioapic_vector -#define enable_edge_ioapic unmask_IO_APIC_vector -#define disable_edge_ioapic disable_edge_ioapic_vector -#define ack_edge_ioapic ack_edge_ioapic_vector -#define end_edge_ioapic end_edge_ioapic_vector -#else -static inline int use_pci_vector(void) {return 0;} -static inline void disable_edge_ioapic_irq(unsigned int irq) { } -static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } -static inline void end_edge_ioapic_irq (unsigned int irq) { } -#define startup_level_ioapic startup_level_ioapic_irq -#define shutdown_level_ioapic mask_IO_APIC_irq -#define enable_level_ioapic unmask_IO_APIC_irq -#define disable_level_ioapic mask_IO_APIC_irq -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq -#define end_level_ioapic end_level_ioapic_irq -#define set_ioapic_affinity set_ioapic_affinity_irq - -#define startup_edge_ioapic startup_edge_ioapic_irq -#define shutdown_edge_ioapic disable_edge_ioapic_irq -#define enable_edge_ioapic unmask_IO_APIC_irq -#define disable_edge_ioapic disable_edge_ioapic_irq -#define ack_edge_ioapic ack_edge_ioapic_irq -#define end_edge_ioapic end_edge_ioapic_irq -#endif - #define IO_APIC_BASE(idx) \ ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK))) @@ -208,6 +168,4 @@ extern int (*ioapic_renumber_irq)(int io #define io_apic_assign_pci_irqs 0 #endif -extern int assign_irq_vector(int irq); - #endif diff -puN include/asm-i386/mach-default/irq_vectors_limits.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector include/asm-i386/mach-default/irq_vectors_limits.h --- a/include/asm-i386/mach-default/irq_vectors_limits.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/include/asm-i386/mach-default/irq_vectors_limits.h @@ -1,10 +1,6 @@ #ifndef _ASM_IRQ_VECTORS_LIMITS_H #define _ASM_IRQ_VECTORS_LIMITS_H -#ifdef CONFIG_PCI_MSI -#define NR_IRQS FIRST_SYSTEM_VECTOR -#define NR_IRQ_VECTORS NR_IRQS -#else #ifdef CONFIG_X86_IO_APIC #define NR_IRQS 224 # if (224 >= 32 * NR_CPUS) @@ -16,6 +12,5 @@ #define NR_IRQS 16 #define NR_IRQ_VECTORS NR_IRQS #endif -#endif #endif /* _ASM_IRQ_VECTORS_LIMITS_H */ diff -puN include/asm-x86_64/io_apic.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector include/asm-x86_64/io_apic.h --- a/include/asm-x86_64/io_apic.h~genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector +++ a/include/asm-x86_64/io_apic.h @@ -12,8 +12,6 @@ #ifdef CONFIG_X86_IO_APIC -static inline int use_pci_vector(void) {return 0;} - #define APIC_MISMATCH_DEBUG #define IO_APIC_BASE(idx) \ _ Patches currently in -mm which might be from ebiederm@xxxxxxxxxxxx are add-a-sysfs-file-to-determine-if-a-kexec-kernel-is-loaded.patch avoid-tasklist_lock-at-getrusage-for-multithreaded-case-too.patch ptrace-document-the-locking-rules.patch proc-fix-the-inode-number-on-proc-pid-fd.patch proc-remove-useless-bkl-in-proc_pid_readlink.patch proc-remove-unnecessary-and-misleading-assignments.patch proc-simplify-the-ownership-rules-for-proc.patch proc-replace-proc_inodetype-with-proc_inodefd.patch proc-remove-bogus-proc_task_permission.patch proc-kill-proc_mem_inode_operations.patch proc-properly-filter-out-files-that-are-not-visible.patch proc-fix-the-link-count-for-proc-pid-task.patch proc-move-proc_maps_operations-into-task_mmuc.patch proc-rewrite-the-proc-dentry-flush-on-exit.patch proc-close-the-race-of-a-process-dying-durning.patch proc-refactor-reading-directories-of-tasks.patch proc-remove-tasklist_lock-from-proc_pid_readdir.patch proc-remove-tasklist_lock-from-proc_pid_lookup-and.patch proc-remove-tasklist_lock-from-proc_pid_readdir-simply-fix-first_tgid.patch proc-make-proc_numbuf-the-buffer-size-for-holding-a.patch proc-dont-lock-task_structs-indefinitely.patch proc-dont-lock-task_structs-indefinitely-task_mmu-small-fixes.patch proc-use-struct-pid-not-struct-task_ref.patch proc-optimize-proc_check_dentry_visible.patch proc-use-sane-permission-checks-on-the-proc-pid-fd.patch proc-cleanup-proc_fd_access_allowed.patch proc-remove-tasklist_lock-from-proc_task_readdir.patch simplify-fix-first_tid.patch cleanup-next_tid.patch de_thread-fix-lockless-do_each_thread.patch coredump-optimize-mm-users-traversal.patch coredump-speedup-sigkill-sending.patch coredump-kill-ptrace-related-stuff.patch coredump-kill-ptrace-related-stuff-fix.patch coredump-dont-take-tasklist_lock.patch proc-sysctl-add-_proc_do_string-helper.patch namespaces-add-nsproxy.patch namespaces-add-nsproxy-dont-include-compileh.patch namespaces-incorporate-fs-namespace-into-nsproxy.patch namespaces-utsname-introduce-temporary-helpers.patch namespaces-utsname-switch-to-using-uts-namespaces.patch namespaces-utsname-switch-to-using-uts-namespaces-alpha-fix.patch namespaces-utsname-switch-to-using-uts-namespaces-cleanup.patch namespaces-utsname-use-init_utsname-when-appropriate.patch namespaces-utsname-use-init_utsname-when-appropriate-cifs-update.patch namespaces-utsname-implement-utsname-namespaces.patch namespaces-utsname-implement-utsname-namespaces-export.patch namespaces-utsname-implement-utsname-namespaces-dont-include-compileh.patch namespaces-utsname-sysctl-hack.patch namespaces-utsname-sysctl-hack-cleanup.patch namespaces-utsname-sysctl-hack-cleanup-2.patch namespaces-utsname-sysctl-hack-cleanup-2-fix.patch namespaces-utsname-remove-system_utsname.patch namespaces-utsname-implement-clone_newuts-flag.patch uts-copy-nsproxy-only-when-needed.patch ipc-namespace-core-fix.patch ipc-namespace-core-unshare-fix.patch ipc-namespace-utils-compilation-fix.patch genirq-irq-convert-the-move_irq-flag-from-a-32bit-word-to-a-single-bit.patch genirq-irq-add-moved_masked_irq.patch genirq-x86_64-irq-reenable-migrating-irqs-to-other-cpus.patch genirq-msi-simplify-msi-enable-and-disable.patch genirq-msi-simplify-msi-enable-and-disable-fix.patch genirq-msi-make-the-msi-boolean-tests-return-either-0-or-1.patch genirq-msi-implement-helper-functions-read_msi_msg-and-write_msi_msg.patch genirq-msi-refactor-the-msi_ops.patch genirq-msi-simplify-the-msi-irq-limit-policy.patch genirq-irq-add-a-dynamic-irq-creation-api.patch genirq-ia64-irq-dynamic-irq-support.patch genirq-i386-irq-dynamic-irq-support.patch genirq-i386-irq-dynamic-irq-support-fix.patch genirq-x86_64-irq-dynamic-irq-support.patch genirq-msi-make-the-msi-code-irq-based-and-not-vector-based.patch genirq-x86_64-irq-move-msi-message-composition-into-io_apicc.patch genirq-i386-irq-move-msi-message-composition-into-io_apicc.patch genirq-msi-only-build-msi-apicc-on-ia64.patch genirq-x86_64-irq-remove-the-msi-assumption-that-irq-==-vector.patch genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector.patch genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector-fix.patch genirq-irq-remove-msi-hacks.patch genirq-irq-generalize-the-check-for-hardirq_bits.patch genirq-x86_64-irq-make-the-external-irq-handlers-report-their-vector-not-the-irq-number.patch genirq-x86_64-irq-make-vector_irq-per-cpu.patch genirq-x86_64-irq-kill-gsi_irq_sharing.patch genirq-x86_64-irq-kill-irq-compression.patch genirq-irq-document-what-an-irq-is.patch pidhash-temporary-debug-checks.patch genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector-fix-tidies.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html