PCI_PRIMARY_BUS,
&buses);
- if (((buses >> 8) & 0xff) != bus->secondary) {
+ if (((buses >> 8) & 0xff) != bus->busn_res.start) {
buses = (buses & 0xff000000)
| ((unsigned int)(bus->primary) << 0)
- | ((unsigned int)(bus->secondary) << 8)
- | ((unsigned int)(bus->subordinate) << 16);
+ | ((unsigned int)(bus->busn_res.start) << 8)
+ | ((unsigned int)(bus->busn_res.end) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
}
return NOTIFY_OK;
if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
return AE_OK;
+ status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+ if (ACPI_FAILURE(status)) {
+ warn("can't evaluate _ADR (%#x)\n", status);
+ return AE_OK;
+ }
+
+ device = (adr >> 16) & 0xffff;
+ function = adr & 0xffff;
+
pdev = pbus->self;
if (pdev && pci_is_pcie(pdev)) {
tmp = acpi_find_root_bridge_handle(pdev);
}
}
- acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
- device = (adr >> 16) & 0xffff;
- function = adr & 0xffff;
-
newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
if (!newfunc)
return AE_NO_MEMORY;
* bus->subordinate value because it could have
* padding in it.
*/
- max = bus->secondary;
+ max = bus->busn_res.start;
list_for_each(tmp, &bus->children) {
n = pci_bus_max_busnr(pci_bus_b(tmp));
}
}
+/* return first device in slot, acquiring a reference on it */
+static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
+{
+ struct pci_bus *bus = slot->bridge->pci_bus;
+ struct pci_dev *dev;
+ struct pci_dev *ret = NULL;
+
+ down_read(&pci_bus_sem);
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ if (PCI_SLOT(dev->devfn) == slot->device) {
+ ret = pci_dev_get(dev);
+ break;
+ }
+ up_read(&pci_bus_sem);
+
+ return ret;
+}
+
/**
* disable_device - disable a slot
* @slot: ACPI PHP slot
pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
if (!pdev)
goto err_exit;
+ pci_dev_put(pdev);
list_for_each_entry(func, &slot->funcs, sibling) {
if (func->bridge) {
(u32)1, NULL, NULL);
func->bridge = NULL;
}
+ }
- pdev = pci_get_slot(slot->bridge->pci_bus,
- PCI_DEVFN(slot->device, func->function));
- if (pdev) {
- pci_stop_bus_device(pdev);
- if (pdev->subordinate) {
- disable_bridges(pdev->subordinate);
- pci_disable_device(pdev);
- }
- __pci_remove_bus_device(pdev);
- pci_dev_put(pdev);
+ /*
+ * enable_device() enumerates all functions in this device via
+ * pci_scan_slot(), whether they have associated ACPI hotplug
+ * methods (_EJ0, etc.) or not. Therefore, we remove all functions
+ * here.
+ */
+ while ((pdev = dev_in_slot(slot))) {
+ pci_stop_bus_device(pdev);
+ if (pdev->subordinate) {
+ disable_bridges(pdev->subordinate);
+ pci_disable_device(pdev);
}
+ __pci_remove_bus_device(pdev);
+ pci_dev_put(pdev);
}
list_for_each_entry(func, &slot->funcs, sibling) {
struct list_head *tmp;
unsigned char max, n;
- max = bus->subordinate;
+ max = bus->busn_res.end;
list_for_each(tmp, &bus->children) {
n = pci_bus_max_busnr(pci_bus_b(tmp));
if(n > max)
EXPORT_SYMBOL_GPL(pci_ioremap_bar);
#endif
-#if 0
-/**
- * pci_max_busnr - returns maximum PCI bus number
- *
- * Returns the highest PCI bus number present in the system global list of
- * PCI buses.
- */
-unsigned char __devinit
-pci_max_busnr(void)
-{
- struct pci_bus *bus = NULL;
- unsigned char max, n;
-
- max = 0;
- while ((bus = pci_find_next_bus(bus)) != NULL) {
- n = pci_bus_max_busnr(bus);
- if(n > max)
- max = n;
- }
- return max;
-}
-
-#endif /* 0 */
-
#define PCI_FIND_CAP_TTL 48
static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
return pos;
}
+/**
+ * pci_pcie_cap2 - query for devices' PCI_CAP_ID_EXP v2 capability structure
+ * @dev: PCI device to check
+ *
+ * Like pci_pcie_cap() but also checks that the PCIe capability version is
+ * >= 2. Note that v1 capability structures could be sparse in that not
+ * all register fields were required. v2 requires the entire structure to
+ * be present size wise, while still allowing for non-implemented registers
+ * to exist but they must be hardwired to 0.
+ *
+ * Due to the differences in the versions of capability structures, one
+ * must be careful not to try and access non-existant registers that may
+ * exist in early versions - v1 - of Express devices.
+ *
+ * Returns the offset of the PCIe capability structure as long as the
+ * capability version is >= 2; otherwise 0 is returned.
+ */
+static int pci_pcie_cap2(struct pci_dev *dev)
+{
+ u16 flags;
+ int pos;
+
+ pos = pci_pcie_cap(dev);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
+ if ((flags & PCI_EXP_FLAGS_VERS) < 2)
+ pos = 0;
+ }
+
+ return pos;
+}
+
/**
* pci_find_ext_capability - Find an extended capability
* @dev: PCI device to query
}
EXPORT_SYMBOL_GPL(pci_find_ext_capability);
-/**
- * pci_bus_find_ext_capability - find an extended capability
- * @bus: the PCI bus to query
- * @devfn: PCI device to query
- * @cap: capability code
- *
- * Like pci_find_ext_capability() but works for pci devices that do not have a
- * pci_dev structure set up yet.
- *
- * Returns the address of the requested capability structure within the
- * device's PCI configuration space or 0 in case the device does not
- * support it.
- */
-int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn,
- int cap)
-{
- u32 header;
- int ttl;
- int pos = PCI_CFG_SPACE_SIZE;
-
- /* minimum 8 bytes per capability */
- ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
-
- if (!pci_bus_read_config_dword(bus, devfn, pos, &header))
- return 0;
- if (header == 0xffffffff || header == 0)
- return 0;
-
- while (ttl-- > 0) {
- if (PCI_EXT_CAP_ID(header) == cap)
- return pos;
-
- pos = PCI_EXT_CAP_NEXT(header);
- if (pos < PCI_CFG_SPACE_SIZE)
- break;
-
- if (!pci_bus_read_config_dword(bus, devfn, pos, &header))
- break;
- }
-
- return 0;
-}
-
static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
{
int rc, ttl = PCI_FIND_CAP_TTL;
((flags & PCI_EXP_FLAGS_VERS) > 1 || \
(type == PCI_EXP_TYPE_ROOT_PORT || \
type == PCI_EXP_TYPE_RC_EC))
-#define pcie_cap_has_devctl2(type, flags) \
- ((flags & PCI_EXP_FLAGS_VERS) > 1)
-#define pcie_cap_has_lnkctl2(type, flags) \
- ((flags & PCI_EXP_FLAGS_VERS) > 1)
-#define pcie_cap_has_sltctl2(type, flags) \
- ((flags & PCI_EXP_FLAGS_VERS) > 1)
static struct pci_cap_saved_state *pci_find_saved_cap(
struct pci_dev *pci_dev, char cap)
pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
if (pcie_cap_has_rtctl(dev->pcie_type, flags))
pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
- if (pcie_cap_has_devctl2(dev->pcie_type, flags))
- pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
- if (pcie_cap_has_lnkctl2(dev->pcie_type, flags))
- pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
- if (pcie_cap_has_sltctl2(dev->pcie_type, flags))
- pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
+ pos = pci_pcie_cap2(dev);
+ if (!pos)
+ return 0;
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
return 0;
}
pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
if (pcie_cap_has_rtctl(dev->pcie_type, flags))
pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
- if (pcie_cap_has_devctl2(dev->pcie_type, flags))
- pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
- if (pcie_cap_has_lnkctl2(dev->pcie_type, flags))
- pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
- if (pcie_cap_has_sltctl2(dev->pcie_type, flags))
- pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
+
+ pos = pci_pcie_cap2(dev);
+ if (!pos)
+ return;
+
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
}
* is the default implementation. Architecture implementations can
* override this.
*/
- void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
+ void __weak pcibios_disable_device (struct pci_dev *dev) {}
static void do_pci_disable_device(struct pci_dev *dev)
{
* Sets the PCIe reset state for the device. This is the default
* implementation. Architecture implementations can override this.
*/
- int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev,
- enum pcie_reset_state state)
+ int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
+ enum pcie_reset_state state)
{
return -EINVAL;
}
{
int pos;
u32 cap;
- u16 flags, ctrl;
+ u16 ctrl;
struct pci_dev *bridge;
if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
return;
bridge = dev->bus->self;
- if (!bridge || !pci_is_pcie(bridge))
+ if (!bridge)
return;
- pos = pci_pcie_cap(bridge);
+ /* ARI is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(bridge);
if (!pos)
return;
- /* ARI is a PCIe v2 feature */
- pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags);
- if ((flags & PCI_EXP_FLAGS_VERS) < 2)
- return;
-
pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);
if (!(cap & PCI_EXP_DEVCAP2_ARI))
return;
}
/**
- * pci_enable_ido - enable ID-based ordering on a device
+ * pci_enable_ido - enable ID-based Ordering on a device
* @dev: the PCI device
* @type: which types of IDO to enable
*
int pos;
u16 ctrl;
- pos = pci_pcie_cap(dev);
+ /* ID-based Ordering is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return;
int pos;
u16 ctrl;
- if (!pci_is_pcie(dev))
- return;
-
- pos = pci_pcie_cap(dev);
+ /* ID-based Ordering is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return;
u16 ctrl;
int ret;
- if (!pci_is_pcie(dev))
- return -ENOTSUPP;
-
- pos = pci_pcie_cap(dev);
+ /* OBFF is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return -ENOTSUPP;
return -ENOTSUPP; /* no OBFF support at all */
/* Make sure the topology supports OBFF as well */
- if (dev->bus) {
+ if (dev->bus->self) {
ret = pci_enable_obff(dev->bus->self, type);
if (ret)
return ret;
int pos;
u16 ctrl;
- if (!pci_is_pcie(dev))
- return;
-
- pos = pci_pcie_cap(dev);
+ /* OBFF is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return;
* RETURNS:
* True if @dev supports latency tolerance reporting, false otherwise.
*/
-bool pci_ltr_supported(struct pci_dev *dev)
+static bool pci_ltr_supported(struct pci_dev *dev)
{
int pos;
u32 cap;
- if (!pci_is_pcie(dev))
- return false;
-
- pos = pci_pcie_cap(dev);
+ /* LTR is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return false;
return cap & PCI_EXP_DEVCAP2_LTR;
}
-EXPORT_SYMBOL(pci_ltr_supported);
/**
* pci_enable_ltr - enable latency tolerance reporting
if (!pci_ltr_supported(dev))
return -ENOTSUPP;
- pos = pci_pcie_cap(dev);
+ /* LTR is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return -ENOTSUPP;
return -EINVAL;
/* Enable upstream ports first */
- if (dev->bus) {
+ if (dev->bus->self) {
ret = pci_enable_ltr(dev->bus->self);
if (ret)
return ret;
if (!pci_ltr_supported(dev))
return;
- pos = pci_pcie_cap(dev);
+ /* LTR is a PCIe cap v2 feature */
+ pos = pci_pcie_cap2(dev);
if (!pos)
return;
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
}
+/**
+ * pci_acs_enabled - test ACS against required flags for a given device
+ * @pdev: device to test
+ * @acs_flags: required PCI ACS flags
+ *
+ * Return true if the device supports the provided flags. Automatically
+ * filters out flags that are not implemented on multifunction devices.
+ */
+bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
+{
+ int pos, ret;
+ u16 ctrl;
+
+ ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
+ if (ret >= 0)
+ return ret > 0;
+
+ if (!pci_is_pcie(pdev))
+ return false;
+
+ /* Filter out flags not applicable to multifunction */
+ if (pdev->multifunction)
+ acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
+ PCI_ACS_EC | PCI_ACS_DT);
+
+ if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
+ pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
+ pdev->multifunction) {
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+ if (!pos)
+ return false;
+
+ pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+ if ((ctrl & acs_flags) != acs_flags)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * pci_acs_path_enable - test ACS flags from start to end in a hierarchy
+ * @start: starting downstream device
+ * @end: ending upstream device or NULL to search to the root bus
+ * @acs_flags: required flags
+ *
+ * Walk up a device tree from start to end testing PCI ACS support. If
+ * any step along the way does not support the required flags, return false.
+ */
+bool pci_acs_path_enabled(struct pci_dev *start,
+ struct pci_dev *end, u16 acs_flags)
+{
+ struct pci_dev *pdev, *parent = start;
+
+ do {
+ pdev = parent;
+
+ if (!pci_acs_enabled(pdev, acs_flags))
+ return false;
+
+ if (pci_is_root_bus(pdev->bus))
+ return (end == NULL);
+
+ parent = pdev->bus->self;
+ } while (pdev != end);
+
+ return true;
+}
+
/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
bool mask_supported = false;
u16 orig, new;
+ if (dev->broken_intx_masking)
+ return false;
+
pci_cfg_access_lock(dev);
pci_read_config_word(dev, PCI_COMMAND, &orig);
o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
if (o != v) {
- if (v > o && dev->bus &&
- (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
+ if (v > o && (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
return -EIO;
cmd &= ~PCI_X_CMD_MAX_READ;
* greater than 0xff). This is the default implementation. Architecture
* implementations can override this.
*/
- int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev)
+ int __weak pci_ext_cfg_avail(struct pci_dev *dev)
{
return 1;
}
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
+struct resource busn_resource = {
+ .name = "PCI busn",
+ .start = 0,
+ .end = 255,
+ .flags = IORESOURCE_BUS,
+};
+
/* Ugh. Need to stop exporting this to modules. */
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
+static LIST_HEAD(pci_domain_busn_res_list);
+
+struct pci_domain_busn_res {
+ struct list_head list;
+ struct resource res;
+ int domain_nr;
+};
+
+static struct resource *get_pci_domain_busn_res(int domain_nr)
+{
+ struct pci_domain_busn_res *r;
+
+ list_for_each_entry(r, &pci_domain_busn_res_list, list)
+ if (r->domain_nr == domain_nr)
+ return &r->res;
+
+ r = kzalloc(sizeof(*r), GFP_KERNEL);
+ if (!r)
+ return NULL;
+
+ r->domain_nr = domain_nr;
+ r->res.start = 0;
+ r->res.end = 0xff;
+ r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED;
+
+ list_add_tail(&r->list, &pci_domain_busn_res_list);
+
+ return &r->res;
+}
+
static int find_anything(struct device *dev, void *data)
{
return 1;
if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
u16 io_base_hi, io_limit_hi;
+
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_hi << 16);
- limit |= (io_limit_hi << 16);
+ base |= ((unsigned long) io_base_hi << 16);
+ limit |= ((unsigned long) io_limit_hi << 16);
}
if (base && base <= limit) {
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;
+ base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+ limit = ((unsigned long) mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
region.start = base;
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);
- base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
- limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+ base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+ limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
u32 mem_base_hi, mem_limit_hi;
+
pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
*/
if (mem_base_hi <= mem_limit_hi) {
#if BITS_PER_LONG == 64
- base |= ((long) mem_base_hi) << 32;
- limit |= ((long) mem_limit_hi) << 32;
+ base |= ((unsigned long) mem_base_hi) << 32;
+ limit |= ((unsigned long) mem_limit_hi) << 32;
#else
if (mem_base_hi || mem_limit_hi) {
dev_err(&dev->dev, "can't handle 64-bit "
if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
return;
- dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
- child->secondary, child->subordinate,
+ dev_info(&dev->dev, "PCI bridge to %pR%s\n",
+ &child->busn_res,
dev->transparent ? " (subtractive decode)" : "");
pci_bus_remove_resources(child);
* Set up the primary, secondary and subordinate
* bus numbers.
*/
- child->number = child->secondary = busnr;
- child->primary = parent->secondary;
- child->subordinate = 0xff;
+ child->number = child->busn_res.start = busnr;
+ child->primary = parent->busn_res.start;
+ child->busn_res.end = 0xff;
if (!bridge)
return child;
if (!pcibios_assign_all_busses())
return;
- while (parent->parent && parent->subordinate < max) {
- parent->subordinate = max;
+ while (parent->parent && parent->busn_res.end < max) {
+ parent->busn_res.end = max;
pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
parent = parent->parent;
}
if (!child)
goto out;
child->primary = primary;
- child->subordinate = subordinate;
+ pci_bus_insert_busn_res(child, secondary, subordinate);
child->bridge_ctl = bctl;
}
cmax = pci_scan_child_bus(child);
if (cmax > max)
max = cmax;
- if (child->subordinate > max)
- max = child->subordinate;
+ if (child->busn_res.end > max)
+ max = child->busn_res.end;
} else {
/*
* We need to assign a number to this bus which we always
child = pci_add_new_bus(bus, dev, ++max);
if (!child)
goto out;
+ pci_bus_insert_busn_res(child, max, 0xff);
}
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
- | ((unsigned int)(child->secondary) << 8)
- | ((unsigned int)(child->subordinate) << 16);
+ | ((unsigned int)(child->busn_res.start) << 8)
+ | ((unsigned int)(child->busn_res.end) << 16);
/*
* yenta.c forces a secondary latency timer of 176.
break;
while (parent->parent) {
if ((!pcibios_assign_all_busses()) &&
- (parent->subordinate > max) &&
- (parent->subordinate <= max+i)) {
+ (parent->busn_res.end > max) &&
+ (parent->busn_res.end <= max+i)) {
j = 1;
}
parent = parent->parent;
/*
* Set the subordinate bus number to its real value.
*/
- child->subordinate = max;
+ pci_bus_update_busn_res_end(child, max);
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
}
/* Has only triggered on CardBus, fixup is in yenta_socket */
while (bus->parent) {
- if ((child->subordinate > bus->subordinate) ||
- (child->number > bus->subordinate) ||
+ if ((child->busn_res.end > bus->busn_res.end) ||
+ (child->number > bus->busn_res.end) ||
(child->number < bus->number) ||
- (child->subordinate < bus->number)) {
- dev_info(&child->dev, "[bus %02x-%02x] %s "
- "hidden behind%s bridge %s [bus %02x-%02x]\n",
- child->number, child->subordinate,
- (bus->number > child->subordinate &&
- bus->subordinate < child->number) ?
+ (child->busn_res.end < bus->number)) {
+ dev_info(&child->dev, "%pR %s "
+ "hidden behind%s bridge %s %pR\n",
+ &child->busn_res,
+ (bus->number > child->busn_res.end &&
+ bus->busn_res.end < child->number) ?
"wholly" : "partially",
bus->self->transparent ? " transparent" : "",
dev_name(&bus->dev),
- bus->number, bus->subordinate);
+ &bus->busn_res);
}
bus = bus->parent;
}
unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{
- unsigned int devfn, pass, max = bus->secondary;
+ unsigned int devfn, pass, max = bus->busn_res.start;
struct pci_dev *dev;
dev_dbg(&bus->dev, "scanning bus\n");
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(b);
- b->number = b->secondary = bus;
+ b->number = b->busn_res.start = bus;
if (parent)
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
list_move_tail(&window->list, &bridge->windows);
res = window->res;
offset = window->offset;
- pci_bus_add_resource(b, res, 0);
+ if (res->flags & IORESOURCE_BUS)
+ pci_bus_insert_busn_res(b, bus, res->end);
+ else
+ pci_bus_add_resource(b, res, 0);
if (offset) {
if (resource_type(res) == IORESOURCE_IO)
fmt = " (bus address [%#06llx-%#06llx])";
return NULL;
}
+int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
+{
+ struct resource *res = &b->busn_res;
+ struct resource *parent_res, *conflict;
+
+ res->start = bus;
+ res->end = bus_max;
+ res->flags = IORESOURCE_BUS;
+
+ if (!pci_is_root_bus(b))
+ parent_res = &b->parent->busn_res;
+ else {
+ parent_res = get_pci_domain_busn_res(pci_domain_nr(b));
+ res->flags |= IORESOURCE_PCI_FIXED;
+ }
+
+ conflict = insert_resource_conflict(parent_res, res);
+
+ if (conflict)
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: can not insert %pR under %s%pR (conflicts with %s %pR)\n",
+ res, pci_is_root_bus(b) ? "domain " : "",
+ parent_res, conflict->name, conflict);
+ else
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR is inserted under %s%pR\n",
+ res, pci_is_root_bus(b) ? "domain " : "",
+ parent_res);
+
+ return conflict == NULL;
+}
+
+int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max)
+{
+ struct resource *res = &b->busn_res;
+ struct resource old_res = *res;
+ resource_size_t size;
+ int ret;
+
+ if (res->start > bus_max)
+ return -EINVAL;
+
+ size = bus_max - res->start + 1;
+ ret = adjust_resource(res, res->start, size);
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR end %s updated to %02x\n",
+ &old_res, ret ? "can not be" : "is", bus_max);
+
+ if (!ret && !res->parent)
+ pci_bus_insert_busn_res(b, res->start, res->end);
+
+ return ret;
+}
+
+void pci_bus_release_busn_res(struct pci_bus *b)
+{
+ struct resource *res = &b->busn_res;
+ int ret;
+
+ if (!res->flags || !res->parent)
+ return;
+
+ ret = release_resource(res);
+ dev_printk(KERN_DEBUG, &b->dev,
+ "busn_res: %pR %s released\n",
+ res, ret ? "can not be" : "is");
+}
+
struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
+ struct pci_host_bridge_window *window;
+ bool found = false;
struct pci_bus *b;
+ int max;
+
+ list_for_each_entry(window, resources, list)
+ if (window->res->flags & IORESOURCE_BUS) {
+ found = true;
+ break;
+ }
b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
if (!b)
return NULL;
- b->subordinate = pci_scan_child_bus(b);
+ if (!found) {
+ dev_info(&b->dev,
+ "No busn resource found for root bus, will use [bus %02x-ff]\n",
+ bus);
+ pci_bus_insert_busn_res(b, bus, 255);
+ }
+
+ max = pci_scan_child_bus(b);
+
+ if (!found)
+ pci_bus_update_busn_res_end(b, max);
+
pci_bus_add_devices(b);
return b;
}
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
+ pci_add_resource(&resources, &busn_resource);
b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
if (b)
- b->subordinate = pci_scan_child_bus(b);
+ pci_scan_child_bus(b);
else
pci_free_resource_list(&resources);
return b;
pci_add_resource(&resources, &ioport_resource);
pci_add_resource(&resources, &iomem_resource);
+ pci_add_resource(&resources, &busn_resource);
b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
if (b) {
- b->subordinate = pci_scan_child_bus(b);
+ pci_scan_child_bus(b);
pci_bus_add_devices(b);
} else {
pci_free_resource_list(&resources);
* assign_requested_resources_sorted() - satisfy resource requests
*
* @head : head of the list tracking requests for resources
- * @failed_list : head of the list tracking requests that could
+ * @fail_head : head of the list tracking requests that could
* not be allocated
*
* Satisfy resource requests of each element in the list. Add
struct resource *res;
struct pci_bus_region region;
- dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n",
- bus->secondary, bus->subordinate);
+ dev_info(&bridge->dev, "CardBus bridge to %pR\n",
+ &bus->busn_res);
res = bus->resource[0];
pcibios_resource_to_bus(bridge, ®ion, res);
{
struct pci_dev *bridge = bus->self;
- dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
- bus->secondary, bus->subordinate);
+ dev_info(&bridge->dev, "PCI bridge to %pR\n",
+ &bus->busn_res);
if (type & IORESOURCE_IO)
pci_setup_bridge_io(bus);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
- "%pR to [bus %02x-%02x] (unused)\n", b_res,
- bus->secondary, bus->subordinate);
+ "%pR to %pR (unused)\n", b_res,
+ &bus->busn_res);
b_res->flags = 0;
return;
}
if (size1 > size0 && realloc_head) {
add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
- "%pR to [bus %02x-%02x] add_size %lx\n", b_res,
- bus->secondary, bus->subordinate, size1-size0);
+ "%pR to %pR add_size %lx\n", b_res,
+ &bus->busn_res, size1-size0);
}
}
if (!size0 && !size1) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
- "%pR to [bus %02x-%02x] (unused)\n", b_res,
- bus->secondary, bus->subordinate);
+ "%pR to %pR (unused)\n", b_res,
+ &bus->busn_res);
b_res->flags = 0;
return 1;
}
if (size1 > size0 && realloc_head) {
add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
- "%pR to [bus %02x-%02x] add_size %llx\n", b_res,
- bus->secondary, bus->subordinate, (unsigned long long)size1-size0);
+ "%pR to %pR add_size %llx\n", b_res,
+ &bus->busn_res, (unsigned long long)size1-size0);
}
return 1;
}