Updated MSI Patches
Subsystems (3)
Hi,
Here is an updated version of the MSI patch based on kernel linux-2.6.0-test5. Thanks for all the input received from the community, below patches include the following changes from the previous patches, which are based on kernel linux-2.6.0-test2:
- Reconstructing a vector-base patch.
- Adding a new API "int pci_enable_msi(struct pci_dev *dev)" based on the input from the community to handle buggy PCI/PCI-X hardware when MSI is enabled. Any MSI/MSI-X capable device driver, which wants to have MSI enabled on its hardware device, must call this API to request for MSI mode.
- Adding a set_msi_affinity feature.
- Adding a feature, which dynamically detects any MSI/MSI-X capable devices and establishes a reserved policy to ensure that no MSI-X device driver can claim all available vectors.
- Resolving issue with kernel build when configuring system in UP mode without setting CONFIG_X86_LOCAL_APIC to 'Y'. This solution provides MSI support independent from IOxAPICs (IOxAPIC free).
- Renaming pci_msi.c to msi.c and moving this file under ../drivers/pci to have code share as much as possible across all Linux architectures.
- Replacing all direct memory access with readl/writel.
- Using kmem_cache instead of kmalloc to allocate msi_desc entries.
- Putting the EXPORT_SYMBOL in the file msi.c
- Removing boot parameters "pci_nomsi", "device_msi=", and "device_nomsi=".
Thanks,
Long
----------------------------------------------------------------------------
arch/i386/Kconfig +11 -0
@@ -1086,6 +1086,17 @@ depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS) default y +config PCI_USE_VECTOR + bool "PCI_USE_VECTOR" + default n + help + This replaces the current existing IRQ-based index interrupt scheme + with the vector-base index scheme. The advantages of vector base over IRQ base are listed below: + 1) Support MSI implementation. + 2) Support future IOxAPIC hotplug + + If you don't know what to do here, say N. + source "drivers/pci/Kconfig" config ISA
arch/i386/kernel/i8259.c +3 -1
@@ -419,8 +419,10 @@* us. (some of these will be overridden and become * 'special' SMP interrupts) */ -for (i =0 ; i <NR_IRQS ; i++) { +for (i =0 ; i < (NR_VECTORS -FIRST_EXTERNAL_VECTOR ); i++) {int vector =FIRST_EXTERNAL_VECTOR + i; +if (i >=NR_IRQS ) +break ;if (vector !=SYSCALL_VECTOR )set_intr_gate (vector, interrupt[i]); }
arch/i386/kernel/io_apic.c +125 -48
297 lines not on this page · raw message
arch/i386/kernel/mpparse.c +8 -4
@@ -1131,15 +1131,19 @@if ((1 <<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {printk (KERN_DEBUG "Pin %d-%d already programmed\n" , mp_ioapic_routing[ioapic].apic_id, ioapic_pin); - entry->irq = irq; +if (use_pci_vector () && !platform_legacy_irq (irq)) + irq =IO_APIC_VECTOR (irq); + entry->irq = irq;continue ; } mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1 <<bit); -if (!io_apic_set_pci_routing (ioapic, ioapic_pin, irq, edge_level, active_high_low)) - entry->irq = irq; - +if (!io_apic_set_pci_routing (ioapic, ioapic_pin, irq, edge_level, active_high_low)) { +if (use_pci_vector () && !platform_legacy_irq (irq)) + irq =IO_APIC_VECTOR (irq); + entry->irq = irq; + } printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", entry->id.segment, entry->id.bus, entry->id.device, ('A' + entry->pin),
arch/i386/pci/irq.c +4 -0
@@ -745,6 +745,10 @@ bridge->bus->number, PCI_SLOT(bridge->devfn), 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: (B%d,I%d,P%d) -> %d\n" , dev->bus->number,PCI_SLOT (dev->devfn), pin, irq); dev->irq = irq;
include/asm-i386/hw_irq.h +1 -0
@@ -41,6 +41,7 @@ asmlinkage void error_interrupt(void); asmlinkage void spurious_interrupt(void); asmlinkage void thermal_interrupt(struct pt_regs); +#define platform_legacy_irq (irq) ((irq) < 16)#endif void mask_irq (unsigned int irq);
include/asm-i386/io_apic.h +40 -0
@@ -13,6 +13,46 @@#ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_PCI_USE_VECTOR +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 APIC_MISMATCH_DEBUG #define IO_APIC_BASE (idx) \
include/asm-i386/mach-default/irq_vectors.h +10 -0
@@ -76,11 +76,21 @@* Since vectors 0x00-0x1f are used/reserved for the CPU, * the usable vector space is 0x20-0xff (224 vectors) */ +/* +* The maximum number of vectors supported by i386 processors +* is limited to 256. For processors other than i386, NR_VECTORS +* should be changed accordingly. +*/ +#define NR_VECTORS 256 +#ifdef CONFIG_PCI_USE_VECTOR +#define NR_IRQS FIRST_SYSTEM_VECTOR +#else #ifdef CONFIG_X86_IO_APIC #define NR_IRQS 224#else #define NR_IRQS 16#endif +#endif #define FPU_IRQ 13
arch/i386/Kconfig +7 -0
@@ -1088,6 +1088,7 @@ config PCI_USE_VECTOR bool "PCI_USE_VECTOR" + depends on X86_LOCAL_APIC default n help This replaces the current existing IRQ-based index interrupt scheme
@@ -1095,6 +1096,12 @@ 1) Support MSI implementation. 2) Support future IOxAPIC hotplug + Note that this enables MSI, Message Signaled Interrupt, on all + MSI capable device functions detected if users also install the + MSI patch. Message Signal Interrupt enables an MSI-capable + hardware device to send an inbound Memory Write on its PCI bus + instead of asserting IRQ signal on device IRQ pin. + If you don't know what to do here, say N. source "drivers/pci/Kconfig"
arch/i386/kernel/io_apic.c +5 -5
@@ -296,7 +296,7 @@extern cpumask_t irq_affinity[NR_IRQS ]; -static cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; +cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];#define IRQBALANCE_CHECK_ARCH -999static int irqbalance_disabled =IRQBALANCE_CHECK_ARCH ;
@@ -1148,6 +1148,7 @@int irq_vector[NR_IRQS ] = {FIRST_DEVICE_VECTOR ,0 }; +#ifndef CONFIG_PCI_USE_VECTOR static int __init assign_irq_vector (int irq) {static int current_vector =FIRST_DEVICE_VECTOR , offset =0 ;
@@ -1165,14 +1166,13 @@ current_vector = FIRST_DEVICE_VECTOR + offset; } -#ifdef CONFIG_PCI_USE_VECTOR - vector_irq[current_vector] = irq; -#endif -IO_APIC_VECTOR (irq) = current_vector;return current_vector; } +#else +extern int assign_irq_vector (int irq); +#endif static struct hw_interrupt_type ioapic_level_type;static struct hw_interrupt_type ioapic_edge_type;
arch/i386/pci/irq.c +2 -0
@@ -680,8 +680,10 @@if ( dev2->irq && dev2->irq != irq && \ (!(pci_probe &PCI_USE_PIRQ_MASK ) || \ ((1 << dev2->irq) & mask)) ) { +#ifndef CONFIG_PCI_USE_VECTOR printk (KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n" ,pci_name (dev2), dev2->irq, irq); +#endif continue ; } dev2->irq = irq;
Documentation/MSI-HOWTO.txt +275 -0
275 lines not on this page · raw message
drivers/acpi/pci_irq.c +1 -1
@@ -234,7 +234,7 @@PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -static int +int acpi_pci_irq_lookup (struct pci_bus *bus,int device,int pin) {struct acpi_prt_entry *entry =NULL ;
drivers/pci/Makefile +1 -0
@@ -28,6 +28,7 @@ obj-$(CONFIG_SGI_IP27) += setup-irq.o obj-$(CONFIG_SGI_IP32) += setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o +obj-$(CONFIG_PCI_USE_VECTOR) += msi.o # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o
drivers/pci/msi.c +1041 -0
1,041 lines not on this page · raw message
drivers/pci/probe.c +4 -0
@@ -552,6 +552,7 @@struct pci_dev *dev; dev =pci_scan_device (bus, devfn); +pci_scan_msi_device (dev);if (func ==0 ) {if (!dev)break ;
@@ -564,6 +565,9 @@/* Fix up broken headers */ pci_fixup_device (PCI_FIXUP_HEADER , dev); +/* Fix up broken MSI hardware */ +pci_fixup_device (PCI_FIXUP_MSI , dev); +/* * Add the device to our list of discovered devices * and the bus list for fixup functions, etc.
drivers/pci/remove.c +2 -0
@@ -14,6 +14,8 @@ {int i; +msi_remove_pci_irq_vectors (dev); +for (i =0 ; i <PCI_NUM_RESOURCES ; i++) {struct resource *res = dev->resource + i;if (res->parent)
include/linux/pci.h +18 -0
@@ -36,6 +36,7 @@#define PCI_COMMAND_WAIT 0x80/* Enable address/data stepping */ #define PCI_COMMAND_SERR 0x100/* Enable SERR */ #define PCI_COMMAND_FAST_BACK 0x200/* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400/* INTx Emulation Disable */ #define PCI_STATUS 0x06/* 16 bits */ #define PCI_STATUS_CAP_LIST 0x10/* Support Capability List */
@@ -198,6 +199,8 @@#define PCI_CAP_ID_MSI 0x05/* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06/* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07/* PCI-X */ +#define PCI_CAP_ID_EXP 0x10/* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11/* MSI-X */ #define PCI_CAP_LIST_NEXT 1/* Next capability in the list */ #define PCI_CAP_FLAGS 2/* Capability defined flags (16 bits) */ #define PCI_CAP_SIZEOF 4
@@ -275,11 +278,13 @@#define PCI_MSI_FLAGS_QSIZE 0x70/* Message queue size configured */ #define PCI_MSI_FLAGS_QMASK 0x0e/* Maximum queue size available */ #define PCI_MSI_FLAGS_ENABLE 0x01/* MSI feature enabled */ +#define PCI_MSI_FLAGS_MASKBIT 0x100/* 64-bit mask bits allowed */ #define PCI_MSI_RFU 3/* Rest of capability flags */ #define PCI_MSI_ADDRESS_LO 4/* Lower 32 bits */ #define PCI_MSI_ADDRESS_HI 8/* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ #define PCI_MSI_DATA_32 8/* 16 bits of data for 32-bit devices */ #define PCI_MSI_DATA_64 12/* 16 bits of data for 64-bit devices */ +#define PCI_MSI_MASK_BIT 16/* Mask bits register */ /* CompactPCI Hotswap Register */
@@ -696,6 +701,18 @@extern struct pci_dev *isa_bridge;#endif +#ifndef CONFIG_PCI_USE_VECTOR +static inline void pci_scan_msi_device (struct pci_dev *dev) {} +static inline int pci_enable_msi (struct pci_dev *dev) {return -1 ;} +static inline void msi_remove_pci_irq_vectors (struct pci_dev *dev) {} +#else +extern void pci_scan_msi_device (struct pci_dev *dev); +extern int pci_enable_msi (struct pci_dev *dev); +extern void msi_remove_pci_irq_vectors (struct pci_dev *dev); +extern int msi_alloc_vectors (struct pci_dev * dev,int *vector,int nvec); +extern int msi_free_vectors (struct pci_dev * dev,int *vector,int nvec); +#endif +#endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */
@@ -866,6 +883,7 @@#define PCI_FIXUP_HEADER 1/* Called immediately after reading configuration header */ #define PCI_FIXUP_FINAL 2/* Final phase of device fixups */ +#define PCI_FIXUP_MSI 3/* Fixup for MSI buggy hardware */ void pci_fixup_device (int pass,struct pci_dev *dev);
include/linux/pci_msi.h +170 -0
170 lines not on this page · raw message
Quoted 4 lines · long
Here is an updated version of the MSI patch based on kernel linux-2.6.0-test5. Thanks for all the input received from the community, below patches include the following changes from the previous patches, which are based on kernel linux-2.6.0-test2:
Lookin' real good to me.
Quoted 8 lines
Documentation/MSI-HOWTO.txt +8
-0+Q2. Will it work on all the Pentium processors (P3, P4, Xeon, +AMD processors)? In P3 IPI's are transmitted on the APIC local +bus and in P4 and Xeon they are transmitted on the system +bus. Are there any implications with this? + +A2. MSI support enables a PCI device sending an inbound +memory write (0xfeexxxxx as target address) on its PCI bus +directly to the FSB. Since the message address has a
Documentation/MSI-HOWTO.txt line 262
Quoted 10 lines
Documentation/MSI-HOWTO.txt +10
-0+redirection hint bit cleared, it should work. + +Q3. The target address 0xfeexxxxx will be translated by the +Host Bridge into an interrupt message. Are there any +limitations on the chipsets such as Intel 8xx, Intel e7xxx, +or VIA? + +A3. If these chipsets support an inbound memory write with +target address set as 0xfeexxxxx, as conformed to PCI +specification 2.3 or latest, then it should work.
I would prefer a section in the documentation that spells out, in plain English, exactly what hardware support is needed for MSI to work. i.e.
"APIC required and must be enabled"
"Northbridge must support MSI transactions"
etc.
Using that information, users and developers may know _exactly_ whether they can use MSI or not. From "Q2/A2" and "Q3/A3" above, it is not clear to me.
Quoted 32 lines
drivers/pci/msi.c +32
-0+static struct hw_interrupt_type msix_irq_type = { +"PCI MSI-X" , + startup_msi_irq_w_maskbit, + shutdown_msi_irq_w_maskbit, + enable_msi_irq_w_maskbit, + disable_msi_irq_w_maskbit, + act_msi_irq_w_maskbit, + end_msi_irq_w_maskbit, + set_msi_irq_affinity +}; + +/* +* Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices, +* which implement the MSI Capability Structure with +* Mask-and-Pending Bits. +*/ +static struct hw_interrupt_type msi_irq_w_maskbit_type = { +"PCI MSI" , + startup_msi_irq_w_maskbit, + shutdown_msi_irq_w_maskbit, + enable_msi_irq_w_maskbit, + disable_msi_irq_w_maskbit, + act_msi_irq_w_maskbit, + end_msi_irq_w_maskbit, + set_msi_irq_affinity +}; + +/* +* Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices, +* which implement the MSI Capability Structure without +* Mask-and-Pending Bits. +*/
drivers/pci/msi.c line 238
Quoted 10 lines
drivers/pci/msi.c +10
-0+static struct hw_interrupt_type msi_irq_wo_maskbit_type = { +"PCI MSI" , + startup_msi_irq_wo_maskbit, + shutdown_msi_irq_wo_maskbit, + enable_msi_irq_wo_maskbit, + disable_msi_irq_wo_maskbit, + act_msi_irq_wo_maskbit, + end_msi_irq_wo_maskbit, + set_msi_irq_affinity +};
Suggest converting these structure initializers to C99 style:
.member_name = value,
Quoted 10 lines
+/**
+ *msix_capability_init: configure device's MSI-X capability structure
+ * argument: dev of structpci_devtype
+ *
+ * description: called to configure the device's MSI-X capability structure
+ * with a single MSI. To request for additional MSI vectors, the device drivers
+ * are required to utilize the following supported APIs:
+ * 1)msi_alloc_vectors(...)for requesting one or more MSI
+ * 2)msi_free_vectors(...)for releasing one or more MSI back to PCI subsystem
+ *
When added header comments, please use the official kernel style, so that it may be picked up automatically by the kernel documentation processing system (Documentation/DocBook/*). Specifically,
/**
begins a header (you did this),
* my_function - description
begins a function header (you need to use " - "),
* @arg1: description... * @arg2: description...
describes the arguments.
The rest is fine. Note that lines ending with a colon ("blah blah:\n") are bolded, and considered paragraph leaders.
Quoted 12 lines
diff -urN
linux-260t5-vectorbase-testbox/drivers/pci/probe.clinux-260t5-msi-testbox/drivers/pci/probe.cdrivers/pci/probe.c +1
-0@@ -552,6 +552,7 @@struct pci_dev *dev; dev =pci_scan_device (bus, devfn); +pci_scan_msi_device (dev);if (func ==0 ) {if (!dev)break ;
drivers/pci/probe.c line 573
Quoted 9 lines
drivers/pci/probe.c +3
-0@@ -564,6 +565,9 @@/* Fix up broken headers */ pci_fixup_device (PCI_FIXUP_HEADER , dev); +/* Fix up broken MSI hardware */ +pci_fixup_device (PCI_FIXUP_MSI , dev); +/* * Add the device to our list of discovered devices * and the bus list for fixup functions, etc.
Why does MSI need a separate list of fixups?
AFAICS adding broken MSI devices to either the PCI_FIXUP_HEADER or PCI_FIXUP_FINAL lists is entirely appropriate.
Quoted 36 lines
drivers/pci/probe.c +36
-0+struct msg_data { +__u32 vector :8 , + delivery_mode :3 ,/* 000b: FIXED +001b: lowest priority +111b: ExtINT */ + reserved_1 :3 , + level :1 ,/* 0: deassert, 1: assert */ + trigger :1 ,/* 0: edge, 1: level */ + reserved_2 :16 ; +} __attribute__ ((packed)); + +struct msg_address { +union { +struct {__u32 + reserved_1 :2 , + dest_mode :1 ,/* 0: physical, +1: logical */ + redirection_hint :1 ,/* 0: dedicated CPU +1: lowest priority */ + reserved_2 :8 , + dest_id :8 ,/* Destination ID */ + header :12 ;/* FEEH */ + }u; +__u32 value; + }lo_address; +__u32 hi_address; +} __attribute__ ((packed)); + +struct msi_desc { +struct { +__u32 type :5 ,/* {0: unused, 5h:MSI, 11h:MSI-X} */ + maskbit :1 ,/* mask-pending bit supported ? */ + reserved:2 ,/* reserved */ + entry_nr:8 ,/* specific enabled entry */ + default_vector:8 ,/* default pre-assigned vector */ + current_cpu:8 ;/* current destination cpu */
drivers/pci/probe.c
Quoted 10 lines
drivers/pci/probe.c +10
-0+ }msi_attrib; + +struct { +__u32 head :16 , + tail :16 ; + }link; + +unsigned long mask_base; +struct pci_dev *dev; +};
These bitfields should be defined in big-endian and little-endian forms, shouldn't they? grep for __LITTLE_ENDIAN_BITFIELD and __BIG_ENDIAN_BITFIELD in include/*/*.h.
Jeff