📄 setup-bus.c
字号:
/* * drivers/pci/setup-bus.c * * Extruded from code written by * Dave Rusling (david.rusling@reo.mts.dec.com) * David Mosberger (davidm@cs.arizona.edu) * David Miller (davem@redhat.com) * * Support routines for initializing a PCI subsystem. *//* * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * PCI-PCI bridges cleanup, sorted resource allocation. * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * Converted to allocation in 3 passes, which gives * tighter packing. Prefetchable range support. */#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/cache.h>#include <linux/slab.h>#define DEBUG_CONFIG 1#if DEBUG_CONFIG#define DBG(x...) printk(x)#else#define DBG(x...)#endifstatic void pbus_assign_resources_sorted(struct pci_bus *bus){ struct pci_dev *dev; struct resource *res; struct resource_list head, *list, *tmp; int idx; head.next = NULL; list_for_each_entry(dev, &bus->devices, bus_list) { u16 class = dev->class >> 8; /* Don't touch classless devices or host bridges or ioapics. */ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) continue; /* Don't touch ioapic devices already enabled by firmware */ if (class == PCI_CLASS_SYSTEM_PIC) { u16 command; pci_read_config_word(dev, PCI_COMMAND, &command); if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) continue; } pdev_sort_resources(dev, &head); } for (list = head.next; list;) { res = list->res; idx = res - &list->dev->resource[0]; if (pci_assign_resource(list->dev, idx)) { res->start = 0; res->end = 0; res->flags = 0; } tmp = list; list = list->next; kfree(tmp); }}void pci_setup_cardbus(struct pci_bus *bus){ struct pci_dev *bridge = bus->self; struct pci_bus_region region; printk("PCI: Bus %d, cardbus bridge: %s\n", bus->number, pci_name(bridge)); pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); if (bus->resource[0]->flags & IORESOURCE_IO) { /* * The IO resource is allocated a range twice as large as it * would normally need. This allows us to set both IO regs. */ printk(" IO window: %08lx-%08lx\n", region.start, region.end); pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, region.end); } pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); if (bus->resource[1]->flags & IORESOURCE_IO) { printk(" IO window: %08lx-%08lx\n", region.start, region.end); pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, region.end); } pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_MEM) { printk(" PREFETCH window: %08lx-%08lx\n", region.start, region.end); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, region.end); } pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); if (bus->resource[3]->flags & IORESOURCE_MEM) { printk(" MEM window: %08lx-%08lx\n", region.start, region.end); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, region.end); }}EXPORT_SYMBOL(pci_setup_cardbus);/* Initialize bridges with base/limit values we have collected. PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998) requires that if there is no I/O ports or memory behind the bridge, corresponding range must be turned off by writing base value greater than limit to the bridge's base/limit registers. Note: care must be taken when updating I/O base/limit registers of bridges which support 32-bit I/O. This update requires two config space writes, so it's quite possible that an I/O window of the bridge will have some undesirable address (e.g. 0) after the first write. Ditto 64-bit prefetchable MMIO. */static void __devinitpci_setup_bridge(struct pci_bus *bus){ struct pci_dev *bridge = bus->self; struct pci_bus_region region; u32 l, io_upper16; DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge)); /* Set up the top and bottom of the PCI I/O segment for this bus. */ pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); if (bus->resource[0]->flags & IORESOURCE_IO) { pci_read_config_dword(bridge, PCI_IO_BASE, &l); l &= 0xffff0000; l |= (region.start >> 8) & 0x00f0; l |= region.end & 0xf000; /* Set up upper 16 bits of I/O base/limit. */ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); DBG(KERN_INFO " IO window: %04lx-%04lx\n", region.start, region.end); } else { /* Clear upper 16 bits of I/O base/limit. */ io_upper16 = 0; l = 0x00f0; DBG(KERN_INFO " IO window: disabled.\n"); } /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); /* Update lower 16 bits of I/O base/limit. */ pci_write_config_dword(bridge, PCI_IO_BASE, l); /* Update upper 16 bits of I/O base/limit. */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); /* Set up the top and bottom of the PCI Memory segment for this bus. */ pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); if (bus->resource[1]->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; DBG(KERN_INFO " MEM window: %08lx-%08lx\n", region.start, region.end); } else { l = 0x0000fff0; DBG(KERN_INFO " MEM window: disabled.\n"); } pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); /* Clear out the upper 32 bits of PREF limit. If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily disables PREF range, which is ok. */ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; DBG(KERN_INFO " PREFETCH window: %08lx-%08lx\n", region.start, region.end); } else { l = 0x0000fff0; DBG(KERN_INFO " PREFETCH window: disabled.\n"); } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); /* Clear out the upper 32 bits of PREF base. */ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);}/* Check whether the bridge supports optional I/O and prefetchable memory ranges. If not, the respective base/limit registers must be read-only and read as 0. */static void pci_bridge_check_ranges(struct pci_bus *bus){ u16 io; u32 pmem; struct pci_dev *bridge = bus->self; struct resource *b_res; b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; b_res[1].flags |= IORESOURCE_MEM; pci_read_config_word(bridge, PCI_IO_BASE, &io); if (!io) { pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0); pci_read_config_word(bridge, PCI_IO_BASE, &io); pci_write_config_word(bridge, PCI_IO_BASE, 0x0); } if (io) b_res[0].flags |= IORESOURCE_IO; /* DECchip 21050 pass 2 errata: the bridge may miss an address disconnect boundary by one PCI data phase. Workaround: do not use prefetching on this device. */ if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001) return; pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); if (!pmem) { pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0xfff0fff0); pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); } if (pmem) b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;}/* Helper function for sizing routines: find first available bus resource of a given type. Note: we intentionally skip the bus resources which have already been assigned (that is, have non-NULL parent resource). */static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type){ int i; struct resource *r; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { r = bus->resource[i]; if (r == &ioport_resource || r == &iomem_resource) continue; if (r && (r->flags & type_mask) == type && !r->parent) return r; } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -