mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 05:50:53 +07:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6
This commit is contained in:
commit
977127174a
@ -1,4 +1,5 @@
|
||||
Accessing PCI device resources through sysfs
|
||||
--------------------------------------------
|
||||
|
||||
sysfs, usually mounted at /sys, provides access to PCI resources on platforms
|
||||
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
|
||||
cpumask - file contains a cpumask type
|
||||
|
||||
The read only files are informational, writes to them will be ignored.
|
||||
Writable files can be used to perform actions on the device (e.g. changing
|
||||
config space, detaching a device). mmapable files are available via an
|
||||
mmap of the file at offset 0 and can be used to do actual device programming
|
||||
from userspace. Note that some platforms don't support mmapping of certain
|
||||
resources, so be sure to check the return value from any attempted mmap.
|
||||
The read only files are informational, writes to them will be ignored, with
|
||||
the exception of the 'rom' file. Writable files can be used to perform
|
||||
actions on the device (e.g. changing config space, detaching a device).
|
||||
mmapable files are available via an mmap of the file at offset 0 and can be
|
||||
used to do actual device programming from userspace. Note that some platforms
|
||||
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
|
||||
----------------------------------------
|
||||
|
||||
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,
|
||||
@ -75,6 +83,7 @@ simply dereference the returned pointer (after checking for errors of course)
|
||||
to access legacy memory space.
|
||||
|
||||
Supporting PCI access on new platforms
|
||||
--------------------------------------
|
||||
|
||||
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.
|
||||
|
246
Documentation/pci-error-recovery.txt
Normal file
246
Documentation/pci-error-recovery.txt
Normal 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>
|
@ -1987,6 +1987,13 @@ M: hch@infradead.org
|
||||
L: linux-abi-devel@lists.sourceforge.net
|
||||
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)
|
||||
P: Thomas Sailer
|
||||
M: sailer@ife.ee.ethz.ch
|
||||
|
@ -254,7 +254,7 @@ alcor_init_pci(void)
|
||||
* motherboard, by looking for a 21040 TULIP in slot 6, which is
|
||||
* 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,
|
||||
NULL);
|
||||
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",
|
||||
__FUNCTION__);
|
||||
}
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,7 +105,7 @@ sio_collect_irq_levels(void)
|
||||
struct pci_dev *dev = NULL;
|
||||
|
||||
/* 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) &&
|
||||
(dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
|
||||
continue;
|
||||
@ -229,8 +229,8 @@ alphabook1_init_pci(void)
|
||||
*/
|
||||
|
||||
dev = NULL;
|
||||
while ((dev = pci_find_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) {
|
||||
if (dev->device == PCI_DEVICE_ID_NCR_53C810
|
||||
while ((dev = pci_get_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) {
|
||||
if (dev->device == PCI_DEVICE_ID_NCR_53C810
|
||||
|| dev->device == PCI_DEVICE_ID_NCR_53C815
|
||||
|| dev->device == PCI_DEVICE_ID_NCR_53C820
|
||||
|| dev->device == PCI_DEVICE_ID_NCR_53C825) {
|
||||
|
@ -142,9 +142,7 @@ static void __init pcibios_allocate_resources(int pass)
|
||||
u16 command;
|
||||
struct resource *r, *pr;
|
||||
|
||||
while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev),
|
||||
dev != NULL
|
||||
) {
|
||||
for_each_pci_dev(dev) {
|
||||
pci_read_config_word(dev, PCI_COMMAND, &command);
|
||||
for(idx = 0; idx < 6; idx++) {
|
||||
r = &dev->resource[idx];
|
||||
@ -188,9 +186,7 @@ static void __init pcibios_assign_resources(void)
|
||||
int idx;
|
||||
struct resource *r;
|
||||
|
||||
while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev),
|
||||
dev != NULL
|
||||
) {
|
||||
for_each_pci_dev(dev) {
|
||||
int class = dev->class >> 8;
|
||||
|
||||
/* Don't touch classless devices and host bridges */
|
||||
|
@ -48,9 +48,7 @@ void __init pcibios_fixup_irqs(void)
|
||||
struct pci_dev *dev = NULL;
|
||||
uint8_t line, pin;
|
||||
|
||||
while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev),
|
||||
dev != NULL
|
||||
) {
|
||||
for_each_pci_dev(dev) {
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
if (pin) {
|
||||
dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
|
||||
|
@ -143,7 +143,7 @@ static int __init scx200_init(void)
|
||||
{
|
||||
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)
|
||||
|
@ -53,7 +53,7 @@ static int __init pci_acpi_init(void)
|
||||
* don't use pci_enable_device().
|
||||
*/
|
||||
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);
|
||||
} else
|
||||
printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n");
|
||||
|
@ -413,6 +413,13 @@ static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Toshiba A40 based laptop",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "PSA40U"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -78,7 +78,7 @@ static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
|
||||
for (i=0; i < rt->size; i++)
|
||||
sum += addr[i];
|
||||
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 NULL;
|
||||
@ -128,7 +128,7 @@ static void __init pirq_peer_trick(void)
|
||||
#ifdef DEBUG
|
||||
{
|
||||
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++)
|
||||
DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
|
||||
DBG("\n");
|
||||
@ -160,10 +160,10 @@ void eisa_set_level_irq(unsigned int irq)
|
||||
return;
|
||||
|
||||
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);
|
||||
if (!(val & mask)) {
|
||||
DBG(" -> edge");
|
||||
DBG(KERN_DEBUG " -> edge");
|
||||
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_M1563:
|
||||
printk("PCI: Using ALI IRQ Router\n");
|
||||
r->name = "ALI";
|
||||
r->get = pirq_ali_get;
|
||||
r->set = pirq_ali_set;
|
||||
return 1;
|
||||
printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n");
|
||||
r->name = "ALI";
|
||||
r->get = pirq_ali_get;
|
||||
r->set = pirq_ali_set;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -749,12 +749,13 @@ static void __init pirq_find_router(struct irq_router *r)
|
||||
r->get = 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);
|
||||
|
||||
pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
|
||||
if (!pirq_router_dev) {
|
||||
DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
|
||||
DBG(KERN_DEBUG "PCI: Interrupt router not found at "
|
||||
"%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -799,7 +800,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
||||
/* Find IRQ pin */
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
if (!pin) {
|
||||
DBG(" -> no interrupt pin\n");
|
||||
DBG(KERN_DEBUG " -> no interrupt pin\n");
|
||||
return 0;
|
||||
}
|
||||
pin = pin - 1;
|
||||
@ -809,16 +810,16 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
|
||||
if (!pirq_table)
|
||||
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);
|
||||
if (!info) {
|
||||
DBG(" -> not found in routing table\n");
|
||||
DBG(" -> not found in routing table\n" KERN_DEBUG);
|
||||
return 0;
|
||||
}
|
||||
pirq = info->irq[pin].link;
|
||||
mask = info->irq[pin].bitmap;
|
||||
if (!pirq) {
|
||||
DBG(" -> not routed\n");
|
||||
DBG(" -> not routed\n" KERN_DEBUG);
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
if (newirq && !((1 << newirq) & mask)) {
|
||||
if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
|
||||
else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, pci_name(dev));
|
||||
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) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
@ -923,14 +927,14 @@ static void __init pcibios_fixup_irqs(void)
|
||||
struct pci_dev *dev = NULL;
|
||||
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) {
|
||||
/*
|
||||
* If the BIOS has set an out of range IRQ number, just ignore it.
|
||||
* Also keep track of which IRQ's are already in use.
|
||||
*/
|
||||
if (dev->irq >= 16) {
|
||||
DBG("%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq);
|
||||
DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq);
|
||||
dev->irq = 0;
|
||||
}
|
||||
/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
|
||||
@ -1039,7 +1043,7 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = {
|
||||
|
||||
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)
|
||||
return 0;
|
||||
|
@ -561,7 +561,7 @@ static int __devinit vrc4173_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pci_module_init(&vrc4173_driver);
|
||||
err = pci_register_driver(&vrc4173_driver);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -503,7 +503,7 @@ pcibios_allocate_resources(int pass)
|
||||
u16 command;
|
||||
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);
|
||||
for (idx = 0; idx < 6; idx++) {
|
||||
r = &dev->resource[idx];
|
||||
@ -540,7 +540,7 @@ pcibios_assign_resources(void)
|
||||
int idx;
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
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)
|
||||
continue;
|
||||
if (dev->devfn != *devfn)
|
||||
continue;
|
||||
*bus = dev->bus->number;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for_each_pci_dev(dev)
|
||||
if (pci_to_OF_bus_map[dev->bus->number] == *bus &&
|
||||
dev->devfn == *devfn) {
|
||||
*bus = dev->bus->number;
|
||||
pci_dev_put(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_device_from_OF_node);
|
||||
|
@ -351,10 +351,10 @@ mpc85xx_cds_fixup_via(struct pci_controller *hose)
|
||||
void __init
|
||||
mpc85xx_cds_pcibios_fixup(void)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
struct pci_dev *dev;
|
||||
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))) {
|
||||
/*
|
||||
* U-Boot does not set the enable bits
|
||||
@ -371,21 +371,24 @@ mpc85xx_cds_pcibios_fixup(void)
|
||||
*/
|
||||
dev->irq = 14;
|
||||
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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))) {
|
||||
dev->irq = 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))) {
|
||||
dev->irq = 11;
|
||||
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
@ -527,18 +527,12 @@ static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
|
||||
{
|
||||
struct pci_dev *pdev = start;
|
||||
|
||||
do {
|
||||
pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev);
|
||||
if (pdev &&
|
||||
(pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
|
||||
pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
|
||||
while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev)))
|
||||
if (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
|
||||
pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)
|
||||
break;
|
||||
} while (pdev != NULL);
|
||||
|
||||
if (pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
|
||||
*is_rio_p = 1;
|
||||
else
|
||||
*is_rio_p = 0;
|
||||
*is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS));
|
||||
|
||||
return pdev;
|
||||
}
|
||||
@ -637,6 +631,7 @@ void __init ebus_init(void)
|
||||
ebus->is_rio = is_rio;
|
||||
++num_ebus;
|
||||
}
|
||||
pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
|
||||
|
||||
#ifdef CONFIG_SUN_AUXIO
|
||||
auxio_probe();
|
||||
|
@ -361,8 +361,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,
|
||||
|
||||
if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
|
||||
/* 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) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"No interrupt pin configured for device %s\n",
|
||||
@ -412,7 +411,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
||||
if (!dev)
|
||||
return_VALUE(-EINVAL);
|
||||
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
pin = dev->pin;
|
||||
if (!pin) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"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)
|
||||
return_VOID;
|
||||
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
pin = dev->pin;
|
||||
if (!pin)
|
||||
return_VOID;
|
||||
pin--;
|
||||
|
@ -7179,7 +7179,7 @@ static int DAC960_init_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pci_module_init(&DAC960_pci_driver);
|
||||
ret = pci_register_driver(&DAC960_pci_driver);
|
||||
#ifdef DAC960_GAM_MINOR
|
||||
if (!ret)
|
||||
DAC960_gam_init();
|
||||
|
@ -3360,7 +3360,7 @@ static int __init cciss_init(void)
|
||||
printk(KERN_INFO DRIVER_NAME "\n");
|
||||
|
||||
/* 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)
|
||||
|
@ -1755,7 +1755,7 @@ static void carm_remove_one (struct pci_dev *pdev)
|
||||
|
||||
static int __init carm_init(void)
|
||||
{
|
||||
return pci_module_init(&carm_driver);
|
||||
return pci_register_driver(&carm_driver);
|
||||
}
|
||||
|
||||
static void __exit carm_exit(void)
|
||||
|
@ -1174,7 +1174,7 @@ static int __init mm_init(void)
|
||||
|
||||
printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
|
||||
|
||||
retval = pci_module_init(&mm_pci_driver);
|
||||
retval = pci_register_driver(&mm_pci_driver);
|
||||
if (retval)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -841,7 +841,7 @@ static int __devinit vt8231_pci_probe(struct pci_dev *dev,
|
||||
|
||||
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)
|
||||
|
@ -395,7 +395,7 @@ static struct pci_driver gemtek_pci_driver =
|
||||
|
||||
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 )
|
||||
|
@ -338,7 +338,7 @@ static struct pci_driver maxiradio_driver = {
|
||||
|
||||
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)
|
||||
|
@ -464,7 +464,7 @@ static struct pci_driver parport_serial_pci_driver = {
|
||||
|
||||
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)
|
||||
|
@ -794,12 +794,14 @@ static int enable_device(struct acpiphp_slot *slot)
|
||||
if (PCI_SLOT(dev->devfn) != slot->device)
|
||||
continue;
|
||||
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);
|
||||
if (pass && dev->subordinate)
|
||||
pci_bus_size_bridges(dev->subordinate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
acpiphp_sanitize_bus(bus);
|
||||
pci_enable_bridges(bus);
|
||||
|
@ -317,6 +317,7 @@ struct controller {
|
||||
u16 vendor_id;
|
||||
struct work_struct int_task_event;
|
||||
wait_queue_head_t queue; /* sleep & wake process */
|
||||
struct dentry *dentry; /* debugfs dentry */
|
||||
};
|
||||
|
||||
struct irq_mapping {
|
||||
@ -399,8 +400,11 @@ struct resource_lists {
|
||||
#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n"
|
||||
|
||||
|
||||
/* sysfs functions for the hotplug controller info */
|
||||
extern void cpqhp_create_ctrl_files (struct controller *ctrl);
|
||||
/* debugfs functions for the hotplug controller info */
|
||||
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 */
|
||||
extern void cpqhp_pushbutton_thread (unsigned long event_pointer);
|
||||
|
@ -327,7 +327,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
|
||||
void __iomem *smbios_start,
|
||||
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 slot_device;
|
||||
u8 slot_number;
|
||||
@ -345,93 +347,105 @@ static int ctrl_slot_setup(struct controller *ctrl,
|
||||
slot_number = ctrl->first_slot;
|
||||
|
||||
while (number_of_slots) {
|
||||
new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
|
||||
if (!new_slot)
|
||||
slot = kmalloc(sizeof(*slot), GFP_KERNEL);
|
||||
if (!slot)
|
||||
goto error;
|
||||
|
||||
memset(new_slot, 0, sizeof(struct slot));
|
||||
new_slot->hotplug_slot = kmalloc(sizeof(*(new_slot->hotplug_slot)),
|
||||
memset(slot, 0, sizeof(struct slot));
|
||||
slot->hotplug_slot = kmalloc(sizeof(*(slot->hotplug_slot)),
|
||||
GFP_KERNEL);
|
||||
if (!new_slot->hotplug_slot)
|
||||
if (!slot->hotplug_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 =
|
||||
kmalloc(sizeof(*(new_slot->hotplug_slot->info)),
|
||||
hotplug_slot->info =
|
||||
kmalloc(sizeof(*(hotplug_slot->info)),
|
||||
GFP_KERNEL);
|
||||
if (!new_slot->hotplug_slot->info)
|
||||
if (!hotplug_slot->info)
|
||||
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));
|
||||
new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
|
||||
if (!new_slot->hotplug_slot->name)
|
||||
hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
|
||||
|
||||
if (!hotplug_slot->name)
|
||||
goto error_info;
|
||||
|
||||
new_slot->ctrl = ctrl;
|
||||
new_slot->bus = ctrl->bus;
|
||||
new_slot->device = slot_device;
|
||||
new_slot->number = slot_number;
|
||||
dbg("slot->number = %d\n",new_slot->number);
|
||||
slot->ctrl = ctrl;
|
||||
slot->bus = ctrl->bus;
|
||||
slot->device = slot_device;
|
||||
slot->number = slot_number;
|
||||
dbg("slot->number = %d\n", slot->number);
|
||||
|
||||
slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9,
|
||||
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,
|
||||
smbios_table, 9, slot_entry);
|
||||
}
|
||||
|
||||
new_slot->p_sm_slot = slot_entry;
|
||||
slot->p_sm_slot = slot_entry;
|
||||
|
||||
init_timer(&new_slot->task_event);
|
||||
new_slot->task_event.expires = jiffies + 5 * HZ;
|
||||
new_slot->task_event.function = cpqhp_pushbutton_thread;
|
||||
init_timer(&slot->task_event);
|
||||
slot->task_event.expires = jiffies + 5 * HZ;
|
||||
slot->task_event.function = cpqhp_pushbutton_thread;
|
||||
|
||||
//FIXME: these capabilities aren't used but if they are
|
||||
// they need to be correctly implemented
|
||||
new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED;
|
||||
new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED;
|
||||
slot->capabilities |= PCISLOT_REPLACE_SUPPORTED;
|
||||
slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED;
|
||||
|
||||
if (is_slot64bit(new_slot))
|
||||
new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
|
||||
if (is_slot66mhz(new_slot))
|
||||
new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
|
||||
if (is_slot64bit(slot))
|
||||
slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
|
||||
if (is_slot66mhz(slot))
|
||||
slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
|
||||
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
|
||||
new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02;
|
||||
slot->capabilities |=
|
||||
((((~tempdword) >> 23) |
|
||||
((~tempdword) >> 15)) >> ctrl_slot) & 0x02;
|
||||
// Check the switch state
|
||||
new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01;
|
||||
slot->capabilities |=
|
||||
((~tempdword & 0xFF) >> ctrl_slot) & 0x01;
|
||||
// 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 */
|
||||
new_slot->hotplug_slot->release = &release_slot;
|
||||
new_slot->hotplug_slot->private = new_slot;
|
||||
make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
|
||||
new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
|
||||
hotplug_slot->release = &release_slot;
|
||||
hotplug_slot->private = slot;
|
||||
make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
|
||||
hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
|
||||
|
||||
new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot);
|
||||
new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot);
|
||||
new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot);
|
||||
new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot);
|
||||
hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot);
|
||||
hotplug_slot_info->attention_status =
|
||||
cpq_get_attention_status(ctrl, 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",
|
||||
new_slot->bus, new_slot->device,
|
||||
new_slot->number, ctrl->slot_device_offset,
|
||||
slot->bus, slot->device,
|
||||
slot->number, ctrl->slot_device_offset,
|
||||
slot_number);
|
||||
result = pci_hp_register (new_slot->hotplug_slot);
|
||||
result = pci_hp_register(hotplug_slot);
|
||||
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;
|
||||
}
|
||||
|
||||
new_slot->next = ctrl->slot;
|
||||
ctrl->slot = new_slot;
|
||||
slot->next = ctrl->slot;
|
||||
ctrl->slot = slot;
|
||||
|
||||
number_of_slots--;
|
||||
slot_device++;
|
||||
@ -439,15 +453,14 @@ static int ctrl_slot_setup(struct controller *ctrl,
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_name:
|
||||
kfree(new_slot->hotplug_slot->name);
|
||||
kfree(hotplug_slot->name);
|
||||
error_info:
|
||||
kfree(new_slot->hotplug_slot->info);
|
||||
kfree(hotplug_slot_info);
|
||||
error_hpslot:
|
||||
kfree(new_slot->hotplug_slot);
|
||||
kfree(hotplug_slot);
|
||||
error_slot:
|
||||
kfree(new_slot);
|
||||
kfree(slot);
|
||||
error:
|
||||
return result;
|
||||
}
|
||||
@ -466,6 +479,8 @@ static int ctrl_slot_cleanup (struct controller * ctrl)
|
||||
old_slot = next_slot;
|
||||
}
|
||||
|
||||
cpqhp_remove_debugfs_files(ctrl);
|
||||
|
||||
//Free IRQ associated with hot plug device
|
||||
free_irq(ctrl->interrupt, ctrl);
|
||||
//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
|
||||
up(&ctrl->crit_sect);
|
||||
|
||||
cpqhp_create_ctrl_files(ctrl);
|
||||
cpqhp_create_debugfs_files(ctrl);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1502,6 +1517,7 @@ static int __init cpqhpc_init(void)
|
||||
cpqhp_debug = debug;
|
||||
|
||||
info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
|
||||
cpqhp_initialize_debugfs();
|
||||
result = pci_register_driver(&cpqhpc_driver);
|
||||
dbg("pci_register_driver = %d\n", result);
|
||||
return result;
|
||||
@ -1515,6 +1531,7 @@ static void __exit cpqhpc_cleanup(void)
|
||||
|
||||
dbg("pci_unregister_driver\n");
|
||||
pci_unregister_driver(&cpqhpc_driver);
|
||||
cpqhp_shutdown_debugfs();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2630,29 +2630,15 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||
hold_mem_node = NULL;
|
||||
}
|
||||
|
||||
/* If we have prefetchable memory resources copy them and
|
||||
* fill in the bridge's memory range registers. Otherwise,
|
||||
* 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;
|
||||
memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
|
||||
p_mem_node->next = NULL;
|
||||
|
||||
/* set Pre Mem base and Limit registers */
|
||||
temp_word = p_mem_node->base >> 16;
|
||||
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
|
||||
/* set Pre Mem base and Limit registers */
|
||||
temp_word = p_mem_node->base >> 16;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
/* Adjust this to compensate for extra adjustment in first loop */
|
||||
irqs.barber_pole--;
|
||||
|
@ -33,22 +33,15 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include "cpqphp.h"
|
||||
|
||||
|
||||
/* 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)
|
||||
static int show_ctrl (struct controller *ctrl, char *buf)
|
||||
{
|
||||
struct pci_dev *pci_dev;
|
||||
struct controller *ctrl;
|
||||
char * out = buf;
|
||||
char *out = buf;
|
||||
int index;
|
||||
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");
|
||||
index = 11;
|
||||
res = ctrl->mem_head;
|
||||
@ -80,22 +73,16 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
|
||||
|
||||
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;
|
||||
int index;
|
||||
struct pci_resource *res;
|
||||
struct pci_func *new_slot;
|
||||
struct slot *slot;
|
||||
|
||||
pci_dev = container_of (dev, struct pci_dev, dev);
|
||||
ctrl = pci_get_drvdata(pci_dev);
|
||||
|
||||
slot=ctrl->slot;
|
||||
slot = ctrl->slot;
|
||||
|
||||
while (slot) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev);
|
||||
int used;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -969,7 +969,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno)
|
||||
debug ("io 32\n");
|
||||
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");
|
||||
need_pfmem_upper = TRUE;
|
||||
}
|
||||
|
@ -103,7 +103,10 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
|
||||
|
||||
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 slot_device;
|
||||
u32 slot_number;
|
||||
@ -114,59 +117,66 @@ static int init_slots(struct controller *ctrl)
|
||||
slot_number = ctrl->first_slot;
|
||||
|
||||
while (number_of_slots) {
|
||||
new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
|
||||
if (!new_slot)
|
||||
slot = kmalloc(sizeof(*slot), GFP_KERNEL);
|
||||
if (!slot)
|
||||
goto error;
|
||||
|
||||
memset(new_slot, 0, sizeof(struct slot));
|
||||
new_slot->hotplug_slot =
|
||||
kmalloc(sizeof(*(new_slot->hotplug_slot)),
|
||||
memset(slot, 0, sizeof(struct slot));
|
||||
slot->hotplug_slot =
|
||||
kmalloc(sizeof(*(slot->hotplug_slot)),
|
||||
GFP_KERNEL);
|
||||
if (!new_slot->hotplug_slot)
|
||||
if (!slot->hotplug_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 =
|
||||
kmalloc(sizeof(*(new_slot->hotplug_slot->info)),
|
||||
hotplug_slot->info =
|
||||
kmalloc(sizeof(*(hotplug_slot->info)),
|
||||
GFP_KERNEL);
|
||||
if (!new_slot->hotplug_slot->info)
|
||||
if (!hotplug_slot->info)
|
||||
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));
|
||||
new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE,
|
||||
GFP_KERNEL);
|
||||
if (!new_slot->hotplug_slot->name)
|
||||
hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
|
||||
if (!hotplug_slot->name)
|
||||
goto error_info;
|
||||
|
||||
new_slot->ctrl = ctrl;
|
||||
new_slot->bus = ctrl->slot_bus;
|
||||
new_slot->device = slot_device;
|
||||
new_slot->hpc_ops = ctrl->hpc_ops;
|
||||
slot->ctrl = ctrl;
|
||||
slot->bus = ctrl->slot_bus;
|
||||
slot->device = slot_device;
|
||||
slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
|
||||
|
||||
new_slot->number = ctrl->first_slot;
|
||||
new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
|
||||
slot->number = ctrl->first_slot;
|
||||
slot->hp_slot = slot_device - ctrl->slot_device_offset;
|
||||
|
||||
/* register this slot with the hotplug pci core */
|
||||
new_slot->hotplug_slot->private = new_slot;
|
||||
new_slot->hotplug_slot->release = &release_slot;
|
||||
make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
|
||||
new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops;
|
||||
hotplug_slot->private = slot;
|
||||
hotplug_slot->release = &release_slot;
|
||||
make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
|
||||
hotplug_slot->ops = &pciehp_hotplug_slot_ops;
|
||||
|
||||
new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
|
||||
new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
|
||||
new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
|
||||
new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
|
||||
hpc_ops->get_power_status(slot,
|
||||
&(hotplug_slot_info->power_status));
|
||||
hpc_ops->get_attention_status(slot,
|
||||
&(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",
|
||||
new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
|
||||
result = pci_hp_register (new_slot->hotplug_slot);
|
||||
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
|
||||
"slot_device_offset=%x\n",
|
||||
slot->bus, slot->device, slot->hp_slot, slot->number,
|
||||
ctrl->slot_device_offset);
|
||||
result = pci_hp_register(hotplug_slot);
|
||||
if (result) {
|
||||
err ("pci_hp_register failed with error %d\n", result);
|
||||
goto error_name;
|
||||
}
|
||||
|
||||
new_slot->next = ctrl->slot;
|
||||
ctrl->slot = new_slot;
|
||||
slot->next = ctrl->slot;
|
||||
ctrl->slot = slot;
|
||||
|
||||
number_of_slots--;
|
||||
slot_device++;
|
||||
@ -176,13 +186,13 @@ static int init_slots(struct controller *ctrl)
|
||||
return 0;
|
||||
|
||||
error_name:
|
||||
kfree(new_slot->hotplug_slot->name);
|
||||
kfree(hotplug_slot->name);
|
||||
error_info:
|
||||
kfree(new_slot->hotplug_slot->info);
|
||||
kfree(hotplug_slot_info);
|
||||
error_hpslot:
|
||||
kfree(new_slot->hotplug_slot);
|
||||
kfree(hotplug_slot);
|
||||
error_slot:
|
||||
kfree(new_slot);
|
||||
kfree(slot);
|
||||
error:
|
||||
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)
|
||||
{
|
||||
|
@ -787,8 +787,13 @@ static int hpc_power_on_slot(struct slot * slot)
|
||||
|
||||
slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
|
||||
|
||||
/* Enable detection that we turned off at slot power-off time */
|
||||
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);
|
||||
|
||||
@ -833,8 +838,18 @@ static int hpc_power_off_slot(struct slot * slot)
|
||||
|
||||
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)
|
||||
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);
|
||||
|
||||
|
@ -34,6 +34,31 @@
|
||||
#include "../pci.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)
|
||||
{
|
||||
@ -55,8 +80,8 @@ int pciehp_configure_device(struct slot *p_slot)
|
||||
}
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
if (!(dev = pci_find_slot(p_slot->bus,
|
||||
PCI_DEVFN(p_slot->device, fn))))
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
|
||||
if (!dev)
|
||||
continue;
|
||||
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
|
||||
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) ||
|
||||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
|
||||
/* Find an unused bus number for the new bridge */
|
||||
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);
|
||||
pciehp_add_bridge(dev);
|
||||
}
|
||||
/* TBD: program firmware provided _HPP values */
|
||||
/* program_fw_provided_values(dev); */
|
||||
@ -93,7 +98,6 @@ int pciehp_configure_device(struct slot *p_slot)
|
||||
|
||||
pci_bus_assign_resources(parent);
|
||||
pci_bus_add_devices(parent);
|
||||
pci_enable_bridges(parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,9 @@ int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
|
||||
acpi_status status;
|
||||
acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
|
||||
struct pci_dev *pdev = dev;
|
||||
struct pci_bus *parent;
|
||||
u8 *path_name;
|
||||
|
||||
/*
|
||||
* Per PCI firmware specification, we should run the ACPI _OSC
|
||||
* 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)
|
||||
break;
|
||||
parent = pdev->bus->parent;
|
||||
dbg("Could not find %s in acpi namespace, trying parent\n",
|
||||
pci_name(pdev));
|
||||
if (!pdev->bus->parent->self)
|
||||
if (!parent->self)
|
||||
/* Parent must be a host bridge */
|
||||
handle = acpi_get_pci_rootbridge_handle(
|
||||
pci_domain_nr(pdev->bus->parent),
|
||||
pdev->bus->parent->number);
|
||||
pci_domain_nr(parent),
|
||||
parent->number);
|
||||
else
|
||||
handle = DEVICE_ACPI_HANDLE(
|
||||
&(pdev->bus->parent->self->dev));
|
||||
pdev = pdev->bus->parent->self;
|
||||
&(parent->self->dev));
|
||||
pdev = parent->self;
|
||||
}
|
||||
|
||||
while (handle) {
|
||||
|
@ -112,28 +112,6 @@ static struct slot *find_slot(struct device_node *dn)
|
||||
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,
|
||||
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_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 */
|
||||
dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
|
||||
if (!dev) {
|
||||
@ -170,7 +149,7 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
|
||||
rpaphp_init_new_devs(dev->subordinate);
|
||||
|
||||
/* 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 */
|
||||
(void) remap_bus_range(dev->bus);
|
||||
|
@ -62,28 +62,6 @@ struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct device_node *dn;
|
||||
@ -324,7 +290,7 @@ int rpaphp_config_pci_adapter(struct pci_bus *bus)
|
||||
if (!dn)
|
||||
goto exit;
|
||||
|
||||
rpaphp_eeh_init_nodes(dn);
|
||||
eeh_add_device_tree_early(dn);
|
||||
dev = rpaphp_pci_config_slot(bus);
|
||||
if (!dev) {
|
||||
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)
|
||||
{
|
||||
struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
|
||||
|
||||
dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
|
||||
__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,
|
||||
&slot->hotplug_slot->info->
|
||||
adapter_status);
|
||||
if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
|
||||
&hotplug_slot_info->adapter_status);
|
||||
if (hotplug_slot_info->adapter_status == NOT_VALID) {
|
||||
err("%s: NOT_VALID: skip dn->full_name=%s\n",
|
||||
__FUNCTION__, slot->dn->full_name);
|
||||
return -EINVAL;
|
||||
|
@ -98,6 +98,10 @@ struct controller {
|
||||
enum pci_bus_speed speed;
|
||||
u32 first_slot; /* First physical slot number */
|
||||
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 {
|
||||
|
@ -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_latch_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_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_latch_status = get_latch_status,
|
||||
.get_adapter_status = get_adapter_status,
|
||||
.get_address = get_address,
|
||||
.get_max_bus_speed = get_max_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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
|
||||
|
||||
pci_set_drvdata(pdev, ctrl);
|
||||
|
||||
ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
|
||||
|
@ -248,7 +248,6 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
|
||||
up(&ctrl->crit_sect);
|
||||
return WRONG_BUS_FREQUENCY;
|
||||
}
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
|
||||
err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
|
||||
@ -330,9 +329,6 @@ static int board_added(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
rc = p_slot->hpc_ops->check_cmd_status(ctrl);
|
||||
if (rc) {
|
||||
@ -352,7 +348,6 @@ static int board_added(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return WRONG_BUS_FREQUENCY;
|
||||
}
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
|
||||
err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
|
||||
@ -367,7 +362,6 @@ static int board_added(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return rc;
|
||||
}
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
|
||||
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
|
||||
@ -494,7 +488,6 @@ static int board_added(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return rc;
|
||||
}
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
|
||||
err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
|
||||
@ -532,9 +525,6 @@ static int board_added(struct slot *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 */
|
||||
up(&ctrl->crit_sect);
|
||||
|
||||
@ -552,8 +542,6 @@ static int board_added(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return rc;
|
||||
}
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
rc = p_slot->hpc_ops->check_cmd_status(ctrl);
|
||||
if (rc) {
|
||||
@ -603,8 +591,6 @@ static int remove_board(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return rc;
|
||||
}
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
rc = p_slot->hpc_ops->check_cmd_status(ctrl);
|
||||
if (rc) {
|
||||
@ -621,8 +607,6 @@ static int remove_board(struct slot *p_slot)
|
||||
up(&ctrl->crit_sect);
|
||||
return rc;
|
||||
}
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
/* Done with exclusive hardware access */
|
||||
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);
|
||||
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (p_slot->ctrl);
|
||||
|
||||
/* Done with exclusive hardware access */
|
||||
up(&p_slot->ctrl->crit_sect);
|
||||
}
|
||||
@ -790,14 +771,9 @@ static void interrupt_event_handler(struct controller *ctrl)
|
||||
down(&ctrl->crit_sect);
|
||||
|
||||
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);
|
||||
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
/* Done with exclusive hardware access */
|
||||
up(&ctrl->crit_sect);
|
||||
break;
|
||||
@ -806,12 +782,8 @@ static void interrupt_event_handler(struct controller *ctrl)
|
||||
down(&ctrl->crit_sect);
|
||||
|
||||
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);
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
/* Done with exclusive hardware access */
|
||||
up(&ctrl->crit_sect);
|
||||
@ -845,14 +817,9 @@ static void interrupt_event_handler(struct controller *ctrl)
|
||||
|
||||
/* blink green LED and turn off amber */
|
||||
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);
|
||||
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
/* Done with exclusive hardware access */
|
||||
up(&ctrl->crit_sect);
|
||||
|
||||
@ -870,12 +837,8 @@ static void interrupt_event_handler(struct controller *ctrl)
|
||||
down(&ctrl->crit_sect);
|
||||
|
||||
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);
|
||||
/* Wait for the command to complete */
|
||||
wait_for_ctrl_irq (ctrl);
|
||||
|
||||
/* Done with exclusive hardware access */
|
||||
up(&ctrl->crit_sect);
|
||||
|
@ -275,6 +275,25 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
|
||||
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)
|
||||
{
|
||||
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
|
||||
* command.
|
||||
*/
|
||||
slot->ctrl->cmd_busy = 1;
|
||||
writew(temp_word, php_ctlr->creg + CMD);
|
||||
|
||||
/*
|
||||
* Wait for command completion.
|
||||
*/
|
||||
retval = shpc_wait_cmd(slot->ctrl);
|
||||
|
||||
DBG_LEAVE_ROUTINE
|
||||
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);
|
||||
|
||||
if (pi == 2) {
|
||||
*mode = (sec_bus_status & 0x0100) >> 7;
|
||||
*mode = (sec_bus_status & 0x0100) >> 8;
|
||||
} else {
|
||||
retval = -1;
|
||||
}
|
||||
@ -791,7 +816,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
|
||||
}
|
||||
if (php_ctlr->pci_dev) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1058,12 +1083,13 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
|
||||
if (intr_loc & 0x0001) {
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
|
||||
temp_dword &= 0xfffeffff;
|
||||
temp_dword &= 0xfffdffff;
|
||||
writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
|
||||
ctrl->cmd_busy = 0;
|
||||
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;
|
||||
u8 pi;
|
||||
u32 slot_avail1, slot_avail2;
|
||||
int slot_num;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 )
|
||||
else if (slot_avail1 & SLOT_133MHZ_PCIX)
|
||||
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;
|
||||
else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 )
|
||||
else if (slot_avail1 & SLOT_66MHZ_PCIX)
|
||||
bus_speed = PCIX_66MHZ;
|
||||
else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 )
|
||||
else if (slot_avail2 & SLOT_66MHZ)
|
||||
bus_speed = PCI_66MHZ;
|
||||
else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 )
|
||||
else if (slot_avail1 & SLOT_33MHZ)
|
||||
bus_speed = PCI_33MHZ;
|
||||
else bus_speed = PCI_SPEED_UNKNOWN;
|
||||
} else {
|
||||
if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 )
|
||||
if (slot_avail1 & SLOT_133MHZ_PCIX)
|
||||
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;
|
||||
else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 )
|
||||
else if (slot_avail1 & SLOT_66MHZ_PCIX)
|
||||
bus_speed = PCIX_66MHZ;
|
||||
else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 )
|
||||
else if (slot_avail2 & SLOT_66MHZ)
|
||||
bus_speed = PCI_66MHZ;
|
||||
else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 )
|
||||
else if (slot_avail1 & SLOT_33MHZ)
|
||||
bus_speed = PCI_33MHZ;
|
||||
else bus_speed = PCI_SPEED_UNKNOWN;
|
||||
}
|
||||
@ -1321,19 +1346,34 @@ static struct hpc_ops shpchp_hpc_ops = {
|
||||
.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)
|
||||
{
|
||||
struct php_ctlr_state_s *php_ctlr, *p;
|
||||
void *instance_id = ctrl;
|
||||
int rc;
|
||||
int rc, num_slots = 0;
|
||||
u8 hp_slot;
|
||||
static int first = 1;
|
||||
u32 shpc_cap_offset, shpc_base_offset;
|
||||
u32 shpc_base_offset;
|
||||
u32 tempdword, slot_reg;
|
||||
u8 i;
|
||||
|
||||
DBG_ENTER_ROUTINE
|
||||
|
||||
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
|
||||
|
||||
spin_lock_init(&list_lock);
|
||||
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 ==
|
||||
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 {
|
||||
if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) {
|
||||
err("%s : shpc_cap_offset == 0\n", __FUNCTION__);
|
||||
ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
|
||||
if (!ctrl->cap_offset) {
|
||||
err("%s : cap_offset == 0\n", __FUNCTION__);
|
||||
goto abort_free_ctlr;
|
||||
}
|
||||
dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset);
|
||||
|
||||
rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET);
|
||||
dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
|
||||
|
||||
rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset);
|
||||
if (rc) {
|
||||
err("%s : pci_word_config_byte failed\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__);
|
||||
err("%s: cannot read base_offset\n", __FUNCTION__);
|
||||
goto abort_free_ctlr;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 14; i++) {
|
||||
rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , i);
|
||||
rc = shpc_indirect_creg_read(ctrl, 3, &tempdword);
|
||||
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) {
|
||||
err("%s : pci_word_config_byte failed\n", __FUNCTION__);
|
||||
goto abort_free_ctlr;
|
||||
}
|
||||
|
||||
rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword);
|
||||
if (rc) {
|
||||
err("%s : pci_read_config_dword failed\n", __FUNCTION__);
|
||||
err("%s: cannot read creg (index = %d)\n",
|
||||
__FUNCTION__, i);
|
||||
goto abort_free_ctlr;
|
||||
}
|
||||
dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
|
||||
tempdword);
|
||||
}
|
||||
|
||||
ctrl->mmio_base =
|
||||
pci_resource_start(pdev, 0) + shpc_base_offset;
|
||||
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
@ -1396,16 +1440,16 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
|
||||
if (pci_enable_device(pdev))
|
||||
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__);
|
||||
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) {
|
||||
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0),
|
||||
pci_resource_start(pdev, 0) + shpc_base_offset);
|
||||
release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
|
||||
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
|
||||
ctrl->mmio_size, ctrl->mmio_base);
|
||||
release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
|
||||
goto abort_free_ctlr;
|
||||
}
|
||||
dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
|
||||
|
@ -89,10 +89,11 @@ int shpchp_configure_device(struct slot *p_slot)
|
||||
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
|
||||
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) {
|
||||
err("Device %s already exists at %x:%x, cannot hot-add\n",
|
||||
pci_name(dev), p_slot->bus, p_slot->device);
|
||||
pci_dev_put(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -103,12 +104,13 @@ int shpchp_configure_device(struct slot *p_slot)
|
||||
}
|
||||
|
||||
for (fn = 0; fn < 8; fn++) {
|
||||
if (!(dev = pci_find_slot(p_slot->bus,
|
||||
PCI_DEVFN(p_slot->device, fn))))
|
||||
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
|
||||
if (!dev)
|
||||
continue;
|
||||
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
|
||||
err("Cannot hot-add display device %s\n",
|
||||
pci_name(dev));
|
||||
pci_dev_put(dev);
|
||||
continue;
|
||||
}
|
||||
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
|
||||
@ -124,18 +126,21 @@ int shpchp_configure_device(struct slot *p_slot)
|
||||
}
|
||||
if (busnr >= end) {
|
||||
err("No free bus for hot-added bridge\n");
|
||||
pci_dev_put(dev);
|
||||
continue;
|
||||
}
|
||||
child = pci_add_new_bus(parent, dev, busnr);
|
||||
if (!child) {
|
||||
err("Cannot add new bus for %s\n",
|
||||
pci_name(dev));
|
||||
pci_dev_put(dev);
|
||||
continue;
|
||||
}
|
||||
child->subordinate = pci_do_scan_bus(child);
|
||||
pci_bus_size_bridges(child);
|
||||
}
|
||||
program_fw_provided_values(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
pci_bus_assign_resources(parent);
|
||||
@ -149,17 +154,19 @@ int shpchp_unconfigure_device(struct slot *p_slot)
|
||||
int rc = 0;
|
||||
int j;
|
||||
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);
|
||||
|
||||
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);
|
||||
if (!temp)
|
||||
continue;
|
||||
if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
|
||||
err("Cannot remove display device %s\n",
|
||||
pci_name(temp));
|
||||
pci_dev_put(temp);
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
err("Cannot remove display device %s\n",
|
||||
pci_name(temp));
|
||||
pci_dev_put(temp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pci_remove_bus_device(temp);
|
||||
pci_dev_put(temp);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <asm/dma.h> /* isa_dma_bridge_buggy */
|
||||
#include "pci.h"
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
|
||||
@ -63,6 +64,8 @@ pci_max_busnr(void)
|
||||
return max;
|
||||
}
|
||||
|
||||
#endif /* 0 */
|
||||
|
||||
static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
|
||||
{
|
||||
u8 id;
|
||||
@ -587,7 +590,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
|
||||
{
|
||||
u8 pin;
|
||||
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
pin = dev->pin;
|
||||
if (!pin)
|
||||
return -1;
|
||||
pin--;
|
||||
@ -917,8 +920,6 @@ EXPORT_SYMBOL_GPL(pci_restore_bars);
|
||||
EXPORT_SYMBOL(pci_enable_device_bars);
|
||||
EXPORT_SYMBOL(pci_enable_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_bus_find_capability);
|
||||
EXPORT_SYMBOL(pci_release_regions);
|
||||
|
@ -26,20 +26,15 @@ extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern int pci_proc_attach_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);
|
||||
#else
|
||||
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_attach_bus(struct pci_bus *bus) { return 0; }
|
||||
static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
|
||||
#endif
|
||||
|
||||
/* Functions for PCI Hotplug drivers to use */
|
||||
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 void pci_remove_legacy_files(struct pci_bus *bus);
|
||||
|
@ -238,8 +238,8 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
|
||||
device->driver = NULL;
|
||||
device->driver_data = NULL;
|
||||
device->release = release_pcie_device; /* callback to free pcie dev */
|
||||
sprintf(&device->bus_id[0], "pcie%02x",
|
||||
get_descriptor_id(port_type, service_type));
|
||||
snprintf(device->bus_id, sizeof(device->bus_id), "%s:pcie%02x",
|
||||
pci_name(parent), get_descriptor_id(port_type, service_type));
|
||||
device->parent = &parent->dev;
|
||||
}
|
||||
|
||||
|
@ -264,8 +264,10 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
|
||||
|
||||
if (base <= limit) {
|
||||
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
|
||||
res->start = base;
|
||||
res->end = limit + 0xfff;
|
||||
if (!res->start)
|
||||
res->start = base;
|
||||
if (!res->end)
|
||||
res->end = limit + 0xfff;
|
||||
}
|
||||
|
||||
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;
|
||||
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
|
||||
u32 buses, i;
|
||||
u32 buses, i, j = 0;
|
||||
u16 bctl;
|
||||
|
||||
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
|
||||
* 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),
|
||||
max+i+1))
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -571,6 +608,7 @@ static void pci_read_irq(struct pci_dev *dev)
|
||||
unsigned char irq;
|
||||
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
|
||||
dev->pin = irq;
|
||||
if (irq)
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &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
|
||||
decoding (i.e. transparent) bridge must have programming
|
||||
interface code of 0x01. */
|
||||
pci_read_irq(dev);
|
||||
dev->transparent = ((dev->class & 0xff) == 1);
|
||||
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
|
||||
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
|
||||
* capability header.
|
||||
*/
|
||||
static int pci_cfg_space_size(struct pci_dev *dev)
|
||||
int pci_cfg_space_size(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
u32 status;
|
||||
|
@ -431,6 +431,7 @@ int pci_proc_detach_device(struct pci_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int pci_proc_attach_bus(struct pci_bus* bus)
|
||||
{
|
||||
struct proc_dir_entry *de = bus->procdir;
|
||||
@ -447,6 +448,7 @@ int pci_proc_attach_bus(struct pci_bus* bus)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
int pci_proc_detach_bus(struct pci_bus* bus)
|
||||
{
|
||||
@ -612,7 +614,6 @@ __initcall(pci_proc_init);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
EXPORT_SYMBOL(pci_proc_attach_device);
|
||||
EXPORT_SYMBOL(pci_proc_attach_bus);
|
||||
EXPORT_SYMBOL(pci_proc_detach_bus);
|
||||
#endif
|
||||
|
||||
|
@ -1342,6 +1342,32 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
|
||||
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);
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
EXPORT_SYMBOL(pci_fixup_device);
|
||||
|
@ -48,6 +48,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
|
||||
* in question is not being used by a driver.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
#if 0
|
||||
int pci_remove_device_safe(struct pci_dev *dev)
|
||||
{
|
||||
if (pci_dev_driver(dev))
|
||||
@ -55,7 +56,7 @@ int pci_remove_device_safe(struct pci_dev *dev)
|
||||
pci_destroy_dev(dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_remove_device_safe);
|
||||
#endif /* 0 */
|
||||
|
||||
void pci_remove_bus(struct pci_bus *pci_bus)
|
||||
{
|
||||
|
@ -561,7 +561,7 @@ static int __devinit vrc4173_cardu_init(void)
|
||||
{
|
||||
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)
|
||||
|
@ -1195,7 +1195,7 @@ static int __init serial_txx9_init(void)
|
||||
serial_txx9_register_ports(&serial_txx9_reg);
|
||||
|
||||
#ifdef ENABLE_SERIAL_TXX9_PCI
|
||||
ret = pci_module_init(&serial_txx9_pci_driver);
|
||||
ret = pci_register_driver(&serial_txx9_pci_driver);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
|
@ -1666,6 +1666,7 @@ static int __devinit cyblafb_init(void)
|
||||
#endif
|
||||
output("CyblaFB version %s initializing\n", VERSION);
|
||||
return pci_module_init(&cyblafb_pci_driver);
|
||||
return pci_register_driver(&cyblafb_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cyblafb_exit(void)
|
||||
|
@ -78,6 +78,23 @@ typedef int __bitwise pci_power_t;
|
||||
#define PCI_UNKNOWN ((pci_power_t __force) 5)
|
||||
#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.
|
||||
*/
|
||||
@ -98,6 +115,7 @@ struct pci_dev {
|
||||
unsigned int class; /* 3 bytes: (base,sub,prog-if) */
|
||||
u8 hdr_type; /* PCI header type (`multi' flag masked out) */
|
||||
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 */
|
||||
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,
|
||||
and D3 being off. */
|
||||
|
||||
pci_channel_state_t error_state; /* current connectivity state */
|
||||
struct device dev; /* Generic device interface */
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/** 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 pci_driver {
|
||||
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 */
|
||||
void (*shutdown) (struct pci_dev *dev);
|
||||
|
||||
struct pci_error_handlers *err_handler;
|
||||
struct device_driver driver;
|
||||
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 *userdata);
|
||||
int pci_cfg_space_size(struct pci_dev *dev);
|
||||
|
||||
/* kmem_cache style wrapper around pci_alloc_consistent() */
|
||||
|
||||
|
@ -1089,7 +1089,7 @@ static struct pci_driver ad1889_driver = {
|
||||
|
||||
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)
|
||||
|
@ -1101,7 +1101,7 @@ static int btaudio_init_module(void)
|
||||
digital ? "digital" : "",
|
||||
analog && digital ? "+" : "",
|
||||
analog ? "analog" : "");
|
||||
return pci_module_init(&btaudio_pci_driver);
|
||||
return pci_register_driver(&btaudio_pci_driver);
|
||||
}
|
||||
|
||||
static void btaudio_cleanup_module(void)
|
||||
|
@ -3366,7 +3366,7 @@ static struct pci_driver cm_driver = {
|
||||
static int __init init_cmpci(void)
|
||||
{
|
||||
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)
|
||||
|
@ -4461,7 +4461,7 @@ static int __init cs4281_init_module(void)
|
||||
printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
|
||||
__DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
|
||||
CS4281_ARCH);
|
||||
rtn = pci_module_init(&cs4281_pci_driver);
|
||||
rtn = pci_register_driver(&cs4281_pci_driver);
|
||||
|
||||
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
|
||||
printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn));
|
||||
|
@ -5690,7 +5690,7 @@ static int __init cs46xx_init_module(void)
|
||||
int rtn = 0;
|
||||
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
|
||||
"cs46xx: cs46xx_init_module()+ \n"));
|
||||
rtn = pci_module_init(&cs46xx_pci_driver);
|
||||
rtn = pci_register_driver(&cs46xx_pci_driver);
|
||||
|
||||
if(rtn == -ENODEV)
|
||||
{
|
||||
|
@ -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");
|
||||
|
||||
return pci_module_init(&emu10k1_pci_driver);
|
||||
return pci_register_driver(&emu10k1_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit emu10k1_cleanup_module(void)
|
||||
|
@ -2779,7 +2779,7 @@ static struct pci_driver es1370_driver = {
|
||||
static int __init init_es1370(void)
|
||||
{
|
||||
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)
|
||||
|
@ -3090,7 +3090,7 @@ static struct pci_driver es1371_driver = {
|
||||
static int __init init_es1371(void)
|
||||
{
|
||||
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)
|
||||
|
@ -2206,7 +2206,7 @@ static struct pci_driver it8172_driver = {
|
||||
static int __init init_it8172(void)
|
||||
{
|
||||
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)
|
||||
|
@ -218,7 +218,7 @@ static struct pci_driver kahlua_driver = {
|
||||
static int __init kahlua_init_module(void)
|
||||
{
|
||||
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)
|
||||
|
@ -3624,7 +3624,7 @@ static int __init init_maestro(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pci_module_init(&maestro_pci_driver);
|
||||
rc = pci_register_driver(&maestro_pci_driver);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
@ -2045,7 +2045,7 @@ static struct pci_driver vrc5477_ac97_driver = {
|
||||
static int __init init_vrc5477_ac97(void)
|
||||
{
|
||||
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)
|
||||
|
@ -1644,7 +1644,7 @@ module_param(force_load, bool, 0);
|
||||
static int __init do_init_nm256(void)
|
||||
{
|
||||
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)
|
||||
|
@ -1095,7 +1095,7 @@ static int __init init_rme96xx(void)
|
||||
devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
|
||||
printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
|
||||
numcards = 0;
|
||||
return pci_module_init(&rme96xx_driver);
|
||||
return pci_register_driver(&rme96xx_driver);
|
||||
}
|
||||
|
||||
static void __exit cleanup_rme96xx(void)
|
||||
|
@ -2765,7 +2765,7 @@ static int __init init_sonicvibes(void)
|
||||
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");
|
||||
#endif
|
||||
return pci_module_init(&sv_driver);
|
||||
return pci_register_driver(&sv_driver);
|
||||
}
|
||||
|
||||
static void __exit cleanup_sonicvibes(void)
|
||||
|
@ -2680,7 +2680,7 @@ static struct pci_driver ymfpci_driver = {
|
||||
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user