📄 pci.c
字号:
len += sprintf(buf + len, "Max Lat=%d.", max_lat); } switch (hdr_type & 0x7f) { case 0: last_reg = PCI_BASE_ADDRESS_5; break; case 1: last_reg = PCI_BASE_ADDRESS_1; break; default: last_reg = 0; } for (reg = PCI_BASE_ADDRESS_0; reg <= last_reg; reg += 4) { if (len + 40 > size) { return -1; } pcibios_read_config_dword(bus, devfn, reg, &l); base = l; if (!base) { continue; } if (base & PCI_BASE_ADDRESS_SPACE_IO) { len += sprintf(buf + len, "\n I/O at 0x%lx.", base & PCI_BASE_ADDRESS_IO_MASK); } else { const char *pref, *type = "unknown"; if (base & PCI_BASE_ADDRESS_MEM_PREFETCH) { pref = "P"; } else { pref = "Non-p"; } switch (base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { case PCI_BASE_ADDRESS_MEM_TYPE_32: type = "32 bit"; break; case PCI_BASE_ADDRESS_MEM_TYPE_1M: type = "20 bit"; break; case PCI_BASE_ADDRESS_MEM_TYPE_64: type = "64 bit"; /* read top 32 bit address of base addr: */ reg += 4; pcibios_read_config_dword(bus, devfn, reg, &l); base |= ((u64) l) << 32; break; } len += sprintf(buf + len, "\n %srefetchable %s memory at " "0x%lx.", pref, type, base & PCI_BASE_ADDRESS_MEM_MASK); } } len += sprintf(buf + len, "\n"); return len;}/* * Return list of PCI devices as a character string for /proc/pci. * BUF is a buffer that is PAGE_SIZE bytes long. */int get_pci_list(char *buf){ int nprinted, len, size; struct pci_dev *dev;# define MSG "\nwarning: page-size limit reached!\n" /* reserve same for truncation warning message: */ size = PAGE_SIZE - (strlen(MSG) + 1); len = sprintf(buf, "PCI devices found:\n"); for (dev = pci_devices; dev; dev = dev->next) { nprinted = sprint_dev_config(dev, buf + len, size - len); if (nprinted < 0) { return len + sprintf(buf + len, MSG); } len += nprinted; } return len;}/* * pci_malloc() returns initialized memory of size SIZE. Can be * used only while pci_init() is active. */static void *pci_malloc(long size, unsigned long *mem_startp){ void *mem;#ifdef DEBUG printk("...pci_malloc(size=%ld,mem=%p)", size, *mem_startp);#endif mem = (void*) *mem_startp; *mem_startp += (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); memset(mem, 0, size); return mem;}static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp){ unsigned int devfn, l, max; unsigned char cmd, tmp, hdr_type, ht, is_multi = 0; struct pci_dev_info *info; struct pci_dev *dev; struct pci_bus *child;#ifdef DEBUG printk("...scan_bus(busno=%d,mem=%p)\n", bus->number, *mem_startp);#endif max = bus->secondary; for (devfn = 0; devfn < 0xff; ++devfn) { if (PCI_FUNC(devfn) && !is_multi) { /* Not a multi-function device */ continue; } pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type); if (!PCI_FUNC(devfn)) is_multi = hdr_type & 0x80; pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l); /* some broken boards return 0 if a slot is empty: */ if (l == 0xffffffff || l == 0x00000000) { is_multi = 0; continue; } dev = pci_malloc(sizeof(*dev), mem_startp); dev->bus = bus; dev->devfn = devfn; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; /* * Check to see if we know about this device and report * a message at boot time. This is the only way to * learn about new hardware... */ info = pci_lookup_dev(dev->vendor, dev->device); if (!info) {#if 0 printk("Warning : Unknown PCI device (%x:%x). Please read include/linux/pci.h\n", dev->vendor, dev->device);#endif } else { /* Some BIOS' are lazy. Let's do their job: */ if (info->bridge_type != 0xff) { burst_bridge(bus->number, devfn, info->bridge_type, 1); } } /* non-destructively determine if device can be a master: */ pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd); pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp); dev->master = ((tmp & PCI_COMMAND_MASTER) != 0); pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd); /* read irq level (may be changed during pcibios_fixup()): */ pcibios_read_config_byte(bus->number, devfn, PCI_INTERRUPT_LINE, &dev->irq); /* check to see if this device is a PCI-PCI bridge: */ pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &l); l = l >> 8; /* upper 3 bytes */ dev->class = l; /* * Check if the header type is known and consistent with * device type. PCI-to-PCI Bridges should have hdr_type 1, * CardBus Bridges 2, all other devices 0. */ switch (dev->class >> 8) { case PCI_CLASS_BRIDGE_PCI: ht = 1; break; case PCI_CLASS_BRIDGE_CARDBUS: ht = 2; break; default: ht = 0; } if (ht != (hdr_type & 0x7f)) { printk(KERN_WARNING "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n", bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type); continue; } /* * Put it into the simple chain of all PCI devices. * It is used to find devices once everything is set up. */ dev->next = pci_devices; pci_devices = dev; /* * Now insert it into the list of devices held * by the parent bus. */ dev->sibling = bus->devices; bus->devices = dev; if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) { unsigned int buses; unsigned short cr; /* * Insert it into the tree of buses. */ child = pci_malloc(sizeof(*child), mem_startp); 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, 0x18, &buses); if ((buses & 0xFFFFFF) != 0) { child->primary = buses & 0xFF; child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; child->number = child->secondary; max = scan_bus(child, mem_startp); } else { /* * Configure the bus numbers for this bridge: */ buses &= 0xff000000; buses |= (((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) | ((unsigned int)(child->subordinate) << 16)); pcibios_write_config_dword(bus->number, devfn, 0x18, buses); /* * Now we can scan all subordinate buses: */ max = scan_bus(child, mem_startp); /* * Set the subordinate bus number to its real * value: */ child->subordinate = max; buses = (buses & 0xff00ffff) | ((unsigned int)(child->subordinate) << 16); pcibios_write_config_dword(bus->number, devfn, 0x18, buses); } pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); } } /* * We've scanned the bus and so we know all about what's on * the other side of any bridges that may be on this bus plus * any devices. * * Return how far we've got finding sub-buses. */ return max;}unsigned long pci_init (unsigned long mem_start, unsigned long mem_end){ mem_start = pcibios_init(mem_start, mem_end); if (!pcibios_present()) { printk("pci_init: no BIOS32 detected\n"); return mem_start; } printk("Probing PCI hardware.\n"); memset(&pci_root, 0, sizeof(pci_root)); pci_root.subordinate = scan_bus(&pci_root, &mem_start); /* give BIOS a chance to apply platform specific fixes: */ mem_start = pcibios_fixup(mem_start, mem_end);#ifdef DEBUG { int len = get_pci_list((char*)mem_start); if (len) { ((char *) mem_start)[len] = '\0'; printk("%s\n", (char *) mem_start); } }#endif return mem_start;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -