patch-2.3.16 linux/arch/alpha/kernel/bios32.c
Next file: linux/arch/alpha/kernel/bios32.h
Previous file: linux/arch/alpha/kernel/alpha_ksyms.c
Back to the patch index
Back to the overall index
- Lines: 1375
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.15/linux/arch/alpha/kernel/bios32.c
- Orig date:
Fri Aug 13 11:53:50 1999
diff -u --recursive --new-file v2.3.15/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
@@ -1,1374 +0,0 @@
-/*
- * bios32.c - PCI BIOS functions for Alpha systems not using BIOS
- * emulation code.
- *
- * Written by Dave Rusling (david.rusling@reo.mts.dec.com)
- *
- * Adapted to 64-bit kernel and then rewritten by David Mosberger
- * (davidm@cs.arizona.edu)
- *
- * For more information, please consult
- *
- * PCI BIOS Specification Revision
- * PCI Local Bus Specification
- * PCI System Design Guide
- *
- * PCI Special Interest Group
- * M/S HF3-15A
- * 5200 N.E. Elam Young Parkway
- * Hillsboro, Oregon 97124-6497
- * +1 (503) 696-2000
- * +1 (800) 433-5177
- *
- * Manuals are $25 each or $50 for all three, plus $7 shipping
- * within the United States, $35 abroad.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <asm/pci.h>
-#include <asm/dma.h>
-
-#include "proto.h"
-#include "bios32.h"
-
-#define DEBUG_DEVS 0
-#define DEBUG_HOSE 0
-
-#if DEBUG_DEVS
-# define DBG_DEVS(args) printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#if DEBUG_HOSE
-# define DBG_HOSE(args) printk args
-#else
-# define DBG_HOSE(args)
-#endif
-
-#ifndef CONFIG_PCI
-
-asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
-asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
-void reset_for_srm(void) { }
-
-#else /* CONFIG_PCI */
-
-#include <linux/malloc.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-
-/*
- * PCI public interfaces.
- */
-
-#define MAJOR_REV 0
-#define MINOR_REV 4 /* minor revision 4, add multi-PCI handling */
-
-struct linux_hose_info *bus2hose[256];
-struct linux_hose_info *hose_head, **hose_tail = &hose_head;
-int hose_count;
-int pci_probe_enabled;
-
-static void layout_hoses(void);
-
-int
-pcibios_present(void)
-{
- return alpha_mv.hose_read_config_byte != NULL;
-}
-
-void __init
-pcibios_init(void)
-{
- if (!pcibios_present())
- return;
-
- printk("Alpha PCI BIOS32 revision %d.%02d\n", MAJOR_REV, MINOR_REV);
- if (alpha_use_srm_setup)
- printk(" NOT modifying existing (SRM) PCI configuration\n");
-}
-
-char * __init
-pcibios_setup(char *str)
-{
- return str;
-}
-
-void __init
-pcibios_fixup(void)
-{
- alpha_mv.pci_fixup();
-}
-
-void __init
-pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
-
-int
-pcibios_read_config_byte (u8 bus, u8 dev, u8 where, u8 *value)
-{
- int r = PCIBIOS_FUNC_NOT_SUPPORTED;
- *value = 0xff;
- if (alpha_mv.hose_read_config_byte) {
- r = (alpha_mv.hose_read_config_byte
- (bus, dev, where, value, bus2hose[bus]));
- }
- return r;
-}
-
-int
-pcibios_read_config_word (u8 bus, u8 dev, u8 where, u16 *value)
-{
- int r = PCIBIOS_FUNC_NOT_SUPPORTED;
- *value = 0xffff;
- if (alpha_mv.hose_read_config_word) {
- r = PCIBIOS_BAD_REGISTER_NUMBER;
- if (!(where & 1))
- r = (alpha_mv.hose_read_config_word
- (bus, dev, where, value, bus2hose[bus]));
- }
- return r;
-}
-
-int
-pcibios_read_config_dword (u8 bus, u8 dev, u8 where, u32 *value)
-{
- int r = PCIBIOS_FUNC_NOT_SUPPORTED;
- *value = 0xffffffff;
- if (alpha_mv.hose_read_config_dword) {
- r = PCIBIOS_BAD_REGISTER_NUMBER;
- if (!(where & 3))
- r = (alpha_mv.hose_read_config_dword
- (bus, dev, where, value, bus2hose[bus]));
- }
- return r;
-}
-
-int
-pcibios_write_config_byte (u8 bus, u8 dev, u8 where, u8 value)
-{
- int r = PCIBIOS_FUNC_NOT_SUPPORTED;
- if (alpha_mv.hose_write_config_byte) {
- r = (alpha_mv.hose_write_config_byte
- (bus, dev, where, value, bus2hose[bus]));
- }
- return r;
-}
-
-int
-pcibios_write_config_word (u8 bus, u8 dev, u8 where, u16 value)
-{
- int r = PCIBIOS_FUNC_NOT_SUPPORTED;
- if (alpha_mv.hose_write_config_word) {
- r = PCIBIOS_BAD_REGISTER_NUMBER;
- if (!(where & 1))
- r = (alpha_mv.hose_write_config_word
- (bus, dev, where, value, bus2hose[bus]));
- }
- return r;
-}
-
-int
-pcibios_write_config_dword (u8 bus, u8 dev, u8 where, u32 value)
-{
- int r = PCIBIOS_FUNC_NOT_SUPPORTED;
- if (alpha_mv.hose_write_config_dword) {
- r = PCIBIOS_BAD_REGISTER_NUMBER;
- if (!(where & 3))
- r = (alpha_mv.hose_write_config_dword
- (bus, dev, where, value, bus2hose[bus]));
- }
- return r;
-}
-
-asmlinkage int
-sys_pciconfig_read(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len,
- unsigned char *buf)
-{
- unsigned char ubyte;
- unsigned short ushort;
- unsigned int uint;
- long err = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (!pcibios_present())
- return -ENOSYS;
-
- switch (len) {
- case 1:
- err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
- put_user(ubyte, buf);
- break;
- case 2:
- err = pcibios_read_config_word(bus, dfn, off, &ushort);
- put_user(ushort, (unsigned short *)buf);
- break;
- case 4:
- err = pcibios_read_config_dword(bus, dfn, off, &uint);
- put_user(uint, (unsigned int *)buf);
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-asmlinkage int
-sys_pciconfig_write(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len,
- unsigned char *buf)
-{
- unsigned char ubyte;
- unsigned short ushort;
- unsigned int uint;
- long err = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (!pcibios_present())
- return -ENOSYS;
-
- switch (len) {
- case 1:
- err = get_user(ubyte, buf);
- if (err)
- break;
- err = pcibios_write_config_byte(bus, dfn, off, ubyte);
- if (err != PCIBIOS_SUCCESSFUL) {
- err = -EFAULT;
- }
- break;
- case 2:
- err = get_user(ushort, (unsigned short *)buf);
- if (err)
- break;
- err = pcibios_write_config_word(bus, dfn, off, ushort);
- if (err != PCIBIOS_SUCCESSFUL) {
- err = -EFAULT;
- }
- break;
- case 4:
- err = get_user(uint, (unsigned int *)buf);
- if (err)
- break;
- err = pcibios_write_config_dword(bus, dfn, off, uint);
- if (err != PCIBIOS_SUCCESSFUL) {
- err = -EFAULT;
- }
- break;
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-
-/*
- * Gory details start here...
- */
-
-/*
- * Align VAL to ALIGN, which must be a power of two.
- */
-#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
-
-
-/*
- * The following structure records initial configuration of devices
- * so that we can reset them on shutdown and so enable clean reboots
- * on SRM. It is more trouble than it iw worth to conditionalize this.
- */
-
-struct srm_irq_reset {
- struct srm_irq_reset *next;
- struct pci_dev *dev;
- u8 irq;
-} *srm_irq_resets;
-
-struct srm_io_reset {
- struct srm_io_reset *next;
- struct pci_dev *dev;
- u32 io;
- u8 reg;
-} *srm_io_resets;
-
-/* Apply the collected reset modifications. */
-
-void
-reset_for_srm(void)
-{
- struct srm_irq_reset *qreset;
- struct srm_io_reset *ireset;
-
- /* Reset any IRQs that we changed. */
- for (qreset = srm_irq_resets; qreset ; qreset = qreset->next) {
- pcibios_write_config_byte(qreset->dev->bus->number,
- qreset->dev->devfn,
- PCI_INTERRUPT_LINE,
- qreset->irq);
-#if 1
- printk("reset_for_srm: bus %d slot 0x%x "
- "SRM IRQ 0x%x changed back from 0x%x\n",
- qreset->dev->bus->number,
- PCI_SLOT(qreset->dev->devfn),
- qreset->irq, qreset->dev->irq);
-#endif
- }
-
- /* Reset any IO addresses that we changed. */
- for (ireset = srm_io_resets; ireset ; ireset = ireset->next) {
- pcibios_write_config_dword(ireset->dev->bus->number,
- ireset->dev->devfn,
- ireset->reg, ireset->io);
-#if 1
- printk("reset_for_srm: bus %d slot 0x%x "
- "SRM MEM/IO restored to 0x%x\n",
- ireset->dev->bus->number,
- PCI_SLOT(ireset->dev->devfn),
- ireset->io);
-#endif
- }
-}
-
-static void
-new_irq_reset(struct pci_dev *dev, u8 irq)
-{
- struct srm_irq_reset *n;
- n = kmalloc(sizeof(*n), GFP_KERNEL);
-
- n->next = srm_irq_resets;
- n->dev = dev;
- n->irq = irq;
- srm_irq_resets = n;
-}
-
-static void
-new_io_reset(struct pci_dev *dev, u8 reg, u32 io)
-{
- struct srm_io_reset *n;
- n = kmalloc(sizeof(*n), GFP_KERNEL);
-
- n->next = srm_io_resets;
- n->dev = dev;
- n->reg = reg;
- n->io = io;
- srm_io_resets = n;
-}
-
-
-/*
- * Disable PCI device DEV so that it does not respond to I/O or memory
- * accesses.
- */
-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... :-(
- */
- if (dev->vendor == PCI_VENDOR_ID_INTEL &&
- dev->device == PCI_DEVICE_ID_INTEL_82375) {
- dev->class = PCI_CLASS_BRIDGE_EISA;
- DBG_DEVS(("disable_dev: ignoring PCEB...\n"));
- return;
- }
-
- if (dev->vendor == PCI_VENDOR_ID_INTEL &&
- dev->device == PCI_DEVICE_ID_INTEL_82378) {
- dev->class = PCI_CLASS_BRIDGE_ISA;
- DBG_DEVS(("disable_dev: ignoring SIO...\n"));
- return;
- }
-
- /*
- * 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... :-\
- */
- if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
- dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
- DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n"));
- return;
- }
-
-#if DEBUG_DEVS && 0
- /* Worse HACK: Don't disable the video card, so I can see where
- it is *really* falling over. */
- if (dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) {
- DBG_DEVS(("disable_dev: ignoring video card %04x:%04x\n",
- dev->vendor, dev->device));
- return;
- }
-#endif
-
- 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);
-}
-
-
-/*
- * Layout memory and I/O for a device:
- */
-#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
-
-static unsigned int io_base;
-static unsigned int mem_base;
-
-static void __init
-layout_dev(struct pci_dev *dev)
-{
- struct pci_bus *bus;
- unsigned short cmd;
- unsigned int base, mask, size, off, idx;
- unsigned int orig_base;
- unsigned int alignto;
- unsigned long handle;
-
- /*
- * HACK: the PCI-to-EISA bridge does not seem to identify
- * itself as a bridge... :-(
- */
- if (dev->vendor == PCI_VENDOR_ID_INTEL
- && dev->device == PCI_DEVICE_ID_INTEL_82375) {
- dev->class = PCI_CLASS_BRIDGE_EISA;
- DBG_DEVS(("layout_dev: ignoring PCEB...\n"));
- return;
- }
-
- if (dev->vendor == PCI_VENDOR_ID_INTEL
- && dev->device == PCI_DEVICE_ID_INTEL_82378) {
- dev->class = PCI_CLASS_BRIDGE_ISA;
- DBG_DEVS(("layout_dev: ignoring SIO...\n"));
- return;
- }
-
- if (dev->vendor == PCI_VENDOR_ID_CONTAQ
- && dev->device == PCI_DEVICE_ID_CONTAQ_82C693
- && dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
- DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n"));
- return;
- }
-
- bus = dev->bus;
- pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
-
- for (idx = 0; idx <= 5; idx++) {
- off = PCI_BASE_ADDRESS_0 + 4*idx;
- /*
- * Figure out how much space and of what type this
- * device wants.
- */
- pcibios_read_config_dword(bus->number, dev->devfn, off,
- &orig_base);
- pcibios_write_config_dword(bus->number, dev->devfn, off,
- 0xffffffff);
- pcibios_read_config_dword(bus->number, dev->devfn, off, &base);
- if (!base) {
- /* This base-address register is unused. */
- dev->resource[idx].start = 0;
- dev->resource[idx].end = 0;
- dev->resource[idx].flags = 0;
- continue;
- }
-
- DBG_DEVS(("layout_dev: slot %d fn %d off 0x%x base 0x%x\n",
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
- off, base));
-
- /*
- * We've read the base address register back after
- * writing all ones and so now we must decode it.
- */
- if (base & PCI_BASE_ADDRESS_SPACE_IO) {
- /*
- * I/O space base address register.
- */
- cmd |= PCI_COMMAND_IO;
-
- base &= PCI_BASE_ADDRESS_IO_MASK;
- mask = (~base << 1) | 0x1;
- size = (mask & base) & 0xffffffff;
-
- /* We don't want to disturb normal IDE functions, so
- we don't touch the first two I/O ports on the
- Cypress. */
- if (dev->vendor == PCI_VENDOR_ID_CONTAQ
- && dev->device == PCI_DEVICE_ID_CONTAQ_82C693
- && idx < 2) {
- continue;
- }
-
- /*
- * Aligning to 0x800 rather than the minimum base of
- * 0x400 is an attempt to avoid having devices in
- * any 0x?C?? range, which is where the de4x5 driver
- * probes for EISA cards.
- *
- * Adaptecs, especially, resent such intrusions.
- */
- alignto = MAX(0x800, size);
- base = ALIGN(io_base, alignto);
- io_base = base + size;
-
- pcibios_write_config_dword(bus->number, dev->devfn,
- off, base | 0x1);
- new_io_reset(dev, off, orig_base);
-
- handle = PCI_HANDLE(bus->number) | base | 1;
- dev->resource[idx].start
- = handle & PCI_BASE_ADDRESS_IO_MASK;
- dev->resource[idx].end
- = dev->resource[idx].start + size - 1;
- dev->resource[idx].flags
- = handle & ~PCI_BASE_ADDRESS_IO_MASK;
-
- DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%lx (0x%x)\n",
- dev->device, handle, size));
- } else {
- unsigned int type;
- /*
- * Memory space base address register.
- */
- cmd |= PCI_COMMAND_MEMORY;
- type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
- base &= PCI_BASE_ADDRESS_MEM_MASK;
- mask = (~base << 1) | 0x1;
- size = (mask & base) & 0xffffffff;
- switch (type) {
- case PCI_BASE_ADDRESS_MEM_TYPE_32:
- case PCI_BASE_ADDRESS_MEM_TYPE_64:
- break;
-
- case PCI_BASE_ADDRESS_MEM_TYPE_1M:
- /*
- * Allocating memory below 1MB is *very*
- * tricky, as there may be all kinds of
- * ISA devices lurking that we don't know
- * about. For now, we just cross fingers
- * and hope nobody tries to do this on an
- * Alpha (or that the console has set it
- * up properly).
- */
- printk("bios32 WARNING: slot %d, function %d"
- " requests memory below 1MB---don't"
- " know how to do that.\n",
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
- continue;
- }
- /*
- * The following holds at least for the Low Cost
- * Alpha implementation of the PCI interface:
- *
- * In sparse memory address space, the first
- * octant (16MB) of every 128MB segment is
- * aliased to the very first 16 MB of the
- * address space (i.e., it aliases the ISA
- * memory address space). Thus, we try to
- * avoid allocating PCI devices in that range.
- * Can be allocated in 2nd-7th octant only.
- * Devices that need more than 112MB of
- * address space must be accessed through
- * dense memory space only!
- */
- /* align to multiple of size of minimum base */
- alignto = MAX(0x1000, size);
- base = ALIGN(mem_base, alignto);
- if (size > 7 * 16*MB) {
- printk("bios32 WARNING: slot %d, function %d"
- " requests 0x%x bytes of contiguous"
- " address space---don't use sparse"
- " memory accesses on this device!!\n",
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn), size);
- } else {
- if (((base / (16*MB)) & 0x7) == 0) {
- base &= ~(128*MB - 1);
- base += 16*MB;
- base = ALIGN(base, alignto);
- }
- if (base/(128*MB) != (base + size)/(128*MB)) {
- base &= ~(128*MB - 1);
- base += (128 + 16)*MB;
- base = ALIGN(base, alignto);
- }
- }
- mem_base = base + size;
-
- pcibios_write_config_dword(bus->number, dev->devfn,
- off, base);
- new_io_reset(dev, off, orig_base);
-
- handle = PCI_HANDLE(bus->number) | base;
- dev->resource[idx].start
- = handle & PCI_BASE_ADDRESS_MEM_MASK;
- dev->resource[idx].end
- = dev->resource[idx].start + size - 1;
- dev->resource[idx].flags
- = handle & ~PCI_BASE_ADDRESS_MEM_MASK;
-
- /*
- * Currently for 64-bit cards, we simply do the usual
- * for setup of the first register (low) of the pair,
- * and then clear out the second (high) register, as
- * we are not yet able to do 64-bit addresses, and
- * setting the high register to 0 allows 32-bit SAC
- * addresses to be used.
- */
- if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
- unsigned int orig_base2;
- pcibios_read_config_dword(bus->number,
- dev->devfn,
- off+4, &orig_base2);
- if (0 != orig_base2) {
- pcibios_write_config_dword(bus->number,
- dev->devfn,
- off+4, 0);
- new_io_reset (dev, off+4, orig_base2);
- }
- /* Bypass hi reg in the loop. */
- dev->resource[++idx].start = 0;
- dev->resource[idx].end = 0;
- dev->resource[idx].flags = 0;
-
- printk("bios32 WARNING: "
- "handling 64-bit device in "
- "slot %d, function %d: \n",
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
- }
-
- DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n",
- dev->device, handle, size));
- }
- }
-
- /* Enable device: */
- if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
- dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
- dev->class >> 8 == PCI_CLASS_STORAGE_IDE ||
- dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) {
- /*
- * All of these (may) have I/O scattered all around
- * and may not use i/o-base address registers at all.
- * So we just have to always enable I/O to these
- * devices.
- */
- cmd |= PCI_COMMAND_IO;
- }
-
- pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
- cmd | PCI_COMMAND_MASTER);
-
- DBG_DEVS(("layout_dev: bus %d slot %d VID 0x%x DID 0x%x"
- " class 0x%x cmd 0 x%x\n",
- bus->number, PCI_SLOT(dev->devfn), dev->vendor,
- dev->device, dev->class, cmd|PCI_COMMAND_MASTER));
-}
-
-static int __init
-layout_bus(struct pci_bus *bus)
-{
- unsigned int l, tio, bio, tmem, bmem;
- struct pci_bus *child;
- struct pci_dev *dev;
- int found_vga = 0;
-
- DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
-
- if (!bus->devices && !bus->children)
- return 0;
-
- /*
- * Align the current bases on appropriate boundaries (4K for
- * IO and 1MB for memory).
- */
- bio = io_base = ALIGN(io_base, 4*KB);
- bmem = mem_base = ALIGN(mem_base, 1*MB);
-
- /*
- * There are times when the PCI devices have already been
- * setup (e.g., by MILO or SRM). In these cases there is a
- * window during which two devices may have an overlapping
- * address range. To avoid this causing trouble, we first
- * turn off the I/O and memory address decoders for all PCI
- * devices. They'll be re-enabled only once all address
- * decoders are programmed consistently.
- */
- DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number));
-
- for (dev = bus->devices; dev; dev = dev->sibling) {
- if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
- (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
- disable_dev(dev);
- }
- }
-
- /*
- * Allocate space to each device:
- */
- DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
-
- for (dev = bus->devices; dev; dev = dev->sibling) {
- if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
- (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
- layout_dev(dev);
- }
- if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- found_vga = 1;
- }
- /*
- * Recursively allocate space for all of the sub-buses:
- */
- DBG_DEVS(("layout_bus: starting bus %d children\n", bus->number));
-
- for (child = bus->children; child; child = child->next) {
- found_vga += layout_bus(child);
- }
- /*
- * Align the current bases on 4K and 1MB boundaries:
- */
- tio = io_base = ALIGN(io_base, 4*KB);
- tmem = mem_base = ALIGN(mem_base, 1*MB);
-
- if (bus->self) {
- struct pci_dev *bridge = bus->self;
-
- DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number));
-
- /*
- * Set up the top and bottom of the PCI I/O segment
- * for this bus.
- */
- pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
- PCI_IO_BASE, &l);
- l &= 0xffff0000;
- l |= ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000);
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_IO_BASE, l);
-
- /*
- * Clear out the upper 16 bits of IO base/limit.
- * Clear out the upper 32 bits of PREF base/limit.
- */
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_IO_BASE_UPPER16, 0);
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_PREF_BASE_UPPER32, 0);
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_PREF_LIMIT_UPPER32, 0);
-
- /*
- * Set up the top and bottom of the PCI Memory segment
- * for this bus.
- */
- l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000);
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_MEMORY_BASE, l);
-
- /*
- * Turn off downstream PF memory address range, unless
- * there is a VGA behind this bridge, in which case, we
- * enable the PREFETCH range to include BIOS ROM at C0000.
- *
- * NOTE: this is a bit of a hack, done with PREFETCH for
- * simplicity, rather than having to add it into the above
- * non-PREFETCH range, which could then be bigger than we want.
- * We might assume that we could relocate the BIOS ROM, but
- * that would depend on having it found by those who need it
- * (the DEC BIOS emulator would find it, but I do not know
- * about the Xservers). So, we do it this way for now... ;-}
- */
- l = (found_vga) ? 0 : 0x0000ffff;
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_PREF_MEMORY_BASE, l);
-
- /*
- * Tell bridge that there is an ISA bus in the system,
- * and (possibly) a VGA as well.
- */
- l = (found_vga) ? 0x0c : 0x04;
- pcibios_write_config_byte(bridge->bus->number, bridge->devfn,
- PCI_BRIDGE_CONTROL, l);
-
- /*
- * Clear status bits,
- * turn on I/O enable (for downstream I/O),
- * turn on memory enable (for downstream memory),
- * turn on master enable (for upstream memory and I/O).
- */
- pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- PCI_COMMAND, 0xffff0007);
- }
- DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
- return found_vga;
-}
-
-void __init
-layout_all_busses(unsigned long default_io_base,
- unsigned long default_mem_base)
-{
- struct pci_bus *cur;
-
- layout_hoses();
-
- /*
- * Scan the tree, allocating PCI memory and I/O space.
- */
- /*
- * Sigh; check_region() will need changing to accept a PCI_HANDLE,
- * if we allocate I/O space addresses on a per-bus basis.
- * For now, make the I/O bases unique across all busses, so
- * that check_region() will not get confused... ;-}
- */
- io_base = default_io_base;
- for (cur = &pci_root; cur; cur = cur->next) {
- mem_base = default_mem_base;
- DBG_DEVS(("layout_all_busses: calling layout_bus()\n"));
- layout_bus(cur);
- }
- DBG_DEVS(("layout_all_busses: done.\n"));
-}
-
-
-/*
- * The SRM console *disables* the IDE interface, this code ensures it's
- * enabled.
- *
- * This code bangs on a control register of the 87312 Super I/O chip
- * that implements parallel port/serial ports/IDE/FDI. Depending on
- * the motherboard, the Super I/O chip can be configured through a
- * pair of registers that are located either at I/O ports 0x26e/0x26f
- * or 0x398/0x399. Unfortunately, autodetecting which base address is
- * in use works only once (right after a reset). The Super I/O chip
- * has the additional quirk that configuration register data must be
- * written twice (I believe this is a safety feature to prevent
- * accidental modification---fun, isn't it?).
- */
-
-void __init
-enable_ide(long ide_base)
-{
- int data;
- unsigned long flags;
-
- __save_and_cli(flags);
- outb(0, ide_base); /* set the index register for reg #0 */
- data = inb(ide_base+1); /* read the current contents */
- outb(0, ide_base); /* set the index register for reg #0 */
- outb(data | 0x40, ide_base+1); /* turn on IDE */
- outb(data | 0x40, ide_base+1); /* turn on IDE, really! */
- __restore_flags(flags);
-}
-
-/* Look for mis-configured devices' I/O space addresses behind bridges. */
-static void
-check_behind_io(struct pci_dev *dev)
-{
- struct pci_bus *bus = dev->bus;
- unsigned int reg, orig_base, new_base, found_one = 0;
-
- for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
- /* Read the current setting, check for I/O space and >= 64K */
- pcibios_read_config_dword(bus->number, dev->devfn,
- reg, &orig_base);
-
- if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO))
- continue; /* unused or non-IO */
-
- if (orig_base < 64*1024) {
-#if 1
-printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n",
- bus->number, PCI_SLOT(dev->devfn), orig_base);
-#endif
- if (orig_base & ~1)
- continue; /* OK! */
- orig_base = 0x12001; /* HACK! FIXME!! */
- }
-
- /* HACK ALERT! for now, just subtract 32K from the
- original address, which should give us addresses
- in the range 0x8000 and up */
- new_base = orig_base - 0x8000;
-#if 1
-printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n",
- bus->number, PCI_SLOT(dev->devfn), orig_base, new_base);
-#endif
- pcibios_write_config_dword(bus->number, dev->devfn,
- reg, new_base);
-
- new_io_reset(dev, reg, orig_base);
- found_one++;
- }
-
- /* If any were modified, gotta hack the bridge IO limits too. */
- if (found_one) {
- if (bus->self) {
- struct pci_dev *bridge = bus->self;
- unsigned int l;
- /*
- * Set up the top and bottom of the PCI I/O segment
- * for this bus.
- */
- pcibios_read_config_dword(bridge->bus->number,
- bridge->devfn, 0x1c, &l);
-#if 1
-printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n",
- bus->number, PCI_SLOT(bridge->devfn), l);
-#endif
- l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */
- pcibios_write_config_dword(bridge->bus->number,
- bridge->devfn, 0x1c, l);
- pcibios_write_config_dword(bridge->bus->number,
- bridge->devfn,
- 0x3c, 0x00040000);
- pcibios_write_config_dword(bridge->bus->number,
- bridge->devfn,
- 0x4, 0xffff0007);
- } else
- printk("check_behind_io: WARNING! bus->self NULL\n");
- }
-}
-
-
-/*
- * Most boards share most of the fixup code, which is isolated here.
- */
-
-void __init
-common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin),
- int (*swizzle)(struct pci_dev *dev, int *pin))
-{
- struct pci_dev *dev;
- u8 pin, slot, irq_orig;
- int irq;
-
- /*
- * Go through all devices, fixing up irqs as we see fit.
- */
- for (dev = pci_devices; dev; dev = dev->next) {
- if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
- (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
- continue;
-
- /*
- * 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... :-\
- */
- if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
- dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
- DBG_DEVS(("common_pci_fixup: ignoring CYPRESS bridge...\n"));
- continue;
- }
-
- /*
- * This device is not on the primary bus, we need
- * to figure out which interrupt pin it will come
- * in on. We know which slot it will come in on
- * 'cos that slot is where the bridge is. Each
- * time the interrupt line passes through a PCI-PCI
- * bridge we must apply the swizzle function (see
- * the inline static routine above).
- */
- dev->irq = 0;
-
- pcibios_read_config_byte(dev->bus->number, dev->devfn,
- PCI_INTERRUPT_PIN, &pin);
- /* Cope with 0 and illegal. */
- if (pin == 0 || pin > 4)
- pin = 1;
-
- if (!DEV_IS_ON_PRIMARY(dev)) {
- /* Follow the chain of bridges, swizzling as we go. */
-
- int spill = pin;
- slot = (*swizzle)(dev, &spill);
- pin = spill;
-
- /* Must make sure that SRM didn't screw up
- and allocate an address > 64K for I/O
- space behind a PCI-PCI bridge. */
- if (alpha_use_srm_setup)
- check_behind_io(dev);
- } else {
- /* Just a device on a primary bus. */
- slot = PCI_SLOT(dev->devfn);
- }
-
- irq = (*map_irq)(dev, slot, pin);
-
- DBG_DEVS(("common_pci_fixup: bus %d slot %d "
- "pin %d irq %d\n",
- dev->bus->number, slot, pin, irq));
-
- if (irq != -1)
- dev->irq = irq;
-
- if (alpha_using_srm) {
- /* Read the original SRM-set IRQ and tell. */
- pcibios_read_config_byte(dev->bus->number,
- dev->devfn,
- PCI_INTERRUPT_LINE,
- &irq_orig);
-
- if (irq_orig != dev->irq) {
- DBG_DEVS(("common_pci_fixup: bus %d "
- "slot 0x%x SRM IRQ 0x%x "
- "changed to 0x%x\n",
- dev->bus->number,
- PCI_SLOT(dev->devfn),
- irq_orig, dev->irq));
-
- new_irq_reset(dev, irq_orig);
- }
- }
-
- /* Always tell the device, so the driver knows what is
- the real IRQ to use; the device does not use it. */
- pcibios_write_config_byte(dev->bus->number, dev->devfn,
- PCI_INTERRUPT_LINE, dev->irq);
-
- DBG_DEVS(("common_pci_fixup: bus %d slot 0x%x"
- " VID 0x%x DID 0x%x\n"
- " int_slot 0x%x pin 0x%x"
- " pirq 0x%x\n",
- dev->bus->number, PCI_SLOT(dev->devfn),
- dev->vendor, dev->device,
- slot, pin, dev->irq));
-
- /*
- * If it's a VGA, enable its BIOS ROM at C0000.
- */
- if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
- /* But if its a Cirrus 543x/544x DISABLE it,
- since enabling ROM disables the memory... */
- if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
- (dev->device >= 0x00a0) &&
- (dev->device <= 0x00ac)) {
- pcibios_write_config_dword(
- dev->bus->number,
- dev->devfn,
- PCI_ROM_ADDRESS,
- 0x00000000);
- } else {
- pcibios_write_config_dword(
- dev->bus->number,
- dev->devfn,
- PCI_ROM_ADDRESS,
- 0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
- }
- }
- /*
- * If it's a SCSI, disable its BIOS ROM.
- */
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) {
- pcibios_write_config_dword(dev->bus->number,
- dev->devfn,
- PCI_ROM_ADDRESS,
- 0x0000000);
- }
- }
-}
-
-/* Most Alphas have straight-forward swizzling needs. */
-
-int __init
-common_swizzle(struct pci_dev *dev, int *pinp)
-{
- int pin = *pinp;
- do {
- pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
- /* Move up the chain of bridges. */
- dev = dev->bus->self;
- } while (dev->bus->self);
- *pinp = pin;
-
- /* The slot is the slot of the last bridge. */
- return PCI_SLOT(dev->devfn);
-}
-
-/*
- * On multiple bus machines, in order to cope with a somewhat deficient
- * API, we must map the 8-bit bus identifier so that it is unique across
- * multiple interfaces (hoses). At the same time we do this, chain the
- * other hoses off of pci_root so that they will be found during normal
- * PCI probing and layout.
- */
-
-#define PRIMARY(b) ((b)&0xff)
-#define SECONDARY(b) (((b)>>8)&0xff)
-#define SUBORDINATE(b) (((b)>>16)&0xff)
-
-static int __init
-hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus)
-{
- unsigned int devfn, l, class;
- unsigned char hdr_type = 0;
- unsigned int found = 0;
-
- for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) == 0) {
- alpha_mv.hose_read_config_byte(bus, devfn,
- PCI_HEADER_TYPE,
- &hdr_type, hose);
- } else if (!(hdr_type & 0x80)) {
- /* not a multi-function device */
- continue;
- }
-
- /* Check if there is anything here. */
- alpha_mv.hose_read_config_dword(bus, devfn, PCI_VENDOR_ID,
- &l, hose);
- if (l == 0xffffffff || l == 0x00000000) {
- hdr_type = 0;
- continue;
- }
-
- /* See if this is a bridge device. */
- alpha_mv.hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION,
- &class, hose);
-
- if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
- unsigned int busses;
-
- found++;
-
- alpha_mv.hose_read_config_dword(bus, devfn,
- PCI_PRIMARY_BUS,
- &busses, hose);
-
- DBG_HOSE(("hose_scan_bridges: hose %d bus %d "
- "slot %d busses 0x%x\n",
- hose->pci_hose_index, bus, PCI_SLOT(devfn),
- busses));
-
- /*
- * Do something with first_busno and last_busno
- */
- if (hose->pci_first_busno > PRIMARY(busses)) {
- hose->pci_first_busno = PRIMARY(busses);
- DBG_HOSE(("hose_scan_bridges: hose %d bus %d "
- "slot %d change first to %d\n",
- hose->pci_hose_index, bus,
- PCI_SLOT(devfn), PRIMARY(busses)));
- }
- if (hose->pci_last_busno < SUBORDINATE(busses)) {
- hose->pci_last_busno = SUBORDINATE(busses);
- DBG_HOSE(("hose_scan_bridges: hose %d bus %d "
- "slot %d change last to %d\n",
- hose->pci_hose_index, bus,
- PCI_SLOT(devfn),
- SUBORDINATE(busses)));
- }
- /*
- * Now scan everything underneath the bridge.
- */
- hose_scan_bridges(hose, SECONDARY(busses));
- }
- }
- return found;
-}
-
-static void __init
-hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus)
-{
- unsigned int devfn, l, class;
- unsigned char hdr_type = 0;
-
- for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) == 0) {
- alpha_mv.hose_read_config_byte(bus, devfn,
- PCI_HEADER_TYPE,
- &hdr_type, hose);
- } else if (!(hdr_type & 0x80)) {
- /* not a multi-function device */
- continue;
- }
-
- /* Check if there is anything here. */
- alpha_mv.hose_read_config_dword(bus, devfn, PCI_VENDOR_ID,
- &l, hose);
- if (l == 0xffffffff || l == 0x00000000) {
- hdr_type = 0;
- continue;
- }
-
- /* See if this is a bridge device. */
- alpha_mv.hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION,
- &class, hose);
-
- if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
- unsigned int busses;
-
- alpha_mv.hose_read_config_dword(bus, devfn,
- PCI_PRIMARY_BUS,
- &busses, hose);
-
- /*
- * First reconfigure everything underneath the bridge.
- */
- hose_reconfigure_bridges(hose, (busses >> 8) & 0xff);
-
- /*
- * Unconfigure this bridges bus numbers,
- * pci_scan_bus() will fix this up properly.
- */
- busses &= 0xff000000;
- alpha_mv.hose_write_config_dword(bus, devfn,
- PCI_PRIMARY_BUS,
- busses, hose);
- }
- }
-}
-
-static void __init
-hose_fixup_busno(struct linux_hose_info *hose, unsigned char bus)
-{
- int nbus;
-
- /*
- * First, scan for all bridge devices underneath this hose,
- * to determine the first and last busnos.
- */
- DBG_HOSE(("hose_fixup_busno: before hose_scan_bridges()\n"));
-
- if (!hose_scan_bridges(hose, 0)) {
- /* none found, exit */
- hose->pci_first_busno = bus;
- hose->pci_last_busno = bus;
- } else {
- /*
- * Reconfigure all bridge devices underneath this hose.
- */
- DBG_HOSE(("hose_fixup_busno: before hose_reconfigure_bridges\n"));
- hose_reconfigure_bridges(hose, hose->pci_first_busno);
- }
-
- /*
- * Now reconfigure the hose to it's new bus number and set up
- * our bus2hose mapping for this hose.
- */
- nbus = hose->pci_last_busno - hose->pci_first_busno;
-
- hose->pci_first_busno = bus;
-
- DBG_HOSE(("hose_fixup_busno: hose %d startbus %d nbus %d\n",
- hose->pci_hose_index, bus, nbus));
-
- do {
- bus2hose[bus++] = hose;
- } while (nbus-- > 0);
- DBG_HOSE(("hose_fixup_busno: returning...\n"));
-}
-
-static void __init
-layout_one_hose(struct linux_hose_info *hose)
-{
- static struct pci_bus *pchain = NULL;
- struct pci_bus *pbus = &hose->pci_bus;
- static unsigned char busno = 0;
-
- DBG_HOSE(("layout_one_hose: entry\n"));
-
- /*
- * Hoses include child PCI bridges in bus-range property,
- * but we don't scan each of those ourselves, Linux generic PCI
- * probing code will find child bridges and link them into this
- * hose's root PCI device hierarchy.
- */
-
- pbus->number = pbus->secondary = busno;
- pbus->sysdata = hose;
-
- DBG_HOSE(("layout_one_hose: before hose_fixup_busno()\n"));
-
- hose_fixup_busno(hose, busno);
-
- DBG_HOSE(("layout_one_hose: before pci_scan_bus()\n"));
-
- pbus->subordinate = pci_scan_bus(pbus); /* the original! */
-
- /*
- * Set the maximum subordinate bus of this hose.
- */
- hose->pci_last_busno = pbus->subordinate;
-#if 0
- alpha_mv.hose_write_config_byte(busno, 0, 0x41, hose->pci_last_busno,
- hose);
-#endif
- busno = pbus->subordinate + 1;
-
- /*
- * Fixup the chain of primary PCI busses.
- */
- if (pchain) {
- pchain->next = &hose->pci_bus;
- pchain = pchain->next;
- } else {
- pchain = &pci_root;
- memcpy(pchain, &hose->pci_bus, sizeof(pci_root));
- }
- DBG_HOSE(("layout_one_hose: returning...\n"));
-}
-
-static void __init
-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
- setup. The existance of the busses was determined in init_arch. */
-
- if (hose_head) {
- /* Multi-bus machines did not yet wish to allow bus
- accesses. We now do our own thing after the normal
- pci_scan_bus is over. This mechanism is relatively
- broken but will be fixed later. */
- pci_probe_enabled = 1;
-
- for (hose = hose_head; hose; hose = hose->next)
- layout_one_hose(hose);
- } else {
- /* For the benefit of single-bus machines, emulate a
- multi-bus machine to the (limited) extent necessary.
- Init all bus2hose entries to point to a dummy. */
- hose = kmalloc(sizeof(*hose), GFP_KERNEL);
- memset(hose, 0, sizeof(*hose));
- for (i = 0; i < 256; ++i)
- bus2hose[i] = hose;
- }
-}
-
-#endif /* CONFIG_PCI */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)