patch-2.2.16 linux/arch/alpha/kernel/bios32.c
Next file: linux/arch/alpha/kernel/core_irongate.c
Previous file: linux/arch/alpha/kernel/alpha_ksyms.c
Back to the patch index
Back to the overall index
- Lines: 268
- Date:
Wed Jun 7 14:26:42 2000
- Orig file:
v2.2.15/linux/arch/alpha/kernel/bios32.c
- Orig date:
Wed May 3 17:16:30 2000
diff -urN v2.2.15/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
@@ -327,6 +327,28 @@
*/
#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
+static short __inline__
+__disable_dev(struct pci_dev *dev)
+{
+ unsigned short cmd, orig_cmd;
+
+ pcibios_read_config_word(dev->bus->number, dev->devfn,
+ PCI_COMMAND, &cmd);
+
+ orig_cmd = cmd;
+ cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
+
+ pcibios_write_config_word(dev->bus->number, dev->devfn,
+ PCI_COMMAND, cmd);
+ return orig_cmd;
+}
+
+static void __inline__
+__enable_dev(struct pci_dev *dev, short orig_cmd)
+{
+ pcibios_write_config_word(dev->bus->number, dev->devfn,
+ PCI_COMMAND, orig_cmd);
+}
/*
* The following structure records initial configuration of devices
@@ -344,6 +366,7 @@
struct srm_io_reset *next;
struct pci_dev *dev;
u32 io;
+ short cmd;
u8 reg;
} *srm_io_resets;
@@ -354,6 +377,7 @@
{
struct srm_irq_reset *qreset;
struct srm_io_reset *ireset;
+ struct pci_dev *last_dev;
/* Reset any IRQs that we changed. */
for (qreset = srm_irq_resets; qreset ; qreset = qreset->next) {
@@ -370,6 +394,15 @@
#endif
}
+ /* Disable any devices which had IO addresses that we changed. */
+ last_dev = NULL;
+ for (ireset = srm_io_resets; ireset ; ireset = ireset->next) {
+ if (ireset->dev != last_dev) {
+ ireset->cmd = __disable_dev(ireset->dev);
+ last_dev = ireset->dev;
+ }
+ }
+
/* Reset any IO addresses that we changed. */
for (ireset = srm_io_resets; ireset ; ireset = ireset->next) {
pcibios_write_config_dword(ireset->dev->bus->number,
@@ -383,31 +416,40 @@
ireset->io);
#endif
}
+
+ /* Re-enable any devices which had IO addresses that we changed. */
+ last_dev = NULL;
+ for (ireset = srm_io_resets; ireset ; ireset = ireset->next) {
+ if (ireset->dev != last_dev) {
+ __enable_dev(ireset->dev, ireset->cmd);
+ last_dev = ireset->dev;
+ }
+ }
}
static void
new_irq_reset(struct pci_dev *dev, u8 irq)
{
- struct srm_irq_reset *n;
- n = kmalloc(sizeof(*n), GFP_KERNEL);
+ struct srm_irq_reset *new;
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
- n->next = srm_irq_resets;
- n->dev = dev;
- n->irq = irq;
- srm_irq_resets = n;
+ new->next = srm_irq_resets;
+ new->dev = dev;
+ new->irq = irq;
+ srm_irq_resets = new;
}
static void
new_io_reset(struct pci_dev *dev, u8 reg, u32 io)
{
- struct srm_io_reset *n;
- n = kmalloc(sizeof(*n), GFP_KERNEL);
+ struct srm_io_reset *new;
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
- n->next = srm_io_resets;
- n->dev = dev;
- n->reg = reg;
- n->io = io;
- srm_io_resets = n;
+ new->next = srm_io_resets;
+ new->dev = dev;
+ new->reg = reg;
+ new->io = io;
+ srm_io_resets = new;
}
@@ -418,9 +460,6 @@
static void __init
disable_dev(struct pci_dev *dev)
{
- struct pci_bus *bus;
- unsigned short cmd;
-
/*
* HACK: the PCI-to-EISA bridge does not seem to identify
* itself as a bridge... :-(
@@ -442,10 +481,11 @@
/*
* We don't have code that will init the CYPRESS bridge correctly
* so we do the next best thing, and depend on the previous
- * console code to do the right thing, and ignore it here... :-\
+ * console code to do the right thing, and ignore it mostly... :-\
*/
if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
- dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
+ dev->device == PCI_DEVICE_ID_CONTAQ_82C693 &&
+ PCI_FUNC(dev->devfn) == 0) {
DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n"));
return;
}
@@ -463,12 +503,7 @@
DBG_DEVS(("disable_dev: disabling %04x:%04x\n",
dev->vendor, dev->device));
- bus = dev->bus;
- pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
-
- /* hack, turn it off first... */
- cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
- pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd);
+ (void)__disable_dev(dev);
}
@@ -489,6 +524,7 @@
unsigned int orig_base;
unsigned int alignto;
unsigned long handle;
+ int start_idx = 0;
/*
* HACK: the PCI-to-EISA bridge does not seem to identify
@@ -511,18 +547,24 @@
/*
* We don't have code that will init the CYPRESS bridge correctly
* so we do the next best thing, and depend on the previous
- * console code to do the right thing, and ignore it here... :-\
+ * console code to do the right thing, and ignore it mostly... :-\
*/
if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
+ int func = PCI_FUNC(dev->devfn);
+ if (func == 0) {
DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n"));
return;
+ }
+ if (func == 1 || func == 2) {
+ start_idx = 4; /* bypass BAR 0 - 3 for the IDE devs */
+ }
}
bus = dev->bus;
pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
- for (idx = 0; idx <= 5; idx++) {
+ for (idx = start_idx; idx <= 5; idx++) {
off = PCI_BASE_ADDRESS_0 + 4*idx;
/*
* Figure out how much space and of what type this
@@ -713,6 +755,46 @@
dev->device, dev->class, cmd|PCI_COMMAND_MASTER));
}
+/* We must save away the current bridge settings for restore during exit. */
+static void __init
+save_bridge_setup(struct pci_dev *bridge)
+{
+ unsigned int dword;
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_IO_BASE, &dword);
+ new_io_reset(bridge, PCI_IO_BASE, dword);
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_IO_BASE_UPPER16, &dword);
+ new_io_reset(bridge, PCI_IO_BASE_UPPER16, dword);
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_PREF_BASE_UPPER32, &dword);
+ new_io_reset(bridge, PCI_PREF_BASE_UPPER32, dword);
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_PREF_LIMIT_UPPER32, &dword);
+ new_io_reset(bridge, PCI_PREF_LIMIT_UPPER32, dword);
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_MEMORY_BASE, &dword);
+ new_io_reset(bridge, PCI_MEMORY_BASE, dword);
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_PREF_MEMORY_BASE, &dword);
+ new_io_reset(bridge, PCI_PREF_MEMORY_BASE, dword);
+
+ /* Must use dword that contains PCI_BRIDGE_CONTROL. */
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_INTERRUPT_LINE, &dword);
+ new_io_reset(bridge, PCI_INTERRUPT_LINE, dword);
+
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_COMMAND, &dword);
+ new_io_reset(bridge, PCI_COMMAND, dword);
+}
+
static int __init
layout_bus(struct pci_bus *bus)
{
@@ -764,6 +846,7 @@
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
found_vga = 1;
}
+
/*
* Recursively allocate space for all of the sub-buses:
*/
@@ -772,6 +855,7 @@
for (child = bus->children; child; child = child->next) {
found_vga += layout_bus(child);
}
+
/*
* Align the current bases on 4K and 1MB boundaries:
*/
@@ -783,6 +867,8 @@
DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number));
+ save_bridge_setup(bridge);
+
/*
* Set up the top and bottom of the PCI I/O segment
* for this bus.
@@ -1364,7 +1450,6 @@
layout_hoses(void)
{
struct linux_hose_info * hose;
- int i;
/* On multiple bus machines, we play games with pci_root in order
that all of the busses are probed as part of the normal PCI
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)