📄 pci.c
字号:
/* notify userspace of new hotplug device */ run_sbin_hotplug(dev, TRUE);}static voidpci_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); }}voidpci_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);#ifdef CONFIG_PROC_FS pci_proc_detach_device(dev);#endif /* notify userspace of hotplug device removal */ run_sbin_hotplug(dev, FALSE);}#endifstatic struct pci_driver pci_compat_driver = { name: "compat"};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) return &pci_compat_driver; } return NULL;}/* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. */static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;/* * Wrappers for all PCI configuration access functions. They just check * alignment, do locking and call the low-level functions pointed to * by pci_dev->ops. */#define PCI_byte_BAD 0#define PCI_word_BAD (pos & 1)#define PCI_dword_BAD (pos & 3)#define PCI_OP(rw,size,type) \int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \{ \ int res; \ unsigned long flags; \ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ spin_lock_irqsave(&pci_lock, flags); \ res = dev->bus->ops->rw##_##size(dev, pos, value); \ spin_unlock_irqrestore(&pci_lock, flags); \ return res; \}PCI_OP(read, byte, u8 *)PCI_OP(read, word, u16 *)PCI_OP(read, dword, u32 *)PCI_OP(write, byte, u8)PCI_OP(write, word, u16)PCI_OP(write, dword, u32)voidpci_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; pci_write_config_word(dev, PCI_COMMAND, cmd); } pcibios_set_master(dev);}/* * Translate the low bits of the PCI base * to the resource type */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;}/* * Find the extent of a PCI decode.. */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; /* extent = size - 1 */}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) { printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name); 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; }}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, io_base_hi, io_limit_hi; u32 mem_base_hi, mem_limit_hi; unsigned long base, limit; struct resource *res; int i; if (!dev) /* It's a host bus, nothing to read */ 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); 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_lo & PCI_IO_RANGE_MASK) << 8) | (io_base_hi << 16); limit = ((io_limit_lo & PCI_IO_RANGE_MASK) << 8) | (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; } else { /* * Ugh. We don't know enough about this bridge. Just assume * that it's entirely transparent. */ printk("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; } else { /* See comment above. Same thing */ printk("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); pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi); pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi); base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;#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) { 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; } else { /* See comments above */ printk("Unknown bridge resource %d: assuming transparent\n", 2); child->resource[2] = child->parent->resource[2]; }}static struct pci_bus * __init 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;}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; /* * Allocate a new bus, and inherit stuff from the parent.. */ 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; /* * Set up the primary, secondary and subordinate * bus numbers. */ child->number = child->secondary = busnr; child->primary = parent->secondary; child->subordinate = 0xff; /* Set up default resource pointers.. */ 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);/* * If it's a bridge, configure it and scan the bus behind it. * For CardBus bridges, we don't scan behind as the devices will * be handled by the bridge driver itself. * * We need to process bridges in two passes -- first we scan those * already configured by the BIOS and after we are done with all of * them, we proceed to assigning numbers to the remaining buses in * order to avoid overlaps between old and new bus numbers. */static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, 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); DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass); if ((buses & 0xffff00) && !pcibios_assign_all_busses()) { /* * Bus already configured by firmware, process it in the first * pass and just note the configuration. */ if (pass) return max; child = 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 > max) max = cmax; } else { unsigned int cmax = child->subordinate; if (cmax > max) max = cmax; } } else { /* * We need to assign a number to this bus which we always * do in the second pass. We also keep all address decoders * on the bridge disabled during scanning. FIXME: Why? */ if (!pass) return max; pci_read_config_word(dev, PCI_COMMAND, &cr); pci_write_config_word(dev, PCI_COMMAND, 0x0000); pci_write_config_word(dev, PCI_STATUS, 0xffff); child = pci_add_new_bus(bus, dev, ++max); buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) | ((unsigned int)(child->subordinate) << 16); /* * We need to blast all three values with a single write. */ pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { /* Now we can scan all subordinate buses... */ max = pci_do_scan_bus(child); } else { /* * For CardBus bridges, we leave 4 bus numbers * as cards with a PCI-to-PCI bridge can be * inserted later. */ max += 3; } /* * Set the subordinate bus number to its real value. */ child->subordinate = max; pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); pci_write_config_word(dev, PCI_COMMAND, cr); } sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number); return max;}/* * Read interrupt line and base address registers.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -