📄 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 DBGC(args) printk args#else# define DBGC(args)#endif#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))/* * FIXME: IO should be max 256 bytes. However, since we may * have a P2P bridge below a cardbus bridge, we need 4K. */#define CARDBUS_IO_SIZE (4096)#define CARDBUS_MEM_SIZE (32*1024*1024)static void __devinitpbus_assign_resources_sorted(struct pci_bus *bus){ struct pci_dev *dev; struct resource *res; struct resource_list head, *list, *tmp; int idx; bus->bridge_ctl &= ~PCI_BRIDGE_CTL_VGA; head.next = NULL; list_for_each_entry(dev, &bus->devices, bus_list) { u16 class = dev->class >> 8; if (class == PCI_CLASS_DISPLAY_VGA || class == PCI_CLASS_NOT_DEFINED_VGA) bus->bridge_ctl |= PCI_BRIDGE_CTL_VGA; pdev_sort_resources(dev, &head); } for (list = head.next; list;) { res = list->res; idx = res - &list->dev->resource[0]; pci_assign_resource(list->dev, idx); tmp = list; list = list->next; kfree(tmp); }}static void __devinitpci_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); }}/* 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; DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n", bus->number, 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); DBGC((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; DBGC((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; DBGC((KERN_INFO " MEM window: %08lx-%08lx\n", region.start, region.end)); } else { l = 0x0000fff0; DBGC((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; DBGC((KERN_INFO " PREFETCH window: %08lx-%08lx\n", region.start, region.end)); } else { l = 0x0000fff0; DBGC((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 __devinitpci_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 * __devinitfind_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 && (r->flags & type_mask) == type && !r->parent) return r; } return NULL;}/* Sizing the IO windows of the PCI-PCI bridge is trivial,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -