Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 152962 Details for
Bug 237026
RHEL4 Feature Request: add pcifront to Xen paravirt
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Preliminary RHEL-4 PV pcifront patch
linux-2.6.9-xen-pcifront.patch (text/plain), 57.22 KB, created by
Chris Lalancette
on 2007-04-18 22:13:26 UTC
(
hide
)
Description:
Preliminary RHEL-4 PV pcifront patch
Filename:
MIME Type:
Creator:
Chris Lalancette
Created:
2007-04-18 22:13:26 UTC
Size:
57.22 KB
patch
obsolete
>diff -Nurp linux-2.6.9.orig/arch/i386/Kconfig linux-2.6.9/arch/i386/Kconfig >--- linux-2.6.9.orig/arch/i386/Kconfig 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/arch/i386/Kconfig 2007-04-18 17:02:49.000000000 -0400 >@@ -1213,6 +1213,18 @@ config PCI_MMCONFIG > select ACPI_BOOT > default y > >+config XEN_PCIDEV_FRONTEND >+ bool >+ depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY) >+ default y >+ >+config XEN_PCIDEV_FE_DEBUG >+ bool "Xen PCI Frontend Debugging" >+ depends on XEN_PCIDEV_FRONTEND >+ default n >+ help >+ Enables some debug statements within the PCI Frontend. >+ > source "drivers/pci/Kconfig" > > config ISA >diff -Nurp linux-2.6.9.orig/arch/i386/pci/irq-xen.c linux-2.6.9/arch/i386/pci/irq-xen.c >--- linux-2.6.9.orig/arch/i386/pci/irq-xen.c 1969-12-31 19:00:00.000000000 -0500 >+++ linux-2.6.9/arch/i386/pci/irq-xen.c 2007-04-18 17:57:18.000000000 -0400 >@@ -0,0 +1,1161 @@ >+/* >+ * Low-Level PCI Support for PC -- Routing of Interrupts >+ * >+ * (c) 1999--2000 Martin Mares <mj@ucw.cz> >+ */ >+ >+#include <linux/config.h> >+#include <linux/types.h> >+#include <linux/kernel.h> >+#include <linux/pci.h> >+#include <linux/init.h> >+#include <linux/slab.h> >+#include <linux/interrupt.h> >+#include <linux/irq.h> >+#include <linux/dmi.h> >+#include <asm/io.h> >+#include <asm/smp.h> >+#include <asm/io_apic.h> >+#include <asm/hw_irq.h> >+ >+#include "pci.h" >+ >+#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) >+#define PIRQ_VERSION 0x0100 >+ >+static int broken_hp_bios_irq9; >+static int acer_tm360_irqrouting; >+ >+static struct irq_routing_table *pirq_table; >+ >+/* >+ * Never use: 0, 1, 2 (timer, keyboard, and cascade) >+ * Avoid using: 13, 14 and 15 (FP error and IDE). >+ * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse) >+ */ >+unsigned int pcibios_irq_mask = 0xfff8; >+ >+static int pirq_penalty[16] = { >+ 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000, >+ 0, 0, 0, 0, 1000, 100000, 100000, 100000 >+}; >+ >+struct irq_router { >+ char *name; >+ u16 vendor, device; >+ int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq); >+ int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); >+}; >+ >+struct irq_router_handler { >+ u16 vendor; >+ int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); >+}; >+ >+int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; >+ >+/* >+ * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. >+ */ >+ >+static struct irq_routing_table * __init pirq_find_routing_table(void) >+{ >+ u8 *addr; >+ struct irq_routing_table *rt; >+ int i; >+ u8 sum; >+ >+#ifdef CONFIG_XEN >+ if (!is_initial_xendomain()) >+ return NULL; >+#endif >+ >+ for(addr = (u8 *) isa_bus_to_virt(0xf0000); addr < (u8 *) isa_bus_to_virt(0x100000); addr += 16) { >+ rt = (struct irq_routing_table *) addr; >+ if (rt->signature != PIRQ_SIGNATURE || >+ rt->version != PIRQ_VERSION || >+ rt->size % 16 || >+ rt->size < sizeof(struct irq_routing_table)) >+ continue; >+ sum = 0; >+ for(i=0; i<rt->size; i++) >+ sum += addr[i]; >+ if (!sum) { >+ DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt); >+ return rt; >+ } >+ } >+ return NULL; >+} >+ >+/* >+ * If we have a IRQ routing table, use it to search for peer host >+ * bridges. It's a gross hack, but since there are no other known >+ * ways how to get a list of buses, we have to go this way. >+ */ >+ >+static void __init pirq_peer_trick(void) >+{ >+ struct irq_routing_table *rt = pirq_table; >+ u8 busmap[256]; >+ int i; >+ struct irq_info *e; >+ >+ memset(busmap, 0, sizeof(busmap)); >+ for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) { >+ e = &rt->slots[i]; >+#ifdef DEBUG >+ { >+ int j; >+ DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot); >+ for(j=0; j<4; j++) >+ DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap); >+ DBG("\n"); >+ } >+#endif >+ busmap[e->bus] = 1; >+ } >+ for(i = 1; i < 256; i++) { >+ if (!busmap[i] || pci_find_bus(0, i)) >+ continue; >+ if (pci_scan_bus(i, &pci_root_ops, NULL)) >+ printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); >+ } >+ pcibios_last_bus = -1; >+} >+ >+/* >+ * Code for querying and setting of IRQ routes on various interrupt routers. >+ */ >+ >+void eisa_set_level_irq(unsigned int irq) >+{ >+ unsigned char mask = 1 << (irq & 7); >+ unsigned int port = 0x4d0 + (irq >> 3); >+ unsigned char val = inb(port); >+ >+ if (!(val & mask)) { >+ DBG(" -> edge"); >+ outb(val | mask, port); >+ } >+} >+ >+/* >+ * Common IRQ routing practice: nybbles in config space, >+ * offset by some magic constant. >+ */ >+static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr) >+{ >+ u8 x; >+ unsigned reg = offset + (nr >> 1); >+ >+ pci_read_config_byte(router, reg, &x); >+ return (nr & 1) ? (x >> 4) : (x & 0xf); >+} >+ >+static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val) >+{ >+ u8 x; >+ unsigned reg = offset + (nr >> 1); >+ >+ pci_read_config_byte(router, reg, &x); >+ x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val); >+ pci_write_config_byte(router, reg, x); >+} >+ >+/* >+ * ALI pirq entries are damn ugly, and completely undocumented. >+ * This has been figured out from pirq tables, and it's not a pretty >+ * picture. >+ */ >+static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; >+ >+ return irqmap[read_config_nybble(router, 0x48, pirq-1)]; >+} >+ >+static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; >+ unsigned int val = irqmap[irq]; >+ >+ if (val) { >+ write_config_nybble(router, 0x48, pirq-1, val); >+ return 1; >+ } >+ return 0; >+} >+ >+/* >+ * The Intel PIIX4 pirq rules are fairly simple: "pirq" is >+ * just a pointer to the config space. >+ */ >+static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ u8 x; >+ >+ pci_read_config_byte(router, pirq, &x); >+ return (x < 16) ? x : 0; >+} >+ >+static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ pci_write_config_byte(router, pirq, irq); >+ return 1; >+} >+ >+/* >+ * The VIA pirq rules are nibble-based, like ALI, >+ * but without the ugly irq number munging. >+ * However, PIRQD is in the upper instead of lower 4 bits. >+ */ >+static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq); >+} >+ >+static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq); >+ return 1; >+} >+ >+/* >+ * The VIA pirq rules are nibble-based, like ALI, >+ * but without the ugly irq number munging. >+ * However, for 82C586, nibble map is different . >+ */ >+static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ static const unsigned int pirqmap[4] = { 3, 2, 5, 1 }; >+ return read_config_nybble(router, 0x55, pirqmap[pirq-1]); >+} >+ >+static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ static const unsigned int pirqmap[4] = { 3, 2, 5, 1 }; >+ write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); >+ return 1; >+} >+ >+/* >+ * ITE 8330G pirq rules are nibble-based >+ * FIXME: pirqmap may be { 1, 0, 3, 2 }, >+ * 2+3 are both mapped to irq 9 on my system >+ */ >+static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ static unsigned char pirqmap[4] = { 1, 0, 2, 3 }; >+ return read_config_nybble(router,0x43, pirqmap[pirq-1]); >+} >+ >+static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ static unsigned char pirqmap[4] = { 1, 0, 2, 3 }; >+ write_config_nybble(router, 0x43, pirqmap[pirq-1], irq); >+ return 1; >+} >+ >+/* >+ * OPTI: high four bits are nibble pointer.. >+ * I wonder what the low bits do? >+ */ >+static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ return read_config_nybble(router, 0xb8, pirq >> 4); >+} >+ >+static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ write_config_nybble(router, 0xb8, pirq >> 4, irq); >+ return 1; >+} >+ >+/* >+ * Cyrix: nibble offset 0x5C >+ * 0x5C bits 7:4 is INTB bits 3:0 is INTA >+ * 0x5D bits 7:4 is INTD bits 3:0 is INTC >+ */ >+static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ return read_config_nybble(router, 0x5C, (pirq-1)^1); >+} >+ >+static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ write_config_nybble(router, 0x5C, (pirq-1)^1, irq); >+ return 1; >+} >+ >+/* >+ * PIRQ routing for SiS 85C503 router used in several SiS chipsets. >+ * We have to deal with the following issues here: >+ * - vendors have different ideas about the meaning of link values >+ * - some onboard devices (integrated in the chipset) have special >+ * links and are thus routed differently (i.e. not via PCI INTA-INTD) >+ * - different revision of the router have a different layout for >+ * the routing registers, particularly for the onchip devices >+ * >+ * For all routing registers the common thing is we have one byte >+ * per routeable link which is defined as: >+ * bit 7 IRQ mapping enabled (0) or disabled (1) >+ * bits [6:4] reserved (sometimes used for onchip devices) >+ * bits [3:0] IRQ to map to >+ * allowed: 3-7, 9-12, 14-15 >+ * reserved: 0, 1, 2, 8, 13 >+ * >+ * The config-space registers located at 0x41/0x42/0x43/0x44 are >+ * always used to route the normal PCI INT A/B/C/D respectively. >+ * Apparently there are systems implementing PCI routing table using >+ * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D. >+ * We try our best to handle both link mappings. >+ * >+ * Currently (2003-05-21) it appears most SiS chipsets follow the >+ * definition of routing registers from the SiS-5595 southbridge. >+ * According to the SiS 5595 datasheets the revision id's of the >+ * router (ISA-bridge) should be 0x01 or 0xb0. >+ * >+ * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1. >+ * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets. >+ * They seem to work with the current routing code. However there is >+ * some concern because of the two USB-OHCI HCs (original SiS 5595 >+ * had only one). YMMV. >+ * >+ * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1: >+ * >+ * 0x61: IDEIRQ: >+ * bits [6:5] must be written 01 >+ * bit 4 channel-select primary (0), secondary (1) >+ * >+ * 0x62: USBIRQ: >+ * bit 6 OHCI function disabled (0), enabled (1) >+ * >+ * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved >+ * >+ * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved >+ * >+ * We support USBIRQ (in addition to INTA-INTD) and keep the >+ * IDE, ACPI and DAQ routing untouched as set by the BIOS. >+ * >+ * Currently the only reported exception is the new SiS 65x chipset >+ * which includes the SiS 69x southbridge. Here we have the 85C503 >+ * router revision 0x04 and there are changes in the register layout >+ * mostly related to the different USB HCs with USB 2.0 support. >+ * >+ * Onchip routing for router rev-id 0x04 (try-and-error observation) >+ * >+ * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs >+ * bit 6-4 are probably unused, not like 5595 >+ */ >+ >+#define PIRQ_SIS_IRQ_MASK 0x0f >+#define PIRQ_SIS_IRQ_DISABLE 0x80 >+#define PIRQ_SIS_USB_ENABLE 0x40 >+ >+static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ u8 x; >+ int reg; >+ >+ reg = pirq; >+ if (reg >= 0x01 && reg <= 0x04) >+ reg += 0x40; >+ pci_read_config_byte(router, reg, &x); >+ return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); >+} >+ >+static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ u8 x; >+ int reg; >+ >+ reg = pirq; >+ if (reg >= 0x01 && reg <= 0x04) >+ reg += 0x40; >+ pci_read_config_byte(router, reg, &x); >+ x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE); >+ x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE; >+ pci_write_config_byte(router, reg, x); >+ return 1; >+} >+ >+ >+/* >+ * VLSI: nibble offset 0x74 - educated guess due to routing table and >+ * config space of VLSI 82C534 PCI-bridge/router (1004:0102) >+ * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard >+ * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6 >+ * for the busbridge to the docking station. >+ */ >+ >+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ if (pirq > 8) { >+ printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); >+ return 0; >+ } >+ return read_config_nybble(router, 0x74, pirq-1); >+} >+ >+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ if (pirq > 8) { >+ printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); >+ return 0; >+ } >+ write_config_nybble(router, 0x74, pirq-1, irq); >+ return 1; >+} >+ >+/* >+ * ServerWorks: PCI interrupts mapped to system IRQ lines through Index >+ * and Redirect I/O registers (0x0c00 and 0x0c01). The Index register >+ * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect >+ * register is a straight binary coding of desired PIC IRQ (low nibble). >+ * >+ * The 'link' value in the PIRQ table is already in the correct format >+ * for the Index register. There are some special index values: >+ * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1, >+ * and 0x03 for SMBus. >+ */ >+static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ outb_p(pirq, 0xc00); >+ return inb(0xc01) & 0xf; >+} >+ >+static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ outb_p(pirq, 0xc00); >+ outb_p(irq, 0xc01); >+ return 1; >+} >+ >+/* Support for AMD756 PCI IRQ Routing >+ * Jhon H. Caicedo <jhcaiced@osso.org.co> >+ * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced) >+ * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced) >+ * The AMD756 pirq rules are nibble-based >+ * offset 0x56 0-3 PIRQA 4-7 PIRQB >+ * offset 0x57 0-3 PIRQC 4-7 PIRQD >+ */ >+static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq) >+{ >+ u8 irq; >+ irq = 0; >+ if (pirq <= 4) >+ { >+ irq = read_config_nybble(router, 0x56, pirq - 1); >+ } >+ printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n", >+ dev->vendor, dev->device, pirq, irq); >+ return irq; >+} >+ >+static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", >+ dev->vendor, dev->device, pirq, irq); >+ if (pirq <= 4) >+ { >+ write_config_nybble(router, 0x56, pirq - 1, irq); >+ } >+ return 1; >+} >+ >+#ifdef CONFIG_PCI_BIOS >+ >+static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) >+{ >+ struct pci_dev *bridge; >+ int pin = pci_get_interrupt_pin(dev, &bridge); >+ return pcibios_set_irq_routing(bridge, pin, irq); >+} >+ >+#endif >+ >+ >+static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ /* 440GX has a proprietary PIRQ router -- don't use it */ >+ if ( pci_find_device(PCI_VENDOR_ID_INTEL, >+ PCI_DEVICE_ID_INTEL_82443GX_0, NULL) || >+ pci_find_device(PCI_VENDOR_ID_INTEL, >+ PCI_DEVICE_ID_INTEL_82443GX_2, NULL)) >+ return 0; >+ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_INTEL_82371FB_0: >+ case PCI_DEVICE_ID_INTEL_82371SB_0: >+ case PCI_DEVICE_ID_INTEL_82371AB_0: >+ case PCI_DEVICE_ID_INTEL_82371MX: >+ case PCI_DEVICE_ID_INTEL_82443MX_0: >+ case PCI_DEVICE_ID_INTEL_82801AA_0: >+ case PCI_DEVICE_ID_INTEL_82801AB_0: >+ case PCI_DEVICE_ID_INTEL_82801BA_0: >+ case PCI_DEVICE_ID_INTEL_82801BA_10: >+ case PCI_DEVICE_ID_INTEL_82801CA_0: >+ case PCI_DEVICE_ID_INTEL_82801CA_12: >+ case PCI_DEVICE_ID_INTEL_82801DB_0: >+ case PCI_DEVICE_ID_INTEL_82801E_0: >+ case PCI_DEVICE_ID_INTEL_82801EB_0: >+ case PCI_DEVICE_ID_INTEL_ESB_1: >+ case PCI_DEVICE_ID_INTEL_ICH6_0: >+ case PCI_DEVICE_ID_INTEL_ICH6_1: >+ case PCI_DEVICE_ID_INTEL_ICH7_0: >+ case PCI_DEVICE_ID_INTEL_ICH7_1: >+ case PCI_DEVICE_ID_INTEL_ICH7_30: >+ case PCI_DEVICE_ID_INTEL_ICH7_31: >+ case PCI_DEVICE_ID_INTEL_ESB2_0: >+ case PCI_DEVICE_ID_INTEL_ICH8_0: >+ case PCI_DEVICE_ID_INTEL_ICH8_1: >+ case PCI_DEVICE_ID_INTEL_ICH8_2: >+ case PCI_DEVICE_ID_INTEL_ICH8_3: >+ case PCI_DEVICE_ID_INTEL_ICH8_4: >+ case PCI_DEVICE_ID_INTEL_ICH9_0: >+ case PCI_DEVICE_ID_INTEL_ICH9_1: >+ case PCI_DEVICE_ID_INTEL_ICH9_2: >+ case PCI_DEVICE_ID_INTEL_ICH9_3: >+ case PCI_DEVICE_ID_INTEL_ICH9_4: >+ case PCI_DEVICE_ID_INTEL_ICH9_5: >+ r->name = "PIIX/ICH"; >+ r->get = pirq_piix_get; >+ r->set = pirq_piix_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ /* FIXME: We should move some of the quirk fixup stuff here */ >+ >+ /* >+ * work arounds for some buggy BIOSes >+ */ >+ if (device == PCI_DEVICE_ID_VIA_82C586_0) { >+ switch(router->device) { >+ case PCI_DEVICE_ID_VIA_82C686: >+ /* >+ * Asus k7m bios wrongly reports 82C686A >+ * as 586-compatible >+ */ >+ device = PCI_DEVICE_ID_VIA_82C686; >+ break; >+ case PCI_DEVICE_ID_VIA_8235: >+ /** >+ * Asus a7v-x bios wrongly reports 8235 >+ * as 586-compatible >+ */ >+ device = PCI_DEVICE_ID_VIA_8235; >+ break; >+ } >+ } >+ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_VIA_82C586_0: >+ r->name = "VIA"; >+ r->get = pirq_via586_get; >+ r->set = pirq_via586_set; >+ return 1; >+ case PCI_DEVICE_ID_VIA_82C596: >+ case PCI_DEVICE_ID_VIA_82C686: >+ case PCI_DEVICE_ID_VIA_8231: >+ /* FIXME: add new ones for 8233/5 */ >+ r->name = "VIA"; >+ r->get = pirq_via_get; >+ r->set = pirq_via_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_VLSI_82C534: >+ r->name = "VLSI 82C534"; >+ r->get = pirq_vlsi_get; >+ r->set = pirq_vlsi_set; >+ return 1; >+ } >+ return 0; >+} >+ >+ >+static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_SERVERWORKS_OSB4: >+ case PCI_DEVICE_ID_SERVERWORKS_CSB5: >+ r->name = "ServerWorks"; >+ r->get = pirq_serverworks_get; >+ r->set = pirq_serverworks_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ if (device != PCI_DEVICE_ID_SI_503) >+ return 0; >+ >+ r->name = "SIS"; >+ r->get = pirq_sis_get; >+ r->set = pirq_sis_set; >+ return 1; >+} >+ >+static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_CYRIX_5520: >+ r->name = "NatSemi"; >+ r->get = pirq_cyrix_get; >+ r->set = pirq_cyrix_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_OPTI_82C700: >+ r->name = "OPTI"; >+ r->get = pirq_opti_get; >+ r->set = pirq_opti_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_ITE_IT8330G_0: >+ r->name = "ITE"; >+ r->get = pirq_ite_get; >+ r->set = pirq_ite_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_AL_M1533: >+ case PCI_DEVICE_ID_AL_M1563: >+ printk("PCI: Using ALI IRQ Router\n"); >+ r->name = "ALI"; >+ r->get = pirq_ali_get; >+ r->set = pirq_ali_set; >+ return 1; >+ } >+ return 0; >+} >+ >+static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) >+{ >+ switch(device) >+ { >+ case PCI_DEVICE_ID_AMD_VIPER_740B: >+ r->name = "AMD756"; >+ break; >+ case PCI_DEVICE_ID_AMD_VIPER_7413: >+ r->name = "AMD766"; >+ break; >+ case PCI_DEVICE_ID_AMD_VIPER_7443: >+ r->name = "AMD768"; >+ break; >+ default: >+ return 0; >+ } >+ r->get = pirq_amd756_get; >+ r->set = pirq_amd756_set; >+ return 1; >+} >+ >+static __initdata struct irq_router_handler pirq_routers[] = { >+ { PCI_VENDOR_ID_INTEL, intel_router_probe }, >+ { PCI_VENDOR_ID_AL, ali_router_probe }, >+ { PCI_VENDOR_ID_ITE, ite_router_probe }, >+ { PCI_VENDOR_ID_VIA, via_router_probe }, >+ { PCI_VENDOR_ID_OPTI, opti_router_probe }, >+ { PCI_VENDOR_ID_SI, sis_router_probe }, >+ { PCI_VENDOR_ID_CYRIX, cyrix_router_probe }, >+ { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, >+ { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, >+ { PCI_VENDOR_ID_AMD, amd_router_probe }, >+ /* Someone with docs needs to add the ATI Radeon IGP */ >+ { 0, NULL } >+}; >+static struct irq_router pirq_router; >+static struct pci_dev *pirq_router_dev; >+ >+ >+/* >+ * FIXME: should we have an option to say "generic for >+ * chipset" ? >+ */ >+ >+static void __init pirq_find_router(struct irq_router *r) >+{ >+ struct irq_routing_table *rt = pirq_table; >+ struct irq_router_handler *h; >+ >+#ifdef CONFIG_PCI_BIOS >+ if (!rt->signature) { >+ printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); >+ r->set = pirq_bios_set; >+ r->name = "BIOS"; >+ return; >+ } >+#endif >+ >+ /* Default unless a driver reloads it */ >+ r->name = "default"; >+ r->get = NULL; >+ r->set = NULL; >+ >+ DBG("PCI: Attempting to find IRQ router for %04x:%04x\n", >+ rt->rtr_vendor, rt->rtr_device); >+ >+ pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn); >+ if (!pirq_router_dev) { >+ DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); >+ return; >+ } >+ >+ for( h = pirq_routers; h->vendor; h++) { >+ /* First look for a router match */ >+ if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device)) >+ break; >+ /* Fall back to a device match */ >+ if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device)) >+ break; >+ } >+ printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", >+ pirq_router.name, >+ pirq_router_dev->vendor, >+ pirq_router_dev->device, >+ pci_name(pirq_router_dev)); >+} >+ >+static struct irq_info *pirq_get_info(struct pci_dev *dev) >+{ >+ struct irq_routing_table *rt = pirq_table; >+ int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); >+ struct irq_info *info; >+ >+ for (info = rt->slots; entries--; info++) >+ if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn)) >+ return info; >+ return NULL; >+} >+ >+static int pcibios_lookup_irq(struct pci_dev *dev, int assign) >+{ >+ u8 pin; >+ struct irq_info *info; >+ int i, pirq, newirq; >+ int irq = 0; >+ u32 mask; >+ struct irq_router *r = &pirq_router; >+ struct pci_dev *dev2 = NULL; >+ char *msg = NULL; >+ >+ /* Find IRQ pin */ >+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); >+ if (!pin) { >+ DBG(" -> no interrupt pin\n"); >+ return 0; >+ } >+ pin = pin - 1; >+ >+ /* Find IRQ routing entry */ >+ >+ if (!pirq_table) >+ return 0; >+ >+ DBG("IRQ for %s:%d", pci_name(dev), pin); >+ info = pirq_get_info(dev); >+ if (!info) { >+ DBG(" -> not found in routing table\n"); >+ return 0; >+ } >+ pirq = info->irq[pin].link; >+ mask = info->irq[pin].bitmap; >+ if (!pirq) { >+ DBG(" -> not routed\n"); >+ return 0; >+ } >+ DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); >+ mask &= pcibios_irq_mask; >+ >+ /* Work around broken HP Pavilion Notebooks which assign USB to >+ IRQ 9 even though it is actually wired to IRQ 11 */ >+ >+ if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) { >+ dev->irq = 11; >+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); >+ r->set(pirq_router_dev, dev, pirq, 11); >+ } >+ >+ /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ >+ if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { >+ pirq = 0x68; >+ mask = 0x400; >+ dev->irq = r->get(pirq_router_dev, dev, pirq); >+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); >+ } >+ >+ /* >+ * Find the best IRQ to assign: use the one >+ * reported by the device if possible. >+ */ >+ newirq = dev->irq; >+ if (!((1 << newirq) & mask)) { >+ if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0; >+ else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, pci_name(dev)); >+ } >+ if (!newirq && assign) { >+ for (i = 0; i < 16; i++) { >+ if (!(mask & (1 << i))) >+ continue; >+ if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, SA_SHIRQ)) >+ newirq = i; >+ } >+ } >+ DBG(" -> newirq=%d", newirq); >+ >+ /* Check if it is hardcoded */ >+ if ((pirq & 0xf0) == 0xf0) { >+ irq = pirq & 0xf; >+ DBG(" -> hardcoded IRQ %d\n", irq); >+ msg = "Hardcoded"; >+ } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \ >+ ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) { >+ DBG(" -> got IRQ %d\n", irq); >+ msg = "Found"; >+ } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { >+ DBG(" -> assigning IRQ %d", newirq); >+ if (r->set(pirq_router_dev, dev, pirq, newirq)) { >+ eisa_set_level_irq(newirq); >+ DBG(" ... OK\n"); >+ msg = "Assigned"; >+ irq = newirq; >+ } >+ } >+ >+ if (!irq) { >+ DBG(" ... failed\n"); >+ if (newirq && mask == (1 << newirq)) { >+ msg = "Guessed"; >+ irq = newirq; >+ } else >+ return 0; >+ } >+ printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, pci_name(dev)); >+ >+ /* Update IRQ for all devices with the same pirq value */ >+ while ((dev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { >+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); >+ if (!pin) >+ continue; >+ pin--; >+ info = pirq_get_info(dev2); >+ if (!info) >+ continue; >+ if (info->irq[pin].link == pirq) { >+ /* We refuse to override the dev->irq information. Give a warning! */ >+ if ( dev2->irq && dev2->irq != irq && \ >+ (!(pci_probe & PCI_USE_PIRQ_MASK) || \ >+ ((1 << dev2->irq) & mask)) ) { >+#ifndef CONFIG_PCI_MSI >+ 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; >+ pirq_penalty[irq]++; >+ if (dev != dev2) >+ printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2)); >+ } >+ } >+ return 1; >+} >+ >+static void __init pcibios_fixup_irqs(void) >+{ >+ struct pci_dev *dev = NULL; >+ u8 pin; >+ >+ DBG("PCI: IRQ fixup\n"); >+ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { >+ /* >+ * If the BIOS has set an out of range IRQ number, just ignore it. >+ * Also keep track of which IRQ's are already in use. >+ */ >+ if (dev->irq >= 16) { >+ DBG("%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq); >+ dev->irq = 0; >+ } >+ /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ >+ if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000) >+ pirq_penalty[dev->irq] = 0; >+ pirq_penalty[dev->irq]++; >+ } >+ >+ dev = NULL; >+ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { >+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); >+#ifdef CONFIG_X86_IO_APIC >+ /* >+ * Recalculate IRQ numbers if we use the I/O APIC. >+ */ >+ if (io_apic_assign_pci_irqs) >+ { >+ int irq; >+ >+ if (pin) { >+ pin--; /* interrupt pins are numbered starting from 1 */ >+ irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); >+ /* >+ * Busses behind bridges are typically not listed in the MP-table. >+ * In this case we have to look up the IRQ based on the parent bus, >+ * parent slot, and pin number. The SMP code detects such bridged >+ * busses itself so we should get into this branch reliably. >+ */ >+ if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ >+ struct pci_dev * bridge = dev->bus->self; >+ >+ pin = (pin + PCI_SLOT(dev->devfn)) % 4; >+ irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, >+ PCI_SLOT(bridge->devfn), pin); >+ if (irq >= 0) >+ printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", >+ 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; >+ } >+ } >+ } >+#endif >+ /* >+ * Still no IRQ? Try to lookup one... >+ */ >+ if (pin && !dev->irq) >+ pcibios_lookup_irq(dev, 0); >+ } >+} >+ >+/* >+ * Work around broken HP Pavilion Notebooks which assign USB to >+ * IRQ 9 even though it is actually wired to IRQ 11 >+ */ >+static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) >+{ >+ if (!broken_hp_bios_irq9) { >+ broken_hp_bios_irq9 = 1; >+ printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); >+ } >+ return 0; >+} >+ >+/* >+ * Work around broken Acer TravelMate 360 Notebooks which assign >+ * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 >+ */ >+static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) >+{ >+ if (!acer_tm360_irqrouting) { >+ acer_tm360_irqrouting = 1; >+ printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); >+ } >+ return 0; >+} >+ >+static struct dmi_system_id __initdata pciirq_dmi_table[] = { >+ { >+ .callback = fix_broken_hp_bios_irq9, >+ .ident = "HP Pavilion N5400 Series Laptop", >+ .matches = { >+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), >+ DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"), >+ DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), >+ DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), >+ }, >+ }, >+ { >+ .callback = fix_acer_tm360_irqrouting, >+ .ident = "Acer TravelMate 36x Laptop", >+ .matches = { >+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), >+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), >+ }, >+ }, >+ { } >+}; >+ >+static int __init pcibios_irq_init(void) >+{ >+ DBG("PCI: IRQ init\n"); >+ >+ if (pcibios_enable_irq || raw_pci_ops == NULL) >+ return 0; >+ >+ dmi_check_system(pciirq_dmi_table); >+ >+ pirq_table = pirq_find_routing_table(); >+ >+#ifdef CONFIG_PCI_BIOS >+ if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) >+ pirq_table = pcibios_get_irq_routing_table(); >+#endif >+ if (pirq_table) { >+ pirq_peer_trick(); >+ pirq_find_router(&pirq_router); >+ if (pirq_table->exclusive_irqs) { >+ int i; >+ for (i=0; i<16; i++) >+ if (!(pirq_table->exclusive_irqs & (1 << i))) >+ pirq_penalty[i] += 100; >+ } >+ /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */ >+ if (io_apic_assign_pci_irqs) >+ pirq_table = NULL; >+ } >+ >+ pcibios_enable_irq = pirq_enable_irq; >+ >+ pcibios_fixup_irqs(); >+ return 0; >+} >+ >+subsys_initcall(pcibios_irq_init); >+ >+ >+void pcibios_penalize_isa_irq(int irq) >+{ >+ /* >+ * If any ISAPnP device reports an IRQ in its list of possible >+ * IRQ's, we try to avoid assigning it to PCI devices. >+ */ >+ pirq_penalty[irq] += 100; >+} >+ >+int pirq_enable_irq(struct pci_dev *dev) >+{ >+ u8 pin; >+ extern int interrupt_line_quirk; >+ struct pci_dev *temp_dev; >+ >+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); >+ if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { >+ char *msg; >+ msg = ""; >+ if (io_apic_assign_pci_irqs) { >+ int irq; >+ >+ if (pin) { >+ pin--; /* interrupt pins are numbered starting from 1 */ >+ irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); >+ /* >+ * Busses behind bridges are typically not listed in the MP-table. >+ * In this case we have to look up the IRQ based on the parent bus, >+ * parent slot, and pin number. The SMP code detects such bridged >+ * busses itself so we should get into this branch reliably. >+ */ >+ temp_dev = dev; >+ while (irq < 0 && dev->bus->parent) { /* go back to the bridge */ >+ struct pci_dev * bridge = dev->bus->self; >+ >+ pin = (pin + PCI_SLOT(dev->devfn)) % 4; >+ irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, >+ PCI_SLOT(bridge->devfn), pin); >+ if (irq >= 0) >+ printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", >+ bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); >+ dev = bridge; >+ } >+ dev = temp_dev; >+ if (irq >= 0) { >+#ifdef CONFIG_PCI_MSI >+ if (!platform_legacy_irq(irq)) >+ irq = IO_APIC_VECTOR(irq); >+#endif >+ 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; >+ return 0; >+ } else >+ msg = " Probably buggy MP table."; >+ } >+ } else if (pci_probe & PCI_BIOS_IRQ_SCAN) >+ msg = ""; >+ else >+ msg = " Please try using pci=biosirq."; >+ >+ /* With IDE legacy devices the IRQ lookup failure is not a problem.. */ >+ if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) >+ return 0; >+ >+ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", >+ 'A' + pin - 1, pci_name(dev), msg); >+ } >+ /* VIA bridges use interrupt line for apic/pci steering across >+ the V-Link */ >+ else if (interrupt_line_quirk) >+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15); >+ return 0; >+} >+ >+int pci_vector_resources(int last, int nr_released) >+{ >+ int count = nr_released; >+ >+ int next = last; >+ int offset = (last % 8); >+ >+ while (next < FIRST_SYSTEM_VECTOR) { >+ next += 8; >+#ifdef CONFIG_X86_64 >+ if (next == IA32_SYSCALL_VECTOR) >+ continue; >+#else >+ if (next == SYSCALL_VECTOR) >+ continue; >+#endif >+ count++; >+ if (next >= FIRST_SYSTEM_VECTOR) { >+ if (offset%8) { >+ next = FIRST_DEVICE_VECTOR + offset; >+ offset++; >+ continue; >+ } >+ count--; >+ } >+ } >+ >+ return count; >+} >diff -Nurp linux-2.6.9.orig/arch/i386/pci/Makefile linux-2.6.9/arch/i386/pci/Makefile >--- linux-2.6.9.orig/arch/i386/pci/Makefile 2007-04-18 16:50:38.000000000 -0400 >+++ linux-2.6.9/arch/i386/pci/Makefile 2007-04-18 18:03:36.000000000 -0400 >@@ -12,3 +12,8 @@ pci-$(CONFIG_X86_VISWS) := visws.o fixu > pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o > > obj-y += $(pci-y) common.o >+ >+ifdef CONFIG_XEN >+include $(srctree)/scripts/Makefile.xen >+obj-y := $(call cherrypickxen, $(obj-y)) >+endif >diff -Nurp linux-2.6.9.orig/arch/x86_64/Kconfig linux-2.6.9/arch/x86_64/Kconfig >--- linux-2.6.9.orig/arch/x86_64/Kconfig 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/arch/x86_64/Kconfig 2007-04-18 17:03:26.000000000 -0400 >@@ -433,6 +433,21 @@ config PCI_MMCONFIG > depends on PCI > select ACPI_BOOT > >+config XEN_PCIDEV_FRONTEND >+ bool "Xen PCI Frontend" >+ depends on PCI && X86_64_XEN >+ default y >+ help >+ The PCI device frontend driver allows the kernel to import arbitrary >+ PCI devices from a PCI backend to support PCI driver domains. >+ >+config XEN_PCIDEV_FE_DEBUG >+ bool "Xen PCI Frontend Debugging" >+ depends on XEN_PCIDEV_FRONTEND >+ default n >+ help >+ Enables some debug statements within the PCI Frontend. >+ > config UNORDERED_IO > bool "Unordered IO mapping access" > depends on EXPERIMENTAL >diff -Nurp linux-2.6.9.orig/configs/kernel-2.6.9-i686-xenU.config linux-2.6.9/configs/kernel-2.6.9-i686-xenU.config >--- linux-2.6.9.orig/configs/kernel-2.6.9-i686-xenU.config 2007-04-18 16:50:55.000000000 -0400 >+++ linux-2.6.9/configs/kernel-2.6.9-i686-xenU.config 2007-04-18 17:26:24.000000000 -0400 >@@ -134,7 +134,19 @@ CONFIG_HAVE_DEC_LOCK=y > # > # Bus options (PCI, PCMCIA, EISA, MCA, ISA) > # >-# CONFIG_PCI is not set >+CONFIG_PCI=y >+# CONFIG_PCI_GOBIOS is not set >+# CONFIG_PCI_GOMMCONFIG is not set >+# CONFIG_PCI_GODIRECT is not set >+# CONFIG_PCI_GOXEN_FE is not set >+CONFIG_PCI_GOANY=y >+CONFIG_PCI_DIRECT=y >+CONFIG_PCI_MMCONFIG=y >+CONFIG_PCI_MSI=y >+CONFIG_PCI_LEGACY_PROC=y >+# CONFIG_PCI_NAMES is not set >+CONFIG_XEN_PCIDEV_FRONTEND=y >+# CONFIG_XEN_PCIDEV_FE_DEBUG is not set > # CONFIG_SCx200 is not set > CONFIG_HOTPLUG_CPU=y > >diff -Nurp linux-2.6.9.orig/configs/kernel-2.6.9-x86_64-xenU.config linux-2.6.9/configs/kernel-2.6.9-x86_64-xenU.config >--- linux-2.6.9.orig/configs/kernel-2.6.9-x86_64-xenU.config 2007-04-18 16:50:57.000000000 -0400 >+++ linux-2.6.9/configs/kernel-2.6.9-x86_64-xenU.config 2007-04-18 17:27:04.000000000 -0400 >@@ -93,8 +93,15 @@ CONFIG_DUMMY_IOMMU=y > # > # Bus options (PCI etc.) > # >-# CONFIG_PCI is not set >+CONFIG_PCI=y >+CONFIG_PCI_DIRECT=y >+CONFIG_PCI_MMCONFIG=y > # CONFIG_UNORDERED_IO is not set >+CONFIG_PCI_MSI=y >+CONFIG_PCI_LEGACY_PROC=y >+# CONFIG_PCI_NAMES is not set >+CONFIG_XEN_PCIDEV_FRONTEND=y >+# CONFIG_XEN_PCIDEV_FE_DEBUG is not set > CONFIG_HOTPLUG_CPU=y > > # >diff -Nurp linux-2.6.9.orig/drivers/pci/bus.c linux-2.6.9/drivers/pci/bus.c >--- linux-2.6.9.orig/drivers/pci/bus.c 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/drivers/pci/bus.c 2007-04-18 17:48:06.000000000 -0400 >@@ -138,6 +138,51 @@ void pci_enable_bridges(struct pci_bus * > } > } > >+/** pci_walk_bus - walk devices on/under bus, calling callback. >+ * @top bus whose devices should be walked >+ * @cb callback to be called for each device found >+ * @userdata arbitrary pointer to be passed to callback. >+ * >+ * Walk the given bus, including any bridged devices >+ * on buses under this bus. Call the provided callback >+ * on each device found. >+ */ >+void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), >+ void *userdata) >+{ >+ struct pci_dev *dev; >+ struct pci_bus *bus; >+ struct list_head *next; >+ >+ bus = top; >+ spin_lock(&pci_bus_lock); >+ next = top->devices.next; >+ for (;;) { >+ if (next == &bus->devices) { >+ /* end of this bus, go up or finish */ >+ if (bus == top) >+ break; >+ next = bus->self->bus_list.next; >+ bus = bus->self->bus; >+ continue; >+ } >+ dev = list_entry(next, struct pci_dev, bus_list); >+ if (dev->subordinate) { >+ /* this is a pci-pci bridge, do its devices next */ >+ next = dev->subordinate->devices.next; >+ bus = dev->subordinate; >+ } else >+ next = dev->bus_list.next; >+ >+ /* Run device routines with the device locked */ >+ // down(&dev->dev.sem); >+ cb(dev, userdata); >+ // up(&dev->dev.sem); >+ } >+ spin_unlock(&pci_bus_lock); >+} >+EXPORT_SYMBOL_GPL(pci_walk_bus); >+ > EXPORT_SYMBOL(pci_bus_alloc_resource); > EXPORT_SYMBOL(pci_bus_add_devices); > EXPORT_SYMBOL(pci_enable_bridges); >diff -Nurp linux-2.6.9.orig/drivers/xen/Makefile linux-2.6.9/drivers/xen/Makefile >--- linux-2.6.9.orig/drivers/xen/Makefile 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/drivers/xen/Makefile 2007-04-18 16:55:22.000000000 -0400 >@@ -15,3 +15,4 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blk > obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ > obj-$(CONFIG_XEN_FRAMEBUFFER) += fbfront/ > obj-$(CONFIG_XEN_KEYBOARD) += fbfront/ >+obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ >diff -Nurp linux-2.6.9.orig/drivers/xen/pcifront/Makefile linux-2.6.9/drivers/xen/pcifront/Makefile >--- linux-2.6.9.orig/drivers/xen/pcifront/Makefile 1969-12-31 19:00:00.000000000 -0500 >+++ linux-2.6.9/drivers/xen/pcifront/Makefile 2007-04-18 16:53:08.000000000 -0400 >@@ -0,0 +1,7 @@ >+obj-y += pcifront.o >+ >+pcifront-y := pci_op.o xenbus.o pci.o >+ >+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y) >+EXTRA_CFLAGS += -DDEBUG >+endif >diff -Nurp linux-2.6.9.orig/drivers/xen/pcifront/pci.c linux-2.6.9/drivers/xen/pcifront/pci.c >--- linux-2.6.9.orig/drivers/xen/pcifront/pci.c 1969-12-31 19:00:00.000000000 -0500 >+++ linux-2.6.9/drivers/xen/pcifront/pci.c 2007-04-18 16:53:08.000000000 -0400 >@@ -0,0 +1,46 @@ >+/* >+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time >+ * >+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> >+ */ >+#include <linux/module.h> >+#include <linux/init.h> >+#include <linux/pci.h> >+#include <linux/spinlock.h> >+#include "pcifront.h" >+ >+DEFINE_SPINLOCK(pcifront_dev_lock); >+static struct pcifront_device *pcifront_dev = NULL; >+ >+int pcifront_connect(struct pcifront_device *pdev) >+{ >+ int err = 0; >+ >+ spin_lock(&pcifront_dev_lock); >+ >+ if (!pcifront_dev) { >+ dev_info(&pdev->xdev->dev, "Installing PCI frontend\n"); >+ pcifront_dev = pdev; >+ } >+ else { >+ dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); >+ err = -EEXIST; >+ } >+ >+ spin_unlock(&pcifront_dev_lock); >+ >+ return err; >+} >+ >+void pcifront_disconnect(struct pcifront_device *pdev) >+{ >+ spin_lock(&pcifront_dev_lock); >+ >+ if (pdev == pcifront_dev) { >+ dev_info(&pdev->xdev->dev, >+ "Disconnecting PCI Frontend Buses\n"); >+ pcifront_dev = NULL; >+ } >+ >+ spin_unlock(&pcifront_dev_lock); >+} >diff -Nurp linux-2.6.9.orig/drivers/xen/pcifront/pcifront.h linux-2.6.9/drivers/xen/pcifront/pcifront.h >--- linux-2.6.9.orig/drivers/xen/pcifront/pcifront.h 1969-12-31 19:00:00.000000000 -0500 >+++ linux-2.6.9/drivers/xen/pcifront/pcifront.h 2007-04-18 16:53:08.000000000 -0400 >@@ -0,0 +1,40 @@ >+/* >+ * PCI Frontend - Common data structures & function declarations >+ * >+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> >+ */ >+#ifndef __XEN_PCIFRONT_H__ >+#define __XEN_PCIFRONT_H__ >+ >+#include <linux/spinlock.h> >+#include <linux/pci.h> >+#include <xen/xenbus.h> >+#include <xen/interface/io/pciif.h> >+#include <xen/pcifront.h> >+ >+struct pci_bus_entry { >+ struct list_head list; >+ struct pci_bus *bus; >+}; >+ >+struct pcifront_device { >+ struct xenbus_device *xdev; >+ struct list_head root_buses; >+ spinlock_t dev_lock; >+ >+ int evtchn; >+ int gnt_ref; >+ >+ /* Lock this when doing any operations in sh_info */ >+ spinlock_t sh_info_lock; >+ struct xen_pci_sharedinfo *sh_info; >+}; >+ >+int pcifront_connect(struct pcifront_device *pdev); >+void pcifront_disconnect(struct pcifront_device *pdev); >+ >+int pcifront_scan_root(struct pcifront_device *pdev, >+ unsigned int domain, unsigned int bus); >+void pcifront_free_roots(struct pcifront_device *pdev); >+ >+#endif /* __XEN_PCIFRONT_H__ */ >diff -Nurp linux-2.6.9.orig/drivers/xen/pcifront/pci_op.c linux-2.6.9/drivers/xen/pcifront/pci_op.c >--- linux-2.6.9.orig/drivers/xen/pcifront/pci_op.c 1969-12-31 19:00:00.000000000 -0500 >+++ linux-2.6.9/drivers/xen/pcifront/pci_op.c 2007-04-18 17:45:06.000000000 -0400 >@@ -0,0 +1,273 @@ >+/* >+ * PCI Frontend Operations - Communicates with frontend >+ * >+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> >+ */ >+#include <linux/module.h> >+#include <linux/version.h> >+#include <linux/init.h> >+#include <linux/pci.h> >+#include <linux/spinlock.h> >+#include <linux/time.h> >+#include <xen/evtchn.h> >+#include "pcifront.h" >+ >+static int verbose_request = 0; >+module_param(verbose_request, int, 0644); >+ >+static int errno_to_pcibios_err(int errno) >+{ >+ switch (errno) { >+ case XEN_PCI_ERR_success: >+ return PCIBIOS_SUCCESSFUL; >+ >+ case XEN_PCI_ERR_dev_not_found: >+ return PCIBIOS_DEVICE_NOT_FOUND; >+ >+ case XEN_PCI_ERR_invalid_offset: >+ case XEN_PCI_ERR_op_failed: >+ return PCIBIOS_BAD_REGISTER_NUMBER; >+ >+ case XEN_PCI_ERR_not_implemented: >+ return PCIBIOS_FUNC_NOT_SUPPORTED; >+ >+ case XEN_PCI_ERR_access_denied: >+ return PCIBIOS_SET_FAILED; >+ } >+ return errno; >+} >+ >+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) >+{ >+ int err = 0; >+ struct xen_pci_op *active_op = &pdev->sh_info->op; >+ unsigned long irq_flags; >+ evtchn_port_t port = pdev->evtchn; >+ unsigned long jf, jf_timeout; >+ struct timeval tv; >+ >+ spin_lock_irqsave(&pdev->sh_info_lock, irq_flags); >+ >+ memcpy(active_op, op, sizeof(struct xen_pci_op)); >+ >+ /* Go */ >+ wmb(); >+ set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); >+ notify_remote_via_evtchn(port); >+ >+ /* >+ * We set a poll timeout of 3 seconds but give up on return after >+ * 2 seconds. It is better to time out too late rather than too early >+ * (in the latter case we end up continually re-executing poll() with a >+ * timeout in the past). 1s difference gives plenty of slack for error. >+ */ >+ do_gettimeofday(&tv); >+ jf_timeout = timeval_to_jiffies(&tv) + 2 * NSEC_PER_SEC; >+ >+ clear_evtchn(port); >+ >+ while (test_bit(_XEN_PCIF_active, >+ (unsigned long *)&pdev->sh_info->flags)) { >+ if (HYPERVISOR_poll(&port, 1, jiffies + 3*HZ)) >+ BUG(); >+ clear_evtchn(port); >+ do_gettimeofday(&tv); >+ jf = timeval_to_jiffies(&tv); >+ if (jf > jf_timeout) { >+ dev_err(&pdev->xdev->dev, >+ "pciback not responding!!!\n"); >+ clear_bit(_XEN_PCIF_active, >+ (unsigned long *)&pdev->sh_info->flags); >+ err = XEN_PCI_ERR_dev_not_found; >+ goto out; >+ } >+ } >+ >+ memcpy(op, active_op, sizeof(struct xen_pci_op)); >+ >+ err = op->err; >+ out: >+ spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags); >+ return err; >+} >+ >+/* Access to this function is spinlocked in drivers/pci/access.c */ >+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn, >+ int where, int size, u32 * val) >+{ >+ int err = 0; >+ struct xen_pci_op op = { >+ .cmd = XEN_PCI_OP_conf_read, >+ .domain = pci_domain_nr(bus), >+ .bus = bus->number, >+ .devfn = devfn, >+ .offset = where, >+ .size = size, >+ }; >+ struct pcifront_sd *sd = bus->sysdata; >+ struct pcifront_device *pdev = pcifront_get_pdev(sd); >+ >+ if (verbose_request) >+ dev_info(&pdev->xdev->dev, >+ "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n", >+ pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), >+ PCI_FUNC(devfn), where, size); >+ >+ err = do_pci_op(pdev, &op); >+ >+ if (likely(!err)) { >+ if (verbose_request) >+ dev_info(&pdev->xdev->dev, "read got back value %x\n", >+ op.value); >+ >+ *val = op.value; >+ } else if (err == -ENODEV) { >+ /* No device here, pretend that it just returned 0 */ >+ err = 0; >+ *val = 0; >+ } >+ >+ return errno_to_pcibios_err(err); >+} >+ >+/* Access to this function is spinlocked in drivers/pci/access.c */ >+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn, >+ int where, int size, u32 val) >+{ >+ struct xen_pci_op op = { >+ .cmd = XEN_PCI_OP_conf_write, >+ .domain = pci_domain_nr(bus), >+ .bus = bus->number, >+ .devfn = devfn, >+ .offset = where, >+ .size = size, >+ .value = val, >+ }; >+ struct pcifront_sd *sd = bus->sysdata; >+ struct pcifront_device *pdev = pcifront_get_pdev(sd); >+ >+ if (verbose_request) >+ dev_info(&pdev->xdev->dev, >+ "write dev=%04x:%02x:%02x.%01x - " >+ "offset %x size %d val %x\n", >+ pci_domain_nr(bus), bus->number, >+ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); >+ >+ return errno_to_pcibios_err(do_pci_op(pdev, &op)); >+} >+ >+struct pci_ops pcifront_bus_ops = { >+ .read = pcifront_bus_read, >+ .write = pcifront_bus_write, >+}; >+ >+/* Claim resources for the PCI frontend as-is, backend won't allow changes */ >+static void pcifront_claim_resource(struct pci_dev *dev, void *data) >+{ >+ struct pcifront_device *pdev = data; >+ int i; >+ struct resource *r; >+ >+ for (i = 0; i < PCI_NUM_RESOURCES; i++) { >+ r = &dev->resource[i]; >+ >+ if (!r->parent && r->start && r->flags) { >+ dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n", >+ pci_name(dev), i); >+ pci_claim_resource(dev, i); >+ } >+ } >+} >+ >+int pcifront_scan_root(struct pcifront_device *pdev, >+ unsigned int domain, unsigned int bus) >+{ >+ struct pci_bus *b; >+ struct pcifront_sd *sd = NULL; >+ struct pci_bus_entry *bus_entry = NULL; >+ int err = 0; >+ >+#ifndef CONFIG_PCI_DOMAINS >+ if (domain != 0) { >+ dev_err(&pdev->xdev->dev, >+ "PCI Root in non-zero PCI Domain! domain=%d\n", domain); >+ dev_err(&pdev->xdev->dev, >+ "Please compile with CONFIG_PCI_DOMAINS\n"); >+ err = -EINVAL; >+ goto err_out; >+ } >+#endif >+ >+ dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", >+ domain, bus); >+ >+ bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); >+ sd = kmalloc(sizeof(*sd), GFP_KERNEL); >+ if (!bus_entry || !sd) { >+ err = -ENOMEM; >+ goto err_out; >+ } >+ pcifront_init_sd(sd, domain, pdev); >+ >+ b = pci_scan_bus_parented(&pdev->xdev->dev, bus, >+ &pcifront_bus_ops, sd); >+ if (!b) { >+ dev_err(&pdev->xdev->dev, >+ "Error creating PCI Frontend Bus!\n"); >+ err = -ENOMEM; >+ goto err_out; >+ } >+ bus_entry->bus = b; >+ >+ list_add(&bus_entry->list, &pdev->root_buses); >+ >+ /* Claim resources before going "live" with our devices */ >+ pci_walk_bus(b, pcifront_claim_resource, pdev); >+ >+ pci_bus_add_devices(b); >+ >+ return 0; >+ >+ err_out: >+ kfree(bus_entry); >+ kfree(sd); >+ >+ return err; >+} >+ >+static void free_root_bus_devs(struct pci_bus *bus) >+{ >+ struct pci_dev *dev; >+ >+ spin_lock(&pci_bus_lock); >+ while (!list_empty(&bus->devices)) { >+ dev = container_of(bus->devices.next, struct pci_dev, bus_list); >+ spin_unlock(&pci_bus_lock); >+ >+ dev_dbg(&dev->dev, "removing device\n"); >+ pci_remove_bus_device(dev); >+ >+ spin_lock(&pci_bus_lock); >+ } >+ spin_unlock(&pci_bus_lock); >+} >+ >+void pcifront_free_roots(struct pcifront_device *pdev) >+{ >+ struct pci_bus_entry *bus_entry, *t; >+ >+ dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); >+ >+ list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { >+ list_del(&bus_entry->list); >+ >+ free_root_bus_devs(bus_entry->bus); >+ >+ kfree(bus_entry->bus->sysdata); >+ >+ device_unregister(bus_entry->bus->bridge); >+ pci_remove_bus(bus_entry->bus); >+ >+ kfree(bus_entry); >+ } >+} >diff -Nurp linux-2.6.9.orig/drivers/xen/pcifront/xenbus.c linux-2.6.9/drivers/xen/pcifront/xenbus.c >--- linux-2.6.9.orig/drivers/xen/pcifront/xenbus.c 1969-12-31 19:00:00.000000000 -0500 >+++ linux-2.6.9/drivers/xen/pcifront/xenbus.c 2007-04-18 16:53:08.000000000 -0400 >@@ -0,0 +1,295 @@ >+/* >+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn) >+ * >+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> >+ */ >+#include <linux/module.h> >+#include <linux/init.h> >+#include <linux/mm.h> >+#include <xen/xenbus.h> >+#include <xen/gnttab.h> >+#include "pcifront.h" >+ >+#define INVALID_GRANT_REF (0) >+#define INVALID_EVTCHN (-1) >+ >+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) >+{ >+ struct pcifront_device *pdev; >+ >+ pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL); >+ if (pdev == NULL) >+ goto out; >+ >+ pdev->sh_info = >+ (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL); >+ if (pdev->sh_info == NULL) { >+ kfree(pdev); >+ pdev = NULL; >+ goto out; >+ } >+ pdev->sh_info->flags = 0; >+ >+ xdev->dev.driver_data = pdev; >+ pdev->xdev = xdev; >+ >+ INIT_LIST_HEAD(&pdev->root_buses); >+ >+ spin_lock_init(&pdev->dev_lock); >+ spin_lock_init(&pdev->sh_info_lock); >+ >+ pdev->evtchn = INVALID_EVTCHN; >+ pdev->gnt_ref = INVALID_GRANT_REF; >+ >+ dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n", >+ pdev, pdev->sh_info); >+ out: >+ return pdev; >+} >+ >+static void free_pdev(struct pcifront_device *pdev) >+{ >+ dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev); >+ >+ pcifront_free_roots(pdev); >+ >+ if (pdev->evtchn != INVALID_EVTCHN) >+ xenbus_free_evtchn(pdev->xdev, pdev->evtchn); >+ >+ if (pdev->gnt_ref != INVALID_GRANT_REF) >+ gnttab_end_foreign_access(pdev->gnt_ref, 0, >+ (unsigned long)pdev->sh_info); >+ >+ pdev->xdev->dev.driver_data = NULL; >+ >+ kfree(pdev); >+} >+ >+static int pcifront_publish_info(struct pcifront_device *pdev) >+{ >+ int err = 0; >+ struct xenbus_transaction trans; >+ >+ err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); >+ if (err < 0) >+ goto out; >+ >+ pdev->gnt_ref = err; >+ >+ err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); >+ if (err) >+ goto out; >+ >+ do_publish: >+ err = xenbus_transaction_start(&trans); >+ if (err) { >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error writing configuration for backend " >+ "(start transaction)"); >+ goto out; >+ } >+ >+ err = xenbus_printf(trans, pdev->xdev->nodename, >+ "pci-op-ref", "%u", pdev->gnt_ref); >+ if (!err) >+ err = xenbus_printf(trans, pdev->xdev->nodename, >+ "event-channel", "%u", pdev->evtchn); >+ if (!err) >+ err = xenbus_printf(trans, pdev->xdev->nodename, >+ "magic", XEN_PCI_MAGIC); >+ >+ if (err) { >+ xenbus_transaction_end(trans, 1); >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error writing configuration for backend"); >+ goto out; >+ } else { >+ err = xenbus_transaction_end(trans, 0); >+ if (err == -EAGAIN) >+ goto do_publish; >+ else if (err) { >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error completing transaction " >+ "for backend"); >+ goto out; >+ } >+ } >+ >+ xenbus_switch_state(pdev->xdev, XenbusStateInitialised); >+ >+ dev_dbg(&pdev->xdev->dev, "publishing successful!\n"); >+ >+ out: >+ return err; >+} >+ >+static int pcifront_try_connect(struct pcifront_device *pdev) >+{ >+ int err = -EFAULT; >+ int i, num_roots, len; >+ char str[64]; >+ unsigned int domain, bus; >+ >+ spin_lock(&pdev->dev_lock); >+ >+ /* Only connect once */ >+ if (xenbus_read_driver_state(pdev->xdev->nodename) != >+ XenbusStateInitialised) >+ goto out; >+ >+ err = pcifront_connect(pdev); >+ if (err) { >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error connecting PCI Frontend"); >+ goto out; >+ } >+ >+ err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, >+ "root_num", "%d", &num_roots); >+ if (err == -ENOENT) { >+ xenbus_dev_error(pdev->xdev, err, >+ "No PCI Roots found, trying 0000:00"); >+ err = pcifront_scan_root(pdev, 0, 0); >+ num_roots = 0; >+ } else if (err != 1) { >+ if (err == 0) >+ err = -EINVAL; >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error reading number of PCI roots"); >+ goto out; >+ } >+ >+ for (i = 0; i < num_roots; i++) { >+ len = snprintf(str, sizeof(str), "root-%d", i); >+ if (unlikely(len >= (sizeof(str) - 1))) { >+ err = -ENOMEM; >+ goto out; >+ } >+ >+ err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, >+ "%x:%x", &domain, &bus); >+ if (err != 2) { >+ if (err >= 0) >+ err = -EINVAL; >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error reading PCI root %d", i); >+ goto out; >+ } >+ >+ err = pcifront_scan_root(pdev, domain, bus); >+ if (err) { >+ xenbus_dev_fatal(pdev->xdev, err, >+ "Error scanning PCI root %04x:%02x", >+ domain, bus); >+ goto out; >+ } >+ } >+ >+ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); >+ if (err) >+ goto out; >+ >+ out: >+ spin_unlock(&pdev->dev_lock); >+ return err; >+} >+ >+static int pcifront_try_disconnect(struct pcifront_device *pdev) >+{ >+ int err = 0; >+ enum xenbus_state prev_state; >+ >+ spin_lock(&pdev->dev_lock); >+ >+ prev_state = xenbus_read_driver_state(pdev->xdev->nodename); >+ >+ if (prev_state < XenbusStateClosing) >+ err = xenbus_switch_state(pdev->xdev, XenbusStateClosing); >+ >+ if (!err && prev_state == XenbusStateConnected) >+ pcifront_disconnect(pdev); >+ >+ spin_unlock(&pdev->dev_lock); >+ >+ return err; >+} >+ >+static void pcifront_backend_changed(struct xenbus_device *xdev, >+ enum xenbus_state be_state) >+{ >+ struct pcifront_device *pdev = xdev->dev.driver_data; >+ >+ switch (be_state) { >+ case XenbusStateClosing: >+ dev_warn(&xdev->dev, "backend going away!\n"); >+ pcifront_try_disconnect(pdev); >+ break; >+ >+ case XenbusStateUnknown: >+ case XenbusStateClosed: >+ dev_warn(&xdev->dev, "backend went away!\n"); >+ pcifront_try_disconnect(pdev); >+ >+ device_unregister(&pdev->xdev->dev); >+ break; >+ >+ case XenbusStateConnected: >+ pcifront_try_connect(pdev); >+ break; >+ >+ default: >+ break; >+ } >+} >+ >+static int pcifront_xenbus_probe(struct xenbus_device *xdev, >+ const struct xenbus_device_id *id) >+{ >+ int err = 0; >+ struct pcifront_device *pdev = alloc_pdev(xdev); >+ >+ if (pdev == NULL) { >+ err = -ENOMEM; >+ xenbus_dev_fatal(xdev, err, >+ "Error allocating pcifront_device struct"); >+ goto out; >+ } >+ >+ err = pcifront_publish_info(pdev); >+ >+ out: >+ return err; >+} >+ >+static int pcifront_xenbus_remove(struct xenbus_device *xdev) >+{ >+ if (xdev->dev.driver_data) >+ free_pdev(xdev->dev.driver_data); >+ >+ return 0; >+} >+ >+static struct xenbus_device_id xenpci_ids[] = { >+ {"pci"}, >+ {{0}}, >+}; >+ >+static struct xenbus_driver xenbus_pcifront_driver = { >+ .name = "pcifront", >+ .owner = THIS_MODULE, >+ .ids = xenpci_ids, >+ .probe = pcifront_xenbus_probe, >+ .remove = pcifront_xenbus_remove, >+ .otherend_changed = pcifront_backend_changed, >+}; >+ >+static int __init pcifront_init(void) >+{ >+ if (!is_running_on_xen()) >+ return -ENODEV; >+ >+ return xenbus_register_frontend(&xenbus_pcifront_driver); >+} >+ >+/* Initialize after the Xen PCI Frontend Stub is initialized */ >+subsys_initcall(pcifront_init); >diff -Nurp linux-2.6.9.orig/include/asm-i386/mach-xen/asm/pci.h linux-2.6.9/include/asm-i386/mach-xen/asm/pci.h >--- linux-2.6.9.orig/include/asm-i386/mach-xen/asm/pci.h 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/include/asm-i386/mach-xen/asm/pci.h 2007-04-18 17:50:52.000000000 -0400 >@@ -27,7 +27,7 @@ void pcibios_config_init(void); > struct pci_bus * pcibios_scan_root(int bus); > > void pcibios_set_master(struct pci_dev *dev); >-void pcibios_penalize_isa_irq(int irq, int active); >+void pcibios_penalize_isa_irq(int irq); > struct irq_routing_table *pcibios_get_irq_routing_table(void); > int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); > >@@ -122,16 +122,6 @@ static inline void pcibios_add_platform_ > { > } > >-#ifdef CONFIG_PCI >-static inline void pci_dma_burst_advice(struct pci_dev *pdev, >- enum pci_dma_burst_strategy *strat, >- unsigned long *strategy_parameter) >-{ >- *strat = PCI_DMA_BURST_INFINITY; >- *strategy_parameter = ~0UL; >-} >-#endif >- > #endif /* __KERNEL__ */ > > #ifdef CONFIG_XEN_PCIDEV_FRONTEND >diff -Nurp linux-2.6.9.orig/include/linux/pci.h linux-2.6.9/include/linux/pci.h >--- linux-2.6.9.orig/include/linux/pci.h 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/include/linux/pci.h 2007-04-18 17:48:53.000000000 -0400 >@@ -823,6 +823,8 @@ void pci_remove_behind_bridge(struct pci > struct pci_driver *pci_dev_driver(const struct pci_dev *); > const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); > int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); >+void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), >+ void *userdata); > > /* kmem_cache style wrapper around pci_alloc_consistent() */ > >diff -Nurp linux-2.6.9.orig/include/xen/pcifront.h linux-2.6.9/include/xen/pcifront.h >--- linux-2.6.9.orig/include/xen/pcifront.h 2007-04-18 16:50:49.000000000 -0400 >+++ linux-2.6.9/include/xen/pcifront.h 2007-04-18 17:42:38.000000000 -0400 >@@ -12,13 +12,25 @@ > #ifdef __KERNEL__ > > struct pcifront_device; >+struct pci_bus; > > struct pcifront_sd { > int domain; > struct pcifront_device *pdev; > }; > >-struct pci_bus; >+static inline struct pcifront_device * >+pcifront_get_pdev(struct pcifront_sd *sd) >+{ >+ return sd->pdev; >+} >+ >+static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain, >+ struct pcifront_device *pdev) >+{ >+ sd->domain = domain; >+ sd->pdev = pdev; >+} > > #ifdef CONFIG_PCI_DOMAINS > static inline int pci_domain_nr(struct pci_bus *bus) >Binary files linux-2.6.9.orig/vmlinux-stripped and linux-2.6.9/vmlinux-stripped differ >Binary files linux-2.6.9.orig/vmlinuz and linux-2.6.9/vmlinuz differ
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 237026
: 152962 |
152963