Commit 3c80c502 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

merge

parents 5c79e500 435883d2
......@@ -931,6 +931,10 @@ running once the system is up.
enabled.
noacpi [IA-32] Do not use ACPI for IRQ routing
or for PCI scanning.
routeirq Do IRQ routing for all PCI devices.
This is normally done in pci_enable_device(),
so this option is a temporary workaround
for broken drivers that don't call it.
firmware [ARM] Do not re-enumerate the bus but
instead just use the configuration
......
......@@ -6,7 +6,7 @@
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP)
void __init quirk_intel_irqbalance(struct pci_dev *dev)
void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
{
u8 config, rev;
u32 word;
......@@ -45,5 +45,5 @@ void __init quirk_intel_irqbalance(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_intel_irqbalance);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
#endif
......@@ -15,6 +15,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
return pcibios_scan_root(busnum);
}
extern int pci_routeirq;
static int __init pci_acpi_init(void)
{
struct pci_dev *dev = NULL;
......@@ -30,14 +31,27 @@ static int __init pci_acpi_init(void)
pcibios_scanned++;
pcibios_enable_irq = acpi_pci_irq_enable;
if (pci_routeirq) {
/*
* PCI IRQ routing is set up by pci_enable_device(), but we
* also do it here in case there are still broken drivers that
* don't use pci_enable_device().
*/
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
printk(KERN_INFO "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n");
printk(KERN_INFO "** was specified. If this was required to make a driver work,\n");
printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
printk(KERN_INFO "** so I can fix the driver.\n");
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
acpi_pci_irq_enable(dev);
} else {
printk(KERN_INFO "** PCI interrupts are no longer routed automatically. If this\n");
printk(KERN_INFO "** causes a device to stop working, it is probably because the\n");
printk(KERN_INFO "** driver failed to call pci_enable_device(). As a temporary\n");
printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n");
printk(KERN_INFO "** behavior. If this argument makes the device work again,\n");
printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
printk(KERN_INFO "** so I can fix the driver.\n");
}
#ifdef CONFIG_X86_IO_APIC
if (acpi_ioapic)
print_IO_APIC();
......
/*
* CHANGELOG :
* Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
* Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
*
* Jan 5, 1995 : Modified to probe PCI hardware at boot time by Frederic
* Potter, potter@cao-vlsi.ibp.fr
*
* Jan 10, 1995 : Modified to store the information about configured pci
* devices into a list, which can be accessed via /proc/pci by
* Curtis Varner, cvarner@cs.ucr.edu
*
* Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
* Alpha version. Intel & UMC chipset support only.
*
* Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
* moved to drivers/pci/pci.c.
*
* Dec 7, 1996 : Added support for direct configuration access of boards
* with Intel compatible access schemes (tsbogend@alpha.franken.de)
*
* Feb 3, 1997 : Set internal functions to static, save/restore flags
* avoid dead locks reading broken PCI BIOS, werner@suse.de
*
* Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
* (mj@atrey.karlin.mff.cuni.cz)
*
* May 7, 1997 : Added some missing cli()'s. [mj]
*
* Jun 20, 1997 : Corrected problems in "conf1" type accesses.
* (paubert@iram.es)
*
* Aug 2, 1997 : Split to PCI BIOS handling and direct PCI access parts
* and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj]
*
* May 1, 1998 : Support for peer host bridges. [mj]
*
* Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
* can be accessed from interrupts even on SMP systems. [mj]
*
* August 1998 : Better support for peer host bridges and more paranoid
* checks for direct hardware access. Ugh, this file starts to look as
* a large gallery of common hardware bug workarounds (watch the comments)
* -- the PCI specs themselves are sane, but most implementors should be
* hit hard with \hammer scaled \magstep5. [mj]
*
* Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
*
* Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj]
*
* August 1999 : New resource management and configuration access stuff. [mj]
*
* Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
* Based on ideas by Chris Frantz and David Hinds. [mj]
*
* Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
* for a lot of patience during testing. [mj]
*
* Oct 8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
*/
\ No newline at end of file
......@@ -23,6 +23,7 @@ extern void pcibios_sort(void);
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
PCI_PROBE_MMCONF;
int pci_routeirq;
int pcibios_last_bus = -1;
struct pci_bus *pci_root_bus = NULL;
struct pci_raw_ops *raw_pci_ops;
......@@ -227,6 +228,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL;
} else if (!strcmp(str, "routeirq")) {
pci_routeirq = 1;
return NULL;
}
return str;
}
......
......@@ -255,3 +255,132 @@ static void __init pci_fixup_nforce2(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2);
/* Max PCI Express root ports */
#define MAX_PCIEROOT 6
static int quirk_aspm_offset[MAX_PCIEROOT << 3];
#define GET_INDEX(a, b) (((a - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + b)
static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
}
/*
* Replace the original pci bus ops for write with a new one that will filter
* the request to insure ASPM cannot be enabled.
*/
static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
u8 offset;
offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)];
if ((offset) && (where == offset))
value = value & 0xfffffffc;
return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
}
struct pci_ops quirk_pcie_aspm_ops = {
.read = quirk_pcie_aspm_read,
.write = quirk_pcie_aspm_write,
};
/*
* Prevents PCI Express ASPM (Active State Power Management) being enabled.
*
* Save the register offset, where the ASPM control bits are located,
* for each PCI Express device that is in the device list of
* the root port in an array for fast indexing. Replace the bus ops
* with the modified one.
*/
void pcie_rootport_aspm_quirk(struct pci_dev *pdev)
{
int cap_base, i;
struct pci_bus *pbus;
struct pci_dev *dev;
if ((pbus = pdev->subordinate) == NULL)
return;
/*
* Check if the DID of pdev matches one of the six root ports. This
* check is needed in the case this function is called directly by the
* hot-plug driver.
*/
if ((pdev->device < PCI_DEVICE_ID_INTEL_MCH_PA) ||
(pdev->device > PCI_DEVICE_ID_INTEL_MCH_PC1))
return;
if (list_empty(&pbus->devices)) {
/*
* If no device is attached to the root port at power-up or
* after hot-remove, the pbus->devices is empty and this code
* will set the offsets to zero and the bus ops to parent's bus
* ops, which is unmodified.
*/
for (i= GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i)
quirk_aspm_offset[i] = 0;
pbus->ops = pbus->parent->ops;
} else {
/*
* If devices are attached to the root port at power-up or
* after hot-add, the code loops through the device list of
* each root port to save the register offsets and replace the
* bus ops.
*/
list_for_each_entry(dev, &pbus->devices, bus_list) {
/* There are 0 to 8 devices attached to this bus */
cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP);
quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)]= cap_base + 0x10;
}
pbus->ops = &quirk_pcie_aspm_ops;
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk );
/*
* Fixup to mark boot BIOS video selected by BIOS before it changes
*
* From information provided by "Jon Smirl" <jonsmirl@yahoo.com>
*
* The standard boot ROM sequence for an x86 machine uses the BIOS
* to select an initial video card for boot display. This boot video
* card will have it's BIOS copied to C0000 in system RAM.
* IORESOURCE_ROM_SHADOW is used to associate the boot video
* card with this copy. On laptops this copy has to be used since
* the main ROM may be compressed or combined with another image.
* See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
* is marked here since the boot video device will be the only enabled
* video device at this point.
*
*/static void __devinit pci_fixup_video(struct pci_dev *pdev)
{
struct pci_dev *bridge;
struct pci_bus *bus;
u16 l;
if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
return;
/* Is VGA routed to us? */
bus = pdev->bus;
while (bus) {
bridge = bus->self;
if (bridge) {
pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l);
if (!(l & PCI_BRIDGE_CTL_VGA))
return;
}
bus = bus->parent;
}
pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
......@@ -460,21 +460,17 @@ static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
#endif
static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
struct pci_dev *dev1, *dev2;
static struct pci_device_id pirq_440gx[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) },
{ },
};
/* 440GX has a proprietary PIRQ router -- don't use it */
dev1 = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82443GX_0, NULL);
dev2 = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82443GX_2, NULL);
if ((dev1 != NULL) || (dev2 != NULL)) {
pci_dev_put(dev1);
pci_dev_put(dev2);
if (pci_dev_present(pirq_440gx))
return 0;
}
switch(device)
{
......
......@@ -30,7 +30,7 @@ static inline void pci_exp_set_dev_base(int bus, int devfn)
u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
if (dev_base != mmcfg_last_accessed_device) {
mmcfg_last_accessed_device = dev_base;
set_fixmap(FIX_PCIE_MCFG, dev_base);
set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
}
}
......@@ -85,9 +85,6 @@ static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 va
break;
}
/* Dummy read to flush PCI write */
readl(mmcfg_virt_addr);
spin_unlock_irqrestore(&pci_config_lock, flags);
return 0;
......
......@@ -46,6 +46,8 @@
#define DBG(x...)
#endif
static int pci_routeirq;
/*
* Low-level SAL-based PCI configuration access functions. Note that SAL
* calls are already serialized (via sal_lock), so we don't need another
......@@ -141,13 +143,28 @@ extern acpi_status acpi_map_iosapic (acpi_handle, u32, void*, void**);
acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL);
#endif
if (pci_routeirq) {
/*
* PCI IRQ routing is set up by pci_enable_device(), but we
* also do it here in case there are still broken drivers that
* don't use pci_enable_device().
*/
printk(KERN_INFO "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n");
printk(KERN_INFO "** was specified. If this was required to make a driver work,\n");
printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
printk(KERN_INFO "** so I can fix the driver.\n");
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
acpi_pci_irq_enable(dev);
} else {
printk(KERN_INFO "** PCI interrupts are no longer routed automatically. If this\n");
printk(KERN_INFO "** causes a device to stop working, it is probably because the\n");
printk(KERN_INFO "** driver failed to call pci_enable_device(). As a temporary\n");
printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n");
printk(KERN_INFO "** behavior. If this argument makes the device work again,\n");
printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
printk(KERN_INFO "** so I can fix the driver.\n");
}
return 0;
}
......@@ -475,6 +492,8 @@ pcibios_align_resource (void *data, struct resource *res,
char * __init
pcibios_setup (char *str)
{
if (!strcmp(str, "routeirq"))
pci_routeirq = 1;
return NULL;
}
......
......@@ -63,9 +63,6 @@ static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 va
break;
}
/* Dummy read to flush PCI write */
readl(addr);
return 0;
}
......
......@@ -3685,9 +3685,9 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
int i, err;
if (pci_enable_device(pcidev)) {
if ((err = pci_enable_device(pcidev))) {
printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev));
return -ENODEV;
return err;
}
if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) {
......
......@@ -4725,7 +4725,7 @@ cy_detect_pci(void)
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
while((device_id = cy_pci_dev_id[dev_index]) != 0) {
if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES,
if((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
device_id, pdev)) == NULL) {
dev_index++; /* try next device id */
} else {
......
......@@ -217,6 +217,11 @@ static struct miscdevice scx200_wdt_miscdev = {
static int __init scx200_wdt_init(void)
{
int r;
static struct pci_device_id ns_sc[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
{ },
};
printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
......@@ -224,12 +229,7 @@ static int __init scx200_wdt_init(void)
* First check that this really is a NatSemi SCx200 CPU or a Geode
* SC1100 processor
*/
if ((pci_find_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SCx200_BRIDGE,
NULL)) == NULL
&& (pci_find_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SC1100_BRIDGE,
NULL)) == NULL)
if (!pci_dev_present(ns_sc))
return -ENODEV;
/* More sanity checks, verify that the configuration block is there */
......
......@@ -335,11 +335,16 @@ static void __init init_ide_data (void)
int ide_system_bus_speed (void)
{
static struct pci_device_id pci_default[] = {
{ PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) },
{ }
};
if (!system_bus_speed) {
if (idebus_parameter) {
/* user supplied value */
system_bus_speed = idebus_parameter;
} else if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) != NULL) {
} else if (pci_dev_present(pci_default)) {
/* safe default value for PCI */
system_bus_speed = 33;
} else {
......
......@@ -88,10 +88,10 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
tpam_card *card, *c;
int i, err;
if (pci_enable_device(dev)) {
if ((err = pci_enable_device(dev))) {
printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
pci_name(dev));
return -ENODEV;
return err;
}
/* allocate memory for the board structure */
......
......@@ -145,14 +145,11 @@ static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = {
static
void __init handle_chipset(void)
{
struct pci_dev *dev = NULL;
/* Just in case some nut set this to something dangerous */
if (triton1)
triton1 = ZORAN_VDC_TRICOM;
while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev)))
{
if (pci_pci_problems & PCIPCI_TRITON) {
printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n");
triton1 = ZORAN_VDC_TRICOM;
}
......
......@@ -59,13 +59,13 @@
static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
int result = -ENOMEM;
int err, result = -ENOMEM;
struct service_processor *sp;
if (pci_enable_device(pdev)) {
if ((err = pci_enable_device(pdev))) {
printk(KERN_ERR "%s: can't enable PCI device at %s\n",
DRIVER_NAME, pci_name(pdev));
return -ENODEV;
return err;
}
sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
......
......@@ -2242,8 +2242,8 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
return -ENODEV;
/* Ok, the device seems to be for us. */
if (pci_enable_device (pdev))
return -ENODEV;
if ((error = pci_enable_device (pdev)))
return error;
if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) {
error = -ENOMEM;
......
......@@ -3,7 +3,8 @@
#
obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
names.o pci-driver.o search.o pci-sysfs.o
names.o pci-driver.o search.o pci-sysfs.o \
rom.o
obj-$(CONFIG_PROC_FS) += proc.o
ifndef CONFIG_SPARC64
......@@ -28,6 +29,11 @@ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
obj-$(CONFIG_PCI_MSI) += msi.o
#
# ACPI Related PCI FW Functions
#
obj-$(CONFIG_ACPI) += pci-acpi.o
# Cardbus & CompactPCI use setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o
......
......@@ -389,7 +389,7 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus)
bridge->pci_bus = pci_find_bus(seg, bus);
bridge->res_lock = SPIN_LOCK_UNLOCKED;
spin_lock_init(&bridge->res_lock);
/* to be overridden when we decode _CRS */
bridge->sub = bridge->bus;
......@@ -457,7 +457,7 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f
return;
}
bridge->res_lock = SPIN_LOCK_UNLOCKED;
spin_lock_init(&bridge->res_lock);
bridge->bus = bridge->pci_bus->number;
bridge->sub = bridge->pci_bus->subordinate;
......
......@@ -63,7 +63,7 @@
/* local variables */
static int debug;
static char* bridge;
static char bridge[256];
static u8 bridge_busnr;
static u8 bridge_slot;
static struct pci_bus *bus;
......@@ -209,7 +209,7 @@ module_exit(cpcihp_generic_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
module_param(debug, bool, 0644);
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
module_param(bridge, charp, 0);
MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)");
......
......@@ -227,6 +227,6 @@ module_exit(dummyphp_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
module_param(debug, bool, 0644);
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
......@@ -51,7 +51,7 @@
int ibmphp_debug;
static int debug;
module_param(debug, bool, 0644);
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC (debug, "Debugging mode enabled or not");
MODULE_LICENSE ("GPL");
MODULE_DESCRIPTION (DRIVER_DESC);
......@@ -838,8 +838,11 @@ static int set_bus (struct slot * slot_cur)
int rc;
u8 speed;
u8 cmd = 0x0;
struct pci_dev *dev = NULL;
int retval;
static struct pci_device_id ciobx[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, 0x0101) },
{ },
};
debug ("%s - entry slot # %d\n", __FUNCTION__, slot_cur->number);
if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) {
......@@ -886,8 +889,7 @@ static int set_bus (struct slot * slot_cur)
break;
case BUS_SPEED_133:
/* This is to take care of the bug in CIOBX chip */
while ((dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
0x0101, dev)) != NULL)
if (pci_dev_present(ciobx))
ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE);
cmd = HPC_BUS_133PCIXMODE;
break;
......
......@@ -127,8 +127,7 @@ struct controller {
enum pci_bus_speed speed;
u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */
u8 slot_bus; /* Bus where the slots handled by this controller sit */
u8 push_flag;
u16 ctlrcap;
u8 ctrlcap;
u16 vendor_id;
};
......@@ -180,6 +179,21 @@ struct resource_lists {
#define DISABLE_CARD 1
/* Field definitions in Slot Capabilities Register */
#define ATTN_BUTTN_PRSN 0x00000001
#define PWR_CTRL_PRSN 0x00000002
#define MRL_SENS_PRSN 0x00000004
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN)
#define MRL_SENS(cap) (cap & MRL_SENS_PRSN)
#define ATTN_LED(cap) (cap & ATTN_LED_PRSN)
#define PWR_LED(cap) (cap & PWR_LED_PRSN)
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
/*
* error Messages
*/
......@@ -312,8 +326,7 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl,
int *num_ctlr_slots,
int *first_device_num,
int *physical_slot_num,
int *updown,
int *flags);
u8 *ctrlcap);
struct hpc_ops {
int (*power_on_slot) (struct slot *slot);
......
......@@ -204,11 +204,10 @@ static int get_ctlr_slot_config(struct controller *ctrl)
int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/
int first_device_num; /* Not needed */
int physical_slot_num;
int updown; /* Not needed */
u8 ctrlcap;
int rc;
int flags; /* Not needed */
rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags);
rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
if (rc) {
err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
return (-1);
......@@ -217,10 +216,10 @@ static int get_ctlr_slot_config(struct controller *ctrl)
ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */
ctrl->slot_device_offset = first_device_num;
ctrl->first_slot = physical_slot_num;
ctrl->slot_num_inc = updown; /* Not needed */ /* either -1 or 1 */
ctrl->ctrlcap = ctrlcap;
dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
__FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, updown,
dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
__FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap,
ctrl->bus, ctrl->device);
return (0);
......@@ -237,6 +236,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
hotplug_slot->info->attention_status = status;
if (ATTN_LED(slot->ctrl->ctrlcap))
slot->hpc_ops->set_attention_status(slot, status);
return 0;
......@@ -451,7 +452,8 @@ static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
dbg("%s: adpater value %x\n", __FUNCTION__, value);
if (!value) {
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
if (rc) {
/* Done with exclusive hardware access */
......
......@@ -38,6 +38,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include "../pci.h"
#include "pciehp.h"
#include "pciehprm.h"
......@@ -51,6 +52,7 @@ static struct semaphore event_semaphore; /* mutex for process loop (up if someth
static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
static int event_finished;
static unsigned long pushbutton_pending; /* = 0 */
static unsigned long surprise_rm_pending; /* = 0 */
u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
{
......@@ -1063,25 +1065,29 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
/* turn off slot, turn on Amber LED, turn off Green LED */
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return;
}
wait_for_ctrl_irq (ctrl);
}
if (PWR_LED(ctrl->ctrlcap)) {
pslot->hpc_ops->green_led_off(pslot);
wait_for_ctrl_irq (ctrl);
}
/* turn on Amber LED */
if (ATTN_LED(ctrl->ctrlcap)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return;
}
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
......@@ -1112,6 +1118,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
rc = p_slot->hpc_ops->power_on_slot(p_slot);
if (rc) {
......@@ -1121,11 +1128,14 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_blink(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
......@@ -1212,6 +1222,13 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
}
} while (new_func);
/*
* Some PCI Express root ports require fixup after hot-plug operation.
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
if (PWR_LED(ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
......@@ -1220,10 +1237,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
}
} else {
set_slot_off(ctrl, p_slot);
return -1;
......@@ -1289,6 +1305,7 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl)
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
rc = p_slot->hpc_ops->power_off_slot(p_slot);
if (rc) {
......@@ -1298,12 +1315,15 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl)
}
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
if (PWR_LED(ctrl->ctrlcap)) {
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
......@@ -1368,7 +1388,6 @@ static void pushbutton_helper_thread(unsigned long data)
up(&event_semaphore);
}
/**
* pciehp_pushbutton_thread
*
......@@ -1399,7 +1418,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
p_slot->state = POWERON_STATE;
dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
if (pciehp_enable_slot(p_slot)) {
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
down(&p_slot->ctrl->crit_sect);
......@@ -1417,6 +1436,55 @@ static void pciehp_pushbutton_thread(unsigned long slot)
return;
}
/**
* pciehp_surprise_rm_thread
*
* Scheduled procedure to handle blocking stuff for the surprise removal
* Handles all pending events and exits.
*
*/
static void pciehp_surprise_rm_thread(unsigned long slot)
{
struct slot *p_slot = (struct slot *) slot;
u8 getstatus;
surprise_rm_pending = 0;
if (!p_slot) {
dbg("%s: Error! slot NULL\n", __FUNCTION__);
return;
}
p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (!getstatus) {
p_slot->state = POWEROFF_STATE;
dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
pciehp_disable_slot(p_slot);
p_slot->state = STATIC_STATE;
} else {
p_slot->state = POWERON_STATE;
dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
down(&p_slot->ctrl->crit_sect);
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
up(&p_slot->ctrl->crit_sect);
}
p_slot->state = STATIC_STATE;
}
return;
}
/* this is the main worker thread */
static int event_thread(void* data)
......@@ -1436,6 +1504,8 @@ static int event_thread(void* data)
/* Do stuff here */
if (pushbutton_pending)
pciehp_pushbutton_thread(pushbutton_pending);
else if (surprise_rm_pending)
pciehp_surprise_rm_thread(surprise_rm_pending);
else
for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
interrupt_event_handler(ctrl);
......@@ -1529,15 +1599,17 @@ static void interrupt_event_handler(struct controller *ctrl)
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_on(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
if (ATTN_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->set_attention_status(p_slot, 0);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
break;
......@@ -1545,14 +1617,16 @@ static void interrupt_event_handler(struct controller *ctrl)
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
if (ATTN_LED(ctrl->ctrlcap)){
p_slot->hpc_ops->set_attention_status(p_slot, 0);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
......@@ -1566,8 +1640,9 @@ static void interrupt_event_handler(struct controller *ctrl)
}
/* ***********Button Pressed (No action on 1st press...) */
else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
dbg("Button pressed\n");
if (ATTN_BUTTN(ctrl->ctrlcap)) {
dbg("Button pressed\n");
p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (getstatus) {
/* slot is on */
......@@ -1585,14 +1660,18 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect);
/* blink green LED and turn off amber */
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_blink(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
if (ATTN_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->set_attention_status(p_slot, 0);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
......@@ -1605,20 +1684,39 @@ static void interrupt_event_handler(struct controller *ctrl)
dbg("add_timer p_slot = %p\n", (void *) p_slot);
add_timer(&p_slot->task_event);
}
}
/***********POWER FAULT********************/
else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
if (ATTN_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->set_attention_status(p_slot, 1);
wait_for_ctrl_irq (ctrl);
}
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_off(p_slot);
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
}
}
/***********SURPRISE REMOVAL********************/
else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) ||
(ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
if (HP_SUPR_RM(ctrl->ctrlcap)) {
dbg("Surprise Removal\n");
if (p_slot) {
surprise_rm_pending = (unsigned long) p_slot;
up(&event_semaphore);
update_slot_info(p_slot);
}
}
} else {
/* refresh notification */
if (p_slot)
......@@ -1648,26 +1746,30 @@ int pciehp_enable_slot(struct slot *p_slot)
/* Check to see if (latch closed, card present, power off) */
down(&p_slot->ctrl->crit_sect);
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 1;
}
if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 1;
}
}
if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 1;
}
}
up(&p_slot->ctrl->crit_sect);
slot_remove(func);
......@@ -1735,26 +1837,33 @@ int pciehp_disable_slot(struct slot *p_slot)
/* Check to see if (latch closed, card present, power on) */
down(&p_slot->ctrl->crit_sect);
if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 1;
}
}
if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 1;
}
}
if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
return 1;
}
}
up(&p_slot->ctrl->crit_sect);
func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
......
......@@ -182,7 +182,7 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define MRL_SENS_PRSN 0x00000004
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM 0x00000020
#define HP_SUPR_RM_SUP 0x00000020
#define HP_CAP 0x00000040
#define SLOT_PWR_VALUE 0x000003F8
#define SLOT_PWR_LIMIT 0x00000C00
......@@ -237,8 +237,8 @@ struct php_ctlr_state_s {
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
static int ctlr_seq_num; /* Controller sequence # */
static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */
static int ctlr_seq_num = 0; /* Controller sequence # */
static spinlock_t list_lock;
static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);
......@@ -691,8 +691,7 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl,
int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */
int *first_device_num, /* PCI dev num of the first slot in this PCIE */
int *physical_slot_num, /* phy slot num of the first slot in this PCIE */
int *updown, /* physical_slot_num increament: 1 or -1 */
int *flags)
u8 *ctrlcap)
{
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u32 slot_cap;
......@@ -716,8 +715,9 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl,
}
*physical_slot_num = slot_cap >> 19;
dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
*updown = -1;
*ctrlcap = slot_cap & 0x0000007f;
DBG_LEAVE_ROUTINE
return 0;
......@@ -741,6 +741,8 @@ static void hpc_release_ctlr(struct controller *ctrl)
if (php_ctlr->irq) {
free_irq(php_ctlr->irq, ctrl);
php_ctlr->irq = 0;
if (!pcie_mch_quirk)
pci_disable_msi(php_ctlr->pci_dev);
}
}
if (php_ctlr->pci_dev)
......@@ -1259,7 +1261,7 @@ int pcie_init(struct controller * ctrl,
static int first = 1;
u16 temp_word;
u16 cap_reg;
u16 intr_enable;
u16 intr_enable = 0;
u32 slot_cap;
int cap_base, saved_cap_base;
u16 slot_status, slot_ctrl;
......@@ -1402,8 +1404,8 @@ int pcie_init(struct controller * ctrl,
start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
} else {
/* Installs the interrupt handler */
dbg("%s: pciehp_msi_quirk = %x\n", __FUNCTION__, pciehp_msi_quirk);
if (!pciehp_msi_quirk) {
dbg("%s: pcie_mch_quirk = %x\n", __FUNCTION__, pcie_mch_quirk);
if (!pcie_mch_quirk) {
rc = pci_enable_msi(pdev);
if (rc) {
info("Can't get msi for the hotplug controller\n");
......@@ -1412,6 +1414,7 @@ int pcie_init(struct controller * ctrl,
} else
php_ctlr->irq = pdev->irq;
}
rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
if (rc) {
......@@ -1426,9 +1429,18 @@ int pcie_init(struct controller * ctrl,
goto abort_free_ctlr;
}
dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap);
intr_enable = intr_enable | PRSN_DETECT_ENABLE;
if (ATTN_BUTTN(slot_cap))
intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
if (POWER_CTRL(slot_cap))
intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
intr_enable = ATTN_BUTTN_ENABLE | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
PRSN_DETECT_ENABLE;
if (MRL_SENS(slot_cap))
intr_enable = intr_enable | MRL_DETECT_ENABLE;
temp_word = (temp_word & ~intr_enable) | intr_enable;
......
......@@ -82,9 +82,11 @@ int pciehp_unconfigure_device(struct pci_func* func)
{
int rc = 0;
int j;
struct pci_bus *pbus;
dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus,
func->device, func->function);
pbus = func->pci_dev->bus;
for (j=0; j<8 ; j++) {
struct pci_dev* temp = pci_find_slot(func->bus,
......@@ -93,6 +95,12 @@ int pciehp_unconfigure_device(struct pci_func* func)
pci_remove_bus_device(temp);
}
}
/*
* Some PCI Express root ports require fixup after hot-plug operation.
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, pbus->self);
return rc;
}
......
......@@ -32,6 +32,7 @@
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/pci-acpi.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#ifdef CONFIG_IA64
......@@ -50,6 +51,14 @@
#define METHOD_NAME__HPP "_HPP"
#define METHOD_NAME_OSHP "OSHP"
/* Status code for running acpi method to gain native control */
#define NC_NOT_RUN 0
#define OSC_NOT_EXIST 1
#define OSC_RUN_FAILED 2
#define OSHP_NOT_EXIST 3
#define OSHP_RUN_FAILED 4
#define NC_RUN_SUCCESS 5
#define PHP_RES_BUS 0xA0
#define PHP_RES_IO 0xA1
#define PHP_RES_MEM 0xA2
......@@ -125,7 +134,9 @@ static u8 * acpi_path_name( acpi_handle handle)
}
static void acpi_get__hpp ( struct acpi_bridge *ab);
static void acpi_run_oshp ( struct acpi_bridge *ab);
static int acpi_run_oshp ( struct acpi_bridge *ab);
static int osc_run_status = NC_NOT_RUN;
static int oshp_run_status = NC_NOT_RUN;
static int acpi_add_slot_to_php_slots(
struct acpi_bridge *ab,
......@@ -159,7 +170,8 @@ static int acpi_add_slot_to_php_slots(
if (!ab->_hpp)
acpi_get__hpp(ab);
acpi_run_oshp(ab);
if (osc_run_status == OSC_NOT_EXIST)
oshp_run_status = acpi_run_oshp(ab);
if (sun != samesun) {
info("acpi_pciehprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n",
......@@ -238,7 +250,7 @@ static void acpi_get__hpp ( struct acpi_bridge *ab)
kfree(ret_buf.pointer);
}
static void acpi_run_oshp ( struct acpi_bridge *ab)
static int acpi_run_oshp ( struct acpi_bridge *ab)
{
acpi_status status;
u8 *path_name = acpi_path_name(ab->handle);
......@@ -248,9 +260,13 @@ static void acpi_run_oshp ( struct acpi_bridge *ab)
status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf);
if (ACPI_FAILURE(status)) {
err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
} else
oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED;
} else {
oshp_run_status = NC_RUN_SUCCESS;
dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
return;
dbg("acpi_pciehprm:%s oshp_run_status =0x%x\n", path_name, oshp_run_status);
}
return oshp_run_status;
}
static acpi_status acpi_evaluate_crs(
......@@ -1056,6 +1072,16 @@ static struct acpi_bridge * add_host_bridge(
kfree(ab);
return NULL;
}
status = pci_osc_control_set (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
if (ACPI_FAILURE(status)) {
err("%s: status %x\n", __FUNCTION__, status);
osc_run_status = (status == AE_NOT_FOUND) ? OSC_NOT_EXIST : OSC_RUN_FAILED;
} else {
osc_run_status = NC_RUN_SUCCESS;
}
dbg("%s: osc_run_status %x\n", __FUNCTION__, osc_run_status);
build_a_bridge(ab, ab);
return ab;
......@@ -1141,6 +1167,11 @@ int pciehprm_init(enum php_ctlr_type ctlr_type)
if (rc)
return rc;
if ((oshp_run_status != NC_RUN_SUCCESS) && (osc_run_status != NC_RUN_SUCCESS)) {
err("Fails to gain control of native hot-plug\n");
rc = -ENODEV;
}
dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success");
return rc;
}
......
......@@ -1157,6 +1157,40 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
return -1;
}
if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
if (slots_not_empty)
return WRONG_BUS_FREQUENCY;
if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY;
}
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
__FUNCTION__);
err("%s: Error code (%d)\n", __FUNCTION__, rc);
up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY;
}
/* turn on board, blink green LED, turn off Amber LED */
if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
up(&ctrl->crit_sect);
return rc;
}
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
up(&ctrl->crit_sect);
return rc;
}
}
rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
/* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
/* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC, 0xa = PCI-X 133 Mhz 266, */
......
......@@ -792,6 +792,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
if (php_ctlr->irq) {
free_irq(php_ctlr->irq, ctrl);
php_ctlr->irq = 0;
pci_disable_msi(php_ctlr->pci_dev);
}
}
if (php_ctlr->pci_dev) {
......
/*
* File: pci-acpi.c
* Purpose: Provide PCI supports in ACPI
*
* Copyright (C) 2004 Intel
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acresrc.h>
#include <acpi/acpi_bus.h>
#include <linux/pci-acpi.h>
static u32 ctrlset_buf[3] = {0, 0, 0};
static u32 global_ctrlsets = 0;
u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
static acpi_status
acpi_query_osc (
acpi_handle handle,
u32 level,
void *context,
void **retval )
{
acpi_status status;
struct acpi_object_list input;
union acpi_object in_params[4];
struct acpi_buffer output;
union acpi_object out_obj;
u32 osc_dw0;
/* Setting up output buffer */
output.length = sizeof(out_obj) + 3*sizeof(u32);
output.pointer = &out_obj;
/* Setting up input parameters */
input.count = 4;
input.pointer = in_params;
in_params[0].type = ACPI_TYPE_BUFFER;
in_params[0].buffer.length = 16;
in_params[0].buffer.pointer = OSC_UUID;
in_params[1].type = ACPI_TYPE_INTEGER;
in_params[1].integer.value = 1;
in_params[2].type = ACPI_TYPE_INTEGER;
in_params[2].integer.value = 3;
in_params[3].type = ACPI_TYPE_BUFFER;
in_params[3].buffer.length = 12;
in_params[3].buffer.pointer = (u8 *)context;
status = acpi_evaluate_object(handle, "_OSC", &input, &output);
if (ACPI_FAILURE (status)) {
printk(KERN_DEBUG
"Evaluate _OSC Set fails. Status = 0x%04x\n", status);
return status;
}
if (out_obj.type != ACPI_TYPE_BUFFER) {
printk(KERN_DEBUG
"Evaluate _OSC returns wrong type\n");
return AE_TYPE;
}
osc_dw0 = *((u32 *) out_obj.buffer.pointer);
if (osc_dw0) {
if (osc_dw0 & OSC_REQUEST_ERROR)
printk(KERN_DEBUG "_OSC request fails\n");
if (osc_dw0 & OSC_INVALID_UUID_ERROR)
printk(KERN_DEBUG "_OSC invalid UUID\n");
if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
printk(KERN_DEBUG "_OSC invalid revision\n");
if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
/* Update Global Control Set */
global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8));
return AE_OK;
}
return AE_ERROR;
}
/* Update Global Control Set */
global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8));
return AE_OK;
}
static acpi_status
acpi_run_osc (
acpi_handle handle,
u32 level,
void *context,
void **retval )
{
acpi_status status;
struct acpi_object_list input;
union acpi_object in_params[4];
struct acpi_buffer output;
union acpi_object out_obj;
u32 osc_dw0;
/* Setting up output buffer */
output.length = sizeof(out_obj) + 3*sizeof(u32);
output.pointer = &out_obj;
/* Setting up input parameters */
input.count = 4;
input.pointer = in_params;
in_params[0].type = ACPI_TYPE_BUFFER;
in_params[0].buffer.length = 16;
in_params[0].buffer.pointer = OSC_UUID;
in_params[1].type = ACPI_TYPE_INTEGER;
in_params[1].integer.value = 1;
in_params[2].type = ACPI_TYPE_INTEGER;
in_params[2].integer.value = 3;
in_params[3].type = ACPI_TYPE_BUFFER;
in_params[3].buffer.length = 12;
in_params[3].buffer.pointer = (u8 *)context;
status = acpi_evaluate_object(handle, "_OSC", &input, &output);
if (ACPI_FAILURE (status)) {
printk(KERN_DEBUG
"Evaluate _OSC Set fails. Status = 0x%04x\n", status);
return status;
}
if (out_obj.type != ACPI_TYPE_BUFFER) {
printk(KERN_DEBUG
"Evaluate _OSC returns wrong type\n");
return AE_TYPE;
}
osc_dw0 = *((u32 *) out_obj.buffer.pointer);
if (osc_dw0) {
if (osc_dw0 & OSC_REQUEST_ERROR)
printk(KERN_DEBUG "_OSC request fails\n");
if (osc_dw0 & OSC_INVALID_UUID_ERROR)
printk(KERN_DEBUG "_OSC invalid UUID\n");
if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
printk(KERN_DEBUG "_OSC invalid revision\n");
if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
printk(KERN_DEBUG "_OSC FW not grant req. control\n");
return AE_SUPPORT;
}
return AE_ERROR;
}
return AE_OK;
}
/**
* pci_osc_support_set - register OS support to Firmware
* @flags: OS support bits
*
* Update OS support fields and doing a _OSC Query to obtain an update
* from Firmware on supported control bits.
**/
acpi_status pci_osc_support_set(u32 flags)
{
u32 temp;
if (!(flags & OSC_SUPPORT_MASKS)) {
return AE_TYPE;
}
ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
/* do _OSC query for all possible controls */
temp = ctrlset_buf[OSC_CONTROL_TYPE];
ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
acpi_get_devices ( PCI_ROOT_HID_STRING,
acpi_query_osc,
ctrlset_buf,
NULL );
ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
ctrlset_buf[OSC_CONTROL_TYPE] = temp;
return AE_OK;
}
EXPORT_SYMBOL(pci_osc_support_set);
/**
* pci_osc_control_set - commit requested control to Firmware
* @flags: driver's requested control bits
*
* Attempt to take control from Firmware on requested control bits.
**/
acpi_status pci_osc_control_set(u32 flags)
{
acpi_status status;
u32 ctrlset;
ctrlset = (flags & OSC_CONTROL_MASKS);
if (!ctrlset) {
return AE_TYPE;
}
if (ctrlset_buf[OSC_SUPPORT_TYPE] &&
((global_ctrlsets & ctrlset) != ctrlset)) {
return AE_SUPPORT;
}
ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
status = acpi_get_devices ( PCI_ROOT_HID_STRING,
acpi_run_osc,
ctrlset_buf,
NULL );
if (ACPI_FAILURE (status)) {
ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
}
return status;
}
EXPORT_SYMBOL(pci_osc_control_set);
......@@ -271,17 +271,14 @@ static int pci_device_remove(struct device * dev)
pci_dev->driver = NULL;
}
#ifdef CONFIG_DEBUG_KERNEL
/*
* If the driver decides to stop using the device, it should
* call pci_disable_device().
* We would love to complain here if pci_dev->is_enabled is set, that
* the driver should have called pci_disable_device(), but the
* unfortunate fact is there are too many odd BIOS and bridge setups
* that don't like drivers doing that all of the time.
* Oh well, we can dream of sane hardware when we sleep, no matter how
* horrible the crap we have to deal with is when we are awake...
*/
if (pci_dev->is_enabled) {
dev_warn(&pci_dev->dev, "Device was removed without properly "
"calling pci_disable_device(). This may need fixing.\n");
/* WARN_ON(1); */
}
#endif /* CONFIG_DEBUG_KERNEL */
pci_dev_put(pci_dev);
return 0;
......
......@@ -5,6 +5,8 @@
* (C) Copyright 2002-2004 IBM Corp.
* (C) Copyright 2003 Matthew Wilcox
* (C) Copyright 2003 Hewlett-Packard
* (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
* (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
*
* File attributes for PCI devices
*
......@@ -20,6 +22,8 @@
#include "pci.h"
static int sysfs_initialized; /* = 0 */
/* show configuration fields */
#define pci_config_attr(field, format_string) \
static ssize_t \
......@@ -164,6 +168,65 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
return count;
}
/**
* pci_write_rom - used to enable access to the PCI ROM display
* @kobj: kernel object handle
* @buf: user input
* @off: file offset
* @count: number of byte in input
*
* writing anything except 0 enables it
*/
static ssize_t
pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
if ((off == 0) && (*buf == '0') && (count == 2))
pdev->rom_attr_enabled = 0;
else
pdev->rom_attr_enabled = 1;
return count;
}
/**
* pci_read_rom - read a PCI ROM
* @kobj: kernel object handle
* @buf: where to put the data we read from the ROM
* @off: file offset
* @count: number of bytes to read
*
* Put @count bytes starting at @off into @buf from the ROM in the PCI
* device corresponding to @kobj.
*/
static ssize_t
pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
void __iomem *rom;
size_t size;
if (!pdev->rom_attr_enabled)
return -EINVAL;
rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */
if (!rom)
return 0;
if (off >= size)
count = 0;
else {
if (off + count > size)
count = size - off;
memcpy_fromio(buf, rom + off, count);
}
pci_unmap_rom(pdev, rom);
return count;
}
static struct bin_attribute pci_config_attr = {
.attr = {
.name = "config",
......@@ -186,13 +249,68 @@ static struct bin_attribute pcie_config_attr = {
.write = pci_write_config,
};
void pci_create_sysfs_dev_files (struct pci_dev *pdev)
int pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
if (!sysfs_initialized)
return -EACCES;
if (pdev->cfg_size < 4096)
sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
/* If the device has a ROM, try to expose it in sysfs. */
if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
struct bin_attribute *rom_attr;
rom_attr = kmalloc(sizeof(*rom_attr), GFP_ATOMIC);
if (rom_attr) {
pdev->rom_attr = rom_attr;
rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
rom_attr->attr.name = "rom";
rom_attr->attr.mode = S_IRUSR;
rom_attr->attr.owner = THIS_MODULE;
rom_attr->read = pci_read_rom;
rom_attr->write = pci_write_rom;
sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
}
}
/* add platform-specific attributes */
pcibios_add_platform_entries(pdev);
return 0;
}
/**
* pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
* @pdev: device whose entries we should free
*
* Cleanup when @pdev is removed from sysfs.
*/
void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
{
if (pdev->cfg_size < 4096)
sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
if (pdev->rom_attr) {
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
kfree(pdev->rom_attr);
}
}
}
static int __init pci_sysfs_init(void)
{
struct pci_dev *pdev = NULL;
sysfs_initialized = 1;
while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL)
pci_create_sysfs_dev_files(pdev);
return 0;
}
__initcall(pci_sysfs_init);
......@@ -374,6 +374,16 @@ pci_enable_device(struct pci_dev *dev)
return 0;
}
/**
* pcibios_disable_device - disable arch specific PCI resources for device dev
* @dev: the PCI device to disable
*
* Disables architecture specific PCI resources for the device. This
* is the default implementation. Architecture implementations can
* override this.
*/
void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
/**
* pci_disable_device - Disable PCI device after use
* @dev: PCI device to be disabled
......@@ -394,6 +404,8 @@ pci_disable_device(struct pci_dev *dev)
pci_command &= ~PCI_COMMAND_MASTER;
pci_write_config_word(dev, PCI_COMMAND, pci_command);
}
pcibios_disable_device(dev);
}
/**
......
......@@ -2,7 +2,9 @@
extern int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
extern void pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
unsigned long size, unsigned long align,
unsigned long min, unsigned int type_mask,
......@@ -61,7 +63,7 @@ extern int pci_visit_dev(struct pci_visit *fn,
/* Lock for read/write access to pci device and bus lists */
extern spinlock_t pci_bus_lock;
extern int pciehp_msi_quirk;
extern int pcie_mch_quirk;
extern struct device_attribute pci_dev_attrs[];
/**
......
......@@ -170,7 +170,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
if (sz && sz != 0xffffffff) {
sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK);
if (sz) {
res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
res->flags = (l & IORESOURCE_ROM_ENABLE) |
IORESOURCE_MEM | IORESOURCE_PREFETCH |
IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
res->start = l & PCI_ROM_ADDRESS_MASK;
......@@ -478,6 +478,9 @@ static int pci_setup_device(struct pci_dev * dev)
/* "Unknown power state" */
dev->current_state = 4;
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
......
......@@ -1136,7 +1136,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_a
#endif
#ifdef CONFIG_SCSI_SATA
static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
{
u8 prog, comb, tmp;
int ich = 0;
......@@ -1210,14 +1210,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_co
#endif /* CONFIG_SCSI_SATA */
int pciehp_msi_quirk;
int pcie_mch_quirk;
static void __devinit quirk_pciehp_msi(struct pci_dev *pdev)
static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
pciehp_msi_quirk = 1;
pcie_mch_quirk = 1;
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch );
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
{
......@@ -1266,4 +1267,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
pci_do_fixups(dev, start, end);
}
EXPORT_SYMBOL(pciehp_msi_quirk);
EXPORT_SYMBOL(pcie_mch_quirk);
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_fixup_device);
#endif
......@@ -16,6 +16,7 @@ static void pci_free_resources(struct pci_dev *dev)
msi_remove_pci_irq_vectors(dev);
pci_cleanup_rom(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i;
if (res->parent)
......@@ -26,6 +27,7 @@ static void pci_free_resources(struct pci_dev *dev)
static void pci_destroy_dev(struct pci_dev *dev)
{
pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev);
device_unregister(&dev->dev);
/* Remove the device from the device lists, and prevent any further
......
/*
* drivers/pci/rom.c
*
* (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
* (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
*
* PCI ROM access routines
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include "pci.h"
/**
* pci_enable_rom - enable ROM decoding for a PCI device
* @dev: PCI device to enable
*
* Enable ROM decoding on @dev. This involves simply turning on the last
* bit of the PCI ROM BAR. Note that some cards may share address decoders
* between the ROM and other resources, so enabling it may disable access
* to MMIO registers or other card memory.
*/
static void
pci_enable_rom(struct pci_dev *pdev)
{
u32 rom_addr;
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
rom_addr |= PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
}
/**
* pci_disable_rom - disable ROM decoding for a PCI device
* @dev: PCI device to disable
*
* Disable ROM decoding on a PCI device by turning off the last bit in the
* ROM BAR.
*/
static void
pci_disable_rom(struct pci_dev *pdev)
{
u32 rom_addr;
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
}
/**
* pci_map_rom - map a PCI ROM to kernel space
* @dev: pointer to pci device struct
* @size: pointer to receive size of pci window over ROM
* @return: kernel virtual pointer to image of ROM
*
* Map a PCI ROM into kernel space. If ROM is boot video ROM,
* the shadow BIOS copy will be returned instead of the
* actual ROM.
*/
void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
loff_t start;
void __iomem *rom;
void __iomem *image;
int last_image;
if (res->flags & IORESOURCE_ROM_SHADOW) { /* IORESOURCE_ROM_SHADOW only set on x86 */
start = (loff_t)0xC0000; /* primary video rom always starts here */
*size = 0x20000; /* cover C000:0 through E000:0 */
} else {
if (res->flags & IORESOURCE_ROM_COPY) {
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE);
} else {
/* assign the ROM an address if it doesn't have one */
if (res->parent == NULL)
pci_assign_resource(pdev, PCI_ROM_RESOURCE);
start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
if (*size == 0)
return NULL;
/* Enable ROM space decodes */
pci_enable_rom(pdev);
}
}
rom = ioremap(start, *size);
if (!rom) {
/* restore enable if ioremap fails */
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY)))
pci_disable_rom(pdev);
return NULL;
}
/* Try to find the true size of the ROM since sometimes the PCI window */
/* size is much larger than the actual size of the ROM. */
/* True size is important if the ROM is going to be copied. */
image = rom;
do {
void __iomem *pds;
/* Standard PCI ROMs start out with these bytes 55 AA */
if (readb(image) != 0x55)
break;
if (readb(image + 1) != 0xAA)
break;
/* get the PCI data structure and check its signature */
pds = image + readw(image + 24);
if (readb(pds) != 'P')
break;
if (readb(pds + 1) != 'C')
break;
if (readb(pds + 2) != 'I')
break;
if (readb(pds + 3) != 'R')
break;
last_image = readb(pds + 21) & 0x80;
/* this length is reliable */
image += readw(pds + 16) * 512;
} while (!last_image);
*size = image - rom;
return rom;
}
/**
* pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
* @dev: pointer to pci device struct
* @size: pointer to receive size of pci window over ROM
* @return: kernel virtual pointer to image of ROM
*
* Map a PCI ROM into kernel space. If ROM is boot video ROM,
* the shadow BIOS copy will be returned instead of the
* actual ROM.
*/
void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
void __iomem *rom;
rom = pci_map_rom(pdev, size);
if (!rom)
return NULL;
if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW))
return rom;
res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
if (!res->start)
return rom;
res->end = res->start + *size;
memcpy_fromio((void*)res->start, rom, *size);
pci_unmap_rom(pdev, rom);
res->flags |= IORESOURCE_ROM_COPY;
return (void __iomem *)res->start;
}
/**
* pci_unmap_rom - unmap the ROM from kernel space
* @dev: pointer to pci device struct
* @rom: virtual address of the previous mapping
*
* Remove a mapping of a previously mapped ROM
*/
void
pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
if (res->flags & IORESOURCE_ROM_COPY)
return;
iounmap(rom);
/* Disable again before continuing, leave enabled if pci=rom */
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
pci_disable_rom(pdev);
}
/**
* pci_remove_rom - disable the ROM and remove its sysfs attribute
* @dev: pointer to pci device struct
*
*/
void
pci_remove_rom(struct pci_dev *pdev)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY)))
pci_disable_rom(pdev);
}
/**
* pci_cleanup_rom - internal routine for freeing the ROM copy created
* by pci_map_rom_copy called from remove.c
* @dev: pointer to pci device struct
*
*/
void
pci_cleanup_rom(struct pci_dev *pdev)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
if (res->flags & IORESOURCE_ROM_COPY) {
kfree((void*)res->start);
res->flags &= ~IORESOURCE_ROM_COPY;
res->start = 0;
res->end = 0;
}
}
EXPORT_SYMBOL(pci_map_rom);
EXPORT_SYMBOL(pci_map_rom_copy);
EXPORT_SYMBOL(pci_unmap_rom);
EXPORT_SYMBOL(pci_remove_rom);
......@@ -56,7 +56,7 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
if (resno < 6) {
reg = PCI_BASE_ADDRESS_0 + 4 * resno;
} else if (resno == PCI_ROM_RESOURCE) {
new |= res->flags & PCI_ROM_ADDRESS_ENABLE;
new |= res->flags & IORESOURCE_ROM_ENABLE;
reg = dev->rom_base_reg;
} else {
/* Hmm, non-standard resource. */
......
......@@ -18,6 +18,9 @@
\
/* PCI quirks */ \
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \
*(.pci_fixup_early) \
VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \
VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \
*(.pci_fixup_header) \
VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \
......
......@@ -82,6 +82,11 @@ struct resource_list {
#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */
#define IORESOURCE_MEM_EXPANSIONROM (1<<6)
/* PCI ROM control bits (IORESOURCE_BITS) */
#define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
#define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */
#define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */
/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
extern struct resource ioport_resource;
extern struct resource iomem_resource;
......
/*
* File pci-acpi.h
*
* Copyright (C) 2004 Intel
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
#ifndef _PCI_ACPI_H_
#define _PCI_ACPI_H_
#define OSC_QUERY_TYPE 0
#define OSC_SUPPORT_TYPE 1
#define OSC_CONTROL_TYPE 2
#define OSC_SUPPORT_MASKS 0x1f
/*
* _OSC DW0 Definition
*/
#define OSC_QUERY_ENABLE 1
#define OSC_REQUEST_ERROR 2
#define OSC_INVALID_UUID_ERROR 4
#define OSC_INVALID_REVISION_ERROR 8
#define OSC_CAPABILITIES_MASK_ERROR 16
/*
* _OSC DW1 Definition (OS Support Fields)
*/
#define OSC_EXT_PCI_CONFIG_SUPPORT 1
#define OSC_ACTIVE_STATE_PWR_SUPPORT 2
#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT 4
#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 8
#define OSC_MSI_SUPPORT 16
/*
* _OSC DW1 Definition (OS Control Fields)
*/
#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 1
#define OSC_SHPC_NATIVE_HP_CONTROL 2
#define OSC_PCI_EXPRESS_PME_CONTROL 4
#define OSC_PCI_EXPRESS_AER_CONTROL 8
#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL 16
#define OSC_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
OSC_SHPC_NATIVE_HP_CONTROL | \
OSC_PCI_EXPRESS_PME_CONTROL | \
OSC_PCI_EXPRESS_AER_CONTROL | \
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
#ifdef CONFIG_ACPI
extern acpi_status pci_osc_control_set(u32 flags);
extern acpi_status pci_osc_support_set(u32 flags);
#else
#if !defined(acpi_status)
typedef u32 acpi_status;
#define AE_ERROR (acpi_status) (0x0001)
#endif
static inline acpi_status pci_osc_control_set(u32 flags) {return AE_ERROR;}
static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;}
#endif
#endif /* _PCI_ACPI_H_ */
......@@ -537,6 +537,8 @@ struct pci_dev {
unsigned int is_busmaster:1; /* device is busmaster */
u32 saved_config_space[16]; /* config space saved at suspend time */
struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
int rom_attr_enabled; /* has display of the rom attribute been enabled? */
#ifdef CONFIG_PCI_NAMES
#define PCI_NAME_SIZE 96
#define PCI_NAME_HALF __stringify(43) /* less than half to handle slop */
......@@ -785,6 +787,12 @@ int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
int pci_assign_resource(struct pci_dev *dev, int i);
/* ROM control related routines */
void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size);
void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size);
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
void pci_remove_rom(struct pci_dev *pdev);
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);
int pci_restore_state(struct pci_dev *dev);
......@@ -994,26 +1002,28 @@ struct pci_fixup {
};
enum pci_fixup_pass {
pci_fixup_header, /* Called immediately after reading configuration header */
pci_fixup_early, /* Before probing BARs */
pci_fixup_header, /* After reading configuration header */
pci_fixup_final, /* Final phase of device fixups */
pci_fixup_enable, /* pci_enable_device() time */
};
/* Anonymous variables would be nice... */
#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, hook) \
static struct pci_fixup __pci_fixup_##name __attribute_used__ \
__attribute__((__section__(#section))) = { vendor, device, hook };
#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
vendor##device##hook, vendor, device, hook)
#define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook) \
static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__ \
__attribute__((__section__(".pci_fixup_header"))) = { \
vendor, device, hook };
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \
vendor##device##hook, vendor, device, hook)
#define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook) \
static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__ \
__attribute__((__section__(".pci_fixup_final"))) = { \
vendor, device, hook };
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final, \
vendor##device##hook, vendor, device, hook)
#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \
static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__ \
__attribute__((__section__(".pci_fixup_enable"))) = { \
vendor, device, hook };
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \
vendor##device##hook, vendor, device, hook)
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
......
......@@ -2206,8 +2206,14 @@
#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580
#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582
#define PCI_DEVICE_ID_INTEL_SMCH 0x3590
#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590
#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592
#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595
#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596
#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597
#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598
#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599
#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a
#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
#define PCI_DEVICE_ID_INTEL_80310 0x530d
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment