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

This commit is contained in:
Linus Torvalds 2006-01-09 18:41:42 -08:00
commit 977127174a
68 changed files with 955 additions and 443 deletions

View file

@ -1,4 +1,5 @@
Accessing PCI device resources through sysfs Accessing PCI device resources through sysfs
--------------------------------------------
sysfs, usually mounted at /sys, provides access to PCI resources on platforms sysfs, usually mounted at /sys, provides access to PCI resources on platforms
that support it. For example, a given bus might look like this: that support it. For example, a given bus might look like this:
@ -47,14 +48,21 @@ files, each with their own function.
binary - file contains binary data binary - file contains binary data
cpumask - file contains a cpumask type cpumask - file contains a cpumask type
The read only files are informational, writes to them will be ignored. The read only files are informational, writes to them will be ignored, with
Writable files can be used to perform actions on the device (e.g. changing the exception of the 'rom' file. Writable files can be used to perform
config space, detaching a device). mmapable files are available via an actions on the device (e.g. changing config space, detaching a device).
mmap of the file at offset 0 and can be used to do actual device programming mmapable files are available via an mmap of the file at offset 0 and can be
from userspace. Note that some platforms don't support mmapping of certain used to do actual device programming from userspace. Note that some platforms
resources, so be sure to check the return value from any attempted mmap. don't support mmapping of certain resources, so be sure to check the return
value from any attempted mmap.
The 'rom' file is special in that it provides read-only access to the device's
ROM file, if available. It's disabled by default, however, so applications
should write the string "1" to the file to enable it before attempting a read
call, and disable it following the access by writing "0" to the file.
Accessing legacy resources through sysfs Accessing legacy resources through sysfs
----------------------------------------
Legacy I/O port and ISA memory resources are also provided in sysfs if the Legacy I/O port and ISA memory resources are also provided in sysfs if the
underlying platform supports them. They're located in the PCI class heirarchy, underlying platform supports them. They're located in the PCI class heirarchy,
@ -75,6 +83,7 @@ simply dereference the returned pointer (after checking for errors of course)
to access legacy memory space. to access legacy memory space.
Supporting PCI access on new platforms Supporting PCI access on new platforms
--------------------------------------
In order to support PCI resource mapping as described above, Linux platform In order to support PCI resource mapping as described above, Linux platform
code must define HAVE_PCI_MMAP and provide a pci_mmap_page_range function. code must define HAVE_PCI_MMAP and provide a pci_mmap_page_range function.

View file

@ -0,0 +1,246 @@
PCI Error Recovery
------------------
May 31, 2005
Current document maintainer:
Linas Vepstas <linas@austin.ibm.com>
Some PCI bus controllers are able to detect certain "hard" PCI errors
on the bus, such as parity errors on the data and address busses, as
well as SERR and PERR errors. These chipsets are then able to disable
I/O to/from the affected device, so that, for example, a bad DMA
address doesn't end up corrupting system memory. These same chipsets
are also able to reset the affected PCI device, and return it to
working condition. This document describes a generic API form
performing error recovery.
The core idea is that after a PCI error has been detected, there must
be a way for the kernel to coordinate with all affected device drivers
so that the pci card can be made operational again, possibly after
performing a full electrical #RST of the PCI card. The API below
provides a generic API for device drivers to be notified of PCI
errors, and to be notified of, and respond to, a reset sequence.
Preliminary sketch of API, cut-n-pasted-n-modified email from
Ben Herrenschmidt, circa 5 april 2005
The error recovery API support is exposed to the driver in the form of
a structure of function pointers pointed to by a new field in struct
pci_driver. The absence of this pointer in pci_driver denotes an
"non-aware" driver, behaviour on these is platform dependant.
Platforms like ppc64 can try to simulate pci hotplug remove/add.
The definition of "pci_error_token" is not covered here. It is based on
Seto's work on the synchronous error detection. We still need to define
functions for extracting infos out of an opaque error token. This is
separate from this API.
This structure has the form:
struct pci_error_handlers
{
int (*error_detected)(struct pci_dev *dev, pci_error_token error);
int (*mmio_enabled)(struct pci_dev *dev);
int (*resume)(struct pci_dev *dev);
int (*link_reset)(struct pci_dev *dev);
int (*slot_reset)(struct pci_dev *dev);
};
A driver doesn't have to implement all of these callbacks. The
only mandatory one is error_detected(). If a callback is not
implemented, the corresponding feature is considered unsupported.
For example, if mmio_enabled() and resume() aren't there, then the
driver is assumed as not doing any direct recovery and requires
a reset. If link_reset() is not implemented, the card is assumed as
not caring about link resets, in which case, if recover is supported,
the core can try recover (but not slot_reset() unless it really did
reset the slot). If slot_reset() is not supported, link_reset() can
be called instead on a slot reset.
At first, the call will always be :
1) error_detected()
Error detected. This is sent once after an error has been detected. At
this point, the device might not be accessible anymore depending on the
platform (the slot will be isolated on ppc64). The driver may already
have "noticed" the error because of a failing IO, but this is the proper
"synchronisation point", that is, it gives a chance to the driver to
cleanup, waiting for pending stuff (timers, whatever, etc...) to
complete; it can take semaphores, schedule, etc... everything but touch
the device. Within this function and after it returns, the driver
shouldn't do any new IOs. Called in task context. This is sort of a
"quiesce" point. See note about interrupts at the end of this doc.
Result codes:
- PCIERR_RESULT_CAN_RECOVER:
Driever returns this if it thinks it might be able to recover
the HW by just banging IOs or if it wants to be given
a chance to extract some diagnostic informations (see
below).
- PCIERR_RESULT_NEED_RESET:
Driver returns this if it thinks it can't recover unless the
slot is reset.
- PCIERR_RESULT_DISCONNECT:
Return this if driver thinks it won't recover at all,
(this will detach the driver ? or just leave it
dangling ? to be decided)
So at this point, we have called error_detected() for all drivers
on the segment that had the error. On ppc64, the slot is isolated. What
happens now typically depends on the result from the drivers. If all
drivers on the segment/slot return PCIERR_RESULT_CAN_RECOVER, we would
re-enable IOs on the slot (or do nothing special if the platform doesn't
isolate slots) and call 2). If not and we can reset slots, we go to 4),
if neither, we have a dead slot. If it's an hotplug slot, we might
"simulate" reset by triggering HW unplug/replug though.
>>> Current ppc64 implementation assumes that a device driver will
>>> *not* schedule or semaphore in this routine; the current ppc64
>>> implementation uses one kernel thread to notify all devices;
>>> thus, of one device sleeps/schedules, all devices are affected.
>>> Doing better requires complex multi-threaded logic in the error
>>> recovery implementation (e.g. waiting for all notification threads
>>> to "join" before proceeding with recovery.) This seems excessively
>>> complex and not worth implementing.
>>> The current ppc64 implementation doesn't much care if the device
>>> attempts i/o at this point, or not. I/O's will fail, returning
>>> a value of 0xff on read, and writes will be dropped. If the device
>>> driver attempts more than 10K I/O's to a frozen adapter, it will
>>> assume that the device driver has gone into an infinite loop, and
>>> it will panic the the kernel.
2) mmio_enabled()
This is the "early recovery" call. IOs are allowed again, but DMA is
not (hrm... to be discussed, I prefer not), with some restrictions. This
is NOT a callback for the driver to start operations again, only to
peek/poke at the device, extract diagnostic information, if any, and
eventually do things like trigger a device local reset or some such,
but not restart operations. This is sent if all drivers on a segment
agree that they can try to recover and no automatic link reset was
performed by the HW. If the platform can't just re-enable IOs without
a slot reset or a link reset, it doesn't call this callback and goes
directly to 3) or 4). All IOs should be done _synchronously_ from
within this callback, errors triggered by them will be returned via
the normal pci_check_whatever() api, no new error_detected() callback
will be issued due to an error happening here. However, such an error
might cause IOs to be re-blocked for the whole segment, and thus
invalidate the recovery that other devices on the same segment might
have done, forcing the whole segment into one of the next states,
that is link reset or slot reset.
Result codes:
- PCIERR_RESULT_RECOVERED
Driver returns this if it thinks the device is fully
functionnal and thinks it is ready to start
normal driver operations again. There is no
guarantee that the driver will actually be
allowed to proceed, as another driver on the
same segment might have failed and thus triggered a
slot reset on platforms that support it.
- PCIERR_RESULT_NEED_RESET
Driver returns this if it thinks the device is not
recoverable in it's current state and it needs a slot
reset to proceed.
- PCIERR_RESULT_DISCONNECT
Same as above. Total failure, no recovery even after
reset driver dead. (To be defined more precisely)
>>> The current ppc64 implementation does not implement this callback.
3) link_reset()
This is called after the link has been reset. This is typically
a PCI Express specific state at this point and is done whenever a
non-fatal error has been detected that can be "solved" by resetting
the link. This call informs the driver of the reset and the driver
should check if the device appears to be in working condition.
This function acts a bit like 2) mmio_enabled(), in that the driver
is not supposed to restart normal driver I/O operations right away.
Instead, it should just "probe" the device to check it's recoverability
status. If all is right, then the core will call resume() once all
drivers have ack'd link_reset().
Result codes:
(identical to mmio_enabled)
>>> The current ppc64 implementation does not implement this callback.
4) slot_reset()
This is called after the slot has been soft or hard reset by the
platform. A soft reset consists of asserting the adapter #RST line
and then restoring the PCI BARs and PCI configuration header. If the
platform supports PCI hotplug, then it might instead perform a hard
reset by toggling power on the slot off/on. This call gives drivers
the chance to re-initialize the hardware (re-download firmware, etc.),
but drivers shouldn't restart normal I/O processing operations at
this point. (See note about interrupts; interrupts aren't guaranteed
to be delivered until the resume() callback has been called). If all
device drivers report success on this callback, the patform will call
resume() to complete the error handling and let the driver restart
normal I/O processing.
A driver can still return a critical failure for this function if
it can't get the device operational after reset. If the platform
previously tried a soft reset, it migh now try a hard reset (power
cycle) and then call slot_reset() again. It the device still can't
be recovered, there is nothing more that can be done; the platform
will typically report a "permanent failure" in such a case. The
device will be considered "dead" in this case.
Result codes:
- PCIERR_RESULT_DISCONNECT
Same as above.
>>> The current ppc64 implementation does not try a power-cycle reset
>>> if the driver returned PCIERR_RESULT_DISCONNECT. However, it should.
5) resume()
This is called if all drivers on the segment have returned
PCIERR_RESULT_RECOVERED from one of the 3 prevous callbacks.
That basically tells the driver to restart activity, tht everything
is back and running. No result code is taken into account here. If
a new error happens, it will restart a new error handling process.
That's it. I think this covers all the possibilities. The way those
callbacks are called is platform policy. A platform with no slot reset
capability for example may want to just "ignore" drivers that can't
recover (disconnect them) and try to let other cards on the same segment
recover. Keep in mind that in most real life cases, though, there will
be only one driver per segment.
Now, there is a note about interrupts. If you get an interrupt and your
device is dead or has been isolated, there is a problem :)
After much thinking, I decided to leave that to the platform. That is,
the recovery API only precies that:
- There is no guarantee that interrupt delivery can proceed from any
device on the segment starting from the error detection and until the
restart callback is sent, at which point interrupts are expected to be
fully operational.
- There is no guarantee that interrupt delivery is stopped, that is, ad
river that gets an interrupts after detecting an error, or that detects
and error within the interrupt handler such that it prevents proper
ack'ing of the interrupt (and thus removal of the source) should just
return IRQ_NOTHANDLED. It's up to the platform to deal with taht
condition, typically by masking the irq source during the duration of
the error handling. It is expected that the platform "knows" which
interrupts are routed to error-management capable slots and can deal
with temporarily disabling that irq number during error processing (this
isn't terribly complex). That means some IRQ latency for other devices
sharing the interrupt, but there is simply no other way. High end
platforms aren't supposed to share interrupts between many devices
anyway :)
Revised: 31 May 2005 Linas Vepstas <linas@austin.ibm.com>

View file

@ -1987,6 +1987,13 @@ M: hch@infradead.org
L: linux-abi-devel@lists.sourceforge.net L: linux-abi-devel@lists.sourceforge.net
S: Maintained S: Maintained
PCI ERROR RECOVERY
P: Linas Vepstas
M: linas@austin.ibm.com
L: linux-kernel@vger.kernel.org
L: linux-pci@atrey.karlin.mff.cuni.cz
S: Supported
PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES) PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES)
P: Thomas Sailer P: Thomas Sailer
M: sailer@ife.ee.ethz.ch M: sailer@ife.ee.ethz.ch

View file

@ -254,7 +254,7 @@ alcor_init_pci(void)
* motherboard, by looking for a 21040 TULIP in slot 6, which is * motherboard, by looking for a 21040 TULIP in slot 6, which is
* built into XLT and BRET/MAVERICK, but not available on ALCOR. * built into XLT and BRET/MAVERICK, but not available on ALCOR.
*/ */
dev = pci_find_device(PCI_VENDOR_ID_DEC, dev = pci_get_device(PCI_VENDOR_ID_DEC,
PCI_DEVICE_ID_DEC_TULIP, PCI_DEVICE_ID_DEC_TULIP,
NULL); NULL);
if (dev && dev->devfn == PCI_DEVFN(6,0)) { if (dev && dev->devfn == PCI_DEVFN(6,0)) {
@ -262,6 +262,7 @@ alcor_init_pci(void)
printk(KERN_INFO "%s: Detected AS500 or XLT motherboard.\n", printk(KERN_INFO "%s: Detected AS500 or XLT motherboard.\n",
__FUNCTION__); __FUNCTION__);
} }
pci_dev_put(dev);
} }

View file

@ -105,7 +105,7 @@ sio_collect_irq_levels(void)
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
/* Iterate through the devices, collecting IRQ levels. */ /* Iterate through the devices, collecting IRQ levels. */
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for_each_pci_dev(dev) {
if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
(dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
continue; continue;
@ -229,8 +229,8 @@ alphabook1_init_pci(void)
*/ */
dev = NULL; dev = NULL;
while ((dev = pci_find_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) { while ((dev = pci_get_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) {
if (dev->device == PCI_DEVICE_ID_NCR_53C810 if (dev->device == PCI_DEVICE_ID_NCR_53C810
|| dev->device == PCI_DEVICE_ID_NCR_53C815 || dev->device == PCI_DEVICE_ID_NCR_53C815
|| dev->device == PCI_DEVICE_ID_NCR_53C820 || dev->device == PCI_DEVICE_ID_NCR_53C820
|| dev->device == PCI_DEVICE_ID_NCR_53C825) { || dev->device == PCI_DEVICE_ID_NCR_53C825) {

View file

@ -142,9 +142,7 @@ static void __init pcibios_allocate_resources(int pass)
u16 command; u16 command;
struct resource *r, *pr; struct resource *r, *pr;
while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev), for_each_pci_dev(dev) {
dev != NULL
) {
pci_read_config_word(dev, PCI_COMMAND, &command); pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) { for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx]; r = &dev->resource[idx];
@ -188,9 +186,7 @@ static void __init pcibios_assign_resources(void)
int idx; int idx;
struct resource *r; struct resource *r;
while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev), for_each_pci_dev(dev) {
dev != NULL
) {
int class = dev->class >> 8; int class = dev->class >> 8;
/* Don't touch classless devices and host bridges */ /* Don't touch classless devices and host bridges */

View file

@ -48,9 +48,7 @@ void __init pcibios_fixup_irqs(void)
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
uint8_t line, pin; uint8_t line, pin;
while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev), for_each_pci_dev(dev) {
dev != NULL
) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) { if (pin) {
dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1]; dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];

View file

@ -143,7 +143,7 @@ static int __init scx200_init(void)
{ {
printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n"); printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
return pci_module_init(&scx200_pci_driver); return pci_register_driver(&scx200_pci_driver);
} }
static void __exit scx200_cleanup(void) static void __exit scx200_cleanup(void)

View file

@ -53,7 +53,7 @@ static int __init pci_acpi_init(void)
* don't use pci_enable_device(). * don't use pci_enable_device().
*/ */
printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n"); printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) for_each_pci_dev(dev)
acpi_pci_irq_enable(dev); acpi_pci_irq_enable(dev);
} else } else
printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n");

View file

@ -413,6 +413,13 @@ static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"), DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"),
}, },
}, },
{
.ident = "Toshiba A40 based laptop",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_VERSION, "PSA40U"),
},
},
{ } { }
}; };

View file

@ -78,7 +78,7 @@ static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
for (i=0; i < rt->size; i++) for (i=0; i < rt->size; i++)
sum += addr[i]; sum += addr[i];
if (!sum) { if (!sum) {
DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt); DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt);
return rt; return rt;
} }
return NULL; return NULL;
@ -128,7 +128,7 @@ static void __init pirq_peer_trick(void)
#ifdef DEBUG #ifdef DEBUG
{ {
int j; int j;
DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot); DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
for(j=0; j<4; j++) for(j=0; j<4; j++)
DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap); DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
DBG("\n"); DBG("\n");
@ -160,10 +160,10 @@ void eisa_set_level_irq(unsigned int irq)
return; return;
eisa_irq_mask |= (1 << irq); eisa_irq_mask |= (1 << irq);
printk("PCI: setting IRQ %u as level-triggered\n", irq); printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq);
val = inb(port); val = inb(port);
if (!(val & mask)) { if (!(val & mask)) {
DBG(" -> edge"); DBG(KERN_DEBUG " -> edge");
outb(val | mask, port); outb(val | mask, port);
} }
} }
@ -677,11 +677,11 @@ static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router,
{ {
case PCI_DEVICE_ID_AL_M1533: case PCI_DEVICE_ID_AL_M1533:
case PCI_DEVICE_ID_AL_M1563: case PCI_DEVICE_ID_AL_M1563:
printk("PCI: Using ALI IRQ Router\n"); printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n");
r->name = "ALI"; r->name = "ALI";
r->get = pirq_ali_get; r->get = pirq_ali_get;
r->set = pirq_ali_set; r->set = pirq_ali_set;
return 1; return 1;
} }
return 0; return 0;
} }
@ -749,12 +749,13 @@ static void __init pirq_find_router(struct irq_router *r)
r->get = NULL; r->get = NULL;
r->set = NULL; r->set = NULL;
DBG("PCI: Attempting to find IRQ router for %04x:%04x\n", DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n",
rt->rtr_vendor, rt->rtr_device); rt->rtr_vendor, rt->rtr_device);
pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn); pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
if (!pirq_router_dev) { if (!pirq_router_dev) {
DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); DBG(KERN_DEBUG "PCI: Interrupt router not found at "
"%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
return; return;
} }
@ -799,7 +800,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
/* Find IRQ pin */ /* Find IRQ pin */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) { if (!pin) {
DBG(" -> no interrupt pin\n"); DBG(KERN_DEBUG " -> no interrupt pin\n");
return 0; return 0;
} }
pin = pin - 1; pin = pin - 1;
@ -809,16 +810,16 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
if (!pirq_table) if (!pirq_table)
return 0; return 0;
DBG("IRQ for %s[%c]", pci_name(dev), 'A' + pin); DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin);
info = pirq_get_info(dev); info = pirq_get_info(dev);
if (!info) { if (!info) {
DBG(" -> not found in routing table\n"); DBG(" -> not found in routing table\n" KERN_DEBUG);
return 0; return 0;
} }
pirq = info->irq[pin].link; pirq = info->irq[pin].link;
mask = info->irq[pin].bitmap; mask = info->irq[pin].bitmap;
if (!pirq) { if (!pirq) {
DBG(" -> not routed\n"); DBG(" -> not routed\n" KERN_DEBUG);
return 0; return 0;
} }
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
@ -848,7 +849,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
newirq = dev->irq; newirq = dev->irq;
if (newirq && !((1 << newirq) & mask)) { if (newirq && !((1 << newirq) & mask)) {
if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0; if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, pci_name(dev)); else printk("\n" KERN_WARNING
"PCI: IRQ %i for device %s doesn't match PIRQ mask "
"- try pci=usepirqmask\n" KERN_DEBUG, newirq,
pci_name(dev));
} }
if (!newirq && assign) { if (!newirq && assign) {
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
@ -923,14 +927,14 @@ static void __init pcibios_fixup_irqs(void)
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
u8 pin; u8 pin;
DBG("PCI: IRQ fixup\n"); DBG(KERN_DEBUG "PCI: IRQ fixup\n");
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
/* /*
* If the BIOS has set an out of range IRQ number, just ignore it. * If the BIOS has set an out of range IRQ number, just ignore it.
* Also keep track of which IRQ's are already in use. * Also keep track of which IRQ's are already in use.
*/ */
if (dev->irq >= 16) { if (dev->irq >= 16) {
DBG("%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq); DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq);
dev->irq = 0; dev->irq = 0;
} }
/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
@ -1039,7 +1043,7 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = {
static int __init pcibios_irq_init(void) static int __init pcibios_irq_init(void)
{ {
DBG("PCI: IRQ init\n"); DBG(KERN_DEBUG "PCI: IRQ init\n");
if (pcibios_enable_irq || raw_pci_ops == NULL) if (pcibios_enable_irq || raw_pci_ops == NULL)
return 0; return 0;

View file

@ -561,7 +561,7 @@ static int __devinit vrc4173_init(void)
{ {
int err; int err;
err = pci_module_init(&vrc4173_driver); err = pci_register_driver(&vrc4173_driver);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -503,7 +503,7 @@ pcibios_allocate_resources(int pass)
u16 command; u16 command;
struct resource *r; struct resource *r;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for_each_pci_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command); pci_read_config_word(dev, PCI_COMMAND, &command);
for (idx = 0; idx < 6; idx++) { for (idx = 0; idx < 6; idx++) {
r = &dev->resource[idx]; r = &dev->resource[idx];
@ -540,7 +540,7 @@ pcibios_assign_resources(void)
int idx; int idx;
struct resource *r; struct resource *r;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for_each_pci_dev(dev) {
int class = dev->class >> 8; int class = dev->class >> 8;
/* Don't touch classless devices and host bridges */ /* Don't touch classless devices and host bridges */
@ -867,14 +867,15 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
*/ */
if (!pci_to_OF_bus_map) if (!pci_to_OF_bus_map)
return 0; return 0;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (pci_to_OF_bus_map[dev->bus->number] != *bus) for_each_pci_dev(dev)
continue; if (pci_to_OF_bus_map[dev->bus->number] == *bus &&
if (dev->devfn != *devfn) dev->devfn == *devfn) {
continue; *bus = dev->bus->number;
*bus = dev->bus->number; pci_dev_put(dev);
return 0; return 0;
} }
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL(pci_device_from_OF_node); EXPORT_SYMBOL(pci_device_from_OF_node);

View file

@ -351,10 +351,10 @@ mpc85xx_cds_fixup_via(struct pci_controller *hose)
void __init void __init
mpc85xx_cds_pcibios_fixup(void) mpc85xx_cds_pcibios_fixup(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev;
u_char c; u_char c;
if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_1, NULL))) { PCI_DEVICE_ID_VIA_82C586_1, NULL))) {
/* /*
* U-Boot does not set the enable bits * U-Boot does not set the enable bits
@ -371,21 +371,24 @@ mpc85xx_cds_pcibios_fixup(void)
*/ */
dev->irq = 14; dev->irq = 14;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
pci_dev_put(dev);
} }
/* /*
* Force legacy USB interrupt routing * Force legacy USB interrupt routing
*/ */
if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_2, NULL))) { PCI_DEVICE_ID_VIA_82C586_2, NULL))) {
dev->irq = 10; dev->irq = 10;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10);
pci_dev_put(dev);
} }
if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_2, dev))) { PCI_DEVICE_ID_VIA_82C586_2, dev))) {
dev->irq = 11; dev->irq = 11;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
pci_dev_put(dev);
} }
} }
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */

View file

@ -527,18 +527,12 @@ static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
{ {
struct pci_dev *pdev = start; struct pci_dev *pdev = start;
do { while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev)))
pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev); if (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
if (pdev && pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)
(pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
break; break;
} while (pdev != NULL);
if (pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)) *is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS));
*is_rio_p = 1;
else
*is_rio_p = 0;
return pdev; return pdev;
} }
@ -637,6 +631,7 @@ void __init ebus_init(void)
ebus->is_rio = is_rio; ebus->is_rio = is_rio;
++num_ebus; ++num_ebus;
} }
pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
#ifdef CONFIG_SUN_AUXIO #ifdef CONFIG_SUN_AUXIO
auxio_probe(); auxio_probe();

View file

@ -361,8 +361,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,
if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
/* PC card has the same IRQ as its cardbridge */ /* PC card has the same IRQ as its cardbridge */
pci_read_config_byte(bridge, PCI_INTERRUPT_PIN, bridge_pin = bridge->pin;
&bridge_pin);
if (!bridge_pin) { if (!bridge_pin) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No interrupt pin configured for device %s\n", "No interrupt pin configured for device %s\n",
@ -412,7 +411,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
if (!dev) if (!dev)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pin = dev->pin;
if (!pin) { if (!pin) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No interrupt pin configured for device %s\n", "No interrupt pin configured for device %s\n",
@ -503,7 +502,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
if (!dev || !dev->bus) if (!dev || !dev->bus)
return_VOID; return_VOID;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pin = dev->pin;
if (!pin) if (!pin)
return_VOID; return_VOID;
pin--; pin--;

View file

@ -7179,7 +7179,7 @@ static int DAC960_init_module(void)
{ {
int ret; int ret;
ret = pci_module_init(&DAC960_pci_driver); ret = pci_register_driver(&DAC960_pci_driver);
#ifdef DAC960_GAM_MINOR #ifdef DAC960_GAM_MINOR
if (!ret) if (!ret)
DAC960_gam_init(); DAC960_gam_init();

View file

@ -3360,7 +3360,7 @@ static int __init cciss_init(void)
printk(KERN_INFO DRIVER_NAME "\n"); printk(KERN_INFO DRIVER_NAME "\n");
/* Register for our PCI devices */ /* Register for our PCI devices */
return pci_module_init(&cciss_pci_driver); return pci_register_driver(&cciss_pci_driver);
} }
static void __exit cciss_cleanup(void) static void __exit cciss_cleanup(void)

View file

@ -1755,7 +1755,7 @@ static void carm_remove_one (struct pci_dev *pdev)
static int __init carm_init(void) static int __init carm_init(void)
{ {
return pci_module_init(&carm_driver); return pci_register_driver(&carm_driver);
} }
static void __exit carm_exit(void) static void __exit carm_exit(void)

View file

@ -1174,7 +1174,7 @@ static int __init mm_init(void)
printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
retval = pci_module_init(&mm_pci_driver); retval = pci_register_driver(&mm_pci_driver);
if (retval) if (retval)
return -ENOMEM; return -ENOMEM;

View file

@ -841,7 +841,7 @@ static int __devinit vt8231_pci_probe(struct pci_dev *dev,
static int __init sm_vt8231_init(void) static int __init sm_vt8231_init(void)
{ {
return pci_module_init(&vt8231_pci_driver); return pci_register_driver(&vt8231_pci_driver);
} }
static void __exit sm_vt8231_exit(void) static void __exit sm_vt8231_exit(void)

View file

@ -395,7 +395,7 @@ static struct pci_driver gemtek_pci_driver =
static int __init gemtek_pci_init_module( void ) static int __init gemtek_pci_init_module( void )
{ {
return pci_module_init( &gemtek_pci_driver ); return pci_register_driver( &gemtek_pci_driver );
} }
static void __exit gemtek_pci_cleanup_module( void ) static void __exit gemtek_pci_cleanup_module( void )

View file

@ -338,7 +338,7 @@ static struct pci_driver maxiradio_driver = {
static int __init maxiradio_radio_init(void) static int __init maxiradio_radio_init(void)
{ {
return pci_module_init(&maxiradio_driver); return pci_register_driver(&maxiradio_driver);
} }
static void __exit maxiradio_radio_exit(void) static void __exit maxiradio_radio_exit(void)

View file

@ -464,7 +464,7 @@ static struct pci_driver parport_serial_pci_driver = {
static int __init parport_serial_init (void) static int __init parport_serial_init (void)
{ {
return pci_module_init (&parport_serial_pci_driver); return pci_register_driver (&parport_serial_pci_driver);
} }
static void __exit parport_serial_exit (void) static void __exit parport_serial_exit (void)

View file

@ -794,12 +794,14 @@ static int enable_device(struct acpiphp_slot *slot)
if (PCI_SLOT(dev->devfn) != slot->device) if (PCI_SLOT(dev->devfn) != slot->device)
continue; continue;
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
max = pci_scan_bridge(bus, dev, max, pass); max = pci_scan_bridge(bus, dev, max, pass);
if (pass && dev->subordinate)
pci_bus_size_bridges(dev->subordinate);
}
} }
} }
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus); acpiphp_sanitize_bus(bus);
pci_enable_bridges(bus); pci_enable_bridges(bus);

View file

@ -317,6 +317,7 @@ struct controller {
u16 vendor_id; u16 vendor_id;
struct work_struct int_task_event; struct work_struct int_task_event;
wait_queue_head_t queue; /* sleep & wake process */ wait_queue_head_t queue; /* sleep & wake process */
struct dentry *dentry; /* debugfs dentry */
}; };
struct irq_mapping { struct irq_mapping {
@ -399,8 +400,11 @@ struct resource_lists {
#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" #define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n"
/* sysfs functions for the hotplug controller info */ /* debugfs functions for the hotplug controller info */
extern void cpqhp_create_ctrl_files (struct controller *ctrl); extern void cpqhp_initialize_debugfs (void);
extern void cpqhp_shutdown_debugfs (void);
extern void cpqhp_create_debugfs_files (struct controller *ctrl);
extern void cpqhp_remove_debugfs_files (struct controller *ctrl);
/* controller functions */ /* controller functions */
extern void cpqhp_pushbutton_thread (unsigned long event_pointer); extern void cpqhp_pushbutton_thread (unsigned long event_pointer);

View file

@ -327,7 +327,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
void __iomem *smbios_start, void __iomem *smbios_start,
void __iomem *smbios_table) void __iomem *smbios_table)
{ {
struct slot *new_slot; struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *hotplug_slot_info;
u8 number_of_slots; u8 number_of_slots;
u8 slot_device; u8 slot_device;
u8 slot_number; u8 slot_number;
@ -345,93 +347,105 @@ static int ctrl_slot_setup(struct controller *ctrl,
slot_number = ctrl->first_slot; slot_number = ctrl->first_slot;
while (number_of_slots) { while (number_of_slots) {
new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); slot = kmalloc(sizeof(*slot), GFP_KERNEL);
if (!new_slot) if (!slot)
goto error; goto error;
memset(new_slot, 0, sizeof(struct slot)); memset(slot, 0, sizeof(struct slot));
new_slot->hotplug_slot = kmalloc(sizeof(*(new_slot->hotplug_slot)), slot->hotplug_slot = kmalloc(sizeof(*(slot->hotplug_slot)),
GFP_KERNEL); GFP_KERNEL);
if (!new_slot->hotplug_slot) if (!slot->hotplug_slot)
goto error_slot; goto error_slot;
memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); hotplug_slot = slot->hotplug_slot;
memset(hotplug_slot, 0, sizeof(struct hotplug_slot));
new_slot->hotplug_slot->info = hotplug_slot->info =
kmalloc(sizeof(*(new_slot->hotplug_slot->info)), kmalloc(sizeof(*(hotplug_slot->info)),
GFP_KERNEL); GFP_KERNEL);
if (!new_slot->hotplug_slot->info) if (!hotplug_slot->info)
goto error_hpslot; goto error_hpslot;
memset(new_slot->hotplug_slot->info, 0, hotplug_slot_info = hotplug_slot->info;
memset(hotplug_slot_info, 0,
sizeof(struct hotplug_slot_info)); sizeof(struct hotplug_slot_info));
new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
if (!new_slot->hotplug_slot->name)
if (!hotplug_slot->name)
goto error_info; goto error_info;
new_slot->ctrl = ctrl; slot->ctrl = ctrl;
new_slot->bus = ctrl->bus; slot->bus = ctrl->bus;
new_slot->device = slot_device; slot->device = slot_device;
new_slot->number = slot_number; slot->number = slot_number;
dbg("slot->number = %d\n",new_slot->number); dbg("slot->number = %d\n", slot->number);
slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9,
slot_entry); slot_entry);
while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) !=
slot->number)) {
slot_entry = get_SMBIOS_entry(smbios_start, slot_entry = get_SMBIOS_entry(smbios_start,
smbios_table, 9, slot_entry); smbios_table, 9, slot_entry);
} }
new_slot->p_sm_slot = slot_entry; slot->p_sm_slot = slot_entry;
init_timer(&new_slot->task_event); init_timer(&slot->task_event);
new_slot->task_event.expires = jiffies + 5 * HZ; slot->task_event.expires = jiffies + 5 * HZ;
new_slot->task_event.function = cpqhp_pushbutton_thread; slot->task_event.function = cpqhp_pushbutton_thread;
//FIXME: these capabilities aren't used but if they are //FIXME: these capabilities aren't used but if they are
// they need to be correctly implemented // they need to be correctly implemented
new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; slot->capabilities |= PCISLOT_REPLACE_SUPPORTED;
new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED;
if (is_slot64bit(new_slot)) if (is_slot64bit(slot))
new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
if (is_slot66mhz(new_slot)) if (is_slot66mhz(slot))
new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
if (ctrl->speed == PCI_SPEED_66MHz) if (ctrl->speed == PCI_SPEED_66MHz)
new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; slot->capabilities |= PCISLOT_66_MHZ_OPERATION;
ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); ctrl_slot =
slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4);
// Check presence // Check presence
new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; slot->capabilities |=
((((~tempdword) >> 23) |
((~tempdword) >> 15)) >> ctrl_slot) & 0x02;
// Check the switch state // Check the switch state
new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; slot->capabilities |=
((~tempdword & 0xFF) >> ctrl_slot) & 0x01;
// Check the slot enable // Check the slot enable
new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; slot->capabilities |=
((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04;
/* register this slot with the hotplug pci core */ /* register this slot with the hotplug pci core */
new_slot->hotplug_slot->release = &release_slot; hotplug_slot->release = &release_slot;
new_slot->hotplug_slot->private = new_slot; hotplug_slot->private = slot;
make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot);
new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); hotplug_slot_info->attention_status =
new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); cpq_get_attention_status(ctrl, slot);
new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); hotplug_slot_info->latch_status =
cpq_get_latch_status(ctrl, slot);
hotplug_slot_info->adapter_status =
get_presence_status(ctrl, slot);
dbg ("registering bus %d, dev %d, number %d, " dbg("registering bus %d, dev %d, number %d, "
"ctrl->slot_device_offset %d, slot %d\n", "ctrl->slot_device_offset %d, slot %d\n",
new_slot->bus, new_slot->device, slot->bus, slot->device,
new_slot->number, ctrl->slot_device_offset, slot->number, ctrl->slot_device_offset,
slot_number); slot_number);
result = pci_hp_register (new_slot->hotplug_slot); result = pci_hp_register(hotplug_slot);
if (result) { if (result) {
err ("pci_hp_register failed with error %d\n", result); err("pci_hp_register failed with error %d\n", result);
goto error_name; goto error_name;
} }
new_slot->next = ctrl->slot; slot->next = ctrl->slot;
ctrl->slot = new_slot; ctrl->slot = slot;
number_of_slots--; number_of_slots--;
slot_device++; slot_device++;
@ -439,15 +453,14 @@ static int ctrl_slot_setup(struct controller *ctrl,
} }
return 0; return 0;
error_name: error_name:
kfree(new_slot->hotplug_slot->name); kfree(hotplug_slot->name);
error_info: error_info:
kfree(new_slot->hotplug_slot->info); kfree(hotplug_slot_info);
error_hpslot: error_hpslot:
kfree(new_slot->hotplug_slot); kfree(hotplug_slot);
error_slot: error_slot:
kfree(new_slot); kfree(slot);
error: error:
return result; return result;
} }
@ -466,6 +479,8 @@ static int ctrl_slot_cleanup (struct controller * ctrl)
old_slot = next_slot; old_slot = next_slot;
} }
cpqhp_remove_debugfs_files(ctrl);
//Free IRQ associated with hot plug device //Free IRQ associated with hot plug device
free_irq(ctrl->interrupt, ctrl); free_irq(ctrl->interrupt, ctrl);
//Unmap the memory //Unmap the memory
@ -1262,7 +1277,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
// Done with exclusive hardware access // Done with exclusive hardware access
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
cpqhp_create_ctrl_files(ctrl); cpqhp_create_debugfs_files(ctrl);
return 0; return 0;
@ -1502,6 +1517,7 @@ static int __init cpqhpc_init(void)
cpqhp_debug = debug; cpqhp_debug = debug;
info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
cpqhp_initialize_debugfs();
result = pci_register_driver(&cpqhpc_driver); result = pci_register_driver(&cpqhpc_driver);
dbg("pci_register_driver = %d\n", result); dbg("pci_register_driver = %d\n", result);
return result; return result;
@ -1515,6 +1531,7 @@ static void __exit cpqhpc_cleanup(void)
dbg("pci_unregister_driver\n"); dbg("pci_unregister_driver\n");
pci_unregister_driver(&cpqhpc_driver); pci_unregister_driver(&cpqhpc_driver);
cpqhp_shutdown_debugfs();
} }

View file

@ -2630,29 +2630,15 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
hold_mem_node = NULL; hold_mem_node = NULL;
} }
/* If we have prefetchable memory resources copy them and memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
* fill in the bridge's memory range registers. Otherwise, p_mem_node->next = NULL;
* fill in the range registers with values that disable them. */
if (p_mem_node) {
memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
p_mem_node->next = NULL;
/* set Pre Mem base and Limit registers */ /* set Pre Mem base and Limit registers */
temp_word = p_mem_node->base >> 16; temp_word = p_mem_node->base >> 16;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
} else {
temp_word = 0xFFFF;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
temp_word = 0x0000;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
kfree(hold_p_mem_node);
hold_p_mem_node = NULL;
}
/* Adjust this to compensate for extra adjustment in first loop */ /* Adjust this to compensate for extra adjustment in first loop */
irqs.barber_pole--; irqs.barber_pole--;

View file

@ -33,22 +33,15 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/debugfs.h>
#include "cpqphp.h" #include "cpqphp.h"
static int show_ctrl (struct controller *ctrl, char *buf)
/* A few routines that create sysfs entries for the hot plug controller */
static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct pci_dev *pci_dev; char *out = buf;
struct controller *ctrl;
char * out = buf;
int index; int index;
struct pci_resource *res; struct pci_resource *res;
pci_dev = container_of (dev, struct pci_dev, dev);
ctrl = pci_get_drvdata(pci_dev);
out += sprintf(buf, "Free resources: memory\n"); out += sprintf(buf, "Free resources: memory\n");
index = 11; index = 11;
res = ctrl->mem_head; res = ctrl->mem_head;
@ -80,22 +73,16 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
return out - buf; return out - buf;
} }
static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) static int show_dev (struct controller *ctrl, char *buf)
{ {
struct pci_dev *pci_dev;
struct controller *ctrl;
char * out = buf; char * out = buf;
int index; int index;
struct pci_resource *res; struct pci_resource *res;
struct pci_func *new_slot; struct pci_func *new_slot;
struct slot *slot; struct slot *slot;
pci_dev = container_of (dev, struct pci_dev, dev); slot = ctrl->slot;
ctrl = pci_get_drvdata(pci_dev);
slot=ctrl->slot;
while (slot) { while (slot) {
new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); new_slot = cpqhp_slot_find(slot->bus, slot->device, 0);
@ -134,10 +121,117 @@ static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char
return out - buf; return out - buf;
} }
static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL);
void cpqhp_create_ctrl_files (struct controller *ctrl) static int spew_debug_info(struct controller *ctrl, char *data, int size)
{ {
device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); int used;
device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev);
used = size - show_ctrl(ctrl, data);
used = (size - used) - show_dev(ctrl, &data[used]);
return used;
} }
struct ctrl_dbg {
int size;
char *data;
struct controller *ctrl;
};
#define MAX_OUTPUT (4*PAGE_SIZE)
static int open(struct inode *inode, struct file *file)
{
struct controller *ctrl = inode->u.generic_ip;
struct ctrl_dbg *dbg;
int retval = -ENOMEM;
lock_kernel();
dbg = kmalloc(sizeof(*dbg), GFP_KERNEL);
if (!dbg)
goto exit;
dbg->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
if (!dbg->data) {
kfree(dbg);
goto exit;
}
dbg->size = spew_debug_info(ctrl, dbg->data, MAX_OUTPUT);
file->private_data = dbg;
retval = 0;
exit:
unlock_kernel();
return retval;
}
static loff_t lseek(struct file *file, loff_t off, int whence)
{
struct ctrl_dbg *dbg;
loff_t new = -1;
lock_kernel();
dbg = file->private_data;
switch (whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
}
if (new < 0 || new > dbg->size) {
unlock_kernel();
return -EINVAL;
}
unlock_kernel();
return (file->f_pos = new);
}
static ssize_t read(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
struct ctrl_dbg *dbg = file->private_data;
return simple_read_from_buffer(buf, nbytes, ppos, dbg->data, dbg->size);
}
static int release(struct inode *inode, struct file *file)
{
struct ctrl_dbg *dbg = file->private_data;
kfree(dbg->data);
kfree(dbg);
return 0;
}
static struct file_operations debug_ops = {
.owner = THIS_MODULE,
.open = open,
.llseek = lseek,
.read = read,
.release = release,
};
static struct dentry *root;
void cpqhp_initialize_debugfs(void)
{
if (!root)
root = debugfs_create_dir("cpqhp", NULL);
}
void cpqhp_shutdown_debugfs(void)
{
debugfs_remove(root);
}
void cpqhp_create_debugfs_files(struct controller *ctrl)
{
ctrl->dentry = debugfs_create_file(ctrl->pci_dev->dev.bus_id, S_IRUGO, root, ctrl, &debug_ops);
}
void cpqhp_remove_debugfs_files(struct controller *ctrl)
{
if (ctrl->dentry)
debugfs_remove(ctrl->dentry);
ctrl->dentry = NULL;
}

View file

@ -969,7 +969,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno)
debug ("io 32\n"); debug ("io 32\n");
need_io_upper = TRUE; need_io_upper = TRUE;
} }
if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { if ((pfmem_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
debug ("pfmem 64\n"); debug ("pfmem 64\n");
need_pfmem_upper = TRUE; need_pfmem_upper = TRUE;
} }

View file

@ -103,7 +103,10 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
static int init_slots(struct controller *ctrl) static int init_slots(struct controller *ctrl)
{ {
struct slot *new_slot; struct slot *slot;
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *hotplug_slot_info;
u8 number_of_slots; u8 number_of_slots;
u8 slot_device; u8 slot_device;
u32 slot_number; u32 slot_number;
@ -114,59 +117,66 @@ static int init_slots(struct controller *ctrl)
slot_number = ctrl->first_slot; slot_number = ctrl->first_slot;
while (number_of_slots) { while (number_of_slots) {
new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); slot = kmalloc(sizeof(*slot), GFP_KERNEL);
if (!new_slot) if (!slot)
goto error; goto error;
memset(new_slot, 0, sizeof(struct slot)); memset(slot, 0, sizeof(struct slot));
new_slot->hotplug_slot = slot->hotplug_slot =
kmalloc(sizeof(*(new_slot->hotplug_slot)), kmalloc(sizeof(*(slot->hotplug_slot)),
GFP_KERNEL); GFP_KERNEL);
if (!new_slot->hotplug_slot) if (!slot->hotplug_slot)
goto error_slot; goto error_slot;
memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); hotplug_slot = slot->hotplug_slot;
memset(hotplug_slot, 0, sizeof(struct hotplug_slot));
new_slot->hotplug_slot->info = hotplug_slot->info =
kmalloc(sizeof(*(new_slot->hotplug_slot->info)), kmalloc(sizeof(*(hotplug_slot->info)),
GFP_KERNEL); GFP_KERNEL);
if (!new_slot->hotplug_slot->info) if (!hotplug_slot->info)
goto error_hpslot; goto error_hpslot;
memset(new_slot->hotplug_slot->info, 0, hotplug_slot_info = hotplug_slot->info;
memset(hotplug_slot_info, 0,
sizeof(struct hotplug_slot_info)); sizeof(struct hotplug_slot_info));
new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
GFP_KERNEL); if (!hotplug_slot->name)
if (!new_slot->hotplug_slot->name)
goto error_info; goto error_info;
new_slot->ctrl = ctrl; slot->ctrl = ctrl;
new_slot->bus = ctrl->slot_bus; slot->bus = ctrl->slot_bus;
new_slot->device = slot_device; slot->device = slot_device;
new_slot->hpc_ops = ctrl->hpc_ops; slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
new_slot->number = ctrl->first_slot; slot->number = ctrl->first_slot;
new_slot->hp_slot = slot_device - ctrl->slot_device_offset; slot->hp_slot = slot_device - ctrl->slot_device_offset;
/* register this slot with the hotplug pci core */ /* register this slot with the hotplug pci core */
new_slot->hotplug_slot->private = new_slot; hotplug_slot->private = slot;
new_slot->hotplug_slot->release = &release_slot; hotplug_slot->release = &release_slot;
make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops; hotplug_slot->ops = &pciehp_hotplug_slot_ops;
new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status)); hpc_ops->get_power_status(slot,
new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status)); &(hotplug_slot_info->power_status));
new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status)); hpc_ops->get_attention_status(slot,
new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status)); &(hotplug_slot_info->attention_status));
hpc_ops->get_latch_status(slot,
&(hotplug_slot_info->latch_status));
hpc_ops->get_adapter_status(slot,
&(hotplug_slot_info->adapter_status));
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset); "slot_device_offset=%x\n",
result = pci_hp_register (new_slot->hotplug_slot); slot->bus, slot->device, slot->hp_slot, slot->number,
ctrl->slot_device_offset);
result = pci_hp_register(hotplug_slot);
if (result) { if (result) {
err ("pci_hp_register failed with error %d\n", result); err ("pci_hp_register failed with error %d\n", result);
goto error_name; goto error_name;
} }
new_slot->next = ctrl->slot; slot->next = ctrl->slot;
ctrl->slot = new_slot; ctrl->slot = slot;
number_of_slots--; number_of_slots--;
slot_device++; slot_device++;
@ -176,13 +186,13 @@ static int init_slots(struct controller *ctrl)
return 0; return 0;
error_name: error_name:
kfree(new_slot->hotplug_slot->name); kfree(hotplug_slot->name);
error_info: error_info:
kfree(new_slot->hotplug_slot->info); kfree(hotplug_slot_info);
error_hpslot: error_hpslot:
kfree(new_slot->hotplug_slot); kfree(hotplug_slot);
error_slot: error_slot:
kfree(new_slot); kfree(slot);
error: error:
return result; return result;
} }
@ -502,7 +512,7 @@ static void __exit unload_pciehpd(void)
} }
int hpdriver_context = 0; static int hpdriver_context = 0;
static void pciehp_remove (struct pcie_device *device) static void pciehp_remove (struct pcie_device *device)
{ {

View file

@ -787,8 +787,13 @@ static int hpc_power_on_slot(struct slot * slot)
slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
/* Enable detection that we turned off at slot power-off time */
if (!pciehp_poll_mode) if (!pciehp_poll_mode)
slot_cmd = slot_cmd | HP_INTR_ENABLE; slot_cmd = slot_cmd |
PWR_FAULT_DETECT_ENABLE |
MRL_DETECT_ENABLE |
PRSN_DETECT_ENABLE |
HP_INTR_ENABLE;
retval = pcie_write_cmd(slot, slot_cmd); retval = pcie_write_cmd(slot, slot_cmd);
@ -833,8 +838,18 @@ static int hpc_power_off_slot(struct slot * slot)
slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
/*
* If we get MRL or presence detect interrupts now, the isr
* will notice the sticky power-fault bit too and issue power
* indicator change commands. This will lead to an endless loop
* of command completions, since the power-fault bit remains on
* till the slot is powered on again.
*/
if (!pciehp_poll_mode) if (!pciehp_poll_mode)
slot_cmd = slot_cmd | HP_INTR_ENABLE; slot_cmd = (slot_cmd &
~PWR_FAULT_DETECT_ENABLE &
~MRL_DETECT_ENABLE &
~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
retval = pcie_write_cmd(slot, slot_cmd); retval = pcie_write_cmd(slot, slot_cmd);

View file

@ -34,6 +34,31 @@
#include "../pci.h" #include "../pci.h"
#include "pciehp.h" #include "pciehp.h"
static int pciehp_add_bridge(struct pci_dev *dev)
{
struct pci_bus *parent = dev->bus;
int pass, busnr, start = parent->secondary;
int end = parent->subordinate;
for (busnr = start; busnr <= end; busnr++) {
if (!pci_find_bus(pci_domain_nr(parent), busnr))
break;
}
if (busnr-- > end) {
err("No bus number available for hot-added bridge %s\n",
pci_name(dev));
return -1;
}
for (pass = 0; pass < 2; pass++)
busnr = pci_scan_bridge(parent, dev, busnr, pass);
if (!dev->subordinate)
return -1;
pci_bus_size_bridges(dev->subordinate);
pci_bus_assign_resources(parent);
pci_enable_bridges(parent);
pci_bus_add_devices(parent);
return 0;
}
int pciehp_configure_device(struct slot *p_slot) int pciehp_configure_device(struct slot *p_slot)
{ {
@ -55,8 +80,8 @@ int pciehp_configure_device(struct slot *p_slot)
} }
for (fn = 0; fn < 8; fn++) { for (fn = 0; fn < 8; fn++) {
if (!(dev = pci_find_slot(p_slot->bus, dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
PCI_DEVFN(p_slot->device, fn)))) if (!dev)
continue; continue;
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
err("Cannot hot-add display device %s\n", err("Cannot hot-add display device %s\n",
@ -65,27 +90,7 @@ int pciehp_configure_device(struct slot *p_slot)
} }
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
/* Find an unused bus number for the new bridge */ pciehp_add_bridge(dev);
struct pci_bus *child;
unsigned char busnr, start = parent->secondary;
unsigned char end = parent->subordinate;
for (busnr = start; busnr <= end; busnr++) {
if (!pci_find_bus(pci_domain_nr(parent),
busnr))
break;
}
if (busnr >= end) {
err("No free bus for hot-added bridge\n");
continue;
}
child = pci_add_new_bus(parent, dev, busnr);
if (!child) {
err("Cannot add new bus for %s\n",
pci_name(dev));
continue;
}
child->subordinate = pci_do_scan_bus(child);
pci_bus_size_bridges(child);
} }
/* TBD: program firmware provided _HPP values */ /* TBD: program firmware provided _HPP values */
/* program_fw_provided_values(dev); */ /* program_fw_provided_values(dev); */
@ -93,7 +98,6 @@ int pciehp_configure_device(struct slot *p_slot)
pci_bus_assign_resources(parent); pci_bus_assign_resources(parent);
pci_bus_add_devices(parent); pci_bus_add_devices(parent);
pci_enable_bridges(parent);
return 0; return 0;
} }

View file

@ -174,7 +174,9 @@ int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
acpi_status status; acpi_status status;
acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
struct pci_dev *pdev = dev; struct pci_dev *pdev = dev;
struct pci_bus *parent;
u8 *path_name; u8 *path_name;
/* /*
* Per PCI firmware specification, we should run the ACPI _OSC * Per PCI firmware specification, we should run the ACPI _OSC
* method to get control of hotplug hardware before using it. * method to get control of hotplug hardware before using it.
@ -190,17 +192,18 @@ int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
*/ */
if (!pdev || !pdev->bus->parent) if (!pdev || !pdev->bus->parent)
break; break;
parent = pdev->bus->parent;
dbg("Could not find %s in acpi namespace, trying parent\n", dbg("Could not find %s in acpi namespace, trying parent\n",
pci_name(pdev)); pci_name(pdev));
if (!pdev->bus->parent->self) if (!parent->self)
/* Parent must be a host bridge */ /* Parent must be a host bridge */
handle = acpi_get_pci_rootbridge_handle( handle = acpi_get_pci_rootbridge_handle(
pci_domain_nr(pdev->bus->parent), pci_domain_nr(parent),
pdev->bus->parent->number); parent->number);
else else
handle = DEVICE_ACPI_HANDLE( handle = DEVICE_ACPI_HANDLE(
&(pdev->bus->parent->self->dev)); &(parent->self->dev));
pdev = pdev->bus->parent->self; pdev = parent->self;
} }
while (handle) { while (handle) {

View file

@ -112,28 +112,6 @@ static struct slot *find_slot(struct device_node *dn)
return NULL; return NULL;
} }
static void rpadlpar_claim_one_bus(struct pci_bus *b)
{
struct list_head *ld;
struct pci_bus *child_bus;
for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
struct pci_dev *dev = pci_dev_b(ld);
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
if (r->parent || !r->start || !r->flags)
continue;
rpaphp_claim_resource(dev, i);
}
}
list_for_each_entry(child_bus, &b->children, node)
rpadlpar_claim_one_bus(child_bus);
}
static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
struct device_node *dev_dn) struct device_node *dev_dn)
{ {
@ -154,7 +132,8 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
struct pci_controller *phb = pdn->phb; struct pci_controller *phb = pdn->phb;
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
rpaphp_eeh_init_nodes(dn); eeh_add_device_tree_early(dn);
/* Add EADS device to PHB bus, adding new entry to bus->devices */ /* Add EADS device to PHB bus, adding new entry to bus->devices */
dev = of_create_pci_dev(dn, phb->bus, pdn->devfn); dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
if (!dev) { if (!dev) {
@ -170,7 +149,7 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
rpaphp_init_new_devs(dev->subordinate); rpaphp_init_new_devs(dev->subordinate);
/* Claim new bus resources */ /* Claim new bus resources */
rpadlpar_claim_one_bus(dev->bus); pcibios_claim_one_bus(dev->bus);
/* ioremap() for child bus, which may or may not succeed */ /* ioremap() for child bus, which may or may not succeed */
(void) remap_bus_range(dev->bus); (void) remap_bus_range(dev->bus);

View file

@ -62,28 +62,6 @@ struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
} }
EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus); EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus);
int rpaphp_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root = pci_find_parent_resource(dev, res);
char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
int err = -EINVAL;
if (root != NULL) {
err = request_resource(root, res);
}
if (err) {
err("PCI: %s region %d of %s %s [%lx:%lx]\n",
root ? "Address space collision on" :
"No parent found for",
resource, dtype, pci_name(dev), res->start, res->end);
}
return err;
}
EXPORT_SYMBOL_GPL(rpaphp_claim_resource);
static int rpaphp_get_sensor_state(struct slot *slot, int *state) static int rpaphp_get_sensor_state(struct slot *slot, int *state)
{ {
int rc; int rc;
@ -177,7 +155,7 @@ void rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
if (r->parent || !r->start || !r->flags) if (r->parent || !r->start || !r->flags)
continue; continue;
rpaphp_claim_resource(dev, i); pci_claim_resource(dev, i);
} }
} }
} }
@ -287,18 +265,6 @@ rpaphp_pci_config_slot(struct pci_bus *bus)
return dev; return dev;
} }
void rpaphp_eeh_init_nodes(struct device_node *dn)
{
struct device_node *sib;
for (sib = dn->child; sib; sib = sib->sibling)
rpaphp_eeh_init_nodes(sib);
eeh_add_device_early(dn);
return;
}
EXPORT_SYMBOL_GPL(rpaphp_eeh_init_nodes);
static void print_slot_pci_funcs(struct pci_bus *bus) static void print_slot_pci_funcs(struct pci_bus *bus)
{ {
struct device_node *dn; struct device_node *dn;
@ -324,7 +290,7 @@ int rpaphp_config_pci_adapter(struct pci_bus *bus)
if (!dn) if (!dn)
goto exit; goto exit;
rpaphp_eeh_init_nodes(dn); eeh_add_device_tree_early(dn);
dev = rpaphp_pci_config_slot(bus); dev = rpaphp_pci_config_slot(bus);
if (!dev) { if (!dev) {
err("%s: can't find any devices.\n", __FUNCTION__); err("%s: can't find any devices.\n", __FUNCTION__);
@ -370,13 +336,14 @@ EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter);
static int setup_pci_hotplug_slot_info(struct slot *slot) static int setup_pci_hotplug_slot_info(struct slot *slot)
{ {
struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
__FUNCTION__); __FUNCTION__);
rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status); rpaphp_get_power_status(slot, &hotplug_slot_info->power_status);
rpaphp_get_pci_adapter_status(slot, 1, rpaphp_get_pci_adapter_status(slot, 1,
&slot->hotplug_slot->info-> &hotplug_slot_info->adapter_status);
adapter_status); if (hotplug_slot_info->adapter_status == NOT_VALID) {
if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
err("%s: NOT_VALID: skip dn->full_name=%s\n", err("%s: NOT_VALID: skip dn->full_name=%s\n",
__FUNCTION__, slot->dn->full_name); __FUNCTION__, slot->dn->full_name);
return -EINVAL; return -EINVAL;

View file

@ -98,6 +98,10 @@ struct controller {
enum pci_bus_speed speed; enum pci_bus_speed speed;
u32 first_slot; /* First physical slot number */ u32 first_slot; /* First physical slot number */
u8 slot_bus; /* Bus where the slots handled by this controller sit */ u8 slot_bus; /* Bus where the slots handled by this controller sit */
u32 cap_offset;
unsigned long mmio_base;
unsigned long mmio_size;
volatile int cmd_busy;
}; };
struct hotplug_params { struct hotplug_params {

View file

@ -65,6 +65,7 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
static int get_address (struct hotplug_slot *slot, u32 *value);
static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
@ -77,6 +78,7 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
.get_attention_status = get_attention_status, .get_attention_status = get_attention_status,
.get_latch_status = get_latch_status, .get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status, .get_adapter_status = get_adapter_status,
.get_address = get_address,
.get_max_bus_speed = get_max_bus_speed, .get_max_bus_speed = get_max_bus_speed,
.get_cur_bus_speed = get_cur_bus_speed, .get_cur_bus_speed = get_cur_bus_speed,
}; };
@ -314,6 +316,18 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
return 0; return 0;
} }
static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
{
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
*value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
return 0;
}
static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{ {
struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
@ -377,8 +391,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_ctrl; goto err_out_free_ctrl;
} }
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
pci_set_drvdata(pdev, ctrl); pci_set_drvdata(pdev, ctrl);
ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);

View file

@ -248,7 +248,6 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
@ -330,9 +329,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return -1; return -1;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
rc = p_slot->hpc_ops->check_cmd_status(ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl);
if (rc) { if (rc) {
@ -352,7 +348,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
@ -367,7 +362,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
@ -494,7 +488,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
wait_for_ctrl_irq (ctrl);
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
@ -532,9 +525,6 @@ static int board_added(struct slot *p_slot)
p_slot->hpc_ops->green_led_on(p_slot); p_slot->hpc_ops->green_led_on(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
@ -552,8 +542,6 @@ static int board_added(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
rc = p_slot->hpc_ops->check_cmd_status(ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl);
if (rc) { if (rc) {
@ -603,8 +591,6 @@ static int remove_board(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
rc = p_slot->hpc_ops->check_cmd_status(ctrl); rc = p_slot->hpc_ops->check_cmd_status(ctrl);
if (rc) { if (rc) {
@ -621,8 +607,6 @@ static int remove_board(struct slot *p_slot)
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
return rc; return rc;
} }
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
@ -676,9 +660,6 @@ static void shpchp_pushbutton_thread (unsigned long slot)
p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
} }
@ -790,14 +771,9 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect); down(&ctrl->crit_sect);
p_slot->hpc_ops->green_led_on(p_slot); p_slot->hpc_ops->green_led_on(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->set_attention_status(p_slot, 0); p_slot->hpc_ops->set_attention_status(p_slot, 0);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
break; break;
@ -806,12 +782,8 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect); down(&ctrl->crit_sect);
p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->set_attention_status(p_slot, 0); p_slot->hpc_ops->set_attention_status(p_slot, 0);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
@ -845,14 +817,9 @@ static void interrupt_event_handler(struct controller *ctrl)
/* blink green LED and turn off amber */ /* blink green LED and turn off amber */
p_slot->hpc_ops->green_led_blink(p_slot); p_slot->hpc_ops->green_led_blink(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->set_attention_status(p_slot, 0); p_slot->hpc_ops->set_attention_status(p_slot, 0);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);
@ -870,12 +837,8 @@ static void interrupt_event_handler(struct controller *ctrl)
down(&ctrl->crit_sect); down(&ctrl->crit_sect);
p_slot->hpc_ops->set_attention_status(p_slot, 1); p_slot->hpc_ops->set_attention_status(p_slot, 1);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->green_led_off(p_slot);
/* Wait for the command to complete */
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */ /* Done with exclusive hardware access */
up(&ctrl->crit_sect); up(&ctrl->crit_sect);

View file

@ -275,6 +275,25 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
return; return;
} }
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) {
retval = -EIO;
err("Command not completed in %d msec\n", timeout_msec);
} else if (rc < 0) {
retval = -EINTR;
info("Command was interrupted by a signal\n");
}
ctrl->cmd_busy = 0;
return retval;
}
static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
@ -314,8 +333,14 @@ 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 /* To make sure the Controller Busy bit is 0 before we send out the
* command. * command.
*/ */
slot->ctrl->cmd_busy = 1;
writew(temp_word, php_ctlr->creg + CMD); writew(temp_word, php_ctlr->creg + CMD);
/*
* Wait for command completion.
*/
retval = shpc_wait_cmd(slot->ctrl);
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return retval; return retval;
} }
@ -604,7 +629,7 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
if (pi == 2) { if (pi == 2) {
*mode = (sec_bus_status & 0x0100) >> 7; *mode = (sec_bus_status & 0x0100) >> 8;
} else { } else {
retval = -1; retval = -1;
} }
@ -791,7 +816,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
} }
if (php_ctlr->pci_dev) { if (php_ctlr->pci_dev) {
iounmap(php_ctlr->creg); iounmap(php_ctlr->creg);
release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
php_ctlr->pci_dev = NULL; php_ctlr->pci_dev = NULL;
} }
@ -1058,12 +1083,13 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
if (intr_loc & 0x0001) { if (intr_loc & 0x0001) {
/* /*
* Command Complete Interrupt Pending * Command Complete Interrupt Pending
* RO only - clear by writing 0 to the Command Completion * RO only - clear by writing 1 to the Command Completion
* Detect bit in Controller SERR-INT register * Detect bit in Controller SERR-INT register
*/ */
temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
temp_dword &= 0xfffeffff; temp_dword &= 0xfffdffff;
writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue); wake_up_interruptible(&ctrl->queue);
} }
@ -1121,7 +1147,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
int retval = 0; int retval = 0;
u8 pi; u8 pi;
u32 slot_avail1, slot_avail2; u32 slot_avail1, slot_avail2;
int slot_num;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
@ -1140,39 +1165,39 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2);
if (pi == 2) { if (pi == 2) {
if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_533) >> 27) ) != 0 ) if (slot_avail2 & SLOT_133MHZ_PCIX_533)
bus_speed = PCIX_133MHZ_533; bus_speed = PCIX_133MHZ_533;
else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_533) >> 23) ) != 0 ) else if (slot_avail2 & SLOT_100MHZ_PCIX_533)
bus_speed = PCIX_100MHZ_533; bus_speed = PCIX_100MHZ_533;
else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_533) >> 19) ) != 0 ) else if (slot_avail2 & SLOT_66MHZ_PCIX_533)
bus_speed = PCIX_66MHZ_533; bus_speed = PCIX_66MHZ_533;
else if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_266) >> 15) ) != 0 ) else if (slot_avail2 & SLOT_133MHZ_PCIX_266)
bus_speed = PCIX_133MHZ_266; bus_speed = PCIX_133MHZ_266;
else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_266) >> 11) ) != 0 ) else if (slot_avail2 & SLOT_100MHZ_PCIX_266)
bus_speed = PCIX_100MHZ_266; bus_speed = PCIX_100MHZ_266;
else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_266) >> 7) ) != 0 ) else if (slot_avail2 & SLOT_66MHZ_PCIX_266)
bus_speed = PCIX_66MHZ_266; bus_speed = PCIX_66MHZ_266;
else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) else if (slot_avail1 & SLOT_133MHZ_PCIX)
bus_speed = PCIX_133MHZ; bus_speed = PCIX_133MHZ;
else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) else if (slot_avail1 & SLOT_100MHZ_PCIX)
bus_speed = PCIX_100MHZ; bus_speed = PCIX_100MHZ;
else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) else if (slot_avail1 & SLOT_66MHZ_PCIX)
bus_speed = PCIX_66MHZ; bus_speed = PCIX_66MHZ;
else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) else if (slot_avail2 & SLOT_66MHZ)
bus_speed = PCI_66MHZ; bus_speed = PCI_66MHZ;
else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) else if (slot_avail1 & SLOT_33MHZ)
bus_speed = PCI_33MHZ; bus_speed = PCI_33MHZ;
else bus_speed = PCI_SPEED_UNKNOWN; else bus_speed = PCI_SPEED_UNKNOWN;
} else { } else {
if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) if (slot_avail1 & SLOT_133MHZ_PCIX)
bus_speed = PCIX_133MHZ; bus_speed = PCIX_133MHZ;
else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) else if (slot_avail1 & SLOT_100MHZ_PCIX)
bus_speed = PCIX_100MHZ; bus_speed = PCIX_100MHZ;
else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) else if (slot_avail1 & SLOT_66MHZ_PCIX)
bus_speed = PCIX_66MHZ; bus_speed = PCIX_66MHZ;
else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) else if (slot_avail2 & SLOT_66MHZ)
bus_speed = PCI_66MHZ; bus_speed = PCI_66MHZ;
else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) else if (slot_avail1 & SLOT_33MHZ)
bus_speed = PCI_33MHZ; bus_speed = PCI_33MHZ;
else bus_speed = PCI_SPEED_UNKNOWN; else bus_speed = PCI_SPEED_UNKNOWN;
} }
@ -1321,19 +1346,34 @@ static struct hpc_ops shpchp_hpc_ops = {
.check_cmd_status = hpc_check_cmd_status, .check_cmd_status = hpc_check_cmd_status,
}; };
inline static int shpc_indirect_creg_read(struct controller *ctrl, int index,
u32 *value)
{
int rc;
u32 cap_offset = ctrl->cap_offset;
struct pci_dev *pdev = ctrl->pci_dev;
rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);
if (rc)
return rc;
return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);
}
int shpc_init(struct controller * ctrl, struct pci_dev * pdev) int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
{ {
struct php_ctlr_state_s *php_ctlr, *p; struct php_ctlr_state_s *php_ctlr, *p;
void *instance_id = ctrl; void *instance_id = ctrl;
int rc; int rc, num_slots = 0;
u8 hp_slot; u8 hp_slot;
static int first = 1; static int first = 1;
u32 shpc_cap_offset, shpc_base_offset; u32 shpc_base_offset;
u32 tempdword, slot_reg; u32 tempdword, slot_reg;
u8 i; u8 i;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
spin_lock_init(&list_lock); spin_lock_init(&list_lock);
php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
@ -1348,41 +1388,45 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
PCI_DEVICE_ID_AMD_GOLAM_7450)) { PCI_DEVICE_ID_AMD_GOLAM_7450)) {
shpc_base_offset = 0; /* amd shpc driver doesn't use this; assume 0 */ /* amd shpc driver doesn't use Base Offset; assume 0 */
ctrl->mmio_base = pci_resource_start(pdev, 0);
ctrl->mmio_size = pci_resource_len(pdev, 0);
} else { } else {
if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) { ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
err("%s : shpc_cap_offset == 0\n", __FUNCTION__); if (!ctrl->cap_offset) {
err("%s : cap_offset == 0\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_ctlr;
} }
dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset); dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET); rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset);
if (rc) { if (rc) {
err("%s : pci_word_config_byte failed\n", __FUNCTION__); err("%s: cannot read base_offset\n", __FUNCTION__);
goto abort_free_ctlr;
}
rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset);
if (rc) {
err("%s : pci_read_config_dword failed\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_ctlr;
} }
for (i = 0; i <= 14; i++) { rc = shpc_indirect_creg_read(ctrl, 3, &tempdword);
rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , i); if (rc) {
err("%s: cannot read slot config\n", __FUNCTION__);
goto abort_free_ctlr;
}
num_slots = tempdword & SLOT_NUM;
dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
for (i = 0; i < 9 + num_slots; i++) {
rc = shpc_indirect_creg_read(ctrl, i, &tempdword);
if (rc) { if (rc) {
err("%s : pci_word_config_byte failed\n", __FUNCTION__); err("%s: cannot read creg (index = %d)\n",
goto abort_free_ctlr; __FUNCTION__, i);
}
rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword);
if (rc) {
err("%s : pci_read_config_dword failed\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_ctlr;
} }
dbg("%s: offset %d: value %x\n", __FUNCTION__,i, dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
tempdword); tempdword);
} }
ctrl->mmio_base =
pci_resource_start(pdev, 0) + shpc_base_offset;
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
} }
if (first) { if (first) {
@ -1396,16 +1440,16 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
if (pci_enable_device(pdev)) if (pci_enable_device(pdev))
goto abort_free_ctlr; goto abort_free_ctlr;
if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) { if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
err("%s: cannot reserve MMIO region\n", __FUNCTION__); err("%s: cannot reserve MMIO region\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_ctlr;
} }
php_ctlr->creg = ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
if (!php_ctlr->creg) { if (!php_ctlr->creg) {
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
pci_resource_start(pdev, 0) + shpc_base_offset); ctrl->mmio_size, ctrl->mmio_base);
release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
goto abort_free_ctlr; goto abort_free_ctlr;
} }
dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);

View file

@ -89,10 +89,11 @@ int shpchp_configure_device(struct slot *p_slot)
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
int num, fn; int num, fn;
dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (dev) { if (dev) {
err("Device %s already exists at %x:%x, cannot hot-add\n", err("Device %s already exists at %x:%x, cannot hot-add\n",
pci_name(dev), p_slot->bus, p_slot->device); pci_name(dev), p_slot->bus, p_slot->device);
pci_dev_put(dev);
return -EINVAL; return -EINVAL;
} }
@ -103,12 +104,13 @@ int shpchp_configure_device(struct slot *p_slot)
} }
for (fn = 0; fn < 8; fn++) { for (fn = 0; fn < 8; fn++) {
if (!(dev = pci_find_slot(p_slot->bus, dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
PCI_DEVFN(p_slot->device, fn)))) if (!dev)
continue; continue;
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
err("Cannot hot-add display device %s\n", err("Cannot hot-add display device %s\n",
pci_name(dev)); pci_name(dev));
pci_dev_put(dev);
continue; continue;
} }
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
@ -124,18 +126,21 @@ int shpchp_configure_device(struct slot *p_slot)
} }
if (busnr >= end) { if (busnr >= end) {
err("No free bus for hot-added bridge\n"); err("No free bus for hot-added bridge\n");
pci_dev_put(dev);
continue; continue;
} }
child = pci_add_new_bus(parent, dev, busnr); child = pci_add_new_bus(parent, dev, busnr);
if (!child) { if (!child) {
err("Cannot add new bus for %s\n", err("Cannot add new bus for %s\n",
pci_name(dev)); pci_name(dev));
pci_dev_put(dev);
continue; continue;
} }
child->subordinate = pci_do_scan_bus(child); child->subordinate = pci_do_scan_bus(child);
pci_bus_size_bridges(child); pci_bus_size_bridges(child);
} }
program_fw_provided_values(dev); program_fw_provided_values(dev);
pci_dev_put(dev);
} }
pci_bus_assign_resources(parent); pci_bus_assign_resources(parent);
@ -149,17 +154,19 @@ int shpchp_unconfigure_device(struct slot *p_slot)
int rc = 0; int rc = 0;
int j; int j;
u8 bctl = 0; u8 bctl = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device);
for (j=0; j<8 ; j++) { for (j=0; j<8 ; j++) {
struct pci_dev* temp = pci_find_slot(p_slot->bus, struct pci_dev* temp = pci_get_slot(parent,
(p_slot->device << 3) | j); (p_slot->device << 3) | j);
if (!temp) if (!temp)
continue; continue;
if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
err("Cannot remove display device %s\n", err("Cannot remove display device %s\n",
pci_name(temp)); pci_name(temp));
pci_dev_put(temp);
continue; continue;
} }
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
@ -167,10 +174,12 @@ int shpchp_unconfigure_device(struct slot *p_slot)
if (bctl & PCI_BRIDGE_CTL_VGA) { if (bctl & PCI_BRIDGE_CTL_VGA) {
err("Cannot remove display device %s\n", err("Cannot remove display device %s\n",
pci_name(temp)); pci_name(temp));
pci_dev_put(temp);
continue; continue;
} }
} }
pci_remove_bus_device(temp); pci_remove_bus_device(temp);
pci_dev_put(temp);
} }
return rc; return rc;
} }

View file

@ -19,6 +19,7 @@
#include <asm/dma.h> /* isa_dma_bridge_buggy */ #include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h" #include "pci.h"
#if 0
/** /**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
@ -63,6 +64,8 @@ pci_max_busnr(void)
return max; return max;
} }
#endif /* 0 */
static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
{ {
u8 id; u8 id;
@ -587,7 +590,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{ {
u8 pin; u8 pin;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pin = dev->pin;
if (!pin) if (!pin)
return -1; return -1;
pin--; pin--;
@ -917,8 +920,6 @@ EXPORT_SYMBOL_GPL(pci_restore_bars);
EXPORT_SYMBOL(pci_enable_device_bars); EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_max_busnr);
EXPORT_SYMBOL(pci_bus_max_busnr);
EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability); EXPORT_SYMBOL(pci_bus_find_capability);
EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_release_regions);

View file

@ -26,20 +26,15 @@ extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern int pci_proc_attach_device(struct pci_dev *dev); extern int pci_proc_attach_device(struct pci_dev *dev);
extern int pci_proc_detach_device(struct pci_dev *dev); extern int pci_proc_detach_device(struct pci_dev *dev);
extern int pci_proc_attach_bus(struct pci_bus *bus);
extern int pci_proc_detach_bus(struct pci_bus *bus); extern int pci_proc_detach_bus(struct pci_bus *bus);
#else #else
static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; } static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; }
static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; } static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; }
static inline int pci_proc_attach_bus(struct pci_bus *bus) { return 0; }
static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
#endif #endif
/* Functions for PCI Hotplug drivers to use */ /* Functions for PCI Hotplug drivers to use */
extern unsigned int pci_do_scan_bus(struct pci_bus *bus); extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
extern int pci_remove_device_safe(struct pci_dev *dev);
extern unsigned char pci_max_busnr(void);
extern unsigned char pci_bus_max_busnr(struct pci_bus *bus);
extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
extern void pci_remove_legacy_files(struct pci_bus *bus); extern void pci_remove_legacy_files(struct pci_bus *bus);

View file

@ -238,8 +238,8 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
device->driver = NULL; device->driver = NULL;
device->driver_data = NULL; device->driver_data = NULL;
device->release = release_pcie_device; /* callback to free pcie dev */ device->release = release_pcie_device; /* callback to free pcie dev */
sprintf(&device->bus_id[0], "pcie%02x", snprintf(device->bus_id, sizeof(device->bus_id), "%s:pcie%02x",
get_descriptor_id(port_type, service_type)); pci_name(parent), get_descriptor_id(port_type, service_type));
device->parent = &parent->dev; device->parent = &parent->dev;
} }

View file

@ -264,8 +264,10 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
if (base <= limit) { if (base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
res->start = base; if (!res->start)
res->end = limit + 0xfff; res->start = base;
if (!res->end)
res->end = limit + 0xfff;
} }
res = child->resource[1]; res = child->resource[1];
@ -431,7 +433,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
{ {
struct pci_bus *child; struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
u32 buses, i; u32 buses, i, j = 0;
u16 bctl; u16 bctl;
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
@ -541,10 +543,29 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
* as cards with a PCI-to-PCI bridge can be * as cards with a PCI-to-PCI bridge can be
* inserted later. * inserted later.
*/ */
for (i=0; i<CARDBUS_RESERVE_BUSNR; i++) for (i=0; i<CARDBUS_RESERVE_BUSNR; i++) {
struct pci_bus *parent = bus;
if (pci_find_bus(pci_domain_nr(bus), if (pci_find_bus(pci_domain_nr(bus),
max+i+1)) max+i+1))
break; break;
while (parent->parent) {
if ((!pcibios_assign_all_busses()) &&
(parent->subordinate > max) &&
(parent->subordinate <= max+i)) {
j = 1;
}
parent = parent->parent;
}
if (j) {
/*
* Often, there are two cardbus bridges
* -- try to leave one valid bus number
* for each one.
*/
i /= 2;
break;
}
}
max += i; max += i;
pci_fixup_parent_subordinate_busnr(child, max); pci_fixup_parent_subordinate_busnr(child, max);
} }
@ -559,6 +580,22 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number); sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
while (bus->parent) {
if ((child->subordinate > bus->subordinate) ||
(child->number > bus->subordinate) ||
(child->number < bus->number) ||
(child->subordinate < bus->number)) {
printk(KERN_WARNING "PCI: Bus #%02x (-#%02x) may be "
"hidden behind%s bridge #%02x (-#%02x)%s\n",
child->number, child->subordinate,
bus->self->transparent ? " transparent" : " ",
bus->number, bus->subordinate,
pcibios_assign_all_busses() ? " " :
" (try 'pci=assign-busses')");
}
bus = bus->parent;
}
return max; return max;
} }
@ -571,6 +608,7 @@ static void pci_read_irq(struct pci_dev *dev)
unsigned char irq; unsigned char irq;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
dev->pin = irq;
if (irq) if (irq)
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq; dev->irq = irq;
@ -624,6 +662,7 @@ static int pci_setup_device(struct pci_dev * dev)
/* The PCI-to-PCI bridge spec requires that subtractive /* The PCI-to-PCI bridge spec requires that subtractive
decoding (i.e. transparent) bridge must have programming decoding (i.e. transparent) bridge must have programming
interface code of 0x01. */ interface code of 0x01. */
pci_read_irq(dev);
dev->transparent = ((dev->class & 0xff) == 1); dev->transparent = ((dev->class & 0xff) == 1);
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
break; break;
@ -678,7 +717,7 @@ static void pci_release_dev(struct device *dev)
* reading the dword at 0x100 which must either be 0 or a valid extended * reading the dword at 0x100 which must either be 0 or a valid extended
* capability header. * capability header.
*/ */
static int pci_cfg_space_size(struct pci_dev *dev) int pci_cfg_space_size(struct pci_dev *dev)
{ {
int pos; int pos;
u32 status; u32 status;

View file

@ -431,6 +431,7 @@ int pci_proc_detach_device(struct pci_dev *dev)
return 0; return 0;
} }
#if 0
int pci_proc_attach_bus(struct pci_bus* bus) int pci_proc_attach_bus(struct pci_bus* bus)
{ {
struct proc_dir_entry *de = bus->procdir; struct proc_dir_entry *de = bus->procdir;
@ -447,6 +448,7 @@ int pci_proc_attach_bus(struct pci_bus* bus)
} }
return 0; return 0;
} }
#endif /* 0 */
int pci_proc_detach_bus(struct pci_bus* bus) int pci_proc_detach_bus(struct pci_bus* bus)
{ {
@ -612,7 +614,6 @@ __initcall(pci_proc_init);
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_proc_attach_device); EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_attach_bus);
EXPORT_SYMBOL(pci_proc_detach_bus); EXPORT_SYMBOL(pci_proc_detach_bus);
#endif #endif

View file

@ -1342,6 +1342,32 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
pci_do_fixups(dev, start, end); pci_do_fixups(dev, start, end);
} }
/* Enable 1k I/O space granularity on the Intel P64H2 */
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
{
u16 en1k;
u8 io_base_lo, io_limit_lo;
unsigned long base, limit;
struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
pci_read_config_word(dev, 0x40, &en1k);
if (en1k & 0x200) {
printk(KERN_INFO "PCI: Enable I/O Space to 1 KB Granularity\n");
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
base = (io_base_lo & (PCI_IO_RANGE_MASK | 0x0c)) << 8;
limit = (io_limit_lo & (PCI_IO_RANGE_MASK | 0x0c)) << 8;
if (base <= limit) {
res->start = base;
res->end = limit + 0x3ff;
}
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io);
EXPORT_SYMBOL(pcie_mch_quirk); EXPORT_SYMBOL(pcie_mch_quirk);
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_fixup_device); EXPORT_SYMBOL(pci_fixup_device);

View file

@ -48,6 +48,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
* in question is not being used by a driver. * in question is not being used by a driver.
* Returns 0 on success. * Returns 0 on success.
*/ */
#if 0
int pci_remove_device_safe(struct pci_dev *dev) int pci_remove_device_safe(struct pci_dev *dev)
{ {
if (pci_dev_driver(dev)) if (pci_dev_driver(dev))
@ -55,7 +56,7 @@ int pci_remove_device_safe(struct pci_dev *dev)
pci_destroy_dev(dev); pci_destroy_dev(dev);
return 0; return 0;
} }
EXPORT_SYMBOL(pci_remove_device_safe); #endif /* 0 */
void pci_remove_bus(struct pci_bus *pci_bus) void pci_remove_bus(struct pci_bus *pci_bus)
{ {

View file

@ -561,7 +561,7 @@ static int __devinit vrc4173_cardu_init(void)
{ {
vrc4173_cardu_slots = 0; vrc4173_cardu_slots = 0;
return pci_module_init(&vrc4173_cardu_driver); return pci_register_driver(&vrc4173_cardu_driver);
} }
static void __devexit vrc4173_cardu_exit(void) static void __devexit vrc4173_cardu_exit(void)

View file

@ -1195,7 +1195,7 @@ static int __init serial_txx9_init(void)
serial_txx9_register_ports(&serial_txx9_reg); serial_txx9_register_ports(&serial_txx9_reg);
#ifdef ENABLE_SERIAL_TXX9_PCI #ifdef ENABLE_SERIAL_TXX9_PCI
ret = pci_module_init(&serial_txx9_pci_driver); ret = pci_register_driver(&serial_txx9_pci_driver);
#endif #endif
} }
return ret; return ret;

View file

@ -1666,6 +1666,7 @@ static int __devinit cyblafb_init(void)
#endif #endif
output("CyblaFB version %s initializing\n", VERSION); output("CyblaFB version %s initializing\n", VERSION);
return pci_module_init(&cyblafb_pci_driver); return pci_module_init(&cyblafb_pci_driver);
return pci_register_driver(&cyblafb_pci_driver);
} }
static void __exit cyblafb_exit(void) static void __exit cyblafb_exit(void)

View file

@ -78,6 +78,23 @@ typedef int __bitwise pci_power_t;
#define PCI_UNKNOWN ((pci_power_t __force) 5) #define PCI_UNKNOWN ((pci_power_t __force) 5)
#define PCI_POWER_ERROR ((pci_power_t __force) -1) #define PCI_POWER_ERROR ((pci_power_t __force) -1)
/** The pci_channel state describes connectivity between the CPU and
* the pci device. If some PCI bus between here and the pci device
* has crashed or locked up, this info is reflected here.
*/
typedef unsigned int __bitwise pci_channel_state_t;
enum pci_channel_state {
/* I/O channel is in normal state */
pci_channel_io_normal = (__force pci_channel_state_t) 1,
/* I/O to channel is blocked */
pci_channel_io_frozen = (__force pci_channel_state_t) 2,
/* PCI card is dead */
pci_channel_io_perm_failure = (__force pci_channel_state_t) 3,
};
/* /*
* The pci_dev structure is used to describe PCI devices. * The pci_dev structure is used to describe PCI devices.
*/ */
@ -98,6 +115,7 @@ struct pci_dev {
unsigned int class; /* 3 bytes: (base,sub,prog-if) */ unsigned int class; /* 3 bytes: (base,sub,prog-if) */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */ u8 hdr_type; /* PCI header type (`multi' flag masked out) */
u8 rom_base_reg; /* which config register controls the ROM */ u8 rom_base_reg; /* which config register controls the ROM */
u8 pin; /* which interrupt pin this device uses */
struct pci_driver *driver; /* which driver has allocated this device */ struct pci_driver *driver; /* which driver has allocated this device */
u64 dma_mask; /* Mask of the bits of bus address this u64 dma_mask; /* Mask of the bits of bus address this
@ -110,6 +128,7 @@ struct pci_dev {
this is D0-D3, D0 being fully functional, this is D0-D3, D0 being fully functional,
and D3 being off. */ and D3 being off. */
pci_channel_state_t error_state; /* current connectivity state */
struct device dev; /* Generic device interface */ struct device dev; /* Generic device interface */
/* device is compatible with these IDs */ /* device is compatible with these IDs */
@ -232,6 +251,54 @@ struct pci_dynids {
unsigned int use_driver_data:1; /* pci_driver->driver_data is used */ unsigned int use_driver_data:1; /* pci_driver->driver_data is used */
}; };
/* ---------------------------------------------------------------- */
/** PCI Error Recovery System (PCI-ERS). If a PCI device driver provides
* a set fof callbacks in struct pci_error_handlers, then that device driver
* will be notified of PCI bus errors, and will be driven to recovery
* when an error occurs.
*/
typedef unsigned int __bitwise pci_ers_result_t;
enum pci_ers_result {
/* no result/none/not supported in device driver */
PCI_ERS_RESULT_NONE = (__force pci_ers_result_t) 1,
/* Device driver can recover without slot reset */
PCI_ERS_RESULT_CAN_RECOVER = (__force pci_ers_result_t) 2,
/* Device driver wants slot to be reset. */
PCI_ERS_RESULT_NEED_RESET = (__force pci_ers_result_t) 3,
/* Device has completely failed, is unrecoverable */
PCI_ERS_RESULT_DISCONNECT = (__force pci_ers_result_t) 4,
/* Device driver is fully recovered and operational */
PCI_ERS_RESULT_RECOVERED = (__force pci_ers_result_t) 5,
};
/* PCI bus error event callbacks */
struct pci_error_handlers
{
/* PCI bus error detected on this device */
pci_ers_result_t (*error_detected)(struct pci_dev *dev,
enum pci_channel_state error);
/* MMIO has been re-enabled, but not DMA */
pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
/* PCI Express link has been reset */
pci_ers_result_t (*link_reset)(struct pci_dev *dev);
/* PCI slot has been reset */
pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
/* Device driver may resume normal operations */
void (*resume)(struct pci_dev *dev);
};
/* ---------------------------------------------------------------- */
struct module; struct module;
struct pci_driver { struct pci_driver {
struct list_head node; struct list_head node;
@ -244,6 +311,7 @@ struct pci_driver {
int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable); /* Enable wake event */ int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable); /* Enable wake event */
void (*shutdown) (struct pci_dev *dev); void (*shutdown) (struct pci_dev *dev);
struct pci_error_handlers *err_handler;
struct device_driver driver; struct device_driver driver;
struct pci_dynids dynids; struct pci_dynids dynids;
}; };
@ -448,6 +516,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
void *userdata); void *userdata);
int pci_cfg_space_size(struct pci_dev *dev);
/* kmem_cache style wrapper around pci_alloc_consistent() */ /* kmem_cache style wrapper around pci_alloc_consistent() */

View file

@ -1089,7 +1089,7 @@ static struct pci_driver ad1889_driver = {
static int __init ad1889_init_module(void) static int __init ad1889_init_module(void)
{ {
return pci_module_init(&ad1889_driver); return pci_register_driver(&ad1889_driver);
} }
static void ad1889_exit_module(void) static void ad1889_exit_module(void)

View file

@ -1101,7 +1101,7 @@ static int btaudio_init_module(void)
digital ? "digital" : "", digital ? "digital" : "",
analog && digital ? "+" : "", analog && digital ? "+" : "",
analog ? "analog" : ""); analog ? "analog" : "");
return pci_module_init(&btaudio_pci_driver); return pci_register_driver(&btaudio_pci_driver);
} }
static void btaudio_cleanup_module(void) static void btaudio_cleanup_module(void)

View file

@ -3366,7 +3366,7 @@ static struct pci_driver cm_driver = {
static int __init init_cmpci(void) static int __init init_cmpci(void)
{ {
printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n"); printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n");
return pci_module_init(&cm_driver); return pci_register_driver(&cm_driver);
} }
static void __exit cleanup_cmpci(void) static void __exit cleanup_cmpci(void)

View file

@ -4461,7 +4461,7 @@ static int __init cs4281_init_module(void)
printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " " printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
__DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION, __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
CS4281_ARCH); CS4281_ARCH);
rtn = pci_module_init(&cs4281_pci_driver); rtn = pci_register_driver(&cs4281_pci_driver);
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn)); printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn));

View file

@ -5690,7 +5690,7 @@ static int __init cs46xx_init_module(void)
int rtn = 0; int rtn = 0;
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
"cs46xx: cs46xx_init_module()+ \n")); "cs46xx: cs46xx_init_module()+ \n"));
rtn = pci_module_init(&cs46xx_pci_driver); rtn = pci_register_driver(&cs46xx_pci_driver);
if(rtn == -ENODEV) if(rtn == -ENODEV)
{ {

View file

@ -1428,7 +1428,7 @@ static int __init emu10k1_init_module(void)
{ {
printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
return pci_module_init(&emu10k1_pci_driver); return pci_register_driver(&emu10k1_pci_driver);
} }
static void __exit emu10k1_cleanup_module(void) static void __exit emu10k1_cleanup_module(void)

View file

@ -2779,7 +2779,7 @@ static struct pci_driver es1370_driver = {
static int __init init_es1370(void) static int __init init_es1370(void)
{ {
printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n"); printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n");
return pci_module_init(&es1370_driver); return pci_register_driver(&es1370_driver);
} }
static void __exit cleanup_es1370(void) static void __exit cleanup_es1370(void)

View file

@ -3090,7 +3090,7 @@ static struct pci_driver es1371_driver = {
static int __init init_es1371(void) static int __init init_es1371(void)
{ {
printk(KERN_INFO PFX "version v0.32 time " __TIME__ " " __DATE__ "\n"); printk(KERN_INFO PFX "version v0.32 time " __TIME__ " " __DATE__ "\n");
return pci_module_init(&es1371_driver); return pci_register_driver(&es1371_driver);
} }
static void __exit cleanup_es1371(void) static void __exit cleanup_es1371(void)

View file

@ -2206,7 +2206,7 @@ static struct pci_driver it8172_driver = {
static int __init init_it8172(void) static int __init init_it8172(void)
{ {
info("version v0.5 time " __TIME__ " " __DATE__); info("version v0.5 time " __TIME__ " " __DATE__);
return pci_module_init(&it8172_driver); return pci_register_driver(&it8172_driver);
} }
static void __exit cleanup_it8172(void) static void __exit cleanup_it8172(void)

View file

@ -218,7 +218,7 @@ static struct pci_driver kahlua_driver = {
static int __init kahlua_init_module(void) static int __init kahlua_init_module(void)
{ {
printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n"); printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n");
return pci_module_init(&kahlua_driver); return pci_register_driver(&kahlua_driver);
} }
static void __devexit kahlua_cleanup_module(void) static void __devexit kahlua_cleanup_module(void)

View file

@ -3624,7 +3624,7 @@ static int __init init_maestro(void)
{ {
int rc; int rc;
rc = pci_module_init(&maestro_pci_driver); rc = pci_register_driver(&maestro_pci_driver);
if (rc < 0) if (rc < 0)
return rc; return rc;

View file

@ -2045,7 +2045,7 @@ static struct pci_driver vrc5477_ac97_driver = {
static int __init init_vrc5477_ac97(void) static int __init init_vrc5477_ac97(void)
{ {
printk("Vrc5477 AC97 driver: version v0.2 time " __TIME__ " " __DATE__ " by Jun Sun\n"); printk("Vrc5477 AC97 driver: version v0.2 time " __TIME__ " " __DATE__ " by Jun Sun\n");
return pci_module_init(&vrc5477_ac97_driver); return pci_register_driver(&vrc5477_ac97_driver);
} }
static void __exit cleanup_vrc5477_ac97(void) static void __exit cleanup_vrc5477_ac97(void)

View file

@ -1644,7 +1644,7 @@ module_param(force_load, bool, 0);
static int __init do_init_nm256(void) static int __init do_init_nm256(void)
{ {
printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1p\n"); printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1p\n");
return pci_module_init(&nm256_pci_driver); return pci_register_driver(&nm256_pci_driver);
} }
static void __exit cleanup_nm256 (void) static void __exit cleanup_nm256 (void)

View file

@ -1095,7 +1095,7 @@ static int __init init_rme96xx(void)
devices = ((devices-1) & RME96xx_MASK_DEVS) + 1; devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices); printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
numcards = 0; numcards = 0;
return pci_module_init(&rme96xx_driver); return pci_register_driver(&rme96xx_driver);
} }
static void __exit cleanup_rme96xx(void) static void __exit cleanup_rme96xx(void)

View file

@ -2765,7 +2765,7 @@ static int __init init_sonicvibes(void)
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
#endif #endif
return pci_module_init(&sv_driver); return pci_register_driver(&sv_driver);
} }
static void __exit cleanup_sonicvibes(void) static void __exit cleanup_sonicvibes(void)

View file

@ -2680,7 +2680,7 @@ static struct pci_driver ymfpci_driver = {
static int __init ymf_init_module(void) static int __init ymf_init_module(void)
{ {
return pci_module_init(&ymfpci_driver); return pci_register_driver(&ymfpci_driver);
} }
static void __exit ymf_cleanup_module (void) static void __exit ymf_cleanup_module (void)