home *** CD-ROM | disk | FTP | other *** search
- /* $Id: pci.c,v 1.2 2002/04/26 23:09:35 smilcke Exp $ */
-
- /*
- * pci.c
- * Autor: Stefan Milcke
- * Erstellt am: 25.10.2001
- * Letzte Aenderung am: 09.04.2002
- *
- */
-
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/poll.h>
- #include <asm/uaccess.h>
- #include <asm/hardirq.h>
- #include <asm/io.h>
- #include <asm/delay.h>
- #include <linux/pci.h>
- #include <linux/slab.h>
- #include <linux/module.h>
-
- #ifndef FAR
- #define FAR_LDEFOS2
- #endif
- #include <ldefos2.h>
- #ifdef FAR_LDEFOS2
- #undef FAR
- #undef FAR_LDEFOS2
- #endif
-
- #define INCL_NOPMAPI
- #include <os2.h>
- #include <lxrmcall.h>
-
- #define LINUX
- #include <stacktoflat.h>
-
- #define PCI_CONFIG_ADDRESS 0xCF8
- #define PCI_CONFIG_DATA 0xCFC
- #define PCI_CONFIG_ENABLE 0x80000000
-
- LIST_HEAD(pci_root_buses);
- LIST_HEAD(pci_devices);
-
- LIST_HEAD(pci_drivers);
- extern void dev_probe_lock(void);
- extern void dev_probe_unlock(void);
-
- #ifdef TARGET_OS2
- extern int dopcifixups;
- extern int dopcienable;
- extern int dopcisetmaster;
- extern int dopcisetpowerstate;
- extern int dopciupdateresource;
- MODULE_PARM_LIST_HEAD(pcidrv_parms)
- MODULE_PARM(dopcifixups,"i")
- MODULE_PARM(dopcienable,"i")
- MODULE_PARM(dopcisetmaster,"i")
- MODULE_PARM(dopcisetpowerstate,"i")
- MODULE_PARM(dopciupdateresource,"i")
- MODULE_PARM_LIST_TAIL(pcidrv_parms)
- #endif
-
- //----------------------------- pci_enable_device ------------------------------
- int pci_enable_device(struct pci_dev *dev)
- {
- int err;
- #ifdef TARGET_OS2
- if(0==dopcienable)
- return 0;
- #endif
- pci_set_power_state(dev,0);
- if((err=pcibios_enable_device(dev))<0)
- return err;
- return 0;
- }
-
- //----------------------------- pci_disable_device -----------------------------
- void pci_disable_device(struct pci_dev *dev)
- {
- u16 pci_command;
- pci_read_config_word(dev,PCI_COMMAND,&pci_command);
- if(pci_command & PCI_COMMAND_MASTER)
- {
- pci_command&=~PCI_COMMAND_MASTER;
- #ifdef TARGET_OS2
- if(0!=dopcienable)
- #endif
- pci_write_config_word(dev,PCI_COMMAND,pci_command);
- }
- }
-
- //------------------------------ pci_match_device ------------------------------
- const struct pci_device_id *pci_match_device(const struct pci_device_id *ids
- ,const struct pci_dev *dev)
- {
- while(ids->vendor||ids->subvendor||ids->class_mask)
- {
- if((ids->vendor==PCI_ANY_ID || ids->vendor==dev->vendor) &&
- (ids->device==PCI_ANY_ID || ids->device==dev->device) &&
- (ids->subvendor==PCI_ANY_ID || ids->subvendor==dev->subsystem_vendor) &&
- (ids->subdevice==PCI_ANY_ID || ids->subdevice==dev->subsystem_device) &&
- !((ids->pciclass ^ dev->pciclass) & ids->class_mask))
- return ids;
- ids++;
- }
- return NULL;
- }
-
- #ifdef TARGET_OS2
- unsigned long OS2_pci_announce_device(struct pci_driver *drv,struct pci_dev *dev);
- #endif
- //---------------------------- pci_announce_device -----------------------------
- static int pci_announce_device(struct pci_driver *drv,struct pci_dev *dev)
- {
- const struct pci_device_id *id;
- int ret=0;
- if(drv->id_table)
- {
- id=pci_match_device(drv->id_table,dev);
- if(!id)
- {
- ret=0;
- goto out;
- }
- }
- else
- id=NULL;
- dev_probe_lock();
- if(drv->probe(dev,id)>=0)
- {
- dev->driver=drv;
- #ifdef TARGET_OS2
- OS2_pci_announce_device(drv,dev);
- #endif
- ret=1;
- }
- dev_probe_unlock();
- out:
- return ret;
- }
-
- #ifdef TARGET_OS2
- unsigned long OS2_pci_register_driver(struct pci_driver *drv);
- unsigned long OS2_pci_unregister_driver(struct pci_driver *drv);
- #endif
- //---------------------------- pci_register_driver -----------------------------
- int pci_register_driver(struct pci_driver *drv)
- {
- struct pci_dev *dev;
- int count=0;
- list_add_tail(&drv->node,&pci_drivers);
- #ifdef TARGET_OS2
- OS2_pci_register_driver(drv);
- #endif
- pci_for_each_dev(dev)
- {
- if(!pci_dev_driver(dev))
- count+=pci_announce_device(drv,dev);
- }
- return count;
- }
-
- //--------------------------- pci_unregister_driver ----------------------------
- void pci_unregister_driver(struct pci_driver *drv)
- {
- struct pci_dev *dev;
- list_del(&drv->node);
- pci_for_each_dev(dev)
- {
- if(dev->driver==drv)
- {
- if(drv->remove)
- drv->remove(dev);
- dev->driver=NULL;
- }
- }
- #ifdef TARGET_OS2
- OS2_pci_unregister_driver(drv);
- #endif
- }
-
- //----------------------- pci_announce_device_to_drivers -----------------------
- void pci_announce_device_to_drivers(struct pci_dev *dev)
- {
- struct list_head *ln;
- for(ln=pci_drivers.next;ln!=&pci_drivers;ln=ln->next)
- {
- struct pci_driver *drv=list_entry(ln,struct pci_driver,node);
- if(drv->remove && pci_announce_device(drv,dev))
- break;
- }
- // run_sbin_hotplug(dev,TRUE);
- }
-
- //----------------------------- pci_insert_device ------------------------------
- void pci_insert_device(struct pci_dev *dev,struct pci_bus *bus)
- {
- list_add_tail(&dev->bus_list,&bus->devices);
- list_add_tail(&dev->global_list,&pci_devices);
- pci_announce_device_to_drivers(dev);
- }
-
- //----------------------------- pci_free_resources -----------------------------
- static void pci_free_resources(struct pci_dev *dev)
- {
- int i;
- for(i=0;i<PCI_NUM_RESOURCES;i++)
- {
- struct resource *res=dev->resource+i;
- if(res->parent)
- release_resource(res);
- }
- }
-
- //----------------------------- pci_remove_device ------------------------------
- void pci_remove_device(struct pci_dev *dev)
- {
- if(dev->driver)
- {
- if(dev->driver->remove)
- dev->driver->remove(dev);
- dev->driver=NULL;
- }
- list_del(&dev->bus_list);
- list_del(&dev->global_list);
- pci_free_resources(dev);
- // run_sbin_hotplug(dev,FALSE);
- }
-
- static struct pci_driver pci_compat_driver={0};
-
- //------------------------------- pci_dev_driver -------------------------------
- struct pci_driver *pci_dev_driver(const struct pci_dev *dev)
- {
- if(dev->driver)
- return dev->driver;
- else
- {
- int i;
- for(i=0;i<=PCI_ROM_RESOURCE;i++)
- if(dev->resource[i].flags & IORESOURCE_BUSY)
- {
- pci_compat_driver.name="compat";
- return &pci_compat_driver;
- }
- }
- return NULL;
- }
-
- //------------------------------- pci_find_slot --------------------------------
- struct pci_dev *pci_find_slot(unsigned int bus,unsigned int devfn)
- {
- struct pci_dev *dev;
- pci_for_each_dev(dev)
- {
- if(dev->bus->number==bus && dev->devfn==devfn)
- return dev;
- }
- return NULL;
- }
-
- //------------------------------ pci_find_subsys -------------------------------
- struct pci_dev *pci_find_subsys(unsigned int vendor,unsigned int device
- ,unsigned int ss_vendor,unsigned int ss_device
- ,const struct pci_dev *from)
- {
- struct list_head *n=from ? from->global_list.next : pci_devices.next;
- while(n!=&pci_devices)
- {
- struct pci_dev *dev=pci_dev_g(n);
- if((vendor==PCI_ANY_ID || dev->vendor==vendor) &&
- (device==PCI_ANY_ID || dev->device==device) &&
- (ss_vendor==PCI_ANY_ID || dev->subsystem_vendor==ss_vendor) &&
- (ss_device==PCI_ANY_ID || dev->subsystem_device==ss_device))
- return dev;
- n=n->next;
- }
- return NULL;
- }
-
- //------------------------------ pci_find_device -------------------------------
- struct pci_dev *pci_find_device(unsigned int vendor,unsigned int device
- ,const struct pci_dev *from)
- {
- return pci_find_subsys(vendor,device,PCI_ANY_ID,PCI_ANY_ID,from);
- }
-
- //------------------------------- pci_find_class -------------------------------
- struct pci_dev *pci_find_class(unsigned int pciclass, const struct pci_dev *from)
- {
- struct list_head *n = from ? from->global_list.next : pci_devices.next;
- while (n != &pci_devices)
- {
- struct pci_dev *dev = pci_dev_g(n);
- if (dev->pciclass == pciclass)
- return dev;
- n = n->next;
- }
- return NULL;
- }
-
- //---------------------------- pci_find_capability -----------------------------
- int pci_find_capability(struct pci_dev *dev, int cap)
- {
- u16 status;
- u8 pos, id;
- int ttl = 48;
- pci_read_config_word(dev, PCI_STATUS, &status);
- if (!(status & PCI_STATUS_CAP_LIST))
- return 0;
- switch (dev->hdr_type)
- {
- case PCI_HEADER_TYPE_NORMAL:
- case PCI_HEADER_TYPE_BRIDGE:
- pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
- break;
- case PCI_HEADER_TYPE_CARDBUS:
- pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
- break;
- default:
- return 0;
- }
- while (ttl-- && pos >= 0x40)
- {
- pos &= ~3;
- pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
- if (id == 0xff)
- break;
- if (id == cap)
- return pos;
- pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
- }
- return 0;
- }
-
- //-------------------------- pci_find_parent_resource --------------------------
- struct resource *pci_find_parent_resource(const struct pci_dev *dev
- ,struct resource *res)
- {
- const struct pci_bus *bus=dev->bus;
- int i;
- struct resource *best=NULL;
- for(i=0;i<4;i++)
- {
- struct resource *r=bus->resource[i];
- if(!r)
- continue;
- if(res->start && !(res->start>=r->start && res->end<=r->end))
- continue;
- if((res->flags^r->flags)&(IORESOURCE_IO | IORESOURCE_MEM))
- continue;
- if(!((res->flags^r->flags)&IORESOURCE_PREFETCH))
- return r;
- if((res->flags&IORESOURCE_PREFETCH)&&!(r->flags&IORESOURCE_PREFETCH))
- best=r;
- }
- return best;
- }
-
- //---------------------------- pci_set_power_state -----------------------------
- int pci_set_power_state(struct pci_dev *dev,int state)
- {
- int pm;
- u16 pmcsr;
- #ifdef TARGET_OS2
- if(0==dopcisetpowerstate)
- return 0;
- #endif
- if(state>3)
- state=3;
- if(state>0 && dev->current_state>state)
- return -EINVAL;
- else if(dev->current_state==state)
- return 0;
- pm=pci_find_capability(dev,PCI_CAP_ID_PM);
- if(!pm)
- return -EIO;
- if(state==1 || state==2)
- {
- u16 pmc;
- pci_read_config_word(dev,pm+PCI_PM_PMC,&pmc);
- if(state==1 && !(pmc&PCI_PM_CAP_D1))
- return -EIO;
- else if(state==2 && !(pmc&PCI_PM_CAP_D2))
- return -EIO;
- }
- if(dev->current_state>=3)
- pmcsr=0;
- else
- {
- pci_read_config_word(dev,pm+PCI_PM_CTRL,&pmcsr);
- pmcsr&=~PCI_PM_CTRL_STATE_MASK;
- pmcsr|=state;
- }
- pci_write_config_word(dev,pm+PCI_PM_CTRL,pmcsr);
- if(state==3 || dev->current_state==3)
- {
- // Incomplete (SM)
- // set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/100);
- }
- else if(state==2 || dev->current_state==2)
- udelay(200);
- dev->current_state=state;
- return 0;
- }
-
- #define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
- //---------------------------- pci_read_config_byte ----------------------------
- int pci_read_config_byte(struct pci_dev *dev, int where, u8 *value)
- {
- outl(CONFIG_CMD(dev,where), 0xCF8);
- *value = inb(0xCFC + (where&3));
- return PCIBIOS_SUCCESSFUL;
- }
-
- //---------------------------- pci_read_config_word ----------------------------
- int pci_read_config_word(struct pci_dev *dev, int where, u16 *value)
- {
- outl(CONFIG_CMD(dev,where), 0xCF8);
- *value = inw(0xCFC + (where&2));
- return PCIBIOS_SUCCESSFUL;
- }
-
- //--------------------------- pci_read_config_dword ----------------------------
- int pci_read_config_dword(struct pci_dev *dev, int where, u32 *value)
- {
- outl(CONFIG_CMD(dev,where), 0xCF8);
- *value = inl(0xCFC);
- return PCIBIOS_SUCCESSFUL;
- }
-
- //--------------------------- pci_write_config_byte ----------------------------
- int pci_write_config_byte(struct pci_dev *dev, int where, u8 value)
- {
- outl(CONFIG_CMD(dev,where), 0xCF8);
- outb(value, 0xCFC + (where&3));
- return PCIBIOS_SUCCESSFUL;
- }
-
- //--------------------------- pci_write_config_word ----------------------------
- int pci_write_config_word(struct pci_dev *dev, int where, u16 value)
- {
- outl(CONFIG_CMD(dev,where), 0xCF8);
- outw(value, 0xCFC + (where&2));
- return PCIBIOS_SUCCESSFUL;
- }
-
- //--------------------------- pci_write_config_dword ---------------------------
- int pci_write_config_dword(struct pci_dev *dev, int where, u32 value)
- {
- outl(CONFIG_CMD(dev,where), 0xCF8);
- outl(value, 0xCFC);
- return PCIBIOS_SUCCESSFUL;
- }
-
- //-------------------------- pci_calc_resource_flags ---------------------------
- static __inline__ unsigned int pci_calc_resource_flags(unsigned int flags)
- {
- if(flags&PCI_BASE_ADDRESS_SPACE_IO)
- return IORESOURCE_IO;
- if(flags&PCI_BASE_ADDRESS_MEM_PREFETCH)
- return IORESOURCE_MEM | IORESOURCE_PREFETCH;
- return IORESOURCE_MEM;
- }
-
- //---------------------------------- pci_size ----------------------------------
- static u32 pci_size(u32 base,unsigned long mask)
- {
- u32 size=mask&base; // find the significant bits
- size=size&~(size-1); // get the lowest of them to find the decode size
- return size-1; // extend=size-1
- }
-
- //------------------------------- pci_set_master -------------------------------
- void pci_set_master(struct pci_dev *dev)
- {
- u16 cmd;
- pci_read_config_word(dev,PCI_COMMAND,&cmd);
- if(!(cmd&PCI_COMMAND_MASTER))
- {
- // DBG("PCI: Enabling bus mastering for device %s\n",dev->slot_name);
- cmd|=PCI_COMMAND_MASTER;
- #ifdef TARGET_OS2
- if(0!=dopcisetmaster)
- #endif
- pci_write_config_word(dev,PCI_COMMAND,cmd);
- }
- pcibios_set_master(dev);
- }
-
- //------------------------------- pci_read_bases -------------------------------
- static void pci_read_bases(struct pci_dev *dev,unsigned int howmany,int rom)
- {
- unsigned int pos,reg,next;
- u32 l,sz;
- struct resource *res;
- for(pos=0;pos<howmany;pos=next)
- {
- next=pos+1;
- res=&dev->resource[pos];
- res->name=dev->name;
- reg=PCI_BASE_ADDRESS_0 + (pos << 2);
- pci_read_config_dword(dev,reg,&l);
- pci_write_config_dword(dev,reg,~0);
- pci_read_config_dword(dev,reg,&sz);
- pci_write_config_dword(dev,reg,l);
- if(!sz || sz==0xffffffff)
- continue;
- if(l==0xffffffff)
- l=0;
- if((l&PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_MEMORY)
- {
- res->start=l&PCI_BASE_ADDRESS_MEM_MASK;
- sz=pci_size(sz,PCI_BASE_ADDRESS_MEM_MASK);
- }
- else
- {
- res->start=l&PCI_BASE_ADDRESS_IO_MASK;
- sz=pci_size(sz,PCI_BASE_ADDRESS_IO_MASK & 0xffff);
- }
- res->end=res->start+(unsigned long)sz;
- res->flags|=(l&0xf) | pci_calc_resource_flags(l);
- if((l&(PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- ==(PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64))
- {
- pci_read_config_dword(dev,reg+4,&l);
- next++;
- #if BITS_PER_LONG==64
- res->start|=((unsigned long)l)<<32;
- res->end=res->start+sz;
- pci_write_config_dword(dev,reg+4,~0);
- pci_read_config_dword(dev,reg+4,&sz);
- pci_write_config_dword(dev,reg+4,l);
- if(~sz)
- res->end=res->start+0xffffffff+(((unsigned long)~sz)<<32);
- #else
- if(l)
- {
- res->start=0;
- res->flags=0;
- continue;
- }
- #endif
- }
- }
- if(rom)
- {
- dev->rom_base_reg=rom;
- res=&dev->resource[PCI_ROM_RESOURCE];
- pci_read_config_dword(dev,rom,&l);
- pci_write_config_dword(dev,rom,~PCI_ROM_ADDRESS_ENABLE);
- pci_read_config_dword(dev,rom,&sz);
- pci_write_config_dword(dev,rom,l);
- if(l==0xffffffff)
- l=0;
- if(sz && sz!=0xffffffff)
- {
- res->flags=(l&PCI_ROM_ADDRESS_ENABLE)
- | IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
- res->start=l&PCI_ROM_ADDRESS_MASK;
- sz=pci_size(sz,PCI_ROM_ADDRESS_MASK);
- res->end=res->start+(unsigned long)sz;
- }
- res->name=dev->name;
- }
- }
-
- //--------------------------- pci_read_bridge_bases ----------------------------
- void __init pci_read_bridge_bases(struct pci_bus *child)
- {
- struct pci_dev *dev=child->self;
- u8 io_base_lo,io_limit_lo;
- u16 mem_base_lo,mem_limit_lo;
- unsigned long base,limit;
- struct resource *res;
- int i;
- if(!dev)
- return;
- for(i=0;i<3;i++)
- child->resource[i]=&dev->resource[PCI_BRIDGE_RESOURCES+i];
- res=child->resource[0];
- 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)<<8;
- limit=(io_limit_lo & PCI_IO_RANGE_MASK)<<8;
- if((base&PCI_IO_RANGE_TYPE_MASK)==PCI_IO_RANGE_TYPE_32)
- {
- u16 io_base_hi,io_limit_hi;
- pci_read_config_word(dev,PCI_IO_BASE_UPPER16,&io_base_hi);
- pci_read_config_word(dev,PCI_IO_LIMIT_UPPER16,&io_limit_hi);
- base|=(io_base_hi<<16);
- limit|=(io_limit_hi<<16);
- }
- if(base && base <= limit)
- {
- res->flags=(io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
- res->start=base;
- res->end=limit+0xfff;
- res->name=child->name; // ??? (SM)
- }
- else
- {
- // Ugh. We don't know enough about this bridge. Just assume
- // that it's entirely transparent
- CPK(printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n",0));
- child->resource[0]=child->parent->resource[0];
- }
- res=child->resource[1];
- pci_read_config_word(dev,PCI_MEMORY_BASE,&mem_base_lo);
- pci_read_config_word(dev,PCI_MEMORY_LIMIT,&mem_limit_lo);
- base=(mem_base_lo & PCI_MEMORY_RANGE_MASK)<<16;
- limit=(mem_limit_lo & PCI_MEMORY_RANGE_MASK)<<16;
- if(base && base <= limit)
- {
- res->flags=(mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
- res->start=base;
- res->end=limit+0xfffff;
- res->name=child->name; // ??? (SM)
- }
- else
- {
- // Ugh. We don't know enough about this bridge. Just assume
- // that it's entirely transparent
- CPK(printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n",1));
- child->resource[1]=child->parent->resource[1];
- }
- res=child->resource[2];
- pci_read_config_word(dev,PCI_PREF_MEMORY_BASE,&mem_base_lo);
- pci_read_config_word(dev,PCI_PREF_MEMORY_LIMIT,&mem_limit_lo);
- base=(mem_base_lo & PCI_PREF_RANGE_MASK)<<16;
- limit=(mem_limit_lo & PCI_PREF_RANGE_MASK)<<16;
- if((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK)==PCI_PREF_RANGE_TYPE_64)
- {
- u32 mem_base_hi,mem_limit_hi;
- pci_read_config_dword(dev,PCI_PREF_BASE_UPPER32,&mem_base_hi);
- pci_read_config_dword(dev,PCI_PREF_LIMIT_UPPER32,&mem_limit_hi);
- #if BITS_PER_LONG==64
- base |=((long)mem_base_hi)<<32;
- limit |=((long)mem_limit_hi)<<32;
- #else
- if(mem_base_hi || mem_limit_hi)
- {
- CPK(printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n",child->name));
- return;
- }
- #endif
- }
- if(base & base <= limit)
- {
- res->flags=(mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
- res->start=base;
- res->end=limit+0xfffff;
- res->name=child->name; // ??? (SM)
- }
- else
- {
- // Ugh. We don't know enough about this bridge. Just assume
- // that it's entirely transparent
- CPK(printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n",2));
- child->resource[2]=child->parent->resource[2];
- }
- }
-
- //------------------------------- pci_alloc_bus --------------------------------
- static struct pci_bus *pci_alloc_bus(void)
- {
- struct pci_bus *b;
- b=kmalloc(sizeof(*b),GFP_KERNEL);
- if(b)
- {
- memset(b,0,sizeof(*b));
- INIT_LIST_HEAD(&b->children);
- INIT_LIST_HEAD(&b->devices);
- }
- return b;
- }
-
- //------------------------------ pci_add_new_bus -------------------------------
- static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent
- ,struct pci_dev *dev
- ,int busnr)
- {
- struct pci_bus *child;
- int i;
- child=pci_alloc_bus();
- list_add_tail(&child->node,&parent->children);
- child->self=dev;
- dev->subordinate=child;
- child->parent=parent;
- child->ops=parent->ops;
- child->sysdata=parent->sysdata;
- child->number=child->secondary=busnr;
- child->primary=parent->secondary;
- child->subordinate=0xff;
- for(i=0;i<4;i++)
- child->resource[i]=&dev->resource[PCI_BRIDGE_RESOURCES+i];
- return child;
- }
-
- static unsigned int __init pci_do_scan_bus(struct pci_bus *bus);
-
- //------------------------------ pci_scan_bridge -------------------------------
- static int __init pci_scan_bridge(struct pci_bus *bus,struct pci_dev *dev
- ,int maxb,int pass)
- {
- unsigned int buses;
- unsigned short cr;
- struct pci_bus *child;
- int is_cardbus=(dev->hdr_type==PCI_HEADER_TYPE_CARDBUS);
- pci_read_config_dword(dev,PCI_PRIMARY_BUS,&buses);
- if((buses&0xffff00) && !pcibios_assign_all_busses())
- {
- if(pass)
- return maxb;
- child=(struct pci_bus *)pci_add_new_bus(bus,dev,0);
- child->primary=buses&0xFF;
- child->secondary=(buses>>8)&0xFF;
- child->subordinate=(buses>>16)&0xFF;
- child->number=child->secondary;
- if(!is_cardbus)
- {
- unsigned int cmax=pci_do_scan_bus(child);
- if(cmax>maxb)
- maxb=cmax;
- }
- else
- {
- unsigned int cmax=child->subordinate;
- if(cmax>maxb)
- maxb=cmax;
- }
- }
- else
- {
- if(!pass)
- return maxb;
- pci_read_config_word(dev,PCI_COMMAND,&cr);
- pci_write_config_word(dev,PCI_COMMAND,0x0000);
- pci_write_config_word(dev,PCI_COMMAND,0xFFFF);
- child=(struct pci_bus *)pci_add_new_bus(bus,dev,++maxb);
- buses=(buses&0xff000000)
- |((unsigned int)(child->primary)<<0)
- |((unsigned int)(child->secondary)<<8)
- |((unsigned int)(child->subordinate)<<16);
- pci_write_config_dword(dev,PCI_PRIMARY_BUS,buses);
- if(!is_cardbus)
- maxb=pci_do_scan_bus(child);
- else
- maxb+=3;
- child->subordinate=maxb;
- pci_write_config_byte(dev,PCI_SUBORDINATE_BUS,maxb);
- pci_write_config_word(dev,PCI_COMMAND,cr);
- }
- sprintf(child->name,(is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"),child->number);
- return maxb;
- }
-
- //-------------------------------- pci_read_irq --------------------------------
- static void pci_read_irq(struct pci_dev *dev)
- {
- unsigned char irq;
- pci_read_config_byte(dev,PCI_INTERRUPT_PIN,&irq);
- if(irq)
- pci_read_config_byte(dev,PCI_INTERRUPT_LINE,&irq);
- dev->irq=irq;
- }
-
- //------------------------------ pci_setup_device ------------------------------
- int pci_setup_device(struct pci_dev *dev)
- {
- u32 dclass;
- sprintf(dev->slot_name,"%02x:%02x.%d"
- ,dev->bus->number
- ,PCI_SLOT(dev->devfn)
- ,PCI_FUNC(dev->devfn));
- sprintf(dev->name,"PCI device %04x:%04x"
- ,dev->vendor
- ,dev->device);
- pci_read_config_dword(dev,PCI_CLASS_REVISION,&dclass);
- dclass >>=8;
- dev->pciclass=dclass;
- dclass >>=8;
- dev->current_state=4;
- switch(dev->hdr_type)
- {
- case PCI_HEADER_TYPE_NORMAL:
- if(dclass==PCI_CLASS_BRIDGE_PCI)
- goto bad;
- pci_read_irq(dev);
- pci_read_bases(dev,6,PCI_ROM_ADDRESS);
- pci_read_config_word(dev,PCI_SUBSYSTEM_VENDOR_ID,&dev->subsystem_vendor);
- pci_read_config_word(dev,PCI_SUBSYSTEM_ID,&dev->subsystem_device);
- break;
- case PCI_HEADER_TYPE_BRIDGE:
- if(dclass!=PCI_CLASS_BRIDGE_PCI)
- goto bad;
- pci_read_bases(dev,2,PCI_ROM_ADDRESS1);
- break;
- case PCI_HEADER_TYPE_CARDBUS:
- if(dclass!=PCI_CLASS_BRIDGE_CARDBUS)
- goto bad;
- pci_read_irq(dev);
- pci_read_bases(dev,1,0);
- pci_read_config_word(dev,PCI_SUBSYSTEM_VENDOR_ID,&dev->subsystem_vendor);
- pci_read_config_word(dev,PCI_SUBSYSTEM_ID,&dev->subsystem_device);
- break;
- default:
- return -1;
- bad:
- dev->pciclass=PCI_CLASS_NOT_DEFINED;
- }
- return 0;
- }
-
- //------------------------------ pci_scan_device -------------------------------
- static struct pci_dev *pci_scan_device(struct pci_dev *temp)
- {
- struct pci_dev *dev;
- u32 l;
- if(pci_read_config_dword(temp,PCI_VENDOR_ID,&l))
- return NULL;
- if(l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
- return NULL;
- dev=kmalloc(sizeof(*dev),GFP_KERNEL);
- if(!dev)
- return NULL;
- memcpy(dev,temp,sizeof(*dev));
- dev->vendor=l&0xffff;
- dev->device=(l>>16)&0xffff;
- // Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
- // set this higher, assuming the system even supports it;
- dev->dma_mask=0xffffffff;
- if(pci_setup_device(dev)<0)
- {
- kfree(dev);
- dev=NULL;
- }
- #ifdef TARGET_OS2
- dev->rm_subadapter=kmalloc(sizeof(struct lxrm_subadapter),0);
- memset(dev->rm_subadapter,0,sizeof(struct lxrm_subadapter));
- dev->rm_subdevice=kmalloc(sizeof(struct lxrm_subdevice),0);
- memset(dev->rm_subdevice,0,sizeof(struct lxrm_subdevice));
- #endif
- return dev;
- }
-
- //------------------------------- pci_scan_slot --------------------------------
- struct pci_dev *pci_scan_slot(struct pci_dev *temp)
- {
- struct pci_bus *bus=temp->bus;
- struct pci_dev *dev;
- struct pci_dev *first_dev=NULL;
- int func=0;
- int is_multi=0;
- u8 hdr_type;
- for(func=0;func<8;func++,temp->devfn++)
- {
- if(func&&!is_multi)
- continue;
- if(pci_read_config_byte(temp,PCI_HEADER_TYPE,&hdr_type))
- continue;
- temp->hdr_type=hdr_type&0x7f;
- dev=pci_scan_device(temp);
- if(!dev)
- continue;
- pci_name_device(dev);
- if(!func)
- {
- is_multi=hdr_type&0x80;
- first_dev=dev;
- }
- list_add_tail(&dev->global_list,&pci_devices);
- list_add_tail(&dev->bus_list,&bus->devices);
- pci_fixup_device(PCI_FIXUP_HEADER,dev);
- }
- return first_dev;
- }
-
- //------------------------------ pci_do_scan_bus -------------------------------
- static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
- {
- unsigned int devfn,maxb,pass;
- struct list_head *ln;
- struct pci_dev *dev,dev0;
- maxb=bus->secondary;
- memset(&dev0,0,sizeof(dev0));
- dev0.bus=bus;
- dev0.sysdata=bus->sysdata;
- for(devfn=0;devfn<0x100;devfn+=8)
- {
- dev0.devfn=devfn;
- pci_scan_slot(&dev0);
- }
- pcibios_fixup_bus(bus);
- for(pass=0;pass<2;pass++)
- for(ln=bus->devices.next;ln!=&bus->devices;ln=ln->next)
- {
- dev=pci_dev_b(ln);
- if(dev->hdr_type==PCI_HEADER_TYPE_BRIDGE || dev->hdr_type==PCI_HEADER_TYPE_CARDBUS)
- maxb=pci_scan_bridge(bus,dev,maxb,pass);
- }
- // (SM)
- return maxb;
- }
-
- //------------------------------- pci_bus_exists -------------------------------
- int pci_bus_exists(const struct list_head *list,int nr)
- {
- const struct list_head *l;
- for(l=list->next;l!=list;l=l->next)
- {
- const struct pci_bus *b=pci_bus_b(l);
- if(b->number==nr || pci_bus_exists(&b->children,nr))
- return 1;
- }
- return 0;
- }
-
- //--------------------------- pci_alloc_primary_bus ----------------------------
- struct pci_bus *pci_alloc_primary_bus(int bus)
- {
- struct pci_bus *b;
- if(pci_bus_exists(&pci_root_buses,bus))
- {
- return NULL;
- }
- b=pci_alloc_bus();
- list_add_tail(&b->node,&pci_root_buses);
- b->number=b->secondary=bus;
- b->resource[0]=&ioport_resource;
- b->resource[1]=&iomem_resource;
- return b;
- }
-
- //-------------------------------- pci_scan_bus --------------------------------
- struct pci_bus *pci_scan_bus(int bus,struct pci_ops *ops,void *sysdata)
- {
- struct pci_bus *b=pci_alloc_primary_bus(bus);
- if(b)
- {
- b->sysdata=sysdata;
- b->ops=ops;
- b->subordinate=pci_do_scan_bus(b);
- }
- return b;
- }
-
- #ifdef TARGET_OS2
- void pci_name_device_free(void);
- #endif
-
- //---------------------------------- pci_init ----------------------------------
- void pci_init(void)
- {
- struct pci_dev *dev;
- pcibios_init();
- pci_for_each_dev(dev)
- pci_fixup_device(PCI_FIXUP_FINAL,dev);
- #ifdef CONFIG_PM
- pm_register(PM_PCI_DEV,0,pci_pm_callback);
- #endif
- #ifdef TARGET_OS2
- pci_name_device_free();
- #endif
- }
-