home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
lxapi32.zip
/
Linux
/
PCI
/
setup-res.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-11-26
|
6KB
|
234 lines
/*
* drivers/pci/setup-res.c
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*
* Support routines for initializing a PCI subsystem.
*/
/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
/*
* Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
* Resource sorting
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
#define DEBUG_CONFIG 0
#if DEBUG_CONFIG
# define DBGC(args) printk args
#else
# define DBGC(args)
#endif
int __init
pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root = pci_find_parent_resource(dev, res);
int err;
err = -EINVAL;
if (root != NULL) {
err = request_resource(root, res);
if (err) {
printk(KERN_ERR "PCI: Address space collision on "
"region %d of device %s [%lx:%lx]\n",
resource, dev->name, res->start, res->end);
}
} else {
printk(KERN_ERR "PCI: No parent found for region %d "
"of device %s\n", resource, dev->name);
}
return err;
}
/*
* Given the PCI bus a device resides on, try to
* find an acceptable resource allocation for a
* specific device resource..
*/
static int pci_assign_bus_resource(const struct pci_bus *bus,
struct pci_dev *dev,
struct resource *res,
unsigned long size,
unsigned long min,
unsigned int type_mask,
int resno)
{
int i;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
for (i = 0 ; i < 4; i++) {
struct resource *r = bus->resource[i];
if (!r)
continue;
/* type_mask must match */
if ((res->flags ^ r->flags) & type_mask)
continue;
/* We cannot allocate a non-prefetching resource from a pre-fetching area */
if ((r->flags & IORESOURCE_PREFETCH) && !(res->flags & IORESOURCE_PREFETCH))
continue;
/* Ok, try it out.. */
if (allocate_resource(r, res, size, min, -1, size, pcibios_align_resource, dev) < 0)
continue;
/* Update PCI config space. */
pcibios_update_resource(dev, r, res, resno);
return 0;
}
return -EBUSY;
}
int
pci_assign_resource(struct pci_dev *dev, int i)
{
const struct pci_bus *bus = dev->bus;
struct resource *res = dev->resource + i;
unsigned long size, min;
size = res->end - res->start + 1;
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
/* First, try exact prefetching match.. */
if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) {
/*
* That failed.
*
* But a prefetching area can handle a non-prefetching
* window (it will just not perform as well).
*/
if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) {
printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n",
i, res->start, res->end, dev->slot_name);
return -EBUSY;
}
}
DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", res->start,
res->end, i, dev->name));
return 0;
}
/* Sort resources of a given type by alignment */
void __init
pdev_sort_resources(struct pci_dev *dev,
struct resource_list *head, u32 type_mask)
{
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r;
struct resource_list *list, *tmp;
unsigned long r_size;
/* PCI-PCI bridges may have I/O ports or
memory on the primary bus */
if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI &&
i >= PCI_BRIDGE_RESOURCES)
continue;
r = &dev->resource[i];
r_size = r->end - r->start;
if (!(r->flags & type_mask) || r->parent)
continue;
if (!r_size) {
printk(KERN_WARNING "PCI: Ignore bogus resource %d "
"[%lx:%lx] of %s\n",
i, r->start, r->end, dev->name);
continue;
}
for (list = head; ; list = list->next) {
unsigned long size = 0;
struct resource_list *ln = list->next;
if (ln)
size = ln->res->end - ln->res->start;
if (r_size > size) {
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n");
continue;
}
tmp->next = ln;
tmp->res = r;
tmp->dev = dev;
list->next = tmp;
break;
}
}
}
}
void __init
pdev_enable_device(struct pci_dev *dev)
{
u32 reg;
u16 cmd;
int i;
DBGC((KERN_ERR "PCI enable device: (%s)\n", dev->name));
pci_read_config_word(dev, PCI_COMMAND, &cmd);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = &dev->resource[i];
if (res->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
else if (res->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
/* Special case, disable the ROM. Several devices act funny
(ie. do not respond to memory space writes) when it is left
enabled. A good example are QlogicISP adapters. */
if (dev->rom_base_reg) {
pci_read_config_dword(dev, dev->rom_base_reg, ®);
reg &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(dev, dev->rom_base_reg, reg);
dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
}
/* 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 IO to these devices. */
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) {
cmd |= PCI_COMMAND_IO;
}
/* Do not enable bus mastering. A device could corrupt
* system memory by DMAing before a driver is ready for it. */
/* Set the cache line and default latency (32). */
pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
(32 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
/* Enable the appropriate bits in the PCI command register. */
pci_write_config_word(dev, PCI_COMMAND, cmd);
DBGC((KERN_ERR " cmd reg 0x%x\n", cmd));
}