📄 pci.c
字号:
tmp = *area; for (r=first; r!=past; r=r->next) { alloc_space(&tmp, r); }}#define BUS0_IO_START 0x10000#define BUS0_IO_END 0x1ffff#define BUS0_MEM_START 0x1000000#define BUS0_MEM_END 0x3f00000#define BUSREST_IO_START 0x20000#define BUSREST_IO_END 0x7ffff#define BUSREST_MEM_START 0x4000000#define BUSREST_MEM_END 0x10000000static void reconfigure_pci(void) { pci_resource *r; struct pci_dev *dev; /* FIXME: for now memory is relocated from low, it's better * to start from higher addresses. */ /* init_free_area(&pci->io, 0x10000, 0x7fffff, 0xfff, 0); init_free_area(&pci->mem, 0x1000000, 0x3cffffff, 0xfffff, 0); */ init_free_area(&pci->io, BUS0_IO_START, BUS0_IO_END, 0xfff, 0); init_free_area(&pci->mem, BUS0_MEM_START, BUS0_MEM_END, 0xfffff, 0); /* First reconfigure the I/O space, this will be more * complex when there is more than 1 bus. And 64 bits * devices are another kind of problems. */ reconfigure_bus_space(0, PCI_AREA_IO, &pci->io); reconfigure_bus_space(0, PCI_AREA_MEMORY, &pci->mem); reconfigure_bus_space(0, PCI_AREA_PREFETCHABLE, &pci->mem); /* Now we have to touch the configuration space of all * the devices to remap them better than they are right now. * This is done in 3 steps: * 1) first disable I/O and memory response of all devices * 2) modify the base registers * 3) restore the original PCI_COMMAND register. */ for (r=pci->resources; r; r= r->next) { if (!r->dev->sysdata) { r->dev->sysdata=r; pci_read_config_word(r->dev, PCI_COMMAND, &r->cmd); pci_write_config_word(r->dev, PCI_COMMAND, r->cmd & ~(PCI_COMMAND_IO| PCI_COMMAND_MEMORY)); } } for (r=pci->resources; r; r= r->next) { pci_write_config_dword(r->dev, PCI_BASE_ADDRESS_0+(r->reg<<2), r->base); if ((r->type& (PCI_BASE_ADDRESS_SPACE| PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_SPACE_MEMORY| PCI_BASE_ADDRESS_MEM_TYPE_64)) { pci_write_config_dword(r->dev, PCI_BASE_ADDRESS_1+(r->reg<<2), 0); } } for (dev=bd->pci_devices; dev; dev= dev->next) { if (dev->sysdata) { pci_write_config_word(dev, PCI_COMMAND, ((pci_resource *)dev->sysdata) ->cmd); dev->sysdata=NULL; } }}static intindirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { out_be32(pci->config_addr, 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); *val=in_8(pci->config_data + (offset&3)); return PCIBIOS_SUCCESSFUL;}static intindirect_pci_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { *val = 0xffff; if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; out_be32(pci->config_addr, 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); *val=in_le16((volatile u_short *)(pci->config_data + (offset&3))); return PCIBIOS_SUCCESSFUL;}static intindirect_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { *val = 0xffffffff; if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; out_be32(pci->config_addr, 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24)); *val=in_le32((volatile u_int *)pci->config_data); return PCIBIOS_SUCCESSFUL;}static intindirect_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { out_be32(pci->config_addr, 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); out_8(pci->config_data + (offset&3), val); return PCIBIOS_SUCCESSFUL;}static intindirect_pci_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; out_be32(pci->config_addr, 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); out_le16((volatile u_short *)(pci->config_data + (offset&3)), val); return PCIBIOS_SUCCESSFUL;}static intindirect_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; out_be32(pci->config_addr, 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24)); out_le32((volatile u_int *)pci->config_data, val); return PCIBIOS_SUCCESSFUL;}static const struct pci_config_access_functions indirect_functions = { indirect_pci_read_config_byte, indirect_pci_read_config_word, indirect_pci_read_config_dword, indirect_pci_write_config_byte, indirect_pci_write_config_word, indirect_pci_write_config_dword};static intdirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) { *val=0xff; return PCIBIOS_DEVICE_NOT_FOUND; } *val=in_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1) + (PCI_FUNC(dev_fn)<<8) + offset); return PCIBIOS_SUCCESSFUL;}static intdirect_pci_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { *val = 0xffff; if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) { return PCIBIOS_DEVICE_NOT_FOUND; } *val=in_le16((volatile u_short *) (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1) + (PCI_FUNC(dev_fn)<<8) + offset)); return PCIBIOS_SUCCESSFUL;}static intdirect_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { *val = 0xffffffff; if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) { return PCIBIOS_DEVICE_NOT_FOUND; } *val=in_le32((volatile u_int *) (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1) + (PCI_FUNC(dev_fn)<<8) + offset)); return PCIBIOS_SUCCESSFUL;}static intdirect_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) { return PCIBIOS_DEVICE_NOT_FOUND; } out_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1) + (PCI_FUNC(dev_fn)<<8) + offset, val); return PCIBIOS_SUCCESSFUL;}static intdirect_pci_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) { return PCIBIOS_DEVICE_NOT_FOUND; } out_le16((volatile u_short *) (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1) + (PCI_FUNC(dev_fn)<<8) + offset), val); return PCIBIOS_SUCCESSFUL;}static intdirect_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) { return PCIBIOS_DEVICE_NOT_FOUND; } out_le32((volatile u_int *) (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1) + (PCI_FUNC(dev_fn)<<8) + offset), val); return PCIBIOS_SUCCESSFUL;}static const struct pci_config_access_functions direct_functions = { direct_pci_read_config_byte, direct_pci_read_config_word, direct_pci_read_config_dword, direct_pci_write_config_byte, direct_pci_write_config_word, direct_pci_write_config_dword};void pci_read_bases(struct pci_dev *dev, unsigned int howmany){ unsigned int reg, nextreg;#define REG (PCI_BASE_ADDRESS_0 + (reg<<2)) u_short cmd; u32 l, ml; pci_read_config_word(dev, PCI_COMMAND, &cmd); for(reg=0; reg<howmany; reg=nextreg) { pci_resource *r; nextreg=reg+1; pci_read_config_dword(dev, REG, &l);#if 0 if (l == 0xffffffff /*AJF || !l*/) continue; #endif /* Note that disabling the memory response of a host bridge * would lose data if a DMA transfer were in progress. In a * bootloader we don't care however. Also we can't print any * message for a while since we might just disable the console. */ pci_write_config_word(dev, PCI_COMMAND, cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)); pci_write_config_dword(dev, REG, ~0); pci_read_config_dword(dev, REG, &ml); pci_write_config_dword(dev, REG, l); /* Reenable the device now that we've played with * base registers. */ pci_write_config_word(dev, PCI_COMMAND, cmd); /* seems to be an unused entry skip it */ if ( ml == 0 || ml == 0xffffffff ) continue; if ((l & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_MEM_TYPE_64 |PCI_BASE_ADDRESS_SPACE_MEMORY)) { nextreg=reg+2; } dev->base_address[reg] = l; r = salloc(sizeof(pci_resource)); if (!r) { printk("Error allocating pci_resource struct.\n"); continue; } r->dev = dev; r->reg = reg; if ((l&PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { r->type = l&~PCI_BASE_ADDRESS_IO_MASK; r->base = l&PCI_BASE_ADDRESS_IO_MASK; /* r->size = ~(ml&PCI_BASE_ADDRESS_IO_MASK)+1; */ } else { r->type = l&~PCI_BASE_ADDRESS_MEM_MASK; r->base = l&PCI_BASE_ADDRESS_MEM_MASK; /* r->size = ~(ml&PCI_BASE_ADDRESS_MEM_MASK)+1; */ } /* find the first bit set to one after the base address type bits to find length of region */ { unsigned int c= 16 , val= 0; while( !(val= ml & c) ) c <<= 1; r->size = val; }#ifdef PCI_DEBUG printk(" readbase bus %d, (%04x:%04x), base %08x, size %08x, type %d\n", r->dev->bus->number, r->dev->vendor, r->dev->device, r->base, r->size, r->type );#endif /* Check for the blacklisted entries */ insert_resource(r); }}u_int pci_scan_bus(struct pci_bus *bus){ unsigned int devfn, l, max, class; unsigned char irq, hdr_type, is_multi = 0; struct pci_dev *dev, **bus_last; struct pci_bus *child;#if 0 printk("scanning pci bus %d\n", bus->number );#endif bus_last = &bus->devices; max = bus->secondary; for (devfn = 0; devfn < 0xff; ++devfn) { if (PCI_FUNC(devfn) && !is_multi) { /* not a multi-function device */ continue; } if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type)) continue; if (!PCI_FUNC(devfn)) is_multi = hdr_type & 0x80; if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) || /* some broken boards return 0 if a slot is empty: */ l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) { is_multi = 0; continue; } dev = salloc(sizeof(*dev)); dev->bus = bus; dev->devfn = devfn; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ dev->class = class; class >>= 8; dev->hdr_type = hdr_type; switch (hdr_type & 0x7f) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ if (class == PCI_CLASS_BRIDGE_PCI) goto bad; /* * If the card generates interrupts, read IRQ number * (some architectures change it during pcibios_fixup()) */ pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq); if (irq) pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq); dev->irq = irq; /* * read base address registers, again pcibios_fixup() can * tweak these */ pci_read_bases(dev, 6); pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l); dev->rom_address = (l == 0xffffffff) ? 0 : l; break; case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ if (class != PCI_CLASS_BRIDGE_PCI) goto bad; pci_read_bases(dev, 2); pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l); dev->rom_address = (l == 0xffffffff) ? 0 : l; break; case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ if (class != PCI_CLASS_BRIDGE_CARDBUS) goto bad; pci_read_bases(dev, 1); break; default: /* unknown header */ bad: printk("PCI device with unknown header type %d ignored.\n", hdr_type&0x7f); continue; } /* * Put it into the global PCI device chain. It's used to * find devices once everything is set up. */ *pci->last_dev_p = dev; pci->last_dev_p = &dev->next; /* * Now insert it into the list of devices held * by the parent bus. */ *bus_last = dev; bus_last = &dev->sibling; } /* * After performing arch-dependent fixup of the bus, look behind * all PCI-to-PCI bridges on this bus. */ for(dev=bus->devices; dev; dev=dev->sibling) /* * If it's a bridge, scan the bus behind it. */ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { unsigned int buses; unsigned int devfn = dev->devfn; unsigned short cr; /* * Insert it into the tree of buses. */ child = salloc(sizeof(*child)); child->next = bus->children; bus->children = child; child->self = dev; child->parent = bus; /* * Set up the primary, secondary and subordinate * bus numbers. */ child->number = child->secondary = ++max; child->primary = bus->secondary; child->subordinate = 0xff; /* * Clear all status bits and turn off memory, * I/O and master enables. */ pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr); pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000); pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff); /* * Read the existing primary/secondary/subordinate bus * number configuration to determine if the PCI bridge * has already been configured by the system. If so, * do not modify the configuration, merely note it. */ pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -