home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
lxapi32.zip
/
PCI
/
pci-i386.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-04-26
|
7KB
|
262 lines
/* $Id: pci-i386.c,v 1.2 2002/04/26 23:09:34 smilcke Exp $ */
/*
* pci-i386.c
* Autor: Stefan Milcke
* Erstellt am: 25.10.2001
* Letzte Aenderung am: 05.04.2002
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <ldefos2.h>
#include "pci-i386.h"
// From kernel/setup.c
unsigned long pci_mem_start=0x10000000;
#ifdef TARGET_OS2
extern int dopcienable;
extern int dopcisetmaster;
extern int dopciupdateresource;
#endif
//-------------------------- pcibios_update_resource ---------------------------
void pcibios_update_resource(struct pci_dev *dev,struct resource *root
,struct resource *res,int resource)
{
u32 newr,check;
int reg;
newr=res->start | (res->flags & PCI_REGION_FLAG_MASK);
if(resource<6)
reg=PCI_BASE_ADDRESS_0+4*resource;
else if(resource==PCI_ROM_RESOURCE)
{
res->flags|=PCI_ROM_ADDRESS_ENABLE;
newr|=PCI_ROM_ADDRESS_ENABLE;
reg=dev->rom_base_reg;
}
else
// Somebody might have asked allocation of a non-standard resource
return;
#ifdef TARGET_OS2
if(0==dopciupdateresource)
return;
#endif
pci_write_config_dword(dev,reg,newr);
pci_read_config_dword(dev,reg,&check);
if((newr^check)&((newr&PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK))
{
CPK(printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n"
,dev->slot_name, resource,newr, check));
}
}
//--------------------------- pcibios_align_resource ---------------------------
void pcibios_align_resource(void *data,struct resource *res,unsigned long size)
{
if(res->flags&IORESOURCE_IO)
{
unsigned long start=res->start;
if(start & 0x300)
{
start=(start+0x3ff)&~0x3ff;
res->start=start;
}
}
}
//----------------------- pcibios_allocate_bus_resources -----------------------
static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
{
struct list_head *ln;
struct pci_bus *bus;
struct pci_dev *dev;
int idx;
struct resource *r,*pr;
// Depth-First Search on bus tree
for(ln=bus_list->next;ln!=bus_list;ln=ln->next)
{
bus=pci_bus_b(ln);
if((dev=bus->self))
{
for(idx=PCI_BRIDGE_RESOURCES;idx<PCI_NUM_RESOURCES;idx++)
{
r=&dev->resource[idx];
if(!r->start)
continue;
pr=pci_find_parent_resource(dev,r);
if(!pr || request_resource(pr,r)<0)
CPK(printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n"
,idx,dev->slot_name));
}
}
pcibios_allocate_bus_resources(&bus->children);
}
}
//------------------------- pcibios_allocate_resources -------------------------
static void __init pcibios_allocate_resources(int pass)
{
struct pci_dev *dev;
int idx,disabled;
u16 command;
struct resource *r,*pr;
pci_for_each_dev(dev)
{
pci_read_config_word(dev,PCI_COMMAND,&command);
for(idx=0;idx<6;idx++)
{
r=&dev->resource[idx];
if(r->parent) // Already allocated
continue;
if(!r->start) // Address not assigned at all
continue;
if(r->flags & IORESOURCE_IO)
disabled=!(command & PCI_COMMAND_IO);
else
disabled=!(command & PCI_COMMAND_MEMORY);
if(pass==disabled)
{
CPK(printk("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n"
,r->start,r->end,r->flags,disabled,pass));
pr=pci_find_parent_resource(dev,r);
if(!pr||request_resource(pr,r)<0)
{
CPK(printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n"
,idx,dev->slot_name));
// We'll assign a new address later
r->end-=r->start;
r->start=0;
}
}
}
if(!pass)
{
r=&dev->resource[PCI_ROM_RESOURCE];
if(r->flags & PCI_ROM_ADDRESS_ENABLE)
{ // Turn the ROM off, leave the resource region, but keep it unregistered
u32 reg;
CPK(printk("PCI: Switching off ROM of %s\n",dev->slot_name));
r->flags&=~PCI_ROM_ADDRESS_ENABLE;
pci_read_config_dword(dev,dev->rom_base_reg,®);
#ifdef TARGET_OS2
if(0!=dopciupdateresource)
#endif
pci_write_config_dword(dev,dev->rom_base_reg,reg & ~PCI_ROM_ADDRESS_ENABLE);
}
}
}
}
//-------------------------- pcibios_assign_resources --------------------------
static void __init pcibios_assign_resources(void)
{
struct pci_dev *dev;
int idx;
struct resource *r;
pci_for_each_dev(dev)
{
int dclass=dev->pciclass>>8;
// Don't touch classless devices and host bridges
if(!dclass || dclass==PCI_CLASS_BRIDGE_HOST)
continue;
for(idx=0;idx<6;idx++)
{
r=&dev->resource[idx];
// Don't touch IDE controllers and I/O ports of video cards!
if((dclass==PCI_CLASS_STORAGE_IDE && idx<4) ||
(dclass==PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
continue;
// We shall assign a new address to this resource, either because
// the BIOS forgot to do so or because we have decided the old
// address was unusable for some reason
if(!r->start && r->end)
pci_assign_resource(dev,idx);
}
if(pci_probe & PCI_ASSIGN_ROMS)
{
r=&dev->resource[PCI_ROM_RESOURCE];
r->end-=r->start;
r->start=0;
if(r->end)
pci_assign_resource(dev,PCI_ROM_RESOURCE);
}
}
}
//-------------------------- pcibios_resource_survey ---------------------------
void __init pcibios_resource_survey(void)
{
CPK(printk("PCI: Allocating resources\n"));
pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
}
//-------------------------- pcibios_enable_resources --------------------------
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd,old_cmd;
int idx;
struct resource *r;
pci_read_config_word(dev,PCI_COMMAND,&cmd);
old_cmd=cmd;
for(idx=0;idx<6;idx++)
{
r=&dev->resource[idx];
if(!r->start && r->end)
{
CPK(printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n"
,dev->slot_name));
return -EINVAL;
}
if(r->flags&IORESOURCE_IO)
cmd|=PCI_COMMAND_IO;
if(r->flags&IORESOURCE_MEM)
cmd|=PCI_COMMAND_MEMORY;
}
if(dev->resource[PCI_ROM_RESOURCE].start)
cmd|=PCI_COMMAND_MEMORY;
if(cmd!=old_cmd)
{
CPK(printk("PCI: Enabling device %s (%04x -> %04x)\n"
,dev->slot_name, old_cmd, cmd));
#ifdef TARGET_OS2
if(0!=dopcienable)
#endif
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
unsigned int pcibios_max_latency = 255;
//----------------------------- pcibios_set_master -----------------------------
void pcibios_set_master(struct pci_dev *dev)
{
u8 lat;
pci_read_config_byte(dev,PCI_LATENCY_TIMER,&lat);
if(lat<16)
lat=(64<=pcibios_max_latency) ? 64 : pcibios_max_latency;
else if(lat>pcibios_max_latency)
lat=pcibios_max_latency;
else
return;
CPK(printk("PCI: Setting latency timer of device %s to %d\n"
,dev->slot_name,lat));
#ifdef TARGET_OS2
if(0!=dopcisetmaster)
#endif
pci_write_config_byte(dev,PCI_LATENCY_TIMER,lat);
}