Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/pci-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/pci-2.6: (22 commits)
  PCI Hotplug: move pci_hotplug.h to include/linux/
  change pci hotplug subsystem maintainer to Kristen
  PCI: optionally sort device lists breadth-first
  cpcihp_generic: prevent loading without "bridge" parameter
  pci: Additional search functions
  PCI: quirks: switch quirks code offender to use pci_get API
  PCI: Update MSI-HOWTO.txt according to pci_msi_supported()
  PCI: Improve pci_msi_supported() comments
  PCI hotplug: ioremap balanced with iounmap
  shpchp: remove unnecessary cmd_busy member from struct controller
  shpchp: fix command completion check
  pci: Stamp out pci_find_* usage in fakephp
  PCI: fix pcie_portdrv_restore_config undefined without CONFIG_PM error
  Fix DMA resource allocation in ACPIPnP
  PCI: Turn pci_fixup_video into generic for embedded VGA
  PCI: add ICH7/8 ACPI/GPIO io resource quirks
  PCI: pcie-check-and-return-bus_register-errors fix
  PCI: VIA IRQ quirk behaviour change
  pciehp: Remove unnecessary check in pciehp_ctrl.c
  pciehp - add missing locking
  ...
This commit is contained in:
Linus Torvalds 2006-10-18 17:50:40 -07:00
commit b6aefcce74
44 changed files with 584 additions and 203 deletions

View File

@ -470,7 +470,68 @@ LOC: 324553 325068
ERR: 0
MIS: 0
6. FAQ
6. MSI quirks
Several PCI chipsets or devices are known to not support MSI.
The PCI stack provides 3 possible levels of MSI disabling:
* on a single device
* on all devices behind a specific bridge
* globally
6.1. Disabling MSI on a single device
Under some circumstances, it might be required to disable MSI on a
single device, It may be achived by either not calling pci_enable_msi()
or all, or setting the pci_dev->no_msi flag before (most of the time
in a quirk).
6.2. Disabling MSI below a bridge
The vast majority of MSI quirks are required by PCI bridges not
being able to route MSI between busses. In this case, MSI have to be
disabled on all devices behind this bridge. It is achieves by setting
the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
subordinate bus. There is no need to set the same flag on bridges that
are below the broken brigde. When pci_enable_msi() is called to enable
MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
flag in all parent busses of the device.
Some bridges actually support dynamic MSI support enabling/disabling
by changing some bits in their PCI configuration space (especially
the Hypertransport chipsets such as the nVidia nForce and Serverworks
HT2000). It may then be required to update the NO_MSI flag on the
corresponding devices in the sysfs hierarchy. To enable MSI support
on device "0000:00:0e", do:
echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus
To disable MSI support, echo 0 instead of 1. Note that it should be
used with caution since changing this value might break interrupts.
6.3. Disabling MSI globally
Some extreme cases may require to disable MSI globally on the system.
For now, the only known case is a Serverworks PCI-X chipsets (MSI are
not supported on several busses that are not all connected to the
chipset in the Linux PCI hierarchy). In the vast majority of other
cases, disabling only behind a specific bridge is enough.
For debugging purpose, the user may also pass pci=nomsi on the kernel
command-line to explicitly disable MSI globally. But, once the appro-
priate quirks are added to the kernel, this option should not be
required anymore.
6.4. Finding why MSI cannot be enabled on a device
Assuming that MSI are not enabled on a device, you should look at
dmesg to find messages that quirks may output when disabling MSI
on some devices, some bridges or even globally.
Then, lspci -t gives the list of bridges above a device. Reading
/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI
are enabled (1) or disabled (0). In 0 is found in a single bridge
msi_bus file above the device, MSI cannot be enabled.
7. FAQ
Q1. Are there any limitations on using the MSI?

View File

@ -1231,6 +1231,11 @@ and is between 256 and 4096 characters. It is defined in the file
machine check when some devices' config space
is read. But various workarounds are disabled
and some IOMMU drivers will not work.
bfsort Sort PCI devices into breadth-first order.
This sorting is done to get a device
order compatible with older (<= 2.4) kernels.
nobfsort Don't sort PCI devices into breadth-first order.
pcmv= [HW,PCMCIA] BadgePAD 4
pd. [PARIDE]

View File

@ -2309,8 +2309,8 @@ T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
S: Supported
PCI HOTPLUG CORE
P: Greg Kroah-Hartman
M: gregkh@suse.de
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
S: Supported
PCI HOTPLUG COMPAQ DRIVER

View File

@ -20,6 +20,7 @@
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
PCI_PROBE_MMCONF;
int pci_bf_sort;
int pci_routeirq;
int pcibios_last_bus = -1;
unsigned long pirq_table_addr;
@ -117,6 +118,20 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b)
pci_read_bridge_bases(b);
}
/*
* Only use DMI information to set this if nothing was passed
* on the kernel command line (which was parsed earlier).
*/
static int __devinit set_bf_sort(struct dmi_system_id *d)
{
if (pci_bf_sort == pci_bf_sort_default) {
pci_bf_sort = pci_dmi_bf;
printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident);
}
return 0;
}
/*
* Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
*/
@ -130,11 +145,11 @@ static int __devinit assign_all_busses(struct dmi_system_id *d)
}
#endif
static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
#ifdef __i386__
/*
* Laptops which need pci=assign-busses to see Cardbus cards
*/
static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
#ifdef __i386__
{
.callback = assign_all_busses,
.ident = "Samsung X20 Laptop",
@ -144,6 +159,38 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
},
},
#endif /* __i386__ */
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 1950",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"),
},
},
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 1955",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"),
},
},
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 2900",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"),
},
},
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 2950",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"),
},
},
{}
};
@ -189,6 +236,8 @@ static int __init pcibios_init(void)
pcibios_resource_survey();
if (pci_bf_sort >= pci_force_bf)
pci_sort_breadthfirst();
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
@ -203,6 +252,12 @@ char * __devinit pcibios_setup(char *str)
if (!strcmp(str, "off")) {
pci_probe = 0;
return NULL;
} else if (!strcmp(str, "bfsort")) {
pci_bf_sort = pci_force_bf;
return NULL;
} else if (!strcmp(str, "nobfsort")) {
pci_bf_sort = pci_force_nobf;
return NULL;
}
#ifdef CONFIG_PCI_BIOS
else if (!strcmp(str, "bios")) {

View File

@ -342,51 +342,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_r
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@gmail.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 config;
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,
&config);
if (!(config & PCI_BRIDGE_CTL_VGA))
return;
}
bus = bus->parent;
}
pci_read_config_word(pdev, PCI_COMMAND, &config);
if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
/*
* Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
*

View File

@ -30,6 +30,13 @@
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
enum pci_bf_sort_state {
pci_bf_sort_default,
pci_force_nobf,
pci_force_bf,
pci_dmi_bf,
};
/* pci-i386.c */
extern unsigned int pcibios_max_latency;

View File

@ -29,10 +29,10 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
#include "pci_hotplug.h"
#define MY_NAME "acpi_pcihp"

View File

@ -38,7 +38,7 @@
#include <linux/acpi.h>
#include <linux/kobject.h> /* for KOBJ_NAME_LEN */
#include <linux/mutex.h>
#include "pci_hotplug.h"
#include <linux/pci_hotplug.h>
#define dbg(format, arg...) \
do { \

View File

@ -37,10 +37,10 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include "pci_hotplug.h"
#include "acpiphp.h"
#define MY_NAME "acpiphp"

View File

@ -45,11 +45,11 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include "../pci.h"
#include "pci_hotplug.h"
#include "acpiphp.h"
static LIST_HEAD(bridge_list);

View File

@ -35,7 +35,6 @@
#include <linux/moduleparam.h>
#include "acpiphp.h"
#include "pci_hotplug.h"
#define DRIVER_VERSION "1.0.1"
#define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"

View File

@ -29,12 +29,12 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include "pci_hotplug.h"
#include "cpci_hotplug.h"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"

View File

@ -26,9 +26,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/proc_fs.h>
#include "../pci.h"
#include "pci_hotplug.h"
#include "cpci_hotplug.h"
#define MY_NAME "cpci_hotplug"

View File

@ -84,7 +84,7 @@ static int __init validate_parameters(void)
if(!bridge) {
info("not configured, disabling.");
return 1;
return -EINVAL;
}
str = bridge;
if(!*str)
@ -147,7 +147,7 @@ static int __init cpcihp_generic_init(void)
info(DRIVER_DESC " version: " DRIVER_VERSION);
status = validate_parameters();
if(status != 0)
if (status)
return status;
r = request_region(port, 1, "#ENUM hotswap signal register");

View File

@ -28,7 +28,6 @@
#ifndef _CPQPHP_H
#define _CPQPHP_H
#include "pci_hotplug.h"
#include <linux/interrupt.h>
#include <asm/io.h> /* for read? and write? functions */
#include <linux/delay.h> /* for delays */

View File

@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <linux/interrupt.h>

View File

@ -36,6 +36,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include "cpqphp.h"
static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,

View File

@ -33,6 +33,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include "cpqphp.h"

View File

@ -33,6 +33,7 @@
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include "../pci.h"
#include "cpqphp.h"
#include "cpqphp_nvram.h"

View File

@ -32,6 +32,7 @@
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/debugfs.h>
#include "cpqphp.h"

View File

@ -35,10 +35,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "pci_hotplug.h"
#include "../pci.h"
#if !defined(MODULE)
@ -181,7 +181,9 @@ static void pci_rescan_slot(struct pci_dev *temp)
if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
temp->hdr_type = hdr_type & 0x7f;
if (!pci_find_slot(bus->number, temp->devfn)) {
if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
pci_dev_put(dev);
else {
dev = pci_scan_single_device(bus, temp->devfn);
if (dev) {
dbg("New device on %s function %x:%x\n",
@ -205,7 +207,9 @@ static void pci_rescan_slot(struct pci_dev *temp)
continue;
temp->hdr_type = hdr_type & 0x7f;
if (!pci_find_slot(bus->number, temp->devfn)) {
if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
pci_dev_put(dev);
else {
dev = pci_scan_single_device(bus, temp->devfn);
if (dev) {
dbg("New device on %s function %x:%x\n",
@ -305,7 +309,7 @@ static int disable_slot(struct hotplug_slot *slot)
/* search for subfunctions and disable them first */
if (!(dslot->dev->devfn & 7)) {
for (func = 1; func < 8; func++) {
dev = pci_find_slot(dslot->dev->bus->number,
dev = pci_get_slot(dslot->dev->bus,
dslot->dev->devfn + func);
if (dev) {
hslot = get_slot_from_dev(dev);
@ -315,6 +319,7 @@ static int disable_slot(struct hotplug_slot *slot)
err("Hotplug slot not found for subfunction of PCI device\n");
return -ENODEV;
}
pci_dev_put(dev);
} else
dbg("No device in slot found\n");
}

View File

@ -30,7 +30,7 @@
*
*/
#include "pci_hotplug.h"
#include <linux/pci_hotplug.h>
extern int ibmphp_debug;

View File

@ -21,9 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <greg@kroah.com>
*
* Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
* Send feedback to <kristen.c.accardi@intel.com>
*
*/
@ -32,6 +30,8 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
@ -39,11 +39,8 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <asm/uaccess.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include "pci_hotplug.h"
#define MY_NAME "pci_hotplug"

View File

@ -31,11 +31,11 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/delay.h>
#include <linux/sched.h> /* signal_pending() */
#include <linux/pcieport_if.h>
#include <linux/mutex.h>
#include "pci_hotplug.h"
#define MY_NAME "pciehp"
@ -92,6 +92,7 @@ struct php_ctlr_state_s {
struct controller {
struct controller *next;
struct mutex crit_sect; /* critical section mutex */
struct mutex ctrl_lock; /* controller lock */
struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
@ -166,10 +167,10 @@ struct controller {
* error Messages
*/
#define msg_initialization_err "Initialization failure, error=%d\n"
#define msg_button_on "PCI slot #%d - powering on due to button press.\n"
#define msg_button_off "PCI slot #%d - powering off due to button press.\n"
#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n"
#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n"
#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n"
/* controller functions */
extern int pciehp_event_start_thread (void);

View File

@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
}
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
if (rc) {
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
goto err_out_free_ctrl_slot;
} else
/* Wait for the command to complete */
@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
return 0;

View File

@ -43,6 +43,11 @@ static int event_finished;
static unsigned long pushbutton_pending; /* = 0 */
static unsigned long surprise_rm_pending; /* = 0 */
static inline char *slot_name(struct slot *p_slot)
{
return p_slot->hotplug_slot->name;
}
u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
{
struct controller *ctrl = (struct controller *) inst_id;
@ -68,7 +73,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
/*
* Button pressed - See if need to TAKE ACTION!!!
*/
info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Button pressed on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_BUTTON_PRESS;
if ((p_slot->state == BLINKINGON_STATE)
@ -78,7 +83,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
* or hot-remove
*/
taskInfo->event_type = INT_BUTTON_CANCEL;
info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Button cancel on Slot(%s)\n", slot_name(p_slot));
} else if ((p_slot->state == POWERON_STATE)
|| (p_slot->state == POWEROFF_STATE)) {
/* Ignore if the slot is on power-on or power-off state; this
@ -86,7 +91,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
* hot-remove is undergoing
*/
taskInfo->event_type = INT_BUTTON_IGNORE;
info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Button ignore on Slot(%s)\n", slot_name(p_slot));
}
if (rc)
@ -122,13 +127,13 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
/*
* Switch opened
*/
info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Latch open on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_SWITCH_OPEN;
} else {
/*
* Switch closed
*/
info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Latch close on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_SWITCH_CLOSE;
}
@ -166,13 +171,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
/*
* Card Present
*/
info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Card present on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_PRESENCE_ON;
} else {
/*
* Not Present
*/
info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Card not present on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_PRESENCE_OFF;
}
@ -206,13 +211,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
/*
* power fault Cleared
*/
info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_POWER_FAULT_CLEAR;
} else {
/*
* power fault
*/
info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
info("Power fault on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_POWER_FAULT;
info("power fault bit %x set\n", hp_slot);
}
@ -229,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
/* 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__);
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
return;
}
wait_for_ctrl_irq (ctrl);
@ -249,14 +254,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
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__);
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
return;
}
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
}
/**
@ -279,13 +284,13 @@ static int board_added(struct slot *p_slot)
ctrl->slot_device_offset, hp_slot);
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
rc = p_slot->hpc_ops->power_on_slot(p_slot);
if (rc) {
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
return -1;
}
@ -301,7 +306,7 @@ static int board_added(struct slot *p_slot)
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
/* Wait for ~1 second */
wait_for_ctrl_irq (ctrl);
@ -335,7 +340,7 @@ static int board_added(struct slot *p_slot)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
if (PWR_LED(ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
p_slot->hpc_ops->green_led_on(p_slot);
@ -343,7 +348,7 @@ static int board_added(struct slot *p_slot)
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
}
return 0;
@ -375,14 +380,14 @@ static int remove_board(struct slot *p_slot)
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
rc = p_slot->hpc_ops->power_off_slot(p_slot);
if (rc) {
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
return rc;
}
/* Wait for the command to complete */
@ -398,7 +403,7 @@ static int remove_board(struct slot *p_slot)
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
return 0;
}
@ -445,7 +450,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
mutex_lock(&p_slot->ctrl->crit_sect);
mutex_lock(&p_slot->ctrl->ctrl_lock);
p_slot->hpc_ops->green_led_off(p_slot);
@ -453,7 +458,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
mutex_unlock(&p_slot->ctrl->crit_sect);
mutex_unlock(&p_slot->ctrl->ctrl_lock);
}
p_slot->state = STATIC_STATE;
}
@ -495,7 +500,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
mutex_lock(&p_slot->ctrl->crit_sect);
mutex_lock(&p_slot->ctrl->ctrl_lock);
p_slot->hpc_ops->green_led_off(p_slot);
@ -503,7 +508,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
mutex_unlock(&p_slot->ctrl->crit_sect);
mutex_unlock(&p_slot->ctrl->ctrl_lock);
}
p_slot->state = STATIC_STATE;
}
@ -616,7 +621,7 @@ static void interrupt_event_handler(struct controller *ctrl)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_on(p_slot);
@ -630,11 +635,11 @@ static void interrupt_event_handler(struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
break;
case BLINKINGON_STATE:
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_off(p_slot);
@ -647,14 +652,14 @@ static void interrupt_event_handler(struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
break;
default:
warn("Not a valid state\n");
return;
}
info(msg_button_cancel, p_slot->number);
info(msg_button_cancel, slot_name(p_slot));
p_slot->state = STATIC_STATE;
}
/* ***********Button Pressed (No action on 1st press...) */
@ -667,16 +672,16 @@ static void interrupt_event_handler(struct controller *ctrl)
/* slot is on */
dbg("slot is on\n");
p_slot->state = BLINKINGOFF_STATE;
info(msg_button_off, p_slot->number);
info(msg_button_off, slot_name(p_slot));
} else {
/* slot is off */
dbg("slot is off\n");
p_slot->state = BLINKINGON_STATE;
info(msg_button_on, p_slot->number);
info(msg_button_on, slot_name(p_slot));
}
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
/* blink green LED and turn off amber */
if (PWR_LED(ctrl->ctrlcap)) {
@ -693,7 +698,7 @@ static void interrupt_event_handler(struct controller *ctrl)
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
init_timer(&p_slot->task_event);
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
@ -708,7 +713,7 @@ static void interrupt_event_handler(struct controller *ctrl)
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
mutex_lock(&ctrl->ctrl_lock);
if (ATTN_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->set_attention_status(p_slot, 1);
@ -721,7 +726,7 @@ static void interrupt_event_handler(struct controller *ctrl)
}
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
mutex_unlock(&ctrl->ctrl_lock);
}
}
/***********SURPRISE REMOVAL********************/
@ -760,14 +765,16 @@ int pciehp_enable_slot(struct slot *p_slot)
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);
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
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);
info("%s: latch open on slot(%s)\n", __FUNCTION__,
slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@ -776,12 +783,12 @@ int pciehp_enable_slot(struct slot *p_slot)
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);
info("%s: already enabled on slot(%s)\n", __FUNCTION__,
slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
}
mutex_unlock(&p_slot->ctrl->crit_sect);
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
@ -790,9 +797,9 @@ int pciehp_enable_slot(struct slot *p_slot)
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
}
if (p_slot)
update_slot_info(p_slot);
update_slot_info(p_slot);
mutex_unlock(&p_slot->ctrl->crit_sect);
return rc;
}
@ -811,7 +818,8 @@ int pciehp_disable_slot(struct slot *p_slot)
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);
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@ -820,7 +828,8 @@ int pciehp_disable_slot(struct slot *p_slot)
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);
info("%s: latch open on slot(%s)\n", __FUNCTION__,
slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@ -829,16 +838,17 @@ int pciehp_disable_slot(struct slot *p_slot)
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);
info("%s: already disabled slot(%s)\n", __FUNCTION__,
slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
}
mutex_unlock(&p_slot->ctrl->crit_sect);
ret = remove_board(p_slot);
update_slot_info(p_slot);
mutex_unlock(&p_slot->ctrl->crit_sect);
return ret;
}

View File

@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
pdev->subsystem_vendor, pdev->subsystem_device);
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);

View File

@ -33,8 +33,8 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include "pci_hotplug.h"
#define SLOT_NAME_SIZE 10
struct slot {

View File

@ -14,7 +14,7 @@
*/
#include <linux/kobject.h>
#include <linux/string.h>
#include "pci_hotplug.h"
#include <linux/pci_hotplug.h>
#include "rpadlpar.h"
#define DLPAR_KOBJ_NAME "control"

View File

@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@ -36,7 +37,6 @@
#include "../pci.h" /* for pci_add_new_bus */
/* and pci_do_scan_bus */
#include "rpaphp.h"
#include "pci_hotplug.h"
int debug;
static struct semaphore rpaphp_sem;

View File

@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/mutex.h>
@ -29,7 +30,6 @@
#include <asm/sn/types.h>
#include "../pci.h"
#include "pci_hotplug.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");

View File

@ -31,12 +31,11 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/delay.h>
#include <linux/sched.h> /* signal_pending(), struct timer_list */
#include <linux/mutex.h>
#include "pci_hotplug.h"
#if !defined(MODULE)
#define MY_NAME "shpchp"
#else
@ -103,7 +102,6 @@ struct controller {
u32 cap_offset;
unsigned long mmio_base;
unsigned long mmio_size;
volatile int cmd_busy;
};

View File

@ -302,21 +302,51 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec)
add_timer(&php_ctlr->int_poll_timer);
}
static inline int is_ctrl_busy(struct controller *ctrl)
{
u16 cmd_status = shpc_readw(ctrl, CMD_STATUS);
return cmd_status & 0x1;
}
/*
* Returns 1 if SHPC finishes executing a command within 1 sec,
* otherwise returns 0.
*/
static inline int shpc_poll_ctrl_busy(struct controller *ctrl)
{
int i;
if (!is_ctrl_busy(ctrl))
return 1;
/* Check every 0.1 sec for a total of 1 sec */
for (i = 0; i < 10; i++) {
msleep(100);
if (!is_ctrl_busy(ctrl))
return 1;
}
return 0;
}
static inline int shpc_wait_cmd(struct controller *ctrl)
{
int retval = 0;
unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;
unsigned long timeout = msecs_to_jiffies(timeout_msec);
int rc = wait_event_interruptible_timeout(ctrl->queue,
!ctrl->cmd_busy, timeout);
if (!rc) {
unsigned long timeout = msecs_to_jiffies(1000);
int rc;
if (shpchp_poll_mode)
rc = shpc_poll_ctrl_busy(ctrl);
else
rc = wait_event_interruptible_timeout(ctrl->queue,
!is_ctrl_busy(ctrl), timeout);
if (!rc && is_ctrl_busy(ctrl)) {
retval = -EIO;
err("Command not completed in %d msec\n", timeout_msec);
err("Command not completed in 1000 msec\n");
} else if (rc < 0) {
retval = -EINTR;
info("Command was interrupted by a signal\n");
}
ctrl->cmd_busy = 0;
return retval;
}
@ -327,26 +357,15 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
u16 cmd_status;
int retval = 0;
u16 temp_word;
int i;
DBG_ENTER_ROUTINE
mutex_lock(&slot->ctrl->cmd_lock);
for (i = 0; i < 10; i++) {
cmd_status = shpc_readw(ctrl, CMD_STATUS);
if (!(cmd_status & 0x1))
break;
/* Check every 0.1 sec for a total of 1 sec*/
msleep(100);
}
cmd_status = shpc_readw(ctrl, CMD_STATUS);
if (cmd_status & 0x1) {
if (!shpc_poll_ctrl_busy(ctrl)) {
/* After 1 sec and and the controller is still busy */
err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
err("%s : Controller is still busy after 1 sec.\n",
__FUNCTION__);
retval = -EBUSY;
goto out;
}
@ -358,7 +377,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
/* To make sure the Controller Busy bit is 0 before we send out the
* command.
*/
slot->ctrl->cmd_busy = 1;
shpc_writew(ctrl, CMD, temp_word);
/*
@ -908,7 +926,6 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
serr_int &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
}
@ -1101,7 +1118,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
{
struct php_ctlr_state_s *php_ctlr, *p;
void *instance_id = ctrl;
int rc, num_slots = 0;
int rc = -1, num_slots = 0;
u8 hp_slot;
u32 shpc_base_offset;
u32 tempdword, slot_reg, slot_config;
@ -1167,11 +1184,15 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device);
if (pci_enable_device(pdev))
rc = pci_enable_device(pdev);
if (rc) {
err("%s: pci_enable_device failed\n", __FUNCTION__);
goto abort_free_ctlr;
}
if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
err("%s: cannot reserve MMIO region\n", __FUNCTION__);
rc = -1;
goto abort_free_ctlr;
}
@ -1180,6 +1201,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
ctrl->mmio_size, ctrl->mmio_base);
release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
rc = -1;
goto abort_free_ctlr;
}
dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
@ -1282,8 +1304,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
*/
if (atomic_add_return(1, &shpchp_num_controllers) == 1) {
shpchp_wq = create_singlethread_workqueue("shpchpd");
if (!shpchp_wq)
return -ENOMEM;
if (!shpchp_wq) {
rc = -ENOMEM;
goto abort_free_ctlr;
}
}
/*
@ -1313,8 +1337,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
/* We end up here for the many possible ways to fail this API. */
abort_free_ctlr:
if (php_ctlr->creg)
iounmap(php_ctlr->creg);
kfree(php_ctlr);
abort:
DBG_LEAVE_ROUTINE
return -1;
return rc;
}

View File

@ -627,22 +627,24 @@ static int msix_capability_init(struct pci_dev *dev,
* pci_msi_supported - check whether MSI may be enabled on device
* @dev: pointer to the pci_dev data structure of MSI device function
*
* MSI must be globally enabled and supported by the device and its root
* bus. But, the root bus is not easy to find since some architectures
* have virtual busses on top of the PCI hierarchy (for instance the
* hypertransport bus), while the actual bus where MSI must be supported
* is below. So we test the MSI flag on all parent busses and assume
* that no quirk will ever set the NO_MSI flag on a non-root bus.
* Look at global flags, the device itself, and its parent busses
* to return 0 if MSI are supported for the device.
**/
static
int pci_msi_supported(struct pci_dev * dev)
{
struct pci_bus *bus;
/* MSI must be globally enabled and supported by the device */
if (!pci_msi_enable || !dev || dev->no_msi)
return -EINVAL;
/* check MSI flags of all parent busses */
/* Any bridge which does NOT route MSI transactions from it's
* secondary bus to it's primary bus must set NO_MSI flag on
* the secondary pci_bus.
* We expect only arch-specific PCI host bus controller driver
* or quirks for specific PCI bridges to be setting NO_MSI.
*/
for (bus = dev->bus; bus; bus = bus->parent)
if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
return -EINVAL;

View File

@ -9,6 +9,8 @@
#ifndef _PORTDRV_H_
#define _PORTDRV_H_
#include <linux/compiler.h>
#if !defined(PCI_CAP_ID_PME)
#define PCI_CAP_ID_PME 1
#endif
@ -39,7 +41,7 @@ extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state);
extern int pcie_port_device_resume(struct pci_dev *dev);
#endif
extern void pcie_port_device_remove(struct pci_dev *dev);
extern int pcie_port_bus_register(void);
extern int __must_check pcie_port_bus_register(void);
extern void pcie_port_bus_unregister(void);
#endif /* _PORTDRV_H_ */

View File

@ -6,7 +6,6 @@
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@ -401,7 +400,7 @@ void pcie_port_device_remove(struct pci_dev *dev)
pci_disable_msi(dev);
}
int __must_check pcie_port_bus_register(void)
int pcie_port_bus_register(void)
{
return bus_register(&pcie_port_bus_type);
}

View File

@ -37,7 +37,6 @@ static int pcie_portdrv_save_config(struct pci_dev *dev)
return pci_save_state(dev);
}
#ifdef CONFIG_PM
static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
int retval;
@ -50,6 +49,7 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
return 0;
}
#ifdef CONFIG_PM
static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
{
int ret = pcie_port_device_suspend(dev, state);

View File

@ -1067,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge);
EXPORT_SYMBOL(pci_scan_single_device);
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
#endif
static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b)
{
if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1;
else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1;
if (a->bus->number < b->bus->number) return -1;
else if (a->bus->number > b->bus->number) return 1;
if (a->devfn < b->devfn) return -1;
else if (a->devfn > b->devfn) return 1;
return 0;
}
/*
* Yes, this forcably breaks the klist abstraction temporarily. It
* just wants to sort the klist, not change reference counts and
* take/drop locks rapidly in the process. It does all this while
* holding the lock for the list, so objects can't otherwise be
* added/removed while we're swizzling.
*/
static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list)
{
struct list_head *pos;
struct klist_node *n;
struct device *dev;
struct pci_dev *b;
list_for_each(pos, list) {
n = container_of(pos, struct klist_node, n_node);
dev = container_of(n, struct device, knode_bus);
b = to_pci_dev(dev);
if (pci_sort_bf_cmp(a, b) <= 0) {
list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node);
return;
}
}
list_move_tail(&a->dev.knode_bus.n_node, list);
}
static void __init pci_sort_breadthfirst_klist(void)
{
LIST_HEAD(sorted_devices);
struct list_head *pos, *tmp;
struct klist_node *n;
struct device *dev;
struct pci_dev *pdev;
spin_lock(&pci_bus_type.klist_devices.k_lock);
list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
n = container_of(pos, struct klist_node, n_node);
dev = container_of(n, struct device, knode_bus);
pdev = to_pci_dev(dev);
pci_insertion_sort_klist(pdev, &sorted_devices);
}
list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
spin_unlock(&pci_bus_type.klist_devices.k_lock);
}
static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
{
struct pci_dev *b;
list_for_each_entry(b, list, global_list) {
if (pci_sort_bf_cmp(a, b) <= 0) {
list_move_tail(&a->global_list, &b->global_list);
return;
}
}
list_move_tail(&a->global_list, list);
}
static void __init pci_sort_breadthfirst_devices(void)
{
LIST_HEAD(sorted_devices);
struct pci_dev *dev, *tmp;
down_write(&pci_bus_sem);
list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) {
pci_insertion_sort_devices(dev, &sorted_devices);
}
list_splice(&sorted_devices, &pci_devices);
up_write(&pci_bus_sem);
}
void __init pci_sort_breadthfirst(void)
{
pci_sort_breadthfirst_devices();
pci_sort_breadthfirst_klist();
}

View File

@ -453,6 +453,12 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
/*
* VIA ACPI: One IO region pointed to by longword at
@ -648,11 +654,43 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi
* Some of the on-chip devices are actually '586 devices' so they are
* listed here.
*/
static int via_irq_fixup_needed = -1;
/*
* As some VIA hardware is available in PCI-card form, we need to restrict
* this quirk to VIA PCI hardware built onto VIA-based motherboards only.
* We try to locate a VIA southbridge before deciding whether the quirk
* should be applied.
*/
static const struct pci_device_id via_irq_fixup_tbl[] = {
{
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.class = PCI_CLASS_BRIDGE_ISA << 8,
.class_mask = 0xffff00,
},
{ 0, },
};
static void quirk_via_irq(struct pci_dev *dev)
{
u8 irq, new_irq;
new_irq = dev->irq & 0xf;
if (via_irq_fixup_needed == -1)
via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl);
if (!via_irq_fixup_needed)
return;
new_irq = dev->irq;
/* Don't quirk interrupts outside the legacy IRQ range */
if (!new_irq || new_irq > 15)
return;
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (new_irq != irq) {
printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n",
@ -661,14 +699,7 @@ static void quirk_via_irq(struct pci_dev *dev)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
/*
* VIA VT82C598 has its device ID settable and many BIOSes
@ -1588,6 +1619,51 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
/*
* Fixup to mark boot BIOS video selected by BIOS before it changes
*
* From information provided by "Jon Smirl" <jonsmirl@gmail.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 fixup_video(struct pci_dev *pdev)
{
struct pci_dev *bridge;
struct pci_bus *bus;
u16 config;
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,
&config);
if (!(config & PCI_BRIDGE_CTL_VGA))
return;
}
bus = bus->parent;
}
pci_read_config_word(pdev, PCI_COMMAND, &config);
if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_video);
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
{
@ -1764,7 +1840,7 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
/* check HT MSI cap on this chipset and the root one.
* a single one having MSI is enough to be sure that MSI are supported.
*/
pdev = pci_find_slot(dev->bus->number, 0);
pdev = pci_get_slot(dev->bus, 0);
if (dev->subordinate && !msi_ht_cap_enabled(dev)
&& !msi_ht_cap_enabled(pdev)) {
printk(KERN_WARNING "PCI: MSI quirk detected. "
@ -1772,6 +1848,7 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
pci_name(dev));
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
}
pci_dev_put(pdev);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap);

View File

@ -71,7 +71,10 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
void __iomem *image;
int last_image;
/* IORESOURCE_ROM_SHADOW only set on x86 */
/*
* IORESOURCE_ROM_SHADOW set if the VGA enable bit of the Bridge Control
* register is set for embedded VGA.
*/
if (res->flags & IORESOURCE_ROM_SHADOW) {
/* primary video rom always starts here */
start = (loff_t)0xC0000;

View File

@ -139,6 +139,31 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
return dev;
}
/**
* pci_get_bus_and_slot - locate PCI device from a given PCI slot
* @bus: number of PCI bus on which desired PCI device resides
* @devfn: encodes number of PCI slot in which the desired PCI
* device resides and the logical device number within that slot
* in case of multi-function devices.
*
* Given a PCI bus and slot/function number, the desired PCI device
* is located in system global list of PCI devices. If the device
* is found, a pointer to its data structure is returned. If no
* device is found, %NULL is returned. The returned device has its
* reference count bumped by one.
*/
struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
{
struct pci_dev *dev = NULL;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->bus->number == bus && dev->devfn == devfn)
return dev;
}
return NULL;
}
/**
* pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
@ -274,6 +299,45 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}
/**
* pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices in the reverse order of
* pci_get_device.
* If a PCI device is found with a matching @vendor and @device, the reference
* count to the device is incremented and a pointer to its device structure
* is returned Otherwise, %NULL is returned. A new search is initiated by
* passing %NULL as the @from argument. Otherwise if @from is not %NULL,
* searches continue from next device on the global list. The reference
* count for @from is always decremented if it is not %NULL.
*/
struct pci_dev *
pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from)
{
struct list_head *n;
struct pci_dev *dev;
WARN_ON(in_interrupt());
down_read(&pci_bus_sem);
n = from ? from->global_list.prev : pci_devices.prev;
while (n && (n != &pci_devices)) {
dev = pci_dev_g(n);
if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
(device == PCI_ANY_ID || dev->device == device))
goto exit;
n = n->prev;
}
dev = NULL;
exit:
dev = pci_dev_get(dev);
up_read(&pci_bus_sem);
pci_dev_put(from);
return dev;
}
/**
* pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
@ -382,12 +446,16 @@ exit:
}
EXPORT_SYMBOL(pci_dev_present);
EXPORT_SYMBOL(pci_find_bus);
EXPORT_SYMBOL(pci_find_next_bus);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
/* For boot time work */
EXPORT_SYMBOL(pci_find_bus);
EXPORT_SYMBOL(pci_find_next_bus);
/* For everyone */
EXPORT_SYMBOL(pci_get_device);
EXPORT_SYMBOL(pci_get_device_reverse);
EXPORT_SYMBOL(pci_get_subsys);
EXPORT_SYMBOL(pci_get_slot);
EXPORT_SYMBOL(pci_get_bus_and_slot);
EXPORT_SYMBOL(pci_get_class);

View File

@ -776,21 +776,32 @@ static void pnpacpi_encode_dma(struct acpi_resource *resource,
struct resource *p)
{
/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
if (p->flags & IORESOURCE_DMA_COMPATIBLE)
resource->data.dma.type = ACPI_COMPATIBILITY;
else if (p->flags & IORESOURCE_DMA_TYPEA)
resource->data.dma.type = ACPI_TYPE_A;
else if (p->flags & IORESOURCE_DMA_TYPEB)
resource->data.dma.type = ACPI_TYPE_B;
else if (p->flags & IORESOURCE_DMA_TYPEF)
resource->data.dma.type = ACPI_TYPE_F;
if (p->flags & IORESOURCE_DMA_8BIT)
resource->data.dma.transfer = ACPI_TRANSFER_8;
else if (p->flags & IORESOURCE_DMA_8AND16BIT)
resource->data.dma.transfer = ACPI_TRANSFER_8_16;
else if (p->flags & IORESOURCE_DMA_16BIT)
resource->data.dma.transfer = ACPI_TRANSFER_16;
resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
case IORESOURCE_DMA_TYPEA:
resource->data.dma.type = ACPI_TYPE_A;
break;
case IORESOURCE_DMA_TYPEB:
resource->data.dma.type = ACPI_TYPE_B;
break;
case IORESOURCE_DMA_TYPEF:
resource->data.dma.type = ACPI_TYPE_F;
break;
default:
resource->data.dma.type = ACPI_COMPATIBILITY;
}
switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
case IORESOURCE_DMA_8BIT:
resource->data.dma.transfer = ACPI_TRANSFER_8;
break;
case IORESOURCE_DMA_8AND16BIT:
resource->data.dma.transfer = ACPI_TRANSFER_8_16;
break;
default:
resource->data.dma.transfer = ACPI_TRANSFER_16;
}
resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
resource->data.dma.channel_count = 1;
resource->data.dma.channels[0] = p->start;
}

View File

@ -443,6 +443,7 @@ extern void pci_remove_bus(struct pci_bus *b);
extern void pci_remove_bus_device(struct pci_dev *dev);
extern void pci_stop_bus_device(struct pci_dev *dev);
void pci_setup_cardbus(struct pci_bus *bus);
extern void pci_sort_breadthfirst(void);
/* Generic PCI functions exported to card drivers */
@ -452,13 +453,14 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
int pci_find_capability (struct pci_dev *dev, int cap);
int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
int pci_find_ext_capability (struct pci_dev *dev, int cap);
struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
struct pci_dev *from);
struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn);
struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn);
struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from);
int pci_dev_present(const struct pci_device_id *ids);

View File

@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <greg@kroah.com>
* Send feedback to <kristen.c.accardi@intel.com>
*
*/
#ifndef _PCI_HOTPLUG_H