mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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:
commit
b6aefcce74
@ -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?
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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")) {
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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 { \
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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>"
|
||||
|
@ -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>"
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pci_hotplug.h"
|
||||
#include <linux/pci_hotplug.h>
|
||||
|
||||
extern int ibmphp_debug;
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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)");
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user